diff options
2103 files changed, 43280 insertions, 26577 deletions
@@ -21,7 +21,8 @@ Adam Radford <aradford@gmail.com> Adriana Reus <adi.reus@gmail.com> <adriana.reus@intel.com> Adrian Bunk <bunk@stusta.de> Ajay Kaher <ajay.kaher@broadcom.com> <akaher@vmware.com> -Akhil P Oommen <quic_akhilpo@quicinc.com> <akhilpo@codeaurora.org> +Akhil P Oommen <akhilpo@oss.qualcomm.com> <akhilpo@codeaurora.org> +Akhil P Oommen <akhilpo@oss.qualcomm.com> <quic_akhilpo@quicinc.com> Alan Cox <alan@lxorguk.ukuu.org.uk> Alan Cox <root@hraefn.swansea.linux.org.uk> Aleksandar Markovic <aleksandar.markovic@mips.com> <aleksandar.markovic@imgtec.com> @@ -106,7 +107,8 @@ Asahi Lina <lina+kernel@asahilina.net> <lina@asahilina.net> Ashok Raj Nagarajan <quic_arnagara@quicinc.com> <arnagara@codeaurora.org> Ashwin Chaugule <quic_ashwinc@quicinc.com> <ashwinc@codeaurora.org> Asutosh Das <quic_asutoshd@quicinc.com> <asutoshd@codeaurora.org> -Atish Patra <atishp@atishpatra.org> <atish.patra@wdc.com> +Atish Patra <atish.patra@linux.dev> <atishp@atishpatra.org> +Atish Patra <atish.patra@linux.dev> <atish.patra@wdc.com> Avaneesh Kumar Dwivedi <quic_akdwived@quicinc.com> <akdwived@codeaurora.org> Axel Dyks <xl@xlsigned.net> Axel Lin <axel.lin@gmail.com> @@ -600,6 +602,12 @@ Paul Mackerras <paulus@ozlabs.org> <paulus@samba.org> Paul Mackerras <paulus@ozlabs.org> <paulus@au1.ibm.com> Paul Moore <paul@paul-moore.com> <paul.moore@hp.com> Paul Moore <paul@paul-moore.com> <pmoore@redhat.com> +Paulo Alcantara <pc@manguebit.org> <pcacjr@zytor.com> +Paulo Alcantara <pc@manguebit.org> <paulo@paulo.ac> +Paulo Alcantara <pc@manguebit.org> <pc@cjr.nz> +Paulo Alcantara <pc@manguebit.org> <palcantara@suse.de> +Paulo Alcantara <pc@manguebit.org> <palcantara@suse.com> +Paulo Alcantara <pc@manguebit.org> <pc@manguebit.com> Pavankumar Kondeti <quic_pkondeti@quicinc.com> <pkondeti@codeaurora.org> Peter A Jonsson <pj@ludd.ltu.se> Peter Oruba <peter.oruba@amd.com> @@ -640,6 +648,8 @@ Richard Genoud <richard.genoud@bootlin.com> <richard.genoud@gmail.com> Richard Leitner <richard.leitner@linux.dev> <dev@g0hl1n.net> Richard Leitner <richard.leitner@linux.dev> <me@g0hl1n.net> Richard Leitner <richard.leitner@linux.dev> <richard.leitner@skidata.com> +Rob Clark <robin.clark@oss.qualcomm.com> <robdclark@chromium.org> +Rob Clark <robin.clark@oss.qualcomm.com> <robdclark@gmail.com> Robert Foss <rfoss@kernel.org> <robert.foss@linaro.org> Rocky Liao <quic_rjliao@quicinc.com> <rjliao@codeaurora.org> Rodrigo Siqueira <siqueira@igalia.com> <rodrigosiqueiramelo@gmail.com> diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index 722aa989baac..190bfcc1e836 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -94,6 +94,7 @@ Description: What: /sys/bus/iio/devices/iio:deviceX/sampling_frequency What: /sys/bus/iio/devices/iio:deviceX/in_intensity_sampling_frequency What: /sys/bus/iio/devices/iio:deviceX/buffer/sampling_frequency +What: /sys/bus/iio/devices/iio:deviceX/events/sampling_frequency What: /sys/bus/iio/devices/triggerX/sampling_frequency KernelVersion: 2.6.35 Contact: linux-iio@vger.kernel.org @@ -740,7 +741,9 @@ Description: 1kohm_to_gnd: connected to ground via an 1kOhm resistor, 2.5kohm_to_gnd: connected to ground via a 2.5kOhm resistor, 6kohm_to_gnd: connected to ground via a 6kOhm resistor, + 7.7kohm_to_gnd: connected to ground via a 7.7kOhm resistor, 20kohm_to_gnd: connected to ground via a 20kOhm resistor, + 32kohm_to_gnd: connected to ground via a 32kOhm resistor, 42kohm_to_gnd: connected to ground via a 42kOhm resistor, 90kohm_to_gnd: connected to ground via a 90kOhm resistor, 100kohm_to_gnd: connected to ground via an 100kOhm resistor, diff --git a/Documentation/ABI/testing/sysfs-driver-intel-m10-bmc b/Documentation/ABI/testing/sysfs-driver-intel-m10-bmc index a6e400364932..faeae8fedb14 100644 --- a/Documentation/ABI/testing/sysfs-driver-intel-m10-bmc +++ b/Documentation/ABI/testing/sysfs-driver-intel-m10-bmc @@ -17,7 +17,7 @@ Description: Read only. Returns the firmware version of Intel MAX10 What: /sys/bus/.../drivers/intel-m10-bmc/.../mac_address Date: January 2021 KernelVersion: 5.12 -Contact: Peter Colberg <peter.colberg@altera.com> +Contact: Matthew Gerlach <matthew.gerlach@altera.com> Description: Read only. Returns the first MAC address in a block of sequential MAC addresses assigned to the board that is managed by the Intel MAX10 BMC. It is stored in @@ -28,7 +28,7 @@ Description: Read only. Returns the first MAC address in a block What: /sys/bus/.../drivers/intel-m10-bmc/.../mac_count Date: January 2021 KernelVersion: 5.12 -Contact: Peter Colberg <peter.colberg@altera.com> +Contact: Matthew Gerlach <matthew.gerlach@altera.com> Description: Read only. Returns the number of sequential MAC addresses assigned to the board managed by the Intel MAX10 BMC. This value is stored in FLASH and is mirrored diff --git a/Documentation/ABI/testing/sysfs-driver-intel-m10-bmc-sec-update b/Documentation/ABI/testing/sysfs-driver-intel-m10-bmc-sec-update index c69fd3894eb4..3a6ca780c75c 100644 --- a/Documentation/ABI/testing/sysfs-driver-intel-m10-bmc-sec-update +++ b/Documentation/ABI/testing/sysfs-driver-intel-m10-bmc-sec-update @@ -1,7 +1,7 @@ What: /sys/bus/platform/drivers/intel-m10bmc-sec-update/.../security/sr_root_entry_hash Date: Sep 2022 KernelVersion: 5.20 -Contact: Peter Colberg <peter.colberg@altera.com> +Contact: Matthew Gerlach <matthew.gerlach@altera.com> Description: Read only. Returns the root entry hash for the static region if one is programmed, else it returns the string: "hash not programmed". This file is only @@ -11,7 +11,7 @@ Description: Read only. Returns the root entry hash for the static What: /sys/bus/platform/drivers/intel-m10bmc-sec-update/.../security/pr_root_entry_hash Date: Sep 2022 KernelVersion: 5.20 -Contact: Peter Colberg <peter.colberg@altera.com> +Contact: Matthew Gerlach <matthew.gerlach@altera.com> Description: Read only. Returns the root entry hash for the partial reconfiguration region if one is programmed, else it returns the string: "hash not programmed". This file @@ -21,7 +21,7 @@ Description: Read only. Returns the root entry hash for the partial What: /sys/bus/platform/drivers/intel-m10bmc-sec-update/.../security/bmc_root_entry_hash Date: Sep 2022 KernelVersion: 5.20 -Contact: Peter Colberg <peter.colberg@altera.com> +Contact: Matthew Gerlach <matthew.gerlach@altera.com> Description: Read only. Returns the root entry hash for the BMC image if one is programmed, else it returns the string: "hash not programmed". This file is only visible if the @@ -31,7 +31,7 @@ Description: Read only. Returns the root entry hash for the BMC image What: /sys/bus/platform/drivers/intel-m10bmc-sec-update/.../security/sr_canceled_csks Date: Sep 2022 KernelVersion: 5.20 -Contact: Peter Colberg <peter.colberg@altera.com> +Contact: Matthew Gerlach <matthew.gerlach@altera.com> Description: Read only. Returns a list of indices for canceled code signing keys for the static region. The standard bitmap list format is used (e.g. "1,2-6,9"). @@ -39,7 +39,7 @@ Description: Read only. Returns a list of indices for canceled code What: /sys/bus/platform/drivers/intel-m10bmc-sec-update/.../security/pr_canceled_csks Date: Sep 2022 KernelVersion: 5.20 -Contact: Peter Colberg <peter.colberg@altera.com> +Contact: Matthew Gerlach <matthew.gerlach@altera.com> Description: Read only. Returns a list of indices for canceled code signing keys for the partial reconfiguration region. The standard bitmap list format is used (e.g. "1,2-6,9"). @@ -47,7 +47,7 @@ Description: Read only. Returns a list of indices for canceled code What: /sys/bus/platform/drivers/intel-m10bmc-sec-update/.../security/bmc_canceled_csks Date: Sep 2022 KernelVersion: 5.20 -Contact: Peter Colberg <peter.colberg@altera.com> +Contact: Matthew Gerlach <matthew.gerlach@altera.com> Description: Read only. Returns a list of indices for canceled code signing keys for the BMC. The standard bitmap list format is used (e.g. "1,2-6,9"). @@ -55,7 +55,7 @@ Description: Read only. Returns a list of indices for canceled code What: /sys/bus/platform/drivers/intel-m10bmc-sec-update/.../security/flash_count Date: Sep 2022 KernelVersion: 5.20 -Contact: Peter Colberg <peter.colberg@altera.com> +Contact: Matthew Gerlach <matthew.gerlach@altera.com> Description: Read only. Returns number of times the secure update staging area has been flashed. Format: "%u". diff --git a/Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon b/Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon index 4ca917ac6382..5a91dcccd3ac 100644 --- a/Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon +++ b/Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon @@ -60,26 +60,26 @@ Description: RO. Package default power limit (default TDP setting). Only supported for particular Intel Xe graphics platforms. -What: /sys/bus/pci/drivers/xe/.../hwmon/hwmon<i>/power2_crit -Date: February 2024 -KernelVersion: 6.8 +What: /sys/bus/pci/drivers/xe/.../hwmon/hwmon<i>/power1_crit +Date: May 2025 +KernelVersion: 6.15 Contact: intel-xe@lists.freedesktop.org -Description: RW. Package reactive critical (I1) power limit in microwatts. +Description: RW. Card reactive critical (I1) power limit in microwatts. - Package reactive critical (I1) power limit in microwatts is exposed + Card reactive critical (I1) power limit in microwatts is exposed for client products. The power controller will throttle the operating frequency if the power averaged over a window exceeds this limit. Only supported for particular Intel Xe graphics platforms. -What: /sys/bus/pci/drivers/xe/.../hwmon/hwmon<i>/curr2_crit -Date: February 2024 -KernelVersion: 6.8 +What: /sys/bus/pci/drivers/xe/.../hwmon/hwmon<i>/curr1_crit +Date: May 2025 +KernelVersion: 6.15 Contact: intel-xe@lists.freedesktop.org -Description: RW. Package reactive critical (I1) power limit in milliamperes. +Description: RW. Card reactive critical (I1) power limit in milliamperes. - Package reactive critical (I1) power limit in milliamperes is + Card reactive critical (I1) power limit in milliamperes is exposed for server products. The power controller will throttle the operating frequency if the power averaged over a window exceeds this limit. diff --git a/Documentation/admin-guide/thunderbolt.rst b/Documentation/admin-guide/thunderbolt.rst index d0502691dfa1..240fee618e06 100644 --- a/Documentation/admin-guide/thunderbolt.rst +++ b/Documentation/admin-guide/thunderbolt.rst @@ -296,6 +296,39 @@ information is missing. To recover from this mode, one needs to flash a valid NVM image to the host controller in the same way it is done in the previous chapter. +Tunneling events +---------------- +The driver sends ``KOBJ_CHANGE`` events to userspace when there is a +tunneling change in the ``thunderbolt_domain``. The notification carries +following environment variables:: + + TUNNEL_EVENT=<EVENT> + TUNNEL_DETAILS=0:12 <-> 1:20 (USB3) + +Possible values for ``<EVENT>`` are: + + activated + The tunnel was activated (created). + + changed + There is a change in this tunnel. For example bandwidth allocation was + changed. + + deactivated + The tunnel was torn down. + + low bandwidth + The tunnel is not getting optimal bandwidth. + + insufficient bandwidth + There is not enough bandwidth for the current tunnel requirements. + +The ``TUNNEL_DETAILS`` is only provided if the tunnel is known. For +example, in case of Firmware Connection Manager this is missing or does +not provide full tunnel information. In case of Software Connection Manager +this includes full tunnel details. The format currently matches what the +driver uses when logging. This may change over time. + Networking over Thunderbolt cable --------------------------------- Thunderbolt technology allows software communication between two hosts diff --git a/Documentation/arch/riscv/cmodx.rst b/Documentation/arch/riscv/cmodx.rst index 8c48bcff3df9..40ba53bed5df 100644 --- a/Documentation/arch/riscv/cmodx.rst +++ b/Documentation/arch/riscv/cmodx.rst @@ -10,13 +10,45 @@ modified by the program itself. Instruction storage and the instruction cache program must enforce its own synchronization with the unprivileged fence.i instruction. -However, the default Linux ABI prohibits the use of fence.i in userspace -applications. At any point the scheduler may migrate a task onto a new hart. If -migration occurs after the userspace synchronized the icache and instruction -storage with fence.i, the icache on the new hart will no longer be clean. This -is due to the behavior of fence.i only affecting the hart that it is called on. -Thus, the hart that the task has been migrated to may not have synchronized -instruction storage and icache. +CMODX in the Kernel Space +------------------------- + +Dynamic ftrace +--------------------- + +Essentially, dynamic ftrace directs the control flow by inserting a function +call at each patchable function entry, and patches it dynamically at runtime to +enable or disable the redirection. In the case of RISC-V, 2 instructions, +AUIPC + JALR, are required to compose a function call. However, it is impossible +to patch 2 instructions and expect that a concurrent read-side executes them +without a race condition. This series makes atmoic code patching possible in +RISC-V ftrace. Kernel preemption makes things even worse as it allows the old +state to persist across the patching process with stop_machine(). + +In order to get rid of stop_machine() and run dynamic ftrace with full kernel +preemption, we partially initialize each patchable function entry at boot-time, +setting the first instruction to AUIPC, and the second to NOP. Now, atmoic +patching is possible because the kernel only has to update one instruction. +According to Ziccif, as long as an instruction is naturally aligned, the ISA +guarantee an atomic update. + +By fixing down the first instruction, AUIPC, the range of the ftrace trampoline +is limited to +-2K from the predetermined target, ftrace_caller, due to the lack +of immediate encoding space in RISC-V. To address the issue, we introduce +CALL_OPS, where an 8B naturally align metadata is added in front of each +pacthable function. The metadata is resolved at the first trampoline, then the +execution can be derect to another custom trampoline. + +CMODX in the User Space +----------------------- + +Though fence.i is an unprivileged instruction, the default Linux ABI prohibits +the use of fence.i in userspace applications. At any point the scheduler may +migrate a task onto a new hart. If migration occurs after the userspace +synchronized the icache and instruction storage with fence.i, the icache on the +new hart will no longer be clean. This is due to the behavior of fence.i only +affecting the hart that it is called on. Thus, the hart that the task has been +migrated to may not have synchronized instruction storage and icache. There are two ways to solve this problem: use the riscv_flush_icache() syscall, or use the ``PR_RISCV_SET_ICACHE_FLUSH_CTX`` prctl() and emit fence.i in diff --git a/Documentation/arch/riscv/hwprobe.rst b/Documentation/arch/riscv/hwprobe.rst index f60bf5991755..2aa9be272d5d 100644 --- a/Documentation/arch/riscv/hwprobe.rst +++ b/Documentation/arch/riscv/hwprobe.rst @@ -271,6 +271,10 @@ The following keys are defined: * :c:macro:`RISCV_HWPROBE_EXT_ZICBOM`: The Zicbom extension is supported, as ratified in commit 3dd606f ("Create cmobase-v1.0.pdf") of riscv-CMOs. + * :c:macro:`RISCV_HWPROBE_EXT_ZABHA`: The Zabha extension is supported as + ratified in commit 49f49c842ff9 ("Update to Rafified state") of + riscv-zabha. + * :c:macro:`RISCV_HWPROBE_KEY_CPUPERF_0`: Deprecated. Returns similar values to :c:macro:`RISCV_HWPROBE_KEY_MISALIGNED_SCALAR_PERF`, but the key was mistakenly classified as a bitmask rather than a value. @@ -335,3 +339,25 @@ The following keys are defined: * :c:macro:`RISCV_HWPROBE_KEY_ZICBOM_BLOCK_SIZE`: An unsigned int which represents the size of the Zicbom block in bytes. + +* :c:macro:`RISCV_HWPROBE_KEY_VENDOR_EXT_SIFIVE_0`: A bitmask containing the + sifive vendor extensions that are compatible with the + :c:macro:`RISCV_HWPROBE_BASE_BEHAVIOR_IMA`: base system behavior. + + * SIFIVE + + * :c:macro:`RISCV_HWPROBE_VENDOR_EXT_XSFVQMACCDOD`: The Xsfqmaccdod vendor + extension is supported in version 1.1 of SiFive Int8 Matrix Multiplication + Extensions Specification. + + * :c:macro:`RISCV_HWPROBE_VENDOR_EXT_XSFVQMACCQOQ`: The Xsfqmaccqoq vendor + extension is supported in version 1.1 of SiFive Int8 Matrix Multiplication + Instruction Extensions Specification. + + * :c:macro:`RISCV_HWPROBE_VENDOR_EXT_XSFVFNRCLIPXFQF`: The Xsfvfnrclipxfqf + vendor extension is supported in version 1.0 of SiFive FP32-to-int8 Ranged + Clip Instructions Extensions Specification. + + * :c:macro:`RISCV_HWPROBE_VENDOR_EXT_XSFVFWMACCQQQ`: The Xsfvfwmaccqqq + vendor extension is supported in version 1.0 of Matrix Multiply Accumulate + Instruction Extensions Specification.
\ No newline at end of file diff --git a/Documentation/block/ublk.rst b/Documentation/block/ublk.rst index 854f823b46c2..c368e1081b41 100644 --- a/Documentation/block/ublk.rst +++ b/Documentation/block/ublk.rst @@ -115,15 +115,15 @@ managing and controlling ublk devices with help of several control commands: - ``UBLK_CMD_START_DEV`` - After the server prepares userspace resources (such as creating per-queue - pthread & io_uring for handling ublk IO), this command is sent to the + After the server prepares userspace resources (such as creating I/O handler + threads & io_uring for handling ublk IO), this command is sent to the driver for allocating & exposing ``/dev/ublkb*``. Parameters set via ``UBLK_CMD_SET_PARAMS`` are applied for creating the device. - ``UBLK_CMD_STOP_DEV`` Halt IO on ``/dev/ublkb*`` and remove the device. When this command returns, - ublk server will release resources (such as destroying per-queue pthread & + ublk server will release resources (such as destroying I/O handler threads & io_uring). - ``UBLK_CMD_DEL_DEV`` @@ -208,15 +208,15 @@ managing and controlling ublk devices with help of several control commands: modify how I/O is handled while the ublk server is dying/dead (this is called the ``nosrv`` case in the driver code). - With just ``UBLK_F_USER_RECOVERY`` set, after one ubq_daemon(ublk server's io - handler) is dying, ublk does not delete ``/dev/ublkb*`` during the whole + With just ``UBLK_F_USER_RECOVERY`` set, after the ublk server exits, + ublk does not delete ``/dev/ublkb*`` during the whole recovery stage and ublk device ID is kept. It is ublk server's responsibility to recover the device context by its own knowledge. Requests which have not been issued to userspace are requeued. Requests which have been issued to userspace are aborted. - With ``UBLK_F_USER_RECOVERY_REISSUE`` additionally set, after one ubq_daemon - (ublk server's io handler) is dying, contrary to ``UBLK_F_USER_RECOVERY``, + With ``UBLK_F_USER_RECOVERY_REISSUE`` additionally set, after the ublk server + exits, contrary to ``UBLK_F_USER_RECOVERY``, requests which have been issued to userspace are requeued and will be re-issued to the new process after handling ``UBLK_CMD_END_USER_RECOVERY``. ``UBLK_F_USER_RECOVERY_REISSUE`` is designed for backends who tolerate @@ -241,10 +241,11 @@ can be controlled/accessed just inside this container. Data plane ---------- -ublk server needs to create per-queue IO pthread & io_uring for handling IO -commands via io_uring passthrough. The per-queue IO pthread -focuses on IO handling and shouldn't handle any control & management -tasks. +The ublk server should create dedicated threads for handling I/O. Each +thread should have its own io_uring through which it is notified of new +I/O, and through which it can complete I/O. These dedicated threads +should focus on IO handling and shouldn't handle any control & +management tasks. The's IO is assigned by a unique tag, which is 1:1 mapping with IO request of ``/dev/ublkb*``. @@ -265,6 +266,18 @@ with specified IO tag in the command data: destined to ``/dev/ublkb*``. This command is sent only once from the server IO pthread for ublk driver to setup IO forward environment. + Once a thread issues this command against a given (qid,tag) pair, the thread + registers itself as that I/O's daemon. In the future, only that I/O's daemon + is allowed to issue commands against the I/O. If any other thread attempts + to issue a command against a (qid,tag) pair for which the thread is not the + daemon, the command will fail. Daemons can be reset only be going through + recovery. + + The ability for every (qid,tag) pair to have its own independent daemon task + is indicated by the ``UBLK_F_PER_IO_DAEMON`` feature. If this feature is not + supported by the driver, daemons must be per-queue instead - i.e. all I/Os + associated to a single qid must be handled by the same task. + - ``UBLK_IO_COMMIT_AND_FETCH_REQ`` When an IO request is destined to ``/dev/ublkb*``, the driver stores diff --git a/Documentation/core-api/symbol-namespaces.rst b/Documentation/core-api/symbol-namespaces.rst index 06f766a6aab2..32fc73dc5529 100644 --- a/Documentation/core-api/symbol-namespaces.rst +++ b/Documentation/core-api/symbol-namespaces.rst @@ -6,18 +6,8 @@ The following document describes how to use Symbol Namespaces to structure the export surface of in-kernel symbols exported through the family of EXPORT_SYMBOL() macros. -.. Table of Contents - - === 1 Introduction - === 2 How to define Symbol Namespaces - --- 2.1 Using the EXPORT_SYMBOL macros - --- 2.2 Using the DEFAULT_SYMBOL_NAMESPACE define - === 3 How to use Symbols exported in Namespaces - === 4 Loading Modules that use namespaced Symbols - === 5 Automatically creating MODULE_IMPORT_NS statements - -1. Introduction -=============== +Introduction +============ Symbol Namespaces have been introduced as a means to structure the export surface of the in-kernel API. It allows subsystem maintainers to partition @@ -28,15 +18,18 @@ kernel. As of today, modules that make use of symbols exported into namespaces, are required to import the namespace. Otherwise the kernel will, depending on its configuration, reject loading the module or warn about a missing import. -2. How to define Symbol Namespaces -================================== +Additionally, it is possible to put symbols into a module namespace, strictly +limiting which modules are allowed to use these symbols. + +How to define Symbol Namespaces +=============================== Symbols can be exported into namespace using different methods. All of them are changing the way EXPORT_SYMBOL and friends are instrumented to create ksymtab entries. -2.1 Using the EXPORT_SYMBOL macros -================================== +Using the EXPORT_SYMBOL macros +------------------------------ In addition to the macros EXPORT_SYMBOL() and EXPORT_SYMBOL_GPL(), that allow exporting of kernel symbols to the kernel symbol table, variants of these are @@ -54,8 +47,8 @@ refer to ``NULL``. There is no default namespace if none is defined. ``modpost`` and kernel/module/main.c make use the namespace at build time or module load time, respectively. -2.2 Using the DEFAULT_SYMBOL_NAMESPACE define -============================================= +Using the DEFAULT_SYMBOL_NAMESPACE define +----------------------------------------- Defining namespaces for all symbols of a subsystem can be very verbose and may become hard to maintain. Therefore a default define (DEFAULT_SYMBOL_NAMESPACE) @@ -83,8 +76,24 @@ unit as preprocessor statement. The above example would then read:: within the corresponding compilation unit before the #include for <linux/export.h>. Typically it's placed before the first #include statement. -3. How to use Symbols exported in Namespaces -============================================ +Using the EXPORT_SYMBOL_GPL_FOR_MODULES() macro +----------------------------------------------- + +Symbols exported using this macro are put into a module namespace. This +namespace cannot be imported. + +The macro takes a comma separated list of module names, allowing only those +modules to access this symbol. Simple tail-globs are supported. + +For example:: + + EXPORT_SYMBOL_GPL_FOR_MODULES(preempt_notifier_inc, "kvm,kvm-*") + +will limit usage of this symbol to modules whoes name matches the given +patterns. + +How to use Symbols exported in Namespaces +========================================= In order to use symbols that are exported into namespaces, kernel modules need to explicitly import these namespaces. Otherwise the kernel might reject to @@ -106,11 +115,10 @@ inspected with modinfo:: It is advisable to add the MODULE_IMPORT_NS() statement close to other module -metadata definitions like MODULE_AUTHOR() or MODULE_LICENSE(). Refer to section -5. for a way to create missing import statements automatically. +metadata definitions like MODULE_AUTHOR() or MODULE_LICENSE(). -4. Loading Modules that use namespaced Symbols -============================================== +Loading Modules that use namespaced Symbols +=========================================== At module loading time (e.g. ``insmod``), the kernel will check each symbol referenced from the module for its availability and whether the namespace it @@ -121,8 +129,8 @@ allow loading of modules that don't satisfy this precondition, a configuration option is available: Setting MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS=y will enable loading regardless, but will emit a warning. -5. Automatically creating MODULE_IMPORT_NS statements -===================================================== +Automatically creating MODULE_IMPORT_NS statements +================================================== Missing namespaces imports can easily be detected at build time. In fact, modpost will emit a warning if a module uses a symbol from a namespace @@ -154,3 +162,6 @@ in-tree modules:: You can also run nsdeps for external module builds. A typical usage is:: $ make -C <path_to_kernel_src> M=$PWD nsdeps + +Note: it will happily generate an import statement for the module namespace; +which will not work and generates build and runtime failures. diff --git a/Documentation/devicetree/bindings/arm/arm,coresight-static-replicator.yaml b/Documentation/devicetree/bindings/arm/arm,coresight-static-replicator.yaml index a6f793ea03b6..0c1017affbad 100644 --- a/Documentation/devicetree/bindings/arm/arm,coresight-static-replicator.yaml +++ b/Documentation/devicetree/bindings/arm/arm,coresight-static-replicator.yaml @@ -30,6 +30,19 @@ properties: power-domains: maxItems: 1 + clocks: + minItems: 1 + maxItems: 3 + + clock-names: + oneOf: + - items: + - enum: [apb_pclk, atclk] + - items: # Zynq-700 + - const: apb_pclk + - const: dbg_trc + - const: dbg_apb + in-ports: $ref: /schemas/graph.yaml#/properties/ports additionalProperties: false diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7380.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7380.yaml index ff4f5c21c548..8dae89ecb64d 100644 --- a/Documentation/devicetree/bindings/iio/adc/adi,ad7380.yaml +++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7380.yaml @@ -25,6 +25,7 @@ description: | * https://www.analog.com/en/products/ad7386-4.html * https://www.analog.com/en/products/ad7387-4.html * https://www.analog.com/en/products/ad7388-4.html + * https://www.analog.com/en/products/ad7389-4.html * https://www.analog.com/en/products/adaq4370-4.html * https://www.analog.com/en/products/adaq4380-4.html * https://www.analog.com/en/products/adaq4381-4.html @@ -49,6 +50,7 @@ properties: - adi,ad7386-4 - adi,ad7387-4 - adi,ad7388-4 + - adi,ad7389-4 - adi,adaq4370-4 - adi,adaq4380-4 - adi,adaq4381-4 @@ -213,6 +215,15 @@ allOf: properties: refin-supply: false + # adi,ad7389-4 is internal reference only + - if: + properties: + compatible: + const: adi,ad7389-4 + then: + properties: + refio-supply: false + # adaq devices need more supplies and using channel to declare gain property # only applies to adaq devices - if: diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7476.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7476.yaml index 44c671eeda73..d0cb32f136e5 100644 --- a/Documentation/devicetree/bindings/iio/adc/adi,ad7476.yaml +++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7476.yaml @@ -17,35 +17,40 @@ description: | properties: compatible: - enum: - - adi,ad7091 - - adi,ad7091r - - adi,ad7273 - - adi,ad7274 - - adi,ad7276 - - adi,ad7277 - - adi,ad7278 - - adi,ad7466 - - adi,ad7467 - - adi,ad7468 - - adi,ad7475 - - adi,ad7476 - - adi,ad7476a - - adi,ad7477 - - adi,ad7477a - - adi,ad7478 - - adi,ad7478a - - adi,ad7495 - - adi,ad7910 - - adi,ad7920 - - adi,ad7940 - - ti,adc081s - - ti,adc101s - - ti,adc121s - - ti,ads7866 - - ti,ads7867 - - ti,ads7868 - - lltc,ltc2314-14 + oneOf: + - items: + - enum: + - adi,ad7091 + - adi,ad7091r + - adi,ad7273 + - adi,ad7274 + - adi,ad7276 + - adi,ad7277 + - adi,ad7278 + - adi,ad7466 + - adi,ad7467 + - adi,ad7468 + - adi,ad7475 + - adi,ad7476 + - adi,ad7476a + - adi,ad7477 + - adi,ad7477a + - adi,ad7478 + - adi,ad7478a + - adi,ad7495 + - adi,ad7910 + - adi,ad7920 + - adi,ad7940 + - ti,adc081s + - ti,adc101s + - ti,adc121s + - ti,ads7866 + - ti,ads7867 + - ti,ads7868 + - lltc,ltc2314-14 + - items: + - const: rohm,bu79100g + - const: ti,ads7866 reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7606.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7606.yaml index 52d3f1ce3367..29f12d650442 100644 --- a/Documentation/devicetree/bindings/iio/adc/adi,ad7606.yaml +++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7606.yaml @@ -45,6 +45,14 @@ properties: "#size-cells": const: 0 + '#trigger-source-cells': + description: | + Cell indicates the output signal: 0 = BUSY, 1 = FIRSTDATA. + + For convenience, macros for these values are available in + dt-bindings/iio/adc/adi,ad7606.h. + const: 1 + # According to the datasheet, "Data is clocked in from SDI on the falling # edge of SCLK, while data is clocked out on DOUTA on the rising edge of # SCLK". Also, even if not stated textually in the datasheet, it is made diff --git a/Documentation/devicetree/bindings/iio/adc/amlogic,meson-saradc.yaml b/Documentation/devicetree/bindings/iio/adc/amlogic,meson-saradc.yaml index b0962a4583ac..bb9825e7346d 100644 --- a/Documentation/devicetree/bindings/iio/adc/amlogic,meson-saradc.yaml +++ b/Documentation/devicetree/bindings/iio/adc/amlogic,meson-saradc.yaml @@ -23,6 +23,7 @@ properties: - amlogic,meson8m2-saradc - amlogic,meson-gxbb-saradc - amlogic,meson-gxl-saradc + - amlogic,meson-gxlx-saradc - amlogic,meson-gxm-saradc - amlogic,meson-axg-saradc - amlogic,meson-g12a-saradc diff --git a/Documentation/devicetree/bindings/iio/adc/mediatek,mt2701-auxadc.yaml b/Documentation/devicetree/bindings/iio/adc/mediatek,mt2701-auxadc.yaml index 6168b44ea72c..b489c984c1bb 100644 --- a/Documentation/devicetree/bindings/iio/adc/mediatek,mt2701-auxadc.yaml +++ b/Documentation/devicetree/bindings/iio/adc/mediatek,mt2701-auxadc.yaml @@ -34,6 +34,7 @@ properties: - const: mediatek,mt2701-auxadc - items: - enum: + - mediatek,mt6893-auxadc - mediatek,mt8183-auxadc - mediatek,mt8186-auxadc - mediatek,mt8188-auxadc diff --git a/Documentation/devicetree/bindings/iio/adc/microchip,mcp3911.yaml b/Documentation/devicetree/bindings/iio/adc/microchip,mcp3911.yaml index 06951ec5f5da..3a69ec60edb9 100644 --- a/Documentation/devicetree/bindings/iio/adc/microchip,mcp3911.yaml +++ b/Documentation/devicetree/bindings/iio/adc/microchip,mcp3911.yaml @@ -32,6 +32,9 @@ properties: spi-max-frequency: maximum: 20000000 + reset-gpios: + maxItems: 1 + clocks: description: | Phandle and clock identifier for external sampling clock. @@ -71,6 +74,7 @@ unevaluatedProperties: false examples: - | + #include <dt-bindings/gpio/gpio.h> spi { #address-cells = <1>; #size-cells = <0>; @@ -80,6 +84,7 @@ examples: reg = <0>; interrupt-parent = <&gpio5>; interrupts = <15 2>; + reset-gpios = <&gpio1 10 GPIO_ACTIVE_LOW>; spi-max-frequency = <20000000>; microchip,device-addr = <0>; vref-supply = <&vref_reg>; diff --git a/Documentation/devicetree/bindings/iio/adc/nuvoton,nct7201.yaml b/Documentation/devicetree/bindings/iio/adc/nuvoton,nct7201.yaml new file mode 100644 index 000000000000..8ce7d415d956 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/nuvoton,nct7201.yaml @@ -0,0 +1,70 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/adc/nuvoton,nct7201.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Nuvoton nct7201 and similar ADCs + +maintainers: + - Eason Yang <j2anfernee@gmail.com> + +description: | + The NCT7201/NCT7202 is a Nuvoton Hardware Monitor IC, contains up to 12 + voltage monitoring channels, with SMBus interface, and up to 4 sets SMBus + address selection by ADDR connection. It also provides ALERT# signal for + event notification and reset input RSTIN# to recover it from a fault + condition. + + NCT7201 contains 8 voltage monitor inputs (VIN1~VIN8). + NCT7202 contains 12 voltage monitor inputs (VIN1~VIN12). + +properties: + compatible: + enum: + - nuvoton,nct7201 + - nuvoton,nct7202 + + reg: + maxItems: 1 + + vdd-supply: + description: + A 3.3V to supply that powers the chip. + + vref-supply: + description: + The regulator supply for the ADC reference voltage. + + interrupts: + maxItems: 1 + + reset-gpios: + maxItems: 1 + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + #include <dt-bindings/gpio/gpio.h> + #include <dt-bindings/interrupt-controller/irq.h> + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + adc@1d { + compatible = "nuvoton,nct7202"; + reg = <0x1d>; + vdd-supply = <&vdd>; + vref-supply = <&vref>; + interrupt-parent = <&gpio3>; + interrupts = <30 IRQ_TYPE_LEVEL_LOW>; + reset-gpios = <&gpio3 28 GPIO_ACTIVE_LOW>; + }; + }; +... diff --git a/Documentation/devicetree/bindings/iio/adc/rohm,bd79104.yaml b/Documentation/devicetree/bindings/iio/adc/rohm,bd79104.yaml new file mode 100644 index 000000000000..2a8ad4fdfc6b --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/rohm,bd79104.yaml @@ -0,0 +1,69 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/adc/rohm,bd79104.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ROHM Semiconductor BD79104 ADC + +maintainers: + - Matti Vaittinen <mazziesaccount@gmail.com> + +description: | + 12 bit SPI ADC with 8 channels. + +properties: + compatible: + const: rohm,bd79104 + + reg: + maxItems: 1 + + vdd-supply: true + iovdd-supply: true + +# The component data-sheet says the frequency is 20M. I, however, found +# that the ROHM evaluation board BD79104FV-EVK-001 had problems with 20M. +# I have successfully used it with 4M. My _assumption_ is that this is not +# the limitation of the component itself, but a limitation of the EVK. + spi-max-frequency: + maximum: 20000000 + + "#io-channel-cells": + const: 1 + + spi-cpha: true + spi-cpol: true + +required: + - compatible + - reg + - vdd-supply + - iovdd-supply + - spi-cpha + - spi-cpol + +allOf: + - $ref: /schemas/spi/spi-peripheral-props.yaml# + +unevaluatedProperties: false + +examples: + - | + #include <dt-bindings/interrupt-controller/irq.h> + spi { + #address-cells = <1>; + #size-cells = <0>; + + adc@0 { + compatible = "rohm,bd79104"; + reg = <0>; + vdd-supply = <&vdd_supply>; + iovdd-supply = <&iovdd_supply>; + spi-max-frequency = <4000000>; + spi-cpha; + spi-cpol; + #io-channel-cells = <1>; + }; + }; +... diff --git a/Documentation/devicetree/bindings/iio/adc/rohm,bd79124.yaml b/Documentation/devicetree/bindings/iio/adc/rohm,bd79124.yaml new file mode 100644 index 000000000000..503285823376 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/rohm,bd79124.yaml @@ -0,0 +1,114 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/adc/rohm,bd79124.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ROHM BD79124 ADC/GPO + +maintainers: + - Matti Vaittinen <mazziesaccount@gmail.com> + +description: | + The ROHM BD79124 is a 12-bit, 8-channel, SAR ADC. The ADC supports + an automatic measurement mode, with an alarm interrupt for out-of-window + measurements. ADC input pins can be also configured as general purpose + outputs. + +properties: + compatible: + const: rohm,bd79124 + + reg: + description: + I2C slave address. + maxItems: 1 + + interrupts: + maxItems: 1 + + gpio-controller: true + + "#gpio-cells": + const: 1 + description: + The pin number. + + vdd-supply: true + + iovdd-supply: true + + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + +patternProperties: + "^channel@[0-7]+$": + type: object + $ref: /schemas/iio/adc/adc.yaml# + description: Represents ADC channel. + + properties: + reg: + description: AIN pin number + minimum: 0 + maximum: 7 + + required: + - reg + + additionalProperties: false + +required: + - compatible + - reg + - iovdd-supply + - vdd-supply + +additionalProperties: false + +examples: + - | + #include <dt-bindings/interrupt-controller/irq.h> + #include <dt-bindings/leds/common.h> + i2c { + #address-cells = <1>; + #size-cells = <0>; + adc: adc@10 { + compatible = "rohm,bd79124"; + reg = <0x10>; + + interrupt-parent = <&gpio1>; + interrupts = <29 8>; + + vdd-supply = <&dummyreg>; + iovdd-supply = <&dummyreg>; + + #address-cells = <1>; + #size-cells = <0>; + + channel@0 { + reg = <0>; + }; + channel@1 { + reg = <1>; + }; + channel@2 { + reg = <2>; + }; + channel@3 { + reg = <3>; + }; + channel@4 { + reg = <4>; + }; + channel@5 { + reg = <5>; + }; + channel@6 { + reg = <6>; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/iio/adc/st,stm32-adc.yaml b/Documentation/devicetree/bindings/iio/adc/st,stm32-adc.yaml index ef9dcc365eab..17bb60e18a1c 100644 --- a/Documentation/devicetree/bindings/iio/adc/st,stm32-adc.yaml +++ b/Documentation/devicetree/bindings/iio/adc/st,stm32-adc.yaml @@ -498,7 +498,7 @@ patternProperties: examples: - | // Example 1: with stm32f429, ADC1, single-ended channel 8 - adc123: adc@40012000 { + adc123: adc@40012000 { compatible = "st,stm32f4-adc-core"; reg = <0x40012000 0x400>; interrupts = <18>; @@ -512,28 +512,28 @@ examples: #address-cells = <1>; #size-cells = <0>; adc@0 { - compatible = "st,stm32f4-adc"; - #io-channel-cells = <1>; - reg = <0x0>; - clocks = <&rcc 0 168>; - interrupt-parent = <&adc123>; - interrupts = <0>; - st,adc-channels = <8>; - dmas = <&dma2 0 0 0x400 0x0>; - dma-names = "rx"; - assigned-resolution-bits = <8>; + compatible = "st,stm32f4-adc"; + #io-channel-cells = <1>; + reg = <0x0>; + clocks = <&rcc 0 168>; + interrupt-parent = <&adc123>; + interrupts = <0>; + st,adc-channels = <8>; + dmas = <&dma2 0 0 0x400 0x0>; + dma-names = "rx"; + assigned-resolution-bits = <8>; }; // ... // other adc child nodes follow... - }; + }; - | // Example 2: with stm32mp157c to setup ADC1 with: // - channels 0 & 1 as single-ended // - channels 2 & 3 as differential (with resp. 6 & 7 negative inputs) - #include <dt-bindings/interrupt-controller/arm-gic.h> - #include <dt-bindings/clock/stm32mp1-clks.h> - adc12: adc@48003000 { + #include <dt-bindings/interrupt-controller/arm-gic.h> + #include <dt-bindings/clock/stm32mp1-clks.h> + adc12: adc@48003000 { compatible = "st,stm32mp1-adc-core"; reg = <0x48003000 0x400>; interrupts = <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>, @@ -550,27 +550,27 @@ examples: #address-cells = <1>; #size-cells = <0>; adc@0 { - compatible = "st,stm32mp1-adc"; - #io-channel-cells = <1>; - reg = <0x0>; - interrupt-parent = <&adc12>; - interrupts = <0>; - st,adc-channels = <0 1>; - st,adc-diff-channels = <2 6>, <3 7>; - st,min-sample-time-nsecs = <5000>; - dmas = <&dmamux1 9 0x400 0x05>; - dma-names = "rx"; + compatible = "st,stm32mp1-adc"; + #io-channel-cells = <1>; + reg = <0x0>; + interrupt-parent = <&adc12>; + interrupts = <0>; + st,adc-channels = <0 1>; + st,adc-diff-channels = <2 6>, <3 7>; + st,min-sample-time-nsecs = <5000>; + dmas = <&dmamux1 9 0x400 0x05>; + dma-names = "rx"; }; // ... // other adc child node follow... - }; + }; - | // Example 3: with stm32mp157c to setup ADC2 with: // - internal channels 13, 14, 15. - #include <dt-bindings/interrupt-controller/arm-gic.h> - #include <dt-bindings/clock/stm32mp1-clks.h> - adc122: adc@48003000 { + #include <dt-bindings/interrupt-controller/arm-gic.h> + #include <dt-bindings/clock/stm32mp1-clks.h> + adc122: adc@48003000 { compatible = "st,stm32mp1-adc-core"; reg = <0x48003000 0x400>; interrupts = <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>, @@ -587,28 +587,28 @@ examples: #address-cells = <1>; #size-cells = <0>; adc@100 { - compatible = "st,stm32mp1-adc"; - #io-channel-cells = <1>; - reg = <0x100>; - interrupts = <1>; - #address-cells = <1>; - #size-cells = <0>; - channel@13 { - reg = <13>; - label = "vrefint"; - st,min-sample-time-ns = <9000>; - }; - channel@14 { - reg = <14>; - label = "vddcore"; - st,min-sample-time-ns = <9000>; - }; - channel@15 { - reg = <15>; - label = "vbat"; - st,min-sample-time-ns = <9000>; - }; + compatible = "st,stm32mp1-adc"; + #io-channel-cells = <1>; + reg = <0x100>; + interrupts = <1>; + #address-cells = <1>; + #size-cells = <0>; + channel@13 { + reg = <13>; + label = "vrefint"; + st,min-sample-time-ns = <9000>; + }; + channel@14 { + reg = <14>; + label = "vddcore"; + st,min-sample-time-ns = <9000>; + }; + channel@15 { + reg = <15>; + label = "vbat"; + st,min-sample-time-ns = <9000>; + }; }; - }; + }; ... diff --git a/Documentation/devicetree/bindings/iio/chemical/winsen,mhz19b.yaml b/Documentation/devicetree/bindings/iio/chemical/winsen,mhz19b.yaml new file mode 100644 index 000000000000..2a6ddb33f163 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/chemical/winsen,mhz19b.yaml @@ -0,0 +1,33 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/chemical/winsen,mhz19b.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MHZ19B CO2 sensor + +maintainers: + - Gyeyoung Baek <gye976@gmail.com> + +properties: + compatible: + const: winsen,mhz19b + + vin-supply: + description: Regulator that provides power to the sensor + +required: + - compatible + - vin-supply + +additionalProperties: false + +examples: + - | + serial { + co2-sensor { + compatible = "winsen,mhz19b"; + vin-supply = <&vdd>; + }; + }; +... diff --git a/Documentation/devicetree/bindings/iio/dac/adi,ad3530r.yaml b/Documentation/devicetree/bindings/iio/dac/adi,ad3530r.yaml new file mode 100644 index 000000000000..a355d52a9d64 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/dac/adi,ad3530r.yaml @@ -0,0 +1,100 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/dac/adi,ad3530r.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices AD3530R and Similar DACs + +maintainers: + - Kim Seer Paller <kimseer.paller@analog.com> + +description: | + The AD3530/AD3530R (8-channel) and AD3531/AD3531R (4-channel) are low-power, + 16-bit, buffered voltage output digital-to-analog converters (DACs) with + software-programmable gain controls, providing full-scale output spans of 2.5V + or 5V for reference voltages of 2.5V. These devices operate from a single 2.7V + to 5.5V supply and are guaranteed monotonic by design. The "R" variants + include a 2.5V, 5ppm/°C internal reference, which is disabled by default. + Datasheet can be found here: + https://www.analog.com/media/en/technical-documentation/data-sheets/ad3530_ad530r.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/ad3531-ad3531r.pdf + +properties: + compatible: + enum: + - adi,ad3530 + - adi,ad3530r + - adi,ad3531 + - adi,ad3531r + + reg: + maxItems: 1 + + spi-max-frequency: + maximum: 50000000 + + vdd-supply: + description: Power Supply Input. + + iovdd-supply: + description: Digital Power Supply Input. + + io-channels: + description: + ADC channel used to monitor internal die temperature, output voltages, and + current of a selected channel via the MUXOUT pin. + maxItems: 1 + + ref-supply: + description: + Reference Input/Output. The voltage at the REF pin sets the full-scale + range of all channels. If not provided the internal reference is used and + also provided on the VREF pin. + + reset-gpios: + description: + Active low signal that is falling edge sensitive. When it is deasserted, + the digital core initialization is performed and all DAC registers except + the Interface Configuration A register are reset to their default values. + maxItems: 1 + + ldac-gpios: + description: + LDAC pin to be used as a hardware trigger to update the DAC channels. If + not present, the DAC channels are updated by Software LDAC. + maxItems: 1 + + adi,range-double: + description: + Configure the output range for all channels. If the property is present, + the output will range from 0V to 2Vref. If the property is not present, + the output will range from 0V to Vref. + type: boolean + +required: + - compatible + - reg + - vdd-supply + - iovdd-supply + +allOf: + - $ref: /schemas/spi/spi-peripheral-props.yaml# + +unevaluatedProperties: false + +examples: + - | + spi { + #address-cells = <1>; + #size-cells = <0>; + dac@0 { + compatible = "adi,ad3530r"; + reg = <0>; + spi-max-frequency = <1000000>; + + vdd-supply = <&vdd>; + iovdd-supply = <&iovdd>; + }; + }; +... diff --git a/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml b/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml index 2d2561a52683..547044b8e246 100644 --- a/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml +++ b/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml @@ -217,7 +217,7 @@ required: - reg - spi-max-frequency -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/iio/dac/adi,ad7293.yaml b/Documentation/devicetree/bindings/iio/dac/adi,ad7293.yaml index 5ee80bf6aa11..f994c1ef6d41 100644 --- a/Documentation/devicetree/bindings/iio/dac/adi,ad7293.yaml +++ b/Documentation/devicetree/bindings/iio/dac/adi,ad7293.yaml @@ -27,6 +27,8 @@ properties: vdrive-supply: true + vrefin-supply: true + reset-gpios: maxItems: 1 diff --git a/Documentation/devicetree/bindings/iio/dac/adi,ltc2664.yaml b/Documentation/devicetree/bindings/iio/dac/adi,ltc2664.yaml index 33490853497b..1aece3392b77 100644 --- a/Documentation/devicetree/bindings/iio/dac/adi,ltc2664.yaml +++ b/Documentation/devicetree/bindings/iio/dac/adi,ltc2664.yaml @@ -144,7 +144,7 @@ required: allOf: - $ref: /schemas/spi/spi-peripheral-props.yaml# -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/iio/dac/adi,ltc2672.yaml b/Documentation/devicetree/bindings/iio/dac/adi,ltc2672.yaml index c8c434c10643..3c8e5781e42c 100644 --- a/Documentation/devicetree/bindings/iio/dac/adi,ltc2672.yaml +++ b/Documentation/devicetree/bindings/iio/dac/adi,ltc2672.yaml @@ -124,7 +124,7 @@ required: allOf: - $ref: /schemas/spi/spi-peripheral-props.yaml# -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/iio/dac/microchip,mcp4821.yaml b/Documentation/devicetree/bindings/iio/dac/microchip,mcp4821.yaml index 0dc577c33918..26011b5639d8 100644 --- a/Documentation/devicetree/bindings/iio/dac/microchip,mcp4821.yaml +++ b/Documentation/devicetree/bindings/iio/dac/microchip,mcp4821.yaml @@ -64,7 +64,7 @@ required: - reg - vdd-supply -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/iio/dac/rohm,bd79703.yaml b/Documentation/devicetree/bindings/iio/dac/rohm,bd79703.yaml index 941a49c93943..c00fa50e42e8 100644 --- a/Documentation/devicetree/bindings/iio/dac/rohm,bd79703.yaml +++ b/Documentation/devicetree/bindings/iio/dac/rohm,bd79703.yaml @@ -5,19 +5,26 @@ $id: http://devicetree.org/schemas/iio/dac/rohm,bd79703.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: ROHM BD79703 DAC device driver +title: ROHM BD79700, BD79701, BD79702 and BD79703 DACs maintainers: - Matti Vaittinen <mazziesaccount@gmail.com> description: | - The ROHM BD79703 is a 6 channel, 8-bit DAC. - Datasheet can be found here: + The ROHM BD7970[0,1,2,3] are 8-bit DACs. The BD79700 has 2 channels, + BD79701 3 channels, BD79702 4 channels and BD79703 has 6 channels. + Datasheets for BD79702 and BD79703 can be found from https://fscdn.rohm.com/en/products/databook/datasheet/ic/data_converter/dac/bd79702fv-lb_bd79703fv-lb-e.pdf + and for the BD79700 and the BD79701 from + https://fscdn.rohm.com/en/products/databook/datasheet/ic/data_converter/dac/bd79700fvm-lb_bd79701fvm-lb-e.pdf properties: compatible: - const: rohm,bd79703 + enum: + - rohm,bd79700 + - rohm,bd79701 + - rohm,bd79702 + - rohm,bd79703 reg: maxItems: 1 @@ -27,23 +34,35 @@ properties: vfs-supply: description: - The regulator to use as a full scale voltage. The voltage should be between 2.7V .. VCC + The regulator to use as a full scale voltage. The voltage should be + between 2.7V .. VCC. Not present on BD79700 and BD79701. vcc-supply: description: - The regulator supplying the operating voltage. Should be between 2.7V ... 5.5V + The regulator supplying the operating voltage. Should be between + 2.7V ... 5.5V. Is used also as a Vfs on BD79700 and BD79701. required: - compatible - reg - spi-max-frequency - - vfs-supply - vcc-supply +if: + properties: + compatible: + contains: + enum: + - rohm,bd79702 + - rohm,bd79703 +then: + required: + - vfs-supply + allOf: - $ref: /schemas/spi/spi-peripheral-props.yaml# -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/iio/filter/adi,admv8818.yaml b/Documentation/devicetree/bindings/iio/filter/adi,admv8818.yaml index b77e855bd594..ff0cb553e871 100644 --- a/Documentation/devicetree/bindings/iio/filter/adi,admv8818.yaml +++ b/Documentation/devicetree/bindings/iio/filter/adi,admv8818.yaml @@ -44,6 +44,24 @@ properties: '#clock-cells': const: 0 + adi,lpf-margin-mhz: + description: + Sets the minimum distance between the fundamental frequency of `rf_in` + and the corner frequency of the low-pass, output filter when operated in + 'auto' mode. The selected low-pass corner frequency will be greater than, + or equal to, `rf_in` + `lpf-margin-hz`. If not setting is found that + satisfies this relationship the filter will be put into 'bypass'. + default: 0 + + adi,hpf-margin-mhz: + description: + Sets the minimum distance between the fundamental frequency of `rf_in` + and the corner frequency of the high-pass, input filter when operated in + 'auto' mode. The selected high-pass corner frequency will be less than, + or equal to, `rf_in` - `hpf-margin-hz`. If not setting is found that + satisfies this relationship the filter will be put into 'bypass'. + default: 0 + required: - compatible - reg @@ -61,6 +79,8 @@ examples: spi-max-frequency = <10000000>; clocks = <&admv8818_rfin>; clock-names = "rf_in"; + adi,lpf-margin-mhz = <300>; + adi,hpf-margin-mhz = <300>; }; }; ... diff --git a/Documentation/devicetree/bindings/iio/imu/adi,adis16550.yaml b/Documentation/devicetree/bindings/iio/imu/adi,adis16550.yaml index a4c273c7a67f..cf5324de4fd6 100644 --- a/Documentation/devicetree/bindings/iio/imu/adi,adis16550.yaml +++ b/Documentation/devicetree/bindings/iio/imu/adi,adis16550.yaml @@ -53,7 +53,7 @@ required: allOf: - $ref: /schemas/spi/spi-peripheral-props.yaml# -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml b/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml index 7e4492bbd027..d4d4e5c3d856 100644 --- a/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml +++ b/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml @@ -39,7 +39,16 @@ properties: maxItems: 1 interrupts: - maxItems: 1 + minItems: 1 + maxItems: 2 + + interrupt-names: + minItems: 1 + maxItems: 2 + items: + enum: + - INT1 + - INT2 drive-open-drain: type: boolean @@ -76,6 +85,7 @@ examples: reg = <0x68>; interrupt-parent = <&gpio2>; interrupts = <7 IRQ_TYPE_EDGE_FALLING>; + interrupt-names = "INT1"; vdd-supply = <&vdd>; vddio-supply = <&vddio>; }; @@ -95,6 +105,7 @@ examples: spi-cpol; interrupt-parent = <&gpio1>; interrupts = <2 IRQ_TYPE_EDGE_FALLING>; + interrupt-names = "INT1"; vdd-supply = <&vdd>; vddio-supply = <&vddio>; }; diff --git a/Documentation/devicetree/bindings/iio/light/bh1750.yaml b/Documentation/devicetree/bindings/iio/light/bh1750.yaml index 1a88b3c253d5..9df81c271411 100644 --- a/Documentation/devicetree/bindings/iio/light/bh1750.yaml +++ b/Documentation/devicetree/bindings/iio/light/bh1750.yaml @@ -24,6 +24,10 @@ properties: reg: maxItems: 1 + reset-gpios: + description: GPIO connected to the DVI reset pin (active low) + maxItems: 1 + required: - compatible - reg @@ -32,6 +36,7 @@ additionalProperties: false examples: - | + #include <dt-bindings/gpio/gpio.h> i2c { #address-cells = <1>; #size-cells = <0>; @@ -39,6 +44,7 @@ examples: light-sensor@23 { compatible = "rohm,bh1750"; reg = <0x23>; + reset-gpios = <&gpio2 17 GPIO_ACTIVE_LOW>; }; }; diff --git a/Documentation/devicetree/bindings/iio/pressure/honeywell,hsc030pa.yaml b/Documentation/devicetree/bindings/iio/pressure/honeywell,hsc030pa.yaml index 89977b9f01cf..412c7bcc310f 100644 --- a/Documentation/devicetree/bindings/iio/pressure/honeywell,hsc030pa.yaml +++ b/Documentation/devicetree/bindings/iio/pressure/honeywell,hsc030pa.yaml @@ -102,7 +102,7 @@ required: allOf: - $ref: /schemas/spi/spi-peripheral-props.yaml -additionalProperties: false +unevaluatedProperties: false dependentSchemas: honeywell,pmin-pascal: diff --git a/Documentation/devicetree/bindings/iio/pressure/honeywell,mprls0025pa.yaml b/Documentation/devicetree/bindings/iio/pressure/honeywell,mprls0025pa.yaml index 6994b30015bd..c756aa863103 100644 --- a/Documentation/devicetree/bindings/iio/pressure/honeywell,mprls0025pa.yaml +++ b/Documentation/devicetree/bindings/iio/pressure/honeywell,mprls0025pa.yaml @@ -115,7 +115,7 @@ allOf: honeywell,pmin-pascal: false honeywell,pmax-pascal: false -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/interconnect/qcom,msm8939.yaml b/Documentation/devicetree/bindings/interconnect/qcom,msm8939.yaml index 4b08be72bbd7..534644cccdcb 100644 --- a/Documentation/devicetree/bindings/interconnect/qcom,msm8939.yaml +++ b/Documentation/devicetree/bindings/interconnect/qcom,msm8939.yaml @@ -70,8 +70,8 @@ examples: reg = <0x00580000 0x14000>; #interconnect-cells = <1>; - snoc_mm: interconnect-snoc { - compatible = "qcom,msm8939-snoc-mm"; - #interconnect-cells = <1>; - }; + snoc_mm: interconnect-snoc { + compatible = "qcom,msm8939-snoc-mm"; + #interconnect-cells = <1>; + }; }; diff --git a/Documentation/devicetree/bindings/interconnect/qcom,msm8953.yaml b/Documentation/devicetree/bindings/interconnect/qcom,msm8953.yaml index 343ff62d7b65..56cdb77b369a 100644 --- a/Documentation/devicetree/bindings/interconnect/qcom,msm8953.yaml +++ b/Documentation/devicetree/bindings/interconnect/qcom,msm8953.yaml @@ -84,17 +84,17 @@ additionalProperties: false examples: - | - #include <dt-bindings/clock/qcom,gcc-msm8953.h> + #include <dt-bindings/clock/qcom,gcc-msm8953.h> - snoc: interconnect@580000 { - compatible = "qcom,msm8953-snoc"; - reg = <0x580000 0x16080>; + interconnect@580000 { + compatible = "qcom,msm8953-snoc"; + reg = <0x580000 0x16080>; - #interconnect-cells = <2>; + #interconnect-cells = <2>; - snoc_mm: interconnect-snoc { - compatible = "qcom,msm8953-snoc-mm"; + interconnect-snoc { + compatible = "qcom,msm8953-snoc-mm"; - #interconnect-cells = <2>; - }; - }; + #interconnect-cells = <2>; + }; + }; diff --git a/Documentation/devicetree/bindings/interconnect/qcom,msm8974.yaml b/Documentation/devicetree/bindings/interconnect/qcom,msm8974.yaml index 8004c4baf397..95ce25ce1f7d 100644 --- a/Documentation/devicetree/bindings/interconnect/qcom,msm8974.yaml +++ b/Documentation/devicetree/bindings/interconnect/qcom,msm8974.yaml @@ -50,13 +50,13 @@ additionalProperties: false examples: - | - #include <dt-bindings/clock/qcom,rpmcc.h> - - bimc: interconnect@fc380000 { - reg = <0xfc380000 0x6a000>; - compatible = "qcom,msm8974-bimc"; - #interconnect-cells = <1>; - clock-names = "bus", "bus_a"; - clocks = <&rpmcc RPM_SMD_BIMC_CLK>, - <&rpmcc RPM_SMD_BIMC_A_CLK>; - }; + #include <dt-bindings/clock/qcom,rpmcc.h> + + interconnect@fc380000 { + reg = <0xfc380000 0x6a000>; + compatible = "qcom,msm8974-bimc"; + #interconnect-cells = <1>; + clock-names = "bus", "bus_a"; + clocks = <&rpmcc RPM_SMD_BIMC_CLK>, + <&rpmcc RPM_SMD_BIMC_A_CLK>; + }; diff --git a/Documentation/devicetree/bindings/interconnect/qcom,osm-l3.yaml b/Documentation/devicetree/bindings/interconnect/qcom,osm-l3.yaml index 4ac0863205b3..cd4bb912e0dc 100644 --- a/Documentation/devicetree/bindings/interconnect/qcom,osm-l3.yaml +++ b/Documentation/devicetree/bindings/interconnect/qcom,osm-l3.yaml @@ -28,6 +28,7 @@ properties: - const: qcom,osm-l3 - items: - enum: + - qcom,sa8775p-epss-l3 - qcom,sc7280-epss-l3 - qcom,sc8280xp-epss-l3 - qcom,sm6375-cpucp-l3 diff --git a/Documentation/devicetree/bindings/interconnect/qcom,rpm.yaml b/Documentation/devicetree/bindings/interconnect/qcom,rpm.yaml index 5aaa92a7cef7..01d436d4a553 100644 --- a/Documentation/devicetree/bindings/interconnect/qcom,rpm.yaml +++ b/Documentation/devicetree/bindings/interconnect/qcom,rpm.yaml @@ -41,10 +41,10 @@ unevaluatedProperties: false examples: - | - #include <dt-bindings/clock/qcom,rpmcc.h> + #include <dt-bindings/clock/qcom,rpmcc.h> - bimc: interconnect@400000 { - compatible = "qcom,msm8916-bimc"; - reg = <0x00400000 0x62000>; - #interconnect-cells = <1>; - }; + interconnect@400000 { + compatible = "qcom,msm8916-bimc"; + reg = <0x00400000 0x62000>; + #interconnect-cells = <1>; + }; diff --git a/Documentation/devicetree/bindings/interconnect/qcom,rpmh.yaml b/Documentation/devicetree/bindings/interconnect/qcom,rpmh.yaml index 1b9164dc162f..dad3ad2fd93b 100644 --- a/Documentation/devicetree/bindings/interconnect/qcom,rpmh.yaml +++ b/Documentation/devicetree/bindings/interconnect/qcom,rpmh.yaml @@ -127,19 +127,19 @@ unevaluatedProperties: false examples: - | - #include <dt-bindings/interconnect/qcom,sdm845.h> + #include <dt-bindings/interconnect/qcom,sdm845.h> - mem_noc: interconnect@1380000 { - compatible = "qcom,sdm845-mem-noc"; - reg = <0x01380000 0x27200>; - #interconnect-cells = <1>; - qcom,bcm-voters = <&apps_bcm_voter>; - }; + interconnect@1380000 { + compatible = "qcom,sdm845-mem-noc"; + reg = <0x01380000 0x27200>; + #interconnect-cells = <1>; + qcom,bcm-voters = <&apps_bcm_voter>; + }; - mmss_noc: interconnect@1740000 { - compatible = "qcom,sdm845-mmss-noc"; - reg = <0x01740000 0x1c1000>; - #interconnect-cells = <1>; - qcom,bcm-voter-names = "apps", "disp"; - qcom,bcm-voters = <&apps_bcm_voter>, <&disp_bcm_voter>; - }; + interconnect@1740000 { + compatible = "qcom,sdm845-mmss-noc"; + reg = <0x01740000 0x1c1000>; + #interconnect-cells = <1>; + qcom,bcm-voter-names = "apps", "disp"; + qcom,bcm-voters = <&apps_bcm_voter>, <&disp_bcm_voter>; + }; diff --git a/Documentation/devicetree/bindings/interconnect/qcom,sdx75-rpmh.yaml b/Documentation/devicetree/bindings/interconnect/qcom,sdx75-rpmh.yaml index 71cf7e252bfc..4b5e9f9b07ec 100644 --- a/Documentation/devicetree/bindings/interconnect/qcom,sdx75-rpmh.yaml +++ b/Documentation/devicetree/bindings/interconnect/qcom,sdx75-rpmh.yaml @@ -78,15 +78,15 @@ examples: #include <dt-bindings/clock/qcom,rpmh.h> clk_virt: interconnect-0 { - compatible = "qcom,sdx75-clk-virt"; - #interconnect-cells = <2>; - qcom,bcm-voters = <&apps_bcm_voter>; - clocks = <&rpmhcc RPMH_QPIC_CLK>; + compatible = "qcom,sdx75-clk-virt"; + #interconnect-cells = <2>; + qcom,bcm-voters = <&apps_bcm_voter>; + clocks = <&rpmhcc RPMH_QPIC_CLK>; }; system_noc: interconnect@1640000 { - compatible = "qcom,sdx75-system-noc"; - reg = <0x1640000 0x4b400>; - #interconnect-cells = <2>; - qcom,bcm-voters = <&apps_bcm_voter>; + compatible = "qcom,sdx75-system-noc"; + reg = <0x1640000 0x4b400>; + #interconnect-cells = <2>; + qcom,bcm-voters = <&apps_bcm_voter>; }; diff --git a/Documentation/devicetree/bindings/mips/econet.yaml b/Documentation/devicetree/bindings/mips/econet.yaml new file mode 100644 index 000000000000..d8181b58c781 --- /dev/null +++ b/Documentation/devicetree/bindings/mips/econet.yaml @@ -0,0 +1,26 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/mips/econet.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: EcoNet MIPS SoCs + +maintainers: + - Caleb James DeLisle <cjd@cjdns.fr> + +properties: + $nodename: + const: '/' + + compatible: + oneOf: + - description: Boards with EcoNet EN751221 family SoC + items: + - enum: + - smartfiber,xp8421-b + - const: econet,en751221 + +additionalProperties: true + +... diff --git a/Documentation/devicetree/bindings/mux/gpio-mux.yaml b/Documentation/devicetree/bindings/mux/gpio-mux.yaml index b597c1f2c577..ef7e33ec85d4 100644 --- a/Documentation/devicetree/bindings/mux/gpio-mux.yaml +++ b/Documentation/devicetree/bindings/mux/gpio-mux.yaml @@ -25,6 +25,10 @@ properties: description: List of gpios used to control the multiplexer, least significant bit first. + mux-supply: + description: + Regulator to power on the multiplexer. + '#mux-control-cells': enum: [ 0, 1 ] diff --git a/Documentation/devicetree/bindings/net/wireless/realtek,rtl8188e.yaml b/Documentation/devicetree/bindings/net/wireless/realtek,rtl8188e.yaml new file mode 100644 index 000000000000..2769731e0708 --- /dev/null +++ b/Documentation/devicetree/bindings/net/wireless/realtek,rtl8188e.yaml @@ -0,0 +1,50 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/net/wireless/realtek,rtl8188e.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Realtek RTL8188E USB WiFi + +maintainers: + - J. Neuschäfer <j.ne@posteo.net> + +description: + Realtek RTL8188E is a family of USB-connected 2.4 GHz WiFi modules. + +allOf: + - $ref: /schemas/usb/usb-device.yaml# + +properties: + compatible: + const: usbbda,179 # RTL8188ETV + + reg: true + + vdd-supply: + description: + Regulator for the 3V3 supply. + +required: + - compatible + - reg + - vdd-supply + +additionalProperties: false + +examples: + - | + #include <dt-bindings/gpio/gpio.h> + + usb { + #address-cells = <1>; + #size-cells = <0>; + + wifi: wifi@1 { + compatible = "usbbda,179"; + reg = <1>; + vdd-supply = <&vcc3v3>; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/nvmem/apple,spmi-nvmem.yaml b/Documentation/devicetree/bindings/nvmem/apple,spmi-nvmem.yaml new file mode 100644 index 000000000000..80b5a6cdcec9 --- /dev/null +++ b/Documentation/devicetree/bindings/nvmem/apple,spmi-nvmem.yaml @@ -0,0 +1,54 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/nvmem/apple,spmi-nvmem.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Apple SPMI NVMEM + +description: Exports a series of SPMI registers as NVMEM cells + +maintainers: + - Sasha Finkelstein <fnkl.kernel@gmail.com> + +allOf: + - $ref: nvmem.yaml# + +properties: + compatible: + items: + - enum: + - apple,maverick-pmic + - apple,sera-pmic + - apple,stowe-pmic + - const: apple,spmi-nvmem + + reg: + maxItems: 1 + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + #include <dt-bindings/spmi/spmi.h> + + pmic@f { + compatible = "apple,maverick-pmic", "apple,spmi-nvmem"; + reg = <0xf SPMI_USID>; + + nvmem-layout { + compatible = "fixed-layout"; + #address-cells = <1>; + #size-cells = <1>; + + boot_stage: boot-stage@6001 { + reg = <0x6001 0x1>; + }; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/pwm/adi,axi-pwmgen.yaml b/Documentation/devicetree/bindings/pwm/adi,axi-pwmgen.yaml index 45e112d0efb4..5575c58357d6 100644 --- a/Documentation/devicetree/bindings/pwm/adi,axi-pwmgen.yaml +++ b/Documentation/devicetree/bindings/pwm/adi,axi-pwmgen.yaml @@ -30,11 +30,19 @@ properties: const: 3 clocks: - maxItems: 1 + minItems: 1 + maxItems: 2 + + clock-names: + minItems: 1 + items: + - const: axi + - const: ext required: - reg - clocks + - clock-names unevaluatedProperties: false @@ -43,6 +51,7 @@ examples: pwm@44b00000 { compatible = "adi,axi-pwmgen-2.00.a"; reg = <0x44b00000 0x1000>; - clocks = <&spi_clk>; + clocks = <&fpga_clk>, <&spi_clk>; + clock-names = "axi", "ext"; #pwm-cells = <3>; }; diff --git a/Documentation/devicetree/bindings/riscv/extensions.yaml b/Documentation/devicetree/bindings/riscv/extensions.yaml index bcab59e0cc2e..ede6a58ccf53 100644 --- a/Documentation/devicetree/bindings/riscv/extensions.yaml +++ b/Documentation/devicetree/bindings/riscv/extensions.yaml @@ -662,6 +662,31 @@ properties: Registers in the AX45MP datasheet. https://www.andestech.com/wp-content/uploads/AX45MP-1C-Rev.-5.0.0-Datasheet.pdf + # SiFive + - const: xsfvqmaccdod + description: + SiFive Int8 Matrix Multiplication Extensions Specification. + See more details in + https://www.sifive.com/document-file/sifive-int8-matrix-multiplication-extensions-specification + + - const: xsfvqmaccqoq + description: + SiFive Int8 Matrix Multiplication Extensions Specification. + See more details in + https://www.sifive.com/document-file/sifive-int8-matrix-multiplication-extensions-specification + + - const: xsfvfnrclipxfqf + description: + SiFive FP32-to-int8 Ranged Clip Instructions Extensions Specification. + See more details in + https://www.sifive.com/document-file/fp32-to-int8-ranged-clip-instructions + + - const: xsfvfwmaccqqq + description: + SiFive Matrix Multiply Accumulate Instruction Extensions Specification. + See more details in + https://www.sifive.com/document-file/matrix-multiply-accumulate-instruction + # T-HEAD - const: xtheadvector description: diff --git a/Documentation/devicetree/bindings/serial/8250.yaml b/Documentation/devicetree/bindings/serial/8250.yaml index dc0d52920575..33d2016b6509 100644 --- a/Documentation/devicetree/bindings/serial/8250.yaml +++ b/Documentation/devicetree/bindings/serial/8250.yaml @@ -135,7 +135,16 @@ properties: clock-frequency: true clocks: - maxItems: 1 + minItems: 1 + items: + - description: The core function clock + - description: An optional bus clock + + clock-names: + minItems: 1 + items: + - const: core + - const: bus resets: maxItems: 1 @@ -224,6 +233,25 @@ required: - reg - interrupts +if: + properties: + compatible: + contains: + const: spacemit,k1-uart +then: + required: [clock-names] + properties: + clocks: + minItems: 2 + clock-names: + minItems: 2 +else: + properties: + clocks: + maxItems: 1 + clock-names: + maxItems: 1 + unevaluatedProperties: false examples: diff --git a/Documentation/devicetree/bindings/serial/8250_omap.yaml b/Documentation/devicetree/bindings/serial/8250_omap.yaml index 4b78de6b46a2..1859f71297ff 100644 --- a/Documentation/devicetree/bindings/serial/8250_omap.yaml +++ b/Documentation/devicetree/bindings/serial/8250_omap.yaml @@ -64,14 +64,7 @@ properties: clock-names: const: fclk - rts-gpios: true - cts-gpios: true - dtr-gpios: true - dsr-gpios: true - rng-gpios: true - dcd-gpios: true rs485-rts-active-high: true - rts-gpio: true power-domains: true clock-frequency: true current-speed: true diff --git a/Documentation/devicetree/bindings/serial/amlogic,meson-uart.yaml b/Documentation/devicetree/bindings/serial/amlogic,meson-uart.yaml index 0565fb7649c5..d8ad1bb6172d 100644 --- a/Documentation/devicetree/bindings/serial/amlogic,meson-uart.yaml +++ b/Documentation/devicetree/bindings/serial/amlogic,meson-uart.yaml @@ -56,6 +56,9 @@ properties: items: - enum: - amlogic,a4-uart + - amlogic,s6-uart + - amlogic,s7-uart + - amlogic,s7d-uart - amlogic,t7-uart - const: amlogic,meson-s4-uart diff --git a/Documentation/devicetree/bindings/serial/arc-uart.txt b/Documentation/devicetree/bindings/serial/arc-uart.txt deleted file mode 100644 index 256cc150ca7e..000000000000 --- a/Documentation/devicetree/bindings/serial/arc-uart.txt +++ /dev/null @@ -1,25 +0,0 @@ -* Synopsys ARC UART : Non standard UART used in some of the ARC FPGA boards - -Required properties: -- compatible : "snps,arc-uart" -- reg : offset and length of the register set for the device. -- interrupts : device interrupt -- clock-frequency : the input clock frequency for the UART -- current-speed : baud rate for UART - -e.g. - -arcuart0: serial@c0fc1000 { - compatible = "snps,arc-uart"; - reg = <0xc0fc1000 0x100>; - interrupts = <5>; - clock-frequency = <80000000>; - current-speed = <115200>; -}; - -Note: Each port should have an alias correctly numbered in "aliases" node. - -e.g. -aliases { - serial0 = &arcuart0; -}; diff --git a/Documentation/devicetree/bindings/serial/arm,mps2-uart.txt b/Documentation/devicetree/bindings/serial/arm,mps2-uart.txt deleted file mode 100644 index 128cc6aed001..000000000000 --- a/Documentation/devicetree/bindings/serial/arm,mps2-uart.txt +++ /dev/null @@ -1,19 +0,0 @@ -ARM MPS2 UART - -Required properties: -- compatible : Should be "arm,mps2-uart" -- reg : Address and length of the register set -- interrupts : Reference to the UART RX, TX and overrun interrupts - -Required clocking property: -- clocks : The input clock of the UART - - -Examples: - -uart0: serial@40004000 { - compatible = "arm,mps2-uart"; - reg = <0x40004000 0x1000>; - interrupts = <0 1 12>; - clocks = <&sysclk>; -}; diff --git a/Documentation/devicetree/bindings/serial/arm,mps2-uart.yaml b/Documentation/devicetree/bindings/serial/arm,mps2-uart.yaml new file mode 100644 index 000000000000..4a8df078e6f3 --- /dev/null +++ b/Documentation/devicetree/bindings/serial/arm,mps2-uart.yaml @@ -0,0 +1,46 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/serial/arm,mps2-uart.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Arm MPS2 UART + +maintainers: + - Vladimir Murzin <vladimir.murzin@arm.com> + +allOf: + - $ref: /schemas/serial/serial.yaml# + +properties: + compatible: + const: arm,mps2-uart + + reg: + maxItems: 1 + + interrupts: + items: + - description: RX interrupt + - description: TX interrupt + - description: Overrun interrupt + + clocks: + maxItems: 1 + +required: + - compatible + - reg + - interrupts + - clocks + +unevaluatedProperties: false + +examples: + - | + serial@40004000 { + compatible = "arm,mps2-uart"; + reg = <0x40004000 0x1000>; + interrupts = <0>, <1>, <12>; + clocks = <&sysclk>; + }; diff --git a/Documentation/devicetree/bindings/serial/arm,sbsa-uart.yaml b/Documentation/devicetree/bindings/serial/arm,sbsa-uart.yaml new file mode 100644 index 000000000000..68e3fd64b1d8 --- /dev/null +++ b/Documentation/devicetree/bindings/serial/arm,sbsa-uart.yaml @@ -0,0 +1,38 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +--- +$id: http://devicetree.org/schemas/serial/arm,sbsa-uart.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ARM SBSA UART + +maintainers: + - Andre Przywara <andre.przywara@arm.com> + +description: + This UART uses a subset of the PL011 registers and consequently lives in the + PL011 driver. It's baudrate and other communication parameters cannot be + adjusted at runtime, so it lacks a clock specifier here. + +allOf: + - $ref: /schemas/serial/serial.yaml# + +properties: + compatible: + const: arm,sbsa-uart + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + current-speed: + description: fixed baud rate set by the firmware + +required: + - compatible + - reg + - interrupts + - current-speed + +unevaluatedProperties: false diff --git a/Documentation/devicetree/bindings/serial/arm_sbsa_uart.txt b/Documentation/devicetree/bindings/serial/arm_sbsa_uart.txt deleted file mode 100644 index 4163e7eb7763..000000000000 --- a/Documentation/devicetree/bindings/serial/arm_sbsa_uart.txt +++ /dev/null @@ -1,10 +0,0 @@ -* ARM SBSA defined generic UART -This UART uses a subset of the PL011 registers and consequently lives -in the PL011 driver. It's baudrate and other communication parameters -cannot be adjusted at runtime, so it lacks a clock specifier here. - -Required properties: -- compatible: must be "arm,sbsa-uart" -- reg: exactly one register range -- interrupts: exactly one interrupt specifier -- current-speed: the (fixed) baud rate set by the firmware diff --git a/Documentation/devicetree/bindings/serial/atmel,at91-usart.yaml b/Documentation/devicetree/bindings/serial/atmel,at91-usart.yaml index f466c38518c4..087a8926f8b4 100644 --- a/Documentation/devicetree/bindings/serial/atmel,at91-usart.yaml +++ b/Documentation/devicetree/bindings/serial/atmel,at91-usart.yaml @@ -26,6 +26,7 @@ properties: - enum: - microchip,sam9x60-usart - microchip,sam9x7-usart + - microchip,sama7d65-usart - const: atmel,at91sam9260-usart - items: - const: microchip,sam9x60-dbgu diff --git a/Documentation/devicetree/bindings/serial/cirrus,clps711x-uart.txt b/Documentation/devicetree/bindings/serial/cirrus,clps711x-uart.txt deleted file mode 100644 index 07013fa60a48..000000000000 --- a/Documentation/devicetree/bindings/serial/cirrus,clps711x-uart.txt +++ /dev/null @@ -1,31 +0,0 @@ -* Cirrus Logic CLPS711X Universal Asynchronous Receiver/Transmitter (UART) - -Required properties: -- compatible: Should be "cirrus,ep7209-uart". -- reg: Address and length of the register set for the device. -- interrupts: Should contain UART TX and RX interrupt. -- clocks: Should contain UART core clock number. -- syscon: Phandle to SYSCON node, which contain UART control bits. - -Optional properties: -- {rts,cts,dtr,dsr,rng,dcd}-gpios: specify a GPIO for RTS/CTS/DTR/DSR/RI/DCD - line respectively. - -Note: Each UART port should have an alias correctly numbered -in "aliases" node. - -Example: - aliases { - serial0 = &uart1; - }; - - uart1: uart@80000480 { - compatible = "cirrus,ep7312-uart","cirrus,ep7209-uart"; - reg = <0x80000480 0x80>; - interrupts = <12 13>; - clocks = <&clks 11>; - syscon = <&syscon1>; - cts-gpios = <&sysgpio 0 GPIO_ACTIVE_LOW>; - dsr-gpios = <&sysgpio 1 GPIO_ACTIVE_LOW>; - dcd-gpios = <&sysgpio 2 GPIO_ACTIVE_LOW>; - }; diff --git a/Documentation/devicetree/bindings/serial/cirrus,ep7209-uart.yaml b/Documentation/devicetree/bindings/serial/cirrus,ep7209-uart.yaml new file mode 100644 index 000000000000..c9976e86872b --- /dev/null +++ b/Documentation/devicetree/bindings/serial/cirrus,ep7209-uart.yaml @@ -0,0 +1,56 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/serial/cirrus,ep7209-uart.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Cirrus Logic CLPS711X Universal Asynchronous Receiver/Transmitter (UART) + +maintainers: + - Alexander Shiyan <shc_work@mail.ru> + +allOf: + - $ref: /schemas/serial/serial.yaml# + +properties: + compatible: + const: cirrus,ep7209-uart + + reg: + maxItems: 1 + + interrupts: + items: + - description: UART TX interrupt + - description: UART RX interrupt + + clocks: + maxItems: 1 + + syscon: + description: Phandle to SYSCON node, which contains UART control bits. + $ref: /schemas/types.yaml#/definitions/phandle + +required: + - compatible + - reg + - interrupts + - clocks + - syscon + +unevaluatedProperties: false + +examples: + - | + #include <dt-bindings/gpio/gpio.h> + + serial@80000480 { + compatible = "cirrus,ep7209-uart"; + reg = <0x80000480 0x80>; + interrupts = <12>, <13>; + clocks = <&clks 11>; + syscon = <&syscon1>; + cts-gpios = <&sysgpio 0 GPIO_ACTIVE_LOW>; + dsr-gpios = <&sysgpio 1 GPIO_ACTIVE_LOW>; + dcd-gpios = <&sysgpio 2 GPIO_ACTIVE_LOW>; + }; diff --git a/Documentation/devicetree/bindings/serial/cnxt,cx92755-usart.yaml b/Documentation/devicetree/bindings/serial/cnxt,cx92755-usart.yaml new file mode 100644 index 000000000000..720229455330 --- /dev/null +++ b/Documentation/devicetree/bindings/serial/cnxt,cx92755-usart.yaml @@ -0,0 +1,48 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/serial/cnxt,cx92755-usart.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Conexant Digicolor USART + +maintainers: + - Baruch Siach <baruch@tkos.co.il> + +description: > + Note: this binding is only applicable for using the USART peripheral as UART. + USART also support synchronous serial protocols like SPI and I2S. + Use the binding that matches the wiring of your system. + +allOf: + - $ref: /schemas/serial/serial.yaml# + +properties: + compatible: + const: cnxt,cx92755-usart + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + + interrupts: + maxItems: 1 + +required: + - compatible + - reg + - clocks + - interrupts + +unevaluatedProperties: false + +examples: + - | + serial@f0000740 { + compatible = "cnxt,cx92755-usart"; + reg = <0xf0000740 0x20>; + clocks = <&main_clk>; + interrupts = <44>; + }; diff --git a/Documentation/devicetree/bindings/serial/digicolor-usart.txt b/Documentation/devicetree/bindings/serial/digicolor-usart.txt deleted file mode 100644 index 2d3ede66889d..000000000000 --- a/Documentation/devicetree/bindings/serial/digicolor-usart.txt +++ /dev/null @@ -1,27 +0,0 @@ -Binding for Conexant Digicolor USART - -Note: this binding is only applicable for using the USART peripheral as -UART. USART also support synchronous serial protocols like SPI and I2S. Use -the binding that matches the wiring of your system. - -Required properties: -- compatible : should be "cnxt,cx92755-usart". -- reg: Should contain USART controller registers location and length. -- interrupts: Should contain a single USART controller interrupt. -- clocks: Must contain phandles to the USART clock - See ../clocks/clock-bindings.txt for details. - -Note: Each UART port should have an alias correctly numbered -in "aliases" node. - -Example: - aliases { - serial0 = &uart0; - }; - - uart0: uart@f0000740 { - compatible = "cnxt,cx92755-usart"; - reg = <0xf0000740 0x20>; - clocks = <&main_clk>; - interrupts = <44>; - }; diff --git a/Documentation/devicetree/bindings/serial/lantiq,asc.yaml b/Documentation/devicetree/bindings/serial/lantiq,asc.yaml new file mode 100644 index 000000000000..96e8c79cb047 --- /dev/null +++ b/Documentation/devicetree/bindings/serial/lantiq,asc.yaml @@ -0,0 +1,56 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/serial/lantiq,asc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Lantiq SoC ASC serial controller + +maintainers: + - John Crispin <john@phrozen.org> + - Songjun Wu <songjun.wu@linux.intel.com> + +allOf: + - $ref: /schemas/serial/serial.yaml# + +properties: + compatible: + const: lantiq,asc + + reg: + maxItems: 1 + + interrupts: + items: + - description: TX interrupt + - description: RX interrupt + - description: Error interrupt + + clocks: + items: + - description: Frequency clock + - description: Gate clock + + clock-names: + items: + - const: freq + - const: asc + +required: + - compatible + - reg + - interrupts + +unevaluatedProperties: false + +examples: + - | + #include <dt-bindings/interrupt-controller/mips-gic.h> + + serial@16600000 { + compatible = "lantiq,asc"; + reg = <0x16600000 0x100000>; + interrupts = <GIC_SHARED 103 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SHARED 105 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SHARED 106 IRQ_TYPE_LEVEL_HIGH>; + }; diff --git a/Documentation/devicetree/bindings/serial/lantiq_asc.txt b/Documentation/devicetree/bindings/serial/lantiq_asc.txt deleted file mode 100644 index 40e81a5818f6..000000000000 --- a/Documentation/devicetree/bindings/serial/lantiq_asc.txt +++ /dev/null @@ -1,31 +0,0 @@ -Lantiq SoC ASC serial controller - -Required properties: -- compatible : Should be "lantiq,asc" -- reg : Address and length of the register set for the device -- interrupts: the 3 (tx rx err) interrupt numbers. The interrupt specifier - depends on the interrupt-parent interrupt controller. - -Optional properties: -- clocks: Should contain frequency clock and gate clock -- clock-names: Should be "freq" and "asc" - -Example: - -asc0: serial@16600000 { - compatible = "lantiq,asc"; - reg = <0x16600000 0x100000>; - interrupt-parent = <&gic>; - interrupts = <GIC_SHARED 103 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SHARED 105 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SHARED 106 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&cgu CLK_SSX4>, <&cgu GCLK_UART>; - clock-names = "freq", "asc"; -}; - -asc1: serial@e100c00 { - compatible = "lantiq,asc"; - reg = <0xE100C00 0x400>; - interrupt-parent = <&icu0>; - interrupts = <112 113 114>; -}; diff --git a/Documentation/devicetree/bindings/serial/marvell,armada-3700-uart.yaml b/Documentation/devicetree/bindings/serial/marvell,armada-3700-uart.yaml new file mode 100644 index 000000000000..6c7fa3d19369 --- /dev/null +++ b/Documentation/devicetree/bindings/serial/marvell,armada-3700-uart.yaml @@ -0,0 +1,102 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/serial/marvell,armada-3700-uart.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Marvell Armada-3700 UART + +maintainers: + - Pali Rohár <pali@kernel.org> + +description: + Marvell UART is a non standard UART used in some of Marvell EBU SoCs (e.g. + Armada-3700). + +properties: + compatible: + enum: + - marvell,armada-3700-uart + - marvell,armada-3700-uart-ext + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + description: + UART reference clock used to derive the baud rate. If absent, only fixed + baud rate from the bootloader is supported. + + interrupts: + minItems: 2 + items: + - description: UART sum interrupt + - description: UART TX interrupt + - description: UART RX interrupt + + interrupt-names: + minItems: 2 + maxItems: 3 + +required: + - compatible + - reg + - interrupts + - interrupt-names + +unevaluatedProperties: false + +allOf: + - $ref: /schemas/serial/serial.yaml# + - if: + properties: + compatible: + const: marvell,armada-3700-uart-ext + then: + properties: + interrupts: + maxItems: 2 + + interrupt-names: + items: + - const: uart-tx + - const: uart-rx + else: + properties: + interrupts: + minItems: 3 + + interrupt-names: + items: + - const: uart-sum + - const: uart-tx + - const: uart-rx + +examples: + - | + #include <dt-bindings/interrupt-controller/arm-gic.h> + + serial@12000 { + compatible = "marvell,armada-3700-uart"; + reg = <0x12000 0x18>; + clocks = <&uartclk 0>; + interrupts = + <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "uart-sum", "uart-tx", "uart-rx"; + }; + + - | + #include <dt-bindings/interrupt-controller/arm-gic.h> + + serial@12200 { + compatible = "marvell,armada-3700-uart-ext"; + reg = <0x12200 0x30>; + clocks = <&uartclk 1>; + interrupts = + <GIC_SPI 30 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 31 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "uart-tx", "uart-rx"; + }; diff --git a/Documentation/devicetree/bindings/serial/mediatek,uart.yaml b/Documentation/devicetree/bindings/serial/mediatek,uart.yaml index 1b02f0b197ff..c55d9a0efa19 100644 --- a/Documentation/devicetree/bindings/serial/mediatek,uart.yaml +++ b/Documentation/devicetree/bindings/serial/mediatek,uart.yaml @@ -33,6 +33,7 @@ properties: - mediatek,mt6779-uart - mediatek,mt6795-uart - mediatek,mt6797-uart + - mediatek,mt6893-uart - mediatek,mt7622-uart - mediatek,mt7623-uart - mediatek,mt7629-uart diff --git a/Documentation/devicetree/bindings/serial/microchip,pic32-uart.txt b/Documentation/devicetree/bindings/serial/microchip,pic32-uart.txt deleted file mode 100644 index c8dd440e9747..000000000000 --- a/Documentation/devicetree/bindings/serial/microchip,pic32-uart.txt +++ /dev/null @@ -1,29 +0,0 @@ -* Microchip Universal Asynchronous Receiver Transmitter (UART) - -Required properties: -- compatible: Should be "microchip,pic32mzda-uart" -- reg: Should contain registers location and length -- interrupts: Should contain interrupt -- clocks: Phandle to the clock. - See: Documentation/devicetree/bindings/clock/clock-bindings.txt -- pinctrl-names: A pinctrl state names "default" must be defined. -- pinctrl-0: Phandle referencing pin configuration of the UART peripheral. - See: Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt - -Optional properties: -- cts-gpios: CTS pin for UART - -Example: - uart1: serial@1f822000 { - compatible = "microchip,pic32mzda-uart"; - reg = <0x1f822000 0x50>; - interrupts = <112 IRQ_TYPE_LEVEL_HIGH>, - <113 IRQ_TYPE_LEVEL_HIGH>, - <114 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&rootclk PB2CLK>; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_uart1 - &pinctrl_uart1_cts - &pinctrl_uart1_rts>; - cts-gpios = <&gpio1 15 0>; - }; diff --git a/Documentation/devicetree/bindings/serial/microchip,pic32mzda-uart.yaml b/Documentation/devicetree/bindings/serial/microchip,pic32mzda-uart.yaml new file mode 100644 index 000000000000..b176fd5b580e --- /dev/null +++ b/Documentation/devicetree/bindings/serial/microchip,pic32mzda-uart.yaml @@ -0,0 +1,53 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/serial/microchip,pic32mzda-uart.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Microchip PIC32 UART + +maintainers: + - Andrei Pistirica <andrei.pistirica@microchip.com> + - Purna Chandra Mandal <purna.mandal@microchip.com> + +allOf: + - $ref: /schemas/serial/serial.yaml# + +properties: + compatible: + const: microchip,pic32mzda-uart + + reg: + maxItems: 1 + + interrupts: + items: + - description: Fault + - description: RX + - description: TX + + clocks: + maxItems: 1 + +required: + - compatible + - reg + - interrupts + - clocks + +unevaluatedProperties: false + +examples: + - | + #include <dt-bindings/interrupt-controller/irq.h> + #include <dt-bindings/clock/microchip,pic32-clock.h> + + serial@1f822000 { + compatible = "microchip,pic32mzda-uart"; + reg = <0x1f822000 0x50>; + interrupts = <112 IRQ_TYPE_LEVEL_HIGH>, + <113 IRQ_TYPE_LEVEL_HIGH>, + <114 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&rootclk PB2CLK>; + cts-gpios = <&gpio1 15 0>; + }; diff --git a/Documentation/devicetree/bindings/serial/milbeaut-uart.txt b/Documentation/devicetree/bindings/serial/milbeaut-uart.txt deleted file mode 100644 index 3d2fb1a7ba94..000000000000 --- a/Documentation/devicetree/bindings/serial/milbeaut-uart.txt +++ /dev/null @@ -1,21 +0,0 @@ -Socionext Milbeaut UART controller - -Required properties: -- compatible: should be "socionext,milbeaut-usio-uart". -- reg: offset and length of the register set for the device. -- interrupts: two interrupts specifier. -- interrupt-names: should be "rx", "tx". -- clocks: phandle to the input clock. - -Optional properties: -- auto-flow-control: flow control enable. - -Example: - usio1: usio_uart@1e700010 { - compatible = "socionext,milbeaut-usio-uart"; - reg = <0x1e700010 0x10>; - interrupts = <0 141 0x4>, <0 149 0x4>; - interrupt-names = "rx", "tx"; - clocks = <&clk 2>; - auto-flow-control; - }; diff --git a/Documentation/devicetree/bindings/serial/mvebu-uart.txt b/Documentation/devicetree/bindings/serial/mvebu-uart.txt deleted file mode 100644 index a062bbca532c..000000000000 --- a/Documentation/devicetree/bindings/serial/mvebu-uart.txt +++ /dev/null @@ -1,56 +0,0 @@ -* Marvell UART : Non standard UART used in some of Marvell EBU SoCs - e.g., Armada-3700. - -Required properties: -- compatible: - - "marvell,armada-3700-uart" for the standard variant of the UART - (32 bytes FIFO, no DMA, level interrupts, 8-bit access to the - FIFO), called also UART1. - - "marvell,armada-3700-uart-ext" for the extended variant of the - UART (128 bytes FIFO, DMA, front interrupts, 8-bit or 32-bit - accesses to the FIFO), called also UART2. -- reg: offset and length of the register set for the device. -- clocks: UART reference clock used to derive the baudrate. If no clock - is provided (possible only with the "marvell,armada-3700-uart" - compatible string for backward compatibility), it will only work - if the baudrate was initialized by the bootloader and no baudrate - change will then be possible. When provided it should be UART1-clk - for standard variant of UART and UART2-clk for extended variant - of UART. TBG clock (with UART TBG divisors d1=d2=1) or xtal clock - should not be used and are supported only for backward compatibility. -- interrupts: - - Must contain three elements for the standard variant of the IP - (marvell,armada-3700-uart): "uart-sum", "uart-tx" and "uart-rx", - respectively the UART sum interrupt, the UART TX interrupt and - UART RX interrupt. A corresponding interrupt-names property must - be defined. - - Must contain two elements for the extended variant of the IP - (marvell,armada-3700-uart-ext): "uart-tx" and "uart-rx", - respectively the UART TX interrupt and the UART RX interrupt. A - corresponding interrupt-names property must be defined. - - For backward compatibility reasons, a single element interrupts - property is also supported for the standard variant of the IP, - containing only the UART sum interrupt. This form is deprecated - and should no longer be used. - -Example: - uart0: serial@12000 { - compatible = "marvell,armada-3700-uart"; - reg = <0x12000 0x18>; - clocks = <&uartclk 0>; - interrupts = - <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>; - interrupt-names = "uart-sum", "uart-tx", "uart-rx"; - }; - - uart1: serial@12200 { - compatible = "marvell,armada-3700-uart-ext"; - reg = <0x12200 0x30>; - clocks = <&uartclk 1>; - interrupts = - <GIC_SPI 30 IRQ_TYPE_EDGE_RISING>, - <GIC_SPI 31 IRQ_TYPE_EDGE_RISING>; - interrupt-names = "uart-tx", "uart-rx"; - }; diff --git a/Documentation/devicetree/bindings/serial/nxp,lpc3220-hsuart.yaml b/Documentation/devicetree/bindings/serial/nxp,lpc3220-hsuart.yaml new file mode 100644 index 000000000000..ffa2ea59f256 --- /dev/null +++ b/Documentation/devicetree/bindings/serial/nxp,lpc3220-hsuart.yaml @@ -0,0 +1,39 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/serial/nxp,lpc3220-hsuart.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NXP LPC32xx SoC High Speed UART + +maintainers: + - Vladimir Zapolskiy <vz@mleia.com> + - Piotr Wojtaszczyk <piotr.wojtaszczyk@timesys.com> + +allOf: + - $ref: /schemas/serial/serial.yaml# + +properties: + compatible: + const: nxp,lpc3220-hsuart + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + +required: + - compatible + - reg + - interrupts + +unevaluatedProperties: false + +examples: + - | + serial@40014000 { + compatible = "nxp,lpc3220-hsuart"; + reg = <0x40014000 0x1000>; + interrupts = <26 0>; + }; diff --git a/Documentation/devicetree/bindings/serial/nxp-lpc32xx-hsuart.txt b/Documentation/devicetree/bindings/serial/nxp-lpc32xx-hsuart.txt deleted file mode 100644 index 0d439dfc1aa5..000000000000 --- a/Documentation/devicetree/bindings/serial/nxp-lpc32xx-hsuart.txt +++ /dev/null @@ -1,14 +0,0 @@ -* NXP LPC32xx SoC High Speed UART - -Required properties: -- compatible: Should be "nxp,lpc3220-hsuart" -- reg: Should contain registers location and length -- interrupts: Should contain interrupt - -Example: - - uart1: serial@40014000 { - compatible = "nxp,lpc3220-hsuart"; - reg = <0x40014000 0x1000>; - interrupts = <26 0>; - }; diff --git a/Documentation/devicetree/bindings/serial/renesas,rsci.yaml b/Documentation/devicetree/bindings/serial/renesas,rsci.yaml new file mode 100644 index 000000000000..ea879db5f485 --- /dev/null +++ b/Documentation/devicetree/bindings/serial/renesas,rsci.yaml @@ -0,0 +1,78 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/serial/renesas,rsci.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Renesas RSCI Serial Communication Interface + +maintainers: + - Geert Uytterhoeven <geert+renesas@glider.be> + - Thierry Bultel <thierry.bultel.yh@bp.renesas.com> + +allOf: + - $ref: serial.yaml# + +properties: + compatible: + const: renesas,r9a09g077-rsci # RZ/T2H + + reg: + maxItems: 1 + + interrupts: + items: + - description: Error interrupt + - description: Receive buffer full interrupt + - description: Transmit buffer empty interrupt + - description: Transmit end interrupt + + interrupt-names: + items: + - const: eri + - const: rxi + - const: txi + - const: tei + + clocks: + maxItems: 1 + + clock-names: + const: fck # UART functional clock + + power-domains: + maxItems: 1 + + uart-has-rtscts: false + +required: + - compatible + - reg + - interrupts + - clocks + - clock-names + - power-domains + +unevaluatedProperties: false + +examples: + - | + #include <dt-bindings/interrupt-controller/arm-gic.h> + #include <dt-bindings/clock/renesas-cpg-mssr.h> + + aliases { + serial0 = &sci0; + }; + + sci0: serial@80005000 { + compatible = "renesas,r9a09g077-rsci"; + reg = <0x80005000 0x400>; + interrupts = <GIC_SPI 590 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 591 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 592 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 593 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "eri", "rxi", "txi", "tei"; + clocks = <&cpg CPG_MOD 108>; + clock-names = "fck"; + power-domains = <&cpg>; + }; diff --git a/Documentation/devicetree/bindings/serial/snps,arc-uart.yaml b/Documentation/devicetree/bindings/serial/snps,arc-uart.yaml new file mode 100644 index 000000000000..dd3096fbfb6a --- /dev/null +++ b/Documentation/devicetree/bindings/serial/snps,arc-uart.yaml @@ -0,0 +1,51 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/serial/snps,arc-uart.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Synopsys ARC UART + +maintainers: + - Vineet Gupta <vgupta@kernel.org> + +description: + Synopsys ARC UART is a non-standard UART used in some of the ARC FPGA boards. + +allOf: + - $ref: /schemas/serial/serial.yaml# + +properties: + compatible: + const: snps,arc-uart + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clock-frequency: + description: the input clock frequency for the UART + + current-speed: + description: baud rate for UART + +required: + - compatible + - reg + - interrupts + - clock-frequency + - current-speed + +unevaluatedProperties: false + +examples: + - | + serial@c0fc1000 { + compatible = "snps,arc-uart"; + reg = <0xc0fc1000 0x100>; + interrupts = <5>; + clock-frequency = <80000000>; + current-speed = <115200>; + }; diff --git a/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml b/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml index 1ee0aed5057d..8f1b7f704c5b 100644 --- a/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml +++ b/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml @@ -17,7 +17,7 @@ allOf: properties: compatible: items: - - const: renesas,r9a06g032-uart + - {} - const: renesas,rzn1-uart - const: snps,dw-apb-uart then: diff --git a/Documentation/devicetree/bindings/serial/socionext,milbeaut-usio-uart.yaml b/Documentation/devicetree/bindings/serial/socionext,milbeaut-usio-uart.yaml new file mode 100644 index 000000000000..34a997ca2e11 --- /dev/null +++ b/Documentation/devicetree/bindings/serial/socionext,milbeaut-usio-uart.yaml @@ -0,0 +1,56 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/serial/socionext,milbeaut-usio-uart.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Socionext Milbeaut UART controller + +maintainers: + - Sugaya Taichi <sugaya.taichi@socionext.com> + +allOf: + - $ref: /schemas/serial/serial.yaml# + +properties: + compatible: + const: socionext,milbeaut-usio-uart + + reg: + maxItems: 1 + + interrupts: + items: + - description: RX interrupt specifier + - description: TX interrupt specifier + + interrupt-names: + items: + - const: rx + - const: tx + + clocks: + maxItems: 1 + + auto-flow-control: + description: Enable automatic flow control. + type: boolean + +required: + - compatible + - reg + - interrupts + - interrupt-names + +unevaluatedProperties: false + +examples: + - | + serial@1e700010 { + compatible = "socionext,milbeaut-usio-uart"; + reg = <0x1e700010 0x10>; + interrupts = <0 141 0x4>, <0 149 0x4>; + interrupt-names = "rx", "tx"; + clocks = <&clk 2>; + auto-flow-control; + }; diff --git a/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml b/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml index 22fe6814b706..590eb177f57a 100644 --- a/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml @@ -193,4 +193,19 @@ examples: sound-dai = <&vamacro 0>; }; }; + + usb-dai-link { + link-name = "USB Playback"; + cpu { + sound-dai = <&q6afedai USB_RX>; + }; + + codec { + sound-dai = <&usbdai USB_RX>; + }; + + platform { + sound-dai = <&q6routing>; + }; + }; }; diff --git a/Documentation/devicetree/bindings/spi/spi-sg2044-nor.yaml b/Documentation/devicetree/bindings/spi/spi-sg2044-nor.yaml index 948ff7a09643..66e54dedab14 100644 --- a/Documentation/devicetree/bindings/spi/spi-sg2044-nor.yaml +++ b/Documentation/devicetree/bindings/spi/spi-sg2044-nor.yaml @@ -14,7 +14,12 @@ allOf: properties: compatible: - const: sophgo,sg2044-spifmc-nor + oneOf: + - const: sophgo,sg2044-spifmc-nor + - items: + - enum: + - sophgo,sg2042-spifmc-nor + - const: sophgo,sg2044-spifmc-nor reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/spmi/apple,spmi.yaml b/Documentation/devicetree/bindings/spmi/apple,spmi.yaml new file mode 100644 index 000000000000..16bd7eb2b7af --- /dev/null +++ b/Documentation/devicetree/bindings/spmi/apple,spmi.yaml @@ -0,0 +1,49 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/spmi/apple,spmi.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Apple SPMI controller + +maintainers: + - Sasha Finkelstein <fnkl.kernel@gmail.com> + +description: A SPMI controller present on most Apple SoCs + +allOf: + - $ref: spmi.yaml# + +properties: + compatible: + items: + - enum: + - apple,t8103-spmi + - apple,t6000-spmi + - apple,t8112-spmi + - const: apple,spmi + + reg: + maxItems: 1 + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + #include <dt-bindings/spmi/spmi.h> + + spmi@920a1300 { + compatible = "apple,t6000-spmi", "apple,spmi"; + reg = <0x920a1300 0x100>; + #address-cells = <2>; + #size-cells = <0>; + + pmic@f { + reg = <0xf SPMI_USID>; + /* PMIC-specific properties */ + }; + }; diff --git a/Documentation/devicetree/bindings/trivial-devices.yaml b/Documentation/devicetree/bindings/trivial-devices.yaml index 8dc81b1ca48e..27930708ccd5 100644 --- a/Documentation/devicetree/bindings/trivial-devices.yaml +++ b/Documentation/devicetree/bindings/trivial-devices.yaml @@ -85,6 +85,8 @@ properties: - devantech,srf08 # Devantech SRF10 ultrasonic ranger - devantech,srf10 + # DFRobot SEN0322 oxygen sensor + - dfrobot,sen0322 # DH electronics GmbH on-board CPLD trivial SPI device - dh,dhcom-board # DA9053: flexible system level PMIC with multicore support diff --git a/Documentation/devicetree/bindings/usb/chipidea,usb2-common.yaml b/Documentation/devicetree/bindings/usb/chipidea,usb2-common.yaml index d2a7d2ecf48a..10020af15afc 100644 --- a/Documentation/devicetree/bindings/usb/chipidea,usb2-common.yaml +++ b/Documentation/devicetree/bindings/usb/chipidea,usb2-common.yaml @@ -42,6 +42,9 @@ properties: phy_type: true + iommus: + maxItems: 1 + itc-setting: description: interrupt threshold control register control, the setting should be diff --git a/Documentation/devicetree/bindings/usb/chipidea,usb2-imx.yaml b/Documentation/devicetree/bindings/usb/chipidea,usb2-imx.yaml index 8f6136f5d72e..51014955ab3c 100644 --- a/Documentation/devicetree/bindings/usb/chipidea,usb2-imx.yaml +++ b/Documentation/devicetree/bindings/usb/chipidea,usb2-imx.yaml @@ -41,6 +41,7 @@ properties: - fsl,imx8mm-usb - fsl,imx8mn-usb - fsl,imx93-usb + - fsl,imx95-usb - const: fsl,imx7d-usb - const: fsl,imx27-usb - items: @@ -54,7 +55,11 @@ properties: maxItems: 1 interrupts: - maxItems: 1 + minItems: 1 + items: + - description: USB controller interrupt or combine USB controller + and wakeup interrupts. + - description: Wakeup interrupt clocks: minItems: 1 @@ -191,6 +196,7 @@ allOf: contains: enum: - fsl,imx93-usb + - fsl,imx95-usb then: properties: clocks: @@ -238,6 +244,22 @@ allOf: maxItems: 1 clock-names: false + # imx95 soc use two interrupts + - if: + properties: + compatible: + contains: + enum: + - fsl,imx95-usb + then: + properties: + interrupts: + minItems: 2 + else: + properties: + interrupts: + maxItems: 1 + unevaluatedProperties: false examples: diff --git a/Documentation/devicetree/bindings/usb/fsl,usbmisc.yaml b/Documentation/devicetree/bindings/usb/fsl,usbmisc.yaml index 0a6e7ac1b37e..019435540df0 100644 --- a/Documentation/devicetree/bindings/usb/fsl,usbmisc.yaml +++ b/Documentation/devicetree/bindings/usb/fsl,usbmisc.yaml @@ -34,6 +34,7 @@ properties: - fsl,imx8mm-usbmisc - fsl,imx8mn-usbmisc - fsl,imx8ulp-usbmisc + - fsl,imx95-usbmisc - const: fsl,imx7d-usbmisc - const: fsl,imx6q-usbmisc - items: @@ -45,7 +46,10 @@ properties: maxItems: 1 reg: - maxItems: 1 + minItems: 1 + items: + - description: Base and length of the Wrapper module register + - description: Base and length of the HSIO Block Control register '#index-cells': const: 1 @@ -56,6 +60,23 @@ required: - compatible - reg +allOf: + # imx95 soc needs use HSIO Block Control + - if: + properties: + compatible: + contains: + enum: + - fsl,imx95-usbmisc + then: + properties: + reg: + minItems: 2 + else: + properties: + reg: + maxItems: 1 + additionalProperties: false examples: diff --git a/Documentation/devicetree/bindings/usb/generic-ehci.yaml b/Documentation/devicetree/bindings/usb/generic-ehci.yaml index 223f2abd5e59..508d958e698c 100644 --- a/Documentation/devicetree/bindings/usb/generic-ehci.yaml +++ b/Documentation/devicetree/bindings/usb/generic-ehci.yaml @@ -86,6 +86,7 @@ properties: - nuvoton,npcm845-ehci - ti,ehci-omap - usb-ehci + - via,vt8500-ehci reg: minItems: 1 diff --git a/Documentation/devicetree/bindings/usb/parade,ps5511.yaml b/Documentation/devicetree/bindings/usb/parade,ps5511.yaml new file mode 100644 index 000000000000..10d002f09db8 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/parade,ps5511.yaml @@ -0,0 +1,108 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/usb/parade,ps5511.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Parade PS5511 4+1 Port USB 3.2 Gen 1 Hub Controller + +maintainers: + - Pin-yen Lin <treapking@chromium.org> + +properties: + compatible: + enum: + - usb1da0,5511 + - usb1da0,55a1 + + reset-gpios: + items: + - description: GPIO specifier for RESETB pin. + + vddd11-supply: + description: + 1V1 power supply to the hub + + vdd33-supply: + description: + 3V3 power supply to the hub + + peer-hub: true + + ports: + $ref: /schemas/graph.yaml#/properties/ports + + patternProperties: + '^port@': + $ref: /schemas/graph.yaml#/properties/port + + properties: + reg: + minimum: 1 + maximum: 5 + +additionalProperties: + properties: + reg: + minimum: 1 + maximum: 5 + +required: + - peer-hub + +allOf: + - $ref: usb-hub.yaml# + - if: + not: + properties: + compatible: + enum: + - usb1da0,55a1 + then: + properties: + ports: + properties: + port@5: false + + patternProperties: + '^.*@5$': false + +examples: + - | + usb { + #address-cells = <1>; + #size-cells = <0>; + + /* 2.0 hub on port 1 */ + hub_2_0: hub@1 { + compatible = "usb1da0,55a1"; + reg = <1>; + peer-hub = <&hub_3_0>; + #address-cells = <1>; + #size-cells = <0>; + /* USB 2.0 device on port 5 */ + device@5 { + reg = <5>; + compatible = "usb123,4567"; + }; + }; + + /* 3.0 hub on port 2 */ + hub_3_0: hub@2 { + compatible = "usb1da0,5511"; + reg = <2>; + peer-hub = <&hub_2_0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + /* Type-A connector on port 3 */ + port@3 { + reg = <3>; + endpoint { + remote-endpoint = <&usb_a0_ss>; + }; + }; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/usb/parade,ps8830.yaml b/Documentation/devicetree/bindings/usb/parade,ps8830.yaml index 935d57f5d26f..aeb33667818e 100644 --- a/Documentation/devicetree/bindings/usb/parade,ps8830.yaml +++ b/Documentation/devicetree/bindings/usb/parade,ps8830.yaml @@ -11,8 +11,11 @@ maintainers: properties: compatible: - enum: - - parade,ps8830 + oneOf: + - items: + - const: parade,ps8833 + - const: parade,ps8830 + - const: parade,ps8830 reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml b/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml index 64137c1619a6..a792434c59db 100644 --- a/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml +++ b/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml @@ -4,11 +4,22 @@ $id: http://devicetree.org/schemas/usb/qcom,dwc3.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: Qualcomm SuperSpeed DWC3 USB SoC controller +title: Legacy Qualcomm SuperSpeed DWC3 USB SoC controller maintainers: - Wesley Cheng <quic_wcheng@quicinc.com> +# Use the combined qcom,snps-dwc3 instead +deprecated: true + +select: + properties: + compatible: + contains: + const: qcom,dwc3 + required: + - compatible + properties: compatible: items: @@ -55,6 +66,7 @@ properties: - qcom,sm8450-dwc3 - qcom,sm8550-dwc3 - qcom,sm8650-dwc3 + - qcom,sm8750-dwc3 - qcom,x1e80100-dwc3 - qcom,x1e80100-dwc3-mp - const: qcom,dwc3 @@ -354,6 +366,7 @@ allOf: - qcom,sm8450-dwc3 - qcom,sm8550-dwc3 - qcom,sm8650-dwc3 + - qcom,sm8750-dwc3 then: properties: clocks: @@ -497,6 +510,7 @@ allOf: - qcom,sm8450-dwc3 - qcom,sm8550-dwc3 - qcom,sm8650-dwc3 + - qcom,sm8750-dwc3 then: properties: interrupts: diff --git a/Documentation/devicetree/bindings/usb/qcom,snps-dwc3.yaml b/Documentation/devicetree/bindings/usb/qcom,snps-dwc3.yaml new file mode 100644 index 000000000000..8dac5eba61b4 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/qcom,snps-dwc3.yaml @@ -0,0 +1,622 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/usb/qcom,snps-dwc3.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm SuperSpeed DWC3 USB SoC controller + +maintainers: + - Wesley Cheng <quic_wcheng@quicinc.com> + +description: + Describes the Qualcomm USB block, based on Synopsys DWC3. + +select: + properties: + compatible: + contains: + const: qcom,snps-dwc3 + required: + - compatible + +properties: + compatible: + items: + - enum: + - qcom,ipq4019-dwc3 + - qcom,ipq5018-dwc3 + - qcom,ipq5332-dwc3 + - qcom,ipq5424-dwc3 + - qcom,ipq6018-dwc3 + - qcom,ipq8064-dwc3 + - qcom,ipq8074-dwc3 + - qcom,ipq9574-dwc3 + - qcom,msm8953-dwc3 + - qcom,msm8994-dwc3 + - qcom,msm8996-dwc3 + - qcom,msm8998-dwc3 + - qcom,qcm2290-dwc3 + - qcom,qcs404-dwc3 + - qcom,qcs615-dwc3 + - qcom,qcs8300-dwc3 + - qcom,qdu1000-dwc3 + - qcom,sa8775p-dwc3 + - qcom,sar2130p-dwc3 + - qcom,sc7180-dwc3 + - qcom,sc7280-dwc3 + - qcom,sc8180x-dwc3 + - qcom,sc8180x-dwc3-mp + - qcom,sc8280xp-dwc3 + - qcom,sc8280xp-dwc3-mp + - qcom,sdm660-dwc3 + - qcom,sdm670-dwc3 + - qcom,sdm845-dwc3 + - qcom,sdx55-dwc3 + - qcom,sdx65-dwc3 + - qcom,sdx75-dwc3 + - qcom,sm4250-dwc3 + - qcom,sm6115-dwc3 + - qcom,sm6125-dwc3 + - qcom,sm6350-dwc3 + - qcom,sm6375-dwc3 + - qcom,sm8150-dwc3 + - qcom,sm8250-dwc3 + - qcom,sm8350-dwc3 + - qcom,sm8450-dwc3 + - qcom,sm8550-dwc3 + - qcom,sm8650-dwc3 + - qcom,x1e80100-dwc3 + - const: qcom,snps-dwc3 + + reg: + maxItems: 1 + + power-domains: + maxItems: 1 + + required-opps: + maxItems: 1 + + clocks: + description: | + Several clocks are used, depending on the variant. Typical ones are:: + - cfg_noc:: System Config NOC clock. + - core:: Master/Core clock, has to be >= 125 MHz for SS operation and >= + 60MHz for HS operation. + - iface:: System bus AXI clock. + - sleep:: Sleep clock, used for wakeup when USB3 core goes into low + power mode (U3). + - mock_utmi:: Mock utmi clock needed for ITP/SOF generation in host + mode. Its frequency should be 19.2MHz. + minItems: 1 + maxItems: 9 + + clock-names: + minItems: 1 + maxItems: 9 + + dma-coherent: true + + iommus: + maxItems: 1 + + resets: + maxItems: 1 + + interconnects: + maxItems: 2 + + interconnect-names: + items: + - const: usb-ddr + - const: apps-usb + + interrupts: + description: | + Different types of interrupts are used based on HS PHY used on target: + - dwc_usb3: Core DWC3 interrupt + - pwr_event: Used for wakeup based on other power events. + - hs_phy_irq: Apart from DP/DM/QUSB2 PHY interrupts, there is + hs_phy_irq which is not triggered by default and its + functionality is mutually exclusive to that of + {dp/dm}_hs_phy_irq and qusb2_phy_irq. + - qusb2_phy: SoCs with QUSB2 PHY do not have separate DP/DM IRQs and + expose only a single IRQ whose behavior can be modified + by the QUSB2PHY_INTR_CTRL register. The required DPSE/ + DMSE configuration is done in QUSB2PHY_INTR_CTRL register + of PHY address space. + - {dp/dm}_hs_phy_irq: These IRQ's directly reflect changes on the DP/ + DM pads of the SoC. These are used for wakeup + only on SoCs with non-QUSB2 targets with + exception of SDM670/SDM845/SM6350. + - ss_phy_irq: Used for remote wakeup in Super Speed mode of operation. + minItems: 3 + maxItems: 19 + + interrupt-names: + minItems: 3 + maxItems: 19 + + qcom,select-utmi-as-pipe-clk: + description: + If present, disable USB3 pipe_clk requirement. + Used when dwc3 operates without SSPHY and only + HS/FS/LS modes are supported. + type: boolean + + wakeup-source: true + +# Required child node: + +required: + - compatible + - reg + - clocks + - clock-names + - interrupts + - interrupt-names + +allOf: + - $ref: snps,dwc3-common.yaml# + - if: + properties: + compatible: + contains: + enum: + - qcom,ipq4019-dwc3 + - qcom,ipq5332-dwc3 + then: + properties: + clocks: + maxItems: 3 + clock-names: + items: + - const: core + - const: sleep + - const: mock_utmi + + - if: + properties: + compatible: + contains: + enum: + - qcom,ipq8064-dwc3 + then: + properties: + clocks: + items: + - description: Master/Core clock, has to be >= 125 MHz + for SS operation and >= 60MHz for HS operation. + clock-names: + items: + - const: core + + - if: + properties: + compatible: + contains: + enum: + - qcom,ipq9574-dwc3 + - qcom,msm8953-dwc3 + - qcom,msm8996-dwc3 + - qcom,msm8998-dwc3 + - qcom,qcs8300-dwc3 + - qcom,sa8775p-dwc3 + - qcom,sc7180-dwc3 + - qcom,sc7280-dwc3 + - qcom,sdm670-dwc3 + - qcom,sdm845-dwc3 + - qcom,sdx55-dwc3 + - qcom,sdx65-dwc3 + - qcom,sdx75-dwc3 + - qcom,sm6350-dwc3 + then: + properties: + clocks: + maxItems: 5 + clock-names: + items: + - const: cfg_noc + - const: core + - const: iface + - const: sleep + - const: mock_utmi + + - if: + properties: + compatible: + contains: + enum: + - qcom,ipq6018-dwc3 + then: + properties: + clocks: + minItems: 3 + maxItems: 4 + clock-names: + oneOf: + - items: + - const: core + - const: sleep + - const: mock_utmi + - items: + - const: cfg_noc + - const: core + - const: sleep + - const: mock_utmi + + - if: + properties: + compatible: + contains: + enum: + - qcom,ipq8074-dwc3 + - qcom,qdu1000-dwc3 + then: + properties: + clocks: + maxItems: 4 + clock-names: + items: + - const: cfg_noc + - const: core + - const: sleep + - const: mock_utmi + + - if: + properties: + compatible: + contains: + enum: + - qcom,ipq5018-dwc3 + - qcom,msm8994-dwc3 + - qcom,qcs404-dwc3 + then: + properties: + clocks: + maxItems: 4 + clock-names: + items: + - const: core + - const: iface + - const: sleep + - const: mock_utmi + + - if: + properties: + compatible: + contains: + enum: + - qcom,sc8280xp-dwc3 + - qcom,sc8280xp-dwc3-mp + - qcom,x1e80100-dwc3 + - qcom,x1e80100-dwc3-mp + then: + properties: + clocks: + maxItems: 9 + clock-names: + items: + - const: cfg_noc + - const: core + - const: iface + - const: sleep + - const: mock_utmi + - const: noc_aggr + - const: noc_aggr_north + - const: noc_aggr_south + - const: noc_sys + + - if: + properties: + compatible: + contains: + enum: + - qcom,sdm660-dwc3 + then: + properties: + clocks: + minItems: 4 + maxItems: 5 + clock-names: + oneOf: + - items: + - const: cfg_noc + - const: core + - const: iface + - const: sleep + - const: mock_utmi + - items: + - const: cfg_noc + - const: core + - const: sleep + - const: mock_utmi + + - if: + properties: + compatible: + contains: + enum: + - qcom,qcm2290-dwc3 + - qcom,qcs615-dwc3 + - qcom,sar2130p-dwc3 + - qcom,sc8180x-dwc3 + - qcom,sc8180x-dwc3-mp + - qcom,sm6115-dwc3 + - qcom,sm6125-dwc3 + - qcom,sm8150-dwc3 + - qcom,sm8250-dwc3 + - qcom,sm8450-dwc3 + - qcom,sm8550-dwc3 + - qcom,sm8650-dwc3 + then: + properties: + clocks: + minItems: 6 + clock-names: + items: + - const: cfg_noc + - const: core + - const: iface + - const: sleep + - const: mock_utmi + - const: xo + + - if: + properties: + compatible: + contains: + enum: + - qcom,sm8350-dwc3 + then: + properties: + clocks: + minItems: 5 + maxItems: 6 + clock-names: + minItems: 5 + items: + - const: cfg_noc + - const: core + - const: iface + - const: sleep + - const: mock_utmi + - const: xo + + - if: + properties: + compatible: + contains: + enum: + - qcom,ipq5018-dwc3 + - qcom,ipq6018-dwc3 + - qcom,ipq8074-dwc3 + - qcom,msm8953-dwc3 + - qcom,msm8998-dwc3 + then: + properties: + interrupts: + minItems: 3 + maxItems: 4 + interrupt-names: + minItems: 3 + items: + - const: dwc_usb3 + - const: pwr_event + - const: qusb2_phy + - const: ss_phy_irq + + - if: + properties: + compatible: + contains: + enum: + - qcom,msm8996-dwc3 + - qcom,qcs404-dwc3 + - qcom,sdm660-dwc3 + - qcom,sm6115-dwc3 + - qcom,sm6125-dwc3 + then: + properties: + interrupts: + minItems: 4 + maxItems: 5 + interrupt-names: + minItems: 4 + items: + - const: dwc_usb3 + - const: pwr_event + - const: qusb2_phy + - const: hs_phy_irq + - const: ss_phy_irq + + - if: + properties: + compatible: + contains: + enum: + - qcom,ipq5332-dwc3 + then: + properties: + interrupts: + maxItems: 4 + interrupt-names: + items: + - const: dwc_usb3 + - const: pwr_event + - const: dp_hs_phy_irq + - const: dm_hs_phy_irq + + - if: + properties: + compatible: + contains: + enum: + - qcom,x1e80100-dwc3 + then: + properties: + interrupts: + maxItems: 5 + interrupt-names: + items: + - const: dwc_usb3 + - const: pwr_event + - const: dp_hs_phy_irq + - const: dm_hs_phy_irq + - const: ss_phy_irq + + - if: + properties: + compatible: + contains: + enum: + - qcom,ipq4019-dwc3 + - qcom,ipq8064-dwc3 + - qcom,msm8994-dwc3 + - qcom,qcs615-dwc3 + - qcom,qcs8300-dwc3 + - qcom,qdu1000-dwc3 + - qcom,sa8775p-dwc3 + - qcom,sc7180-dwc3 + - qcom,sc7280-dwc3 + - qcom,sc8180x-dwc3 + - qcom,sc8280xp-dwc3 + - qcom,sdm670-dwc3 + - qcom,sdm845-dwc3 + - qcom,sdx55-dwc3 + - qcom,sdx65-dwc3 + - qcom,sdx75-dwc3 + - qcom,sm4250-dwc3 + - qcom,sm6350-dwc3 + - qcom,sm8150-dwc3 + - qcom,sm8250-dwc3 + - qcom,sm8350-dwc3 + - qcom,sm8450-dwc3 + - qcom,sm8550-dwc3 + - qcom,sm8650-dwc3 + then: + properties: + interrupts: + minItems: 5 + maxItems: 6 + interrupt-names: + minItems: 5 + items: + - const: dwc_usb3 + - const: pwr_event + - const: hs_phy_irq + - const: dp_hs_phy_irq + - const: dm_hs_phy_irq + - const: ss_phy_irq + + - if: + properties: + compatible: + contains: + enum: + - qcom,sc8180x-dwc3-mp + - qcom,x1e80100-dwc3-mp + then: + properties: + interrupts: + minItems: 11 + maxItems: 11 + interrupt-names: + items: + - const: dwc_usb3 + - const: pwr_event_1 + - const: pwr_event_2 + - const: hs_phy_1 + - const: hs_phy_2 + - const: dp_hs_phy_1 + - const: dm_hs_phy_1 + - const: dp_hs_phy_2 + - const: dm_hs_phy_2 + - const: ss_phy_1 + - const: ss_phy_2 + + - if: + properties: + compatible: + contains: + enum: + - qcom,sc8280xp-dwc3-mp + then: + properties: + interrupts: + minItems: 19 + maxItems: 19 + interrupt-names: + items: + - const: dwc_usb3 + - const: pwr_event_1 + - const: pwr_event_2 + - const: pwr_event_3 + - const: pwr_event_4 + - const: hs_phy_1 + - const: hs_phy_2 + - const: hs_phy_3 + - const: hs_phy_4 + - const: dp_hs_phy_1 + - const: dm_hs_phy_1 + - const: dp_hs_phy_2 + - const: dm_hs_phy_2 + - const: dp_hs_phy_3 + - const: dm_hs_phy_3 + - const: dp_hs_phy_4 + - const: dm_hs_phy_4 + - const: ss_phy_1 + - const: ss_phy_2 + +unevaluatedProperties: false + +examples: + - | + #include <dt-bindings/clock/qcom,gcc-sdm845.h> + #include <dt-bindings/interrupt-controller/arm-gic.h> + #include <dt-bindings/interrupt-controller/irq.h> + soc { + #address-cells = <2>; + #size-cells = <2>; + + usb@a600000 { + compatible = "qcom,sdm845-dwc3", "qcom,snps-dwc3"; + reg = <0 0x0a600000 0 0x100000>; + + clocks = <&gcc GCC_CFG_NOC_USB3_PRIM_AXI_CLK>, + <&gcc GCC_USB30_PRIM_MASTER_CLK>, + <&gcc GCC_AGGRE_USB3_PRIM_AXI_CLK>, + <&gcc GCC_USB30_PRIM_SLEEP_CLK>, + <&gcc GCC_USB30_PRIM_MOCK_UTMI_CLK>; + clock-names = "cfg_noc", + "core", + "iface", + "sleep", + "mock_utmi"; + + assigned-clocks = <&gcc GCC_USB30_PRIM_MOCK_UTMI_CLK>, + <&gcc GCC_USB30_PRIM_MASTER_CLK>; + assigned-clock-rates = <19200000>, <150000000>; + + interrupts = <GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 489 IRQ_TYPE_EDGE_BOTH>, + <GIC_SPI 488 IRQ_TYPE_EDGE_BOTH>, + <GIC_SPI 486 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "dwc_usb3", "pwr_event", "hs_phy_irq", + "dp_hs_phy_irq", "dm_hs_phy_irq", "ss_phy_irq"; + + power-domains = <&gcc USB30_PRIM_GDSC>; + + resets = <&gcc GCC_USB30_PRIM_BCR>; + + iommus = <&apps_smmu 0x740 0>; + snps,dis_u2_susphy_quirk; + snps,dis_enblslpm_quirk; + phys = <&usb_1_hsphy>, <&usb_1_ssphy>; + phy-names = "usb2-phy", "usb3-phy"; + }; + }; +... diff --git a/Documentation/devicetree/bindings/usb/realtek,rts5411.yaml b/Documentation/devicetree/bindings/usb/realtek,rts5411.yaml index 6577a61cc075..a020afaf2d6e 100644 --- a/Documentation/devicetree/bindings/usb/realtek,rts5411.yaml +++ b/Documentation/devicetree/bindings/usb/realtek,rts5411.yaml @@ -10,7 +10,7 @@ maintainers: - Matthias Kaehlcke <mka@chromium.org> allOf: - - $ref: usb-device.yaml# + - $ref: usb-hub.yaml# properties: compatible: @@ -19,61 +19,35 @@ properties: - usbbda,5411 - usbbda,411 - reg: true - - '#address-cells': - const: 1 - - '#size-cells': - const: 0 - vdd-supply: description: phandle to the regulator that provides power to the hub. - peer-hub: - $ref: /schemas/types.yaml#/definitions/phandle - description: - phandle to the peer hub on the controller. + peer-hub: true ports: $ref: /schemas/graph.yaml#/properties/ports - properties: - port@1: - $ref: /schemas/graph.yaml#/properties/port - description: - 1st downstream facing USB port - - port@2: + patternProperties: + '^port@': $ref: /schemas/graph.yaml#/properties/port - description: - 2nd downstream facing USB port - port@3: - $ref: /schemas/graph.yaml#/properties/port - description: - 3rd downstream facing USB port + properties: + reg: + minimum: 1 + maximum: 4 - port@4: - $ref: /schemas/graph.yaml#/properties/port - description: - 4th downstream facing USB port - -patternProperties: - '^.*@[1-4]$': - description: The hard wired USB devices - type: object - $ref: /schemas/usb/usb-device.yaml - additionalProperties: true +additionalProperties: + properties: + reg: + minimum: 1 + maximum: 4 required: - peer-hub - compatible - reg -additionalProperties: false - examples: - | usb { diff --git a/Documentation/devicetree/bindings/usb/renesas,usbhs.yaml b/Documentation/devicetree/bindings/usb/renesas,usbhs.yaml index 980f325341d4..6f4d41ba6ca7 100644 --- a/Documentation/devicetree/bindings/usb/renesas,usbhs.yaml +++ b/Documentation/devicetree/bindings/usb/renesas,usbhs.yaml @@ -27,6 +27,7 @@ properties: - renesas,usbhs-r9a07g044 # RZ/G2{L,LC} - renesas,usbhs-r9a07g054 # RZ/V2L - renesas,usbhs-r9a08g045 # RZ/G3S + - renesas,usbhs-r9a09g057 # RZ/V2H(P) - const: renesas,rzg2l-usbhs - items: @@ -127,11 +128,7 @@ allOf: properties: compatible: contains: - enum: - - renesas,usbhs-r9a07g043 - - renesas,usbhs-r9a07g044 - - renesas,usbhs-r9a07g054 - - renesas,usbhs-r9a08g045 + const: renesas,rzg2l-usbhs then: properties: interrupts: diff --git a/Documentation/devicetree/bindings/usb/samsung,exynos-dwc3.yaml b/Documentation/devicetree/bindings/usb/samsung,exynos-dwc3.yaml index 256bee2a03ca..6d39e5066944 100644 --- a/Documentation/devicetree/bindings/usb/samsung,exynos-dwc3.yaml +++ b/Documentation/devicetree/bindings/usb/samsung,exynos-dwc3.yaml @@ -14,11 +14,13 @@ properties: oneOf: - enum: - google,gs101-dwusb3 + - samsung,exynos2200-dwusb3 - samsung,exynos5250-dwusb3 - samsung,exynos5433-dwusb3 - samsung,exynos7-dwusb3 - samsung,exynos7870-dwusb3 - samsung,exynos850-dwusb3 + - samsung,exynosautov920-dwusb3 - items: - const: samsung,exynos990-dwusb3 - const: samsung,exynos850-dwusb3 @@ -83,6 +85,19 @@ allOf: properties: compatible: contains: + const: samsung,exynos2200-dwusb3 + then: + properties: + clocks: + maxItems: 1 + clock-names: + items: + - const: link_aclk + + - if: + properties: + compatible: + contains: const: samsung,exynos5250-dwusb3 then: properties: @@ -165,6 +180,21 @@ allOf: required: - vdd10-supply + - if: + properties: + compatible: + contains: + const: samsung,exynosautov920-dwusb3 + then: + properties: + clocks: + minItems: 2 + maxItems: 2 + clock-names: + items: + - const: ref + - const: susp_clk + additionalProperties: false examples: diff --git a/Documentation/devicetree/bindings/usb/smsc,usb3503.yaml b/Documentation/devicetree/bindings/usb/smsc,usb3503.yaml index 6156dc26e65c..18e35122dc1f 100644 --- a/Documentation/devicetree/bindings/usb/smsc,usb3503.yaml +++ b/Documentation/devicetree/bindings/usb/smsc,usb3503.yaml @@ -106,54 +106,54 @@ additionalProperties: false examples: - | - i2c { - #address-cells = <1>; - #size-cells = <0>; - - usb-hub@8 { - compatible = "smsc,usb3503"; - reg = <0x08>; - connect-gpios = <&gpx3 0 1>; - disabled-ports = <2 3>; - intn-gpios = <&gpx3 4 1>; - reset-gpios = <&gpx3 5 1>; - initial-mode = <1>; - clocks = <&clks 80>; - clock-names = "refclk"; - }; - }; + i2c { + #address-cells = <1>; + #size-cells = <0>; + + usb-hub@8 { + compatible = "smsc,usb3503"; + reg = <0x08>; + connect-gpios = <&gpx3 0 1>; + disabled-ports = <2 3>; + intn-gpios = <&gpx3 4 1>; + reset-gpios = <&gpx3 5 1>; + initial-mode = <1>; + clocks = <&clks 80>; + clock-names = "refclk"; + }; + }; - | - i2c { - #address-cells = <1>; - #size-cells = <0>; - - usb-hub@8 { - compatible = "smsc,usb3803"; - reg = <0x08>; - connect-gpios = <&gpx3 0 1>; - disabled-ports = <2 3>; - intn-gpios = <&gpx3 4 1>; - reset-gpios = <&gpx3 5 1>; - bypass-gpios = <&gpx3 6 1>; - initial-mode = <3>; - clocks = <&clks 80>; - clock-names = "refclk"; - }; - }; + i2c { + #address-cells = <1>; + #size-cells = <0>; + + usb-hub@8 { + compatible = "smsc,usb3803"; + reg = <0x08>; + connect-gpios = <&gpx3 0 1>; + disabled-ports = <2 3>; + intn-gpios = <&gpx3 4 1>; + reset-gpios = <&gpx3 5 1>; + bypass-gpios = <&gpx3 6 1>; + initial-mode = <3>; + clocks = <&clks 80>; + clock-names = "refclk"; + }; + }; - | - #include <dt-bindings/gpio/gpio.h> - - usb-hub { - /* I2C is not connected */ - compatible = "smsc,usb3503"; - initial-mode = <1>; /* initialize in HUB mode */ - disabled-ports = <1>; - intn-gpios = <&pio 7 5 GPIO_ACTIVE_HIGH>; /* PH5 */ - reset-gpios = <&pio 4 16 GPIO_ACTIVE_LOW>; /* PE16 */ - connect-gpios = <&pio 4 17 GPIO_ACTIVE_HIGH>; /* PE17 */ - refclk-frequency = <19200000>; - }; + #include <dt-bindings/gpio/gpio.h> + + usb-hub { + /* I2C is not connected */ + compatible = "smsc,usb3503"; + initial-mode = <1>; /* initialize in HUB mode */ + disabled-ports = <1>; + intn-gpios = <&pio 7 5 GPIO_ACTIVE_HIGH>; /* PH5 */ + reset-gpios = <&pio 4 16 GPIO_ACTIVE_LOW>; /* PE16 */ + connect-gpios = <&pio 4 17 GPIO_ACTIVE_HIGH>; /* PE17 */ + refclk-frequency = <19200000>; + }; ... diff --git a/Documentation/devicetree/bindings/usb/snps,dwc3-common.yaml b/Documentation/devicetree/bindings/usb/snps,dwc3-common.yaml index 71249b6ba616..6c0b8b653824 100644 --- a/Documentation/devicetree/bindings/usb/snps,dwc3-common.yaml +++ b/Documentation/devicetree/bindings/usb/snps,dwc3-common.yaml @@ -390,6 +390,12 @@ properties: maximum: 8 default: 1 + connector: + $ref: /schemas/connector/usb-connector.yaml# + description: Connector for dual role switch + type: object + unevaluatedProperties: false + port: $ref: /schemas/graph.yaml#/properties/port description: diff --git a/Documentation/devicetree/bindings/usb/ti,usb8041.yaml b/Documentation/devicetree/bindings/usb/ti,usb8041.yaml index bce730a5e237..5e3eae9c2961 100644 --- a/Documentation/devicetree/bindings/usb/ti,usb8041.yaml +++ b/Documentation/devicetree/bindings/usb/ti,usb8041.yaml @@ -4,7 +4,7 @@ $id: http://devicetree.org/schemas/usb/ti,usb8041.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: TI USB8041 USB 3.0 hub controller +title: TI USB8041 and USB8044 USB 3.0 hub controllers maintainers: - Alexander Stein <alexander.stein@ew.tq-group.com> @@ -17,6 +17,8 @@ properties: enum: - usb451,8140 - usb451,8142 + - usb451,8440 + - usb451,8442 reg: true diff --git a/Documentation/devicetree/bindings/usb/usb-device.yaml b/Documentation/devicetree/bindings/usb/usb-device.yaml index c67695681033..09fceb469f10 100644 --- a/Documentation/devicetree/bindings/usb/usb-device.yaml +++ b/Documentation/devicetree/bindings/usb/usb-device.yaml @@ -28,7 +28,8 @@ description: | properties: compatible: - pattern: "^usb[0-9a-f]{1,4},[0-9a-f]{1,4}$" + contains: + pattern: "^usb[0-9a-f]{1,4},[0-9a-f]{1,4}$" description: Device nodes or combined nodes. "usbVID,PID", where VID is the vendor id and PID the product id. The textual representation of VID and PID shall be in lower case diff --git a/Documentation/devicetree/bindings/usb/usb-hub.yaml b/Documentation/devicetree/bindings/usb/usb-hub.yaml new file mode 100644 index 000000000000..5238ab105763 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/usb-hub.yaml @@ -0,0 +1,84 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/usb/usb-hub.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Generic USB Hub + +maintainers: + - Pin-yen Lin <treapking@chromium.org> + +allOf: + - $ref: usb-device.yaml# + +properties: + '#address-cells': + const: 1 + + peer-hub: + $ref: /schemas/types.yaml#/definitions/phandle + description: + phandle to the peer hub on the controller. + + ports: + $ref: /schemas/graph.yaml#/properties/ports + description: + The downstream facing USB ports + + patternProperties: + "^port@[1-9a-f][0-9a-f]*$": + $ref: /schemas/graph.yaml#/properties/port + +patternProperties: + '^.*@[1-9a-f][0-9a-f]*$': + description: The hard wired USB devices + type: object + $ref: /schemas/usb/usb-device.yaml + additionalProperties: true + +required: + - compatible + - reg + +additionalProperties: true + +examples: + - | + usb { + #address-cells = <1>; + #size-cells = <0>; + + /* 2.0 hub on port 1 */ + hub_2_0: hub@1 { + compatible = "usb123,4567"; + reg = <1>; + peer-hub = <&hub_3_0>; + #address-cells = <1>; + #size-cells = <0>; + /* USB 2.0 device on port 5 */ + device@5 { + reg = <5>; + compatible = "usb765,4321"; + }; + }; + + /* 3.0 hub on port 2 */ + hub_3_0: hub@2 { + compatible = "usb123,abcd"; + reg = <2>; + peer-hub = <&hub_2_0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + /* Type-A connector on port 3 */ + port@3 { + reg = <3>; + endpoint { + remote-endpoint = <&usb_a0_ss>; + }; + }; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/usb/usb-switch.yaml b/Documentation/devicetree/bindings/usb/usb-switch.yaml index da76118e73a5..896201912630 100644 --- a/Documentation/devicetree/bindings/usb/usb-switch.yaml +++ b/Documentation/devicetree/bindings/usb/usb-switch.yaml @@ -26,11 +26,24 @@ properties: type: boolean port: - $ref: /schemas/graph.yaml#/properties/port + $ref: /schemas/graph.yaml#/$defs/port-base description: A port node to link the device to a TypeC controller for the purpose of handling altmode muxing and orientation switching. + properties: + endpoint: + $ref: /schemas/graph.yaml#/$defs/endpoint-base + unevaluatedProperties: false + properties: + data-lanes: + $ref: /schemas/types.yaml#/definitions/uint32-array + minItems: 1 + maxItems: 8 + uniqueItems: true + items: + maximum: 8 + ports: $ref: /schemas/graph.yaml#/properties/ports properties: diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml index c01adbaacbbb..5d2a7a8d3ac6 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml @@ -1406,6 +1406,8 @@ patternProperties: description: SKOV A/S "^skyworks,.*": description: Skyworks Solutions, Inc. + "^smartfiber,.*": + description: ShenZhen Smartfiber Technology Co, Ltd. "^smartlabs,.*": description: SmartLabs LLC "^smartrg,.*": @@ -1703,6 +1705,8 @@ patternProperties: description: Wingtech Technology Co., Ltd. "^winlink,.*": description: WinLink Co., Ltd + "^winsen,.*": + description: Winsen Corp. "^winstar,.*": description: Winstar Display Corp. "^wirelesstag,.*": diff --git a/Documentation/driver-api/nvmem.rst b/Documentation/driver-api/nvmem.rst index 5d9500d21ecc..790e2dc652c0 100644 --- a/Documentation/driver-api/nvmem.rst +++ b/Documentation/driver-api/nvmem.rst @@ -59,10 +59,10 @@ For example, a simple nvram case:: devm_nvmem_register(&config); } -Users of board files can define and register nvmem cells using the -nvmem_cell_table struct:: +Device drivers can define and register an nvmem cell using the nvmem_cell_info +struct:: - static struct nvmem_cell_info foo_nvmem_cells[] = { + static const struct nvmem_cell_info foo_nvmem_cell = { { .name = "macaddr", .offset = 0x7f00, @@ -70,13 +70,7 @@ nvmem_cell_table struct:: } }; - static struct nvmem_cell_table foo_nvmem_cell_table = { - .nvmem_name = "i2c-eeprom", - .cells = foo_nvmem_cells, - .ncells = ARRAY_SIZE(foo_nvmem_cells), - }; - - nvmem_add_cell_table(&foo_nvmem_cell_table); + int nvmem_add_one_cell(nvmem, &foo_nvmem_cell); Additionally it is possible to create nvmem cell lookup entries and register them with the nvmem framework from machine code as shown in the example below:: diff --git a/Documentation/features/core/mseal_sys_mappings/arch-support.txt b/Documentation/features/core/mseal_sys_mappings/arch-support.txt index c6cab9760d57..a3c24233eb9b 100644 --- a/Documentation/features/core/mseal_sys_mappings/arch-support.txt +++ b/Documentation/features/core/mseal_sys_mappings/arch-support.txt @@ -12,7 +12,7 @@ | arm64: | ok | | csky: | N/A | | hexagon: | N/A | - | loongarch: | TODO | + | loongarch: | ok | | m68k: | N/A | | microblaze: | N/A | | mips: | TODO | diff --git a/Documentation/filesystems/overlayfs.rst b/Documentation/filesystems/overlayfs.rst index 2db379b4b31e..4133a336486d 100644 --- a/Documentation/filesystems/overlayfs.rst +++ b/Documentation/filesystems/overlayfs.rst @@ -443,6 +443,13 @@ Only the data of the files in the "data-only" lower layers may be visible when a "metacopy" file in one of the lower layers above it, has a "redirect" to the absolute path of the "lower data" file in the "data-only" lower layer. +Instead of explicitly enabling "metacopy=on" it is sufficient to specify at +least one data-only layer to enable redirection of data to a data-only layer. +In this case other forms of metacopy are rejected. Note: this way data-only +layers may be used toghether with "userxattr", in which case careful attention +must be given to privileges needed to change the "user.overlay.redirect" xattr +to prevent misuse. + Since kernel version v6.8, "data-only" lower layers can also be added using the "datadir+" mount options and the fsconfig syscall from new mount api. For example:: diff --git a/Documentation/filesystems/smb/index.rst b/Documentation/filesystems/smb/index.rst index 1c8597a679ab..6df23b0e45c8 100644 --- a/Documentation/filesystems/smb/index.rst +++ b/Documentation/filesystems/smb/index.rst @@ -8,3 +8,4 @@ CIFS ksmbd cifsroot + smbdirect diff --git a/Documentation/filesystems/smb/smbdirect.rst b/Documentation/filesystems/smb/smbdirect.rst new file mode 100644 index 000000000000..ca6927c0b2c0 --- /dev/null +++ b/Documentation/filesystems/smb/smbdirect.rst @@ -0,0 +1,103 @@ +.. SPDX-License-Identifier: GPL-2.0 + +=========================== +SMB Direct - SMB3 over RDMA +=========================== + +This document describes how to set up the Linux SMB client and server to +use RDMA. + +Overview +======== +The Linux SMB kernel client supports SMB Direct, which is a transport +scheme for SMB3 that uses RDMA (Remote Direct Memory Access) to provide +high throughput and low latencies by bypassing the traditional TCP/IP +stack. +SMB Direct on the Linux SMB client can be tested against KSMBD - a +kernel-space SMB server. + +Installation +============= +- Install an RDMA device. As long as the RDMA device driver is supported + by the kernel, it should work. This includes both software emulators (soft + RoCE, soft iWARP) and hardware devices (InfiniBand, RoCE, iWARP). + +- Install a kernel with SMB Direct support. The first kernel release to + support SMB Direct on both the client and server side is 5.15. Therefore, + a distribution compatible with kernel 5.15 or later is required. + +- Install cifs-utils, which provides the `mount.cifs` command to mount SMB + shares. + +- Configure the RDMA stack + + Make sure that your kernel configuration has RDMA support enabled. Under + Device Drivers -> Infiniband support, update the kernel configuration to + enable Infiniband support. + + Enable the appropriate IB HCA support or iWARP adapter support, + depending on your hardware. + + If you are using InfiniBand, enable IP-over-InfiniBand support. + + For soft RDMA, enable either the soft iWARP (`RDMA _SIW`) or soft RoCE + (`RDMA_RXE`) module. Install the `iproute2` package and use the + `rdma link add` command to load the module and create an + RDMA interface. + + e.g. if your local ethernet interface is `eth0`, you can use: + + .. code-block:: bash + + sudo rdma link add siw0 type siw netdev eth0 + +- Enable SMB Direct support for both the server and the client in the kernel + configuration. + + Server Setup + + .. code-block:: text + + Network File Systems ---> + <M> SMB3 server support + [*] Support for SMB Direct protocol + + Client Setup + + .. code-block:: text + + Network File Systems ---> + <M> SMB3 and CIFS support (advanced network filesystem) + [*] SMB Direct support + +- Build and install the kernel. SMB Direct support will be enabled in the + cifs.ko and ksmbd.ko modules. + +Setup and Usage +================ + +- Set up and start a KSMBD server as described in the `KSMBD documentation + <https://www.kernel.org/doc/Documentation/filesystems/smb/ksmbd.rst>`_. + Also add the "server multi channel support = yes" parameter to ksmbd.conf. + +- On the client, mount the share with `rdma` mount option to use SMB Direct + (specify a SMB version 3.0 or higher using `vers`). + + For example: + + .. code-block:: bash + + mount -t cifs //server/share /mnt/point -o vers=3.1.1,rdma + +- To verify that the mount is using SMB Direct, you can check dmesg for the + following log line after mounting: + + .. code-block:: text + + CIFS: VFS: RDMA transport established + + Or, verify `rdma` mount option for the share in `/proc/mounts`: + + .. code-block:: bash + + cat /proc/mounts | grep cifs diff --git a/Documentation/gpu/xe/index.rst b/Documentation/gpu/xe/index.rst index b2369561f24e..42ba6c263cd0 100644 --- a/Documentation/gpu/xe/index.rst +++ b/Documentation/gpu/xe/index.rst @@ -16,6 +16,7 @@ DG2, etc is provided to prototype the driver. xe_migrate xe_cs xe_pm + xe_gt_freq xe_pcode xe_gt_mcr xe_wa diff --git a/Documentation/gpu/xe/xe_gt_freq.rst b/Documentation/gpu/xe/xe_gt_freq.rst new file mode 100644 index 000000000000..c0811200e327 --- /dev/null +++ b/Documentation/gpu/xe/xe_gt_freq.rst @@ -0,0 +1,14 @@ +.. SPDX-License-Identifier: (GPL-2.0+ OR MIT) + +========================== +Xe GT Frequency Management +========================== + +.. kernel-doc:: drivers/gpu/drm/xe/xe_gt_freq.c + :doc: Xe GT Frequency Management + +Internal API +============ + +.. kernel-doc:: drivers/gpu/drm/xe/xe_gt_freq.c + :internal: diff --git a/Documentation/iio/ad3552r.rst b/Documentation/iio/ad3552r.rst new file mode 100644 index 000000000000..f5d59e4e86c7 --- /dev/null +++ b/Documentation/iio/ad3552r.rst @@ -0,0 +1,72 @@ +.. SPDX-License-Identifier: GPL-2.0-only + +============== +AD3552R driver +============== + +Device driver for Analog Devices Inc. AD35XXR series of DACs. The module name +is ``ad3552r``. +With the same module name, two different driver variants are available, the +``generic spi`` variant, to be used with any classic SPI controllers, and the +``hs`` (high speed) variant, for an ADI ``axi-dac`` (IP core) based controller +that allows to reach the maximum sample rate supported from the DACs, using the +DMA transfer and all the SPI lines available (D/QDSPI).. +The high speed driver variant is intended to be used with the ``adi-axi-dac`` +backend support enabled, that is enabled by default when the driver is selected. + +Supported devices +================= + +* `AD3541R <https://www.analog.com/en/products/ad3541r.html>`_ +* `AD3542R <https://www.analog.com/en/products/ad3542r.html>`_ +* `AD3551R <https://www.analog.com/en/products/ad3551r.html>`_ +* `AD3552R <https://www.analog.com/en/products/ad3552r.html>`_ + +Wiring connections +================== + +Generic SPI +----------- +Use the classic SPI S_CLK/CS/SDO/SDI connection. + +High speed (using axi-dac backend) +---------------------------------- + +:: + + .-----------------. .-------. + | |--- D/QSPI -----| | + | DAC IP CORE |--- SPI S_CLK --| DAC | + | |--- SPI CS -----| | + | |--- LDAC -------| | + | |--- RESET ------| | + |_________________| |_______| + + +High speed features +=================== + +Device attributes +----------------- + +The following table shows the ad35xxr related device debug files, found in the +specific debugfs path ``/sys/kernel/debug/iio/iio:deviceX``. + ++-----------------------+------------------------------------------------------+ +| Debugfs device files | Description | ++-----------------------+------------------------------------------------------+ +| data_source | The used data source, as | +| | ``normal``, ``ramp-16bit``, etc. | ++-----------------------+------------------------------------------------------+ +| data_source_available | The available data sources. | ++-----------------------+------------------------------------------------------+ + +Usage examples +-------------- + +. code-block:: bash + root:/sys/bus/iio/devices/iio:device0# cat data_source + normal + root:/sys/bus/iio/devices/iio:device0# echo -n ramp-16bit > data_source + root:/sys/bus/iio/devices/iio:device0# cat data_source + ramp-16bit diff --git a/Documentation/iio/ad4000.rst b/Documentation/iio/ad4000.rst index de8fd3ae6e62..c1d04d3436d2 100644 --- a/Documentation/iio/ad4000.rst +++ b/Documentation/iio/ad4000.rst @@ -4,7 +4,7 @@ AD4000 driver ============= -Device driver for Analog Devices Inc. AD4000 series of ADCs. +Device driver for Analog Devices Inc. AD4000 series of ADCs and similar devices. Supported devices ================= @@ -25,6 +25,21 @@ Supported devices * `AD4022 <https://www.analog.com/AD4022>`_ * `ADAQ4001 <https://www.analog.com/ADAQ4001>`_ * `ADAQ4003 <https://www.analog.com/ADAQ4003>`_ +* `AD7685 <https://www.analog.com/AD7685>`_ +* `AD7686 <https://www.analog.com/AD7686>`_ +* `AD7687 <https://www.analog.com/AD7687>`_ +* `AD7688 <https://www.analog.com/AD7688>`_ +* `AD7690 <https://www.analog.com/AD7690>`_ +* `AD7691 <https://www.analog.com/AD7691>`_ +* `AD7693 <https://www.analog.com/AD7693>`_ +* `AD7942 <https://www.analog.com/AD7942>`_ +* `AD7946 <https://www.analog.com/AD7946>`_ +* `AD7980 <https://www.analog.com/AD7980>`_ +* `AD7982 <https://www.analog.com/AD7982>`_ +* `AD7983 <https://www.analog.com/AD7983>`_ +* `AD7984 <https://www.analog.com/AD7984>`_ +* `AD7988-1 <https://www.analog.com/AD7988-1>`_ +* `AD7988-5 <https://www.analog.com/AD7988-5>`_ Wiring connections ------------------ @@ -129,3 +144,77 @@ Set ``adi,sdi-pin`` to ``"cs"`` to select this mode. ^ | | +--------------------| SCLK | +-------------+ + +IIO Device characteristics +========================== + +The AD4000 series driver supports differential and pseudo-differential ADCs. + +The span compression feature available in AD4000 series devices can be +enabled/disabled by changing the ``_scale_available`` attribute of the voltage +channel. Note that span compression configuration requires writing to AD4000 +configuration register, which is only possible when the ADC is wired in 3-wire +turbo mode, and the SPI controller is ``SPI_MOSI_IDLE_HIGH`` capable. If those +conditions are not met, no ``_scale_available`` attribute is provided. + +Besides that, differential and pseudo-differential voltage channels present +slightly different sysfs interfaces. + +Pseudo-differential ADCs +------------------------ + +Typical voltage channel attributes of a pseudo-differential AD4000 series device: + ++-------------------------------------------+------------------------------------------+ +| Voltage Channel Attributes | Description | ++===========================================+==========================================+ +| ``in_voltage0_raw`` | Raw ADC output code. | ++-------------------------------------------+------------------------------------------+ +| ``in_voltage0_offset`` | Offset to convert raw value to mV. | ++-------------------------------------------+------------------------------------------+ +| ``in_voltage0_scale`` | Scale factor to convert raw value to mV. | ++-------------------------------------------+------------------------------------------+ +| ``in_voltage0_scale_available`` | Toggles input span compression | ++-------------------------------------------+------------------------------------------+ + +Differential ADCs +----------------- + +Typical voltage channel attributes of a differential AD4000 series device: + ++-------------------------------------------+------------------------------------------+ +| Voltage Channel Attributes | Description | ++===========================================+==========================================+ +| ``in_voltage0-voltage1_raw`` | Raw ADC output code. | ++-------------------------------------------+------------------------------------------+ +| ``in_voltage0-voltage1_scale`` | Scale factor to convert raw value to mV. | ++-------------------------------------------+------------------------------------------+ +| ``in_voltage0-voltage1_scale_available`` | Toggles input span compression | ++-------------------------------------------+------------------------------------------+ + +SPI offload support +------------------- + +To be able to achieve the maximum sample rate, the driver can be used with SPI +offload engines such as the one usually present in `AXI SPI Engine`_, to provide +SPI offload support. + +.. _AXI SPI Engine: http://analogdevicesinc.github.io/hdl/projects/pulsar_adc/index.html + +To keep up with SPI offloading transfer speeds, the ADC must be connected either +in 3-wire turbo mode or in 3-wire without busy indicator mode and have SPI +controller CS line connected to the CNV pin. + +When set for SPI offload support, the IIO device will provide different +interfaces. + +* Either ``in_voltage0_sampling_frequency`` or + ``in_voltage0-voltage1_sampling_frequency`` file is provided to allow setting + the sample rate. +* IIO trigger device is not provided (no ``trigger`` directory). +* ``timestamp`` channel is not provided. + +Also, because the ADC output has a one sample latency (delay) when the device is +wired in "3-wire" mode and only one transfer per sample is done when using SPI +offloading, the first data sample in the buffer is not valid because it contains +the output of an earlier conversion result. diff --git a/Documentation/iio/ad7380.rst b/Documentation/iio/ad7380.rst index 24a92a1c4371..d51f9ee3e939 100644 --- a/Documentation/iio/ad7380.rst +++ b/Documentation/iio/ad7380.rst @@ -27,6 +27,7 @@ The following chips are supported by this driver: * `AD7386-4 <https://www.analog.com/en/products/ad7386-4.html>`_ * `AD7387-4 <https://www.analog.com/en/products/ad7387-4.html>`_ * `AD7388-4 <https://www.analog.com/en/products/ad7388-4.html>`_ +* `AD7389-4 <https://www.analog.com/en/products/ad7389-4.html>`_ * `ADAQ4370-4 <https://www.analog.com/en/products/adaq4370-4.html>`_ * `ADAQ4380-4 <https://www.analog.com/en/products/adaq4380-4.html>`_ * `ADAQ4381-4 <https://www.analog.com/en/products/adaq4381-4.html>`_ @@ -50,6 +51,12 @@ ad7380-4 ad7380-4 supports only an external reference voltage (2.5V to 3.3V). It must be declared in the device tree as ``refin-supply``. +ad7389-4 +~~~~~~~~ + +ad7389-4 supports only an internal reference voltage. ``refin-supply`` and +``refio-supply`` properties are both omitted in this case. + ADAQ devices ~~~~~~~~~~~~ diff --git a/Documentation/iio/ad7606.rst b/Documentation/iio/ad7606.rst index 930199e03c67..5e02516bab40 100644 --- a/Documentation/iio/ad7606.rst +++ b/Documentation/iio/ad7606.rst @@ -26,6 +26,35 @@ SPI wiring modes These ADCs can output data on several SDO lines (1/2/4/8). The driver currently supports only 1 SDO line. +SPI offload wiring +------------------ +When used with a SPI offload, the supported wiring configuration is: + +.. code-block:: + + +-------------+ +-------------+ + | BUSY |-------->| TRIGGER | + | CS |<--------| CS | + | | | | + | ADC | | SPI | + | | | | + | SDI |<--------| SDO | + | DOUTA |-------->| SDI | + | SCLK |<--------| SCLK | + | | | | + | | +-------------+ + | CONVST |<--------| PWM | + +-------------+ +-------------+ + +In this case, the ``pwms`` property is required. +The ``#trigger-source-cells = <1>`` property is also required to connect back +to the SPI offload. The SPI offload will have ``trigger-sources`` property +with a cell to indicate the busy signal: +``<&ad7606 AD4695_TRIGGER_EVENT_BUSY>``. + +.. seealso:: `SPI offload support`_ + + Parallel wiring mode -------------------- @@ -123,6 +152,22 @@ Unimplemented features - CRC indication - Calibration +SPI offload support +=================== + +To be able to achieve the maximum sample rate, the driver can be used with the +`AXI SPI Engine`_ to provide SPI offload support. + +.. _AXI SPI Engine: https://analogdevicesinc.github.io/hdl/library/spi_engine/index.html + +When SPI offload is being used, some attributes will be different. + +* ``trigger`` directory is removed. +* ``sampling_frequency`` attribute is added for setting the sample rate. +* ``timestamp`` channel is removed. +* Buffer data format may be different compared to when offload is not used, + e.g. the ``in_voltage0_type`` attribute. + Device buffers ============== diff --git a/Documentation/iio/index.rst b/Documentation/iio/index.rst index bbb2edce8272..2d6afc5a8ed5 100644 --- a/Documentation/iio/index.rst +++ b/Documentation/iio/index.rst @@ -19,6 +19,7 @@ Industrial I/O Kernel Drivers .. toctree:: :maxdepth: 1 + ad3552r ad4000 ad4030 ad4695 diff --git a/Documentation/kbuild/gendwarfksyms.rst b/Documentation/kbuild/gendwarfksyms.rst index e4beaae7e456..ed366250a54e 100644 --- a/Documentation/kbuild/gendwarfksyms.rst +++ b/Documentation/kbuild/gendwarfksyms.rst @@ -2,8 +2,8 @@ DWARF module versioning ======================= -1. Introduction -=============== +Introduction +============ When CONFIG_MODVERSIONS is enabled, symbol versions for modules are typically calculated from preprocessed source code using the @@ -14,8 +14,8 @@ selected, **gendwarfksyms** is used instead to calculate symbol versions from the DWARF debugging information, which contains the necessary details about the final module ABI. -1.1. Usage -========== +Usage +----- gendwarfksyms accepts a list of object files on the command line, and a list of symbol names (one per line) in standard input:: @@ -33,8 +33,8 @@ list of symbol names (one per line) in standard input:: -h, --help Print this message -2. Type information availability -================================ +Type information availability +============================= While symbols are typically exported in the same translation unit (TU) where they're defined, it's also perfectly fine for a TU to export @@ -56,8 +56,8 @@ type for calculating symbol versions even if the symbol is defined elsewhere. The name of the symbol pointer is expected to start with `__gendwarfksyms_ptr_`, followed by the name of the exported symbol. -3. Symtypes output format -========================= +Symtypes output format +====================== Similarly to genksyms, gendwarfksyms supports writing a symtypes file for each processed object that contain types for exported @@ -85,8 +85,8 @@ produces C-style type strings, gendwarfksyms uses the same simple parsed DWARF format produced by **--dump-dies**, but with type references instead of fully expanded strings. -4. Maintaining a stable kABI -============================ +Maintaining a stable kABI +========================= Distribution maintainers often need the ability to make ABI compatible changes to kernel data structures due to LTS updates or backports. Using @@ -104,8 +104,8 @@ for source code annotation. Note that as these features are only used to transform the inputs for symbol versioning, the user is responsible for ensuring that their changes actually won't break the ABI. -4.1. kABI rules -=============== +kABI rules +---------- kABI rules allow distributions to fine-tune certain parts of gendwarfksyms output and thus control how symbol @@ -125,22 +125,25 @@ the rules. The fields are as follows: qualified name of the DWARF Debugging Information Entry (DIE). - `value`: Provides rule-specific data. -The following helper macro, for example, can be used to specify rules +The following helper macros, for example, can be used to specify rules in the source code:: - #define __KABI_RULE(hint, target, value) \ - static const char __PASTE(__gendwarfksyms_rule_, \ + #define ___KABI_RULE(hint, target, value) \ + static const char __PASTE(__gendwarfksyms_rule_, \ __COUNTER__)[] __used __aligned(1) \ __section(".discard.gendwarfksyms.kabi_rules") = \ - "1\0" #hint "\0" #target "\0" #value + "1\0" #hint "\0" target "\0" value + + #define __KABI_RULE(hint, target, value) \ + ___KABI_RULE(hint, #target, #value) Currently, only the rules discussed in this section are supported, but the format is extensible enough to allow further rules to be added as need arises. -4.1.1. Managing definition visibility -===================================== +Managing definition visibility +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A declaration can change into a full definition when additional includes are pulled into the translation unit. This changes the versions of any @@ -168,8 +171,8 @@ Example usage:: KABI_DECLONLY(s); -4.1.2. Adding enumerators -========================= +Adding enumerators +~~~~~~~~~~~~~~~~~~ For enums, all enumerators and their values are included in calculating symbol versions, which becomes a problem if we later need to add more @@ -223,8 +226,89 @@ Example usage:: KABI_ENUMERATOR_IGNORE(e, C); KABI_ENUMERATOR_VALUE(e, LAST, 2); -4.3. Adding structure members -============================= +Managing structure size changes +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A data structure can be partially opaque to modules if its allocation is +handled by the core kernel, and modules only need to access some of its +members. In this situation, it's possible to append new members to the +structure without breaking the ABI, as long as the layout for the original +members remains unchanged. + +To append new members, we can hide them from symbol versioning as +described in section :ref:`Hiding members <hiding_members>`, but we can't +hide the increase in structure size. The `byte_size` rule allows us to +override the structure size used for symbol versioning. + +The rule fields are expected to be as follows: + +- `type`: "byte_size" +- `target`: The fully qualified name of the target data structure + (as shown in **--dump-dies** output). +- `value`: A positive decimal number indicating the structure size + in bytes. + +Using the `__KABI_RULE` macro, this rule can be defined as:: + + #define KABI_BYTE_SIZE(fqn, value) \ + __KABI_RULE(byte_size, fqn, value) + +Example usage:: + + struct s { + /* Unchanged original members */ + unsigned long a; + void *p; + + /* Appended new members */ + KABI_IGNORE(0, unsigned long n); + }; + + KABI_BYTE_SIZE(s, 16); + +Overriding type strings +~~~~~~~~~~~~~~~~~~~~~~~ + +In rare situations where distributions must make significant changes to +otherwise opaque data structures that have inadvertently been included +in the published ABI, keeping symbol versions stable using the more +targeted kABI rules can become tedious. The `type_string` rule allows us +to override the full type string for a type or a symbol, and even add +types for versioning that no longer exist in the kernel. + +The rule fields are expected to be as follows: + +- `type`: "type_string" +- `target`: The fully qualified name of the target data structure + (as shown in **--dump-dies** output) or symbol. +- `value`: A valid type string (as shown in **--symtypes**) output) + to use instead of the real type. + +Using the `__KABI_RULE` macro, this rule can be defined as:: + + #define KABI_TYPE_STRING(type, str) \ + ___KABI_RULE("type_string", type, str) + +Example usage:: + + /* Override type for a structure */ + KABI_TYPE_STRING("s#s", + "structure_type s { " + "member base_type int byte_size(4) " + "encoding(5) n " + "data_member_location(0) " + "} byte_size(8)"); + + /* Override type for a symbol */ + KABI_TYPE_STRING("my_symbol", "variable s#s"); + +The `type_string` rule should be used only as a last resort if maintaining +a stable symbol versions cannot be reasonably achieved using other +means. Overriding a type string increases the risk of actual ABI breakages +going unnoticed as it hides all changes to the type. + +Adding structure members +------------------------ Perhaps the most common ABI compatible change is adding a member to a kernel data structure. When changes to a structure are anticipated, @@ -237,8 +321,8 @@ natural method. This section describes gendwarfksyms support for using reserved space in data structures and hiding members that don't change the ABI when calculating symbol versions. -4.3.1. Reserving space and replacing members -============================================ +Reserving space and replacing members +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Space is typically reserved for later use by appending integer types, or arrays, to the end of the data structure, but any type can be used. Each @@ -276,8 +360,10 @@ The examples include `KABI_(RESERVE|USE|REPLACE)*` macros that help simplify the process and also ensure the replacement member is correctly aligned and its size won't exceed the reserved space. -4.3.2. Hiding members -===================== +.. _hiding_members: + +Hiding members +~~~~~~~~~~~~~~ Predicting which structures will require changes during the support timeframe isn't always possible, in which case one might have to resort @@ -305,4 +391,5 @@ member to a union where one of the fields has a name starting with unsigned long b; }; -With **--stable**, both versions produce the same symbol version. +With **--stable**, both versions produce the same symbol version. The +examples include a `KABI_IGNORE` macro to simplify the code. diff --git a/Documentation/kbuild/makefiles.rst b/Documentation/kbuild/makefiles.rst index 38cc656fac20..8aef3650c1f3 100644 --- a/Documentation/kbuild/makefiles.rst +++ b/Documentation/kbuild/makefiles.rst @@ -291,6 +291,10 @@ Example:: # arch/x86/kernel/Makefile extra-y += vmlinux.lds +extra-y is now deprecated because this is equivalent to: + + always-$(KBUILD_BUILTIN) += vmlinux.lds + $(extra-y) should only contain targets needed for vmlinux. Kbuild skips extra-y when vmlinux is apparently not a final goal. diff --git a/Documentation/misc-devices/amd-sbi.rst b/Documentation/misc-devices/amd-sbi.rst new file mode 100644 index 000000000000..5648fc6ec572 --- /dev/null +++ b/Documentation/misc-devices/amd-sbi.rst @@ -0,0 +1,99 @@ +.. SPDX-License-Identifier: GPL-2.0 + +======================= +AMD SIDE BAND interface +======================= + +Some AMD Zen based processors supports system management +functionality via side-band interface (SBI) called +Advanced Platform Management Link (APML). APML is an I2C/I3C +based 2-wire processor target interface. APML is used to +communicate with the Remote Management Interface +(SB Remote Management Interface (SB-RMI) +and SB Temperature Sensor Interface (SB-TSI)). + +More details on the interface can be found in chapter +"5 Advanced Platform Management Link (APML)" of the family/model PPR [1]_. + +.. [1] https://www.amd.com/content/dam/amd/en/documents/epyc-technical-docs/programmer-references/55898_B1_pub_0_50.zip + + +SBRMI device +============ + +apml_sbrmi driver under the drivers/misc/amd-sbi creates miscdevice +/dev/sbrmi-* to let user space programs run APML mailbox, CPUID, +MCAMSR and register xfer commands. + +Register sets is common across APML protocols. IOCTL is providing synchronization +among protocols as transactions may create race condition. + +$ ls -al /dev/sbrmi-3c +crw------- 1 root root 10, 53 Jul 10 11:13 /dev/sbrmi-3c + +apml_sbrmi driver registers hwmon sensors for monitoring power_cap_max, +current power consumption and managing power_cap. + +Characteristics of the dev node: + * Differnet xfer protocols are defined: + * Mailbox + * CPUID + * MCA_MSR + * Register xfer + +Access restrictions: + * Only root user is allowed to open the file. + * APML Mailbox messages and Register xfer access are read-write, + * CPUID and MCA_MSR access is read-only. + +Driver IOCTLs +============= + +.. c:macro:: SBRMI_IOCTL_MBOX_CMD +.. kernel-doc:: include/uapi/misc/amd-apml.h + :doc: SBRMI_IOCTL_MBOX_CMD +.. c:macro:: SBRMI_IOCTL_CPUID_CMD +.. kernel-doc:: include/uapi/misc/amd-apml.h + :doc: SBRMI_IOCTL_CPUID_CMD +.. c:macro:: SBRMI_IOCTL_MCAMSR_CMD +.. kernel-doc:: include/uapi/misc/amd-apml.h + :doc: SBRMI_IOCTL_MCAMSR_CMD +.. c:macro:: SBRMI_IOCTL_REG_XFER_CMD +.. kernel-doc:: include/uapi/misc/amd-apml.h + :doc: SBRMI_IOCTL_REG_XFER_CMD + +User-space usage +================ + +To access side band interface from a C program. +First, user need to include the headers:: + + #include <uapi/misc/amd-apml.h> + +Which defines the supported IOCTL and data structure to be passed +from the user space. + +Next thing, open the device file, as follows:: + + int file; + + file = open("/dev/sbrmi-*", O_RDWR); + if (file < 0) { + /* ERROR HANDLING */ + exit(1); + } + +The following IOCTLs are defined: + +``#define SB_BASE_IOCTL_NR 0xF9`` +``#define SBRMI_IOCTL_MBOX_CMD _IOWR(SB_BASE_IOCTL_NR, 0, struct apml_mbox_msg)`` +``#define SBRMI_IOCTL_CPUID_CMD _IOWR(SB_BASE_IOCTL_NR, 1, struct apml_cpuid_msg)`` +``#define SBRMI_IOCTL_MCAMSR_CMD _IOWR(SB_BASE_IOCTL_NR, 2, struct apml_mcamsr_msg)`` +``#define SBRMI_IOCTL_REG_XFER_CMD _IOWR(SB_BASE_IOCTL_NR, 3, struct apml_reg_xfer_msg)`` + + +User space C-APIs are made available by esmi_oob_library, hosted at +[2]_ which is provided by the E-SMS project [3]_. + +.. [2] https://github.com/amd/esmi_oob_library +.. [3] https://www.amd.com/en/developer/e-sms.html diff --git a/Documentation/misc-devices/index.rst b/Documentation/misc-devices/index.rst index 8c5b226d8313..081e79415e38 100644 --- a/Documentation/misc-devices/index.rst +++ b/Documentation/misc-devices/index.rst @@ -12,6 +12,7 @@ fit into other categories. :maxdepth: 2 ad525x_dpot + amd-sbi apds990x bh1770glc c2port diff --git a/Documentation/misc-devices/lis3lv02d.rst b/Documentation/misc-devices/lis3lv02d.rst index 959bd2b822cf..6b3b7405ebdf 100644 --- a/Documentation/misc-devices/lis3lv02d.rst +++ b/Documentation/misc-devices/lis3lv02d.rst @@ -22,10 +22,10 @@ sporting the feature officially called "HP Mobile Data Protection System 3D" or models (full list can be found in drivers/platform/x86/hp_accel.c) will have their axis automatically oriented on standard way (eg: you can directly play neverball). The accelerometer data is readable via -/sys/devices/platform/lis3lv02d. Reported values are scaled +/sys/devices/faux/lis3lv02d. Reported values are scaled to mg values (1/1000th of earth gravity). -Sysfs attributes under /sys/devices/platform/lis3lv02d/: +Sysfs attributes under /sys/devices/faux/lis3lv02d/: position - 3D position that the accelerometer reports. Format: "(x,y,z)" @@ -85,7 +85,7 @@ the accelerometer are converted into a "standard" organisation of the axes If your laptop model is not recognized (cf "dmesg"), you can send an email to the maintainer to add it to the database. When reporting a new laptop, please include the output of "dmidecode" plus the value of -/sys/devices/platform/lis3lv02d/position in these four cases. +/sys/devices/faux/lis3lv02d/position in these four cases. Q&A --- diff --git a/Documentation/sound/soc/index.rst b/Documentation/sound/soc/index.rst index e57df2dab2fd..8bed8f8f48da 100644 --- a/Documentation/sound/soc/index.rst +++ b/Documentation/sound/soc/index.rst @@ -18,3 +18,4 @@ The documentation is spilt into the following sections:- jack dpcm codec-to-codec + usb diff --git a/Documentation/sound/soc/usb.rst b/Documentation/sound/soc/usb.rst new file mode 100644 index 000000000000..94c12f9d9dd1 --- /dev/null +++ b/Documentation/sound/soc/usb.rst @@ -0,0 +1,482 @@ +================ +ASoC USB support +================ + +Overview +======== +In order to leverage the existing USB sound device support in ALSA, the +ASoC USB APIs are introduced to allow the subsystems to exchange +configuration information. + +One potential use case would be to support USB audio offloading, which is +an implementation that allows for an alternate power-optimized path in the audio +subsystem to handle the transfer of audio data over the USB bus. This would +let the main processor to stay in lower power modes for longer duration. The +following is an example design of how the ASoC and ALSA pieces can be connected +together to achieve this: + +:: + + USB | ASoC + | _________________________ + | | ASoC Platform card | + | |_________________________| + | | | + | ___V____ ____V____ + | |ASoC BE | |ASoC FE | + | |DAI LNK | |DAI LNK | + | |________| |_________| + | ^ ^ ^ + | | |________| + | ___V____ | + | |SoC-USB | | + ________ ________ | | | + |USB SND |<--->|USBSND |<------------>|________| | + |(card.c)| |offld |<---------- | + |________| |________|___ | | | + ^ ^ | | | ____________V_________ + | | | | | |IPC | + __ V_______________V_____ | | | |______________________| + |USB SND (endpoint.c) | | | | ^ + |_________________________| | | | | + ^ | | | ___________V___________ + | | | |->|audio DSP | + ___________V_____________ | | |_______________________| + |XHCI HCD |<- | + |_________________________| | + + +SoC USB driver +============== +Structures +---------- +``struct snd_soc_usb`` + + - ``list``: list head for SND SoC struct list + - ``component``: reference to ASoC component + - ``connection_status_cb``: callback to notify connection events + - ``update_offload_route_info``: callback to fetch selected USB sound card/PCM + device + - ``priv_data``: driver data + +The snd_soc_usb structure can be referenced using the ASoC platform card +device, or a USB device (udev->dev). This is created by the ASoC BE DAI +link, and the USB sound entity will be able to pass information to the +ASoC BE DAI link using this structure. + +``struct snd_soc_usb_device`` + + - ``card_idx``: sound card index associated with USB sound device + - ``chip_idx``: USB sound chip array index + - ``cpcm_idx``: capture pcm device indexes associated with the USB sound device + - ``ppcm_idx``: playback pcm device indexes associated with the USB sound device + - ``num_playback``: number of playback streams + - ``num_capture``: number of capture streams + - ``list``: list head for the USB sound device list + +The struct snd_soc_usb_device is created by the USB sound offload driver. +This will carry basic parameters/limitations that will be used to +determine the possible offloading paths for this USB audio device. + +Functions +--------- +.. code-block:: rst + + int snd_soc_usb_find_supported_format(int card_idx, + struct snd_pcm_hw_params *params, int direction) +.. + + - ``card_idx``: the index into the USB sound chip array. + - ``params``: Requested PCM parameters from the USB DPCM BE DAI link + - ``direction``: capture or playback + +**snd_soc_usb_find_supported_format()** ensures that the requested audio profile +being requested by the external DSP is supported by the USB device. + +Returns 0 on success, and -EOPNOTSUPP on failure. + +.. code-block:: rst + + int snd_soc_usb_connect(struct device *usbdev, struct snd_soc_usb_device *sdev) +.. + + - ``usbdev``: the usb device that was discovered + - ``sdev``: capabilities of the device + +**snd_soc_usb_connect()** notifies the ASoC USB DCPM BE DAI link of a USB +audio device detection. This can be utilized in the BE DAI +driver to keep track of available USB audio devices. This is intended +to be called by the USB offload driver residing in USB SND. + +Returns 0 on success, negative error code on failure. + +.. code-block:: rst + + int snd_soc_usb_disconnect(struct device *usbdev, struct snd_soc_usb_device *sdev) +.. + + - ``usbdev``: the usb device that was removed + - ``sdev``: capabilities to free + +**snd_soc_usb_disconnect()** notifies the ASoC USB DCPM BE DAI link of a USB +audio device removal. This is intended to be called by the USB offload +driver that resides in USB SND. + +.. code-block:: rst + + void *snd_soc_usb_find_priv_data(struct device *usbdev) +.. + + - ``usbdev``: the usb device to reference to find private data + +**snd_soc_usb_find_priv_data()** fetches the private data saved to the SoC USB +device. + +Returns pointer to priv_data on success, NULL on failure. + +.. code-block:: rst + + int snd_soc_usb_setup_offload_jack(struct snd_soc_component *component, + struct snd_soc_jack *jack) +.. + + - ``component``: ASoC component to add the jack + - ``jack``: jack component to populate + +**snd_soc_usb_setup_offload_jack()** is a helper to add a sound jack control to +the platform sound card. This will allow for consistent naming to be used on +designs that support USB audio offloading. Additionally, this will enable the +jack to notify of changes. + +Returns 0 on success, negative otherwise. + +.. code-block:: rst + + int snd_soc_usb_update_offload_route(struct device *dev, int card, int pcm, + int direction, enum snd_soc_usb_kctl path, + long *route) +.. + + - ``dev``: USB device to look up offload path mapping + - ``card``: USB sound card index + - ``pcm``: USB sound PCM device index + - ``direction``: direction to fetch offload routing information + - ``path``: kcontrol selector - pcm device or card index + - ``route``: mapping of sound card and pcm indexes for the offload path. This is + an array of two integers that will carry the card and pcm device indexes + in that specific order. This can be used as the array for the kcontrol + output. + +**snd_soc_usb_update_offload_route()** calls a registered callback to the USB BE DAI +link to fetch the information about the mapped ASoC devices for executing USB audio +offload for the device. ``route`` may be a pointer to a kcontrol value output array, +which carries values when the kcontrol is read. + +Returns 0 on success, negative otherwise. + +.. code-block:: rst + + struct snd_soc_usb *snd_soc_usb_allocate_port(struct snd_soc_component *component, + void *data); +.. + + - ``component``: DPCM BE DAI link component + - ``data``: private data + +**snd_soc_usb_allocate_port()** allocates a SoC USB device and populates standard +parameters that is used for further operations. + +Returns a pointer to struct soc_usb on success, negative on error. + +.. code-block:: rst + + void snd_soc_usb_free_port(struct snd_soc_usb *usb); +.. + + - ``usb``: SoC USB device to free + +**snd_soc_usb_free_port()** frees a SoC USB device. + +.. code-block:: rst + + void snd_soc_usb_add_port(struct snd_soc_usb *usb); +.. + + - ``usb``: SoC USB device to add + +**snd_soc_usb_add_port()** add an allocated SoC USB device to the SOC USB framework. +Once added, this device can be referenced by further operations. + +.. code-block:: rst + + void snd_soc_usb_remove_port(struct snd_soc_usb *usb); +.. + + - ``usb``: SoC USB device to remove + +**snd_soc_usb_remove_port()** removes a SoC USB device from the SoC USB framework. +After removing a device, any SOC USB operations would not be able to reference the +device removed. + +How to Register to SoC USB +-------------------------- +The ASoC DPCM USB BE DAI link is the entity responsible for allocating and +registering the SoC USB device on the component bind. Likewise, it will +also be responsible for freeing the allocated resources. An example can +be shown below: + +.. code-block:: rst + + static int q6usb_component_probe(struct snd_soc_component *component) + { + ... + data->usb = snd_soc_usb_allocate_port(component, 1, &data->priv); + if (!data->usb) + return -ENOMEM; + + usb->connection_status_cb = q6usb_alsa_connection_cb; + + ret = snd_soc_usb_add_port(usb); + if (ret < 0) { + dev_err(component->dev, "failed to add usb port\n"); + goto free_usb; + } + ... + } + + static void q6usb_component_remove(struct snd_soc_component *component) + { + ... + snd_soc_usb_remove_port(data->usb); + snd_soc_usb_free_port(data->usb); + } + + static const struct snd_soc_component_driver q6usb_dai_component = { + .probe = q6usb_component_probe, + .remove = q6usb_component_remove, + .name = "q6usb-dai-component", + ... + }; +.. + +BE DAI links can pass along vendor specific information as part of the +call to allocate the SoC USB device. This will allow any BE DAI link +parameters or settings to be accessed by the USB offload driver that +resides in USB SND. + +USB Audio Device Connection Flow +-------------------------------- +USB devices can be hotplugged into the USB ports at any point in time. +The BE DAI link should be aware of the current state of the physical USB +port, i.e. if there are any USB devices with audio interface(s) connected. +connection_status_cb() can be used to notify the BE DAI link of any change. + +This is called whenever there is a USB SND interface bind or remove event, +using snd_soc_usb_connect() or snd_soc_usb_disconnect(): + +.. code-block:: rst + + static void qc_usb_audio_offload_probe(struct snd_usb_audio *chip) + { + ... + snd_soc_usb_connect(usb_get_usb_backend(udev), sdev); + ... + } + + static void qc_usb_audio_offload_disconnect(struct snd_usb_audio *chip) + { + ... + snd_soc_usb_disconnect(usb_get_usb_backend(chip->dev), dev->sdev); + ... + } +.. + +In order to account for conditions where driver or device existence is +not guaranteed, USB SND exposes snd_usb_rediscover_devices() to resend the +connect events for any identified USB audio interfaces. Consider the +the following situation: + + **usb_audio_probe()** + | --> USB audio streams allocated and saved to usb_chip[] + | --> Propagate connect event to USB offload driver in USB SND + | --> **snd_soc_usb_connect()** exits as USB BE DAI link is not ready + + BE DAI link component probe + | --> DAI link is probed and SoC USB port is allocated + | --> The USB audio device connect event is missed + +To ensure connection events are not missed, **snd_usb_rediscover_devices()** +is executed when the SoC USB device is registered. Now, when the BE DAI +link component probe occurs, the following highlights the sequence: + + BE DAI link component probe + | --> DAI link is probed and SoC USB port is allocated + | --> SoC USB device added, and **snd_usb_rediscover_devices()** runs + + **snd_usb_rediscover_devices()** + | --> Traverses through usb_chip[] and for non-NULL entries issue + | **connection_status_cb()** + +In the case where the USB offload driver is unbound, while USB SND is ready, +the **snd_usb_rediscover_devices()** is called during module init. This allows +for the offloading path to also be enabled with the following flow: + + **usb_audio_probe()** + | --> USB audio streams allocated and saved to usb_chip[] + | --> Propagate connect event to USB offload driver in USB SND + | --> USB offload driver **NOT** ready! + + BE DAI link component probe + | --> DAI link is probed and SoC USB port is allocated + | --> No USB connect event due to missing USB offload driver + + USB offload driver probe + | --> **qc_usb_audio_offload_init()** + | --> Calls **snd_usb_rediscover_devices()** to notify of devices + +USB Offload Related Kcontrols +============================= +Details +------- +A set of kcontrols can be utilized by applications to help select the proper sound +devices to enable USB audio offloading. SoC USB exposes the get_offload_dev() +callback that designs can use to ensure that the proper indices are returned to the +application. + +Implementation +-------------- + +**Example:** + + **Sound Cards**: + + :: + + 0 [SM8250MTPWCD938]: sm8250 - SM8250-MTP-WCD9380-WSA8810-VA-D + SM8250-MTP-WCD9380-WSA8810-VA-DMIC + 1 [Seri ]: USB-Audio - Plantronics Blackwire 3225 Seri + Plantronics Plantronics Blackwire + 3225 Seri at usb-xhci-hcd.1.auto-1.1, + full sp + 2 [C320M ]: USB-Audio - Plantronics C320-M + Plantronics Plantronics C320-M at usb-xhci-hcd.1.auto-1.2, full speed + + **PCM Devices**: + + :: + + card 0: SM8250MTPWCD938 [SM8250-MTP-WCD9380-WSA8810-VA-D], device 0: MultiMedia1 (*) [] + Subdevices: 1/1 + Subdevice #0: subdevice #0 + card 0: SM8250MTPWCD938 [SM8250-MTP-WCD9380-WSA8810-VA-D], device 1: MultiMedia2 (*) [] + Subdevices: 1/1 + Subdevice #0: subdevice #0 + card 1: Seri [Plantronics Blackwire 3225 Seri], device 0: USB Audio [USB Audio] + Subdevices: 1/1 + Subdevice #0: subdevice #0 + card 2: C320M [Plantronics C320-M], device 0: USB Audio [USB Audio] + Subdevices: 1/1 + Subdevice #0: subdevice #0 + + **USB Sound Card** - card#1: + + :: + + USB Offload Playback Card Route PCM#0 -1 (range -1->32) + USB Offload Playback PCM Route PCM#0 -1 (range -1->255) + + **USB Sound Card** - card#2: + + :: + + USB Offload Playback Card Route PCM#0 0 (range -1->32) + USB Offload Playback PCM Route PCM#0 1 (range -1->255) + +The above example shows a scenario where the system has one ASoC platform card +(card#0) and two USB sound devices connected (card#1 and card#2). When reading +the available kcontrols for each USB audio device, the following kcontrols lists +the mapped offload card and pcm device indexes for the specific USB device: + + ``USB Offload Playback Card Route PCM#*`` + + ``USB Offload Playback PCM Route PCM#*`` + +The kcontrol is indexed, because a USB audio device could potentially have +several PCM devices. The above kcontrols are defined as: + + - ``USB Offload Playback Card Route PCM#`` **(R)**: Returns the ASoC platform sound + card index for a mapped offload path. The output **"0"** (card index) signifies + that there is an available offload path for the USB SND device through card#0. + If **"-1"** is seen, then no offload path is available for the USB SND device. + This kcontrol exists for each USB audio device that exists in the system, and + its expected to derive the current status of offload based on the output value + for the kcontrol along with the PCM route kcontrol. + + - ``USB Offload Playback PCM Route PCM#`` **(R)**: Returns the ASoC platform sound + PCM device index for a mapped offload path. The output **"1"** (PCM device index) + signifies that there is an available offload path for the USB SND device through + PCM device#0. If **"-1"** is seen, then no offload path is available for the USB\ + SND device. This kcontrol exists for each USB audio device that exists in the + system, and its expected to derive the current status of offload based on the + output value for this kcontrol, in addition to the card route kcontrol. + +USB Offload Playback Route Kcontrol +----------------------------------- +In order to allow for vendor specific implementations on audio offloading device +selection, the SoC USB layer exposes the following: + +.. code-block:: rst + + int (*update_offload_route_info)(struct snd_soc_component *component, + int card, int pcm, int direction, + enum snd_soc_usb_kctl path, + long *route) +.. + +These are specific for the **USB Offload Playback Card Route PCM#** and **USB +Offload PCM Route PCM#** kcontrols. + +When users issue get calls to the kcontrol, the registered SoC USB callbacks will +execute the registered function calls to the DPCM BE DAI link. + +**Callback Registration:** + +.. code-block:: rst + + static int q6usb_component_probe(struct snd_soc_component *component) + { + ... + usb = snd_soc_usb_allocate_port(component, 1, &data->priv); + if (IS_ERR(usb)) + return -ENOMEM; + + usb->connection_status_cb = q6usb_alsa_connection_cb; + usb->update_offload_route_info = q6usb_get_offload_dev; + + ret = snd_soc_usb_add_port(usb); +.. + +Existing USB Sound Kcontrol +--------------------------- +With the introduction of USB offload support, the above USB offload kcontrol +will be added to the pre existing list of kcontrols identified by the USB sound +framework. These kcontrols are still the main controls that are used to +modify characteristics pertaining to the USB audio device. + + :: + + Number of controls: 9 + ctl type num name value + 0 INT 2 Capture Channel Map 0, 0 (range 0->36) + 1 INT 2 Playback Channel Map 0, 0 (range 0->36) + 2 BOOL 1 Headset Capture Switch On + 3 INT 1 Headset Capture Volume 10 (range 0->13) + 4 BOOL 1 Sidetone Playback Switch On + 5 INT 1 Sidetone Playback Volume 4096 (range 0->8192) + 6 BOOL 1 Headset Playback Switch On + 7 INT 2 Headset Playback Volume 20, 20 (range 0->24) + 8 INT 1 USB Offload Playback Card Route PCM#0 0 (range -1->32) + 9 INT 1 USB Offload Playback PCM Route PCM#0 1 (range -1->255) + +Since USB audio device controls are handled over the USB control endpoint, use the +existing mechanisms present in the USB mixer to set parameters, such as volume. diff --git a/Documentation/trace/coresight/coresight-perf.rst b/Documentation/trace/coresight/coresight-perf.rst index d087aae7d492..30be89320621 100644 --- a/Documentation/trace/coresight/coresight-perf.rst +++ b/Documentation/trace/coresight/coresight-perf.rst @@ -78,6 +78,37 @@ enabled like:: Please refer to the kernel configuration help for more information. +Fine-grained tracing with AUX pause and resume +---------------------------------------------- + +Arm CoreSight may generate a large amount of hardware trace data, which +will lead to overhead in recording and distract users when reviewing +profiling result. To mitigate the issue of excessive trace data, Perf +provides AUX pause and resume functionality for fine-grained tracing. + +The AUX pause and resume can be triggered by associated events. These +events can be ftrace tracepoints (including static and dynamic +tracepoints) or PMU events (e.g. CPU PMU cycle event). To create a perf +session with AUX pause / resume, three configuration terms are +introduced: + +- "aux-action=start-paused": it is specified for the cs_etm PMU event to + launch in a paused state. +- "aux-action=pause": an associated event is specified with this term + to pause AUX trace. +- "aux-action=resume": an associated event is specified with this term + to resume AUX trace. + +Example for triggering AUX pause and resume with ftrace tracepoints:: + + perf record -e cs_etm/aux-action=start-paused/k,syscalls:sys_enter_openat/aux-action=resume/,syscalls:sys_exit_openat/aux-action=pause/ ls + +Example for triggering AUX pause and resume with PMU event:: + + perf record -a -e cs_etm/aux-action=start-paused/k \ + -e cycles/aux-action=pause,period=10000000/ \ + -e cycles/aux-action=resume,period=1050000/ -- sleep 1 + Perf test - Verify kernel and userspace perf CoreSight work ----------------------------------------------------------- diff --git a/Documentation/translations/it_IT/core-api/symbol-namespaces.rst b/Documentation/translations/it_IT/core-api/symbol-namespaces.rst index 6ee713988531..baa344f4523a 100644 --- a/Documentation/translations/it_IT/core-api/symbol-namespaces.rst +++ b/Documentation/translations/it_IT/core-api/symbol-namespaces.rst @@ -10,8 +10,8 @@ Questo documento descrive come usare lo spazio dei nomi dei simboli per strutturare quello che viene esportato internamente al kernel grazie alle macro della famiglia EXPORT_SYMBOL(). -1. Introduzione -=============== +Introduzione +============ Lo spazio dei nomi dei simboli è stato introdotto come mezzo per strutturare l'API esposta internamente al kernel. Permette ai manutentori di un @@ -24,15 +24,15 @@ devono prima importare detto spazio. Altrimenti il kernel, a seconda della configurazione, potrebbe rifiutare di caricare il modulo o avvisare l'utente di un'importazione mancante. -2. Come definire uno spazio dei nomi dei simboli -================================================ +Come definire uno spazio dei nomi dei simboli +============================================= I simboli possono essere esportati in spazi dei nomi usando diversi meccanismi. Tutti questi meccanismi cambiano il modo in cui EXPORT_SYMBOL e simili vengono guidati verso la creazione di voci in ksymtab. -2.1 Usare le macro EXPORT_SYMBOL -================================ +Usare le macro EXPORT_SYMBOL +---------------------------- In aggiunta alle macro EXPORT_SYMBOL() e EXPORT_SYMBOL_GPL(), che permettono di esportare simboli del kernel nella rispettiva tabella, ci sono @@ -53,8 +53,8 @@ di base. Il programma ``modpost`` e il codice in kernel/module/main.c usano lo spazio dei nomi, rispettivamente, durante la compilazione e durante il caricamento di un modulo. -2.2 Usare il simbolo di preprocessore DEFAULT_SYMBOL_NAMESPACE -============================================================== +Usare il simbolo di preprocessore DEFAULT_SYMBOL_NAMESPACE +---------------------------------------------------------- Definire lo spazio dei nomi per tutti i simboli di un sottosistema può essere logorante e di difficile manutenzione. Perciò è stato fornito un simbolo @@ -83,8 +83,8 @@ direttamente nei file da compilare. L'esempio precedente diventerebbe:: Questo va messo prima di un qualsiasi uso di EXPORT_SYMBOL. -3. Come usare i simboli esportati attraverso uno spazio dei nomi -================================================================ +Come usare i simboli esportati attraverso uno spazio dei nomi +============================================================= Per usare i simboli esportati da uno spazio dei nomi, i moduli del kernel devono esplicitamente importare il relativo spazio dei nomi; altrimenti @@ -108,12 +108,10 @@ modinfo:: Si consiglia di posizionare la dichiarazione MODULE_IMPORT_NS() vicino -ai metadati del modulo come MODULE_AUTHOR() o MODULE_LICENSE(). Fate -riferimento alla sezione 5. per creare automaticamente le importazioni -mancanti. +ai metadati del modulo come MODULE_AUTHOR() o MODULE_LICENSE(). -4. Caricare moduli che usano simboli provenienti da spazi dei nomi -================================================================== +Caricare moduli che usano simboli provenienti da spazi dei nomi +=============================================================== Quando un modulo viene caricato (per esempio usando ``insmod``), il kernel verificherà la disponibilità di ogni simbolo usato e se lo spazio dei nomi @@ -125,8 +123,8 @@ un'opzione di configurazione: impostare MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS=y caricherà i moduli comunque ma emetterà un avviso. -5. Creare automaticamente la dichiarazione MODULE_IMPORT_NS -=========================================================== +Creare automaticamente la dichiarazione MODULE_IMPORT_NS +======================================================== La mancanza di un'importazione può essere individuata facilmente al momento della compilazione. Infatti, modpost emetterà un avviso se il modulo usa diff --git a/Documentation/translations/zh_CN/core-api/symbol-namespaces.rst b/Documentation/translations/zh_CN/core-api/symbol-namespaces.rst index b1bec219912d..d9477ccea98f 100644 --- a/Documentation/translations/zh_CN/core-api/symbol-namespaces.rst +++ b/Documentation/translations/zh_CN/core-api/symbol-namespaces.rst @@ -14,18 +14,8 @@ 本文档æè¿°äº†å¦‚何使用符å·å‘½åç©ºé—´æ¥æž„é€ é€šè¿‡EXPORT_SYMBOL()系列å®å¯¼å‡ºçš„å†…æ ¸å†…ç¬¦å·çš„导出é¢ã€‚ -.. 目录 - - === 1 简介 - === 2 如何定义符å·å‘½å空间 - --- 2.1 使用EXPORT_SYMBOLå® - --- 2.2 使用DEFAULT_SYMBOL_NAMESPACE定义 - === 3 如何使用命å空间ä¸å¯¼å‡ºçš„ç¬¦å· - === 4 åŠ è½½ä½¿ç”¨å‘½å空间符å·çš„æ¨¡å— - === 5 自动创建MODULE_IMPORT_NS声明 - -1. 简介 -======= +简介 +==== 符å·å‘½å空间已ç»è¢«å¼•å…¥ï¼Œä½œä¸ºæž„é€ å†…æ ¸å†…API的导出é¢çš„ä¸€ç§æ‰‹æ®µã€‚它å…许å系统维护者将 他们导出的符å·åˆ’分进独立的命å空间。这对于文档的编写éžå¸¸æœ‰ç”¨ï¼ˆæƒ³æƒ³SUBSYSTEM_DEBUG @@ -33,14 +23,14 @@ 的模å—必须导入命å空间。å¦åˆ™ï¼Œå†…æ ¸å°†æ ¹æ®å…¶é…置,拒ç»åŠ è½½è¯¥æ¨¡å—æˆ–è¦å‘Šè¯´ç¼ºå°‘ 导入。 -2. 如何定义符å·å‘½å空间 -======================= +如何定义符å·å‘½å空间 +==================== 符å·å¯ä»¥ç”¨ä¸åŒçš„æ–¹æ³•导出到命åç©ºé—´ã€‚æ‰€æœ‰è¿™äº›éƒ½åœ¨æ”¹å˜ EXPORT_SYMBOL å’Œä¸Žä¹‹ç±»ä¼¼çš„é‚£äº›å® è¢«æ£€æµ‹åˆ°çš„æ–¹å¼ï¼Œä»¥åˆ›å»º ksymtab æ¡ç›®ã€‚ -2.1 使用EXPORT_SYMBOLå® -======================= +使用EXPORT_SYMBOLå® +------------------- 除了å…è®¸å°†å†…æ ¸ç¬¦å·å¯¼å‡ºåˆ°å†…æ ¸ç¬¦å·è¡¨çš„å®EXPORT_SYMBOL()å’ŒEXPORT_SYMBOL_GPL()之外, 这些å®çš„å˜ä½“还å¯ä»¥å°†ç¬¦å·å¯¼å‡ºåˆ°æŸä¸ªå‘½å空间:EXPORT_SYMBOL_NS() å’Œ EXPORT_SYMBOL_NS_GPL()。 @@ -54,8 +44,8 @@ 导出时未指明命å空间的符å·å°†æŒ‡å‘ ``NULL`` 。如果没有定义命å空间,则默认没有。 ``modpost`` å’Œkernel/module/main.c分别在构建时或模å—åŠ è½½æ—¶ä½¿ç”¨å称空间。 -2.2 使用DEFAULT_SYMBOL_NAMESPACE定义 -==================================== +使用DEFAULT_SYMBOL_NAMESPACE定义 +-------------------------------- 为一个å系统的所有符å·å®šä¹‰å‘½å空间å¯èƒ½ä¼šéžå¸¸å†—长,并å¯èƒ½å˜å¾—éš¾ä»¥ç»´æŠ¤ã€‚å› æ¤ï¼Œæˆ‘ 们æä¾›äº†ä¸€ä¸ªé»˜è®¤å®šä¹‰ï¼ˆDEFAULT_SYMBOL_NAMESPACE),如果设置了这个定义, å®ƒå°†æˆ @@ -80,8 +70,8 @@ 应置于相关编译å•å…ƒä¸ä»»ä½• EXPORT_SYMBOL å®ä¹‹å‰ -3. 如何使用命å空间ä¸å¯¼å‡ºçš„ç¬¦å· -=============================== +如何使用命å空间ä¸å¯¼å‡ºçš„ç¬¦å· +============================ 为了使用被导出到命å空间的符å·ï¼Œå†…æ ¸æ¨¡å—éœ€è¦æ˜Žç¡®åœ°å¯¼å…¥è¿™äº›å‘½å空间。 å¦åˆ™å†…æ ¸å¯èƒ½ä¼šæ‹’ç»åŠ è½½è¯¥æ¨¡å—。模å—代ç 需è¦ä½¿ç”¨å®MODULE_IMPORT_NSæ¥ @@ -100,11 +90,10 @@ 建议将 MODULE_IMPORT_NS() è¯å¥æ·»åŠ åˆ°é 近其他模å—元数æ®å®šä¹‰çš„地方, -如 MODULE_AUTHOR() 或 MODULE_LICENSE() 。关于自动创建缺失的导入 -è¯å¥çš„æ–¹æ³•,请å‚考第5节。 +如 MODULE_AUTHOR() 或 MODULE_LICENSE() 。 -4. åŠ è½½ä½¿ç”¨å‘½å空间符å·çš„æ¨¡å— -============================= +åŠ è½½ä½¿ç”¨å‘½å空间符å·çš„æ¨¡å— +========================== 在模å—åŠ è½½æ—¶ï¼ˆæ¯”å¦‚ ``insmod`` ï¼‰ï¼Œå†…æ ¸å°†æ£€æŸ¥æ¯ä¸ªä»Žæ¨¡å—ä¸å¼•ç”¨çš„ç¬¦å·æ˜¯å¦å¯ 用,以åŠå®ƒå¯èƒ½è¢«å¯¼å‡ºåˆ°çš„åå—空间是å¦è¢«æ¨¡å—å¯¼å…¥ã€‚å†…æ ¸çš„é»˜è®¤è¡Œä¸ºæ˜¯æ‹’ç» @@ -113,8 +102,8 @@ EINVALæ–¹å¼å¤±è´¥ã€‚è¦å…è®¸åŠ è½½ä¸æ»¡è¶³è¿™ä¸ªå‰ææ¡ä»¶çš„æ¨¡å—,å¯ä» 设置 MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS=y å°†ä½¿åŠ è½½ä¸å—å½±å“,但会 å‘出è¦å‘Šã€‚ -5. 自动创建MODULE_IMPORT_NS声明 -=============================== +自动创建MODULE_IMPORT_NS声明 +============================ 缺少命å空间的导入å¯ä»¥åœ¨æž„å»ºæ—¶å¾ˆå®¹æ˜“è¢«æ£€æµ‹åˆ°ã€‚äº‹å®žä¸Šï¼Œå¦‚æžœä¸€ä¸ªæ¨¡å— ä½¿ç”¨äº†ä¸€ä¸ªå‘½å空间的符å·è€Œæ²¡æœ‰å¯¼å…¥å®ƒï¼Œmodpost会å‘出è¦å‘Šã€‚ diff --git a/Documentation/userspace-api/ioctl/ioctl-number.rst b/Documentation/userspace-api/ioctl/ioctl-number.rst index 3d1171fd96c1..bc91756bde73 100644 --- a/Documentation/userspace-api/ioctl/ioctl-number.rst +++ b/Documentation/userspace-api/ioctl/ioctl-number.rst @@ -402,6 +402,8 @@ Code Seq# Include File Comments <mailto:mathieu.desnoyers@efficios.com> 0xF8 all arch/x86/include/uapi/asm/amd_hsmp.h AMD HSMP EPYC system management interface driver <mailto:nchatrad@amd.com> +0xF9 00-0F uapi/misc/amd-apml.h AMD side band system management interface driver + <mailto:naveenkrishna.chatradhi@amd.com> 0xFD all linux/dm-ioctl.h 0xFE all linux/isst_if.h ==== ===== ======================================================= ================================================================ diff --git a/Documentation/userspace-api/mseal.rst b/Documentation/userspace-api/mseal.rst index 7195a7f91107..ea9b11a0bd89 100644 --- a/Documentation/userspace-api/mseal.rst +++ b/Documentation/userspace-api/mseal.rst @@ -144,7 +144,7 @@ Use cases architecture. The following architectures currently support this feature: x86-64, arm64, - and s390. + loongarch and s390. WARNING: This feature breaks programs which rely on relocating or unmapping system mappings. Known broken software at the time diff --git a/MAINTAINERS b/MAINTAINERS index f2668b81115c..a92290fffa16 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1338,12 +1338,21 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net.git T: git git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next.git F: drivers/net/amt.c +ANALOG DEVICES INC AD3530R DRIVER +M: Kim Seer Paller <kimseer.paller@analog.com> +L: linux-iio@vger.kernel.org +S: Supported +W: https://ez.analog.com/linux-software-drivers +F: Documentation/devicetree/bindings/iio/dac/adi,ad3530r.yaml +F: drivers/iio/dac/ad3530r.c + ANALOG DEVICES INC AD3552R DRIVER M: Nuno Sá <nuno.sa@analog.com> L: linux-iio@vger.kernel.org S: Supported W: https://ez.analog.com/linux-software-drivers F: Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml +F: Documentation/iio/ad3552r.rst F: drivers/iio/dac/ad3552r.c ANALOG DEVICES INC AD4000 DRIVER @@ -1387,6 +1396,16 @@ F: Documentation/iio/ad4695.rst F: drivers/iio/adc/ad4695.c F: include/dt-bindings/iio/adc/adi,ad4695.h +ANALOG DEVICES INC AD4851 DRIVER +M: Sergiu Cuciurean <sergiu.cuciurean@analog.com> +M: Dragos Bogdan <dragos.bogdan@analog.com> +R: Antoniu Miclaus <antoniu.miclaus@analog.com> +L: linux-iio@vger.kernel.org +S: Supported +W: https://ez.analog.com/linux-software-drivers +F: Documentation/devicetree/bindings/iio/adc/adi,ad4851.yaml +F: drivers/iio/adc/ad4851.c + ANALOG DEVICES INC AD7091R DRIVER M: Marcelo Schmitt <marcelo.schmitt@analog.com> L: linux-iio@vger.kernel.org @@ -2322,11 +2341,13 @@ F: Documentation/devicetree/bindings/mailbox/apple,mailbox.yaml F: Documentation/devicetree/bindings/net/bluetooth/brcm,bcm4377-bluetooth.yaml F: Documentation/devicetree/bindings/nvme/apple,nvme-ans.yaml F: Documentation/devicetree/bindings/nvmem/apple,efuses.yaml +F: Documentation/devicetree/bindings/nvmem/apple,spmi-nvmem.yaml F: Documentation/devicetree/bindings/pci/apple,pcie.yaml F: Documentation/devicetree/bindings/pinctrl/apple,pinctrl.yaml F: Documentation/devicetree/bindings/power/apple* F: Documentation/devicetree/bindings/pwm/apple,s5l-fpwm.yaml F: Documentation/devicetree/bindings/spi/apple,spi.yaml +F: Documentation/devicetree/bindings/spmi/apple,spmi.yaml F: Documentation/devicetree/bindings/watchdog/apple,wdt.yaml F: arch/arm64/boot/dts/apple/ F: drivers/bluetooth/hci_bcm4377.c @@ -2342,10 +2363,12 @@ F: drivers/iommu/io-pgtable-dart.c F: drivers/irqchip/irq-apple-aic.c F: drivers/nvme/host/apple.c F: drivers/nvmem/apple-efuses.c +F: drivers/nvmem/apple-spmi-nvmem.c F: drivers/pinctrl/pinctrl-apple-gpio.c F: drivers/pwm/pwm-apple.c F: drivers/soc/apple/* F: drivers/spi/spi-apple.c +F: drivers/spmi/spmi-apple-controller.c F: drivers/video/backlight/apple_dwi_bl.c F: drivers/watchdog/apple_wdt.c F: include/dt-bindings/interrupt-controller/apple-aic.h @@ -5963,7 +5986,7 @@ X: drivers/clk/clkdev.c COMMON INTERNET FILE SYSTEM CLIENT (CIFS and SMB3) M: Steve French <sfrench@samba.org> M: Steve French <smfrench@gmail.com> -R: Paulo Alcantara <pc@manguebit.com> (DFS, global name space) +R: Paulo Alcantara <pc@manguebit.org> (DFS, global name space) R: Ronnie Sahlberg <ronniesahlberg@gmail.com> (directory leases, sparse files) R: Shyam Prasad N <sprasad@microsoft.com> (multichannel) R: Tom Talpey <tom@talpey.com> (RDMA, smbdirect) @@ -6938,6 +6961,12 @@ L: linux-rtc@vger.kernel.org S: Maintained F: drivers/rtc/rtc-sd2405al.c +DFROBOT SEN0322 DRIVER +M: Tóth János <gomba007@gmail.com> +L: linux-iio@vger.kernel.org +S: Maintained +F: drivers/iio/chemical/sen0322.c + DH ELECTRONICS DHSOM SOM AND BOARD SUPPORT M: Christoph Niedermaier <cniedermaier@dh-electronics.com> M: Marek Vasut <marex@denx.de> @@ -7599,7 +7628,7 @@ F: Documentation/devicetree/bindings/display/panel/panel-mipi-dbi-spi.yaml F: drivers/gpu/drm/tiny/panel-mipi-dbi.c DRM DRIVER for Qualcomm Adreno GPUs -M: Rob Clark <robdclark@gmail.com> +M: Rob Clark <robin.clark@oss.qualcomm.com> R: Sean Paul <sean@poorly.run> R: Konrad Dybcio <konradybcio@kernel.org> L: linux-arm-msm@vger.kernel.org @@ -7618,9 +7647,10 @@ F: drivers/gpu/drm/msm/registers/adreno/ F: include/uapi/drm/msm_drm.h DRM DRIVER for Qualcomm display hardware -M: Rob Clark <robdclark@gmail.com> -M: Abhinav Kumar <quic_abhinavk@quicinc.com> +M: Rob Clark <robin.clark@oss.qualcomm.com> M: Dmitry Baryshkov <lumag@kernel.org> +R: Abhinav Kumar <abhinav.kumar@linux.dev> +R: Jessica Zhang <jessica.zhang@oss.qualcomm.com> R: Sean Paul <sean@poorly.run> R: Marijn Suijten <marijn.suijten@somainline.org> L: linux-arm-msm@vger.kernel.org @@ -8477,6 +8507,18 @@ W: https://linuxtv.org Q: http://patchwork.linuxtv.org/project/linux-media/list/ F: drivers/media/dvb-frontends/ec100* +ECONET MIPS PLATFORM +M: Caleb James DeLisle <cjd@cjdns.fr> +L: linux-mips@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/interrupt-controller/econet,en751221-intc.yaml +F: Documentation/devicetree/bindings/mips/econet.yaml +F: Documentation/devicetree/bindings/timer/econet,en751221-timer.yaml +F: arch/mips/boot/dts/econet/ +F: arch/mips/econet/ +F: drivers/clocksource/timer-econet-en751221.c +F: drivers/irqchip/irq-econet-en751221.c + ECRYPT FILE SYSTEM M: Tyler Hicks <code@tyhicks.com> L: ecryptfs@vger.kernel.org @@ -9134,9 +9176,10 @@ F: lib/fault-inject.c F: tools/testing/fault-injection/ FBTFT Framebuffer drivers +M: Andy Shevchenko <andy@kernel.org> L: dri-devel@lists.freedesktop.org L: linux-fbdev@vger.kernel.org -S: Orphan +S: Odd fixes F: drivers/staging/fbtft/ FC0011 TUNER DRIVER @@ -9237,7 +9280,7 @@ F: include/linux/iomap.h FILESYSTEMS [NETFS LIBRARY] M: David Howells <dhowells@redhat.com> -M: Paulo Alcantara <pc@manguebit.com> +M: Paulo Alcantara <pc@manguebit.org> L: netfs@lists.linux.dev L: linux-fsdevel@vger.kernel.org S: Supported @@ -10923,7 +10966,7 @@ F: drivers/crypto/hisilicon/sec2/sec_crypto.h F: drivers/crypto/hisilicon/sec2/sec_main.c HISILICON SPI Controller DRIVER FOR KUNPENG SOCS -M: Jay Fang <f.fangjian@huawei.com> +M: Yang Shen <shenyang39@huawei.com> L: linux-spi@vger.kernel.org S: Maintained W: http://www.hisilicon.com @@ -10949,7 +10992,7 @@ S: Maintained F: drivers/crypto/hisilicon/trng/trng.c HISILICON V3XX SPI NOR FLASH Controller Driver -M: Jay Fang <f.fangjian@huawei.com> +M: Yang Shen <shenyang39@huawei.com> S: Maintained W: http://www.hisilicon.com F: drivers/spi/spi-hisi-sfc-v3xx.c @@ -11107,6 +11150,7 @@ S: Maintained F: Documentation/devicetree/bindings/platform/huawei,gaokun-ec.yaml F: drivers/platform/arm64/huawei-gaokun-ec.c F: drivers/power/supply/huawei-gaokun-battery.c +F: drivers/usb/typec/ucsi/ucsi_huawei_gaokun.c F: include/linux/platform_data/huawei-gaokun-ec.h HUGETLB SUBSYSTEM @@ -11630,6 +11674,13 @@ L: linux-media@vger.kernel.org S: Maintained F: drivers/media/rc/iguanair.c +IIO ADC HELPERS +M: Matti Vaittinen <mazziesaccount@gmail.com> +L: linux-iio@vger.kernel.org +S: Maintained +F: drivers/iio/adc/industrialio-adc.c +F: include/linux/iio/adc-helpers.h + IIO BACKEND FRAMEWORK M: Nuno Sa <nuno.sa@analog.com> R: Olivier Moysan <olivier.moysan@foss.st.com> @@ -11678,7 +11729,9 @@ F: drivers/iio/common/scmi_sensors/scmi_iio.c IIO SUBSYSTEM AND DRIVERS M: Jonathan Cameron <jic23@kernel.org> -R: Lars-Peter Clausen <lars@metafoo.de> +R: David Lechner <dlechner@baylibre.com> +R: Nuno Sá <nuno.sa@analog.com> +R: Andy Shevchenko <andy@kernel.org> L: linux-iio@vger.kernel.org S: Maintained T: git git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio.git @@ -12237,7 +12290,7 @@ F: drivers/crypto/intel/keembay/ocs-hcu.c F: drivers/crypto/intel/keembay/ocs-hcu.h INTEL LA JOLLA COVE ADAPTER (LJCA) USB I/O EXPANDER DRIVERS -M: Wentong Wu <wentong.wu@intel.com> +M: Lixu Zhang <lixu.zhang@intel.com> M: Sakari Ailus <sakari.ailus@linux.intel.com> S: Maintained F: drivers/gpio/gpio-ljca.c @@ -12271,7 +12324,7 @@ F: drivers/mfd/intel-m10-bmc* F: include/linux/mfd/intel-m10-bmc.h INTEL MAX10 BMC SECURE UPDATES -M: Peter Colberg <peter.colberg@altera.com> +M: Matthew Gerlach <matthew.gerlach@altera.com> L: linux-fpga@vger.kernel.org S: Maintained F: Documentation/ABI/testing/sysfs-driver-intel-m10-bmc-sec-update @@ -12617,7 +12670,6 @@ F: include/linux/iosys-map.h IO_URING M: Jens Axboe <axboe@kernel.dk> -M: Pavel Begunkov <asml.silence@gmail.com> L: io-uring@vger.kernel.org S: Maintained T: git git://git.kernel.dk/linux-block @@ -13218,7 +13270,7 @@ F: arch/powerpc/kvm/ KERNEL VIRTUAL MACHINE FOR RISC-V (KVM/riscv) M: Anup Patel <anup@brainfault.org> -R: Atish Patra <atishp@atishpatra.org> +R: Atish Patra <atish.patra@linux.dev> L: kvm@vger.kernel.org L: kvm-riscv@lists.infradead.org L: linux-riscv@lists.infradead.org @@ -14451,7 +14503,7 @@ MARVELL ARMADA 3700 SERIAL DRIVER M: Pali Rohár <pali@kernel.org> S: Maintained F: Documentation/devicetree/bindings/clock/marvell,armada-3700-uart-clock.yaml -F: Documentation/devicetree/bindings/serial/mvebu-uart.txt +F: Documentation/devicetree/bindings/serial/marvell,armada-3700-uart.yaml F: drivers/tty/serial/mvebu-uart.c MARVELL ARMADA DRM SUPPORT @@ -15766,6 +15818,7 @@ R: Rakie Kim <rakie.kim@sk.com> R: Byungchul Park <byungchul@sk.com> R: Gregory Price <gourry@gourry.net> R: Ying Huang <ying.huang@linux.alibaba.com> +R: Alistair Popple <apopple@nvidia.com> L: linux-mm@kvack.org S: Maintained W: http://www.linux-mm.org @@ -15837,6 +15890,25 @@ S: Maintained F: include/linux/secretmem.h F: mm/secretmem.c +MEMORY MANAGEMENT - SWAP +M: Andrew Morton <akpm@linux-foundation.org> +R: Kemeng Shi <shikemeng@huaweicloud.com> +R: Kairui Song <kasong@tencent.com> +R: Nhat Pham <nphamcs@gmail.com> +R: Baoquan He <bhe@redhat.com> +R: Barry Song <baohua@kernel.org> +R: Chris Li <chrisl@kernel.org> +L: linux-mm@kvack.org +S: Maintained +F: include/linux/swap.h +F: include/linux/swapfile.h +F: include/linux/swapops.h +F: mm/page_io.c +F: mm/swap.c +F: mm/swap.h +F: mm/swap_state.c +F: mm/swapfile.c + MEMORY MANAGEMENT - THP (TRANSPARENT HUGE PAGE) M: Andrew Morton <akpm@linux-foundation.org> M: David Hildenbrand <david@redhat.com> @@ -16675,6 +16747,7 @@ L: linux-mm@kvack.org S: Maintained F: arch/*/include/asm/tlb.h F: include/asm-generic/tlb.h +F: include/trace/events/tlb.h F: mm/mmu_gather.c MN88472 MEDIA DRIVER @@ -16924,7 +16997,7 @@ F: include/uapi/linux/mmc/ MULTIPLEXER SUBSYSTEM M: Peter Rosin <peda@axentia.se> -S: Maintained +S: Odd Fixes F: Documentation/ABI/testing/sysfs-class-mux* F: Documentation/devicetree/bindings/mux/ F: drivers/mux/ @@ -17701,6 +17774,13 @@ F: drivers/nubus/ F: include/linux/nubus.h F: include/uapi/linux/nubus.h +NUVOTON NCT7201 IIO DRIVER +M: Eason Yang <j2anfernee@gmail.com> +L: linux-iio@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/iio/adc/nuvoton,nct7201.yaml +F: drivers/iio/adc/nct7201.c + NVIDIA (rivafb and nvidiafb) FRAMEBUFFER DRIVER M: Antonino Daplas <adaplas@gmail.com> L: linux-fbdev@vger.kernel.org @@ -20384,7 +20464,7 @@ F: drivers/soc/qcom/icc-bwmon.c F: drivers/soc/qcom/trace_icc-bwmon.h QUALCOMM IOMMU -M: Rob Clark <robdclark@gmail.com> +M: Rob Clark <robin.clark@oss.qualcomm.com> L: iommu@lists.linux.dev L: linux-arm-msm@vger.kernel.org S: Maintained @@ -20427,7 +20507,7 @@ F: drivers/regulator/vqmmc-ipq4019-regulator.c QUALCOMM IRIS VIDEO ACCELERATOR DRIVER M: Vikash Garodia <quic_vgarodia@quicinc.com> M: Dikshita Agarwal <quic_dikshita@quicinc.com> -R: Abhinav Kumar <quic_abhinavk@quicinc.com> +R: Abhinav Kumar <abhinav.kumar@linux.dev> R: Bryan O'Donoghue <bryan.odonoghue@linaro.org> L: linux-media@vger.kernel.org L: linux-arm-msm@vger.kernel.org @@ -21273,7 +21353,7 @@ F: arch/riscv/boot/dts/sifive/ F: arch/riscv/boot/dts/starfive/ RISC-V PMU DRIVERS -M: Atish Patra <atishp@atishpatra.org> +M: Atish Patra <atish.patra@linux.dev> R: Anup Patel <anup@brainfault.org> L: linux-riscv@lists.infradead.org S: Supported @@ -21431,6 +21511,11 @@ S: Supported F: drivers/power/supply/bd99954-charger.c F: drivers/power/supply/bd99954-charger.h +ROHM BD79124 ADC / GPO IC +M: Matti Vaittinen <mazziesaccount@gmail.com> +S: Supported +F: drivers/iio/adc/rohm-bd79124.c + ROHM BH1745 COLOUR SENSOR M: Mudit Sharma <muditsharma.info@gmail.com> L: linux-iio@vger.kernel.org @@ -24632,6 +24717,12 @@ M: Robert Richter <rric@kernel.org> S: Odd Fixes F: drivers/gpio/gpio-thunderx.c +TI ADC12xs and ROHM BD79104 ADC driver +M: Matti Vaittinen <mazziesaccount@gmail.com> +S: Maintained +F: drivers/iio/adc/ti-adc128s052.c +L: linux-iio@vger.kernel.org + TI ADS1119 ADC DRIVER M: Francesco Dolcini <francesco@dolcini.it> M: João Paulo Gonçalves <jpaulo.silvagoncalves@gmail.com> @@ -24943,10 +25034,8 @@ F: mm/shmem.c TOMOYO SECURITY MODULE M: Kentaro Takeda <takedakn@nttdata.co.jp> M: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> -L: tomoyo-dev-en@lists.osdn.me (subscribers-only, for developers in English) -L: tomoyo-users-en@lists.osdn.me (subscribers-only, for users in English) -L: tomoyo-dev@lists.osdn.me (subscribers-only, for developers in Japanese) -L: tomoyo-users@lists.osdn.me (subscribers-only, for users in Japanese) +L: tomoyo-users_en@lists.sourceforge.net (subscribers-only, English language) +L: tomoyo-users_ja@lists.sourceforge.net (subscribers-only, Japanese language) S: Maintained W: https://tomoyo.sourceforge.net/ F: security/tomoyo/ @@ -26581,6 +26670,12 @@ M: David Härdeman <david@hardeman.nu> S: Maintained F: drivers/media/rc/winbond-cir.c +WINSEN MHZ19B +M: Gyeyoung Baek <gye976@gmail.com> +S: Maintained +F: Documentation/devicetree/bindings/iio/chemical/winsen,mhz19b.yaml +F: drivers/iio/chemical/mhz19b.c + WINSYSTEMS EBC-C384 WATCHDOG DRIVER L: linux-watchdog@vger.kernel.org S: Orphan @@ -27078,8 +27173,6 @@ M: Dragan Cvetic <dragan.cvetic@amd.com> S: Maintained F: Documentation/devicetree/bindings/misc/xlnx,sd-fec.yaml F: Documentation/misc-devices/xilinx_sdfec.rst -F: drivers/misc/Kconfig -F: drivers/misc/Makefile F: drivers/misc/xilinx_sdfec.c F: include/uapi/misc/xilinx_sdfec.h @@ -1,8 +1,8 @@ # SPDX-License-Identifier: GPL-2.0 VERSION = 6 -PATCHLEVEL = 15 +PATCHLEVEL = 16 SUBLEVEL = 0 -EXTRAVERSION = +EXTRAVERSION = -rc1 NAME = Baby Opossum Posse # *DOCUMENTATION* @@ -754,7 +754,7 @@ targets := # Normally, just do built-in. KBUILD_MODULES := -KBUILD_BUILTIN := 1 +KBUILD_BUILTIN := y # If we have only "make modules", don't compile built-in objects. ifeq ($(MAKECMDGOALS),modules) @@ -766,11 +766,11 @@ endif # Just "make" or "make all" shall build modules as well ifneq ($(filter all modules nsdeps compile_commands.json clang-%,$(MAKECMDGOALS)),) - KBUILD_MODULES := 1 + KBUILD_MODULES := y endif ifeq ($(MAKECMDGOALS),) - KBUILD_MODULES := 1 + KBUILD_MODULES := y endif export KBUILD_MODULES KBUILD_BUILTIN @@ -1189,13 +1189,8 @@ export ARCH_LIB := $(filter %/, $(libs-y)) export ARCH_DRIVERS := $(drivers-y) $(drivers-m) # Externally visible symbols (used by link-vmlinux.sh) -KBUILD_VMLINUX_OBJS := ./built-in.a -ifdef CONFIG_MODULES -KBUILD_VMLINUX_OBJS += $(patsubst %/, %/lib.a, $(filter %/, $(libs-y))) +KBUILD_VMLINUX_OBJS := built-in.a $(patsubst %/, %/lib.a, $(filter %/, $(libs-y))) KBUILD_VMLINUX_LIBS := $(filter-out %/, $(libs-y)) -else -KBUILD_VMLINUX_LIBS := $(patsubst %/,%/lib.a, $(libs-y)) -endif export KBUILD_VMLINUX_LIBS export KBUILD_LDS := arch/$(SRCARCH)/kernel/vmlinux.lds @@ -1203,7 +1198,7 @@ export KBUILD_LDS := arch/$(SRCARCH)/kernel/vmlinux.lds ifdef CONFIG_TRIM_UNUSED_KSYMS # For the kernel to actually contain only the needed exported symbols, # we have to build modules as well to determine what those symbols are. -KBUILD_MODULES := 1 +KBUILD_MODULES := y endif # '$(AR) mPi' needs 'T' to workaround the bug of llvm-ar <= 14 @@ -1370,7 +1365,7 @@ PHONY += archheaders archscripts hdr-inst := -f $(srctree)/scripts/Makefile.headersinst obj PHONY += headers -headers: $(version_h) scripts_unifdef uapi-asm-generic archheaders archscripts +headers: $(version_h) scripts_unifdef uapi-asm-generic archheaders ifdef HEADER_ARCH $(Q)$(MAKE) -f $(srctree)/Makefile HEADER_ARCH= SRCARCH=$(HEADER_ARCH) headers else @@ -1543,7 +1538,7 @@ all: modules # the built-in objects during the descend as well, in order to # make sure the checksums are up to date before we record them. ifdef CONFIG_MODVERSIONS - KBUILD_BUILTIN := 1 + KBUILD_BUILTIN := y endif # Build modules @@ -1552,7 +1547,7 @@ endif # *.ko are usually independent of vmlinux, but CONFIG_DEBUG_INFO_BTF_MODULES # is an exception. ifdef CONFIG_DEBUG_INFO_BTF_MODULES -KBUILD_BUILTIN := 1 +KBUILD_BUILTIN := y modules: vmlinux endif @@ -1837,9 +1832,12 @@ rustfmtcheck: rustfmt # Misc # --------------------------------------------------------------------------- +# Run misc checks when ${KBUILD_EXTRA_WARN} contains 1 PHONY += misc-check +ifneq ($(findstring 1,$(KBUILD_EXTRA_WARN)),) misc-check: $(Q)$(srctree)/scripts/misc-check +endif all: misc-check @@ -1865,7 +1863,7 @@ filechk_kernel.release = echo $(KERNELRELEASE) # We are always building only modules. KBUILD_BUILTIN := -KBUILD_MODULES := 1 +KBUILD_MODULES := y build-dir := . @@ -1993,7 +1991,7 @@ endif single-goals := $(addprefix $(build-dir)/, $(single-no-ko)) -KBUILD_MODULES := 1 +KBUILD_MODULES := y endif diff --git a/arch/alpha/kernel/Makefile b/arch/alpha/kernel/Makefile index b6c862dff1f6..187cd8df2faf 100644 --- a/arch/alpha/kernel/Makefile +++ b/arch/alpha/kernel/Makefile @@ -3,7 +3,7 @@ # Makefile for the linux kernel. # -extra-y := vmlinux.lds +always-$(KBUILD_BUILTIN) := vmlinux.lds asflags-y := $(KBUILD_CFLAGS) ccflags-y := -Wno-sign-compare diff --git a/arch/alpha/kernel/srmcons.c b/arch/alpha/kernel/srmcons.c index a89ce84371f9..d19e51ec711d 100644 --- a/arch/alpha/kernel/srmcons.c +++ b/arch/alpha/kernel/srmcons.c @@ -69,7 +69,8 @@ srmcons_do_receive_chars(struct tty_port *port) static void srmcons_receive_chars(struct timer_list *t) { - struct srmcons_private *srmconsp = from_timer(srmconsp, t, timer); + struct srmcons_private *srmconsp = timer_container_of(srmconsp, t, + timer); struct tty_port *port = &srmconsp->port; unsigned long flags; int incr = 10; diff --git a/arch/arc/kernel/Makefile b/arch/arc/kernel/Makefile index 95fbf9364c67..fa94fff02419 100644 --- a/arch/arc/kernel/Makefile +++ b/arch/arc/kernel/Makefile @@ -26,4 +26,4 @@ ifdef CONFIG_ISA_ARCOMPACT CFLAGS_fpu.o += -mdpfp endif -extra-y := vmlinux.lds +always-$(KBUILD_BUILTIN) := vmlinux.lds diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index b3333d070390..afc9de7ef9a1 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile @@ -104,4 +104,4 @@ obj-$(CONFIG_HAVE_ARM_SMCCC) += smccc-call.o obj-$(CONFIG_GENERIC_CPU_VULNERABILITIES) += spectre.o -extra-y := vmlinux.lds +always-$(KBUILD_BUILTIN) := vmlinux.lds diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile index 71c29a2a2f19..2920b0a51403 100644 --- a/arch/arm64/kernel/Makefile +++ b/arch/arm64/kernel/Makefile @@ -78,7 +78,7 @@ $(obj)/vdso32-wrap.o: $(obj)/vdso32/vdso.so obj-y += probes/ obj-y += head.o -extra-y += vmlinux.lds +always-$(KBUILD_BUILTIN) += vmlinux.lds ifeq ($(CONFIG_DEBUG_EFI),y) AFLAGS_head.o += -DVMLINUX_PATH="\"$(realpath $(objtree)/vmlinux)\"" diff --git a/arch/csky/kernel/Makefile b/arch/csky/kernel/Makefile index de1c3472e8f0..a406a4ac2378 100644 --- a/arch/csky/kernel/Makefile +++ b/arch/csky/kernel/Makefile @@ -1,5 +1,5 @@ # SPDX-License-Identifier: GPL-2.0-only -extra-y := vmlinux.lds +always-$(KBUILD_BUILTIN) := vmlinux.lds obj-y += head.o entry.o atomic.o signal.o traps.o irq.o time.o vdso.o vdso/ obj-y += power.o syscall.o syscall_table.o setup.o diff --git a/arch/hexagon/kernel/Makefile b/arch/hexagon/kernel/Makefile index 3fdf937eb572..8e0fb4a62315 100644 --- a/arch/hexagon/kernel/Makefile +++ b/arch/hexagon/kernel/Makefile @@ -1,5 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 -extra-y := vmlinux.lds +always-$(KBUILD_BUILTIN) := vmlinux.lds obj-y += head.o obj-$(CONFIG_SMP) += smp.o diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig index 1a2cf012b8f2..4b19f93379a1 100644 --- a/arch/loongarch/Kconfig +++ b/arch/loongarch/Kconfig @@ -69,6 +69,7 @@ config LOONGARCH select ARCH_SUPPORTS_INT128 if CC_HAS_INT128 select ARCH_SUPPORTS_LTO_CLANG select ARCH_SUPPORTS_LTO_CLANG_THIN + select ARCH_SUPPORTS_MSEAL_SYSTEM_MAPPINGS select ARCH_SUPPORTS_NUMA_BALANCING select ARCH_SUPPORTS_RT select ARCH_USE_BUILTIN_BSWAP @@ -123,6 +124,7 @@ config LOONGARCH select HAVE_ARCH_RANDOMIZE_KSTACK_OFFSET select HAVE_ARCH_SECCOMP select HAVE_ARCH_SECCOMP_FILTER + select HAVE_ARCH_STACKLEAK select HAVE_ARCH_TRACEHOOK select HAVE_ARCH_TRANSPARENT_HUGEPAGE select HAVE_ARCH_USERFAULTFD_MINOR if USERFAULTFD @@ -187,6 +189,7 @@ config LOONGARCH select MODULES_USE_ELF_RELA if MODULES select NEED_PER_CPU_EMBED_FIRST_CHUNK select NEED_PER_CPU_PAGE_FIRST_CHUNK + select NUMA_MEMBLKS if NUMA select OF select OF_EARLY_FLATTREE select PCI @@ -456,6 +459,15 @@ config SCHED_SMT Improves scheduler's performance when there are multiple threads in one physical core. +config SCHED_MC + bool "Multi-core scheduler support" + depends on SMP + default y + help + Multi-core scheduler support improves the CPU scheduler's decision + making when dealing with multi-core CPU chips at a cost of slightly + increased overhead in some places. + config SMP bool "Multi-Processing support" help @@ -485,10 +497,10 @@ config HOTPLUG_CPU Say N if you want to disable CPU hotplug. config NR_CPUS - int "Maximum number of CPUs (2-256)" - range 2 256 + int "Maximum number of CPUs (2-2048)" + range 2 2048 + default "2048" depends on SMP - default "64" help This allows you to specify the maximum number of CPUs which this kernel will support. diff --git a/arch/loongarch/Makefile b/arch/loongarch/Makefile index 0304eabbe606..b0703a4e02a2 100644 --- a/arch/loongarch/Makefile +++ b/arch/loongarch/Makefile @@ -181,11 +181,14 @@ vmlinux.elf vmlinux.efi vmlinuz.efi: vmlinux $(Q)$(MAKE) $(build)=$(boot) $(bootvars-y) $(boot)/$@ install: - $(Q)install -D -m 755 $(KBUILD_IMAGE) $(INSTALL_PATH)/$(image-name-y)-$(KERNELRELEASE) - $(Q)install -D -m 644 .config $(INSTALL_PATH)/config-$(KERNELRELEASE) - $(Q)install -D -m 644 System.map $(INSTALL_PATH)/System.map-$(KERNELRELEASE) + $(call cmd,install) define archhelp - echo ' install - install kernel into $(INSTALL_PATH)' + echo ' vmlinux.elf - Uncompressed ELF kernel image (arch/loongarch/boot/vmlinux.elf)' + echo ' vmlinux.efi - Uncompressed EFI kernel image (arch/loongarch/boot/vmlinux.efi)' + echo ' vmlinuz.efi - GZIP/ZSTD-compressed EFI kernel image (arch/loongarch/boot/vmlinuz.efi)' + echo ' Default when CONFIG_EFI_ZBOOT=y' + echo ' install - Install kernel using (your) ~/bin/$(INSTALLKERNEL) or' + echo ' (distribution) /sbin/$(INSTALLKERNEL) or install.sh to $$(INSTALL_PATH)' echo endef diff --git a/arch/loongarch/boot/dts/loongson-2k0500.dtsi b/arch/loongarch/boot/dts/loongson-2k0500.dtsi index 3b38ff8853a7..760c60eebb89 100644 --- a/arch/loongarch/boot/dts/loongson-2k0500.dtsi +++ b/arch/loongarch/boot/dts/loongson-2k0500.dtsi @@ -169,6 +169,166 @@ interrupts = <3>; }; + pwm@1ff5c000 { + compatible = "loongson,ls2k0500-pwm", "loongson,ls7a-pwm"; + reg = <0x0 0x1ff5c000 0x0 0x10>; + interrupt-parent = <&liointc0>; + interrupts = <24 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clk LOONGSON2_APB_CLK>; + #pwm-cells = <3>; + status = "disabled"; + }; + + pwm@1ff5c010 { + compatible = "loongson,ls2k0500-pwm", "loongson,ls7a-pwm"; + reg = <0x0 0x1ff5c010 0x0 0x10>; + interrupt-parent = <&liointc0>; + interrupts = <24 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clk LOONGSON2_APB_CLK>; + #pwm-cells = <3>; + status = "disabled"; + }; + + pwm@1ff5c020 { + compatible = "loongson,ls2k0500-pwm", "loongson,ls7a-pwm"; + reg = <0x0 0x1ff5c020 0x0 0x10>; + interrupt-parent = <&liointc0>; + interrupts = <24 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clk LOONGSON2_APB_CLK>; + #pwm-cells = <3>; + status = "disabled"; + }; + + pwm@1ff5c030 { + compatible = "loongson,ls2k0500-pwm", "loongson,ls7a-pwm"; + reg = <0x0 0x1ff5c030 0x0 0x10>; + interrupt-parent = <&liointc0>; + interrupts = <24 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clk LOONGSON2_APB_CLK>; + #pwm-cells = <3>; + status = "disabled"; + }; + + pwm@1ff5c040 { + compatible = "loongson,ls2k0500-pwm", "loongson,ls7a-pwm"; + reg = <0x0 0x1ff5c040 0x0 0x10>; + interrupt-parent = <&liointc0>; + interrupts = <25 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clk LOONGSON2_APB_CLK>; + #pwm-cells = <3>; + status = "disabled"; + }; + + pwm@1ff5c050 { + compatible = "loongson,ls2k0500-pwm", "loongson,ls7a-pwm"; + reg = <0x0 0x1ff5c050 0x0 0x10>; + interrupt-parent = <&liointc0>; + interrupts = <25 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clk LOONGSON2_APB_CLK>; + #pwm-cells = <3>; + status = "disabled"; + }; + + pwm@1ff5c060 { + compatible = "loongson,ls2k0500-pwm", "loongson,ls7a-pwm"; + reg = <0x0 0x1ff5c060 0x0 0x10>; + interrupt-parent = <&liointc0>; + interrupts = <25 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clk LOONGSON2_APB_CLK>; + #pwm-cells = <3>; + status = "disabled"; + }; + + pwm@1ff5c070 { + compatible = "loongson,ls2k0500-pwm", "loongson,ls7a-pwm"; + reg = <0x0 0x1ff5c070 0x0 0x10>; + interrupt-parent = <&liointc0>; + interrupts = <25 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clk LOONGSON2_APB_CLK>; + #pwm-cells = <3>; + status = "disabled"; + }; + + pwm@1ff5c080 { + compatible = "loongson,ls2k0500-pwm", "loongson,ls7a-pwm"; + reg = <0x0 0x1ff5c080 0x0 0x10>; + interrupt-parent = <&liointc0>; + interrupts = <26 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clk LOONGSON2_APB_CLK>; + #pwm-cells = <3>; + status = "disabled"; + }; + + pwm@1ff5c090 { + compatible = "loongson,ls2k0500-pwm", "loongson,ls7a-pwm"; + reg = <0x0 0x1ff5c090 0x0 0x10>; + interrupt-parent = <&liointc0>; + interrupts = <26 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clk LOONGSON2_APB_CLK>; + #pwm-cells = <3>; + status = "disabled"; + }; + + pwm@1ff5c0a0 { + compatible = "loongson,ls2k0500-pwm", "loongson,ls7a-pwm"; + reg = <0x0 0x1ff5c0a0 0x0 0x10>; + interrupt-parent = <&liointc0>; + interrupts = <26 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clk LOONGSON2_APB_CLK>; + #pwm-cells = <3>; + status = "disabled"; + }; + + pwm@1ff5c0b0 { + compatible = "loongson,ls2k0500-pwm", "loongson,ls7a-pwm"; + reg = <0x0 0x1ff5c0b0 0x0 0x10>; + interrupt-parent = <&liointc0>; + interrupts = <26 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clk LOONGSON2_APB_CLK>; + #pwm-cells = <3>; + status = "disabled"; + }; + + pwm@1ff5c0c0 { + compatible = "loongson,ls2k0500-pwm", "loongson,ls7a-pwm"; + reg = <0x0 0x1ff5c0c0 0x0 0x10>; + interrupt-parent = <&liointc0>; + interrupts = <27 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clk LOONGSON2_APB_CLK>; + #pwm-cells = <3>; + status = "disabled"; + }; + + pwm@1ff5c0d0 { + compatible = "loongson,ls2k0500-pwm", "loongson,ls7a-pwm"; + reg = <0x0 0x1ff5c0d0 0x0 0x10>; + interrupt-parent = <&liointc0>; + interrupts = <27 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clk LOONGSON2_APB_CLK>; + #pwm-cells = <3>; + status = "disabled"; + }; + + pwm@1ff5c0e0 { + compatible = "loongson,ls2k0500-pwm", "loongson,ls7a-pwm"; + reg = <0x0 0x1ff5c0e0 0x0 0x10>; + interrupt-parent = <&liointc0>; + interrupts = <27 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clk LOONGSON2_APB_CLK>; + #pwm-cells = <3>; + status = "disabled"; + }; + + pwm@1ff5c0f0 { + compatible = "loongson,ls2k0500-pwm", "loongson,ls7a-pwm"; + reg = <0x0 0x1ff5c0f0 0x0 0x10>; + interrupt-parent = <&liointc0>; + interrupts = <27 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clk LOONGSON2_APB_CLK>; + #pwm-cells = <3>; + status = "disabled"; + }; + gmac0: ethernet@1f020000 { compatible = "snps,dwmac-3.70a"; reg = <0x0 0x1f020000 0x0 0x10000>; diff --git a/arch/loongarch/boot/dts/loongson-2k1000-ref.dts b/arch/loongarch/boot/dts/loongson-2k1000-ref.dts index 3514ea78f525..78ea995abf1c 100644 --- a/arch/loongarch/boot/dts/loongson-2k1000-ref.dts +++ b/arch/loongarch/boot/dts/loongson-2k1000-ref.dts @@ -5,6 +5,7 @@ /dts-v1/; +#include "dt-bindings/thermal/thermal.h" #include "loongson-2k1000.dtsi" / { @@ -38,6 +39,13 @@ linux,cma-default; }; }; + + fan0: pwm-fan { + compatible = "pwm-fan"; + cooling-levels = <255 153 85 25>; + pwms = <&pwm1 0 100000 0>; + #cooling-cells = <2>; + }; }; &gmac0 { @@ -92,6 +100,22 @@ #size-cells = <0>; }; +&pwm1 { + status = "okay"; + + pinctrl-0 = <&pwm1_pins_default>; + pinctrl-names = "default"; +}; + +&cpu_thermal { + cooling-maps { + map0 { + trip = <&cpu_alert>; + cooling-device = <&fan0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; +}; + &ehci0 { status = "okay"; }; diff --git a/arch/loongarch/boot/dts/loongson-2k1000.dtsi b/arch/loongarch/boot/dts/loongson-2k1000.dtsi index 8dff2aa52417..1da3beb00f0e 100644 --- a/arch/loongarch/boot/dts/loongson-2k1000.dtsi +++ b/arch/loongarch/boot/dts/loongson-2k1000.dtsi @@ -68,7 +68,7 @@ }; thermal-zones { - cpu-thermal { + cpu_thermal: cpu-thermal { polling-delay-passive = <1000>; polling-delay = <5000>; thermal-sensors = <&tsensor 0>; @@ -322,6 +322,46 @@ status = "disabled"; }; + pwm@1fe22000 { + compatible = "loongson,ls2k1000-pwm", "loongson,ls7a-pwm"; + reg = <0x0 0x1fe22000 0x0 0x10>; + interrupt-parent = <&liointc0>; + interrupts = <24 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clk LOONGSON2_APB_CLK>; + #pwm-cells = <3>; + status = "disabled"; + }; + + pwm1: pwm@1fe22010 { + compatible = "loongson,ls2k1000-pwm", "loongson,ls7a-pwm"; + reg = <0x0 0x1fe22010 0x0 0x10>; + interrupt-parent = <&liointc0>; + interrupts = <25 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clk LOONGSON2_APB_CLK>; + #pwm-cells = <3>; + status = "disabled"; + }; + + pwm@1fe22020 { + compatible = "loongson,ls2k1000-pwm", "loongson,ls7a-pwm"; + reg = <0x0 0x1fe22020 0x0 0x10>; + interrupt-parent = <&liointc0>; + interrupts = <26 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clk LOONGSON2_APB_CLK>; + #pwm-cells = <3>; + status = "disabled"; + }; + + pwm@1fe22030 { + compatible = "loongson,ls2k1000-pwm", "loongson,ls7a-pwm"; + reg = <0x0 0x1fe22030 0x0 0x10>; + interrupt-parent = <&liointc0>; + interrupts = <27 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clk LOONGSON2_APB_CLK>; + #pwm-cells = <3>; + status = "disabled"; + }; + pmc: power-management@1fe27000 { compatible = "loongson,ls2k1000-pmc", "loongson,ls2k0500-pmc", "syscon"; reg = <0x0 0x1fe27000 0x0 0x58>; diff --git a/arch/loongarch/boot/dts/loongson-2k2000.dtsi b/arch/loongarch/boot/dts/loongson-2k2000.dtsi index b4ff55a33e90..9e0411f2754c 100644 --- a/arch/loongarch/boot/dts/loongson-2k2000.dtsi +++ b/arch/loongarch/boot/dts/loongson-2k2000.dtsi @@ -165,6 +165,66 @@ interrupt-parent = <&eiointc>; }; + pwm@100a0000 { + compatible = "loongson,ls2k2000-pwm", "loongson,ls7a-pwm"; + reg = <0x0 0x100a0000 0x0 0x10>; + interrupt-parent = <&pic>; + interrupts = <24 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clk LOONGSON2_MISC_CLK>; + #pwm-cells = <3>; + status = "disabled"; + }; + + pwm@100a0100 { + compatible = "loongson,ls2k2000-pwm", "loongson,ls7a-pwm"; + reg = <0x0 0x100a0100 0x0 0x10>; + interrupt-parent = <&pic>; + interrupts = <25 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clk LOONGSON2_MISC_CLK>; + #pwm-cells = <3>; + status = "disabled"; + }; + + pwm@100a0200 { + compatible = "loongson,ls2k2000-pwm", "loongson,ls7a-pwm"; + reg = <0x0 0x100a0200 0x0 0x10>; + interrupt-parent = <&pic>; + interrupts = <26 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clk LOONGSON2_MISC_CLK>; + #pwm-cells = <3>; + status = "disabled"; + }; + + pwm@100a0300 { + compatible = "loongson,ls2k2000-pwm", "loongson,ls7a-pwm"; + reg = <0x0 0x100a0300 0x0 0x10>; + interrupt-parent = <&pic>; + interrupts = <27 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clk LOONGSON2_MISC_CLK>; + #pwm-cells = <3>; + status = "disabled"; + }; + + pwm@100a0400 { + compatible = "loongson,ls2k2000-pwm", "loongson,ls7a-pwm"; + reg = <0x0 0x100a0400 0x0 0x10>; + interrupt-parent = <&pic>; + interrupts = <38 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clk LOONGSON2_MISC_CLK>; + #pwm-cells = <3>; + status = "disabled"; + }; + + pwm@100a0500 { + compatible = "loongson,ls2k2000-pwm", "loongson,ls7a-pwm"; + reg = <0x0 0x100a0500 0x0 0x10>; + interrupt-parent = <&pic>; + interrupts = <39 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clk LOONGSON2_MISC_CLK>; + #pwm-cells = <3>; + status = "disabled"; + }; + rtc0: rtc@100d0100 { compatible = "loongson,ls2k2000-rtc", "loongson,ls7a-rtc"; reg = <0x0 0x100d0100 0x0 0x100>; diff --git a/arch/loongarch/boot/install.sh b/arch/loongarch/boot/install.sh new file mode 100755 index 000000000000..daac197d3315 --- /dev/null +++ b/arch/loongarch/boot/install.sh @@ -0,0 +1,56 @@ +#!/bin/sh +# +# This file is subject to the terms and conditions of the GNU General Public +# License. See the file "COPYING" in the main directory of this archive +# for more details. +# +# Copyright (C) 1995 by Linus Torvalds +# +# Adapted from code in arch/i386/boot/Makefile by H. Peter Anvin +# Adapted from code in arch/i386/boot/install.sh by Russell King +# +# "make install" script for the LoongArch Linux port +# +# Arguments: +# $1 - kernel version +# $2 - kernel image file +# $3 - kernel map file +# $4 - default install path (blank if root directory) + +set -e + +case "${2##*/}" in +vmlinux.elf) + echo "Installing uncompressed vmlinux.elf kernel" + base=vmlinux + ;; +vmlinux.efi) + echo "Installing uncompressed vmlinux.efi kernel" + base=vmlinux + ;; +vmlinuz.efi) + echo "Installing gzip/zstd compressed vmlinuz.efi kernel" + base=vmlinuz + ;; +*) + echo "Warning: Unexpected kernel type" + exit 1 + ;; +esac + +if [ -f $4/$base-$1 ]; then + mv $4/$base-$1 $4/$base-$1.old +fi +cat $2 > $4/$base-$1 + +# Install system map file +if [ -f $4/System.map-$1 ]; then + mv $4/System.map-$1 $4/System.map-$1.old +fi +cp $3 $4/System.map-$1 + +# Install kernel config file +if [ -f $4/config-$1 ]; then + mv $4/config-$1 $4/config-$1.old +fi +cp .config $4/config-$1 diff --git a/arch/loongarch/include/asm/acpi.h b/arch/loongarch/include/asm/acpi.h index 313f66f7913a..7376840fa9f7 100644 --- a/arch/loongarch/include/asm/acpi.h +++ b/arch/loongarch/include/asm/acpi.h @@ -33,7 +33,7 @@ static inline bool acpi_has_cpu_in_madt(void) return true; } -#define MAX_CORE_PIC 256 +#define MAX_CORE_PIC 2048 extern struct list_head acpi_wakeup_device_list; extern struct acpi_madt_core_pic acpi_core_pic[MAX_CORE_PIC]; diff --git a/arch/loongarch/include/asm/entry-common.h b/arch/loongarch/include/asm/entry-common.h index 0fe2a098ded9..099132980dc9 100644 --- a/arch/loongarch/include/asm/entry-common.h +++ b/arch/loongarch/include/asm/entry-common.h @@ -2,12 +2,6 @@ #ifndef ARCH_LOONGARCH_ENTRY_COMMON_H #define ARCH_LOONGARCH_ENTRY_COMMON_H -#include <linux/sched.h> -#include <linux/processor.h> - -static inline bool on_thread_stack(void) -{ - return !(((unsigned long)(current->stack) ^ current_stack_pointer) & ~(THREAD_SIZE - 1)); -} +#include <asm/stacktrace.h> /* For on_thread_stack() */ #endif diff --git a/arch/loongarch/include/asm/irqflags.h b/arch/loongarch/include/asm/irqflags.h index 319a8c616f1f..003172b8406b 100644 --- a/arch/loongarch/include/asm/irqflags.h +++ b/arch/loongarch/include/asm/irqflags.h @@ -14,40 +14,48 @@ static inline void arch_local_irq_enable(void) { u32 flags = CSR_CRMD_IE; + register u32 mask asm("t0") = CSR_CRMD_IE; + __asm__ __volatile__( "csrxchg %[val], %[mask], %[reg]\n\t" : [val] "+r" (flags) - : [mask] "r" (CSR_CRMD_IE), [reg] "i" (LOONGARCH_CSR_CRMD) + : [mask] "r" (mask), [reg] "i" (LOONGARCH_CSR_CRMD) : "memory"); } static inline void arch_local_irq_disable(void) { u32 flags = 0; + register u32 mask asm("t0") = CSR_CRMD_IE; + __asm__ __volatile__( "csrxchg %[val], %[mask], %[reg]\n\t" : [val] "+r" (flags) - : [mask] "r" (CSR_CRMD_IE), [reg] "i" (LOONGARCH_CSR_CRMD) + : [mask] "r" (mask), [reg] "i" (LOONGARCH_CSR_CRMD) : "memory"); } static inline unsigned long arch_local_irq_save(void) { u32 flags = 0; + register u32 mask asm("t0") = CSR_CRMD_IE; + __asm__ __volatile__( "csrxchg %[val], %[mask], %[reg]\n\t" : [val] "+r" (flags) - : [mask] "r" (CSR_CRMD_IE), [reg] "i" (LOONGARCH_CSR_CRMD) + : [mask] "r" (mask), [reg] "i" (LOONGARCH_CSR_CRMD) : "memory"); return flags; } static inline void arch_local_irq_restore(unsigned long flags) { + register u32 mask asm("t0") = CSR_CRMD_IE; + __asm__ __volatile__( "csrxchg %[val], %[mask], %[reg]\n\t" : [val] "+r" (flags) - : [mask] "r" (CSR_CRMD_IE), [reg] "i" (LOONGARCH_CSR_CRMD) + : [mask] "r" (mask), [reg] "i" (LOONGARCH_CSR_CRMD) : "memory"); } diff --git a/arch/loongarch/include/asm/loongarch.h b/arch/loongarch/include/asm/loongarch.h index 52651aa0e583..d84dac88a584 100644 --- a/arch/loongarch/include/asm/loongarch.h +++ b/arch/loongarch/include/asm/loongarch.h @@ -411,8 +411,8 @@ /* Config CSR registers */ #define LOONGARCH_CSR_CPUID 0x20 /* CPU core id */ -#define CSR_CPUID_COREID_WIDTH 9 -#define CSR_CPUID_COREID _ULCAST_(0x1ff) +#define CSR_CPUID_COREID_WIDTH 11 +#define CSR_CPUID_COREID _ULCAST_(0x7ff) #define LOONGARCH_CSR_PRCFG1 0x21 /* Config1 */ #define CSR_CONF1_VSMAX_SHIFT 12 diff --git a/arch/loongarch/include/asm/numa.h b/arch/loongarch/include/asm/numa.h index b5f9de9f102e..bbf9f70bd25f 100644 --- a/arch/loongarch/include/asm/numa.h +++ b/arch/loongarch/include/asm/numa.h @@ -22,20 +22,6 @@ extern int numa_off; extern s16 __cpuid_to_node[CONFIG_NR_CPUS]; extern nodemask_t numa_nodes_parsed __initdata; -struct numa_memblk { - u64 start; - u64 end; - int nid; -}; - -#define NR_NODE_MEMBLKS (MAX_NUMNODES*2) -struct numa_meminfo { - int nr_blks; - struct numa_memblk blk[NR_NODE_MEMBLKS]; -}; - -extern int __init numa_add_memblk(int nodeid, u64 start, u64 end); - extern void __init early_numa_add_cpu(int cpuid, s16 node); extern void numa_add_cpu(unsigned int cpu); extern void numa_remove_cpu(unsigned int cpu); diff --git a/arch/loongarch/include/asm/smp.h b/arch/loongarch/include/asm/smp.h index b87d1d5e5890..ad0bd234a0f1 100644 --- a/arch/loongarch/include/asm/smp.h +++ b/arch/loongarch/include/asm/smp.h @@ -25,6 +25,7 @@ extern int smp_num_siblings; extern int num_processors; extern int disabled_cpus; extern cpumask_t cpu_sibling_map[]; +extern cpumask_t cpu_llc_shared_map[]; extern cpumask_t cpu_core_map[]; extern cpumask_t cpu_foreign_map[]; diff --git a/arch/loongarch/include/asm/sparsemem.h b/arch/loongarch/include/asm/sparsemem.h index 8d4af6aff8a8..4501efac1a87 100644 --- a/arch/loongarch/include/asm/sparsemem.h +++ b/arch/loongarch/include/asm/sparsemem.h @@ -21,11 +21,6 @@ #define VMEMMAP_SIZE 0 /* 1, For FLATMEM; 2, For SPARSEMEM without VMEMMAP. */ #endif -#ifdef CONFIG_MEMORY_HOTPLUG -int memory_add_physaddr_to_nid(u64 addr); -#define memory_add_physaddr_to_nid memory_add_physaddr_to_nid -#endif - #define INIT_MEMBLOCK_RESERVED_REGIONS (INIT_MEMBLOCK_REGIONS + NR_CPUS) #endif /* _LOONGARCH_SPARSEMEM_H */ diff --git a/arch/loongarch/include/asm/stackframe.h b/arch/loongarch/include/asm/stackframe.h index 66736837085b..3eda298702b1 100644 --- a/arch/loongarch/include/asm/stackframe.h +++ b/arch/loongarch/include/asm/stackframe.h @@ -57,6 +57,12 @@ jirl zero, \temp1, 0xc .endm + .macro STACKLEAK_ERASE +#ifdef CONFIG_GCC_PLUGIN_STACKLEAK + bl stackleak_erase_on_task_stack +#endif + .endm + .macro BACKUP_T0T1 csrwr t0, EXCEPTION_KS0 csrwr t1, EXCEPTION_KS1 diff --git a/arch/loongarch/include/asm/stacktrace.h b/arch/loongarch/include/asm/stacktrace.h index fc8b64773794..5c8be156567c 100644 --- a/arch/loongarch/include/asm/stacktrace.h +++ b/arch/loongarch/include/asm/stacktrace.h @@ -31,6 +31,11 @@ bool in_irq_stack(unsigned long stack, struct stack_info *info); bool in_task_stack(unsigned long stack, struct task_struct *task, struct stack_info *info); int get_stack_info(unsigned long stack, struct task_struct *task, struct stack_info *info); +static __always_inline bool on_thread_stack(void) +{ + return !(((unsigned long)(current->stack) ^ current_stack_pointer) & ~(THREAD_SIZE - 1)); +} + #define STR_LONG_L __stringify(LONG_L) #define STR_LONG_S __stringify(LONG_S) #define STR_LONGSIZE __stringify(LONGSIZE) diff --git a/arch/loongarch/include/asm/topology.h b/arch/loongarch/include/asm/topology.h index 50273c9187d0..f06e7ff25bb7 100644 --- a/arch/loongarch/include/asm/topology.h +++ b/arch/loongarch/include/asm/topology.h @@ -19,17 +19,22 @@ extern int pcibus_to_node(struct pci_bus *); #define cpumask_of_pcibus(bus) (cpu_online_mask) -extern unsigned char node_distances[MAX_NUMNODES][MAX_NUMNODES]; - -void numa_set_distance(int from, int to, int distance); - -#define node_distance(from, to) (node_distances[(from)][(to)]) +int __node_distance(int from, int to); +#define node_distance(from, to) __node_distance(from, to) #else #define pcibus_to_node(bus) 0 #endif #ifdef CONFIG_SMP +/* + * Return cpus that shares the last level cache. + */ +static inline const struct cpumask *cpu_coregroup_mask(int cpu) +{ + return &cpu_llc_shared_map[cpu]; +} + #define topology_physical_package_id(cpu) (cpu_data[cpu].package) #define topology_core_id(cpu) (cpu_data[cpu].core) #define topology_core_cpumask(cpu) (&cpu_core_map[cpu]) diff --git a/arch/loongarch/include/asm/vdso/getrandom.h b/arch/loongarch/include/asm/vdso/getrandom.h index 48c43f55b039..a81724b69f29 100644 --- a/arch/loongarch/include/asm/vdso/getrandom.h +++ b/arch/loongarch/include/asm/vdso/getrandom.h @@ -20,7 +20,7 @@ static __always_inline ssize_t getrandom_syscall(void *_buffer, size_t _len, uns asm volatile( " syscall 0\n" - : "+r" (ret) + : "=r" (ret) : "r" (nr), "r" (buffer), "r" (len), "r" (flags) : "$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7", "$t8", "memory"); diff --git a/arch/loongarch/include/asm/vdso/gettimeofday.h b/arch/loongarch/include/asm/vdso/gettimeofday.h index 88cfcf133116..f15503e3336c 100644 --- a/arch/loongarch/include/asm/vdso/gettimeofday.h +++ b/arch/loongarch/include/asm/vdso/gettimeofday.h @@ -25,7 +25,7 @@ static __always_inline long gettimeofday_fallback( asm volatile( " syscall 0\n" - : "+r" (ret) + : "=r" (ret) : "r" (nr), "r" (tv), "r" (tz) : "$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7", "$t8", "memory"); @@ -44,7 +44,7 @@ static __always_inline long clock_gettime_fallback( asm volatile( " syscall 0\n" - : "+r" (ret) + : "=r" (ret) : "r" (nr), "r" (clkid), "r" (ts) : "$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7", "$t8", "memory"); @@ -63,7 +63,7 @@ static __always_inline int clock_getres_fallback( asm volatile( " syscall 0\n" - : "+r" (ret) + : "=r" (ret) : "r" (nr), "r" (clkid), "r" (ts) : "$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7", "$t8", "memory"); diff --git a/arch/loongarch/kernel/Makefile b/arch/loongarch/kernel/Makefile index f9dcaa60033d..6f5a4574a911 100644 --- a/arch/loongarch/kernel/Makefile +++ b/arch/loongarch/kernel/Makefile @@ -5,7 +5,7 @@ OBJECT_FILES_NON_STANDARD_head.o := y -extra-y := vmlinux.lds +always-$(KBUILD_BUILTIN) := vmlinux.lds obj-y += head.o cpu-probe.o cacheinfo.o env.o setup.o entry.o genex.o \ traps.o irq.o idle.o process.o dma.o mem.o reset.o switch.o \ diff --git a/arch/loongarch/kernel/acpi.c b/arch/loongarch/kernel/acpi.c index 1120ac2824f6..a54cd6fd3796 100644 --- a/arch/loongarch/kernel/acpi.c +++ b/arch/loongarch/kernel/acpi.c @@ -244,22 +244,6 @@ fdt_earlycon: #ifdef CONFIG_ACPI_NUMA -static __init int setup_node(int pxm) -{ - return acpi_map_pxm_to_node(pxm); -} - -void __init numa_set_distance(int from, int to, int distance) -{ - if ((u8)distance != distance || (from == to && distance != LOCAL_DISTANCE)) { - pr_warn_once("Warning: invalid distance parameter, from=%d to=%d distance=%d\n", - from, to, distance); - return; - } - - node_distances[from][to] = distance; -} - /* Callback for Proximity Domain -> CPUID mapping */ void __init acpi_numa_processor_affinity_init(struct acpi_srat_cpu_affinity *pa) @@ -280,7 +264,41 @@ acpi_numa_processor_affinity_init(struct acpi_srat_cpu_affinity *pa) pxm |= (pa->proximity_domain_hi[1] << 16); pxm |= (pa->proximity_domain_hi[2] << 24); } - node = setup_node(pxm); + node = acpi_map_pxm_to_node(pxm); + if (node < 0) { + pr_err("SRAT: Too many proximity domains %x\n", pxm); + bad_srat(); + return; + } + + if (pa->apic_id >= CONFIG_NR_CPUS) { + pr_info("SRAT: PXM %u -> CPU 0x%02x -> Node %u skipped apicid that is too big\n", + pxm, pa->apic_id, node); + return; + } + + early_numa_add_cpu(pa->apic_id, node); + + set_cpuid_to_node(pa->apic_id, node); + node_set(node, numa_nodes_parsed); + pr_info("SRAT: PXM %u -> CPU 0x%02x -> Node %u\n", pxm, pa->apic_id, node); +} + +void __init +acpi_numa_x2apic_affinity_init(struct acpi_srat_x2apic_cpu_affinity *pa) +{ + int pxm, node; + + if (srat_disabled()) + return; + if (pa->header.length < sizeof(struct acpi_srat_x2apic_cpu_affinity)) { + bad_srat(); + return; + } + if ((pa->flags & ACPI_SRAT_CPU_ENABLED) == 0) + return; + pxm = pa->proximity_domain; + node = acpi_map_pxm_to_node(pxm); if (node < 0) { pr_err("SRAT: Too many proximity domains %x\n", pxm); bad_srat(); diff --git a/arch/loongarch/kernel/entry.S b/arch/loongarch/kernel/entry.S index 2abc29e57381..47e1db9a1ce4 100644 --- a/arch/loongarch/kernel/entry.S +++ b/arch/loongarch/kernel/entry.S @@ -73,6 +73,7 @@ SYM_CODE_START(handle_syscall) move a0, sp bl do_syscall + STACKLEAK_ERASE RESTORE_ALL_AND_RET SYM_CODE_END(handle_syscall) _ASM_NOKPROBE(handle_syscall) @@ -81,6 +82,7 @@ SYM_CODE_START(ret_from_fork_asm) UNWIND_HINT_REGS move a1, sp bl ret_from_fork + STACKLEAK_ERASE RESTORE_STATIC RESTORE_SOME RESTORE_SP_AND_RET @@ -92,6 +94,7 @@ SYM_CODE_START(ret_from_kernel_thread_asm) move a2, s0 move a3, s1 bl ret_from_kernel_thread + STACKLEAK_ERASE RESTORE_STATIC RESTORE_SOME RESTORE_SP_AND_RET diff --git a/arch/loongarch/kernel/numa.c b/arch/loongarch/kernel/numa.c index 30a72fd528c0..d6e73e8f9c0b 100644 --- a/arch/loongarch/kernel/numa.c +++ b/arch/loongarch/kernel/numa.c @@ -11,6 +11,7 @@ #include <linux/mmzone.h> #include <linux/export.h> #include <linux/nodemask.h> +#include <linux/numa_memblks.h> #include <linux/swap.h> #include <linux/memblock.h> #include <linux/pfn.h> @@ -27,10 +28,6 @@ #include <asm/time.h> int numa_off; -unsigned char node_distances[MAX_NUMNODES][MAX_NUMNODES]; -EXPORT_SYMBOL(node_distances); - -static struct numa_meminfo numa_meminfo; cpumask_t cpus_on_node[MAX_NUMNODES]; cpumask_t phys_cpus_on_node[MAX_NUMNODES]; EXPORT_SYMBOL(cpus_on_node); @@ -43,8 +40,6 @@ s16 __cpuid_to_node[CONFIG_NR_CPUS] = { }; EXPORT_SYMBOL(__cpuid_to_node); -nodemask_t numa_nodes_parsed __initdata; - #ifdef CONFIG_HAVE_SETUP_PER_CPU_AREA unsigned long __per_cpu_offset[NR_CPUS] __read_mostly; EXPORT_SYMBOL(__per_cpu_offset); @@ -145,48 +140,6 @@ void numa_remove_cpu(unsigned int cpu) cpumask_clear_cpu(cpu, &cpus_on_node[nid]); } -static int __init numa_add_memblk_to(int nid, u64 start, u64 end, - struct numa_meminfo *mi) -{ - /* ignore zero length blks */ - if (start == end) - return 0; - - /* whine about and ignore invalid blks */ - if (start > end || nid < 0 || nid >= MAX_NUMNODES) { - pr_warn("NUMA: Warning: invalid memblk node %d [mem %#010Lx-%#010Lx]\n", - nid, start, end - 1); - return 0; - } - - if (mi->nr_blks >= NR_NODE_MEMBLKS) { - pr_err("NUMA: too many memblk ranges\n"); - return -EINVAL; - } - - mi->blk[mi->nr_blks].start = PFN_ALIGN(start); - mi->blk[mi->nr_blks].end = PFN_ALIGN(end - PAGE_SIZE + 1); - mi->blk[mi->nr_blks].nid = nid; - mi->nr_blks++; - return 0; -} - -/** - * numa_add_memblk - Add one numa_memblk to numa_meminfo - * @nid: NUMA node ID of the new memblk - * @start: Start address of the new memblk - * @end: End address of the new memblk - * - * Add a new memblk to the default numa_meminfo. - * - * RETURNS: - * 0 on success, -errno on failure. - */ -int __init numa_add_memblk(int nid, u64 start, u64 end) -{ - return numa_add_memblk_to(nid, start, end, &numa_meminfo); -} - static void __init node_mem_init(unsigned int node) { unsigned long start_pfn, end_pfn; @@ -205,18 +158,6 @@ static void __init node_mem_init(unsigned int node) #ifdef CONFIG_ACPI_NUMA -static void __init add_node_intersection(u32 node, u64 start, u64 size, u32 type) -{ - static unsigned long num_physpages; - - num_physpages += (size >> PAGE_SHIFT); - pr_info("Node%d: mem_type:%d, mem_start:0x%llx, mem_size:0x%llx Bytes\n", - node, type, start, size); - pr_info(" start_pfn:0x%llx, end_pfn:0x%llx, num_physpages:0x%lx\n", - start >> PAGE_SHIFT, (start + size) >> PAGE_SHIFT, num_physpages); - memblock_set_node(start, size, &memblock.memory, node); -} - /* * add_numamem_region * @@ -228,28 +169,21 @@ static void __init add_node_intersection(u32 node, u64 start, u64 size, u32 type */ static void __init add_numamem_region(u64 start, u64 end, u32 type) { - u32 i; - u64 ofs = start; + u32 node = pa_to_nid(start); + u64 size = end - start; + static unsigned long num_physpages; if (start >= end) { pr_debug("Invalid region: %016llx-%016llx\n", start, end); return; } - for (i = 0; i < numa_meminfo.nr_blks; i++) { - struct numa_memblk *mb = &numa_meminfo.blk[i]; - - if (ofs > mb->end) - continue; - - if (end > mb->end) { - add_node_intersection(mb->nid, ofs, mb->end - ofs, type); - ofs = mb->end; - } else { - add_node_intersection(mb->nid, ofs, end - ofs, type); - break; - } - } + num_physpages += (size >> PAGE_SHIFT); + pr_info("Node%d: mem_type:%d, mem_start:0x%llx, mem_size:0x%llx Bytes\n", + node, type, start, size); + pr_info(" start_pfn:0x%llx, end_pfn:0x%llx, num_physpages:0x%lx\n", + start >> PAGE_SHIFT, end >> PAGE_SHIFT, num_physpages); + memblock_set_node(start, size, &memblock.memory, node); } static void __init init_node_memblock(void) @@ -291,24 +225,6 @@ static void __init init_node_memblock(void) } } -static void __init numa_default_distance(void) -{ - int row, col; - - for (row = 0; row < MAX_NUMNODES; row++) - for (col = 0; col < MAX_NUMNODES; col++) { - if (col == row) - node_distances[row][col] = LOCAL_DISTANCE; - else - /* We assume that one node per package here! - * - * A SLIT should be used for multiple nodes - * per package to override default setting. - */ - node_distances[row][col] = REMOTE_DISTANCE; - } -} - /* * fake_numa_init() - For Non-ACPI systems * Return: 0 on success, -errno on failure. @@ -333,11 +249,11 @@ int __init init_numa_memory(void) for (i = 0; i < NR_CPUS; i++) set_cpuid_to_node(i, NUMA_NO_NODE); - numa_default_distance(); + numa_reset_distance(); nodes_clear(numa_nodes_parsed); nodes_clear(node_possible_map); nodes_clear(node_online_map); - memset(&numa_meminfo, 0, sizeof(numa_meminfo)); + WARN_ON(memblock_clear_hotplug(0, PHYS_ADDR_MAX)); /* Parse SRAT and SLIT if provided by firmware. */ ret = acpi_disabled ? fake_numa_init() : acpi_numa_init(); diff --git a/arch/loongarch/kernel/smp.c b/arch/loongarch/kernel/smp.c index 4b24589c0b56..46036d98da75 100644 --- a/arch/loongarch/kernel/smp.c +++ b/arch/loongarch/kernel/smp.c @@ -46,6 +46,10 @@ EXPORT_SYMBOL(__cpu_logical_map); cpumask_t cpu_sibling_map[NR_CPUS] __read_mostly; EXPORT_SYMBOL(cpu_sibling_map); +/* Representing the last level cache shared map of each logical CPU */ +cpumask_t cpu_llc_shared_map[NR_CPUS] __read_mostly; +EXPORT_SYMBOL(cpu_llc_shared_map); + /* Representing the core map of multi-core chips of each logical CPU */ cpumask_t cpu_core_map[NR_CPUS] __read_mostly; EXPORT_SYMBOL(cpu_core_map); @@ -63,6 +67,9 @@ EXPORT_SYMBOL(cpu_foreign_map); /* representing cpus for which sibling maps can be computed */ static cpumask_t cpu_sibling_setup_map; +/* representing cpus for which llc shared maps can be computed */ +static cpumask_t cpu_llc_shared_setup_map; + /* representing cpus for which core maps can be computed */ static cpumask_t cpu_core_setup_map; @@ -102,6 +109,34 @@ static inline void set_cpu_core_map(int cpu) } } +static inline void set_cpu_llc_shared_map(int cpu) +{ + int i; + + cpumask_set_cpu(cpu, &cpu_llc_shared_setup_map); + + for_each_cpu(i, &cpu_llc_shared_setup_map) { + if (cpu_to_node(cpu) == cpu_to_node(i)) { + cpumask_set_cpu(i, &cpu_llc_shared_map[cpu]); + cpumask_set_cpu(cpu, &cpu_llc_shared_map[i]); + } + } +} + +static inline void clear_cpu_llc_shared_map(int cpu) +{ + int i; + + for_each_cpu(i, &cpu_llc_shared_setup_map) { + if (cpu_to_node(cpu) == cpu_to_node(i)) { + cpumask_clear_cpu(i, &cpu_llc_shared_map[cpu]); + cpumask_clear_cpu(cpu, &cpu_llc_shared_map[i]); + } + } + + cpumask_clear_cpu(cpu, &cpu_llc_shared_setup_map); +} + static inline void set_cpu_sibling_map(int cpu) { int i; @@ -406,6 +441,7 @@ int loongson_cpu_disable(void) #endif set_cpu_online(cpu, false); clear_cpu_sibling_map(cpu); + clear_cpu_llc_shared_map(cpu); calculate_cpu_foreign_map(); local_irq_save(flags); irq_migrate_all_off_this_cpu(); @@ -572,6 +608,7 @@ void __init smp_prepare_cpus(unsigned int max_cpus) current_thread_info()->cpu = 0; loongson_prepare_cpus(max_cpus); set_cpu_sibling_map(0); + set_cpu_llc_shared_map(0); set_cpu_core_map(0); calculate_cpu_foreign_map(); #ifndef CONFIG_HOTPLUG_CPU @@ -613,6 +650,7 @@ asmlinkage void start_secondary(void) loongson_init_secondary(); set_cpu_sibling_map(cpu); + set_cpu_llc_shared_map(cpu); set_cpu_core_map(cpu); notify_cpu_starting(cpu); diff --git a/arch/loongarch/kernel/vdso.c b/arch/loongarch/kernel/vdso.c index 10cf1608c7b3..7b888d9085a0 100644 --- a/arch/loongarch/kernel/vdso.c +++ b/arch/loongarch/kernel/vdso.c @@ -105,7 +105,9 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) vdso_addr = data_addr + VVAR_SIZE; vma = _install_special_mapping(mm, vdso_addr, info->size, - VM_READ | VM_EXEC | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC, + VM_READ | VM_EXEC | + VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC | + VM_SEALED_SYSMAP, &info->code_mapping); if (IS_ERR(vma)) { ret = PTR_ERR(vma); diff --git a/arch/loongarch/mm/hugetlbpage.c b/arch/loongarch/mm/hugetlbpage.c index cea84d7f2b91..02dad4624fe3 100644 --- a/arch/loongarch/mm/hugetlbpage.c +++ b/arch/loongarch/mm/hugetlbpage.c @@ -47,7 +47,8 @@ pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr, pmd = pmd_offset(pud, addr); } } - return pmd_none(pmdp_get(pmd)) ? NULL : (pte_t *) pmd; + + return (!pmd || pmd_none(pmdp_get(pmd))) ? NULL : (pte_t *) pmd; } uint64_t pmd_to_entrylo(unsigned long pmd_val) diff --git a/arch/loongarch/mm/init.c b/arch/loongarch/mm/init.c index 06f11d9e4ec1..c3e4586a7975 100644 --- a/arch/loongarch/mm/init.c +++ b/arch/loongarch/mm/init.c @@ -106,14 +106,6 @@ void arch_remove_memory(u64 start, u64 size, struct vmem_altmap *altmap) page += vmem_altmap_offset(altmap); __remove_pages(start_pfn, nr_pages, altmap); } - -#ifdef CONFIG_NUMA -int memory_add_physaddr_to_nid(u64 start) -{ - return pa_to_nid(start); -} -EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid); -#endif #endif #ifdef CONFIG_SPARSEMEM_VMEMMAP diff --git a/arch/loongarch/pci/acpi.c b/arch/loongarch/pci/acpi.c index 1da4dc46df43..50c9016641a4 100644 --- a/arch/loongarch/pci/acpi.c +++ b/arch/loongarch/pci/acpi.c @@ -194,6 +194,7 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root) { struct pci_bus *bus; struct pci_root_info *info; + struct pci_host_bridge *host; struct acpi_pci_root_ops *root_ops; int domain = root->segment; int busnum = root->secondary.start; @@ -237,8 +238,17 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root) return NULL; } - pci_bus_size_bridges(bus); - pci_bus_assign_resources(bus); + /* If we must preserve the resource configuration, claim now */ + host = pci_find_host_bridge(bus); + if (host->preserve_config) + pci_bus_claim_resources(bus); + + /* + * Assign whatever was left unassigned. If we didn't claim above, + * this will reassign everything. + */ + pci_assign_unassigned_root_bus_resources(bus); + list_for_each_entry(child, &bus->children, node) pcie_bus_configure_settings(child); } diff --git a/arch/m68k/kernel/Makefile b/arch/m68k/kernel/Makefile index 6c732ed3998b..57c1b3e8d60e 100644 --- a/arch/m68k/kernel/Makefile +++ b/arch/m68k/kernel/Makefile @@ -3,7 +3,7 @@ # Makefile for the linux kernel. # -extra-y += vmlinux.lds +always-$(KBUILD_BUILTIN) += vmlinux.lds obj-$(CONFIG_MMU_MOTOROLA) := head.o obj-$(CONFIG_SUN3) := sun3-head.o diff --git a/arch/microblaze/kernel/Makefile b/arch/microblaze/kernel/Makefile index 85c4d29ef43e..241e466e7333 100644 --- a/arch/microblaze/kernel/Makefile +++ b/arch/microblaze/kernel/Makefile @@ -11,7 +11,7 @@ CFLAGS_REMOVE_ftrace.o = -pg CFLAGS_REMOVE_process.o = -pg endif -extra-y := vmlinux.lds +always-$(KBUILD_BUILTIN) := vmlinux.lds obj-y += head.o dma.o exceptions.o \ hw_exception_handler.o irq.o \ diff --git a/arch/mips/Kbuild.platforms b/arch/mips/Kbuild.platforms index bca37ddf974b..41a00fa860c1 100644 --- a/arch/mips/Kbuild.platforms +++ b/arch/mips/Kbuild.platforms @@ -11,6 +11,7 @@ platform-$(CONFIG_CAVIUM_OCTEON_SOC) += cavium-octeon/ platform-$(CONFIG_EYEQ) += mobileye/ platform-$(CONFIG_MIPS_COBALT) += cobalt/ platform-$(CONFIG_MACH_DECSTATION) += dec/ +platform-$(CONFIG_ECONET) += econet/ platform-$(CONFIG_MIPS_GENERIC) += generic/ platform-$(CONFIG_MACH_JAZZ) += jazz/ platform-$(CONFIG_LANTIQ) += lantiq/ diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index fc0772c1bad4..1e48184ecf1e 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -391,6 +391,31 @@ config MACH_DECSTATION otherwise choose R3000. +config ECONET + bool "EcoNet MIPS family" + select BOOT_RAW + select CPU_BIG_ENDIAN + select DEBUG_ZBOOT if DEBUG_KERNEL + select EARLY_PRINTK_8250 + select ECONET_EN751221_TIMER + select SERIAL_8250 + select SERIAL_OF_PLATFORM + select SYS_SUPPORTS_BIG_ENDIAN + select SYS_HAS_CPU_MIPS32_R1 + select SYS_HAS_CPU_MIPS32_R2 + select SYS_HAS_EARLY_PRINTK + select SYS_SUPPORTS_32BIT_KERNEL + select SYS_SUPPORTS_MIPS16 + select SYS_SUPPORTS_ZBOOT_UART16550 + select USE_GENERIC_EARLY_PRINTK_8250 + select USE_OF + help + EcoNet EN75xx MIPS devices are big endian MIPS machines used + in XPON (fiber) and DSL applications. They have SPI, PCI, USB, + GPIO, and Ethernet, with optional XPON, DSL, and VoIP DSP cores. + Don't confuse these with the Airoha ARM devices sometimes referred + to as "EcoNet", this family is for MIPS based devices only. + config MACH_JAZZ bool "Jazz family of machines" select ARC_MEMORY @@ -617,6 +642,7 @@ config EYEQ select USB_UHCI_BIG_ENDIAN_DESC if CPU_BIG_ENDIAN select USB_UHCI_BIG_ENDIAN_MMIO if CPU_BIG_ENDIAN select USE_OF + select HOTPLUG_PARALLEL if SMP help Select this to build a kernel supporting EyeQ SoC from Mobileye. @@ -1020,6 +1046,7 @@ source "arch/mips/ath79/Kconfig" source "arch/mips/bcm47xx/Kconfig" source "arch/mips/bcm63xx/Kconfig" source "arch/mips/bmips/Kconfig" +source "arch/mips/econet/Kconfig" source "arch/mips/generic/Kconfig" source "arch/mips/ingenic/Kconfig" source "arch/mips/jazz/Kconfig" @@ -2287,6 +2314,7 @@ config MIPS_CPS select MIPS_CM select MIPS_CPS_PM if HOTPLUG_CPU select SMP + select HOTPLUG_SMT if HOTPLUG_PARALLEL select HOTPLUG_CORE_SYNC_DEAD if HOTPLUG_CPU select SYNC_R4K if (CEVT_R4K || CSRC_R4K) select SYS_SUPPORTS_HOTPLUG_CPU diff --git a/arch/mips/alchemy/common/gpiolib.c b/arch/mips/alchemy/common/gpiolib.c index 1b16daaa86ae..411f70ceb762 100644 --- a/arch/mips/alchemy/common/gpiolib.c +++ b/arch/mips/alchemy/common/gpiolib.c @@ -119,9 +119,11 @@ static int alchemy_gpic_get(struct gpio_chip *chip, unsigned int off) return !!au1300_gpio_get_value(off + AU1300_GPIO_BASE); } -static void alchemy_gpic_set(struct gpio_chip *chip, unsigned int off, int v) +static int alchemy_gpic_set(struct gpio_chip *chip, unsigned int off, int v) { au1300_gpio_set_value(off + AU1300_GPIO_BASE, v); + + return 0; } static int alchemy_gpic_dir_input(struct gpio_chip *chip, unsigned int off) @@ -145,7 +147,7 @@ static struct gpio_chip au1300_gpiochip = { .direction_input = alchemy_gpic_dir_input, .direction_output = alchemy_gpic_dir_output, .get = alchemy_gpic_get, - .set = alchemy_gpic_set, + .set_rv = alchemy_gpic_set, .to_irq = alchemy_gpic_gpio_to_irq, .base = AU1300_GPIO_BASE, .ngpio = AU1300_GPIO_NUM, diff --git a/arch/mips/bcm63xx/boards/board_bcm963xx.c b/arch/mips/bcm63xx/boards/board_bcm963xx.c index 9cc8fbf218a5..c5617b889b1c 100644 --- a/arch/mips/bcm63xx/boards/board_bcm963xx.c +++ b/arch/mips/bcm63xx/boards/board_bcm963xx.c @@ -764,7 +764,7 @@ void __init board_prom_init(void) snprintf(cfe_version, 12, "%s", (char *) &cfe[4]); } } else { - strcpy(cfe_version, "unknown"); + strscpy(cfe_version, "unknown"); } pr_info("CFE version: %s\n", cfe_version); diff --git a/arch/mips/bcm63xx/gpio.c b/arch/mips/bcm63xx/gpio.c index 5c4a233db55f..e7a53cd0dec5 100644 --- a/arch/mips/bcm63xx/gpio.c +++ b/arch/mips/bcm63xx/gpio.c @@ -35,8 +35,7 @@ static void bcm63xx_gpio_out_low_reg_init(void) static DEFINE_SPINLOCK(bcm63xx_gpio_lock); static u32 gpio_out_low, gpio_out_high; -static void bcm63xx_gpio_set(struct gpio_chip *chip, - unsigned gpio, int val) +static int bcm63xx_gpio_set(struct gpio_chip *chip, unsigned int gpio, int val) { u32 reg; u32 mask; @@ -62,6 +61,8 @@ static void bcm63xx_gpio_set(struct gpio_chip *chip, *v &= ~mask; bcm_gpio_writel(*v, reg); spin_unlock_irqrestore(&bcm63xx_gpio_lock, flags); + + return 0; } static int bcm63xx_gpio_get(struct gpio_chip *chip, unsigned gpio) @@ -130,7 +131,7 @@ static struct gpio_chip bcm63xx_gpio_chip = { .direction_input = bcm63xx_gpio_direction_input, .direction_output = bcm63xx_gpio_direction_output, .get = bcm63xx_gpio_get, - .set = bcm63xx_gpio_set, + .set_rv = bcm63xx_gpio_set, .base = 0, }; diff --git a/arch/mips/boot/compressed/uart-16550.c b/arch/mips/boot/compressed/uart-16550.c index db618e72a0c4..529e77a6487c 100644 --- a/arch/mips/boot/compressed/uart-16550.c +++ b/arch/mips/boot/compressed/uart-16550.c @@ -20,6 +20,11 @@ #define PORT(offset) (CKSEG1ADDR(INGENIC_UART_BASE_ADDR) + (4 * offset)) #endif +#ifdef CONFIG_ECONET +#define EN75_UART_BASE 0x1fbf0003 +#define PORT(offset) (CKSEG1ADDR(EN75_UART_BASE) + (4 * (offset))) +#endif + #ifndef IOTYPE #define IOTYPE char #endif diff --git a/arch/mips/boot/dts/Makefile b/arch/mips/boot/dts/Makefile index ff468439a8c4..7375c6ced82b 100644 --- a/arch/mips/boot/dts/Makefile +++ b/arch/mips/boot/dts/Makefile @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 subdir-$(CONFIG_BMIPS_GENERIC) += brcm subdir-$(CONFIG_CAVIUM_OCTEON_SOC) += cavium-octeon +subdir-$(CONFIG_ECONET) += econet subdir-$(CONFIG_EYEQ) += mobileye subdir-$(CONFIG_FIT_IMAGE_FDT_MARDUK) += img subdir-$(CONFIG_FIT_IMAGE_FDT_BOSTON) += img diff --git a/arch/mips/boot/dts/econet/Makefile b/arch/mips/boot/dts/econet/Makefile new file mode 100644 index 000000000000..b467d5624e39 --- /dev/null +++ b/arch/mips/boot/dts/econet/Makefile @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0 +dtb-$(CONFIG_DTB_ECONET_SMARTFIBER_XP8421_B) += en751221_smartfiber_xp8421-b.dtb diff --git a/arch/mips/boot/dts/econet/en751221.dtsi b/arch/mips/boot/dts/econet/en751221.dtsi new file mode 100644 index 000000000000..66197e73d4f0 --- /dev/null +++ b/arch/mips/boot/dts/econet/en751221.dtsi @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/dts-v1/; + +/ { + compatible = "econet,en751221"; + #address-cells = <1>; + #size-cells = <1>; + + hpt_clock: clock { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <200000000>; /* 200 MHz */ + }; + + cpus: cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + device_type = "cpu"; + compatible = "mips,mips24KEc"; + reg = <0>; + }; + }; + + cpuintc: interrupt-controller { + compatible = "mti,cpu-interrupt-controller"; + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <1>; + }; + + intc: interrupt-controller@1fb40000 { + compatible = "econet,en751221-intc"; + reg = <0x1fb40000 0x100>; + interrupt-parent = <&cpuintc>; + interrupts = <2>; + + interrupt-controller; + #interrupt-cells = <1>; + econet,shadow-interrupts = <7 2>, <8 3>, <13 12>, <30 29>; + }; + + uart: serial@1fbf0000 { + compatible = "ns16550"; + reg = <0x1fbf0000 0x30>; + reg-io-width = <4>; + reg-shift = <2>; + interrupt-parent = <&intc>; + interrupts = <0>; + /* + * Conversion of baud rate to clock frequency requires a + * computation that is not in the ns16550 driver, so this + * uart is fixed at 115200 baud. + */ + clock-frequency = <1843200>; + }; + + timer_hpt: timer@1fbf0400 { + compatible = "econet,en751221-timer"; + reg = <0x1fbf0400 0x100>; + + interrupt-parent = <&intc>; + interrupts = <30>; + clocks = <&hpt_clock>; + }; +}; diff --git a/arch/mips/boot/dts/econet/en751221_smartfiber_xp8421-b.dts b/arch/mips/boot/dts/econet/en751221_smartfiber_xp8421-b.dts new file mode 100644 index 000000000000..8223c5bce67f --- /dev/null +++ b/arch/mips/boot/dts/econet/en751221_smartfiber_xp8421-b.dts @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/dts-v1/; + +#include "en751221.dtsi" + +/ { + model = "SmartFiber XP8421-B"; + compatible = "smartfiber,xp8421-b", "econet,en751221"; + + memory@0 { + device_type = "memory"; + reg = <0x00000000 0x1c000000>; + }; + + chosen { + stdout-path = "/serial@1fbf0000:115200"; + linux,usable-memory-range = <0x00020000 0x1bfe0000>; + }; +}; diff --git a/arch/mips/boot/dts/loongson/loongson64c_4core_ls7a.dts b/arch/mips/boot/dts/loongson/loongson64c_4core_ls7a.dts index c7ea4f1c0bb2..6c277ab83d4b 100644 --- a/arch/mips/boot/dts/loongson/loongson64c_4core_ls7a.dts +++ b/arch/mips/boot/dts/loongson/loongson64c_4core_ls7a.dts @@ -29,6 +29,7 @@ compatible = "loongson,pch-msi-1.0"; reg = <0 0x2ff00000 0 0x8>; interrupt-controller; + #interrupt-cells = <1>; msi-controller; loongson,msi-base-vec = <64>; loongson,msi-num-vecs = <64>; diff --git a/arch/mips/boot/dts/pic32/pic32mzda.dtsi b/arch/mips/boot/dts/pic32/pic32mzda.dtsi index fdc721b414a8..feca35ba56a4 100644 --- a/arch/mips/boot/dts/pic32/pic32mzda.dtsi +++ b/arch/mips/boot/dts/pic32/pic32mzda.dtsi @@ -225,7 +225,7 @@ gpio-ranges = <&pic32_pinctrl 0 144 16>; }; - sdhci: sdhci@1f8ec000 { + sdhci: mmc@1f8ec000 { compatible = "microchip,pic32mzda-sdhci"; reg = <0x1f8ec000 0x100>; interrupts = <191 IRQ_TYPE_LEVEL_HIGH>; diff --git a/arch/mips/boot/dts/realtek/rtl930x.dtsi b/arch/mips/boot/dts/realtek/rtl930x.dtsi index f2e57ea3a60c..101bab72a95f 100644 --- a/arch/mips/boot/dts/realtek/rtl930x.dtsi +++ b/arch/mips/boot/dts/realtek/rtl930x.dtsi @@ -69,6 +69,39 @@ #size-cells = <0>; status = "disabled"; }; + + mdio_controller: mdio-controller@ca00 { + compatible = "realtek,rtl9301-mdio"; + reg = <0xca00 0x200>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + + mdio0: mdio-bus@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + mdio1: mdio-bus@1 { + reg = <1>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + mdio2: mdio-bus@2 { + reg = <2>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + mdio3: mdio-bus@3 { + reg = <3>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + }; }; soc: soc@18000000 { diff --git a/arch/mips/econet/Kconfig b/arch/mips/econet/Kconfig new file mode 100644 index 000000000000..fd69884cc9a8 --- /dev/null +++ b/arch/mips/econet/Kconfig @@ -0,0 +1,48 @@ +# SPDX-License-Identifier: GPL-2.0 +if ECONET + +choice + prompt "EcoNet SoC selection" + default SOC_ECONET_EN751221 + help + Select EcoNet MIPS SoC type. Individual SoCs within a family are + very similar, so is it enough to select the right family, and + then customize to the specific SoC using the device tree only. + + config SOC_ECONET_EN751221 + bool "EN751221 family" + select COMMON_CLK + select ECONET_EN751221_INTC + select IRQ_MIPS_CPU + select SMP + select SMP_UP + select SYS_SUPPORTS_SMP + help + The EN751221 family includes EN7512, RN7513, EN7521, EN7526. + They are based on single core MIPS 34Kc processors. To boot + this kernel, you will need a device tree such as + MIPS_RAW_APPENDED_DTB=y, and a root filesystem. +endchoice + +choice + prompt "Devicetree selection" + default DTB_ECONET_NONE + help + Select the devicetree. + + config DTB_ECONET_NONE + bool "None" + + config DTB_ECONET_SMARTFIBER_XP8421_B + bool "EN751221 SmartFiber XP8421-B" + depends on SOC_ECONET_EN751221 + select BUILTIN_DTB + help + The SmartFiber XP8421-B is a device based on the EN751221 SoC. + It has 512MB of memory and 256MB of NAND flash. This kernel + needs only an appended initramfs to boot. It can be loaded + through XMODEM and booted from memory in the bootloader, or + it can be packed in tclinux.trx format and written to flash. +endchoice + +endif diff --git a/arch/mips/econet/Makefile b/arch/mips/econet/Makefile new file mode 100644 index 000000000000..7e4529e7d3d7 --- /dev/null +++ b/arch/mips/econet/Makefile @@ -0,0 +1,2 @@ + +obj-y := init.o diff --git a/arch/mips/econet/Platform b/arch/mips/econet/Platform new file mode 100644 index 000000000000..ea5616447bcd --- /dev/null +++ b/arch/mips/econet/Platform @@ -0,0 +1,5 @@ +# To address a 7.2MB kernel size limit in the EcoNet SDK bootloader, +# we put the load address well above where the bootloader loads and then use +# zboot. So please set CONFIG_ZBOOT_LOAD_ADDRESS to the address where your +# bootloader actually places the kernel. +load-$(CONFIG_ECONET) += 0xffffffff81000000 diff --git a/arch/mips/econet/init.c b/arch/mips/econet/init.c new file mode 100644 index 000000000000..6f43ffb209cb --- /dev/null +++ b/arch/mips/econet/init.c @@ -0,0 +1,78 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * EcoNet setup code + * + * Copyright (C) 2025 Caleb James DeLisle <cjd@cjdns.fr> + */ + +#include <linux/init.h> +#include <linux/of_clk.h> +#include <linux/irqchip.h> + +#include <asm/addrspace.h> +#include <asm/io.h> +#include <asm/bootinfo.h> +#include <asm/time.h> +#include <asm/prom.h> +#include <asm/smp-ops.h> +#include <asm/reboot.h> + +#define CR_AHB_RSTCR ((void __iomem *)CKSEG1ADDR(0x1fb00040)) +#define RESET BIT(31) + +#define UART_BASE CKSEG1ADDR(0x1fbf0003) +#define UART_REG_SHIFT 2 + +static void hw_reset(char *command) +{ + iowrite32(RESET, CR_AHB_RSTCR); +} + +/* 1. Bring up early printk. */ +void __init prom_init(void) +{ + setup_8250_early_printk_port(UART_BASE, UART_REG_SHIFT, 0); + _machine_restart = hw_reset; +} + +/* 2. Parse the DT and find memory */ +void __init plat_mem_setup(void) +{ + void *dtb; + + set_io_port_base(KSEG1); + + dtb = get_fdt(); + if (!dtb) + panic("no dtb found"); + + __dt_setup_arch(dtb); + + early_init_dt_scan_memory(); +} + +/* 3. Overload __weak device_tree_init(), add SMP_UP ops */ +void __init device_tree_init(void) +{ + unflatten_and_copy_device_tree(); + + register_up_smp_ops(); +} + +const char *get_system_type(void) +{ + return "EcoNet-EN75xx"; +} + +/* 4. Initialize the IRQ subsystem */ +void __init arch_init_irq(void) +{ + irqchip_init(); +} + +/* 5. Timers */ +void __init plat_time_init(void) +{ + of_clk_init(NULL); + timer_probe(); +} diff --git a/arch/mips/include/asm/mach-loongson2ef/cs5536/cs5536_pci.h b/arch/mips/include/asm/mach-loongson2ef/cs5536/cs5536_pci.h index a0d4b752899e..5dbc9b13d15b 100644 --- a/arch/mips/include/asm/mach-loongson2ef/cs5536/cs5536_pci.h +++ b/arch/mips/include/asm/mach-loongson2ef/cs5536/cs5536_pci.h @@ -12,12 +12,32 @@ #ifndef _CS5536_PCI_H #define _CS5536_PCI_H +#include <linux/init.h> #include <linux/types.h> #include <linux/pci_regs.h> extern void cs5536_pci_conf_write4(int function, int reg, u32 value); extern u32 cs5536_pci_conf_read4(int function, int reg); +extern void pci_ehci_write_reg(int reg, u32 value); +extern u32 pci_ehci_read_reg(int reg); + +extern void pci_ide_write_reg(int reg, u32 value); +extern u32 pci_ide_read_reg(int reg); + +extern void pci_acc_write_reg(int reg, u32 value); +extern u32 pci_acc_read_reg(int reg); + +extern void pci_ohci_write_reg(int reg, u32 value); +extern u32 pci_ohci_read_reg(int reg); + +extern void pci_isa_write_bar(int n, u32 value); +extern u32 pci_isa_read_bar(int n); +extern void pci_isa_write_reg(int reg, u32 value); +extern u32 pci_isa_read_reg(int reg); + +extern int __init init_mfgpt_clocksource(void); + #define CS5536_ACC_INTR 9 #define CS5536_IDE_INTR 14 #define CS5536_USB_INTR 11 diff --git a/arch/mips/include/asm/mach-loongson2ef/loongson.h b/arch/mips/include/asm/mach-loongson2ef/loongson.h index ca039b8dcde3..4a098fb10232 100644 --- a/arch/mips/include/asm/mach-loongson2ef/loongson.h +++ b/arch/mips/include/asm/mach-loongson2ef/loongson.h @@ -18,6 +18,9 @@ extern void bonito_irq_init(void); extern void mach_prepare_reboot(void); extern void mach_prepare_shutdown(void); +/* machine-specific PROM functions */ +extern void __init mach_prom_init_machtype(void); + /* environment arguments from bootloader */ extern u32 cpu_clock_freq; extern u32 memsize, highmemsize; @@ -45,6 +48,12 @@ extern void __init mach_init_irq(void); extern void mach_irq_dispatch(unsigned int pending); extern int mach_i8259_irq(void); +/* power management functions */ +extern void setup_wakeup_events(void); +extern int wakeup_loongson(void); +extern void __weak mach_suspend(void); +extern void __weak mach_resume(void); + /* We need this in some places... */ #define delay() ({ \ int x; \ diff --git a/arch/mips/include/asm/topology.h b/arch/mips/include/asm/topology.h index 0673d2d0f2e6..5158c802eb65 100644 --- a/arch/mips/include/asm/topology.h +++ b/arch/mips/include/asm/topology.h @@ -16,6 +16,9 @@ #define topology_core_id(cpu) (cpu_core(&cpu_data[cpu])) #define topology_core_cpumask(cpu) (&cpu_core_map[cpu]) #define topology_sibling_cpumask(cpu) (&cpu_sibling_map[cpu]) + +extern struct cpumask __cpu_primary_thread_mask; +#define cpu_primary_thread_mask ((const struct cpumask *)&__cpu_primary_thread_mask) #endif #endif /* __ASM_TOPOLOGY_H */ diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index ecf3278a32f7..95a1e674fd67 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile @@ -3,7 +3,7 @@ # Makefile for the Linux/MIPS kernel. # -extra-y := vmlinux.lds +always-$(KBUILD_BUILTIN) := vmlinux.lds obj-y += head.o branch.o cmpxchg.o elf.o entry.o genex.o idle.o irq.o \ process.o prom.o ptrace.o reset.o setup.o signal.o \ diff --git a/arch/mips/kernel/gpio_txx9.c b/arch/mips/kernel/gpio_txx9.c index 8c083612df9d..027fb57d0d79 100644 --- a/arch/mips/kernel/gpio_txx9.c +++ b/arch/mips/kernel/gpio_txx9.c @@ -32,14 +32,16 @@ static void txx9_gpio_set_raw(unsigned int offset, int value) __raw_writel(val, &txx9_pioptr->dout); } -static void txx9_gpio_set(struct gpio_chip *chip, unsigned int offset, - int value) +static int txx9_gpio_set(struct gpio_chip *chip, unsigned int offset, + int value) { unsigned long flags; spin_lock_irqsave(&txx9_gpio_lock, flags); txx9_gpio_set_raw(offset, value); mmiowb(); spin_unlock_irqrestore(&txx9_gpio_lock, flags); + + return 0; } static int txx9_gpio_dir_in(struct gpio_chip *chip, unsigned int offset) @@ -68,7 +70,7 @@ static int txx9_gpio_dir_out(struct gpio_chip *chip, unsigned int offset, static struct gpio_chip txx9_gpio_chip = { .get = txx9_gpio_get, - .set = txx9_gpio_set, + .set_rv = txx9_gpio_set, .direction_input = txx9_gpio_dir_in, .direction_output = txx9_gpio_dir_out, .label = "TXx9", diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c index f7107479c7fa..b890d64d352c 100644 --- a/arch/mips/kernel/ptrace.c +++ b/arch/mips/kernel/ptrace.c @@ -922,11 +922,13 @@ static const struct pt_regs_offset regoffset_table[] = { */ int regs_query_register_offset(const char *name) { - const struct pt_regs_offset *roff; - for (roff = regoffset_table; roff->name != NULL; roff++) - if (!strcmp(roff->name, name)) - return roff->offset; - return -EINVAL; + const struct pt_regs_offset *roff; + + for (roff = regoffset_table; roff->name != NULL; roff++) + if (!strcmp(roff->name, name)) + return roff->offset; + + return -EINVAL; } #if defined(CONFIG_32BIT) || defined(CONFIG_MIPS32_O32) @@ -937,7 +939,7 @@ static const struct user_regset mips_regsets[] = { .n = ELF_NGREG, .size = sizeof(unsigned int), .align = sizeof(unsigned int), - .regset_get = gpr32_get, + .regset_get = gpr32_get, .set = gpr32_set, }, [REGSET_DSP] = { @@ -945,7 +947,7 @@ static const struct user_regset mips_regsets[] = { .n = NUM_DSP_REGS + 1, .size = sizeof(u32), .align = sizeof(u32), - .regset_get = dsp32_get, + .regset_get = dsp32_get, .set = dsp32_set, .active = dsp_active, }, @@ -955,7 +957,7 @@ static const struct user_regset mips_regsets[] = { .n = ELF_NFPREG, .size = sizeof(elf_fpreg_t), .align = sizeof(elf_fpreg_t), - .regset_get = fpr_get, + .regset_get = fpr_get, .set = fpr_set, }, [REGSET_FP_MODE] = { @@ -963,7 +965,7 @@ static const struct user_regset mips_regsets[] = { .n = 1, .size = sizeof(int), .align = sizeof(int), - .regset_get = fp_mode_get, + .regset_get = fp_mode_get, .set = fp_mode_set, }, #endif @@ -973,7 +975,7 @@ static const struct user_regset mips_regsets[] = { .n = NUM_FPU_REGS + 1, .size = 16, .align = 16, - .regset_get = msa_get, + .regset_get = msa_get, .set = msa_set, }, #endif @@ -997,7 +999,7 @@ static const struct user_regset mips64_regsets[] = { .n = ELF_NGREG, .size = sizeof(unsigned long), .align = sizeof(unsigned long), - .regset_get = gpr64_get, + .regset_get = gpr64_get, .set = gpr64_set, }, [REGSET_DSP] = { @@ -1005,7 +1007,7 @@ static const struct user_regset mips64_regsets[] = { .n = NUM_DSP_REGS + 1, .size = sizeof(u64), .align = sizeof(u64), - .regset_get = dsp64_get, + .regset_get = dsp64_get, .set = dsp64_set, .active = dsp_active, }, @@ -1015,7 +1017,7 @@ static const struct user_regset mips64_regsets[] = { .n = 1, .size = sizeof(int), .align = sizeof(int), - .regset_get = fp_mode_get, + .regset_get = fp_mode_get, .set = fp_mode_set, }, [REGSET_FPR] = { @@ -1023,7 +1025,7 @@ static const struct user_regset mips64_regsets[] = { .n = ELF_NFPREG, .size = sizeof(elf_fpreg_t), .align = sizeof(elf_fpreg_t), - .regset_get = fpr_get, + .regset_get = fpr_get, .set = fpr_set, }, #endif @@ -1033,7 +1035,7 @@ static const struct user_regset mips64_regsets[] = { .n = NUM_FPU_REGS + 1, .size = 16, .align = 16, - .regset_get = msa_get, + .regset_get = msa_get, .set = msa_set, }, #endif @@ -1351,7 +1353,7 @@ asmlinkage long syscall_trace_enter(struct pt_regs *regs) */ asmlinkage void syscall_trace_leave(struct pt_regs *regs) { - /* + /* * We may come here right after calling schedule_user() * or do_notify_resume(), in which case we can be in RCU * user mode. diff --git a/arch/mips/kernel/smp-cps.c b/arch/mips/kernel/smp-cps.c index cc26d56f3ab6..7b0e69af4097 100644 --- a/arch/mips/kernel/smp-cps.c +++ b/arch/mips/kernel/smp-cps.c @@ -236,6 +236,7 @@ static void __init cps_smp_setup(void) /* Use the number of VPEs in cluster 0 core 0 for smp_num_siblings */ if (!cl && !c) smp_num_siblings = core_vpes; + cpumask_set_cpu(nvpes, &__cpu_primary_thread_mask); for (v = 0; v < min_t(int, core_vpes, NR_CPUS - nvpes); v++) { cpu_set_cluster(&cpu_data[nvpes + v], cl); @@ -368,6 +369,7 @@ static void __init cps_prepare_cpus(unsigned int max_cpus) cl = cpu_cluster(¤t_cpu_data); c = cpu_core(¤t_cpu_data); cluster_bootcfg = &mips_cps_cluster_bootcfg[cl]; + cpu_smt_set_num_threads(core_vpes, core_vpes); core_bootcfg = &cluster_bootcfg->core_config[c]; bitmap_set(cluster_bootcfg->core_power, cpu_core(¤t_cpu_data), 1); atomic_set(&core_bootcfg->vpe_mask, 1 << cpu_vpe_id(¤t_cpu_data)); diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c index 39e193cad2b9..4868e79f3b30 100644 --- a/arch/mips/kernel/smp.c +++ b/arch/mips/kernel/smp.c @@ -56,8 +56,10 @@ EXPORT_SYMBOL(cpu_sibling_map); cpumask_t cpu_core_map[NR_CPUS] __read_mostly; EXPORT_SYMBOL(cpu_core_map); +#ifndef CONFIG_HOTPLUG_PARALLEL static DECLARE_COMPLETION(cpu_starting); static DECLARE_COMPLETION(cpu_running); +#endif /* * A logical cpu mask containing only one VPE per core to @@ -74,6 +76,8 @@ static cpumask_t cpu_core_setup_map; cpumask_t cpu_coherent_mask; +struct cpumask __cpu_primary_thread_mask __read_mostly; + unsigned int smp_max_threads __initdata = UINT_MAX; static int __init early_nosmt(char *s) @@ -367,6 +371,9 @@ asmlinkage void start_secondary(void) * to an option instead of something based on .cputype */ +#ifdef CONFIG_HOTPLUG_PARALLEL + cpuhp_ap_sync_alive(); +#endif calibrate_delay(); cpu_data[cpu].udelay_val = loops_per_jiffy; @@ -376,8 +383,10 @@ asmlinkage void start_secondary(void) cpumask_set_cpu(cpu, &cpu_coherent_mask); notify_cpu_starting(cpu); +#ifndef CONFIG_HOTPLUG_PARALLEL /* Notify boot CPU that we're starting & ready to sync counters */ complete(&cpu_starting); +#endif synchronise_count_slave(cpu); @@ -386,11 +395,13 @@ asmlinkage void start_secondary(void) calculate_cpu_foreign_map(); +#ifndef CONFIG_HOTPLUG_PARALLEL /* * Notify boot CPU that we're up & online and it can safely return * from __cpu_up */ complete(&cpu_running); +#endif /* * irq will be enabled in ->smp_finish(), enabling it too early @@ -447,6 +458,12 @@ void __init smp_prepare_boot_cpu(void) set_cpu_online(0, true); } +#ifdef CONFIG_HOTPLUG_PARALLEL +int arch_cpuhp_kick_ap_alive(unsigned int cpu, struct task_struct *tidle) +{ + return mp_ops->boot_secondary(cpu, tidle); +} +#else int __cpu_up(unsigned int cpu, struct task_struct *tidle) { int err; @@ -466,6 +483,7 @@ int __cpu_up(unsigned int cpu, struct task_struct *tidle) wait_for_completion(&cpu_running); return 0; } +#endif #ifdef CONFIG_PROFILING /* Not really SMP stuff ... */ diff --git a/arch/mips/kernel/vpe.c b/arch/mips/kernel/vpe.c index 737d0d4fdcd3..2b67c44adab9 100644 --- a/arch/mips/kernel/vpe.c +++ b/arch/mips/kernel/vpe.c @@ -22,6 +22,7 @@ #include <linux/vmalloc.h> #include <linux/elf.h> #include <linux/seq_file.h> +#include <linux/string.h> #include <linux/syscalls.h> #include <linux/moduleloader.h> #include <linux/interrupt.h> @@ -582,7 +583,7 @@ static int vpe_elfload(struct vpe *v) struct module mod; /* so we can re-use the relocations code */ memset(&mod, 0, sizeof(struct module)); - strcpy(mod.name, "VPE loader"); + strscpy(mod.name, "VPE loader"); hdr = (Elf_Ehdr *) v->pbuffer; len = v->plen; diff --git a/arch/mips/rb532/gpio.c b/arch/mips/rb532/gpio.c index ea6ebfea4a67..0e47cd59b6cb 100644 --- a/arch/mips/rb532/gpio.c +++ b/arch/mips/rb532/gpio.c @@ -105,13 +105,15 @@ static int rb532_gpio_get(struct gpio_chip *chip, unsigned offset) /* * Set output GPIO level */ -static void rb532_gpio_set(struct gpio_chip *chip, - unsigned offset, int value) +static int rb532_gpio_set(struct gpio_chip *chip, unsigned int offset, + int value) { struct rb532_gpio_chip *gpch; gpch = gpiochip_get_data(chip); rb532_set_bit(value, offset, gpch->regbase + GPIOD); + + return 0; } /* @@ -162,7 +164,7 @@ static struct rb532_gpio_chip rb532_gpio_chip[] = { .direction_input = rb532_gpio_direction_input, .direction_output = rb532_gpio_direction_output, .get = rb532_gpio_get, - .set = rb532_gpio_set, + .set_rv = rb532_gpio_set, .to_irq = rb532_gpio_to_irq, .base = 0, .ngpio = 32, diff --git a/arch/mips/txx9/generic/setup.c b/arch/mips/txx9/generic/setup.c index 1e67fecd466e..0586ca7668b4 100644 --- a/arch/mips/txx9/generic/setup.c +++ b/arch/mips/txx9/generic/setup.c @@ -603,8 +603,8 @@ static int txx9_iocled_get(struct gpio_chip *chip, unsigned int offset) return !!(data->cur_val & (1 << offset)); } -static void txx9_iocled_set(struct gpio_chip *chip, unsigned int offset, - int value) +static int txx9_iocled_set(struct gpio_chip *chip, unsigned int offset, + int value) { struct txx9_iocled_data *data = gpiochip_get_data(chip); unsigned long flags; @@ -616,6 +616,8 @@ static void txx9_iocled_set(struct gpio_chip *chip, unsigned int offset, writeb(data->cur_val, data->mmioaddr); mmiowb(); spin_unlock_irqrestore(&txx9_iocled_lock, flags); + + return 0; } static int txx9_iocled_dir_in(struct gpio_chip *chip, unsigned int offset) @@ -653,7 +655,7 @@ void __init txx9_iocled_init(unsigned long baseaddr, if (!iocled->mmioaddr) goto out_free; iocled->chip.get = txx9_iocled_get; - iocled->chip.set = txx9_iocled_set; + iocled->chip.set_rv = txx9_iocled_set; iocled->chip.direction_input = txx9_iocled_dir_in; iocled->chip.direction_output = txx9_iocled_dir_out; iocled->chip.label = "iocled"; diff --git a/arch/mips/vdso/Makefile b/arch/mips/vdso/Makefile index fb4c493aaffa..69d4593f64fe 100644 --- a/arch/mips/vdso/Makefile +++ b/arch/mips/vdso/Makefile @@ -27,6 +27,7 @@ endif # offsets. cflags-vdso := $(ccflags-vdso) \ $(filter -W%,$(filter-out -Wa$(comma)%,$(KBUILD_CFLAGS))) \ + $(filter -std=%,$(KBUILD_CFLAGS)) \ -O3 -g -fPIC -fno-strict-aliasing -fno-common -fno-builtin -G 0 \ -mrelax-pic-calls $(call cc-option, -mexplicit-relocs) \ -fno-stack-protector -fno-jump-tables -DDISABLE_BRANCH_PROFILING \ diff --git a/arch/nios2/kernel/Makefile b/arch/nios2/kernel/Makefile index 78a913181fa1..4dce965a7b73 100644 --- a/arch/nios2/kernel/Makefile +++ b/arch/nios2/kernel/Makefile @@ -3,7 +3,7 @@ # Makefile for the nios2 linux kernel. # -extra-y += vmlinux.lds +always-$(KBUILD_BUILTIN) += vmlinux.lds obj-y += head.o obj-y += cpuinfo.o diff --git a/arch/openrisc/kernel/Makefile b/arch/openrisc/kernel/Makefile index e4c7d9bdd598..58e6a1b525b7 100644 --- a/arch/openrisc/kernel/Makefile +++ b/arch/openrisc/kernel/Makefile @@ -3,7 +3,7 @@ # Makefile for the linux kernel. # -extra-y := vmlinux.lds +always-$(KBUILD_BUILTIN) := vmlinux.lds obj-y := head.o setup.o or32_ksyms.o process.o dma.o \ traps.o time.o irq.o entry.o ptrace.o signal.o \ diff --git a/arch/parisc/kernel/Makefile b/arch/parisc/kernel/Makefile index 5ab0467be70a..d5055ba33722 100644 --- a/arch/parisc/kernel/Makefile +++ b/arch/parisc/kernel/Makefile @@ -3,7 +3,7 @@ # Makefile for arch/parisc/kernel # -extra-y := vmlinux.lds +always-$(KBUILD_BUILTIN) := vmlinux.lds obj-y := head.o cache.o pacache.o setup.o pdt.o traps.o time.o irq.o \ syscall.o entry.o sys_parisc.o firmware.o \ diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index 9d1ab3971694..fb2b95267022 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -126,7 +126,7 @@ obj-$(CONFIG_PPC_BOOK3S_32) += head_book3s_32.o obj-$(CONFIG_44x) += head_44x.o obj-$(CONFIG_PPC_8xx) += head_8xx.o obj-$(CONFIG_PPC_85xx) += head_85xx.o -extra-y += vmlinux.lds +always-$(KBUILD_BUILTIN) += vmlinux.lds obj-$(CONFIG_RELOCATABLE) += reloc_$(BITS).o diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c index 791d1942a058..3401b96be475 100644 --- a/arch/powerpc/kvm/booke.c +++ b/arch/powerpc/kvm/booke.c @@ -628,7 +628,7 @@ static void arm_next_watchdog(struct kvm_vcpu *vcpu) static void kvmppc_watchdog_func(struct timer_list *t) { - struct kvm_vcpu *vcpu = from_timer(vcpu, t, arch.wdt_timer); + struct kvm_vcpu *vcpu = timer_container_of(vcpu, t, arch.wdt_timer); u32 tsr, new_tsr; int final; diff --git a/arch/powerpc/platforms/powermac/low_i2c.c b/arch/powerpc/platforms/powermac/low_i2c.c index a0ae58636e10..02474e27df9b 100644 --- a/arch/powerpc/platforms/powermac/low_i2c.c +++ b/arch/powerpc/platforms/powermac/low_i2c.c @@ -359,7 +359,8 @@ static irqreturn_t kw_i2c_irq(int irq, void *dev_id) static void kw_i2c_timeout(struct timer_list *t) { - struct pmac_i2c_host_kw *host = from_timer(host, t, timeout_timer); + struct pmac_i2c_host_kw *host = timer_container_of(host, t, + timeout_timer); unsigned long flags; spin_lock_irqsave(&host->lock, flags); diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index bbec87b79309..36061f4732b7 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -70,6 +70,7 @@ config RISCV # LLD >= 14: https://github.com/llvm/llvm-project/issues/50505 select ARCH_SUPPORTS_LTO_CLANG if LLD_VERSION >= 140000 select ARCH_SUPPORTS_LTO_CLANG_THIN if LLD_VERSION >= 140000 + select ARCH_SUPPORTS_MSEAL_SYSTEM_MAPPINGS if 64BIT && MMU select ARCH_SUPPORTS_PAGE_TABLE_CHECK if MMU select ARCH_SUPPORTS_PER_VMA_LOCK if MMU select ARCH_SUPPORTS_RT @@ -99,6 +100,7 @@ config RISCV select EDAC_SUPPORT select FRAME_POINTER if PERF_EVENTS || (FUNCTION_TRACER && !DYNAMIC_FTRACE) select FTRACE_MCOUNT_USE_PATCHABLE_FUNCTION_ENTRY if DYNAMIC_FTRACE + select FUNCTION_ALIGNMENT_8B if DYNAMIC_FTRACE_WITH_CALL_OPS select GENERIC_ARCH_TOPOLOGY select GENERIC_ATOMIC64 if !64BIT select GENERIC_CLOCKEVENTS_BROADCAST if SMP @@ -143,6 +145,7 @@ config RISCV select HAVE_ARCH_THREAD_STRUCT_WHITELIST select HAVE_ARCH_TRACEHOOK select HAVE_ARCH_TRANSPARENT_HUGEPAGE if 64BIT && MMU + select HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD if 64BIT && MMU select HAVE_ARCH_USERFAULTFD_MINOR if 64BIT && USERFAULTFD select HAVE_ARCH_VMAP_STACK if MMU && 64BIT select HAVE_ASM_MODVERSIONS @@ -150,13 +153,15 @@ config RISCV select HAVE_DEBUG_KMEMLEAK select HAVE_DMA_CONTIGUOUS if MMU select HAVE_DYNAMIC_FTRACE if !XIP_KERNEL && MMU && (CLANG_SUPPORTS_DYNAMIC_FTRACE || GCC_SUPPORTS_DYNAMIC_FTRACE) - select HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS + select FUNCTION_ALIGNMENT_4B if HAVE_DYNAMIC_FTRACE && RISCV_ISA_C + select HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS if HAVE_DYNAMIC_FTRACE_WITH_CALL_OPS + select HAVE_DYNAMIC_FTRACE_WITH_CALL_OPS if (DYNAMIC_FTRACE_WITH_ARGS && !CFI_CLANG) select HAVE_DYNAMIC_FTRACE_WITH_ARGS if HAVE_DYNAMIC_FTRACE select HAVE_FTRACE_GRAPH_FUNC select HAVE_FTRACE_MCOUNT_RECORD if !XIP_KERNEL select HAVE_FUNCTION_GRAPH_TRACER if HAVE_DYNAMIC_FTRACE_WITH_ARGS select HAVE_FUNCTION_GRAPH_FREGS - select HAVE_FUNCTION_TRACER if !XIP_KERNEL && !PREEMPTION + select HAVE_FUNCTION_TRACER if !XIP_KERNEL select HAVE_EBPF_JIT if MMU select HAVE_GUP_FAST if MMU select HAVE_FUNCTION_ARG_ACCESS_API @@ -218,6 +223,7 @@ config RISCV select THREAD_INFO_IN_TASK select TRACE_IRQFLAGS_SUPPORT select UACCESS_MEMCPY if !MMU + select VDSO_GETRANDOM if HAVE_GENERIC_VDSO select USER_STACKTRACE_SUPPORT select ZONE_DMA32 if 64BIT @@ -236,6 +242,7 @@ config CLANG_SUPPORTS_DYNAMIC_FTRACE config GCC_SUPPORTS_DYNAMIC_FTRACE def_bool CC_IS_GCC depends on $(cc-option,-fpatchable-function-entry=8) + depends on CC_HAS_MIN_FUNCTION_ALIGNMENT || !RISCV_ISA_C config HAVE_SHADOW_CALL_STACK def_bool $(cc-option,-fsanitize=shadow-call-stack) @@ -664,12 +671,12 @@ config RISCV_ISA_V_PREEMPTIVE default y help Usually, in-kernel SIMD routines are run with preemption disabled. - Functions which envoke long running SIMD thus must yield core's + Functions which invoke long running SIMD thus must yield the core's vector unit to prevent blocking other tasks for too long. - This config allows kernel to run SIMD without explicitly disable - preemption. Enabling this config will result in higher memory - consumption due to the allocation of per-task's kernel Vector context. + This config allows the kernel to run SIMD without explicitly disabling + preemption. Enabling this config will result in higher memory consumption + due to the allocation of per-task's kernel Vector context. config RISCV_ISA_ZAWRS bool "Zawrs extension support for more efficient busy waiting" @@ -842,6 +849,21 @@ config RISCV_ISA_ZICBOZ If you don't know what to do here, say Y. +config RISCV_ISA_ZICBOP + bool "Zicbop extension support for cache block prefetch" + depends on MMU + depends on RISCV_ALTERNATIVE + default y + help + Adds support to dynamically detect the presence of the ZICBOP + extension (Cache Block Prefetch Operations) and enable its + usage. + + The Zicbop extension can be used to prefetch cache blocks for + read/write fetch. + + If you don't know what to do here, say Y. + config TOOLCHAIN_NEEDS_EXPLICIT_ZICSR_ZIFENCEI def_bool y # https://sourceware.org/git/?p=binutils-gdb.git;a=commit;h=aed44286efa8ae8717a77d94b51ac3614e2ca6dc @@ -1171,8 +1193,8 @@ config CMDLINE_FALLBACK config CMDLINE_EXTEND bool "Extend bootloader kernel arguments" help - The command-line arguments provided during boot will be - appended to the built-in command line. This is useful in + The built-in command line will be appended to the command- + line arguments provided during boot. This is useful in cases where the provided arguments are insufficient and you don't want to or cannot modify them. diff --git a/arch/riscv/Kconfig.vendor b/arch/riscv/Kconfig.vendor index b096548fe0ff..e14f26368963 100644 --- a/arch/riscv/Kconfig.vendor +++ b/arch/riscv/Kconfig.vendor @@ -16,6 +16,19 @@ config RISCV_ISA_VENDOR_EXT_ANDES If you don't know what to do here, say Y. endmenu +menu "SiFive" +config RISCV_ISA_VENDOR_EXT_SIFIVE + bool "SiFive vendor extension support" + select RISCV_ISA_VENDOR_EXT + default y + help + Say N here if you want to disable all SiFive vendor extension + support. This will cause any SiFive vendor extensions that are + requested by hardware probing to be ignored. + + If you don't know what to do here, say Y. +endmenu + menu "T-Head" config RISCV_ISA_VENDOR_EXT_THEAD bool "T-Head vendor extension support" diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile index 539d2aef5cab..df57654a615e 100644 --- a/arch/riscv/Makefile +++ b/arch/riscv/Makefile @@ -15,9 +15,9 @@ ifeq ($(CONFIG_DYNAMIC_FTRACE),y) LDFLAGS_vmlinux += --no-relax KBUILD_CPPFLAGS += -DCC_USING_PATCHABLE_FUNCTION_ENTRY ifeq ($(CONFIG_RISCV_ISA_C),y) - CC_FLAGS_FTRACE := -fpatchable-function-entry=4 + CC_FLAGS_FTRACE := -fpatchable-function-entry=8,4 else - CC_FLAGS_FTRACE := -fpatchable-function-entry=2 + CC_FLAGS_FTRACE := -fpatchable-function-entry=4,2 endif endif diff --git a/arch/riscv/configs/defconfig b/arch/riscv/configs/defconfig index eea825ee58e1..fe8bd8afb418 100644 --- a/arch/riscv/configs/defconfig +++ b/arch/riscv/configs/defconfig @@ -18,12 +18,9 @@ CONFIG_CGROUP_DEVICE=y CONFIG_CGROUP_CPUACCT=y CONFIG_CGROUP_PERF=y CONFIG_CGROUP_BPF=y -CONFIG_NAMESPACES=y CONFIG_USER_NS=y CONFIG_CHECKPOINT_RESTORE=y CONFIG_BLK_DEV_INITRD=y -CONFIG_EXPERT=y -# CONFIG_SYSFS_SYSCALL is not set CONFIG_PROFILING=y CONFIG_ARCH_MICROCHIP=y CONFIG_ARCH_SIFIVE=y @@ -182,6 +179,7 @@ CONFIG_REGULATOR_FIXED_VOLTAGE=y CONFIG_REGULATOR_AXP20X=y CONFIG_REGULATOR_GPIO=y CONFIG_MEDIA_SUPPORT=m +CONFIG_MEDIA_PLATFORM_SUPPORT=y CONFIG_VIDEO_CADENCE_CSI2RX=m CONFIG_DRM=m CONFIG_DRM_RADEON=m @@ -297,25 +295,7 @@ CONFIG_DEFAULT_SECURITY_DAC=y CONFIG_CRYPTO_USER_API_HASH=y CONFIG_CRYPTO_DEV_VIRTIO=y CONFIG_PRINTK_TIME=y +CONFIG_DEBUG_KERNEL=y CONFIG_DEBUG_FS=y -CONFIG_DEBUG_PAGEALLOC=y -CONFIG_SCHED_STACK_END_CHECK=y -CONFIG_DEBUG_VM=y -CONFIG_DEBUG_VM_PGFLAGS=y -CONFIG_DEBUG_MEMORY_INIT=y -CONFIG_DEBUG_PER_CPU_MAPS=y -CONFIG_SOFTLOCKUP_DETECTOR=y -CONFIG_WQ_WATCHDOG=y -CONFIG_DEBUG_RT_MUTEXES=y -CONFIG_DEBUG_SPINLOCK=y -CONFIG_DEBUG_MUTEXES=y -CONFIG_DEBUG_RWSEMS=y -CONFIG_DEBUG_ATOMIC_SLEEP=y -CONFIG_DEBUG_LIST=y -CONFIG_DEBUG_PLIST=y -CONFIG_DEBUG_SG=y -# CONFIG_RCU_TRACE is not set -CONFIG_RCU_EQS_DEBUG=y -# CONFIG_FTRACE is not set # CONFIG_RUNTIME_TESTING_MENU is not set CONFIG_MEMTEST=y diff --git a/arch/riscv/include/asm/asm-prototypes.h b/arch/riscv/include/asm/asm-prototypes.h index bfc8ea5f9319..a9988bf21ec8 100644 --- a/arch/riscv/include/asm/asm-prototypes.h +++ b/arch/riscv/include/asm/asm-prototypes.h @@ -12,7 +12,7 @@ long long __ashlti3(long long a, int b); #ifdef CONFIG_RISCV_ISA_V #ifdef CONFIG_MMU -asmlinkage int enter_vector_usercopy(void *dst, void *src, size_t n); +asmlinkage int enter_vector_usercopy(void *dst, void *src, size_t n, bool enable_sum); #endif /* CONFIG_MMU */ void xor_regs_2_(unsigned long bytes, unsigned long *__restrict p1, diff --git a/arch/riscv/include/asm/barrier.h b/arch/riscv/include/asm/barrier.h index e1d9bf1deca6..b8c5726d86ac 100644 --- a/arch/riscv/include/asm/barrier.h +++ b/arch/riscv/include/asm/barrier.h @@ -14,11 +14,6 @@ #include <asm/cmpxchg.h> #include <asm/fence.h> -#define nop() __asm__ __volatile__ ("nop") -#define __nops(n) ".rept " #n "\nnop\n.endr\n" -#define nops(n) __asm__ __volatile__ (__nops(n)) - - /* These barriers need to enforce ordering on both devices or memory. */ #define __mb() RISCV_FENCE(iorw, iorw) #define __rmb() RISCV_FENCE(ir, ir) diff --git a/arch/riscv/include/asm/cacheflush.h b/arch/riscv/include/asm/cacheflush.h index b59ffeb668d6..6086b38d5427 100644 --- a/arch/riscv/include/asm/cacheflush.h +++ b/arch/riscv/include/asm/cacheflush.h @@ -85,6 +85,7 @@ static inline void flush_icache_range(unsigned long start, unsigned long end) extern unsigned int riscv_cbom_block_size; extern unsigned int riscv_cboz_block_size; +extern unsigned int riscv_cbop_block_size; void riscv_init_cbo_blocksizes(void); #ifdef CONFIG_RISCV_DMA_NONCOHERENT diff --git a/arch/riscv/include/asm/cmpxchg.h b/arch/riscv/include/asm/cmpxchg.h index 2ec119eb147b..0b749e710216 100644 --- a/arch/riscv/include/asm/cmpxchg.h +++ b/arch/riscv/include/asm/cmpxchg.h @@ -13,6 +13,7 @@ #include <asm/hwcap.h> #include <asm/insn-def.h> #include <asm/cpufeature-macros.h> +#include <asm/processor.h> #define __arch_xchg_masked(sc_sfx, swap_sfx, prepend, sc_append, \ swap_append, r, p, n) \ @@ -37,6 +38,7 @@ \ __asm__ __volatile__ ( \ prepend \ + PREFETCHW_ASM(%5) \ "0: lr.w %0, %2\n" \ " and %1, %0, %z4\n" \ " or %1, %1, %z3\n" \ @@ -44,7 +46,7 @@ " bnez %1, 0b\n" \ sc_append \ : "=&r" (__retx), "=&r" (__rc), "+A" (*(__ptr32b)) \ - : "rJ" (__newx), "rJ" (~__mask) \ + : "rJ" (__newx), "rJ" (~__mask), "rJ" (__ptr32b) \ : "memory"); \ \ r = (__typeof__(*(p)))((__retx & __mask) >> __s); \ diff --git a/arch/riscv/include/asm/cpufeature.h b/arch/riscv/include/asm/cpufeature.h index f56b409361fb..fbd0e4306c93 100644 --- a/arch/riscv/include/asm/cpufeature.h +++ b/arch/riscv/include/asm/cpufeature.h @@ -67,11 +67,11 @@ void __init riscv_user_isa_enable(void); _RISCV_ISA_EXT_DATA(_name, _id, _sub_exts, ARRAY_SIZE(_sub_exts), _validate) bool __init check_unaligned_access_emulated_all_cpus(void); +void unaligned_access_init(void); +int cpu_online_unaligned_access_init(unsigned int cpu); #if defined(CONFIG_RISCV_SCALAR_MISALIGNED) -void check_unaligned_access_emulated(struct work_struct *work __always_unused); void unaligned_emulation_finish(void); bool unaligned_ctl_available(void); -DECLARE_PER_CPU(long, misaligned_access_speed); #else static inline bool unaligned_ctl_available(void) { @@ -79,6 +79,16 @@ static inline bool unaligned_ctl_available(void) } #endif +#if defined(CONFIG_RISCV_MISALIGNED) +DECLARE_PER_CPU(long, misaligned_access_speed); +bool misaligned_traps_can_delegate(void); +#else +static inline bool misaligned_traps_can_delegate(void) +{ + return false; +} +#endif + bool __init check_vector_unaligned_access_emulated_all_cpus(void); #if defined(CONFIG_RISCV_VECTOR_MISALIGNED) void check_vector_unaligned_access_emulated(struct work_struct *work __always_unused); diff --git a/arch/riscv/include/asm/ftrace.h b/arch/riscv/include/asm/ftrace.h index d627f63ee289..22ebea3c2b26 100644 --- a/arch/riscv/include/asm/ftrace.h +++ b/arch/riscv/include/asm/ftrace.h @@ -20,10 +20,9 @@ extern void *return_address(unsigned int level); #define ftrace_return_address(n) return_address(n) void _mcount(void); -static inline unsigned long ftrace_call_adjust(unsigned long addr) -{ - return addr; -} +unsigned long ftrace_call_adjust(unsigned long addr); +unsigned long arch_ftrace_get_symaddr(unsigned long fentry_ip); +#define ftrace_get_symaddr(fentry_ip) arch_ftrace_get_symaddr(fentry_ip) /* * Let's do like x86/arm64 and ignore the compat syscalls. @@ -57,12 +56,21 @@ struct dyn_arch_ftrace { * 2) jalr: setting low-12 offset to ra, jump to ra, and set ra to * return address (original pc + 4) * + * The first 2 instructions for each tracable function is compiled to 2 nop + * instructions. Then, the kernel initializes the first instruction to auipc at + * boot time (<ftrace disable>). The second instruction is patched to jalr to + * start the trace. + * + *<Image>: + * 0: nop + * 4: nop + * *<ftrace enable>: - * 0: auipc t0/ra, 0x? - * 4: jalr t0/ra, ?(t0/ra) + * 0: auipc t0, 0x? + * 4: jalr t0, ?(t0) * *<ftrace disable>: - * 0: nop + * 0: auipc t0, 0x? * 4: nop * * Dynamic ftrace generates probes to call sites, so we must deal with @@ -75,10 +83,9 @@ struct dyn_arch_ftrace { #define AUIPC_OFFSET_MASK (0xfffff000) #define AUIPC_PAD (0x00001000) #define JALR_SHIFT 20 -#define JALR_RA (0x000080e7) -#define AUIPC_RA (0x00000097) #define JALR_T0 (0x000282e7) #define AUIPC_T0 (0x00000297) +#define JALR_RANGE (JALR_SIGN_MASK - 1) #define to_jalr_t0(offset) \ (((offset & JALR_OFFSET_MASK) << JALR_SHIFT) | JALR_T0) @@ -96,26 +103,14 @@ do { \ call[1] = to_jalr_t0(offset); \ } while (0) -#define to_jalr_ra(offset) \ - (((offset & JALR_OFFSET_MASK) << JALR_SHIFT) | JALR_RA) - -#define to_auipc_ra(offset) \ - ((offset & JALR_SIGN_MASK) ? \ - (((offset & AUIPC_OFFSET_MASK) + AUIPC_PAD) | AUIPC_RA) : \ - ((offset & AUIPC_OFFSET_MASK) | AUIPC_RA)) - -#define make_call_ra(caller, callee, call) \ -do { \ - unsigned int offset = \ - (unsigned long) (callee) - (unsigned long) (caller); \ - call[0] = to_auipc_ra(offset); \ - call[1] = to_jalr_ra(offset); \ -} while (0) - /* - * Let auipc+jalr be the basic *mcount unit*, so we make it 8 bytes here. + * Only the jalr insn in the auipc+jalr is patched, so we make it 4 + * bytes here. */ -#define MCOUNT_INSN_SIZE 8 +#define MCOUNT_INSN_SIZE 4 +#define MCOUNT_AUIPC_SIZE 4 +#define MCOUNT_JALR_SIZE 4 +#define MCOUNT_NOP4_SIZE 4 #ifndef __ASSEMBLY__ struct dyn_ftrace; @@ -135,6 +130,9 @@ struct __arch_ftrace_regs { unsigned long sp; unsigned long s0; unsigned long t1; +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS + unsigned long direct_tramp; +#endif union { unsigned long args[8]; struct { @@ -146,6 +144,13 @@ struct __arch_ftrace_regs { unsigned long a5; unsigned long a6; unsigned long a7; +#ifdef CONFIG_CC_IS_CLANG + unsigned long t2; + unsigned long t3; + unsigned long t4; + unsigned long t5; + unsigned long t6; +#endif }; }; }; @@ -221,10 +226,13 @@ void ftrace_graph_func(unsigned long ip, unsigned long parent_ip, struct ftrace_ops *op, struct ftrace_regs *fregs); #define ftrace_graph_func ftrace_graph_func +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS static inline void arch_ftrace_set_direct_caller(struct ftrace_regs *fregs, unsigned long addr) { arch_ftrace_regs(fregs)->t1 = addr; } +#endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */ + #endif /* CONFIG_DYNAMIC_FTRACE_WITH_ARGS */ #endif /* __ASSEMBLY__ */ diff --git a/arch/riscv/include/asm/hwcap.h b/arch/riscv/include/asm/hwcap.h index e3cbf203cdde..affd63e11b0a 100644 --- a/arch/riscv/include/asm/hwcap.h +++ b/arch/riscv/include/asm/hwcap.h @@ -105,6 +105,7 @@ #define RISCV_ISA_EXT_ZVFBFWMA 96 #define RISCV_ISA_EXT_ZAAMO 97 #define RISCV_ISA_EXT_ZALRSC 98 +#define RISCV_ISA_EXT_ZICBOP 99 #define RISCV_ISA_EXT_XLINUXENVCFG 127 diff --git a/arch/riscv/include/asm/hwprobe.h b/arch/riscv/include/asm/hwprobe.h index 1f690fea0e03..7fe0a379474a 100644 --- a/arch/riscv/include/asm/hwprobe.h +++ b/arch/riscv/include/asm/hwprobe.h @@ -8,7 +8,7 @@ #include <uapi/asm/hwprobe.h> -#define RISCV_HWPROBE_MAX_KEY 12 +#define RISCV_HWPROBE_MAX_KEY 13 static inline bool riscv_hwprobe_key_is_valid(__s64 key) { @@ -22,6 +22,7 @@ static inline bool hwprobe_key_is_bitmask(__s64 key) case RISCV_HWPROBE_KEY_IMA_EXT_0: case RISCV_HWPROBE_KEY_CPUPERF_0: case RISCV_HWPROBE_KEY_VENDOR_EXT_THEAD_0: + case RISCV_HWPROBE_KEY_VENDOR_EXT_SIFIVE_0: return true; } diff --git a/arch/riscv/include/asm/image.h b/arch/riscv/include/asm/image.h index e0b319af3681..8927a6ea1127 100644 --- a/arch/riscv/include/asm/image.h +++ b/arch/riscv/include/asm/image.h @@ -30,6 +30,8 @@ RISCV_HEADER_VERSION_MINOR) #ifndef __ASSEMBLY__ +#define riscv_image_flag_field(flags, field)\ + (((flags) >> field##_SHIFT) & field##_MASK) /** * struct riscv_image_header - riscv kernel image header * @code0: Executable code diff --git a/arch/riscv/include/asm/insn-def.h b/arch/riscv/include/asm/insn-def.h index 71060a2f838e..d5adbaec1d01 100644 --- a/arch/riscv/include/asm/insn-def.h +++ b/arch/riscv/include/asm/insn-def.h @@ -18,6 +18,13 @@ #define INSN_I_RD_SHIFT 7 #define INSN_I_OPCODE_SHIFT 0 +#define INSN_S_SIMM7_SHIFT 25 +#define INSN_S_RS2_SHIFT 20 +#define INSN_S_RS1_SHIFT 15 +#define INSN_S_FUNC3_SHIFT 12 +#define INSN_S_SIMM5_SHIFT 7 +#define INSN_S_OPCODE_SHIFT 0 + #ifdef __ASSEMBLY__ #ifdef CONFIG_AS_HAS_INSN @@ -30,6 +37,10 @@ .insn i \opcode, \func3, \rd, \rs1, \simm12 .endm + .macro insn_s, opcode, func3, rs2, simm12, rs1 + .insn s \opcode, \func3, \rs2, \simm12(\rs1) + .endm + #else #include <asm/gpr-num.h> @@ -51,10 +62,20 @@ (\simm12 << INSN_I_SIMM12_SHIFT)) .endm + .macro insn_s, opcode, func3, rs2, simm12, rs1 + .4byte ((\opcode << INSN_S_OPCODE_SHIFT) | \ + (\func3 << INSN_S_FUNC3_SHIFT) | \ + (.L__gpr_num_\rs2 << INSN_S_RS2_SHIFT) | \ + (.L__gpr_num_\rs1 << INSN_S_RS1_SHIFT) | \ + ((\simm12 & 0x1f) << INSN_S_SIMM5_SHIFT) | \ + (((\simm12 >> 5) & 0x7f) << INSN_S_SIMM7_SHIFT)) + .endm + #endif #define __INSN_R(...) insn_r __VA_ARGS__ #define __INSN_I(...) insn_i __VA_ARGS__ +#define __INSN_S(...) insn_s __VA_ARGS__ #else /* ! __ASSEMBLY__ */ @@ -66,6 +87,9 @@ #define __INSN_I(opcode, func3, rd, rs1, simm12) \ ".insn i " opcode ", " func3 ", " rd ", " rs1 ", " simm12 "\n" +#define __INSN_S(opcode, func3, rs2, simm12, rs1) \ + ".insn s " opcode ", " func3 ", " rs2 ", " simm12 "(" rs1 ")\n" + #else #include <linux/stringify.h> @@ -92,12 +116,26 @@ " (\\simm12 << " __stringify(INSN_I_SIMM12_SHIFT) "))\n" \ " .endm\n" +#define DEFINE_INSN_S \ + __DEFINE_ASM_GPR_NUMS \ +" .macro insn_s, opcode, func3, rs2, simm12, rs1\n" \ +" .4byte ((\\opcode << " __stringify(INSN_S_OPCODE_SHIFT) ") |" \ +" (\\func3 << " __stringify(INSN_S_FUNC3_SHIFT) ") |" \ +" (.L__gpr_num_\\rs2 << " __stringify(INSN_S_RS2_SHIFT) ") |" \ +" (.L__gpr_num_\\rs1 << " __stringify(INSN_S_RS1_SHIFT) ") |" \ +" ((\\simm12 & 0x1f) << " __stringify(INSN_S_SIMM5_SHIFT) ") |" \ +" (((\\simm12 >> 5) & 0x7f) << " __stringify(INSN_S_SIMM7_SHIFT) "))\n" \ +" .endm\n" + #define UNDEFINE_INSN_R \ " .purgem insn_r\n" #define UNDEFINE_INSN_I \ " .purgem insn_i\n" +#define UNDEFINE_INSN_S \ +" .purgem insn_s\n" + #define __INSN_R(opcode, func3, func7, rd, rs1, rs2) \ DEFINE_INSN_R \ "insn_r " opcode ", " func3 ", " func7 ", " rd ", " rs1 ", " rs2 "\n" \ @@ -108,6 +146,11 @@ "insn_i " opcode ", " func3 ", " rd ", " rs1 ", " simm12 "\n" \ UNDEFINE_INSN_I +#define __INSN_S(opcode, func3, rs2, simm12, rs1) \ + DEFINE_INSN_S \ + "insn_s " opcode ", " func3 ", " rs2 ", " simm12 ", " rs1 "\n" \ + UNDEFINE_INSN_S + #endif #endif /* ! __ASSEMBLY__ */ @@ -120,6 +163,10 @@ __INSN_I(RV_##opcode, RV_##func3, RV_##rd, \ RV_##rs1, RV_##simm12) +#define INSN_S(opcode, func3, rs2, simm12, rs1) \ + __INSN_S(RV_##opcode, RV_##func3, RV_##rs2, \ + RV_##simm12, RV_##rs1) + #define RV_OPCODE(v) __ASM_STR(v) #define RV_FUNC3(v) __ASM_STR(v) #define RV_FUNC7(v) __ASM_STR(v) @@ -133,6 +180,7 @@ #define RV___RS2(v) __RV_REG(v) #define RV_OPCODE_MISC_MEM RV_OPCODE(15) +#define RV_OPCODE_OP_IMM RV_OPCODE(19) #define RV_OPCODE_SYSTEM RV_OPCODE(115) #define HFENCE_VVMA(vaddr, asid) \ @@ -196,6 +244,18 @@ INSN_I(OPCODE_MISC_MEM, FUNC3(2), __RD(0), \ RS1(base), SIMM12(4)) +#define PREFETCH_I(base, offset) \ + INSN_S(OPCODE_OP_IMM, FUNC3(6), __RS2(0), \ + SIMM12((offset) & 0xfe0), RS1(base)) + +#define PREFETCH_R(base, offset) \ + INSN_S(OPCODE_OP_IMM, FUNC3(6), __RS2(1), \ + SIMM12((offset) & 0xfe0), RS1(base)) + +#define PREFETCH_W(base, offset) \ + INSN_S(OPCODE_OP_IMM, FUNC3(6), __RS2(3), \ + SIMM12((offset) & 0xfe0), RS1(base)) + #define RISCV_PAUSE ".4byte 0x100000f" #define ZAWRS_WRS_NTO ".4byte 0x00d00073" #define ZAWRS_WRS_STO ".4byte 0x01d00073" @@ -203,4 +263,10 @@ #define RISCV_INSN_NOP4 _AC(0x00000013, U) +#ifndef __ASSEMBLY__ +#define nop() __asm__ __volatile__ ("nop") +#define __nops(n) ".rept " #n "\nnop\n.endr\n" +#define nops(n) __asm__ __volatile__ (__nops(n)) +#endif + #endif /* __ASM_INSN_DEF_H */ diff --git a/arch/riscv/include/asm/kexec.h b/arch/riscv/include/asm/kexec.h index 2b56769cb530..b9ee8346cc8c 100644 --- a/arch/riscv/include/asm/kexec.h +++ b/arch/riscv/include/asm/kexec.h @@ -56,6 +56,7 @@ extern riscv_kexec_method riscv_kexec_norelocate; #ifdef CONFIG_KEXEC_FILE extern const struct kexec_file_ops elf_kexec_ops; +extern const struct kexec_file_ops image_kexec_ops; struct purgatory_info; int arch_kexec_apply_relocations_add(struct purgatory_info *pi, @@ -67,6 +68,11 @@ int arch_kexec_apply_relocations_add(struct purgatory_info *pi, struct kimage; int arch_kimage_file_post_load_cleanup(struct kimage *image); #define arch_kimage_file_post_load_cleanup arch_kimage_file_post_load_cleanup + +int load_extra_segments(struct kimage *image, unsigned long kernel_start, + unsigned long kernel_len, char *initrd, + unsigned long initrd_len, char *cmdline, + unsigned long cmdline_len); #endif #endif diff --git a/arch/riscv/include/asm/pgtable-64.h b/arch/riscv/include/asm/pgtable-64.h index 188fadc1c21f..7de05db7d3bd 100644 --- a/arch/riscv/include/asm/pgtable-64.h +++ b/arch/riscv/include/asm/pgtable-64.h @@ -184,7 +184,7 @@ static inline int pud_none(pud_t pud) static inline int pud_bad(pud_t pud) { - return !pud_present(pud); + return !pud_present(pud) || (pud_val(pud) & _PAGE_LEAF); } #define pud_leaf pud_leaf @@ -399,6 +399,7 @@ p4d_t *p4d_offset(pgd_t *pgd, unsigned long address); #ifdef CONFIG_TRANSPARENT_HUGEPAGE static inline int pte_devmap(pte_t pte); static inline pte_t pmd_pte(pmd_t pmd); +static inline pte_t pud_pte(pud_t pud); static inline int pmd_devmap(pmd_t pmd) { @@ -407,7 +408,7 @@ static inline int pmd_devmap(pmd_t pmd) static inline int pud_devmap(pud_t pud) { - return 0; + return pte_devmap(pud_pte(pud)); } static inline int pgd_devmap(pgd_t pgd) diff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h index f19240fd018e..a11816bbf9e7 100644 --- a/arch/riscv/include/asm/pgtable.h +++ b/arch/riscv/include/asm/pgtable.h @@ -900,6 +900,103 @@ static inline pmd_t pmdp_establish(struct vm_area_struct *vma, #define pmdp_collapse_flush pmdp_collapse_flush extern pmd_t pmdp_collapse_flush(struct vm_area_struct *vma, unsigned long address, pmd_t *pmdp); + +static inline pud_t pud_wrprotect(pud_t pud) +{ + return pte_pud(pte_wrprotect(pud_pte(pud))); +} + +static inline int pud_trans_huge(pud_t pud) +{ + return pud_leaf(pud); +} + +static inline int pud_dirty(pud_t pud) +{ + return pte_dirty(pud_pte(pud)); +} + +static inline pud_t pud_mkyoung(pud_t pud) +{ + return pte_pud(pte_mkyoung(pud_pte(pud))); +} + +static inline pud_t pud_mkold(pud_t pud) +{ + return pte_pud(pte_mkold(pud_pte(pud))); +} + +static inline pud_t pud_mkdirty(pud_t pud) +{ + return pte_pud(pte_mkdirty(pud_pte(pud))); +} + +static inline pud_t pud_mkclean(pud_t pud) +{ + return pte_pud(pte_mkclean(pud_pte(pud))); +} + +static inline pud_t pud_mkwrite(pud_t pud) +{ + return pte_pud(pte_mkwrite_novma(pud_pte(pud))); +} + +static inline pud_t pud_mkhuge(pud_t pud) +{ + return pud; +} + +static inline pud_t pud_mkdevmap(pud_t pud) +{ + return pte_pud(pte_mkdevmap(pud_pte(pud))); +} + +static inline int pudp_set_access_flags(struct vm_area_struct *vma, + unsigned long address, pud_t *pudp, + pud_t entry, int dirty) +{ + return ptep_set_access_flags(vma, address, (pte_t *)pudp, pud_pte(entry), dirty); +} + +static inline int pudp_test_and_clear_young(struct vm_area_struct *vma, + unsigned long address, pud_t *pudp) +{ + return ptep_test_and_clear_young(vma, address, (pte_t *)pudp); +} + +static inline int pud_young(pud_t pud) +{ + return pte_young(pud_pte(pud)); +} + +static inline void update_mmu_cache_pud(struct vm_area_struct *vma, + unsigned long address, pud_t *pudp) +{ + pte_t *ptep = (pte_t *)pudp; + + update_mmu_cache(vma, address, ptep); +} + +static inline pud_t pudp_establish(struct vm_area_struct *vma, + unsigned long address, pud_t *pudp, pud_t pud) +{ + page_table_check_pud_set(vma->vm_mm, pudp, pud); + return __pud(atomic_long_xchg((atomic_long_t *)pudp, pud_val(pud))); +} + +static inline pud_t pud_mkinvalid(pud_t pud) +{ + return __pud(pud_val(pud) & ~(_PAGE_PRESENT | _PAGE_PROT_NONE)); +} + +extern pud_t pudp_invalidate(struct vm_area_struct *vma, unsigned long address, + pud_t *pudp); + +static inline pud_t pud_modify(pud_t pud, pgprot_t newprot) +{ + return pte_pud(pte_modify(pud_pte(pud), newprot)); +} + #endif /* CONFIG_TRANSPARENT_HUGEPAGE */ /* diff --git a/arch/riscv/include/asm/processor.h b/arch/riscv/include/asm/processor.h index 5f56eb9d114a..24d3af4d3807 100644 --- a/arch/riscv/include/asm/processor.h +++ b/arch/riscv/include/asm/processor.h @@ -13,6 +13,9 @@ #include <vdso/processor.h> #include <asm/ptrace.h> +#include <asm/insn-def.h> +#include <asm/alternative-macros.h> +#include <asm/hwcap.h> #define arch_get_mmap_end(addr, len, flags) \ ({ \ @@ -52,7 +55,6 @@ #endif #ifndef __ASSEMBLY__ -#include <linux/cpumask.h> struct task_struct; struct pt_regs; @@ -79,6 +81,10 @@ struct pt_regs; * Thus, the task does not own preempt_v. Any use of Vector will have to * save preempt_v, if dirty, and fallback to non-preemptible kernel-mode * Vector. + * - bit 29: The thread voluntarily calls schedule() while holding an active + * preempt_v. All preempt_v context should be dropped in such case because + * V-regs are caller-saved. Only sstatus.VS=ON is persisted across a + * schedule() call. * - bit 30: The in-kernel preempt_v context is saved, and requries to be * restored when returning to the context that owns the preempt_v. * - bit 31: The in-kernel preempt_v context is dirty, as signaled by the @@ -93,6 +99,7 @@ struct pt_regs; #define RISCV_PREEMPT_V 0x00000100 #define RISCV_PREEMPT_V_DIRTY 0x80000000 #define RISCV_PREEMPT_V_NEED_RESTORE 0x40000000 +#define RISCV_PREEMPT_V_IN_SCHEDULE 0x20000000 /* CPU-specific state of a task */ struct thread_struct { @@ -103,6 +110,7 @@ struct thread_struct { struct __riscv_d_ext_state fstate; unsigned long bad_cause; unsigned long envcfg; + unsigned long sum; u32 riscv_v_flags; u32 vstate_ctrl; struct __riscv_v_ext_state vstate; @@ -136,6 +144,27 @@ static inline void arch_thread_struct_whitelist(unsigned long *offset, #define KSTK_EIP(tsk) (task_pt_regs(tsk)->epc) #define KSTK_ESP(tsk) (task_pt_regs(tsk)->sp) +#define PREFETCH_ASM(x) \ + ALTERNATIVE(__nops(1), PREFETCH_R(x, 0), 0, \ + RISCV_ISA_EXT_ZICBOP, CONFIG_RISCV_ISA_ZICBOP) + +#define PREFETCHW_ASM(x) \ + ALTERNATIVE(__nops(1), PREFETCH_W(x, 0), 0, \ + RISCV_ISA_EXT_ZICBOP, CONFIG_RISCV_ISA_ZICBOP) + +#ifdef CONFIG_RISCV_ISA_ZICBOP +#define ARCH_HAS_PREFETCH +static inline void prefetch(const void *x) +{ + __asm__ __volatile__(PREFETCH_ASM(%0) : : "r" (x) : "memory"); +} + +#define ARCH_HAS_PREFETCHW +static inline void prefetchw(const void *x) +{ + __asm__ __volatile__(PREFETCHW_ASM(%0) : : "r" (x) : "memory"); +} +#endif /* CONFIG_RISCV_ISA_ZICBOP */ /* Do necessary setup to start up a newly executed thread. */ extern void start_thread(struct pt_regs *regs, diff --git a/arch/riscv/include/asm/ptrace.h b/arch/riscv/include/asm/ptrace.h index 2910231977cb..a7dc0e330757 100644 --- a/arch/riscv/include/asm/ptrace.h +++ b/arch/riscv/include/asm/ptrace.h @@ -175,7 +175,7 @@ static inline unsigned long regs_get_kernel_argument(struct pt_regs *regs, return 0; } -static inline int regs_irqs_disabled(struct pt_regs *regs) +static __always_inline bool regs_irqs_disabled(struct pt_regs *regs) { return !(regs->status & SR_PIE); } diff --git a/arch/riscv/include/asm/sbi.h b/arch/riscv/include/asm/sbi.h index 3d250824178b..341e74238aa0 100644 --- a/arch/riscv/include/asm/sbi.h +++ b/arch/riscv/include/asm/sbi.h @@ -35,6 +35,7 @@ enum sbi_ext_id { SBI_EXT_DBCN = 0x4442434E, SBI_EXT_STA = 0x535441, SBI_EXT_NACL = 0x4E41434C, + SBI_EXT_FWFT = 0x46574654, /* Experimentals extensions must lie within this range */ SBI_EXT_EXPERIMENTAL_START = 0x08000000, @@ -402,6 +403,33 @@ enum sbi_ext_nacl_feature { #define SBI_NACL_SHMEM_SRET_X(__i) ((__riscv_xlen / 8) * (__i)) #define SBI_NACL_SHMEM_SRET_X_LAST 31 +/* SBI function IDs for FW feature extension */ +#define SBI_EXT_FWFT_SET 0x0 +#define SBI_EXT_FWFT_GET 0x1 + +enum sbi_fwft_feature_t { + SBI_FWFT_MISALIGNED_EXC_DELEG = 0x0, + SBI_FWFT_LANDING_PAD = 0x1, + SBI_FWFT_SHADOW_STACK = 0x2, + SBI_FWFT_DOUBLE_TRAP = 0x3, + SBI_FWFT_PTE_AD_HW_UPDATING = 0x4, + SBI_FWFT_POINTER_MASKING_PMLEN = 0x5, + SBI_FWFT_LOCAL_RESERVED_START = 0x6, + SBI_FWFT_LOCAL_RESERVED_END = 0x3fffffff, + SBI_FWFT_LOCAL_PLATFORM_START = 0x40000000, + SBI_FWFT_LOCAL_PLATFORM_END = 0x7fffffff, + + SBI_FWFT_GLOBAL_RESERVED_START = 0x80000000, + SBI_FWFT_GLOBAL_RESERVED_END = 0xbfffffff, + SBI_FWFT_GLOBAL_PLATFORM_START = 0xc0000000, + SBI_FWFT_GLOBAL_PLATFORM_END = 0xffffffff, +}; + +#define SBI_FWFT_PLATFORM_FEATURE_BIT BIT(30) +#define SBI_FWFT_GLOBAL_FEATURE_BIT BIT(31) + +#define SBI_FWFT_SET_FLAG_LOCK BIT(0) + /* SBI spec version fields */ #define SBI_SPEC_VERSION_DEFAULT 0x1 #define SBI_SPEC_VERSION_MAJOR_SHIFT 24 @@ -419,6 +447,11 @@ enum sbi_ext_nacl_feature { #define SBI_ERR_ALREADY_STARTED -7 #define SBI_ERR_ALREADY_STOPPED -8 #define SBI_ERR_NO_SHMEM -9 +#define SBI_ERR_INVALID_STATE -10 +#define SBI_ERR_BAD_RANGE -11 +#define SBI_ERR_TIMEOUT -12 +#define SBI_ERR_IO -13 +#define SBI_ERR_DENIED_LOCKED -14 extern unsigned long sbi_spec_version; struct sbiret { @@ -470,6 +503,23 @@ int sbi_remote_hfence_vvma_asid(const struct cpumask *cpu_mask, unsigned long asid); long sbi_probe_extension(int ext); +int sbi_fwft_set(u32 feature, unsigned long value, unsigned long flags); +int sbi_fwft_set_cpumask(const cpumask_t *mask, u32 feature, + unsigned long value, unsigned long flags); +/** + * sbi_fwft_set_online_cpus() - Set a feature on all online cpus + * @feature: The feature to be set + * @value: The feature value to be set + * @flags: FWFT feature set flags + * + * Return: 0 on success, appropriate linux error code otherwise. + */ +static inline int sbi_fwft_set_online_cpus(u32 feature, unsigned long value, + unsigned long flags) +{ + return sbi_fwft_set_cpumask(cpu_online_mask, feature, value, flags); +} + /* Check if current SBI specification version is 0.1 or not */ static inline int sbi_spec_is_0_1(void) { @@ -503,11 +553,21 @@ static inline int sbi_err_map_linux_errno(int err) case SBI_SUCCESS: return 0; case SBI_ERR_DENIED: + case SBI_ERR_DENIED_LOCKED: return -EPERM; case SBI_ERR_INVALID_PARAM: + case SBI_ERR_INVALID_STATE: return -EINVAL; + case SBI_ERR_BAD_RANGE: + return -ERANGE; case SBI_ERR_INVALID_ADDRESS: return -EFAULT; + case SBI_ERR_NO_SHMEM: + return -ENOMEM; + case SBI_ERR_TIMEOUT: + return -ETIMEDOUT; + case SBI_ERR_IO: + return -EIO; case SBI_ERR_NOT_SUPPORTED: case SBI_ERR_FAILURE: default: diff --git a/arch/riscv/include/asm/tlbflush.h b/arch/riscv/include/asm/tlbflush.h index ce0dd0fed764..1a20dd746a49 100644 --- a/arch/riscv/include/asm/tlbflush.h +++ b/arch/riscv/include/asm/tlbflush.h @@ -56,6 +56,8 @@ void local_flush_tlb_kernel_range(unsigned long start, unsigned long end); #define __HAVE_ARCH_FLUSH_PMD_TLB_RANGE void flush_pmd_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end); +void flush_pud_tlb_range(struct vm_area_struct *vma, unsigned long start, + unsigned long end); #endif bool arch_tlbbatch_should_defer(struct mm_struct *mm); diff --git a/arch/riscv/include/asm/uaccess.h b/arch/riscv/include/asm/uaccess.h index fee56b0c8058..d472da4450e6 100644 --- a/arch/riscv/include/asm/uaccess.h +++ b/arch/riscv/include/asm/uaccess.h @@ -62,6 +62,19 @@ static inline unsigned long __untagged_addr_remote(struct mm_struct *mm, unsigne __asm__ __volatile__ ("csrc sstatus, %0" : : "r" (SR_SUM) : "memory") /* + * This is the smallest unsigned integer type that can fit a value + * (up to 'long long') + */ +#define __inttype(x) __typeof__( \ + __typefits(x, char, \ + __typefits(x, short, \ + __typefits(x, int, \ + __typefits(x, long, 0ULL))))) + +#define __typefits(x, type, not) \ + __builtin_choose_expr(sizeof(x) <= sizeof(type), (unsigned type)0, not) + +/* * The exception table consists of pairs of addresses: the first is the * address of an instruction that is allowed to fault, and the second is * the address at which the program should continue. No registers are @@ -83,27 +96,58 @@ static inline unsigned long __untagged_addr_remote(struct mm_struct *mm, unsigne * call. */ -#define __get_user_asm(insn, x, ptr, err) \ +#ifdef CONFIG_CC_HAS_ASM_GOTO_OUTPUT +#define __get_user_asm(insn, x, ptr, label) \ + asm_goto_output( \ + "1:\n" \ + " " insn " %0, %1\n" \ + _ASM_EXTABLE_UACCESS_ERR(1b, %l2, %0) \ + : "=&r" (x) \ + : "m" (*(ptr)) : : label) +#else /* !CONFIG_CC_HAS_ASM_GOTO_OUTPUT */ +#define __get_user_asm(insn, x, ptr, label) \ do { \ - __typeof__(x) __x; \ + long __gua_err = 0; \ __asm__ __volatile__ ( \ "1:\n" \ " " insn " %1, %2\n" \ "2:\n" \ _ASM_EXTABLE_UACCESS_ERR_ZERO(1b, 2b, %0, %1) \ - : "+r" (err), "=&r" (__x) \ + : "+r" (__gua_err), "=&r" (x) \ : "m" (*(ptr))); \ - (x) = __x; \ + if (__gua_err) \ + goto label; \ } while (0) +#endif /* CONFIG_CC_HAS_ASM_GOTO_OUTPUT */ #ifdef CONFIG_64BIT -#define __get_user_8(x, ptr, err) \ - __get_user_asm("ld", x, ptr, err) +#define __get_user_8(x, ptr, label) \ + __get_user_asm("ld", x, ptr, label) #else /* !CONFIG_64BIT */ -#define __get_user_8(x, ptr, err) \ + +#ifdef CONFIG_CC_HAS_ASM_GOTO_OUTPUT +#define __get_user_8(x, ptr, label) \ + u32 __user *__ptr = (u32 __user *)(ptr); \ + u32 __lo, __hi; \ + asm_goto_output( \ + "1:\n" \ + " lw %0, %2\n" \ + "2:\n" \ + " lw %1, %3\n" \ + _ASM_EXTABLE_UACCESS_ERR(1b, %l4, %0) \ + _ASM_EXTABLE_UACCESS_ERR(2b, %l4, %0) \ + : "=&r" (__lo), "=r" (__hi) \ + : "m" (__ptr[__LSW]), "m" (__ptr[__MSW]) \ + : : label); \ + (x) = (__typeof__(x))((__typeof__((x) - (x)))( \ + (((u64)__hi << 32) | __lo))); \ + +#else /* !CONFIG_CC_HAS_ASM_GOTO_OUTPUT */ +#define __get_user_8(x, ptr, label) \ do { \ u32 __user *__ptr = (u32 __user *)(ptr); \ u32 __lo, __hi; \ + long __gu8_err = 0; \ __asm__ __volatile__ ( \ "1:\n" \ " lw %1, %3\n" \ @@ -112,35 +156,62 @@ do { \ "3:\n" \ _ASM_EXTABLE_UACCESS_ERR_ZERO(1b, 3b, %0, %1) \ _ASM_EXTABLE_UACCESS_ERR_ZERO(2b, 3b, %0, %1) \ - : "+r" (err), "=&r" (__lo), "=r" (__hi) \ + : "+r" (__gu8_err), "=&r" (__lo), "=r" (__hi) \ : "m" (__ptr[__LSW]), "m" (__ptr[__MSW])); \ - if (err) \ + if (__gu8_err) { \ __hi = 0; \ - (x) = (__typeof__(x))((__typeof__((x)-(x)))( \ + goto label; \ + } \ + (x) = (__typeof__(x))((__typeof__((x) - (x)))( \ (((u64)__hi << 32) | __lo))); \ } while (0) +#endif /* CONFIG_CC_HAS_ASM_GOTO_OUTPUT */ + #endif /* CONFIG_64BIT */ -#define __get_user_nocheck(x, __gu_ptr, __gu_err) \ +unsigned long __must_check __asm_copy_to_user_sum_enabled(void __user *to, + const void *from, unsigned long n); +unsigned long __must_check __asm_copy_from_user_sum_enabled(void *to, + const void __user *from, unsigned long n); + +#define __get_user_nocheck(x, __gu_ptr, label) \ do { \ + if (!IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && \ + !IS_ALIGNED((uintptr_t)__gu_ptr, sizeof(*__gu_ptr))) { \ + if (__asm_copy_from_user_sum_enabled(&(x), __gu_ptr, sizeof(*__gu_ptr))) \ + goto label; \ + break; \ + } \ switch (sizeof(*__gu_ptr)) { \ case 1: \ - __get_user_asm("lb", (x), __gu_ptr, __gu_err); \ + __get_user_asm("lb", (x), __gu_ptr, label); \ break; \ case 2: \ - __get_user_asm("lh", (x), __gu_ptr, __gu_err); \ + __get_user_asm("lh", (x), __gu_ptr, label); \ break; \ case 4: \ - __get_user_asm("lw", (x), __gu_ptr, __gu_err); \ + __get_user_asm("lw", (x), __gu_ptr, label); \ break; \ case 8: \ - __get_user_8((x), __gu_ptr, __gu_err); \ + __get_user_8((x), __gu_ptr, label); \ break; \ default: \ BUILD_BUG(); \ } \ } while (0) +#define __get_user_error(x, ptr, err) \ +do { \ + __label__ __gu_failed; \ + \ + __get_user_nocheck(x, ptr, __gu_failed); \ + err = 0; \ + break; \ +__gu_failed: \ + x = 0; \ + err = -EFAULT; \ +} while (0) + /** * __get_user: - Get a simple variable from user space, with less checking. * @x: Variable to store result. @@ -165,13 +236,16 @@ do { \ ({ \ const __typeof__(*(ptr)) __user *__gu_ptr = untagged_addr(ptr); \ long __gu_err = 0; \ + __typeof__(x) __gu_val; \ \ __chk_user_ptr(__gu_ptr); \ \ __enable_user_access(); \ - __get_user_nocheck(x, __gu_ptr, __gu_err); \ + __get_user_error(__gu_val, __gu_ptr, __gu_err); \ __disable_user_access(); \ \ + (x) = __gu_val; \ + \ __gu_err; \ }) @@ -201,61 +275,73 @@ do { \ ((x) = (__force __typeof__(x))0, -EFAULT); \ }) -#define __put_user_asm(insn, x, ptr, err) \ +#define __put_user_asm(insn, x, ptr, label) \ do { \ __typeof__(*(ptr)) __x = x; \ - __asm__ __volatile__ ( \ + asm goto( \ "1:\n" \ - " " insn " %z2, %1\n" \ - "2:\n" \ - _ASM_EXTABLE_UACCESS_ERR(1b, 2b, %0) \ - : "+r" (err), "=m" (*(ptr)) \ - : "rJ" (__x)); \ + " " insn " %z0, %1\n" \ + _ASM_EXTABLE(1b, %l2) \ + : : "rJ" (__x), "m"(*(ptr)) : : label); \ } while (0) #ifdef CONFIG_64BIT -#define __put_user_8(x, ptr, err) \ - __put_user_asm("sd", x, ptr, err) +#define __put_user_8(x, ptr, label) \ + __put_user_asm("sd", x, ptr, label) #else /* !CONFIG_64BIT */ -#define __put_user_8(x, ptr, err) \ +#define __put_user_8(x, ptr, label) \ do { \ u32 __user *__ptr = (u32 __user *)(ptr); \ u64 __x = (__typeof__((x)-(x)))(x); \ - __asm__ __volatile__ ( \ + asm goto( \ "1:\n" \ - " sw %z3, %1\n" \ + " sw %z0, %2\n" \ "2:\n" \ - " sw %z4, %2\n" \ - "3:\n" \ - _ASM_EXTABLE_UACCESS_ERR(1b, 3b, %0) \ - _ASM_EXTABLE_UACCESS_ERR(2b, 3b, %0) \ - : "+r" (err), \ - "=m" (__ptr[__LSW]), \ - "=m" (__ptr[__MSW]) \ - : "rJ" (__x), "rJ" (__x >> 32)); \ + " sw %z1, %3\n" \ + _ASM_EXTABLE(1b, %l4) \ + _ASM_EXTABLE(2b, %l4) \ + : : "rJ" (__x), "rJ" (__x >> 32), \ + "m" (__ptr[__LSW]), \ + "m" (__ptr[__MSW]) : : label); \ } while (0) #endif /* CONFIG_64BIT */ -#define __put_user_nocheck(x, __gu_ptr, __pu_err) \ +#define __put_user_nocheck(x, __gu_ptr, label) \ do { \ + if (!IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && \ + !IS_ALIGNED((uintptr_t)__gu_ptr, sizeof(*__gu_ptr))) { \ + __inttype(x) val = (__inttype(x))x; \ + if (__asm_copy_to_user_sum_enabled(__gu_ptr, &(val), sizeof(*__gu_ptr))) \ + goto label; \ + break; \ + } \ switch (sizeof(*__gu_ptr)) { \ case 1: \ - __put_user_asm("sb", (x), __gu_ptr, __pu_err); \ + __put_user_asm("sb", (x), __gu_ptr, label); \ break; \ case 2: \ - __put_user_asm("sh", (x), __gu_ptr, __pu_err); \ + __put_user_asm("sh", (x), __gu_ptr, label); \ break; \ case 4: \ - __put_user_asm("sw", (x), __gu_ptr, __pu_err); \ + __put_user_asm("sw", (x), __gu_ptr, label); \ break; \ case 8: \ - __put_user_8((x), __gu_ptr, __pu_err); \ + __put_user_8((x), __gu_ptr, label); \ break; \ default: \ BUILD_BUG(); \ } \ } while (0) +#define __put_user_error(x, ptr, err) \ +do { \ + __label__ err_label; \ + __put_user_nocheck(x, ptr, err_label); \ + break; \ +err_label: \ + (err) = -EFAULT; \ +} while (0) + /** * __put_user: - Write a simple value into user space, with less checking. * @x: Value to copy to user space. @@ -286,7 +372,7 @@ do { \ __chk_user_ptr(__gu_ptr); \ \ __enable_user_access(); \ - __put_user_nocheck(__val, __gu_ptr, __pu_err); \ + __put_user_error(__val, __gu_ptr, __pu_err); \ __disable_user_access(); \ \ __pu_err; \ @@ -351,23 +437,45 @@ unsigned long __must_check clear_user(void __user *to, unsigned long n) } #define __get_kernel_nofault(dst, src, type, err_label) \ -do { \ - long __kr_err = 0; \ - \ - __get_user_nocheck(*((type *)(dst)), (type *)(src), __kr_err); \ - if (unlikely(__kr_err)) \ - goto err_label; \ -} while (0) + __get_user_nocheck(*((type *)(dst)), (type *)(src), err_label) #define __put_kernel_nofault(dst, src, type, err_label) \ -do { \ - long __kr_err = 0; \ - \ - __put_user_nocheck(*((type *)(src)), (type *)(dst), __kr_err); \ - if (unlikely(__kr_err)) \ - goto err_label; \ + __put_user_nocheck(*((type *)(src)), (type *)(dst), err_label) + +static __must_check __always_inline bool user_access_begin(const void __user *ptr, size_t len) +{ + if (unlikely(!access_ok(ptr, len))) + return 0; + __enable_user_access(); + return 1; +} +#define user_access_begin user_access_begin +#define user_access_end __disable_user_access + +static inline unsigned long user_access_save(void) { return 0UL; } +static inline void user_access_restore(unsigned long enabled) { } + +/* + * We want the unsafe accessors to always be inlined and use + * the error labels - thus the macro games. + */ +#define unsafe_put_user(x, ptr, label) \ + __put_user_nocheck(x, (ptr), label) + +#define unsafe_get_user(x, ptr, label) do { \ + __inttype(*(ptr)) __gu_val; \ + __get_user_nocheck(__gu_val, (ptr), label); \ + (x) = (__force __typeof__(*(ptr)))__gu_val; \ } while (0) +#define unsafe_copy_to_user(_dst, _src, _len, label) \ + if (__asm_copy_to_user_sum_enabled(_dst, _src, _len)) \ + goto label; + +#define unsafe_copy_from_user(_dst, _src, _len, label) \ + if (__asm_copy_from_user_sum_enabled(_dst, _src, _len)) \ + goto label; + #else /* CONFIG_MMU */ #include <asm-generic/uaccess.h> #endif /* CONFIG_MMU */ diff --git a/arch/riscv/include/asm/vdso/getrandom.h b/arch/riscv/include/asm/vdso/getrandom.h new file mode 100644 index 000000000000..8dc92441702a --- /dev/null +++ b/arch/riscv/include/asm/vdso/getrandom.h @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2025 Xi Ruoyao <xry111@xry111.site>. All Rights Reserved. + */ +#ifndef __ASM_VDSO_GETRANDOM_H +#define __ASM_VDSO_GETRANDOM_H + +#ifndef __ASSEMBLY__ + +#include <asm/unistd.h> + +static __always_inline ssize_t getrandom_syscall(void *_buffer, size_t _len, unsigned int _flags) +{ + register long ret asm("a0"); + register long nr asm("a7") = __NR_getrandom; + register void *buffer asm("a0") = _buffer; + register size_t len asm("a1") = _len; + register unsigned int flags asm("a2") = _flags; + + asm volatile ("ecall\n" + : "+r" (ret) + : "r" (nr), "r" (buffer), "r" (len), "r" (flags) + : "memory"); + + return ret; +} + +#endif /* !__ASSEMBLY__ */ + +#endif /* __ASM_VDSO_GETRANDOM_H */ diff --git a/arch/riscv/include/asm/vector.h b/arch/riscv/include/asm/vector.h index e8a83f55be2b..45c9b426fcc5 100644 --- a/arch/riscv/include/asm/vector.h +++ b/arch/riscv/include/asm/vector.h @@ -120,6 +120,11 @@ static __always_inline void riscv_v_disable(void) csr_clear(CSR_SSTATUS, SR_VS); } +static __always_inline bool riscv_v_is_on(void) +{ + return !!(csr_read(CSR_SSTATUS) & SR_VS); +} + static __always_inline void __vstate_csr_save(struct __riscv_v_ext_state *dest) { asm volatile ( @@ -366,6 +371,11 @@ static inline void __switch_to_vector(struct task_struct *prev, struct pt_regs *regs; if (riscv_preempt_v_started(prev)) { + if (riscv_v_is_on()) { + WARN_ON(prev->thread.riscv_v_flags & RISCV_V_CTX_DEPTH_MASK); + riscv_v_disable(); + prev->thread.riscv_v_flags |= RISCV_PREEMPT_V_IN_SCHEDULE; + } if (riscv_preempt_v_dirty(prev)) { __riscv_v_vstate_save(&prev->thread.kernel_vstate, prev->thread.kernel_vstate.datap); @@ -376,10 +386,16 @@ static inline void __switch_to_vector(struct task_struct *prev, riscv_v_vstate_save(&prev->thread.vstate, regs); } - if (riscv_preempt_v_started(next)) - riscv_preempt_v_set_restore(next); - else + if (riscv_preempt_v_started(next)) { + if (next->thread.riscv_v_flags & RISCV_PREEMPT_V_IN_SCHEDULE) { + next->thread.riscv_v_flags &= ~RISCV_PREEMPT_V_IN_SCHEDULE; + riscv_v_enable(); + } else { + riscv_preempt_v_set_restore(next); + } + } else { riscv_v_vstate_set_restore(next, task_pt_regs(next)); + } } void riscv_v_vstate_ctrl_init(struct task_struct *tsk); diff --git a/arch/riscv/include/asm/vendor_extensions/sifive.h b/arch/riscv/include/asm/vendor_extensions/sifive.h new file mode 100644 index 000000000000..ac00e500361c --- /dev/null +++ b/arch/riscv/include/asm/vendor_extensions/sifive.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _ASM_RISCV_VENDOR_EXTENSIONS_SIFIVE_H +#define _ASM_RISCV_VENDOR_EXTENSIONS_SIFIVE_H + +#include <asm/vendor_extensions.h> + +#include <linux/types.h> + +#define RISCV_ISA_VENDOR_EXT_XSFVQMACCDOD 0 +#define RISCV_ISA_VENDOR_EXT_XSFVQMACCQOQ 1 +#define RISCV_ISA_VENDOR_EXT_XSFVFNRCLIPXFQF 2 +#define RISCV_ISA_VENDOR_EXT_XSFVFWMACCQQQ 3 + +extern struct riscv_isa_vendor_ext_data_list riscv_isa_vendor_ext_list_sifive; + +#endif diff --git a/arch/riscv/include/asm/vendor_extensions/sifive_hwprobe.h b/arch/riscv/include/asm/vendor_extensions/sifive_hwprobe.h new file mode 100644 index 000000000000..90a61abd033c --- /dev/null +++ b/arch/riscv/include/asm/vendor_extensions/sifive_hwprobe.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _ASM_RISCV_VENDOR_EXTENSIONS_SIFIVE_HWPROBE_H +#define _ASM_RISCV_VENDOR_EXTENSIONS_SIFIVE_HWPROBE_H + +#include <linux/cpumask.h> + +#include <uapi/asm/hwprobe.h> + +#ifdef CONFIG_RISCV_ISA_VENDOR_EXT_SIFIVE +void hwprobe_isa_vendor_ext_sifive_0(struct riscv_hwprobe *pair, const struct cpumask *cpus); +#else +static inline void hwprobe_isa_vendor_ext_sifive_0(struct riscv_hwprobe *pair, + const struct cpumask *cpus) +{ + pair->value = 0; +} +#endif + +#endif diff --git a/arch/riscv/include/uapi/asm/hwprobe.h b/arch/riscv/include/uapi/asm/hwprobe.h index 3c2fce939673..aaf6ad970499 100644 --- a/arch/riscv/include/uapi/asm/hwprobe.h +++ b/arch/riscv/include/uapi/asm/hwprobe.h @@ -81,6 +81,7 @@ struct riscv_hwprobe { #define RISCV_HWPROBE_EXT_ZICBOM (1ULL << 55) #define RISCV_HWPROBE_EXT_ZAAMO (1ULL << 56) #define RISCV_HWPROBE_EXT_ZALRSC (1ULL << 57) +#define RISCV_HWPROBE_EXT_ZABHA (1ULL << 58) #define RISCV_HWPROBE_KEY_CPUPERF_0 5 #define RISCV_HWPROBE_MISALIGNED_UNKNOWN (0 << 0) #define RISCV_HWPROBE_MISALIGNED_EMULATED (1 << 0) @@ -104,6 +105,7 @@ struct riscv_hwprobe { #define RISCV_HWPROBE_MISALIGNED_VECTOR_UNSUPPORTED 4 #define RISCV_HWPROBE_KEY_VENDOR_EXT_THEAD_0 11 #define RISCV_HWPROBE_KEY_ZICBOM_BLOCK_SIZE 12 +#define RISCV_HWPROBE_KEY_VENDOR_EXT_SIFIVE_0 13 /* Increase RISCV_HWPROBE_MAX_KEY when adding items. */ /* Flags */ diff --git a/arch/riscv/include/uapi/asm/vendor/sifive.h b/arch/riscv/include/uapi/asm/vendor/sifive.h new file mode 100644 index 000000000000..9f3278a4b298 --- /dev/null +++ b/arch/riscv/include/uapi/asm/vendor/sifive.h @@ -0,0 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ + +#define RISCV_HWPROBE_VENDOR_EXT_XSFVQMACCDOD (1 << 0) +#define RISCV_HWPROBE_VENDOR_EXT_XSFVQMACCQOQ (1 << 1) +#define RISCV_HWPROBE_VENDOR_EXT_XSFVFNRCLIPXFQF (1 << 2) +#define RISCV_HWPROBE_VENDOR_EXT_XSFVFWMACCQQQ (1 << 3) diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile index f7480c9c6f8d..c7b542573407 100644 --- a/arch/riscv/kernel/Makefile +++ b/arch/riscv/kernel/Makefile @@ -43,7 +43,7 @@ CFLAGS_sbi_ecall.o += -D__NO_FORTIFY endif endif -extra-y += vmlinux.lds +always-$(KBUILD_BUILTIN) += vmlinux.lds obj-y += head.o obj-y += soc.o @@ -107,7 +107,7 @@ obj-$(CONFIG_HOTPLUG_CPU) += cpu-hotplug.o obj-$(CONFIG_PARAVIRT) += paravirt.o obj-$(CONFIG_KGDB) += kgdb.o obj-$(CONFIG_KEXEC_CORE) += kexec_relocate.o crash_save_regs.o machine_kexec.o -obj-$(CONFIG_KEXEC_FILE) += elf_kexec.o machine_kexec_file.o +obj-$(CONFIG_KEXEC_FILE) += kexec_elf.o kexec_image.o machine_kexec_file.o obj-$(CONFIG_CRASH_DUMP) += crash_dump.o obj-$(CONFIG_VMCORE_INFO) += vmcore_info.o diff --git a/arch/riscv/kernel/asm-offsets.c b/arch/riscv/kernel/asm-offsets.c index 16490755304e..6e8c0d6feae9 100644 --- a/arch/riscv/kernel/asm-offsets.c +++ b/arch/riscv/kernel/asm-offsets.c @@ -34,6 +34,7 @@ void asm_offsets(void) OFFSET(TASK_THREAD_S9, task_struct, thread.s[9]); OFFSET(TASK_THREAD_S10, task_struct, thread.s[10]); OFFSET(TASK_THREAD_S11, task_struct, thread.s[11]); + OFFSET(TASK_THREAD_SUM, task_struct, thread.sum); OFFSET(TASK_TI_CPU, task_struct, thread_info.cpu); OFFSET(TASK_TI_PREEMPT_COUNT, task_struct, thread_info.preempt_count); @@ -346,6 +347,10 @@ void asm_offsets(void) offsetof(struct task_struct, thread.s[11]) - offsetof(struct task_struct, thread.ra) ); + DEFINE(TASK_THREAD_SUM_RA, + offsetof(struct task_struct, thread.sum) + - offsetof(struct task_struct, thread.ra) + ); DEFINE(TASK_THREAD_F0_F0, offsetof(struct task_struct, thread.fstate.f[0]) @@ -493,6 +498,12 @@ void asm_offsets(void) DEFINE(STACKFRAME_SIZE_ON_STACK, ALIGN(sizeof(struct stackframe), STACK_ALIGN)); OFFSET(STACKFRAME_FP, stackframe, fp); OFFSET(STACKFRAME_RA, stackframe, ra); +#ifdef CONFIG_FUNCTION_TRACER + DEFINE(FTRACE_OPS_FUNC, offsetof(struct ftrace_ops, func)); +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS + DEFINE(FTRACE_OPS_DIRECT_CALL, offsetof(struct ftrace_ops, direct_call)); +#endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */ +#endif #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS DEFINE(FREGS_SIZE_ON_STACK, ALIGN(sizeof(struct __arch_ftrace_regs), STACK_ALIGN)); @@ -501,6 +512,13 @@ void asm_offsets(void) DEFINE(FREGS_SP, offsetof(struct __arch_ftrace_regs, sp)); DEFINE(FREGS_S0, offsetof(struct __arch_ftrace_regs, s0)); DEFINE(FREGS_T1, offsetof(struct __arch_ftrace_regs, t1)); +#ifdef CONFIG_CC_IS_CLANG + DEFINE(FREGS_T2, offsetof(struct __arch_ftrace_regs, t2)); + DEFINE(FREGS_T3, offsetof(struct __arch_ftrace_regs, t3)); + DEFINE(FREGS_T4, offsetof(struct __arch_ftrace_regs, t4)); + DEFINE(FREGS_T5, offsetof(struct __arch_ftrace_regs, t5)); + DEFINE(FREGS_T6, offsetof(struct __arch_ftrace_regs, t6)); +#endif DEFINE(FREGS_A0, offsetof(struct __arch_ftrace_regs, a0)); DEFINE(FREGS_A1, offsetof(struct __arch_ftrace_regs, a1)); DEFINE(FREGS_A2, offsetof(struct __arch_ftrace_regs, a2)); diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c index 2054f6c4b0ae..743d53415572 100644 --- a/arch/riscv/kernel/cpufeature.c +++ b/arch/riscv/kernel/cpufeature.c @@ -32,6 +32,7 @@ #define NUM_ALPHA_EXTS ('z' - 'a' + 1) static bool any_cpu_has_zicboz; +static bool any_cpu_has_zicbop; static bool any_cpu_has_zicbom; unsigned long elf_hwcap __read_mostly; @@ -119,6 +120,21 @@ static int riscv_ext_zicboz_validate(const struct riscv_isa_ext_data *data, return 0; } +static int riscv_ext_zicbop_validate(const struct riscv_isa_ext_data *data, + const unsigned long *isa_bitmap) +{ + if (!riscv_cbop_block_size) { + pr_err("Zicbop detected in ISA string, disabling as no cbop-block-size found\n"); + return -EINVAL; + } + if (!is_power_of_2(riscv_cbop_block_size)) { + pr_err("Zicbop disabled as cbop-block-size present, but is not a power-of-2\n"); + return -EINVAL; + } + any_cpu_has_zicbop = true; + return 0; +} + static int riscv_ext_f_validate(const struct riscv_isa_ext_data *data, const unsigned long *isa_bitmap) { @@ -442,6 +458,7 @@ const struct riscv_isa_ext_data riscv_isa_ext[] = { __RISCV_ISA_EXT_SUPERSET_VALIDATE(v, RISCV_ISA_EXT_v, riscv_v_exts, riscv_ext_vector_float_validate), __RISCV_ISA_EXT_DATA(h, RISCV_ISA_EXT_h), __RISCV_ISA_EXT_SUPERSET_VALIDATE(zicbom, RISCV_ISA_EXT_ZICBOM, riscv_xlinuxenvcfg_exts, riscv_ext_zicbom_validate), + __RISCV_ISA_EXT_DATA_VALIDATE(zicbop, RISCV_ISA_EXT_ZICBOP, riscv_ext_zicbop_validate), __RISCV_ISA_EXT_SUPERSET_VALIDATE(zicboz, RISCV_ISA_EXT_ZICBOZ, riscv_xlinuxenvcfg_exts, riscv_ext_zicboz_validate), __RISCV_ISA_EXT_DATA(ziccrse, RISCV_ISA_EXT_ZICCRSE), __RISCV_ISA_EXT_DATA(zicntr, RISCV_ISA_EXT_ZICNTR), @@ -1112,6 +1129,10 @@ void __init riscv_user_isa_enable(void) current->thread.envcfg |= ENVCFG_CBCFE; else if (any_cpu_has_zicbom) pr_warn("Zicbom disabled as it is unavailable on some harts\n"); + + if (!riscv_has_extension_unlikely(RISCV_ISA_EXT_ZICBOP) && + any_cpu_has_zicbop) + pr_warn("Zicbop disabled as it is unavailable on some harts\n"); } #ifdef CONFIG_RISCV_ALTERNATIVE diff --git a/arch/riscv/kernel/elf_kexec.c b/arch/riscv/kernel/elf_kexec.c deleted file mode 100644 index e783a72d051f..000000000000 --- a/arch/riscv/kernel/elf_kexec.c +++ /dev/null @@ -1,485 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Load ELF vmlinux file for the kexec_file_load syscall. - * - * Copyright (C) 2021 Huawei Technologies Co, Ltd. - * - * Author: Liao Chang (liaochang1@huawei.com) - * - * Based on kexec-tools' kexec-elf-riscv.c, heavily modified - * for kernel. - */ - -#define pr_fmt(fmt) "kexec_image: " fmt - -#include <linux/elf.h> -#include <linux/kexec.h> -#include <linux/slab.h> -#include <linux/of.h> -#include <linux/libfdt.h> -#include <linux/types.h> -#include <linux/memblock.h> -#include <linux/vmalloc.h> -#include <asm/setup.h> - -int arch_kimage_file_post_load_cleanup(struct kimage *image) -{ - kvfree(image->arch.fdt); - image->arch.fdt = NULL; - - vfree(image->elf_headers); - image->elf_headers = NULL; - image->elf_headers_sz = 0; - - return kexec_image_post_load_cleanup_default(image); -} - -static int riscv_kexec_elf_load(struct kimage *image, struct elfhdr *ehdr, - struct kexec_elf_info *elf_info, unsigned long old_pbase, - unsigned long new_pbase) -{ - int i; - int ret = 0; - size_t size; - struct kexec_buf kbuf; - const struct elf_phdr *phdr; - - kbuf.image = image; - - for (i = 0; i < ehdr->e_phnum; i++) { - phdr = &elf_info->proghdrs[i]; - if (phdr->p_type != PT_LOAD) - continue; - - size = phdr->p_filesz; - if (size > phdr->p_memsz) - size = phdr->p_memsz; - - kbuf.buffer = (void *) elf_info->buffer + phdr->p_offset; - kbuf.bufsz = size; - kbuf.buf_align = phdr->p_align; - kbuf.mem = phdr->p_paddr - old_pbase + new_pbase; - kbuf.memsz = phdr->p_memsz; - kbuf.top_down = false; - ret = kexec_add_buffer(&kbuf); - if (ret) - break; - } - - return ret; -} - -/* - * Go through the available phsyical memory regions and find one that hold - * an image of the specified size. - */ -static int elf_find_pbase(struct kimage *image, unsigned long kernel_len, - struct elfhdr *ehdr, struct kexec_elf_info *elf_info, - unsigned long *old_pbase, unsigned long *new_pbase) -{ - int i; - int ret; - struct kexec_buf kbuf; - const struct elf_phdr *phdr; - unsigned long lowest_paddr = ULONG_MAX; - unsigned long lowest_vaddr = ULONG_MAX; - - for (i = 0; i < ehdr->e_phnum; i++) { - phdr = &elf_info->proghdrs[i]; - if (phdr->p_type != PT_LOAD) - continue; - - if (lowest_paddr > phdr->p_paddr) - lowest_paddr = phdr->p_paddr; - - if (lowest_vaddr > phdr->p_vaddr) - lowest_vaddr = phdr->p_vaddr; - } - - kbuf.image = image; - kbuf.buf_min = lowest_paddr; - kbuf.buf_max = ULONG_MAX; - - /* - * Current riscv boot protocol requires 2MB alignment for - * RV64 and 4MB alignment for RV32 - * - */ - kbuf.buf_align = PMD_SIZE; - kbuf.mem = KEXEC_BUF_MEM_UNKNOWN; - kbuf.memsz = ALIGN(kernel_len, PAGE_SIZE); - kbuf.top_down = false; - ret = arch_kexec_locate_mem_hole(&kbuf); - if (!ret) { - *old_pbase = lowest_paddr; - *new_pbase = kbuf.mem; - image->start = ehdr->e_entry - lowest_vaddr + kbuf.mem; - } - return ret; -} - -#ifdef CONFIG_CRASH_DUMP -static int get_nr_ram_ranges_callback(struct resource *res, void *arg) -{ - unsigned int *nr_ranges = arg; - - (*nr_ranges)++; - return 0; -} - -static int prepare_elf64_ram_headers_callback(struct resource *res, void *arg) -{ - struct crash_mem *cmem = arg; - - cmem->ranges[cmem->nr_ranges].start = res->start; - cmem->ranges[cmem->nr_ranges].end = res->end; - cmem->nr_ranges++; - - return 0; -} - -static int prepare_elf_headers(void **addr, unsigned long *sz) -{ - struct crash_mem *cmem; - unsigned int nr_ranges; - int ret; - - nr_ranges = 1; /* For exclusion of crashkernel region */ - walk_system_ram_res(0, -1, &nr_ranges, get_nr_ram_ranges_callback); - - cmem = kmalloc(struct_size(cmem, ranges, nr_ranges), GFP_KERNEL); - if (!cmem) - return -ENOMEM; - - cmem->max_nr_ranges = nr_ranges; - cmem->nr_ranges = 0; - ret = walk_system_ram_res(0, -1, cmem, prepare_elf64_ram_headers_callback); - if (ret) - goto out; - - /* Exclude crashkernel region */ - ret = crash_exclude_mem_range(cmem, crashk_res.start, crashk_res.end); - if (!ret) - ret = crash_prepare_elf64_headers(cmem, true, addr, sz); - -out: - kfree(cmem); - return ret; -} - -static char *setup_kdump_cmdline(struct kimage *image, char *cmdline, - unsigned long cmdline_len) -{ - int elfcorehdr_strlen; - char *cmdline_ptr; - - cmdline_ptr = kzalloc(COMMAND_LINE_SIZE, GFP_KERNEL); - if (!cmdline_ptr) - return NULL; - - elfcorehdr_strlen = sprintf(cmdline_ptr, "elfcorehdr=0x%lx ", - image->elf_load_addr); - - if (elfcorehdr_strlen + cmdline_len > COMMAND_LINE_SIZE) { - pr_err("Appending elfcorehdr=<addr> exceeds cmdline size\n"); - kfree(cmdline_ptr); - return NULL; - } - - memcpy(cmdline_ptr + elfcorehdr_strlen, cmdline, cmdline_len); - /* Ensure it's nul terminated */ - cmdline_ptr[COMMAND_LINE_SIZE - 1] = '\0'; - return cmdline_ptr; -} -#endif - -static void *elf_kexec_load(struct kimage *image, char *kernel_buf, - unsigned long kernel_len, char *initrd, - unsigned long initrd_len, char *cmdline, - unsigned long cmdline_len) -{ - int ret; - void *fdt; - unsigned long old_kernel_pbase = ULONG_MAX; - unsigned long new_kernel_pbase = 0UL; - unsigned long initrd_pbase = 0UL; - unsigned long kernel_start; - struct elfhdr ehdr; - struct kexec_buf kbuf; - struct kexec_elf_info elf_info; - char *modified_cmdline = NULL; - - ret = kexec_build_elf_info(kernel_buf, kernel_len, &ehdr, &elf_info); - if (ret) - return ERR_PTR(ret); - - ret = elf_find_pbase(image, kernel_len, &ehdr, &elf_info, - &old_kernel_pbase, &new_kernel_pbase); - if (ret) - goto out; - kernel_start = image->start; - - /* Add the kernel binary to the image */ - ret = riscv_kexec_elf_load(image, &ehdr, &elf_info, - old_kernel_pbase, new_kernel_pbase); - if (ret) - goto out; - - kbuf.image = image; - kbuf.buf_min = new_kernel_pbase + kernel_len; - kbuf.buf_max = ULONG_MAX; - -#ifdef CONFIG_CRASH_DUMP - /* Add elfcorehdr */ - if (image->type == KEXEC_TYPE_CRASH) { - void *headers; - unsigned long headers_sz; - ret = prepare_elf_headers(&headers, &headers_sz); - if (ret) { - pr_err("Preparing elf core header failed\n"); - goto out; - } - - kbuf.buffer = headers; - kbuf.bufsz = headers_sz; - kbuf.mem = KEXEC_BUF_MEM_UNKNOWN; - kbuf.memsz = headers_sz; - kbuf.buf_align = ELF_CORE_HEADER_ALIGN; - kbuf.top_down = true; - - ret = kexec_add_buffer(&kbuf); - if (ret) { - vfree(headers); - goto out; - } - image->elf_headers = headers; - image->elf_load_addr = kbuf.mem; - image->elf_headers_sz = headers_sz; - - kexec_dprintk("Loaded elf core header at 0x%lx bufsz=0x%lx memsz=0x%lx\n", - image->elf_load_addr, kbuf.bufsz, kbuf.memsz); - - /* Setup cmdline for kdump kernel case */ - modified_cmdline = setup_kdump_cmdline(image, cmdline, - cmdline_len); - if (!modified_cmdline) { - pr_err("Setting up cmdline for kdump kernel failed\n"); - ret = -EINVAL; - goto out; - } - cmdline = modified_cmdline; - } -#endif - -#ifdef CONFIG_ARCH_SUPPORTS_KEXEC_PURGATORY - /* Add purgatory to the image */ - kbuf.top_down = true; - kbuf.mem = KEXEC_BUF_MEM_UNKNOWN; - ret = kexec_load_purgatory(image, &kbuf); - if (ret) { - pr_err("Error loading purgatory ret=%d\n", ret); - goto out; - } - kexec_dprintk("Loaded purgatory at 0x%lx\n", kbuf.mem); - - ret = kexec_purgatory_get_set_symbol(image, "riscv_kernel_entry", - &kernel_start, - sizeof(kernel_start), 0); - if (ret) - pr_err("Error update purgatory ret=%d\n", ret); -#endif /* CONFIG_ARCH_SUPPORTS_KEXEC_PURGATORY */ - - /* Add the initrd to the image */ - if (initrd != NULL) { - kbuf.buffer = initrd; - kbuf.bufsz = kbuf.memsz = initrd_len; - kbuf.buf_align = PAGE_SIZE; - kbuf.top_down = true; - kbuf.mem = KEXEC_BUF_MEM_UNKNOWN; - ret = kexec_add_buffer(&kbuf); - if (ret) - goto out; - initrd_pbase = kbuf.mem; - kexec_dprintk("Loaded initrd at 0x%lx\n", initrd_pbase); - } - - /* Add the DTB to the image */ - fdt = of_kexec_alloc_and_setup_fdt(image, initrd_pbase, - initrd_len, cmdline, 0); - if (!fdt) { - pr_err("Error setting up the new device tree.\n"); - ret = -EINVAL; - goto out; - } - - fdt_pack(fdt); - kbuf.buffer = fdt; - kbuf.bufsz = kbuf.memsz = fdt_totalsize(fdt); - kbuf.buf_align = PAGE_SIZE; - kbuf.mem = KEXEC_BUF_MEM_UNKNOWN; - kbuf.top_down = true; - ret = kexec_add_buffer(&kbuf); - if (ret) { - pr_err("Error add DTB kbuf ret=%d\n", ret); - goto out_free_fdt; - } - /* Cache the fdt buffer address for memory cleanup */ - image->arch.fdt = fdt; - kexec_dprintk("Loaded device tree at 0x%lx\n", kbuf.mem); - goto out; - -out_free_fdt: - kvfree(fdt); -out: - kfree(modified_cmdline); - kexec_free_elf_info(&elf_info); - return ret ? ERR_PTR(ret) : NULL; -} - -#define RV_X(x, s, n) (((x) >> (s)) & ((1 << (n)) - 1)) -#define RISCV_IMM_BITS 12 -#define RISCV_IMM_REACH (1LL << RISCV_IMM_BITS) -#define RISCV_CONST_HIGH_PART(x) \ - (((x) + (RISCV_IMM_REACH >> 1)) & ~(RISCV_IMM_REACH - 1)) -#define RISCV_CONST_LOW_PART(x) ((x) - RISCV_CONST_HIGH_PART(x)) - -#define ENCODE_ITYPE_IMM(x) \ - (RV_X(x, 0, 12) << 20) -#define ENCODE_BTYPE_IMM(x) \ - ((RV_X(x, 1, 4) << 8) | (RV_X(x, 5, 6) << 25) | \ - (RV_X(x, 11, 1) << 7) | (RV_X(x, 12, 1) << 31)) -#define ENCODE_UTYPE_IMM(x) \ - (RV_X(x, 12, 20) << 12) -#define ENCODE_JTYPE_IMM(x) \ - ((RV_X(x, 1, 10) << 21) | (RV_X(x, 11, 1) << 20) | \ - (RV_X(x, 12, 8) << 12) | (RV_X(x, 20, 1) << 31)) -#define ENCODE_CBTYPE_IMM(x) \ - ((RV_X(x, 1, 2) << 3) | (RV_X(x, 3, 2) << 10) | (RV_X(x, 5, 1) << 2) | \ - (RV_X(x, 6, 2) << 5) | (RV_X(x, 8, 1) << 12)) -#define ENCODE_CJTYPE_IMM(x) \ - ((RV_X(x, 1, 3) << 3) | (RV_X(x, 4, 1) << 11) | (RV_X(x, 5, 1) << 2) | \ - (RV_X(x, 6, 1) << 7) | (RV_X(x, 7, 1) << 6) | (RV_X(x, 8, 2) << 9) | \ - (RV_X(x, 10, 1) << 8) | (RV_X(x, 11, 1) << 12)) -#define ENCODE_UJTYPE_IMM(x) \ - (ENCODE_UTYPE_IMM(RISCV_CONST_HIGH_PART(x)) | \ - (ENCODE_ITYPE_IMM(RISCV_CONST_LOW_PART(x)) << 32)) -#define ENCODE_UITYPE_IMM(x) \ - (ENCODE_UTYPE_IMM(x) | (ENCODE_ITYPE_IMM(x) << 32)) - -#define CLEAN_IMM(type, x) \ - ((~ENCODE_##type##_IMM((uint64_t)(-1))) & (x)) - -int arch_kexec_apply_relocations_add(struct purgatory_info *pi, - Elf_Shdr *section, - const Elf_Shdr *relsec, - const Elf_Shdr *symtab) -{ - const char *strtab, *name, *shstrtab; - const Elf_Shdr *sechdrs; - Elf64_Rela *relas; - int i, r_type; - - /* String & section header string table */ - sechdrs = (void *)pi->ehdr + pi->ehdr->e_shoff; - strtab = (char *)pi->ehdr + sechdrs[symtab->sh_link].sh_offset; - shstrtab = (char *)pi->ehdr + sechdrs[pi->ehdr->e_shstrndx].sh_offset; - - relas = (void *)pi->ehdr + relsec->sh_offset; - - for (i = 0; i < relsec->sh_size / sizeof(*relas); i++) { - const Elf_Sym *sym; /* symbol to relocate */ - unsigned long addr; /* final location after relocation */ - unsigned long val; /* relocated symbol value */ - unsigned long sec_base; /* relocated symbol value */ - void *loc; /* tmp location to modify */ - - sym = (void *)pi->ehdr + symtab->sh_offset; - sym += ELF64_R_SYM(relas[i].r_info); - - if (sym->st_name) - name = strtab + sym->st_name; - else - name = shstrtab + sechdrs[sym->st_shndx].sh_name; - - loc = pi->purgatory_buf; - loc += section->sh_offset; - loc += relas[i].r_offset; - - if (sym->st_shndx == SHN_ABS) - sec_base = 0; - else if (sym->st_shndx >= pi->ehdr->e_shnum) { - pr_err("Invalid section %d for symbol %s\n", - sym->st_shndx, name); - return -ENOEXEC; - } else - sec_base = pi->sechdrs[sym->st_shndx].sh_addr; - - val = sym->st_value; - val += sec_base; - val += relas[i].r_addend; - - addr = section->sh_addr + relas[i].r_offset; - - r_type = ELF64_R_TYPE(relas[i].r_info); - - switch (r_type) { - case R_RISCV_BRANCH: - *(u32 *)loc = CLEAN_IMM(BTYPE, *(u32 *)loc) | - ENCODE_BTYPE_IMM(val - addr); - break; - case R_RISCV_JAL: - *(u32 *)loc = CLEAN_IMM(JTYPE, *(u32 *)loc) | - ENCODE_JTYPE_IMM(val - addr); - break; - /* - * With no R_RISCV_PCREL_LO12_S, R_RISCV_PCREL_LO12_I - * sym is expected to be next to R_RISCV_PCREL_HI20 - * in purgatory relsec. Handle it like R_RISCV_CALL - * sym, instead of searching the whole relsec. - */ - case R_RISCV_PCREL_HI20: - case R_RISCV_CALL_PLT: - case R_RISCV_CALL: - *(u64 *)loc = CLEAN_IMM(UITYPE, *(u64 *)loc) | - ENCODE_UJTYPE_IMM(val - addr); - break; - case R_RISCV_RVC_BRANCH: - *(u32 *)loc = CLEAN_IMM(CBTYPE, *(u32 *)loc) | - ENCODE_CBTYPE_IMM(val - addr); - break; - case R_RISCV_RVC_JUMP: - *(u32 *)loc = CLEAN_IMM(CJTYPE, *(u32 *)loc) | - ENCODE_CJTYPE_IMM(val - addr); - break; - case R_RISCV_ADD16: - *(u16 *)loc += val; - break; - case R_RISCV_SUB16: - *(u16 *)loc -= val; - break; - case R_RISCV_ADD32: - *(u32 *)loc += val; - break; - case R_RISCV_SUB32: - *(u32 *)loc -= val; - break; - /* It has been applied by R_RISCV_PCREL_HI20 sym */ - case R_RISCV_PCREL_LO12_I: - case R_RISCV_ALIGN: - case R_RISCV_RELAX: - break; - case R_RISCV_64: - *(u64 *)loc = val; - break; - default: - pr_err("Unknown rela relocation: %d\n", r_type); - return -ENOEXEC; - } - } - return 0; -} - -const struct kexec_file_ops elf_kexec_ops = { - .probe = kexec_elf_probe, - .load = elf_kexec_load, -}; diff --git a/arch/riscv/kernel/entry.S b/arch/riscv/kernel/entry.S index 0fb338000c6d..75656afa2d6b 100644 --- a/arch/riscv/kernel/entry.S +++ b/arch/riscv/kernel/entry.S @@ -401,9 +401,18 @@ SYM_FUNC_START(__switch_to) REG_S s9, TASK_THREAD_S9_RA(a3) REG_S s10, TASK_THREAD_S10_RA(a3) REG_S s11, TASK_THREAD_S11_RA(a3) + + /* save the user space access flag */ + csrr s0, CSR_STATUS + REG_S s0, TASK_THREAD_SUM_RA(a3) + /* Save the kernel shadow call stack pointer */ scs_save_current /* Restore context from next->thread */ + REG_L s0, TASK_THREAD_SUM_RA(a4) + li s1, SR_SUM + and s0, s0, s1 + csrs CSR_STATUS, s0 REG_L ra, TASK_THREAD_RA_RA(a4) REG_L sp, TASK_THREAD_SP_RA(a4) REG_L s0, TASK_THREAD_S0_RA(a4) diff --git a/arch/riscv/kernel/ftrace.c b/arch/riscv/kernel/ftrace.c index 674dcdfae7a1..4c6c24380cfd 100644 --- a/arch/riscv/kernel/ftrace.c +++ b/arch/riscv/kernel/ftrace.c @@ -8,98 +8,129 @@ #include <linux/ftrace.h> #include <linux/uaccess.h> #include <linux/memory.h> +#include <linux/irqflags.h> #include <linux/stop_machine.h> #include <asm/cacheflush.h> #include <asm/text-patching.h> #ifdef CONFIG_DYNAMIC_FTRACE -void ftrace_arch_code_modify_prepare(void) __acquires(&text_mutex) +unsigned long ftrace_call_adjust(unsigned long addr) { - mutex_lock(&text_mutex); + if (IS_ENABLED(CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS)) + return addr + 8 + MCOUNT_AUIPC_SIZE; - /* - * The code sequences we use for ftrace can't be patched while the - * kernel is running, so we need to use stop_machine() to modify them - * for now. This doesn't play nice with text_mutex, we use this flag - * to elide the check. - */ - riscv_patch_in_stop_machine = true; + return addr + MCOUNT_AUIPC_SIZE; +} + +unsigned long arch_ftrace_get_symaddr(unsigned long fentry_ip) +{ + return fentry_ip - MCOUNT_AUIPC_SIZE; } -void ftrace_arch_code_modify_post_process(void) __releases(&text_mutex) +void arch_ftrace_update_code(int command) { - riscv_patch_in_stop_machine = false; + mutex_lock(&text_mutex); + command |= FTRACE_MAY_SLEEP; + ftrace_modify_all_code(command); mutex_unlock(&text_mutex); + flush_icache_all(); } -static int ftrace_check_current_call(unsigned long hook_pos, - unsigned int *expected) +static int __ftrace_modify_call(unsigned long source, unsigned long target, bool validate) { + unsigned int call[2], offset; unsigned int replaced[2]; - unsigned int nops[2] = {RISCV_INSN_NOP4, RISCV_INSN_NOP4}; - /* we expect nops at the hook position */ - if (!expected) - expected = nops; + offset = target - source; + call[1] = to_jalr_t0(offset); - /* - * Read the text we want to modify; - * return must be -EFAULT on read error - */ - if (copy_from_kernel_nofault(replaced, (void *)hook_pos, - MCOUNT_INSN_SIZE)) - return -EFAULT; - - /* - * Make sure it is what we expect it to be; - * return must be -EINVAL on failed comparison - */ - if (memcmp(expected, replaced, sizeof(replaced))) { - pr_err("%p: expected (%08x %08x) but got (%08x %08x)\n", - (void *)hook_pos, expected[0], expected[1], replaced[0], - replaced[1]); - return -EINVAL; + if (validate) { + call[0] = to_auipc_t0(offset); + /* + * Read the text we want to modify; + * return must be -EFAULT on read error + */ + if (copy_from_kernel_nofault(replaced, (void *)source, 2 * MCOUNT_INSN_SIZE)) + return -EFAULT; + + if (replaced[0] != call[0]) { + pr_err("%p: expected (%08x) but got (%08x)\n", + (void *)source, call[0], replaced[0]); + return -EINVAL; + } } + /* Replace the jalr at once. Return -EPERM on write error. */ + if (patch_insn_write((void *)(source + MCOUNT_AUIPC_SIZE), call + 1, MCOUNT_JALR_SIZE)) + return -EPERM; + return 0; } -static int __ftrace_modify_call(unsigned long hook_pos, unsigned long target, - bool enable, bool ra) +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS +static const struct ftrace_ops *riscv64_rec_get_ops(struct dyn_ftrace *rec) { - unsigned int call[2]; - unsigned int nops[2] = {RISCV_INSN_NOP4, RISCV_INSN_NOP4}; + const struct ftrace_ops *ops = NULL; - if (ra) - make_call_ra(hook_pos, target, call); - else - make_call_t0(hook_pos, target, call); + if (rec->flags & FTRACE_FL_CALL_OPS_EN) { + ops = ftrace_find_unique_ops(rec); + WARN_ON_ONCE(!ops); + } - /* Replace the auipc-jalr pair at once. Return -EPERM on write error. */ - if (patch_insn_write((void *)hook_pos, enable ? call : nops, MCOUNT_INSN_SIZE)) - return -EPERM; + if (!ops) + ops = &ftrace_list_ops; - return 0; + return ops; +} + +static int ftrace_rec_set_ops(const struct dyn_ftrace *rec, const struct ftrace_ops *ops) +{ + unsigned long literal = ALIGN_DOWN(rec->ip - 12, 8); + + return patch_text_nosync((void *)literal, &ops, sizeof(ops)); +} + +static int ftrace_rec_set_nop_ops(struct dyn_ftrace *rec) +{ + return ftrace_rec_set_ops(rec, &ftrace_nop_ops); +} + +static int ftrace_rec_update_ops(struct dyn_ftrace *rec) +{ + return ftrace_rec_set_ops(rec, riscv64_rec_get_ops(rec)); } +#else +static int ftrace_rec_set_nop_ops(struct dyn_ftrace *rec) { return 0; } +static int ftrace_rec_update_ops(struct dyn_ftrace *rec) { return 0; } +#endif int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) { - unsigned int call[2]; + unsigned long distance, orig_addr, pc = rec->ip - MCOUNT_AUIPC_SIZE; + int ret; - make_call_t0(rec->ip, addr, call); + ret = ftrace_rec_update_ops(rec); + if (ret) + return ret; - if (patch_insn_write((void *)rec->ip, call, MCOUNT_INSN_SIZE)) - return -EPERM; + orig_addr = (unsigned long)&ftrace_caller; + distance = addr > orig_addr ? addr - orig_addr : orig_addr - addr; + if (distance > JALR_RANGE) + addr = FTRACE_ADDR; - return 0; + return __ftrace_modify_call(pc, addr, false); } -int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec, - unsigned long addr) +int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec, unsigned long addr) { - unsigned int nops[2] = {RISCV_INSN_NOP4, RISCV_INSN_NOP4}; + u32 nop4 = RISCV_INSN_NOP4; + int ret; - if (patch_insn_write((void *)rec->ip, nops, MCOUNT_INSN_SIZE)) + ret = ftrace_rec_set_nop_ops(rec); + if (ret) + return ret; + + if (patch_insn_write((void *)rec->ip, &nop4, MCOUNT_NOP4_SIZE)) return -EPERM; return 0; @@ -114,75 +145,71 @@ int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec, */ int ftrace_init_nop(struct module *mod, struct dyn_ftrace *rec) { - int out; + unsigned long pc = rec->ip - MCOUNT_AUIPC_SIZE; + unsigned int nops[2], offset; + int ret; - mutex_lock(&text_mutex); - out = ftrace_make_nop(mod, rec, MCOUNT_ADDR); - mutex_unlock(&text_mutex); + ret = ftrace_rec_set_nop_ops(rec); + if (ret) + return ret; - return out; -} + offset = (unsigned long) &ftrace_caller - pc; + nops[0] = to_auipc_t0(offset); + nops[1] = RISCV_INSN_NOP4; -int ftrace_update_ftrace_func(ftrace_func_t func) -{ - int ret = __ftrace_modify_call((unsigned long)&ftrace_call, - (unsigned long)func, true, true); + mutex_lock(&text_mutex); + ret = patch_insn_write((void *)pc, nops, 2 * MCOUNT_INSN_SIZE); + mutex_unlock(&text_mutex); return ret; } -struct ftrace_modify_param { - int command; - atomic_t cpu_count; -}; - -static int __ftrace_modify_code(void *data) +ftrace_func_t ftrace_call_dest = ftrace_stub; +int ftrace_update_ftrace_func(ftrace_func_t func) { - struct ftrace_modify_param *param = data; - - if (atomic_inc_return(¶m->cpu_count) == num_online_cpus()) { - ftrace_modify_all_code(param->command); - /* - * Make sure the patching store is effective *before* we - * increment the counter which releases all waiting CPUs - * by using the release variant of atomic increment. The - * release pairs with the call to local_flush_icache_all() - * on the waiting CPU. - */ - atomic_inc_return_release(¶m->cpu_count); - } else { - while (atomic_read(¶m->cpu_count) <= num_online_cpus()) - cpu_relax(); - - local_flush_icache_all(); - } + /* + * When using CALL_OPS, the function to call is associated with the + * call site, and we don't have a global function pointer to update. + */ + if (IS_ENABLED(CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS)) + return 0; + WRITE_ONCE(ftrace_call_dest, func); + /* + * The data fence ensure that the update to ftrace_call_dest happens + * before the write to function_trace_op later in the generic ftrace. + * If the sequence is not enforced, then an old ftrace_call_dest may + * race loading a new function_trace_op set in ftrace_modify_all_code + */ + smp_wmb(); + /* + * Updating ftrace dpes not take stop_machine path, so irqs should not + * be disabled. + */ + WARN_ON(irqs_disabled()); + smp_call_function(ftrace_sync_ipi, NULL, 1); return 0; } -void arch_ftrace_update_code(int command) +#else /* CONFIG_DYNAMIC_FTRACE */ +unsigned long ftrace_call_adjust(unsigned long addr) { - struct ftrace_modify_param param = { command, ATOMIC_INIT(0) }; - - stop_machine(__ftrace_modify_code, ¶m, cpu_online_mask); + return addr; } -#endif +#endif /* CONFIG_DYNAMIC_FTRACE */ #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr, unsigned long addr) { - unsigned int call[2]; - unsigned long caller = rec->ip; + unsigned long caller = rec->ip - MCOUNT_AUIPC_SIZE; int ret; - make_call_t0(caller, old_addr, call); - ret = ftrace_check_current_call(caller, call); - + ret = ftrace_rec_update_ops(rec); if (ret) return ret; - return __ftrace_modify_call(caller, addr, true, false); + return __ftrace_modify_call(caller, FTRACE_ADDR, true); } #endif @@ -210,7 +237,6 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr, } #ifdef CONFIG_DYNAMIC_FTRACE -#ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS void ftrace_graph_func(unsigned long ip, unsigned long parent_ip, struct ftrace_ops *op, struct ftrace_regs *fregs) { @@ -231,19 +257,5 @@ void ftrace_graph_func(unsigned long ip, unsigned long parent_ip, if (!function_graph_enter_regs(old, ip, frame_pointer, parent, fregs)) *parent = return_hooker; } -#else /* CONFIG_DYNAMIC_FTRACE_WITH_ARGS */ -extern void ftrace_graph_call(void); -int ftrace_enable_ftrace_graph_caller(void) -{ - return __ftrace_modify_call((unsigned long)&ftrace_graph_call, - (unsigned long)&prepare_ftrace_return, true, true); -} - -int ftrace_disable_ftrace_graph_caller(void) -{ - return __ftrace_modify_call((unsigned long)&ftrace_graph_call, - (unsigned long)&prepare_ftrace_return, false, true); -} -#endif /* CONFIG_DYNAMIC_FTRACE_WITH_ARGS */ #endif /* CONFIG_DYNAMIC_FTRACE */ #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ diff --git a/arch/riscv/kernel/kexec_elf.c b/arch/riscv/kernel/kexec_elf.c new file mode 100644 index 000000000000..f4755d49b89e --- /dev/null +++ b/arch/riscv/kernel/kexec_elf.c @@ -0,0 +1,144 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Load ELF vmlinux file for the kexec_file_load syscall. + * + * Copyright (C) 2021 Huawei Technologies Co, Ltd. + * + * Author: Liao Chang (liaochang1@huawei.com) + * + * Based on kexec-tools' kexec-elf-riscv.c, heavily modified + * for kernel. + */ + +#define pr_fmt(fmt) "kexec_image: " fmt + +#include <linux/elf.h> +#include <linux/kexec.h> +#include <linux/slab.h> +#include <linux/of.h> +#include <linux/libfdt.h> +#include <linux/types.h> +#include <linux/memblock.h> +#include <asm/setup.h> + +static int riscv_kexec_elf_load(struct kimage *image, struct elfhdr *ehdr, + struct kexec_elf_info *elf_info, unsigned long old_pbase, + unsigned long new_pbase) +{ + int i; + int ret = 0; + size_t size; + struct kexec_buf kbuf; + const struct elf_phdr *phdr; + + kbuf.image = image; + + for (i = 0; i < ehdr->e_phnum; i++) { + phdr = &elf_info->proghdrs[i]; + if (phdr->p_type != PT_LOAD) + continue; + + size = phdr->p_filesz; + if (size > phdr->p_memsz) + size = phdr->p_memsz; + + kbuf.buffer = (void *) elf_info->buffer + phdr->p_offset; + kbuf.bufsz = size; + kbuf.buf_align = phdr->p_align; + kbuf.mem = phdr->p_paddr - old_pbase + new_pbase; + kbuf.memsz = phdr->p_memsz; + kbuf.top_down = false; + ret = kexec_add_buffer(&kbuf); + if (ret) + break; + } + + return ret; +} + +/* + * Go through the available phsyical memory regions and find one that hold + * an image of the specified size. + */ +static int elf_find_pbase(struct kimage *image, unsigned long kernel_len, + struct elfhdr *ehdr, struct kexec_elf_info *elf_info, + unsigned long *old_pbase, unsigned long *new_pbase) +{ + int i; + int ret; + struct kexec_buf kbuf; + const struct elf_phdr *phdr; + unsigned long lowest_paddr = ULONG_MAX; + unsigned long lowest_vaddr = ULONG_MAX; + + for (i = 0; i < ehdr->e_phnum; i++) { + phdr = &elf_info->proghdrs[i]; + if (phdr->p_type != PT_LOAD) + continue; + + if (lowest_paddr > phdr->p_paddr) + lowest_paddr = phdr->p_paddr; + + if (lowest_vaddr > phdr->p_vaddr) + lowest_vaddr = phdr->p_vaddr; + } + + kbuf.image = image; + kbuf.buf_min = lowest_paddr; + kbuf.buf_max = ULONG_MAX; + + /* + * Current riscv boot protocol requires 2MB alignment for + * RV64 and 4MB alignment for RV32 + * + */ + kbuf.buf_align = PMD_SIZE; + kbuf.mem = KEXEC_BUF_MEM_UNKNOWN; + kbuf.memsz = ALIGN(kernel_len, PAGE_SIZE); + kbuf.top_down = false; + ret = arch_kexec_locate_mem_hole(&kbuf); + if (!ret) { + *old_pbase = lowest_paddr; + *new_pbase = kbuf.mem; + image->start = ehdr->e_entry - lowest_vaddr + kbuf.mem; + } + return ret; +} + +static void *elf_kexec_load(struct kimage *image, char *kernel_buf, + unsigned long kernel_len, char *initrd, + unsigned long initrd_len, char *cmdline, + unsigned long cmdline_len) +{ + int ret; + unsigned long old_kernel_pbase = ULONG_MAX; + unsigned long new_kernel_pbase = 0UL; + struct elfhdr ehdr; + struct kexec_elf_info elf_info; + + ret = kexec_build_elf_info(kernel_buf, kernel_len, &ehdr, &elf_info); + if (ret) + return ERR_PTR(ret); + + ret = elf_find_pbase(image, kernel_len, &ehdr, &elf_info, + &old_kernel_pbase, &new_kernel_pbase); + if (ret) + goto out; + + /* Add the kernel binary to the image */ + ret = riscv_kexec_elf_load(image, &ehdr, &elf_info, + old_kernel_pbase, new_kernel_pbase); + if (ret) + goto out; + + ret = load_extra_segments(image, image->start, kernel_len, + initrd, initrd_len, cmdline, cmdline_len); +out: + kexec_free_elf_info(&elf_info); + return ret ? ERR_PTR(ret) : NULL; +} + +const struct kexec_file_ops elf_kexec_ops = { + .probe = kexec_elf_probe, + .load = elf_kexec_load, +}; diff --git a/arch/riscv/kernel/kexec_image.c b/arch/riscv/kernel/kexec_image.c new file mode 100644 index 000000000000..26a81774a78a --- /dev/null +++ b/arch/riscv/kernel/kexec_image.c @@ -0,0 +1,96 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * RISC-V Kexec image loader + * + */ + +#define pr_fmt(fmt) "kexec_file(Image): " fmt + +#include <linux/err.h> +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/kexec.h> +#include <linux/pe.h> +#include <linux/string.h> +#include <asm/byteorder.h> +#include <asm/image.h> + +static int image_probe(const char *kernel_buf, unsigned long kernel_len) +{ + const struct riscv_image_header *h = (const struct riscv_image_header *)kernel_buf; + + if (!h || kernel_len < sizeof(*h)) + return -EINVAL; + + /* According to Documentation/riscv/boot-image-header.rst, + * use "magic2" field to check when version >= 0.2. + */ + + if (h->version >= RISCV_HEADER_VERSION && + memcmp(&h->magic2, RISCV_IMAGE_MAGIC2, sizeof(h->magic2))) + return -EINVAL; + + return 0; +} + +static void *image_load(struct kimage *image, + char *kernel, unsigned long kernel_len, + char *initrd, unsigned long initrd_len, + char *cmdline, unsigned long cmdline_len) +{ + struct riscv_image_header *h; + u64 flags; + bool be_image, be_kernel; + struct kexec_buf kbuf; + int ret; + + /* Check Image header */ + h = (struct riscv_image_header *)kernel; + if (!h->image_size) { + ret = -EINVAL; + goto out; + } + + /* Check endianness */ + flags = le64_to_cpu(h->flags); + be_image = riscv_image_flag_field(flags, RISCV_IMAGE_FLAG_BE); + be_kernel = IS_ENABLED(CONFIG_CPU_BIG_ENDIAN); + if (be_image != be_kernel) { + ret = -EINVAL; + goto out; + } + + /* Load the kernel image */ + kbuf.image = image; + kbuf.buf_min = 0; + kbuf.buf_max = ULONG_MAX; + kbuf.top_down = false; + + kbuf.buffer = kernel; + kbuf.bufsz = kernel_len; + kbuf.mem = KEXEC_BUF_MEM_UNKNOWN; + kbuf.memsz = le64_to_cpu(h->image_size); + kbuf.buf_align = le64_to_cpu(h->text_offset); + + ret = kexec_add_buffer(&kbuf); + if (ret) { + pr_err("Error add kernel image ret=%d\n", ret); + goto out; + } + + image->start = kbuf.mem; + + pr_info("Loaded kernel at 0x%lx bufsz=0x%lx memsz=0x%lx\n", + kbuf.mem, kbuf.bufsz, kbuf.memsz); + + ret = load_extra_segments(image, kbuf.mem, kbuf.memsz, + initrd, initrd_len, cmdline, cmdline_len); + +out: + return ret ? ERR_PTR(ret) : NULL; +} + +const struct kexec_file_ops image_kexec_ops = { + .probe = image_probe, + .load = image_load, +}; diff --git a/arch/riscv/kernel/machine_kexec_file.c b/arch/riscv/kernel/machine_kexec_file.c index b0bf8c1722c0..e36104af2e24 100644 --- a/arch/riscv/kernel/machine_kexec_file.c +++ b/arch/riscv/kernel/machine_kexec_file.c @@ -7,8 +7,369 @@ * Author: Liao Chang (liaochang1@huawei.com) */ #include <linux/kexec.h> +#include <linux/elf.h> +#include <linux/slab.h> +#include <linux/of.h> +#include <linux/libfdt.h> +#include <linux/types.h> +#include <linux/memblock.h> +#include <linux/vmalloc.h> +#include <asm/setup.h> const struct kexec_file_ops * const kexec_file_loaders[] = { &elf_kexec_ops, + &image_kexec_ops, NULL }; + +int arch_kimage_file_post_load_cleanup(struct kimage *image) +{ + kvfree(image->arch.fdt); + image->arch.fdt = NULL; + + vfree(image->elf_headers); + image->elf_headers = NULL; + image->elf_headers_sz = 0; + + return kexec_image_post_load_cleanup_default(image); +} + +#ifdef CONFIG_CRASH_DUMP +static int get_nr_ram_ranges_callback(struct resource *res, void *arg) +{ + unsigned int *nr_ranges = arg; + + (*nr_ranges)++; + return 0; +} + +static int prepare_elf64_ram_headers_callback(struct resource *res, void *arg) +{ + struct crash_mem *cmem = arg; + + cmem->ranges[cmem->nr_ranges].start = res->start; + cmem->ranges[cmem->nr_ranges].end = res->end; + cmem->nr_ranges++; + + return 0; +} + +static int prepare_elf_headers(void **addr, unsigned long *sz) +{ + struct crash_mem *cmem; + unsigned int nr_ranges; + int ret; + + nr_ranges = 1; /* For exclusion of crashkernel region */ + walk_system_ram_res(0, -1, &nr_ranges, get_nr_ram_ranges_callback); + + cmem = kmalloc(struct_size(cmem, ranges, nr_ranges), GFP_KERNEL); + if (!cmem) + return -ENOMEM; + + cmem->max_nr_ranges = nr_ranges; + cmem->nr_ranges = 0; + ret = walk_system_ram_res(0, -1, cmem, prepare_elf64_ram_headers_callback); + if (ret) + goto out; + + /* Exclude crashkernel region */ + ret = crash_exclude_mem_range(cmem, crashk_res.start, crashk_res.end); + if (!ret) + ret = crash_prepare_elf64_headers(cmem, true, addr, sz); + +out: + kfree(cmem); + return ret; +} + +static char *setup_kdump_cmdline(struct kimage *image, char *cmdline, + unsigned long cmdline_len) +{ + int elfcorehdr_strlen; + char *cmdline_ptr; + + cmdline_ptr = kzalloc(COMMAND_LINE_SIZE, GFP_KERNEL); + if (!cmdline_ptr) + return NULL; + + elfcorehdr_strlen = sprintf(cmdline_ptr, "elfcorehdr=0x%lx ", + image->elf_load_addr); + + if (elfcorehdr_strlen + cmdline_len > COMMAND_LINE_SIZE) { + pr_err("Appending elfcorehdr=<addr> exceeds cmdline size\n"); + kfree(cmdline_ptr); + return NULL; + } + + memcpy(cmdline_ptr + elfcorehdr_strlen, cmdline, cmdline_len); + /* Ensure it's nul terminated */ + cmdline_ptr[COMMAND_LINE_SIZE - 1] = '\0'; + return cmdline_ptr; +} +#endif + +#define RV_X(x, s, n) (((x) >> (s)) & ((1 << (n)) - 1)) +#define RISCV_IMM_BITS 12 +#define RISCV_IMM_REACH (1LL << RISCV_IMM_BITS) +#define RISCV_CONST_HIGH_PART(x) \ + (((x) + (RISCV_IMM_REACH >> 1)) & ~(RISCV_IMM_REACH - 1)) +#define RISCV_CONST_LOW_PART(x) ((x) - RISCV_CONST_HIGH_PART(x)) + +#define ENCODE_ITYPE_IMM(x) \ + (RV_X(x, 0, 12) << 20) +#define ENCODE_BTYPE_IMM(x) \ + ((RV_X(x, 1, 4) << 8) | (RV_X(x, 5, 6) << 25) | \ + (RV_X(x, 11, 1) << 7) | (RV_X(x, 12, 1) << 31)) +#define ENCODE_UTYPE_IMM(x) \ + (RV_X(x, 12, 20) << 12) +#define ENCODE_JTYPE_IMM(x) \ + ((RV_X(x, 1, 10) << 21) | (RV_X(x, 11, 1) << 20) | \ + (RV_X(x, 12, 8) << 12) | (RV_X(x, 20, 1) << 31)) +#define ENCODE_CBTYPE_IMM(x) \ + ((RV_X(x, 1, 2) << 3) | (RV_X(x, 3, 2) << 10) | (RV_X(x, 5, 1) << 2) | \ + (RV_X(x, 6, 2) << 5) | (RV_X(x, 8, 1) << 12)) +#define ENCODE_CJTYPE_IMM(x) \ + ((RV_X(x, 1, 3) << 3) | (RV_X(x, 4, 1) << 11) | (RV_X(x, 5, 1) << 2) | \ + (RV_X(x, 6, 1) << 7) | (RV_X(x, 7, 1) << 6) | (RV_X(x, 8, 2) << 9) | \ + (RV_X(x, 10, 1) << 8) | (RV_X(x, 11, 1) << 12)) +#define ENCODE_UJTYPE_IMM(x) \ + (ENCODE_UTYPE_IMM(RISCV_CONST_HIGH_PART(x)) | \ + (ENCODE_ITYPE_IMM(RISCV_CONST_LOW_PART(x)) << 32)) +#define ENCODE_UITYPE_IMM(x) \ + (ENCODE_UTYPE_IMM(x) | (ENCODE_ITYPE_IMM(x) << 32)) + +#define CLEAN_IMM(type, x) \ + ((~ENCODE_##type##_IMM((uint64_t)(-1))) & (x)) + +int arch_kexec_apply_relocations_add(struct purgatory_info *pi, + Elf_Shdr *section, + const Elf_Shdr *relsec, + const Elf_Shdr *symtab) +{ + const char *strtab, *name, *shstrtab; + const Elf_Shdr *sechdrs; + Elf64_Rela *relas; + int i, r_type; + + /* String & section header string table */ + sechdrs = (void *)pi->ehdr + pi->ehdr->e_shoff; + strtab = (char *)pi->ehdr + sechdrs[symtab->sh_link].sh_offset; + shstrtab = (char *)pi->ehdr + sechdrs[pi->ehdr->e_shstrndx].sh_offset; + + relas = (void *)pi->ehdr + relsec->sh_offset; + + for (i = 0; i < relsec->sh_size / sizeof(*relas); i++) { + const Elf_Sym *sym; /* symbol to relocate */ + unsigned long addr; /* final location after relocation */ + unsigned long val; /* relocated symbol value */ + unsigned long sec_base; /* relocated symbol value */ + void *loc; /* tmp location to modify */ + + sym = (void *)pi->ehdr + symtab->sh_offset; + sym += ELF64_R_SYM(relas[i].r_info); + + if (sym->st_name) + name = strtab + sym->st_name; + else + name = shstrtab + sechdrs[sym->st_shndx].sh_name; + + loc = pi->purgatory_buf; + loc += section->sh_offset; + loc += relas[i].r_offset; + + if (sym->st_shndx == SHN_ABS) + sec_base = 0; + else if (sym->st_shndx >= pi->ehdr->e_shnum) { + pr_err("Invalid section %d for symbol %s\n", + sym->st_shndx, name); + return -ENOEXEC; + } else + sec_base = pi->sechdrs[sym->st_shndx].sh_addr; + + val = sym->st_value; + val += sec_base; + val += relas[i].r_addend; + + addr = section->sh_addr + relas[i].r_offset; + + r_type = ELF64_R_TYPE(relas[i].r_info); + + switch (r_type) { + case R_RISCV_BRANCH: + *(u32 *)loc = CLEAN_IMM(BTYPE, *(u32 *)loc) | + ENCODE_BTYPE_IMM(val - addr); + break; + case R_RISCV_JAL: + *(u32 *)loc = CLEAN_IMM(JTYPE, *(u32 *)loc) | + ENCODE_JTYPE_IMM(val - addr); + break; + /* + * With no R_RISCV_PCREL_LO12_S, R_RISCV_PCREL_LO12_I + * sym is expected to be next to R_RISCV_PCREL_HI20 + * in purgatory relsec. Handle it like R_RISCV_CALL + * sym, instead of searching the whole relsec. + */ + case R_RISCV_PCREL_HI20: + case R_RISCV_CALL_PLT: + case R_RISCV_CALL: + *(u64 *)loc = CLEAN_IMM(UITYPE, *(u64 *)loc) | + ENCODE_UJTYPE_IMM(val - addr); + break; + case R_RISCV_RVC_BRANCH: + *(u32 *)loc = CLEAN_IMM(CBTYPE, *(u32 *)loc) | + ENCODE_CBTYPE_IMM(val - addr); + break; + case R_RISCV_RVC_JUMP: + *(u32 *)loc = CLEAN_IMM(CJTYPE, *(u32 *)loc) | + ENCODE_CJTYPE_IMM(val - addr); + break; + case R_RISCV_ADD16: + *(u16 *)loc += val; + break; + case R_RISCV_SUB16: + *(u16 *)loc -= val; + break; + case R_RISCV_ADD32: + *(u32 *)loc += val; + break; + case R_RISCV_SUB32: + *(u32 *)loc -= val; + break; + /* It has been applied by R_RISCV_PCREL_HI20 sym */ + case R_RISCV_PCREL_LO12_I: + case R_RISCV_ALIGN: + case R_RISCV_RELAX: + break; + case R_RISCV_64: + *(u64 *)loc = val; + break; + default: + pr_err("Unknown rela relocation: %d\n", r_type); + return -ENOEXEC; + } + } + return 0; +} + + +int load_extra_segments(struct kimage *image, unsigned long kernel_start, + unsigned long kernel_len, char *initrd, + unsigned long initrd_len, char *cmdline, + unsigned long cmdline_len) +{ + int ret; + void *fdt; + unsigned long initrd_pbase = 0UL; + struct kexec_buf kbuf; + char *modified_cmdline = NULL; + + kbuf.image = image; + kbuf.buf_min = kernel_start + kernel_len; + kbuf.buf_max = ULONG_MAX; + +#ifdef CONFIG_CRASH_DUMP + /* Add elfcorehdr */ + if (image->type == KEXEC_TYPE_CRASH) { + void *headers; + unsigned long headers_sz; + ret = prepare_elf_headers(&headers, &headers_sz); + if (ret) { + pr_err("Preparing elf core header failed\n"); + goto out; + } + + kbuf.buffer = headers; + kbuf.bufsz = headers_sz; + kbuf.mem = KEXEC_BUF_MEM_UNKNOWN; + kbuf.memsz = headers_sz; + kbuf.buf_align = ELF_CORE_HEADER_ALIGN; + kbuf.top_down = true; + + ret = kexec_add_buffer(&kbuf); + if (ret) { + vfree(headers); + goto out; + } + image->elf_headers = headers; + image->elf_load_addr = kbuf.mem; + image->elf_headers_sz = headers_sz; + + kexec_dprintk("Loaded elf core header at 0x%lx bufsz=0x%lx memsz=0x%lx\n", + image->elf_load_addr, kbuf.bufsz, kbuf.memsz); + + /* Setup cmdline for kdump kernel case */ + modified_cmdline = setup_kdump_cmdline(image, cmdline, + cmdline_len); + if (!modified_cmdline) { + pr_err("Setting up cmdline for kdump kernel failed\n"); + ret = -EINVAL; + goto out; + } + cmdline = modified_cmdline; + } +#endif + +#ifdef CONFIG_ARCH_SUPPORTS_KEXEC_PURGATORY + /* Add purgatory to the image */ + kbuf.top_down = true; + kbuf.mem = KEXEC_BUF_MEM_UNKNOWN; + ret = kexec_load_purgatory(image, &kbuf); + if (ret) { + pr_err("Error loading purgatory ret=%d\n", ret); + goto out; + } + kexec_dprintk("Loaded purgatory at 0x%lx\n", kbuf.mem); + + ret = kexec_purgatory_get_set_symbol(image, "riscv_kernel_entry", + &kernel_start, + sizeof(kernel_start), 0); + if (ret) + pr_err("Error update purgatory ret=%d\n", ret); +#endif /* CONFIG_ARCH_SUPPORTS_KEXEC_PURGATORY */ + + /* Add the initrd to the image */ + if (initrd != NULL) { + kbuf.buffer = initrd; + kbuf.bufsz = kbuf.memsz = initrd_len; + kbuf.buf_align = PAGE_SIZE; + kbuf.top_down = true; + kbuf.mem = KEXEC_BUF_MEM_UNKNOWN; + ret = kexec_add_buffer(&kbuf); + if (ret) + goto out; + initrd_pbase = kbuf.mem; + kexec_dprintk("Loaded initrd at 0x%lx\n", initrd_pbase); + } + + /* Add the DTB to the image */ + fdt = of_kexec_alloc_and_setup_fdt(image, initrd_pbase, + initrd_len, cmdline, 0); + if (!fdt) { + pr_err("Error setting up the new device tree.\n"); + ret = -EINVAL; + goto out; + } + + fdt_pack(fdt); + kbuf.buffer = fdt; + kbuf.bufsz = kbuf.memsz = fdt_totalsize(fdt); + kbuf.buf_align = PAGE_SIZE; + kbuf.mem = KEXEC_BUF_MEM_UNKNOWN; + kbuf.top_down = true; + ret = kexec_add_buffer(&kbuf); + if (ret) { + pr_err("Error add DTB kbuf ret=%d\n", ret); + goto out_free_fdt; + } + /* Cache the fdt buffer address for memory cleanup */ + image->arch.fdt = fdt; + kexec_dprintk("Loaded device tree at 0x%lx\n", kbuf.mem); + goto out; + +out_free_fdt: + kvfree(fdt); +out: + kfree(modified_cmdline); + return ret; +} diff --git a/arch/riscv/kernel/mcount-dyn.S b/arch/riscv/kernel/mcount-dyn.S index 745dd4c4a69c..48f6c4f7dca0 100644 --- a/arch/riscv/kernel/mcount-dyn.S +++ b/arch/riscv/kernel/mcount-dyn.S @@ -13,7 +13,6 @@ .text -#define FENTRY_RA_OFFSET 8 #define ABI_SIZE_ON_STACK 80 #define ABI_A0 0 #define ABI_A1 8 @@ -56,16 +55,13 @@ addi sp, sp, ABI_SIZE_ON_STACK .endm -#ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS - /** * SAVE_ABI_REGS - save regs against the ftrace_regs struct * * After the stack is established, * * 0(sp) stores the PC of the traced function which can be accessed -* by &(fregs)->epc in tracing function. Note that the real -* function entry address should be computed with -FENTRY_RA_OFFSET. +* by &(fregs)->epc in tracing function. * * 8(sp) stores the function return address (i.e. parent IP) that * can be accessed by &(fregs)->ra in tracing function. @@ -86,17 +82,20 @@ * +++++++++ **/ .macro SAVE_ABI_REGS - mv t4, sp // Save original SP in T4 addi sp, sp, -FREGS_SIZE_ON_STACK - REG_S t0, FREGS_EPC(sp) REG_S x1, FREGS_RA(sp) - REG_S t4, FREGS_SP(sp) // Put original SP on stack #ifdef HAVE_FUNCTION_GRAPH_FP_TEST REG_S x8, FREGS_S0(sp) #endif REG_S x6, FREGS_T1(sp) - +#ifdef CONFIG_CC_IS_CLANG + REG_S x7, FREGS_T2(sp) + REG_S x28, FREGS_T3(sp) + REG_S x29, FREGS_T4(sp) + REG_S x30, FREGS_T5(sp) + REG_S x31, FREGS_T6(sp) +#endif // save the arguments REG_S x10, FREGS_A0(sp) REG_S x11, FREGS_A1(sp) @@ -106,16 +105,25 @@ REG_S x15, FREGS_A5(sp) REG_S x16, FREGS_A6(sp) REG_S x17, FREGS_A7(sp) + mv a0, sp + addi a0, a0, FREGS_SIZE_ON_STACK + REG_S a0, FREGS_SP(sp) // Put original SP on stack .endm - .macro RESTORE_ABI_REGS, all=0 + .macro RESTORE_ABI_REGS REG_L t0, FREGS_EPC(sp) REG_L x1, FREGS_RA(sp) #ifdef HAVE_FUNCTION_GRAPH_FP_TEST REG_L x8, FREGS_S0(sp) #endif REG_L x6, FREGS_T1(sp) - +#ifdef CONFIG_CC_IS_CLANG + REG_L x7, FREGS_T2(sp) + REG_L x28, FREGS_T3(sp) + REG_L x29, FREGS_T4(sp) + REG_L x30, FREGS_T5(sp) + REG_L x31, FREGS_T6(sp) +#endif // restore the arguments REG_L x10, FREGS_A0(sp) REG_L x11, FREGS_A1(sp) @@ -130,60 +138,71 @@ .endm .macro PREPARE_ARGS - addi a0, t0, -FENTRY_RA_OFFSET + addi a0, t0, -MCOUNT_JALR_SIZE // ip (callsite's jalr insn) +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS + mv a1, ra // parent_ip + REG_L a2, -16(t0) // op + REG_L ra, FTRACE_OPS_FUNC(a2) // op->func +#else la a1, function_trace_op - REG_L a2, 0(a1) - mv a1, ra - mv a3, sp + REG_L a2, 0(a1) // op + mv a1, ra // parent_ip +#endif + mv a3, sp // regs .endm -#endif /* CONFIG_DYNAMIC_FTRACE_WITH_ARGS */ - -#ifndef CONFIG_DYNAMIC_FTRACE_WITH_ARGS SYM_FUNC_START(ftrace_caller) - SAVE_ABI - - addi a0, t0, -FENTRY_RA_OFFSET - la a1, function_trace_op - REG_L a2, 0(a1) - mv a1, ra - mv a3, sp +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS + /* + * When CALL_OPS is enabled (2 or 4) nops [8B] are placed before the + * function entry, these are later overwritten with the pointer to the + * associated struct ftrace_ops. + * + * -8: &ftrace_ops of the associated tracer function. + *<ftrace enable>: + * 0: auipc t0/ra, 0x? + * 4: jalr t0/ra, ?(t0/ra) + * + * -8: &ftrace_nop_ops + *<ftrace disable>: + * 0: nop + * 4: nop + * + * t0 is set to ip+8 after the jalr is executed at the callsite, + * so we find the associated op at t0-16. + */ + REG_L t1, -16(t0) // op Should be SZ_REG instead of 16 -SYM_INNER_LABEL(ftrace_call, SYM_L_GLOBAL) - call ftrace_stub - -#ifdef CONFIG_FUNCTION_GRAPH_TRACER - addi a0, sp, ABI_RA - REG_L a1, ABI_T0(sp) - addi a1, a1, -FENTRY_RA_OFFSET -#ifdef HAVE_FUNCTION_GRAPH_FP_TEST - mv a2, s0 +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS + /* + * If the op has a direct call, handle it immediately without + * saving/restoring registers. + */ + REG_L t1, FTRACE_OPS_DIRECT_CALL(t1) + bnez t1, ftrace_caller_direct #endif -SYM_INNER_LABEL(ftrace_graph_call, SYM_L_GLOBAL) - call ftrace_stub #endif - RESTORE_ABI - jr t0 -SYM_FUNC_END(ftrace_caller) - -#else /* CONFIG_DYNAMIC_FTRACE_WITH_ARGS */ -SYM_FUNC_START(ftrace_caller) - mv t1, zero SAVE_ABI_REGS PREPARE_ARGS +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS + jalr ra +#else SYM_INNER_LABEL(ftrace_call, SYM_L_GLOBAL) - call ftrace_stub - + REG_L ra, ftrace_call_dest + jalr ra, 0(ra) +#endif RESTORE_ABI_REGS - bnez t1, .Ldirect +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS + bnez t1, ftrace_caller_direct +#endif jr t0 -.Ldirect: +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS +SYM_INNER_LABEL(ftrace_caller_direct, SYM_L_LOCAL) jr t1 +#endif SYM_FUNC_END(ftrace_caller) -#endif /* CONFIG_DYNAMIC_FTRACE_WITH_ARGS */ - #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS SYM_CODE_START(ftrace_stub_direct_tramp) jr t0 diff --git a/arch/riscv/kernel/module-sections.c b/arch/riscv/kernel/module-sections.c index 91d0b355ceef..75551ac6504c 100644 --- a/arch/riscv/kernel/module-sections.c +++ b/arch/riscv/kernel/module-sections.c @@ -9,6 +9,7 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/moduleloader.h> +#include <linux/sort.h> unsigned long module_emit_got_entry(struct module *mod, unsigned long val) { @@ -55,44 +56,70 @@ unsigned long module_emit_plt_entry(struct module *mod, unsigned long val) return (unsigned long)&plt[i]; } -static int is_rela_equal(const Elf_Rela *x, const Elf_Rela *y) +#define cmp_3way(a, b) ((a) < (b) ? -1 : (a) > (b)) + +static int cmp_rela(const void *a, const void *b) { - return x->r_info == y->r_info && x->r_addend == y->r_addend; + const Elf_Rela *x = a, *y = b; + int i; + + /* sort by type, symbol index and addend */ + i = cmp_3way(x->r_info, y->r_info); + if (i == 0) + i = cmp_3way(x->r_addend, y->r_addend); + return i; } static bool duplicate_rela(const Elf_Rela *rela, int idx) { - int i; - for (i = 0; i < idx; i++) { - if (is_rela_equal(&rela[i], &rela[idx])) - return true; - } - return false; + /* + * Entries are sorted by type, symbol index and addend. That means + * that, if a duplicate entry exists, it must be in the preceding slot. + */ + return idx > 0 && cmp_rela(rela + idx, rela + idx - 1) == 0; } -static void count_max_entries(Elf_Rela *relas, int num, +static void count_max_entries(const Elf_Rela *relas, size_t num, unsigned int *plts, unsigned int *gots) { - for (int i = 0; i < num; i++) { + for (size_t i = 0; i < num; i++) { + if (duplicate_rela(relas, i)) + continue; + switch (ELF_R_TYPE(relas[i].r_info)) { case R_RISCV_CALL_PLT: case R_RISCV_PLT32: - if (!duplicate_rela(relas, i)) - (*plts)++; + (*plts)++; break; case R_RISCV_GOT_HI20: - if (!duplicate_rela(relas, i)) - (*gots)++; + (*gots)++; break; + default: + unreachable(); } } } +static bool rela_needs_plt_got_entry(const Elf_Rela *rela) +{ + switch (ELF_R_TYPE(rela->r_info)) { + case R_RISCV_CALL_PLT: + case R_RISCV_GOT_HI20: + case R_RISCV_PLT32: + return true; + default: + return false; + } +} + int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs, char *secstrings, struct module *mod) { + size_t num_scratch_relas = 0; unsigned int num_plts = 0; unsigned int num_gots = 0; + Elf_Rela *scratch = NULL; + size_t scratch_size = 0; int i; /* @@ -122,9 +149,10 @@ int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs, /* Calculate the maxinum number of entries */ for (i = 0; i < ehdr->e_shnum; i++) { + size_t num_relas = sechdrs[i].sh_size / sizeof(Elf_Rela); Elf_Rela *relas = (void *)ehdr + sechdrs[i].sh_offset; - int num_rela = sechdrs[i].sh_size / sizeof(Elf_Rela); Elf_Shdr *dst_sec = sechdrs + sechdrs[i].sh_info; + size_t scratch_size_needed; if (sechdrs[i].sh_type != SHT_RELA) continue; @@ -133,7 +161,28 @@ int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs, if (!(dst_sec->sh_flags & SHF_EXECINSTR)) continue; - count_max_entries(relas, num_rela, &num_plts, &num_gots); + /* + * apply_relocate_add() relies on HI20 and LO12 relocation pairs being + * close together, so sort a copy of the section to avoid interfering. + */ + scratch_size_needed = (num_scratch_relas + num_relas) * sizeof(*scratch); + if (scratch_size_needed > scratch_size) { + scratch_size = scratch_size_needed; + scratch = kvrealloc(scratch, scratch_size, GFP_KERNEL); + if (!scratch) + return -ENOMEM; + } + + for (size_t j = 0; j < num_relas; j++) + if (rela_needs_plt_got_entry(&relas[j])) + scratch[num_scratch_relas++] = relas[j]; + } + + if (scratch) { + /* sort the accumulated PLT/GOT relocations so duplicates are adjacent */ + sort(scratch, num_scratch_relas, sizeof(*scratch), cmp_rela, NULL); + count_max_entries(scratch, num_scratch_relas, &num_plts, &num_gots); + kvfree(scratch); } mod->arch.plt.shdr->sh_type = SHT_NOBITS; diff --git a/arch/riscv/kernel/process.c b/arch/riscv/kernel/process.c index bbf7ec6a75c0..a0a40889d79a 100644 --- a/arch/riscv/kernel/process.c +++ b/arch/riscv/kernel/process.c @@ -60,7 +60,7 @@ int get_unalign_ctl(struct task_struct *tsk, unsigned long adr) if (!unaligned_ctl_available()) return -EINVAL; - return put_user(tsk->thread.align_ctl, (unsigned long __user *)adr); + return put_user(tsk->thread.align_ctl, (unsigned int __user *)adr); } void __show_regs(struct pt_regs *regs) diff --git a/arch/riscv/kernel/sbi.c b/arch/riscv/kernel/sbi.c index 1989b8cade1b..53836a9235e3 100644 --- a/arch/riscv/kernel/sbi.c +++ b/arch/riscv/kernel/sbi.c @@ -299,6 +299,76 @@ static int __sbi_rfence_v02(int fid, const struct cpumask *cpu_mask, return 0; } +static bool sbi_fwft_supported; + +struct fwft_set_req { + u32 feature; + unsigned long value; + unsigned long flags; + atomic_t error; +}; + +static void cpu_sbi_fwft_set(void *arg) +{ + struct fwft_set_req *req = arg; + int ret; + + ret = sbi_fwft_set(req->feature, req->value, req->flags); + if (ret) + atomic_set(&req->error, ret); +} + +/** + * sbi_fwft_set() - Set a feature on the local hart + * @feature: The feature ID to be set + * @value: The feature value to be set + * @flags: FWFT feature set flags + * + * Return: 0 on success, appropriate linux error code otherwise. + */ +int sbi_fwft_set(u32 feature, unsigned long value, unsigned long flags) +{ + struct sbiret ret; + + if (!sbi_fwft_supported) + return -EOPNOTSUPP; + + ret = sbi_ecall(SBI_EXT_FWFT, SBI_EXT_FWFT_SET, + feature, value, flags, 0, 0, 0); + + return sbi_err_map_linux_errno(ret.error); +} + +/** + * sbi_fwft_set_cpumask() - Set a feature for the specified cpumask + * @mask: CPU mask of cpus that need the feature to be set + * @feature: The feature ID to be set + * @value: The feature value to be set + * @flags: FWFT feature set flags + * + * Return: 0 on success, appropriate linux error code otherwise. + */ +int sbi_fwft_set_cpumask(const cpumask_t *mask, u32 feature, + unsigned long value, unsigned long flags) +{ + struct fwft_set_req req = { + .feature = feature, + .value = value, + .flags = flags, + .error = ATOMIC_INIT(0), + }; + + if (!sbi_fwft_supported) + return -EOPNOTSUPP; + + if (feature & SBI_FWFT_GLOBAL_FEATURE_BIT) + return -EINVAL; + + on_each_cpu_mask(mask, cpu_sbi_fwft_set, &req, 1); + + return atomic_read(&req.error); +} + /** * sbi_set_timer() - Program the timer for next timer event. * @stime_value: The value after which next timer event should fire. @@ -609,7 +679,7 @@ void __init sbi_init(void) } else { __sbi_rfence = __sbi_rfence_v01; } - if ((sbi_spec_version >= sbi_mk_version(0, 3)) && + if (sbi_spec_version >= sbi_mk_version(0, 3) && sbi_probe_extension(SBI_EXT_SRST)) { pr_info("SBI SRST extension detected\n"); pm_power_off = sbi_srst_power_off; @@ -617,11 +687,16 @@ void __init sbi_init(void) sbi_srst_reboot_nb.priority = 192; register_restart_handler(&sbi_srst_reboot_nb); } - if ((sbi_spec_version >= sbi_mk_version(2, 0)) && - (sbi_probe_extension(SBI_EXT_DBCN) > 0)) { + if (sbi_spec_version >= sbi_mk_version(2, 0) && + sbi_probe_extension(SBI_EXT_DBCN) > 0) { pr_info("SBI DBCN extension detected\n"); sbi_debug_console_available = true; } + if (sbi_spec_version >= sbi_mk_version(3, 0) && + sbi_probe_extension(SBI_EXT_FWFT)) { + pr_info("SBI FWFT extension detected\n"); + sbi_fwft_supported = true; + } } else { __sbi_set_timer = __sbi_set_timer_v01; __sbi_send_ipi = __sbi_send_ipi_v01; diff --git a/arch/riscv/kernel/sys_hwprobe.c b/arch/riscv/kernel/sys_hwprobe.c index 249aec8594a9..0b170e18a2be 100644 --- a/arch/riscv/kernel/sys_hwprobe.c +++ b/arch/riscv/kernel/sys_hwprobe.c @@ -15,6 +15,7 @@ #include <asm/uaccess.h> #include <asm/unistd.h> #include <asm/vector.h> +#include <asm/vendor_extensions/sifive_hwprobe.h> #include <asm/vendor_extensions/thead_hwprobe.h> #include <vdso/vsyscall.h> @@ -96,6 +97,7 @@ static void hwprobe_isa_ext0(struct riscv_hwprobe *pair, * presence in the hart_isa bitmap, are made. */ EXT_KEY(ZAAMO); + EXT_KEY(ZABHA); EXT_KEY(ZACAS); EXT_KEY(ZALRSC); EXT_KEY(ZAWRS); @@ -300,6 +302,10 @@ static void hwprobe_one_pair(struct riscv_hwprobe *pair, pair->value = riscv_timebase; break; + case RISCV_HWPROBE_KEY_VENDOR_EXT_SIFIVE_0: + hwprobe_isa_vendor_ext_sifive_0(pair, cpus); + break; + case RISCV_HWPROBE_KEY_VENDOR_EXT_THEAD_0: hwprobe_isa_vendor_ext_thead_0(pair, cpus); break; diff --git a/arch/riscv/kernel/traps_misaligned.c b/arch/riscv/kernel/traps_misaligned.c index 77c788660223..dd8e4af6583f 100644 --- a/arch/riscv/kernel/traps_misaligned.c +++ b/arch/riscv/kernel/traps_misaligned.c @@ -16,6 +16,7 @@ #include <asm/entry-common.h> #include <asm/hwprobe.h> #include <asm/cpufeature.h> +#include <asm/sbi.h> #include <asm/vector.h> #define INSN_MATCH_LB 0x3 @@ -368,9 +369,7 @@ static int handle_scalar_misaligned_load(struct pt_regs *regs) perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, 1, regs, addr); -#ifdef CONFIG_RISCV_PROBE_UNALIGNED_ACCESS *this_cpu_ptr(&misaligned_access_speed) = RISCV_HWPROBE_MISALIGNED_SCALAR_EMULATED; -#endif if (!unaligned_enabled) return -1; @@ -455,7 +454,7 @@ static int handle_scalar_misaligned_load(struct pt_regs *regs) val.data_u64 = 0; if (user_mode(regs)) { - if (copy_from_user(&val, (u8 __user *)addr, len)) + if (copy_from_user_nofault(&val, (u8 __user *)addr, len)) return -1; } else { memcpy(&val, (u8 *)addr, len); @@ -556,7 +555,7 @@ static int handle_scalar_misaligned_store(struct pt_regs *regs) return -EOPNOTSUPP; if (user_mode(regs)) { - if (copy_to_user((u8 __user *)addr, &val, len)) + if (copy_to_user_nofault((u8 __user *)addr, &val, len)) return -1; } else { memcpy((u8 *)addr, &val, len); @@ -626,6 +625,10 @@ bool __init check_vector_unaligned_access_emulated_all_cpus(void) { int cpu; + /* + * While being documented as very slow, schedule_on_each_cpu() is used since + * kernel_vector_begin() expects irqs to be enabled or it will panic() + */ schedule_on_each_cpu(check_vector_unaligned_access_emulated); for_each_online_cpu(cpu) @@ -642,11 +645,23 @@ bool __init check_vector_unaligned_access_emulated_all_cpus(void) } #endif +static bool all_cpus_unaligned_scalar_access_emulated(void) +{ + int cpu; + + for_each_online_cpu(cpu) + if (per_cpu(misaligned_access_speed, cpu) != + RISCV_HWPROBE_MISALIGNED_SCALAR_EMULATED) + return false; + + return true; +} + #ifdef CONFIG_RISCV_SCALAR_MISALIGNED static bool unaligned_ctl __read_mostly; -void check_unaligned_access_emulated(struct work_struct *work __always_unused) +static void check_unaligned_access_emulated(void *arg __always_unused) { int cpu = smp_processor_id(); long *mas_ptr = per_cpu_ptr(&misaligned_access_speed, cpu); @@ -657,6 +672,13 @@ void check_unaligned_access_emulated(struct work_struct *work __always_unused) __asm__ __volatile__ ( " "REG_L" %[tmp], 1(%[ptr])\n" : [tmp] "=r" (tmp_val) : [ptr] "r" (&tmp_var) : "memory"); +} + +static int cpu_online_check_unaligned_access_emulated(unsigned int cpu) +{ + long *mas_ptr = per_cpu_ptr(&misaligned_access_speed, cpu); + + check_unaligned_access_emulated(NULL); /* * If unaligned_ctl is already set, this means that we detected that all @@ -665,26 +687,23 @@ void check_unaligned_access_emulated(struct work_struct *work __always_unused) */ if (unlikely(unaligned_ctl && (*mas_ptr != RISCV_HWPROBE_MISALIGNED_SCALAR_EMULATED))) { pr_crit("CPU misaligned accesses non homogeneous (expected all emulated)\n"); - while (true) - cpu_relax(); + return -EINVAL; } + + return 0; } bool __init check_unaligned_access_emulated_all_cpus(void) { - int cpu; - /* * We can only support PR_UNALIGN controls if all CPUs have misaligned * accesses emulated since tasks requesting such control can run on any * CPU. */ - schedule_on_each_cpu(check_unaligned_access_emulated); + on_each_cpu(check_unaligned_access_emulated, NULL, 1); - for_each_online_cpu(cpu) - if (per_cpu(misaligned_access_speed, cpu) - != RISCV_HWPROBE_MISALIGNED_SCALAR_EMULATED) - return false; + if (!all_cpus_unaligned_scalar_access_emulated()) + return false; unaligned_ctl = true; return true; @@ -699,4 +718,73 @@ bool __init check_unaligned_access_emulated_all_cpus(void) { return false; } +static int cpu_online_check_unaligned_access_emulated(unsigned int cpu) +{ + return 0; +} +#endif + +static bool misaligned_traps_delegated; + +#ifdef CONFIG_RISCV_SBI + +static int cpu_online_sbi_unaligned_setup(unsigned int cpu) +{ + if (sbi_fwft_set(SBI_FWFT_MISALIGNED_EXC_DELEG, 1, 0) && + misaligned_traps_delegated) { + pr_crit("Misaligned trap delegation non homogeneous (expected delegated)"); + return -EINVAL; + } + + return 0; +} + +void __init unaligned_access_init(void) +{ + int ret; + + ret = sbi_fwft_set_online_cpus(SBI_FWFT_MISALIGNED_EXC_DELEG, 1, 0); + if (ret) + return; + + misaligned_traps_delegated = true; + pr_info("SBI misaligned access exception delegation ok\n"); + /* + * Note that we don't have to take any specific action here, if + * the delegation is successful, then + * check_unaligned_access_emulated() will verify that indeed the + * platform traps on misaligned accesses. + */ +} +#else +void __init unaligned_access_init(void) {} + +static int cpu_online_sbi_unaligned_setup(unsigned int cpu __always_unused) +{ + return 0; +} + #endif + +int cpu_online_unaligned_access_init(unsigned int cpu) +{ + int ret; + + ret = cpu_online_sbi_unaligned_setup(cpu); + if (ret) + return ret; + + return cpu_online_check_unaligned_access_emulated(cpu); +} + +bool misaligned_traps_can_delegate(void) +{ + /* + * Either we successfully requested misaligned traps delegation for all + * CPUs, or the SBI does not implement the FWFT extension but delegated + * the exception by default. + */ + return misaligned_traps_delegated || + all_cpus_unaligned_scalar_access_emulated(); +} +EXPORT_SYMBOL_GPL(misaligned_traps_can_delegate); diff --git a/arch/riscv/kernel/unaligned_access_speed.c b/arch/riscv/kernel/unaligned_access_speed.c index b8ba13819d05..ae2068425fbc 100644 --- a/arch/riscv/kernel/unaligned_access_speed.c +++ b/arch/riscv/kernel/unaligned_access_speed.c @@ -236,6 +236,11 @@ arch_initcall_sync(lock_and_set_unaligned_access_static_branch); static int riscv_online_cpu(unsigned int cpu) { + int ret = cpu_online_unaligned_access_init(cpu); + + if (ret) + return ret; + /* We are already set since the last check */ if (per_cpu(misaligned_access_speed, cpu) != RISCV_HWPROBE_MISALIGNED_SCALAR_UNKNOWN) { goto exit; @@ -248,7 +253,6 @@ static int riscv_online_cpu(unsigned int cpu) { static struct page *buf; - check_unaligned_access_emulated(NULL); buf = alloc_pages(GFP_KERNEL, MISALIGNED_BUFFER_ORDER); if (!buf) { pr_warn("Allocation failure, not measuring misaligned performance\n"); @@ -439,6 +443,8 @@ static int __init check_unaligned_access_all_cpus(void) { int cpu; + unaligned_access_init(); + if (unaligned_scalar_speed_param != RISCV_HWPROBE_MISALIGNED_SCALAR_UNKNOWN) { pr_info("scalar unaligned access speed set to '%s' (%lu) by command line\n", speed_str[unaligned_scalar_speed_param], unaligned_scalar_speed_param); diff --git a/arch/riscv/kernel/vdso.c b/arch/riscv/kernel/vdso.c index cc2895d1fbc2..3a8e038b10a2 100644 --- a/arch/riscv/kernel/vdso.c +++ b/arch/riscv/kernel/vdso.c @@ -136,7 +136,7 @@ static int __setup_additional_pages(struct mm_struct *mm, ret = _install_special_mapping(mm, vdso_base, vdso_text_len, - (VM_READ | VM_EXEC | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC), + (VM_READ | VM_EXEC | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC | VM_SEALED_SYSMAP), vdso_info->cm); if (IS_ERR(ret)) diff --git a/arch/riscv/kernel/vdso/Makefile b/arch/riscv/kernel/vdso/Makefile index ad73607abc28..9ebb5e590f93 100644 --- a/arch/riscv/kernel/vdso/Makefile +++ b/arch/riscv/kernel/vdso/Makefile @@ -13,9 +13,17 @@ vdso-syms += flush_icache vdso-syms += hwprobe vdso-syms += sys_hwprobe +ifdef CONFIG_VDSO_GETRANDOM +vdso-syms += getrandom +endif + # Files to link into the vdso obj-vdso = $(patsubst %, %.o, $(vdso-syms)) note.o +ifdef CONFIG_VDSO_GETRANDOM +obj-vdso += vgetrandom-chacha.o +endif + ccflags-y := -fno-stack-protector ccflags-y += -DDISABLE_BRANCH_PROFILING ccflags-y += -fno-builtin @@ -24,6 +32,10 @@ ifneq ($(c-gettimeofday-y),) CFLAGS_vgettimeofday.o += -fPIC -include $(c-gettimeofday-y) endif +ifneq ($(c-getrandom-y),) + CFLAGS_getrandom.o += -fPIC -include $(c-getrandom-y) +endif + CFLAGS_hwprobe.o += -fPIC # Build rules @@ -38,6 +50,7 @@ endif # Disable -pg to prevent insert call site CFLAGS_REMOVE_vgettimeofday.o = $(CC_FLAGS_FTRACE) $(CC_FLAGS_SCS) +CFLAGS_REMOVE_getrandom.o = $(CC_FLAGS_FTRACE) $(CC_FLAGS_SCS) CFLAGS_REMOVE_hwprobe.o = $(CC_FLAGS_FTRACE) $(CC_FLAGS_SCS) # Force dependency @@ -47,7 +60,7 @@ $(obj)/vdso.o: $(obj)/vdso.so $(obj)/vdso.so.dbg: $(obj)/vdso.lds $(obj-vdso) FORCE $(call if_changed,vdsold_and_check) LDFLAGS_vdso.so.dbg = -shared -soname=linux-vdso.so.1 \ - --build-id=sha1 --hash-style=both --eh-frame-hdr + --build-id=sha1 --eh-frame-hdr # strip rule for the .so file $(obj)/%.so: OBJCOPYFLAGS := -S diff --git a/arch/riscv/kernel/vdso/getrandom.c b/arch/riscv/kernel/vdso/getrandom.c new file mode 100644 index 000000000000..f21922e8cebd --- /dev/null +++ b/arch/riscv/kernel/vdso/getrandom.c @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2025 Xi Ruoyao <xry111@xry111.site>. All Rights Reserved. + */ +#include <linux/types.h> + +ssize_t __vdso_getrandom(void *buffer, size_t len, unsigned int flags, void *opaque_state, size_t opaque_len) +{ + return __cvdso_getrandom(buffer, len, flags, opaque_state, opaque_len); +} diff --git a/arch/riscv/kernel/vdso/vdso.lds.S b/arch/riscv/kernel/vdso/vdso.lds.S index 8e86965a8aae..7c15b0f4ee3b 100644 --- a/arch/riscv/kernel/vdso/vdso.lds.S +++ b/arch/riscv/kernel/vdso/vdso.lds.S @@ -80,6 +80,9 @@ VERSION #ifndef COMPAT_VDSO __vdso_riscv_hwprobe; #endif +#if defined(CONFIG_VDSO_GETRANDOM) && !defined(COMPAT_VDSO) + __vdso_getrandom; +#endif local: *; }; } diff --git a/arch/riscv/kernel/vdso/vgetrandom-chacha.S b/arch/riscv/kernel/vdso/vgetrandom-chacha.S new file mode 100644 index 000000000000..5f0dad8f2373 --- /dev/null +++ b/arch/riscv/kernel/vdso/vgetrandom-chacha.S @@ -0,0 +1,249 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2025 Xi Ruoyao <xry111@xry111.site>. All Rights Reserved. + * + * Based on arch/loongarch/vdso/vgetrandom-chacha.S. + */ + +#include <asm/asm.h> +#include <linux/linkage.h> + +.text + +.macro ROTRI rd rs imm + slliw t0, \rs, 32 - \imm + srliw \rd, \rs, \imm + or \rd, \rd, t0 +.endm + +.macro OP_4REG op d0 d1 d2 d3 s0 s1 s2 s3 + \op \d0, \d0, \s0 + \op \d1, \d1, \s1 + \op \d2, \d2, \s2 + \op \d3, \d3, \s3 +.endm + +/* + * a0: output bytes + * a1: 32-byte key input + * a2: 8-byte counter input/output + * a3: number of 64-byte blocks to write to output + */ +SYM_FUNC_START(__arch_chacha20_blocks_nostack) + +#define output a0 +#define key a1 +#define counter a2 +#define nblocks a3 +#define i a4 +#define state0 s0 +#define state1 s1 +#define state2 s2 +#define state3 s3 +#define state4 s4 +#define state5 s5 +#define state6 s6 +#define state7 s7 +#define state8 s8 +#define state9 s9 +#define state10 s10 +#define state11 s11 +#define state12 a5 +#define state13 a6 +#define state14 a7 +#define state15 t1 +#define cnt t2 +#define copy0 t3 +#define copy1 t4 +#define copy2 t5 +#define copy3 t6 + +/* Packs to be used with OP_4REG */ +#define line0 state0, state1, state2, state3 +#define line1 state4, state5, state6, state7 +#define line2 state8, state9, state10, state11 +#define line3 state12, state13, state14, state15 + +#define line1_perm state5, state6, state7, state4 +#define line2_perm state10, state11, state8, state9 +#define line3_perm state15, state12, state13, state14 + +#define copy copy0, copy1, copy2, copy3 + +#define _16 16, 16, 16, 16 +#define _20 20, 20, 20, 20 +#define _24 24, 24, 24, 24 +#define _25 25, 25, 25, 25 + + /* + * The ABI requires s0-s9 saved. + * This does not violate the stack-less requirement: no sensitive data + * is spilled onto the stack. + */ + addi sp, sp, -12*SZREG + REG_S s0, (sp) + REG_S s1, SZREG(sp) + REG_S s2, 2*SZREG(sp) + REG_S s3, 3*SZREG(sp) + REG_S s4, 4*SZREG(sp) + REG_S s5, 5*SZREG(sp) + REG_S s6, 6*SZREG(sp) + REG_S s7, 7*SZREG(sp) + REG_S s8, 8*SZREG(sp) + REG_S s9, 9*SZREG(sp) + REG_S s10, 10*SZREG(sp) + REG_S s11, 11*SZREG(sp) + + ld cnt, (counter) + + li copy0, 0x61707865 + li copy1, 0x3320646e + li copy2, 0x79622d32 + li copy3, 0x6b206574 + +.Lblock: + /* state[0,1,2,3] = "expand 32-byte k" */ + mv state0, copy0 + mv state1, copy1 + mv state2, copy2 + mv state3, copy3 + + /* state[4,5,..,11] = key */ + lw state4, (key) + lw state5, 4(key) + lw state6, 8(key) + lw state7, 12(key) + lw state8, 16(key) + lw state9, 20(key) + lw state10, 24(key) + lw state11, 28(key) + + /* state[12,13] = counter */ + mv state12, cnt + srli state13, cnt, 32 + + /* state[14,15] = 0 */ + mv state14, zero + mv state15, zero + + li i, 10 +.Lpermute: + /* odd round */ + OP_4REG addw line0, line1 + OP_4REG xor line3, line0 + OP_4REG ROTRI line3, _16 + + OP_4REG addw line2, line3 + OP_4REG xor line1, line2 + OP_4REG ROTRI line1, _20 + + OP_4REG addw line0, line1 + OP_4REG xor line3, line0 + OP_4REG ROTRI line3, _24 + + OP_4REG addw line2, line3 + OP_4REG xor line1, line2 + OP_4REG ROTRI line1, _25 + + /* even round */ + OP_4REG addw line0, line1_perm + OP_4REG xor line3_perm, line0 + OP_4REG ROTRI line3_perm, _16 + + OP_4REG addw line2_perm, line3_perm + OP_4REG xor line1_perm, line2_perm + OP_4REG ROTRI line1_perm, _20 + + OP_4REG addw line0, line1_perm + OP_4REG xor line3_perm, line0 + OP_4REG ROTRI line3_perm, _24 + + OP_4REG addw line2_perm, line3_perm + OP_4REG xor line1_perm, line2_perm + OP_4REG ROTRI line1_perm, _25 + + addi i, i, -1 + bnez i, .Lpermute + + /* output[0,1,2,3] = copy[0,1,2,3] + state[0,1,2,3] */ + OP_4REG addw line0, copy + sw state0, (output) + sw state1, 4(output) + sw state2, 8(output) + sw state3, 12(output) + + /* from now on state[0,1,2,3] are scratch registers */ + + /* state[0,1,2,3] = lo(key) */ + lw state0, (key) + lw state1, 4(key) + lw state2, 8(key) + lw state3, 12(key) + + /* output[4,5,6,7] = state[0,1,2,3] + state[4,5,6,7] */ + OP_4REG addw line1, line0 + sw state4, 16(output) + sw state5, 20(output) + sw state6, 24(output) + sw state7, 28(output) + + /* state[0,1,2,3] = hi(key) */ + lw state0, 16(key) + lw state1, 20(key) + lw state2, 24(key) + lw state3, 28(key) + + /* output[8,9,10,11] = tmp[0,1,2,3] + state[8,9,10,11] */ + OP_4REG addw line2, line0 + sw state8, 32(output) + sw state9, 36(output) + sw state10, 40(output) + sw state11, 44(output) + + /* output[12,13,14,15] = state[12,13,14,15] + [cnt_lo, cnt_hi, 0, 0] */ + addw state12, state12, cnt + srli state0, cnt, 32 + addw state13, state13, state0 + sw state12, 48(output) + sw state13, 52(output) + sw state14, 56(output) + sw state15, 60(output) + + /* ++counter */ + addi cnt, cnt, 1 + + /* output += 64 */ + addi output, output, 64 + /* --nblocks */ + addi nblocks, nblocks, -1 + bnez nblocks, .Lblock + + /* counter = [cnt_lo, cnt_hi] */ + sd cnt, (counter) + + /* Zero out the potentially sensitive regs, in case nothing uses these + * again. As at now copy[0,1,2,3] just contains "expand 32-byte k" and + * state[0,...,11] are s0-s11 those we'll restore in the epilogue, we + * only need to zero state[12,...,15]. + */ + mv state12, zero + mv state13, zero + mv state14, zero + mv state15, zero + + REG_L s0, (sp) + REG_L s1, SZREG(sp) + REG_L s2, 2*SZREG(sp) + REG_L s3, 3*SZREG(sp) + REG_L s4, 4*SZREG(sp) + REG_L s5, 5*SZREG(sp) + REG_L s6, 6*SZREG(sp) + REG_L s7, 7*SZREG(sp) + REG_L s8, 8*SZREG(sp) + REG_L s9, 9*SZREG(sp) + REG_L s10, 10*SZREG(sp) + REG_L s11, 11*SZREG(sp) + addi sp, sp, 12*SZREG + + ret +SYM_FUNC_END(__arch_chacha20_blocks_nostack) diff --git a/arch/riscv/kernel/vendor_extensions.c b/arch/riscv/kernel/vendor_extensions.c index 9feb7f67a0a3..92d8ff81f42c 100644 --- a/arch/riscv/kernel/vendor_extensions.c +++ b/arch/riscv/kernel/vendor_extensions.c @@ -6,6 +6,7 @@ #include <asm/vendorid_list.h> #include <asm/vendor_extensions.h> #include <asm/vendor_extensions/andes.h> +#include <asm/vendor_extensions/sifive.h> #include <asm/vendor_extensions/thead.h> #include <linux/array_size.h> @@ -15,6 +16,9 @@ struct riscv_isa_vendor_ext_data_list *riscv_isa_vendor_ext_list[] = { #ifdef CONFIG_RISCV_ISA_VENDOR_EXT_ANDES &riscv_isa_vendor_ext_list_andes, #endif +#ifdef CONFIG_RISCV_ISA_VENDOR_EXT_SIFIVE + &riscv_isa_vendor_ext_list_sifive, +#endif #ifdef CONFIG_RISCV_ISA_VENDOR_EXT_THEAD &riscv_isa_vendor_ext_list_thead, #endif @@ -45,6 +49,12 @@ bool __riscv_isa_vendor_extension_available(int cpu, unsigned long vendor, unsig cpu_bmap = riscv_isa_vendor_ext_list_andes.per_hart_isa_bitmap; break; #endif + #ifdef CONFIG_RISCV_ISA_VENDOR_EXT_SIFIVE + case SIFIVE_VENDOR_ID: + bmap = &riscv_isa_vendor_ext_list_sifive.all_harts_isa_bitmap; + cpu_bmap = riscv_isa_vendor_ext_list_sifive.per_hart_isa_bitmap; + break; + #endif #ifdef CONFIG_RISCV_ISA_VENDOR_EXT_THEAD case THEAD_VENDOR_ID: bmap = &riscv_isa_vendor_ext_list_thead.all_harts_isa_bitmap; diff --git a/arch/riscv/kernel/vendor_extensions/Makefile b/arch/riscv/kernel/vendor_extensions/Makefile index 866414c81a9f..a4eca96d1c8a 100644 --- a/arch/riscv/kernel/vendor_extensions/Makefile +++ b/arch/riscv/kernel/vendor_extensions/Makefile @@ -1,5 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only obj-$(CONFIG_RISCV_ISA_VENDOR_EXT_ANDES) += andes.o +obj-$(CONFIG_RISCV_ISA_VENDOR_EXT_SIFIVE) += sifive.o +obj-$(CONFIG_RISCV_ISA_VENDOR_EXT_SIFIVE) += sifive_hwprobe.o obj-$(CONFIG_RISCV_ISA_VENDOR_EXT_THEAD) += thead.o obj-$(CONFIG_RISCV_ISA_VENDOR_EXT_THEAD) += thead_hwprobe.o diff --git a/arch/riscv/kernel/vendor_extensions/sifive.c b/arch/riscv/kernel/vendor_extensions/sifive.c new file mode 100644 index 000000000000..1411337dc1e6 --- /dev/null +++ b/arch/riscv/kernel/vendor_extensions/sifive.c @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include <asm/cpufeature.h> +#include <asm/vendor_extensions.h> +#include <asm/vendor_extensions/sifive.h> + +#include <linux/array_size.h> +#include <linux/types.h> + +/* All SiFive vendor extensions supported in Linux */ +const struct riscv_isa_ext_data riscv_isa_vendor_ext_sifive[] = { + __RISCV_ISA_EXT_DATA(xsfvfnrclipxfqf, RISCV_ISA_VENDOR_EXT_XSFVFNRCLIPXFQF), + __RISCV_ISA_EXT_DATA(xsfvfwmaccqqq, RISCV_ISA_VENDOR_EXT_XSFVFWMACCQQQ), + __RISCV_ISA_EXT_DATA(xsfvqmaccdod, RISCV_ISA_VENDOR_EXT_XSFVQMACCDOD), + __RISCV_ISA_EXT_DATA(xsfvqmaccqoq, RISCV_ISA_VENDOR_EXT_XSFVQMACCQOQ), +}; + +struct riscv_isa_vendor_ext_data_list riscv_isa_vendor_ext_list_sifive = { + .ext_data_count = ARRAY_SIZE(riscv_isa_vendor_ext_sifive), + .ext_data = riscv_isa_vendor_ext_sifive, +}; diff --git a/arch/riscv/kernel/vendor_extensions/sifive_hwprobe.c b/arch/riscv/kernel/vendor_extensions/sifive_hwprobe.c new file mode 100644 index 000000000000..1f77f6309763 --- /dev/null +++ b/arch/riscv/kernel/vendor_extensions/sifive_hwprobe.c @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include <asm/vendor_extensions/sifive.h> +#include <asm/vendor_extensions/sifive_hwprobe.h> +#include <asm/vendor_extensions/vendor_hwprobe.h> + +#include <linux/cpumask.h> +#include <linux/types.h> + +#include <uapi/asm/hwprobe.h> +#include <uapi/asm/vendor/sifive.h> + +void hwprobe_isa_vendor_ext_sifive_0(struct riscv_hwprobe *pair, const struct cpumask *cpus) +{ + VENDOR_EXTENSION_SUPPORTED(pair, cpus, + riscv_isa_vendor_ext_list_sifive.per_hart_isa_bitmap, { + VENDOR_EXT_KEY(XSFVQMACCDOD); + VENDOR_EXT_KEY(XSFVQMACCQOQ); + VENDOR_EXT_KEY(XSFVFNRCLIPXFQF); + VENDOR_EXT_KEY(XSFVFWMACCQQQ); + }); +} diff --git a/arch/riscv/lib/riscv_v_helpers.c b/arch/riscv/lib/riscv_v_helpers.c index be38a93cedae..7bbdfc6d4552 100644 --- a/arch/riscv/lib/riscv_v_helpers.c +++ b/arch/riscv/lib/riscv_v_helpers.c @@ -16,8 +16,11 @@ #ifdef CONFIG_MMU size_t riscv_v_usercopy_threshold = CONFIG_RISCV_ISA_V_UCOPY_THRESHOLD; int __asm_vector_usercopy(void *dst, void *src, size_t n); +int __asm_vector_usercopy_sum_enabled(void *dst, void *src, size_t n); int fallback_scalar_usercopy(void *dst, void *src, size_t n); -asmlinkage int enter_vector_usercopy(void *dst, void *src, size_t n) +int fallback_scalar_usercopy_sum_enabled(void *dst, void *src, size_t n); +asmlinkage int enter_vector_usercopy(void *dst, void *src, size_t n, + bool enable_sum) { size_t remain, copied; @@ -26,7 +29,8 @@ asmlinkage int enter_vector_usercopy(void *dst, void *src, size_t n) goto fallback; kernel_vector_begin(); - remain = __asm_vector_usercopy(dst, src, n); + remain = enable_sum ? __asm_vector_usercopy(dst, src, n) : + __asm_vector_usercopy_sum_enabled(dst, src, n); kernel_vector_end(); if (remain) { @@ -40,6 +44,7 @@ asmlinkage int enter_vector_usercopy(void *dst, void *src, size_t n) return remain; fallback: - return fallback_scalar_usercopy(dst, src, n); + return enable_sum ? fallback_scalar_usercopy(dst, src, n) : + fallback_scalar_usercopy_sum_enabled(dst, src, n); } #endif diff --git a/arch/riscv/lib/uaccess.S b/arch/riscv/lib/uaccess.S index 6a9f116bb545..4efea1b3326c 100644 --- a/arch/riscv/lib/uaccess.S +++ b/arch/riscv/lib/uaccess.S @@ -17,14 +17,43 @@ SYM_FUNC_START(__asm_copy_to_user) ALTERNATIVE("j fallback_scalar_usercopy", "nop", 0, RISCV_ISA_EXT_ZVE32X, CONFIG_RISCV_ISA_V) REG_L t0, riscv_v_usercopy_threshold bltu a2, t0, fallback_scalar_usercopy - tail enter_vector_usercopy + li a3, 1 + tail enter_vector_usercopy #endif -SYM_FUNC_START(fallback_scalar_usercopy) +SYM_FUNC_END(__asm_copy_to_user) +EXPORT_SYMBOL(__asm_copy_to_user) +SYM_FUNC_ALIAS(__asm_copy_from_user, __asm_copy_to_user) +EXPORT_SYMBOL(__asm_copy_from_user) +SYM_FUNC_START(fallback_scalar_usercopy) /* Enable access to user memory */ - li t6, SR_SUM - csrs CSR_STATUS, t6 + li t6, SR_SUM + csrs CSR_STATUS, t6 + mv t6, ra + call fallback_scalar_usercopy_sum_enabled + + /* Disable access to user memory */ + mv ra, t6 + li t6, SR_SUM + csrc CSR_STATUS, t6 + ret +SYM_FUNC_END(fallback_scalar_usercopy) + +SYM_FUNC_START(__asm_copy_to_user_sum_enabled) +#ifdef CONFIG_RISCV_ISA_V + ALTERNATIVE("j fallback_scalar_usercopy_sum_enabled", "nop", 0, RISCV_ISA_EXT_ZVE32X, CONFIG_RISCV_ISA_V) + REG_L t0, riscv_v_usercopy_threshold + bltu a2, t0, fallback_scalar_usercopy_sum_enabled + li a3, 0 + tail enter_vector_usercopy +#endif +SYM_FUNC_END(__asm_copy_to_user_sum_enabled) +SYM_FUNC_ALIAS(__asm_copy_from_user_sum_enabled, __asm_copy_to_user_sum_enabled) +EXPORT_SYMBOL(__asm_copy_from_user_sum_enabled) +EXPORT_SYMBOL(__asm_copy_to_user_sum_enabled) + +SYM_FUNC_START(fallback_scalar_usercopy_sum_enabled) /* * Save the terminal address which will be used to compute the number * of bytes copied in case of a fixup exception. @@ -178,23 +207,12 @@ SYM_FUNC_START(fallback_scalar_usercopy) bltu a0, t0, 4b /* t0 - end of dst */ .Lout_copy_user: - /* Disable access to user memory */ - csrc CSR_STATUS, t6 li a0, 0 ret - - /* Exception fixup code */ 10: - /* Disable access to user memory */ - csrc CSR_STATUS, t6 sub a0, t5, a0 ret -SYM_FUNC_END(__asm_copy_to_user) -SYM_FUNC_END(fallback_scalar_usercopy) -EXPORT_SYMBOL(__asm_copy_to_user) -SYM_FUNC_ALIAS(__asm_copy_from_user, __asm_copy_to_user) -EXPORT_SYMBOL(__asm_copy_from_user) - +SYM_FUNC_END(fallback_scalar_usercopy_sum_enabled) SYM_FUNC_START(__clear_user) diff --git a/arch/riscv/lib/uaccess_vector.S b/arch/riscv/lib/uaccess_vector.S index 7c45f26de4f7..03b5560609a2 100644 --- a/arch/riscv/lib/uaccess_vector.S +++ b/arch/riscv/lib/uaccess_vector.S @@ -24,7 +24,18 @@ SYM_FUNC_START(__asm_vector_usercopy) /* Enable access to user memory */ li t6, SR_SUM csrs CSR_STATUS, t6 + mv t6, ra + call __asm_vector_usercopy_sum_enabled + + /* Disable access to user memory */ + mv ra, t6 + li t6, SR_SUM + csrc CSR_STATUS, t6 + ret +SYM_FUNC_END(__asm_vector_usercopy) + +SYM_FUNC_START(__asm_vector_usercopy_sum_enabled) loop: vsetvli iVL, iNum, e8, ELEM_LMUL_SETTING, ta, ma fixup vle8.v vData, (pSrc), 10f @@ -36,8 +47,6 @@ loop: /* Exception fixup for vector load is shared with normal exit */ 10: - /* Disable access to user memory */ - csrc CSR_STATUS, t6 mv a0, iNum ret @@ -49,4 +58,4 @@ loop: csrr t2, CSR_VSTART sub iNum, iNum, t2 j 10b -SYM_FUNC_END(__asm_vector_usercopy) +SYM_FUNC_END(__asm_vector_usercopy_sum_enabled) diff --git a/arch/riscv/mm/cacheflush.c b/arch/riscv/mm/cacheflush.c index b8e96dfff19d..4ca5aafce22e 100644 --- a/arch/riscv/mm/cacheflush.c +++ b/arch/riscv/mm/cacheflush.c @@ -24,7 +24,20 @@ void flush_icache_all(void) if (num_online_cpus() < 2) return; - else if (riscv_use_sbi_for_rfence()) + + /* + * Make sure all previous writes to the D$ are ordered before making + * the IPI. The RISC-V spec states that a hart must execute a data fence + * before triggering a remote fence.i in order to make the modification + * visable for remote harts. + * + * IPIs on RISC-V are triggered by MMIO writes to either CLINT or + * S-IMSIC, so the fence ensures previous data writes "happen before" + * the MMIO. + */ + RISCV_FENCE(w, o); + + if (riscv_use_sbi_for_rfence()) sbi_remote_fence_i(NULL); else on_each_cpu(ipi_remote_fence_i, NULL, 1); @@ -101,6 +114,9 @@ EXPORT_SYMBOL_GPL(riscv_cbom_block_size); unsigned int riscv_cboz_block_size; EXPORT_SYMBOL_GPL(riscv_cboz_block_size); +unsigned int riscv_cbop_block_size; +EXPORT_SYMBOL_GPL(riscv_cbop_block_size); + static void __init cbo_get_block_size(struct device_node *node, const char *name, u32 *block_size, unsigned long *first_hartid) @@ -125,8 +141,8 @@ static void __init cbo_get_block_size(struct device_node *node, void __init riscv_init_cbo_blocksizes(void) { - unsigned long cbom_hartid, cboz_hartid; - u32 cbom_block_size = 0, cboz_block_size = 0; + unsigned long cbom_hartid, cboz_hartid, cbop_hartid; + u32 cbom_block_size = 0, cboz_block_size = 0, cbop_block_size = 0; struct device_node *node; struct acpi_table_header *rhct; acpi_status status; @@ -138,13 +154,15 @@ void __init riscv_init_cbo_blocksizes(void) &cbom_block_size, &cbom_hartid); cbo_get_block_size(node, "riscv,cboz-block-size", &cboz_block_size, &cboz_hartid); + cbo_get_block_size(node, "riscv,cbop-block-size", + &cbop_block_size, &cbop_hartid); } } else { status = acpi_get_table(ACPI_SIG_RHCT, 0, &rhct); if (ACPI_FAILURE(status)) return; - acpi_get_cbo_block_size(rhct, &cbom_block_size, &cboz_block_size, NULL); + acpi_get_cbo_block_size(rhct, &cbom_block_size, &cboz_block_size, &cbop_block_size); acpi_put_table((struct acpi_table_header *)rhct); } @@ -153,6 +171,9 @@ void __init riscv_init_cbo_blocksizes(void) if (cboz_block_size) riscv_cboz_block_size = cboz_block_size; + + if (cbop_block_size) + riscv_cbop_block_size = cbop_block_size; } #ifdef CONFIG_SMP diff --git a/arch/riscv/mm/pgtable.c b/arch/riscv/mm/pgtable.c index 4ae67324f992..8b6c0a112a8d 100644 --- a/arch/riscv/mm/pgtable.c +++ b/arch/riscv/mm/pgtable.c @@ -154,4 +154,14 @@ pmd_t pmdp_collapse_flush(struct vm_area_struct *vma, flush_tlb_mm(vma->vm_mm); return pmd; } + +pud_t pudp_invalidate(struct vm_area_struct *vma, unsigned long address, + pud_t *pudp) +{ + VM_WARN_ON_ONCE(!pud_present(*pudp)); + pud_t old = pudp_establish(vma, address, pudp, pud_mkinvalid(*pudp)); + + flush_pud_tlb_range(vma, address, address + HPAGE_PUD_SIZE); + return old; +} #endif /* CONFIG_TRANSPARENT_HUGEPAGE */ diff --git a/arch/riscv/mm/tlbflush.c b/arch/riscv/mm/tlbflush.c index f9e27ba1df99..e737ba7949b1 100644 --- a/arch/riscv/mm/tlbflush.c +++ b/arch/riscv/mm/tlbflush.c @@ -7,6 +7,27 @@ #include <linux/mmu_notifier.h> #include <asm/sbi.h> #include <asm/mmu_context.h> +#include <asm/cpufeature.h> + +#define has_svinval() riscv_has_extension_unlikely(RISCV_ISA_EXT_SVINVAL) + +static inline void local_sfence_inval_ir(void) +{ + asm volatile(SFENCE_INVAL_IR() ::: "memory"); +} + +static inline void local_sfence_w_inval(void) +{ + asm volatile(SFENCE_W_INVAL() ::: "memory"); +} + +static inline void local_sinval_vma(unsigned long vma, unsigned long asid) +{ + if (asid != FLUSH_TLB_NO_ASID) + asm volatile(SINVAL_VMA(%0, %1) : : "r" (vma), "r" (asid) : "memory"); + else + asm volatile(SINVAL_VMA(%0, zero) : : "r" (vma) : "memory"); +} /* * Flush entire TLB if number of entries to be flushed is greater @@ -27,6 +48,16 @@ static void local_flush_tlb_range_threshold_asid(unsigned long start, return; } + if (has_svinval()) { + local_sfence_w_inval(); + for (i = 0; i < nr_ptes_in_range; ++i) { + local_sinval_vma(start, asid); + start += stride; + } + local_sfence_inval_ir(); + return; + } + for (i = 0; i < nr_ptes_in_range; ++i) { local_flush_tlb_page_asid(start, asid); start += stride; @@ -182,6 +213,13 @@ void flush_pmd_tlb_range(struct vm_area_struct *vma, unsigned long start, __flush_tlb_range(vma->vm_mm, mm_cpumask(vma->vm_mm), start, end - start, PMD_SIZE); } + +void flush_pud_tlb_range(struct vm_area_struct *vma, unsigned long start, + unsigned long end) +{ + __flush_tlb_range(vma->vm_mm, mm_cpumask(vma->vm_mm), + start, end - start, PUD_SIZE); +} #endif bool arch_tlbbatch_should_defer(struct mm_struct *mm) diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile index db5f3a3faefb..ea5ed6654050 100644 --- a/arch/s390/kernel/Makefile +++ b/arch/s390/kernel/Makefile @@ -46,7 +46,7 @@ obj-y += nospec-branch.o ipl_vmparm.o machine_kexec_reloc.o unwind_bc.o obj-y += smp.o text_amode31.o stacktrace.o abs_lowcore.o facility.o uv.o wti.o obj-y += diag/ -extra-y += vmlinux.lds +always-$(KBUILD_BUILTIN) += vmlinux.lds obj-$(CONFIG_SYSFS) += nospec-sysfs.o CFLAGS_REMOVE_nospec-branch.o += $(CC_FLAGS_EXPOLINE) diff --git a/arch/s390/kvm/gaccess.c b/arch/s390/kvm/gaccess.c index e23670e1949c..21c2e61fece4 100644 --- a/arch/s390/kvm/gaccess.c +++ b/arch/s390/kvm/gaccess.c @@ -319,7 +319,7 @@ enum prot_type { PROT_TYPE_DAT = 3, PROT_TYPE_IEP = 4, /* Dummy value for passing an initialized value when code != PGM_PROTECTION */ - PROT_NONE, + PROT_TYPE_DUMMY, }; static int trans_exc_ending(struct kvm_vcpu *vcpu, int code, unsigned long gva, u8 ar, @@ -335,7 +335,7 @@ static int trans_exc_ending(struct kvm_vcpu *vcpu, int code, unsigned long gva, switch (code) { case PGM_PROTECTION: switch (prot) { - case PROT_NONE: + case PROT_TYPE_DUMMY: /* We should never get here, acts like termination */ WARN_ON_ONCE(1); break; @@ -805,7 +805,7 @@ static int guest_range_to_gpas(struct kvm_vcpu *vcpu, unsigned long ga, u8 ar, gpa = kvm_s390_real_to_abs(vcpu, ga); if (!kvm_is_gpa_in_memslot(vcpu->kvm, gpa)) { rc = PGM_ADDRESSING; - prot = PROT_NONE; + prot = PROT_TYPE_DUMMY; } } if (rc) @@ -963,7 +963,7 @@ int access_guest_with_key(struct kvm_vcpu *vcpu, unsigned long ga, u8 ar, if (rc == PGM_PROTECTION) prot = PROT_TYPE_KEYC; else - prot = PROT_NONE; + prot = PROT_TYPE_DUMMY; rc = trans_exc_ending(vcpu, rc, ga, ar, mode, prot, terminate); } out_unlock: diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index 3829521450dd..e1ad05bfd28a 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c @@ -441,6 +441,8 @@ void do_secure_storage_access(struct pt_regs *regs) if (rc) BUG(); } else { + if (faulthandler_disabled()) + return handle_fault_error_nolock(regs, 0); mm = current->mm; mmap_read_lock(mm); vma = find_vma(mm, addr); diff --git a/arch/sh/boards/mach-ecovec24/setup.c b/arch/sh/boards/mach-ecovec24/setup.c index 6f13557eecd6..a641e26f8fdf 100644 --- a/arch/sh/boards/mach-ecovec24/setup.c +++ b/arch/sh/boards/mach-ecovec24/setup.c @@ -825,6 +825,7 @@ static struct spi_board_info spi_bus[] = { /* MSIOF0 */ static struct sh_msiof_spi_info msiof0_data = { .num_chipselect = 1, + .mode = MSIOF_SPI_HOST, }; static struct resource msiof0_resources[] = { diff --git a/arch/sh/drivers/heartbeat.c b/arch/sh/drivers/heartbeat.c index 24391b444b28..42103038a7d0 100644 --- a/arch/sh/drivers/heartbeat.c +++ b/arch/sh/drivers/heartbeat.c @@ -58,7 +58,7 @@ static inline void heartbeat_toggle_bit(struct heartbeat_data *hd, static void heartbeat_timer(struct timer_list *t) { - struct heartbeat_data *hd = from_timer(hd, t, timer); + struct heartbeat_data *hd = timer_container_of(hd, t, timer); static unsigned bit = 0, up = 1; heartbeat_toggle_bit(hd, bit, hd->flags & HEARTBEAT_INVERTED); diff --git a/arch/sh/drivers/pci/common.c b/arch/sh/drivers/pci/common.c index 5442475d132e..9633b6147a05 100644 --- a/arch/sh/drivers/pci/common.c +++ b/arch/sh/drivers/pci/common.c @@ -88,7 +88,7 @@ int __init pci_is_66mhz_capable(struct pci_channel *hose, static void pcibios_enable_err(struct timer_list *t) { - struct pci_channel *hose = from_timer(hose, t, err_timer); + struct pci_channel *hose = timer_container_of(hose, t, err_timer); timer_delete(&hose->err_timer); printk(KERN_DEBUG "PCI: re-enabling error IRQ.\n"); @@ -97,7 +97,7 @@ static void pcibios_enable_err(struct timer_list *t) static void pcibios_enable_serr(struct timer_list *t) { - struct pci_channel *hose = from_timer(hose, t, serr_timer); + struct pci_channel *hose = timer_container_of(hose, t, serr_timer); timer_delete(&hose->serr_timer); printk(KERN_DEBUG "PCI: re-enabling system error IRQ.\n"); diff --git a/arch/sh/drivers/push-switch.c b/arch/sh/drivers/push-switch.c index 2b51ad9d5586..443cc6fd26a8 100644 --- a/arch/sh/drivers/push-switch.c +++ b/arch/sh/drivers/push-switch.c @@ -25,7 +25,7 @@ static DEVICE_ATTR_RO(switch); static void switch_timer(struct timer_list *t) { - struct push_switch *psw = from_timer(psw, t, debounce); + struct push_switch *psw = timer_container_of(psw, t, debounce); schedule_work(&psw->work); } diff --git a/arch/sh/include/asm/cache.h b/arch/sh/include/asm/cache.h index b38dbc975581..e7ac9c950275 100644 --- a/arch/sh/include/asm/cache.h +++ b/arch/sh/include/asm/cache.h @@ -22,7 +22,7 @@ #define __read_mostly __section(".data..read_mostly") -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ struct cache_info { unsigned int ways; /* Number of cache ways */ unsigned int sets; /* Number of cache sets */ @@ -48,5 +48,5 @@ struct cache_info { unsigned long flags; }; -#endif /* __ASSEMBLY__ */ +#endif /* __ASSEMBLER__ */ #endif /* __ASM_SH_CACHE_H */ diff --git a/arch/sh/include/asm/dwarf.h b/arch/sh/include/asm/dwarf.h index 571954474122..f46d18b84833 100644 --- a/arch/sh/include/asm/dwarf.h +++ b/arch/sh/include/asm/dwarf.h @@ -189,7 +189,7 @@ */ #define DWARF_ARCH_RA_REG 17 -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #include <linux/compiler.h> #include <linux/bug.h> @@ -379,7 +379,7 @@ extern int module_dwarf_finalize(const Elf_Ehdr *, const Elf_Shdr *, struct module *); extern void module_dwarf_cleanup(struct module *); -#endif /* !__ASSEMBLY__ */ +#endif /* !__ASSEMBLER__ */ #define CFI_STARTPROC .cfi_startproc #define CFI_ENDPROC .cfi_endproc @@ -402,7 +402,7 @@ extern void module_dwarf_cleanup(struct module *); #define CFI_REL_OFFSET CFI_IGNORE #define CFI_UNDEFINED CFI_IGNORE -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ static inline void dwarf_unwinder_init(void) { } diff --git a/arch/sh/include/asm/fpu.h b/arch/sh/include/asm/fpu.h index 0379f4cce5ed..a086e38b70ee 100644 --- a/arch/sh/include/asm/fpu.h +++ b/arch/sh/include/asm/fpu.h @@ -2,7 +2,7 @@ #ifndef __ASM_SH_FPU_H #define __ASM_SH_FPU_H -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #include <asm/ptrace.h> @@ -67,6 +67,6 @@ static inline void clear_fpu(struct task_struct *tsk, struct pt_regs *regs) void float_raise(unsigned int flags); int float_rounding_mode(void); -#endif /* __ASSEMBLY__ */ +#endif /* __ASSEMBLER__ */ #endif /* __ASM_SH_FPU_H */ diff --git a/arch/sh/include/asm/ftrace.h b/arch/sh/include/asm/ftrace.h index 1c10e1066390..d35781ab716e 100644 --- a/arch/sh/include/asm/ftrace.h +++ b/arch/sh/include/asm/ftrace.h @@ -7,7 +7,7 @@ #define MCOUNT_INSN_SIZE 4 /* sizeof mcount call */ #define FTRACE_SYSCALL_MAX NR_syscalls -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ extern void mcount(void); #define MCOUNT_ADDR ((unsigned long)(mcount)) @@ -35,10 +35,10 @@ static inline unsigned long ftrace_call_adjust(unsigned long addr) void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr); -#endif /* __ASSEMBLY__ */ +#endif /* __ASSEMBLER__ */ #endif /* CONFIG_FUNCTION_TRACER */ -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ /* arch/sh/kernel/return_address.c */ extern void *return_address(unsigned int); @@ -53,6 +53,6 @@ static inline void arch_ftrace_nmi_enter(void) { } static inline void arch_ftrace_nmi_exit(void) { } #endif -#endif /* __ASSEMBLY__ */ +#endif /* __ASSEMBLER__ */ #endif /* __ASM_SH_FTRACE_H */ diff --git a/arch/sh/include/asm/mmu.h b/arch/sh/include/asm/mmu.h index 172e329fd92d..b9c9f91e6616 100644 --- a/arch/sh/include/asm/mmu.h +++ b/arch/sh/include/asm/mmu.h @@ -33,7 +33,7 @@ #define PMB_NO_ENTRY (-1) -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #include <linux/errno.h> #include <linux/threads.h> #include <asm/page.h> @@ -102,6 +102,6 @@ pmb_remap(phys_addr_t phys, unsigned long size, pgprot_t prot) return pmb_remap_caller(phys, size, prot, __builtin_return_address(0)); } -#endif /* __ASSEMBLY__ */ +#endif /* __ASSEMBLER__ */ #endif /* __MMU_H */ diff --git a/arch/sh/include/asm/page.h b/arch/sh/include/asm/page.h index 3990cbd9aa04..def4205491ec 100644 --- a/arch/sh/include/asm/page.h +++ b/arch/sh/include/asm/page.h @@ -30,7 +30,7 @@ #define HUGETLB_PAGE_ORDER (HPAGE_SHIFT-PAGE_SHIFT) #endif -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #include <asm/uncached.h> extern unsigned long shm_align_mask; @@ -85,7 +85,7 @@ typedef struct page *pgtable_t; #define pte_pgprot(x) __pgprot(pte_val(x) & PTE_FLAGS_MASK) -#endif /* !__ASSEMBLY__ */ +#endif /* !__ASSEMBLER__ */ /* * __MEMORY_START and SIZE are the physical addresses and size of RAM. @@ -126,10 +126,10 @@ typedef struct page *pgtable_t; #define ___va(x) ((x)+PAGE_OFFSET) #endif -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #define __pa(x) ___pa((unsigned long)x) #define __va(x) (void *)___va((unsigned long)x) -#endif /* !__ASSEMBLY__ */ +#endif /* !__ASSEMBLER__ */ #ifdef CONFIG_UNCACHED_MAPPING #if defined(CONFIG_29BIT) diff --git a/arch/sh/include/asm/pgtable.h b/arch/sh/include/asm/pgtable.h index 729f5c6225fb..10fa8f2bb8d1 100644 --- a/arch/sh/include/asm/pgtable.h +++ b/arch/sh/include/asm/pgtable.h @@ -17,7 +17,7 @@ #include <asm/page.h> #include <asm/mmu.h> -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #include <asm/addrspace.h> #include <asm/fixmap.h> @@ -28,7 +28,7 @@ extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)]; #define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page)) -#endif /* !__ASSEMBLY__ */ +#endif /* !__ASSEMBLER__ */ /* * Effective and physical address definitions, to aid with sign diff --git a/arch/sh/include/asm/pgtable_32.h b/arch/sh/include/asm/pgtable_32.h index db2e48366e0d..71b18741cc11 100644 --- a/arch/sh/include/asm/pgtable_32.h +++ b/arch/sh/include/asm/pgtable_32.h @@ -170,7 +170,7 @@ static inline unsigned long copy_ptea_attributes(unsigned long x) (PTE_MASK | _PAGE_ACCESSED | _PAGE_CACHABLE | \ _PAGE_DIRTY | _PAGE_SPECIAL) -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #if defined(CONFIG_X2TLB) /* SH-X2 TLB */ #define PAGE_NONE __pgprot(_PAGE_PROTNONE | _PAGE_CACHABLE | \ @@ -287,9 +287,9 @@ static inline unsigned long copy_ptea_attributes(unsigned long x) __pgprot(0) #endif -#endif /* __ASSEMBLY__ */ +#endif /* __ASSEMBLER__ */ -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ /* * Certain architectures need to do special things when PTEs @@ -478,5 +478,5 @@ static inline int pte_swp_exclusive(pte_t pte) PTE_BIT_FUNC(low, swp_mkexclusive, |= _PAGE_SWP_EXCLUSIVE); PTE_BIT_FUNC(low, swp_clear_exclusive, &= ~_PAGE_SWP_EXCLUSIVE); -#endif /* __ASSEMBLY__ */ +#endif /* __ASSEMBLER__ */ #endif /* __ASM_SH_PGTABLE_32_H */ diff --git a/arch/sh/include/asm/processor.h b/arch/sh/include/asm/processor.h index 73fba7c922f9..2a0b5713ab80 100644 --- a/arch/sh/include/asm/processor.h +++ b/arch/sh/include/asm/processor.h @@ -5,7 +5,7 @@ #include <asm/cpu-features.h> #include <asm/cache.h> -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ /* * CPU type and hardware bug flags. Kept separately for each CPU. * @@ -168,7 +168,7 @@ extern unsigned int instruction_size(unsigned int insn); void select_idle_routine(void); -#endif /* __ASSEMBLY__ */ +#endif /* __ASSEMBLER__ */ #include <asm/processor_32.h> diff --git a/arch/sh/include/asm/smc37c93x.h b/arch/sh/include/asm/smc37c93x.h index 891f2f8f2fd0..caf4cd8dd241 100644 --- a/arch/sh/include/asm/smc37c93x.h +++ b/arch/sh/include/asm/smc37c93x.h @@ -67,7 +67,7 @@ #define UART_DLL 0x0 /* Divisor Latch (LS) */ #define UART_DLM 0x2 /* Divisor Latch (MS) */ -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ typedef struct uart_reg { volatile __u16 rbr; volatile __u16 ier; @@ -78,7 +78,7 @@ typedef struct uart_reg { volatile __u16 msr; volatile __u16 scr; } uart_reg; -#endif /* ! __ASSEMBLY__ */ +#endif /* ! __ASSEMBLER__ */ /* Alias for Write Only Register */ diff --git a/arch/sh/include/asm/suspend.h b/arch/sh/include/asm/suspend.h index 47db17520261..0f991babc559 100644 --- a/arch/sh/include/asm/suspend.h +++ b/arch/sh/include/asm/suspend.h @@ -2,7 +2,7 @@ #ifndef _ASM_SH_SUSPEND_H #define _ASM_SH_SUSPEND_H -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #include <linux/notifier.h> #include <asm/ptrace.h> diff --git a/arch/sh/include/asm/thread_info.h b/arch/sh/include/asm/thread_info.h index 9f19a682d315..471db5173036 100644 --- a/arch/sh/include/asm/thread_info.h +++ b/arch/sh/include/asm/thread_info.h @@ -21,7 +21,7 @@ #define FAULT_CODE_PROT (1 << 3) /* protection fault */ #define FAULT_CODE_USER (1 << 4) /* user-mode access */ -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #include <asm/processor.h> struct thread_info { @@ -49,7 +49,7 @@ struct thread_info { /* * macros/functions for gaining access to the thread information structure */ -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #define INIT_THREAD_INFO(tsk) \ { \ .task = &tsk, \ @@ -86,7 +86,7 @@ static inline struct thread_info *current_thread_info(void) extern void init_thread_xstate(void); -#endif /* __ASSEMBLY__ */ +#endif /* __ASSEMBLER__ */ /* * Thread information flags @@ -144,7 +144,7 @@ extern void init_thread_xstate(void); */ #define TS_USEDFPU 0x0002 /* FPU used by this task this quantum */ -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #define TI_FLAG_FAULT_CODE_SHIFT 24 @@ -164,5 +164,5 @@ static inline unsigned int get_thread_fault_code(void) return ti->flags >> TI_FLAG_FAULT_CODE_SHIFT; } -#endif /* !__ASSEMBLY__ */ +#endif /* !__ASSEMBLER__ */ #endif /* __ASM_SH_THREAD_INFO_H */ diff --git a/arch/sh/include/asm/tlb.h b/arch/sh/include/asm/tlb.h index ddf324bfb9a0..39df40d0ebc2 100644 --- a/arch/sh/include/asm/tlb.h +++ b/arch/sh/include/asm/tlb.h @@ -2,7 +2,7 @@ #ifndef __ASM_SH_TLB_H #define __ASM_SH_TLB_H -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #include <linux/pagemap.h> #include <asm-generic/tlb.h> @@ -29,5 +29,5 @@ asmlinkage int handle_tlbmiss(struct pt_regs *regs, unsigned long error_code, unsigned long address); #endif /* CONFIG_MMU */ -#endif /* __ASSEMBLY__ */ +#endif /* __ASSEMBLER__ */ #endif /* __ASM_SH_TLB_H */ diff --git a/arch/sh/include/asm/types.h b/arch/sh/include/asm/types.h index 9b3fc923ee28..fec3e89df0b1 100644 --- a/arch/sh/include/asm/types.h +++ b/arch/sh/include/asm/types.h @@ -7,10 +7,10 @@ /* * These aren't exported outside the kernel to avoid name space clashes */ -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ typedef u16 insn_size_t; typedef u32 reg_size_t; -#endif /* __ASSEMBLY__ */ +#endif /* __ASSEMBLER__ */ #endif /* __ASM_SH_TYPES_H */ diff --git a/arch/sh/include/mach-common/mach/romimage.h b/arch/sh/include/mach-common/mach/romimage.h index 1915714263aa..22fb47ec9b15 100644 --- a/arch/sh/include/mach-common/mach/romimage.h +++ b/arch/sh/include/mach-common/mach/romimage.h @@ -1,12 +1,12 @@ /* SPDX-License-Identifier: GPL-2.0 */ -#ifdef __ASSEMBLY__ +#ifdef __ASSEMBLER__ /* do nothing here by default */ -#else /* __ASSEMBLY__ */ +#else /* __ASSEMBLER__ */ static inline void mmcif_update_progress(int nr) { } -#endif /* __ASSEMBLY__ */ +#endif /* __ASSEMBLER__ */ diff --git a/arch/sh/include/mach-ecovec24/mach/romimage.h b/arch/sh/include/mach-ecovec24/mach/romimage.h index 2da6ff326cbd..f93d494736c3 100644 --- a/arch/sh/include/mach-ecovec24/mach/romimage.h +++ b/arch/sh/include/mach-ecovec24/mach/romimage.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0 */ -#ifdef __ASSEMBLY__ +#ifdef __ASSEMBLER__ /* EcoVec board specific boot code: * converts the "partner-jet-script.txt" script into assembly @@ -22,7 +22,7 @@ 1 : .long 0xa8000000 2 : -#else /* __ASSEMBLY__ */ +#else /* __ASSEMBLER__ */ /* Ecovec board specific information: * @@ -45,4 +45,4 @@ static inline void mmcif_update_progress(int nr) __raw_writeb(1 << (nr - 1), PGDR); } -#endif /* __ASSEMBLY__ */ +#endif /* __ASSEMBLER__ */ diff --git a/arch/sh/include/mach-kfr2r09/mach/romimage.h b/arch/sh/include/mach-kfr2r09/mach/romimage.h index 209275872ff0..f68bb480d378 100644 --- a/arch/sh/include/mach-kfr2r09/mach/romimage.h +++ b/arch/sh/include/mach-kfr2r09/mach/romimage.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0 */ -#ifdef __ASSEMBLY__ +#ifdef __ASSEMBLER__ /* kfr2r09 board specific boot code: * converts the "partner-jet-script.txt" script into assembly @@ -22,10 +22,10 @@ 1: .long 0xa8000000 2: -#else /* __ASSEMBLY__ */ +#else /* __ASSEMBLER__ */ static inline void mmcif_update_progress(int nr) { } -#endif /* __ASSEMBLY__ */ +#endif /* __ASSEMBLER__ */ diff --git a/arch/sh/kernel/Makefile b/arch/sh/kernel/Makefile index 7b453592adaf..5ef123bc63f8 100644 --- a/arch/sh/kernel/Makefile +++ b/arch/sh/kernel/Makefile @@ -3,7 +3,7 @@ # Makefile for the Linux/SuperH kernel. # -extra-y := vmlinux.lds +always-$(KBUILD_BUILTIN) := vmlinux.lds ifdef CONFIG_FUNCTION_TRACER # Do not profile debug and lowlevel utilities diff --git a/arch/sh/kernel/kprobes.c b/arch/sh/kernel/kprobes.c index 49c4ffd782d6..a250fb1b9420 100644 --- a/arch/sh/kernel/kprobes.c +++ b/arch/sh/kernel/kprobes.c @@ -404,13 +404,10 @@ int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr) int __kprobes kprobe_exceptions_notify(struct notifier_block *self, unsigned long val, void *data) { - struct kprobe *p = NULL; struct die_args *args = (struct die_args *)data; int ret = NOTIFY_DONE; - kprobe_opcode_t *addr = NULL; struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); - addr = (kprobe_opcode_t *) (args->regs->pc); if (val == DIE_TRAP && args->trapnr == (BREAKPOINT_INSTRUCTION & 0xff)) { if (!kprobe_running()) { @@ -421,7 +418,6 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self, ret = NOTIFY_DONE; } } else { - p = get_kprobe(addr); if ((kcb->kprobe_status == KPROBE_HIT_SS) || (kcb->kprobe_status == KPROBE_REENTER)) { if (post_kprobe_handler(args->regs)) diff --git a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile index 3453f330e363..36f2727e1445 100644 --- a/arch/sparc/kernel/Makefile +++ b/arch/sparc/kernel/Makefile @@ -9,7 +9,7 @@ asflags-y := -ansi # Undefine sparc when processing vmlinux.lds - it is used # And teach CPP we are doing $(BITS) builds (for this case) CPPFLAGS_vmlinux.lds := -Usparc -m$(BITS) -extra-y += vmlinux.lds +always-$(KBUILD_BUILTIN) += vmlinux.lds ifdef CONFIG_FUNCTION_TRACER # Do not profile debug and lowlevel utilities diff --git a/arch/sparc/kernel/viohs.c b/arch/sparc/kernel/viohs.c index e27afd233bf5..8fb2e7ca5015 100644 --- a/arch/sparc/kernel/viohs.c +++ b/arch/sparc/kernel/viohs.c @@ -804,7 +804,7 @@ EXPORT_SYMBOL(vio_port_up); static void vio_port_timer(struct timer_list *t) { - struct vio_driver_state *vio = from_timer(vio, t, timer); + struct vio_driver_state *vio = timer_container_of(vio, t, timer); vio_port_up(vio); } diff --git a/arch/um/drivers/vector_kern.c b/arch/um/drivers/vector_kern.c index 5226d2c52e6a..f292e0b4ff8b 100644 --- a/arch/um/drivers/vector_kern.c +++ b/arch/um/drivers/vector_kern.c @@ -1534,7 +1534,7 @@ static const struct net_device_ops vector_netdev_ops = { static void vector_timer_expire(struct timer_list *t) { - struct vector_private *vp = from_timer(vp, t, tl); + struct vector_private *vp = timer_container_of(vp, t, tl); vp->estats.tx_kicks++; napi_schedule(&vp->napi); diff --git a/arch/um/kernel/Makefile b/arch/um/kernel/Makefile index 4669db2aa9be..b8f4e9281599 100644 --- a/arch/um/kernel/Makefile +++ b/arch/um/kernel/Makefile @@ -12,7 +12,7 @@ CPPFLAGS_vmlinux.lds := -DSTART=$(LDS_START) \ -DELF_ARCH=$(LDS_ELF_ARCH) \ -DELF_FORMAT=$(LDS_ELF_FORMAT) \ $(LDS_EXTRA) -extra-y := vmlinux.lds +always-$(KBUILD_BUILTIN) := vmlinux.lds obj-y = config.o exec.o exitcode.o irq.o ksyms.o mem.o \ physmem.o process.o ptrace.o reboot.o sigio.o \ diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c index 466283326630..741b229f0718 100644 --- a/arch/x86/events/intel/core.c +++ b/arch/x86/events/intel/core.c @@ -2900,6 +2900,7 @@ static void intel_pmu_config_acr(int idx, u64 mask, u32 reload) { struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); int msr_b, msr_c; + int msr_offset; if (!mask && !cpuc->acr_cfg_b[idx]) return; @@ -2907,19 +2908,20 @@ static void intel_pmu_config_acr(int idx, u64 mask, u32 reload) if (idx < INTEL_PMC_IDX_FIXED) { msr_b = MSR_IA32_PMC_V6_GP0_CFG_B; msr_c = MSR_IA32_PMC_V6_GP0_CFG_C; + msr_offset = x86_pmu.addr_offset(idx, false); } else { msr_b = MSR_IA32_PMC_V6_FX0_CFG_B; msr_c = MSR_IA32_PMC_V6_FX0_CFG_C; - idx -= INTEL_PMC_IDX_FIXED; + msr_offset = x86_pmu.addr_offset(idx - INTEL_PMC_IDX_FIXED, false); } if (cpuc->acr_cfg_b[idx] != mask) { - wrmsrl(msr_b + x86_pmu.addr_offset(idx, false), mask); + wrmsrl(msr_b + msr_offset, mask); cpuc->acr_cfg_b[idx] = mask; } /* Only need to update the reload value when there is a valid config value. */ if (mask && cpuc->acr_cfg_c[idx] != reload) { - wrmsrl(msr_c + x86_pmu.addr_offset(idx, false), reload); + wrmsrl(msr_c + msr_offset, reload); cpuc->acr_cfg_c[idx] = reload; } } diff --git a/arch/x86/include/asm/trace/fpu.h b/arch/x86/include/asm/trace/fpu.h index 0454d5e60e5d..721b408d9a67 100644 --- a/arch/x86/include/asm/trace/fpu.h +++ b/arch/x86/include/asm/trace/fpu.h @@ -44,16 +44,6 @@ DEFINE_EVENT(x86_fpu, x86_fpu_after_save, TP_ARGS(fpu) ); -DEFINE_EVENT(x86_fpu, x86_fpu_before_restore, - TP_PROTO(struct fpu *fpu), - TP_ARGS(fpu) -); - -DEFINE_EVENT(x86_fpu, x86_fpu_after_restore, - TP_PROTO(struct fpu *fpu), - TP_ARGS(fpu) -); - DEFINE_EVENT(x86_fpu, x86_fpu_regs_activated, TP_PROTO(struct fpu *fpu), TP_ARGS(fpu) @@ -64,11 +54,6 @@ DEFINE_EVENT(x86_fpu, x86_fpu_regs_deactivated, TP_ARGS(fpu) ); -DEFINE_EVENT(x86_fpu, x86_fpu_init_state, - TP_PROTO(struct fpu *fpu), - TP_ARGS(fpu) -); - DEFINE_EVENT(x86_fpu, x86_fpu_dropped, TP_PROTO(struct fpu *fpu), TP_ARGS(fpu) diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index 99a783fd4691..0d2a6d953be9 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile @@ -3,7 +3,7 @@ # Makefile for the linux kernel. # -extra-y += vmlinux.lds +always-$(KBUILD_BUILTIN) += vmlinux.lds CPPFLAGS_vmlinux.lds += -U$(UTS_MACHINE) diff --git a/arch/x86/kernel/ioport.c b/arch/x86/kernel/ioport.c index 6290dd120f5e..ff40f09ad911 100644 --- a/arch/x86/kernel/ioport.c +++ b/arch/x86/kernel/ioport.c @@ -33,8 +33,9 @@ void io_bitmap_share(struct task_struct *tsk) set_tsk_thread_flag(tsk, TIF_IO_BITMAP); } -static void task_update_io_bitmap(struct task_struct *tsk) +static void task_update_io_bitmap(void) { + struct task_struct *tsk = current; struct thread_struct *t = &tsk->thread; if (t->iopl_emul == 3 || t->io_bitmap) { @@ -54,7 +55,12 @@ void io_bitmap_exit(struct task_struct *tsk) struct io_bitmap *iobm = tsk->thread.io_bitmap; tsk->thread.io_bitmap = NULL; - task_update_io_bitmap(tsk); + /* + * Don't touch the TSS when invoked on a failed fork(). TSS + * reflects the state of @current and not the state of @tsk. + */ + if (tsk == current) + task_update_io_bitmap(); if (iobm && refcount_dec_and_test(&iobm->refcnt)) kfree(iobm); } @@ -192,8 +198,7 @@ SYSCALL_DEFINE1(iopl, unsigned int, level) } t->iopl_emul = level; - task_update_io_bitmap(current); - + task_update_io_bitmap(); return 0; } diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index c1d2dac72b9c..704883c21f3a 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c @@ -176,6 +176,7 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args) frame->ret_addr = (unsigned long) ret_from_fork_asm; p->thread.sp = (unsigned long) fork_frame; p->thread.io_bitmap = NULL; + clear_tsk_thread_flag(p, TIF_IO_BITMAP); p->thread.iopl_warn = 0; memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps)); @@ -464,6 +465,11 @@ void native_tss_update_io_bitmap(void) } else { struct io_bitmap *iobm = t->io_bitmap; + if (WARN_ON_ONCE(!iobm)) { + clear_thread_flag(TIF_IO_BITMAP); + native_tss_invalidate_io_bitmap(); + } + /* * Only copy bitmap data when the sequence number differs. The * update time is accounted to the incoming task. diff --git a/arch/x86/kvm/xen.c b/arch/x86/kvm/xen.c index 38b33cdd4232..9b029bb29a16 100644 --- a/arch/x86/kvm/xen.c +++ b/arch/x86/kvm/xen.c @@ -1571,7 +1571,8 @@ out: static void cancel_evtchn_poll(struct timer_list *t) { - struct kvm_vcpu *vcpu = from_timer(vcpu, t, arch.xen.poll_timer); + struct kvm_vcpu *vcpu = timer_container_of(vcpu, t, + arch.xen.poll_timer); kvm_make_request(KVM_REQ_UNBLOCK, vcpu); kvm_vcpu_kick(vcpu); diff --git a/arch/xtensa/kernel/Makefile b/arch/xtensa/kernel/Makefile index f28b8e3d717e..d3ef0407401f 100644 --- a/arch/xtensa/kernel/Makefile +++ b/arch/xtensa/kernel/Makefile @@ -3,7 +3,7 @@ # Makefile for the Linux/Xtensa kernel. # -extra-y := vmlinux.lds +always-$(KBUILD_BUILTIN) := vmlinux.lds obj-y := head.o align.o coprocessor.o entry.o irq.o platform.o process.o \ ptrace.o setup.o signal.o stacktrace.o syscall.o time.o traps.o \ diff --git a/arch/xtensa/platforms/iss/network.c b/arch/xtensa/platforms/iss/network.c index c6d8c62695e1..f0a63b2f85cc 100644 --- a/arch/xtensa/platforms/iss/network.c +++ b/arch/xtensa/platforms/iss/network.c @@ -338,7 +338,7 @@ static int iss_net_poll(struct iss_net_private *lp) static void iss_net_timer(struct timer_list *t) { - struct iss_net_private *lp = from_timer(lp, t, timer); + struct iss_net_private *lp = timer_container_of(lp, t, timer); iss_net_poll(lp); mod_timer(&lp->timer, jiffies + lp->timer_val); diff --git a/block/bio-integrity.c b/block/bio-integrity.c index cb94e9be26dc..10912988c8f5 100644 --- a/block/bio-integrity.c +++ b/block/bio-integrity.c @@ -154,10 +154,9 @@ int bio_integrity_add_page(struct bio *bio, struct page *page, EXPORT_SYMBOL(bio_integrity_add_page); static int bio_integrity_copy_user(struct bio *bio, struct bio_vec *bvec, - int nr_vecs, unsigned int len, - unsigned int direction) + int nr_vecs, unsigned int len) { - bool write = direction == ITER_SOURCE; + bool write = op_is_write(bio_op(bio)); struct bio_integrity_payload *bip; struct iov_iter iter; void *buf; @@ -168,7 +167,7 @@ static int bio_integrity_copy_user(struct bio *bio, struct bio_vec *bvec, return -ENOMEM; if (write) { - iov_iter_bvec(&iter, direction, bvec, nr_vecs, len); + iov_iter_bvec(&iter, ITER_SOURCE, bvec, nr_vecs, len); if (!copy_from_iter_full(buf, len, &iter)) { ret = -EFAULT; goto free_buf; @@ -264,7 +263,7 @@ int bio_integrity_map_user(struct bio *bio, struct iov_iter *iter) struct page *stack_pages[UIO_FASTIOV], **pages = stack_pages; struct bio_vec stack_vec[UIO_FASTIOV], *bvec = stack_vec; size_t offset, bytes = iter->count; - unsigned int direction, nr_bvecs; + unsigned int nr_bvecs; int ret, nr_vecs; bool copy; @@ -273,11 +272,6 @@ int bio_integrity_map_user(struct bio *bio, struct iov_iter *iter) if (bytes >> SECTOR_SHIFT > queue_max_hw_sectors(q)) return -E2BIG; - if (bio_data_dir(bio) == READ) - direction = ITER_DEST; - else - direction = ITER_SOURCE; - nr_vecs = iov_iter_npages(iter, BIO_MAX_VECS + 1); if (nr_vecs > BIO_MAX_VECS) return -E2BIG; @@ -300,8 +294,7 @@ int bio_integrity_map_user(struct bio *bio, struct iov_iter *iter) copy = true; if (copy) - ret = bio_integrity_copy_user(bio, bvec, nr_bvecs, bytes, - direction); + ret = bio_integrity_copy_user(bio, bvec, nr_bvecs, bytes); else ret = bio_integrity_init_user(bio, bvec, nr_bvecs, bytes); if (ret) diff --git a/block/blk-core.c b/block/blk-core.c index b862c66018f2..fdac48aec5ef 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -381,7 +381,7 @@ static void blk_queue_usage_counter_release(struct percpu_ref *ref) static void blk_rq_timed_out_timer(struct timer_list *t) { - struct request_queue *q = from_timer(q, t, timeout); + struct request_queue *q = timer_container_of(q, t, timeout); kblockd_schedule_work(&q->timeout_work); } diff --git a/block/blk-integrity.c b/block/blk-integrity.c index a1678f0a9f81..e4e2567061f9 100644 --- a/block/blk-integrity.c +++ b/block/blk-integrity.c @@ -117,13 +117,8 @@ int blk_rq_integrity_map_user(struct request *rq, void __user *ubuf, { int ret; struct iov_iter iter; - unsigned int direction; - if (op_is_write(req_op(rq))) - direction = ITER_DEST; - else - direction = ITER_SOURCE; - iov_iter_ubuf(&iter, direction, ubuf, bytes); + iov_iter_ubuf(&iter, rq_data_dir(rq), ubuf, bytes); ret = bio_integrity_map_user(rq->bio, &iter); if (ret) return ret; diff --git a/block/blk-iolatency.c b/block/blk-iolatency.c index 42c1e0b9a68f..2f8fdecdd7a9 100644 --- a/block/blk-iolatency.c +++ b/block/blk-iolatency.c @@ -658,7 +658,8 @@ static const struct rq_qos_ops blkcg_iolatency_ops = { static void blkiolatency_timer_fn(struct timer_list *t) { - struct blk_iolatency *blkiolat = from_timer(blkiolat, t, timer); + struct blk_iolatency *blkiolat = timer_container_of(blkiolat, t, + timer); struct blkcg_gq *blkg; struct cgroup_subsys_state *pos_css; u64 now = blk_time_get_ns(); diff --git a/block/blk-stat.c b/block/blk-stat.c index 46449da856f8..682a8ddb1173 100644 --- a/block/blk-stat.c +++ b/block/blk-stat.c @@ -76,7 +76,7 @@ void blk_stat_add(struct request *rq, u64 now) static void blk_stat_timer_fn(struct timer_list *t) { - struct blk_stat_callback *cb = from_timer(cb, t, timer); + struct blk_stat_callback *cb = timer_container_of(cb, t, timer); unsigned int bucket; int cpu; diff --git a/block/blk-throttle.c b/block/blk-throttle.c index bd15357f23bd..397b6a410f9e 100644 --- a/block/blk-throttle.c +++ b/block/blk-throttle.c @@ -1125,7 +1125,8 @@ static int throtl_select_dispatch(struct throtl_service_queue *parent_sq) */ static void throtl_pending_timer_fn(struct timer_list *t) { - struct throtl_service_queue *sq = from_timer(sq, t, pending_timer); + struct throtl_service_queue *sq = timer_container_of(sq, t, + pending_timer); struct throtl_grp *tg = sq_to_tg(sq); struct throtl_data *td = sq_to_td(sq); struct throtl_service_queue *parent_sq; diff --git a/block/kyber-iosched.c b/block/kyber-iosched.c index 0f0f8452609a..4dba8405bd01 100644 --- a/block/kyber-iosched.c +++ b/block/kyber-iosched.c @@ -276,7 +276,7 @@ static void kyber_resize_domain(struct kyber_queue_data *kqd, static void kyber_timer_fn(struct timer_list *t) { - struct kyber_queue_data *kqd = from_timer(kqd, t, timer); + struct kyber_queue_data *kqd = timer_container_of(kqd, t, timer); unsigned int sched_domain; int cpu; bool bad = false; diff --git a/drivers/accel/ivpu/ivpu_fw.c b/drivers/accel/ivpu/ivpu_fw.c index ccaaf6c100c0..9db741695401 100644 --- a/drivers/accel/ivpu/ivpu_fw.c +++ b/drivers/accel/ivpu/ivpu_fw.c @@ -55,18 +55,18 @@ static struct { int gen; const char *name; } fw_names[] = { - { IVPU_HW_IP_37XX, "vpu_37xx.bin" }, + { IVPU_HW_IP_37XX, "intel/vpu/vpu_37xx_v1.bin" }, { IVPU_HW_IP_37XX, "intel/vpu/vpu_37xx_v0.0.bin" }, - { IVPU_HW_IP_40XX, "vpu_40xx.bin" }, + { IVPU_HW_IP_40XX, "intel/vpu/vpu_40xx_v1.bin" }, { IVPU_HW_IP_40XX, "intel/vpu/vpu_40xx_v0.0.bin" }, - { IVPU_HW_IP_50XX, "vpu_50xx.bin" }, + { IVPU_HW_IP_50XX, "intel/vpu/vpu_50xx_v1.bin" }, { IVPU_HW_IP_50XX, "intel/vpu/vpu_50xx_v0.0.bin" }, }; /* Production fw_names from the table above */ -MODULE_FIRMWARE("intel/vpu/vpu_37xx_v0.0.bin"); -MODULE_FIRMWARE("intel/vpu/vpu_40xx_v0.0.bin"); -MODULE_FIRMWARE("intel/vpu/vpu_50xx_v0.0.bin"); +MODULE_FIRMWARE("intel/vpu/vpu_37xx_v1.bin"); +MODULE_FIRMWARE("intel/vpu/vpu_40xx_v1.bin"); +MODULE_FIRMWARE("intel/vpu/vpu_50xx_v1.bin"); static int ivpu_fw_request(struct ivpu_device *vdev) { diff --git a/drivers/accel/ivpu/ivpu_gem.c b/drivers/accel/ivpu/ivpu_gem.c index e0d242d9f3e5..59cfcf3eaded 100644 --- a/drivers/accel/ivpu/ivpu_gem.c +++ b/drivers/accel/ivpu/ivpu_gem.c @@ -28,11 +28,21 @@ static inline void ivpu_dbg_bo(struct ivpu_device *vdev, struct ivpu_bo *bo, con { ivpu_dbg(vdev, BO, "%6s: bo %8p vpu_addr %9llx size %8zu ctx %d has_pages %d dma_mapped %d mmu_mapped %d wc %d imported %d\n", - action, bo, bo->vpu_addr, ivpu_bo_size(bo), bo->ctx ? bo->ctx->id : 0, + action, bo, bo->vpu_addr, ivpu_bo_size(bo), bo->ctx_id, (bool)bo->base.pages, (bool)bo->base.sgt, bo->mmu_mapped, bo->base.map_wc, (bool)drm_gem_is_imported(&bo->base.base)); } +static inline int ivpu_bo_lock(struct ivpu_bo *bo) +{ + return dma_resv_lock(bo->base.base.resv, NULL); +} + +static inline void ivpu_bo_unlock(struct ivpu_bo *bo) +{ + dma_resv_unlock(bo->base.base.resv); +} + /* * ivpu_bo_pin() - pin the backing physical pages and map them to VPU. * @@ -43,22 +53,22 @@ static inline void ivpu_dbg_bo(struct ivpu_device *vdev, struct ivpu_bo *bo, con int __must_check ivpu_bo_pin(struct ivpu_bo *bo) { struct ivpu_device *vdev = ivpu_bo_to_vdev(bo); + struct sg_table *sgt; int ret = 0; - mutex_lock(&bo->lock); - ivpu_dbg_bo(vdev, bo, "pin"); - drm_WARN_ON(&vdev->drm, !bo->ctx); - if (!bo->mmu_mapped) { - struct sg_table *sgt = drm_gem_shmem_get_pages_sgt(&bo->base); + sgt = drm_gem_shmem_get_pages_sgt(&bo->base); + if (IS_ERR(sgt)) { + ret = PTR_ERR(sgt); + ivpu_err(vdev, "Failed to map BO in IOMMU: %d\n", ret); + return ret; + } - if (IS_ERR(sgt)) { - ret = PTR_ERR(sgt); - ivpu_err(vdev, "Failed to map BO in IOMMU: %d\n", ret); - goto unlock; - } + ivpu_bo_lock(bo); + if (!bo->mmu_mapped) { + drm_WARN_ON(&vdev->drm, !bo->ctx); ret = ivpu_mmu_context_map_sgt(vdev, bo->ctx, bo->vpu_addr, sgt, ivpu_bo_is_snooped(bo)); if (ret) { @@ -69,7 +79,7 @@ int __must_check ivpu_bo_pin(struct ivpu_bo *bo) } unlock: - mutex_unlock(&bo->lock); + ivpu_bo_unlock(bo); return ret; } @@ -84,7 +94,7 @@ ivpu_bo_alloc_vpu_addr(struct ivpu_bo *bo, struct ivpu_mmu_context *ctx, if (!drm_dev_enter(&vdev->drm, &idx)) return -ENODEV; - mutex_lock(&bo->lock); + ivpu_bo_lock(bo); ret = ivpu_mmu_context_insert_node(ctx, range, ivpu_bo_size(bo), &bo->mm_node); if (!ret) { @@ -94,9 +104,7 @@ ivpu_bo_alloc_vpu_addr(struct ivpu_bo *bo, struct ivpu_mmu_context *ctx, ivpu_err(vdev, "Failed to add BO to context %u: %d\n", ctx->id, ret); } - ivpu_dbg_bo(vdev, bo, "alloc"); - - mutex_unlock(&bo->lock); + ivpu_bo_unlock(bo); drm_dev_exit(idx); @@ -107,7 +115,7 @@ static void ivpu_bo_unbind_locked(struct ivpu_bo *bo) { struct ivpu_device *vdev = ivpu_bo_to_vdev(bo); - lockdep_assert(lockdep_is_held(&bo->lock) || !kref_read(&bo->base.base.refcount)); + lockdep_assert(dma_resv_held(bo->base.base.resv) || !kref_read(&bo->base.base.refcount)); if (bo->mmu_mapped) { drm_WARN_ON(&vdev->drm, !bo->ctx); @@ -125,14 +133,12 @@ static void ivpu_bo_unbind_locked(struct ivpu_bo *bo) if (drm_gem_is_imported(&bo->base.base)) return; - dma_resv_lock(bo->base.base.resv, NULL); if (bo->base.sgt) { dma_unmap_sgtable(vdev->drm.dev, bo->base.sgt, DMA_BIDIRECTIONAL, 0); sg_free_table(bo->base.sgt); kfree(bo->base.sgt); bo->base.sgt = NULL; } - dma_resv_unlock(bo->base.base.resv); } void ivpu_bo_unbind_all_bos_from_context(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx) @@ -144,12 +150,12 @@ void ivpu_bo_unbind_all_bos_from_context(struct ivpu_device *vdev, struct ivpu_m mutex_lock(&vdev->bo_list_lock); list_for_each_entry(bo, &vdev->bo_list, bo_list_node) { - mutex_lock(&bo->lock); + ivpu_bo_lock(bo); if (bo->ctx == ctx) { ivpu_dbg_bo(vdev, bo, "unbind"); ivpu_bo_unbind_locked(bo); } - mutex_unlock(&bo->lock); + ivpu_bo_unlock(bo); } mutex_unlock(&vdev->bo_list_lock); } @@ -169,7 +175,6 @@ struct drm_gem_object *ivpu_gem_create_object(struct drm_device *dev, size_t siz bo->base.pages_mark_dirty_on_put = true; /* VPU can dirty a BO anytime */ INIT_LIST_HEAD(&bo->bo_list_node); - mutex_init(&bo->lock); return &bo->base.base; } @@ -215,7 +220,7 @@ fail_detach: return ERR_PTR(ret); } -static struct ivpu_bo *ivpu_bo_alloc(struct ivpu_device *vdev, u64 size, u32 flags) +static struct ivpu_bo *ivpu_bo_alloc(struct ivpu_device *vdev, u64 size, u32 flags, u32 ctx_id) { struct drm_gem_shmem_object *shmem; struct ivpu_bo *bo; @@ -233,6 +238,7 @@ static struct ivpu_bo *ivpu_bo_alloc(struct ivpu_device *vdev, u64 size, u32 fla return ERR_CAST(shmem); bo = to_ivpu_bo(&shmem->base); + bo->ctx_id = ctx_id; bo->base.map_wc = flags & DRM_IVPU_BO_WC; bo->flags = flags; @@ -240,6 +246,8 @@ static struct ivpu_bo *ivpu_bo_alloc(struct ivpu_device *vdev, u64 size, u32 fla list_add_tail(&bo->bo_list_node, &vdev->bo_list); mutex_unlock(&vdev->bo_list_lock); + ivpu_dbg_bo(vdev, bo, "alloc"); + return bo; } @@ -277,10 +285,14 @@ static void ivpu_gem_bo_free(struct drm_gem_object *obj) list_del(&bo->bo_list_node); mutex_unlock(&vdev->bo_list_lock); - drm_WARN_ON(&vdev->drm, !dma_resv_test_signaled(obj->resv, DMA_RESV_USAGE_READ)); + drm_WARN_ON(&vdev->drm, !drm_gem_is_imported(&bo->base.base) && + !dma_resv_test_signaled(obj->resv, DMA_RESV_USAGE_READ)); + drm_WARN_ON(&vdev->drm, ivpu_bo_size(bo) == 0); + drm_WARN_ON(&vdev->drm, bo->base.vaddr); ivpu_bo_unbind_locked(bo); - mutex_destroy(&bo->lock); + drm_WARN_ON(&vdev->drm, bo->mmu_mapped); + drm_WARN_ON(&vdev->drm, bo->ctx); drm_WARN_ON(obj->dev, refcount_read(&bo->base.pages_use_count) > 1); drm_gem_shmem_free(&bo->base); @@ -314,7 +326,7 @@ int ivpu_bo_create_ioctl(struct drm_device *dev, void *data, struct drm_file *fi if (size == 0) return -EINVAL; - bo = ivpu_bo_alloc(vdev, size, args->flags); + bo = ivpu_bo_alloc(vdev, size, args->flags, file_priv->ctx.id); if (IS_ERR(bo)) { ivpu_err(vdev, "Failed to allocate BO: %pe (ctx %u size %llu flags 0x%x)", bo, file_priv->ctx.id, args->size, args->flags); @@ -322,7 +334,10 @@ int ivpu_bo_create_ioctl(struct drm_device *dev, void *data, struct drm_file *fi } ret = drm_gem_handle_create(file, &bo->base.base, &args->handle); - if (!ret) + if (ret) + ivpu_err(vdev, "Failed to create handle for BO: %pe (ctx %u size %llu flags 0x%x)", + bo, file_priv->ctx.id, args->size, args->flags); + else args->vpu_addr = bo->vpu_addr; drm_gem_object_put(&bo->base.base); @@ -345,7 +360,7 @@ ivpu_bo_create(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx, drm_WARN_ON(&vdev->drm, !PAGE_ALIGNED(range->end)); drm_WARN_ON(&vdev->drm, !PAGE_ALIGNED(size)); - bo = ivpu_bo_alloc(vdev, size, flags); + bo = ivpu_bo_alloc(vdev, size, flags, IVPU_GLOBAL_CONTEXT_MMU_SSID); if (IS_ERR(bo)) { ivpu_err(vdev, "Failed to allocate BO: %pe (vpu_addr 0x%llx size %llu flags 0x%x)", bo, range->start, size, flags); @@ -361,9 +376,9 @@ ivpu_bo_create(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx, goto err_put; if (flags & DRM_IVPU_BO_MAPPABLE) { - dma_resv_lock(bo->base.base.resv, NULL); + ivpu_bo_lock(bo); ret = drm_gem_shmem_vmap_locked(&bo->base, &map); - dma_resv_unlock(bo->base.base.resv); + ivpu_bo_unlock(bo); if (ret) goto err_put; @@ -386,9 +401,9 @@ void ivpu_bo_free(struct ivpu_bo *bo) struct iosys_map map = IOSYS_MAP_INIT_VADDR(bo->base.vaddr); if (bo->flags & DRM_IVPU_BO_MAPPABLE) { - dma_resv_lock(bo->base.base.resv, NULL); + ivpu_bo_lock(bo); drm_gem_shmem_vunmap_locked(&bo->base, &map); - dma_resv_unlock(bo->base.base.resv); + ivpu_bo_unlock(bo); } drm_gem_object_put(&bo->base.base); @@ -407,12 +422,12 @@ int ivpu_bo_info_ioctl(struct drm_device *dev, void *data, struct drm_file *file bo = to_ivpu_bo(obj); - mutex_lock(&bo->lock); + ivpu_bo_lock(bo); args->flags = bo->flags; args->mmap_offset = drm_vma_node_offset_addr(&obj->vma_node); args->vpu_addr = bo->vpu_addr; args->size = obj->size; - mutex_unlock(&bo->lock); + ivpu_bo_unlock(bo); drm_gem_object_put(obj); return ret; @@ -449,10 +464,10 @@ int ivpu_bo_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file static void ivpu_bo_print_info(struct ivpu_bo *bo, struct drm_printer *p) { - mutex_lock(&bo->lock); + ivpu_bo_lock(bo); drm_printf(p, "%-9p %-3u 0x%-12llx %-10lu 0x%-8x %-4u", - bo, bo->ctx ? bo->ctx->id : 0, bo->vpu_addr, bo->base.base.size, + bo, bo->ctx_id, bo->vpu_addr, bo->base.base.size, bo->flags, kref_read(&bo->base.base.refcount)); if (bo->base.pages) @@ -466,7 +481,7 @@ static void ivpu_bo_print_info(struct ivpu_bo *bo, struct drm_printer *p) drm_printf(p, "\n"); - mutex_unlock(&bo->lock); + ivpu_bo_unlock(bo); } void ivpu_bo_list(struct drm_device *dev, struct drm_printer *p) diff --git a/drivers/accel/ivpu/ivpu_gem.h b/drivers/accel/ivpu/ivpu_gem.h index a222a9ec9d61..aa8ff14f7aae 100644 --- a/drivers/accel/ivpu/ivpu_gem.h +++ b/drivers/accel/ivpu/ivpu_gem.h @@ -17,10 +17,10 @@ struct ivpu_bo { struct list_head bo_list_node; struct drm_mm_node mm_node; - struct mutex lock; /* Protects: ctx, mmu_mapped, vpu_addr */ u64 vpu_addr; u32 flags; u32 job_status; /* Valid only for command buffer */ + u32 ctx_id; bool mmu_mapped; }; diff --git a/drivers/accel/ivpu/ivpu_job.c b/drivers/accel/ivpu/ivpu_job.c index b28da35c30b6..fae8351aa330 100644 --- a/drivers/accel/ivpu/ivpu_job.c +++ b/drivers/accel/ivpu/ivpu_job.c @@ -247,6 +247,10 @@ static int ivpu_cmdq_unregister(struct ivpu_file_priv *file_priv, struct ivpu_cm if (!cmdq->db_id) return 0; + ret = ivpu_jsm_unregister_db(vdev, cmdq->db_id); + if (!ret) + ivpu_dbg(vdev, JOB, "DB %d unregistered\n", cmdq->db_id); + if (vdev->fw->sched_mode == VPU_SCHEDULING_MODE_HW) { ret = ivpu_jsm_hws_destroy_cmdq(vdev, file_priv->ctx.id, cmdq->id); if (!ret) @@ -254,10 +258,6 @@ static int ivpu_cmdq_unregister(struct ivpu_file_priv *file_priv, struct ivpu_cm cmdq->id, file_priv->ctx.id); } - ret = ivpu_jsm_unregister_db(vdev, cmdq->db_id); - if (!ret) - ivpu_dbg(vdev, JOB, "DB %d unregistered\n", cmdq->db_id); - xa_erase(&file_priv->vdev->db_xa, cmdq->db_id); cmdq->db_id = 0; @@ -986,7 +986,8 @@ void ivpu_context_abort_work_fn(struct work_struct *work) return; if (vdev->fw->sched_mode == VPU_SCHEDULING_MODE_HW) - ivpu_jsm_reset_engine(vdev, 0); + if (ivpu_jsm_reset_engine(vdev, 0)) + return; mutex_lock(&vdev->context_list_lock); xa_for_each(&vdev->context_xa, ctx_id, file_priv) { @@ -1009,7 +1010,8 @@ void ivpu_context_abort_work_fn(struct work_struct *work) if (vdev->fw->sched_mode != VPU_SCHEDULING_MODE_HW) goto runtime_put; - ivpu_jsm_hws_resume_engine(vdev, 0); + if (ivpu_jsm_hws_resume_engine(vdev, 0)) + return; /* * In hardware scheduling mode NPU already has stopped processing jobs * and won't send us any further notifications, thus we have to free job related resources diff --git a/drivers/accel/ivpu/ivpu_jsm_msg.c b/drivers/accel/ivpu/ivpu_jsm_msg.c index 219ab8afefab..0256b2dfefc1 100644 --- a/drivers/accel/ivpu/ivpu_jsm_msg.c +++ b/drivers/accel/ivpu/ivpu_jsm_msg.c @@ -7,6 +7,7 @@ #include "ivpu_hw.h" #include "ivpu_ipc.h" #include "ivpu_jsm_msg.h" +#include "ivpu_pm.h" #include "vpu_jsm_api.h" const char *ivpu_jsm_msg_type_to_str(enum vpu_ipc_msg_type type) @@ -163,8 +164,10 @@ int ivpu_jsm_reset_engine(struct ivpu_device *vdev, u32 engine) ret = ivpu_ipc_send_receive(vdev, &req, VPU_JSM_MSG_ENGINE_RESET_DONE, &resp, VPU_IPC_CHAN_ASYNC_CMD, vdev->timeout.jsm); - if (ret) + if (ret) { ivpu_err_ratelimited(vdev, "Failed to reset engine %d: %d\n", engine, ret); + ivpu_pm_trigger_recovery(vdev, "Engine reset failed"); + } return ret; } @@ -354,8 +357,10 @@ int ivpu_jsm_hws_resume_engine(struct ivpu_device *vdev, u32 engine) ret = ivpu_ipc_send_receive(vdev, &req, VPU_JSM_MSG_HWS_RESUME_ENGINE_DONE, &resp, VPU_IPC_CHAN_ASYNC_CMD, vdev->timeout.jsm); - if (ret) + if (ret) { ivpu_err_ratelimited(vdev, "Failed to resume engine %d: %d\n", engine, ret); + ivpu_pm_trigger_recovery(vdev, "Engine resume failed"); + } return ret; } diff --git a/drivers/accel/qaic/qaic_timesync.c b/drivers/accel/qaic/qaic_timesync.c index 972833fabcfc..3fac540f8e03 100644 --- a/drivers/accel/qaic/qaic_timesync.c +++ b/drivers/accel/qaic/qaic_timesync.c @@ -129,7 +129,7 @@ static void qaic_timesync_dl_xfer_cb(struct mhi_device *mhi_dev, struct mhi_resu static void qaic_timesync_timer(struct timer_list *t) { - struct mqts_dev *mqtsdev = from_timer(mqtsdev, t, timer); + struct mqts_dev *mqtsdev = timer_container_of(mqtsdev, t, timer); struct qts_host_time_sync_msg_data *sync_msg; u64 device_qtimer_us; u64 device_qtimer; diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c index 0f3c663c1b0a..f0584ccad451 100644 --- a/drivers/acpi/apei/ghes.c +++ b/drivers/acpi/apei/ghes.c @@ -1138,7 +1138,7 @@ static void ghes_add_timer(struct ghes *ghes) static void ghes_poll_func(struct timer_list *t) { - struct ghes *ghes = from_timer(ghes, t, timer); + struct ghes *ghes = timer_container_of(ghes, t, timer); unsigned long flags; spin_lock_irqsave(&ghes_notify_lock_irq, flags); diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 5fc2c8ee61b1..c463ca4a8fff 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -79,6 +79,8 @@ static HLIST_HEAD(binder_deferred_list); static DEFINE_MUTEX(binder_deferred_lock); static HLIST_HEAD(binder_devices); +static DEFINE_SPINLOCK(binder_devices_lock); + static HLIST_HEAD(binder_procs); static DEFINE_MUTEX(binder_procs_lock); @@ -3261,20 +3263,16 @@ static void binder_transaction(struct binder_proc *proc, if (reply) binder_debug(BINDER_DEBUG_TRANSACTION, - "%d:%d BC_REPLY %d -> %d:%d, data %016llx-%016llx size %lld-%lld-%lld\n", + "%d:%d BC_REPLY %d -> %d:%d, data size %lld-%lld-%lld\n", proc->pid, thread->pid, t->debug_id, target_proc->pid, target_thread->pid, - (u64)tr->data.ptr.buffer, - (u64)tr->data.ptr.offsets, (u64)tr->data_size, (u64)tr->offsets_size, (u64)extra_buffers_size); else binder_debug(BINDER_DEBUG_TRANSACTION, - "%d:%d BC_TRANSACTION %d -> %d - node %d, data %016llx-%016llx size %lld-%lld-%lld\n", + "%d:%d BC_TRANSACTION %d -> %d - node %d, data size %lld-%lld-%lld\n", proc->pid, thread->pid, t->debug_id, target_proc->pid, target_node->debug_id, - (u64)tr->data.ptr.buffer, - (u64)tr->data.ptr.offsets, (u64)tr->data_size, (u64)tr->offsets_size, (u64)extra_buffers_size); @@ -4223,20 +4221,21 @@ static int binder_thread_write(struct binder_proc *proc, if (IS_ERR_OR_NULL(buffer)) { if (PTR_ERR(buffer) == -EPERM) { binder_user_error( - "%d:%d BC_FREE_BUFFER u%016llx matched unreturned or currently freeing buffer\n", + "%d:%d BC_FREE_BUFFER matched unreturned or currently freeing buffer at offset %lx\n", proc->pid, thread->pid, - (u64)data_ptr); + (unsigned long)data_ptr - proc->alloc.vm_start); } else { binder_user_error( - "%d:%d BC_FREE_BUFFER u%016llx no match\n", + "%d:%d BC_FREE_BUFFER no match for buffer at offset %lx\n", proc->pid, thread->pid, - (u64)data_ptr); + (unsigned long)data_ptr - proc->alloc.vm_start); } break; } binder_debug(BINDER_DEBUG_FREE_BUFFER, - "%d:%d BC_FREE_BUFFER u%016llx found buffer %d for %s transaction\n", - proc->pid, thread->pid, (u64)data_ptr, + "%d:%d BC_FREE_BUFFER at offset %lx found buffer %d for %s transaction\n", + proc->pid, thread->pid, + (unsigned long)data_ptr - proc->alloc.vm_start, buffer->debug_id, buffer->transaction ? "active" : "finished"); binder_free_buf(proc, thread, buffer, false); @@ -5053,16 +5052,14 @@ retry: trace_binder_transaction_received(t); binder_stat_br(proc, thread, cmd); binder_debug(BINDER_DEBUG_TRANSACTION, - "%d:%d %s %d %d:%d, cmd %u size %zd-%zd ptr %016llx-%016llx\n", + "%d:%d %s %d %d:%d, cmd %u size %zd-%zd\n", proc->pid, thread->pid, (cmd == BR_TRANSACTION) ? "BR_TRANSACTION" : (cmd == BR_TRANSACTION_SEC_CTX) ? "BR_TRANSACTION_SEC_CTX" : "BR_REPLY", t->debug_id, t_from ? t_from->proc->pid : 0, t_from ? t_from->pid : 0, cmd, - t->buffer->data_size, t->buffer->offsets_size, - (u64)trd->data.ptr.buffer, - (u64)trd->data.ptr.offsets); + t->buffer->data_size, t->buffer->offsets_size); if (t_from) binder_thread_dec_tmpref(t_from); @@ -5244,6 +5241,7 @@ static void binder_free_proc(struct binder_proc *proc) __func__, proc->outstanding_txns); device = container_of(proc->context, struct binder_device, context); if (refcount_dec_and_test(&device->ref)) { + binder_remove_device(device); kfree(proc->context->name); kfree(device); } @@ -6377,10 +6375,10 @@ static void print_binder_transaction_ilocked(struct seq_file *m, } static void print_binder_work_ilocked(struct seq_file *m, - struct binder_proc *proc, - const char *prefix, - const char *transaction_prefix, - struct binder_work *w) + struct binder_proc *proc, + const char *prefix, + const char *transaction_prefix, + struct binder_work *w, bool hash_ptrs) { struct binder_node *node; struct binder_transaction *t; @@ -6403,9 +6401,15 @@ static void print_binder_work_ilocked(struct seq_file *m, break; case BINDER_WORK_NODE: node = container_of(w, struct binder_node, work); - seq_printf(m, "%snode work %d: u%016llx c%016llx\n", - prefix, node->debug_id, - (u64)node->ptr, (u64)node->cookie); + if (hash_ptrs) + seq_printf(m, "%snode work %d: u%p c%p\n", + prefix, node->debug_id, + (void *)(long)node->ptr, + (void *)(long)node->cookie); + else + seq_printf(m, "%snode work %d: u%016llx c%016llx\n", + prefix, node->debug_id, + (u64)node->ptr, (u64)node->cookie); break; case BINDER_WORK_DEAD_BINDER: seq_printf(m, "%shas dead binder\n", prefix); @@ -6430,7 +6434,7 @@ static void print_binder_work_ilocked(struct seq_file *m, static void print_binder_thread_ilocked(struct seq_file *m, struct binder_thread *thread, - int print_always) + bool print_always, bool hash_ptrs) { struct binder_transaction *t; struct binder_work *w; @@ -6460,14 +6464,16 @@ static void print_binder_thread_ilocked(struct seq_file *m, } list_for_each_entry(w, &thread->todo, entry) { print_binder_work_ilocked(m, thread->proc, " ", - " pending transaction", w); + " pending transaction", + w, hash_ptrs); } if (!print_always && m->count == header_pos) m->count = start_pos; } static void print_binder_node_nilocked(struct seq_file *m, - struct binder_node *node) + struct binder_node *node, + bool hash_ptrs) { struct binder_ref *ref; struct binder_work *w; @@ -6475,8 +6481,13 @@ static void print_binder_node_nilocked(struct seq_file *m, count = hlist_count_nodes(&node->refs); - seq_printf(m, " node %d: u%016llx c%016llx hs %d hw %d ls %d lw %d is %d iw %d tr %d", - node->debug_id, (u64)node->ptr, (u64)node->cookie, + if (hash_ptrs) + seq_printf(m, " node %d: u%p c%p", node->debug_id, + (void *)(long)node->ptr, (void *)(long)node->cookie); + else + seq_printf(m, " node %d: u%016llx c%016llx", node->debug_id, + (u64)node->ptr, (u64)node->cookie); + seq_printf(m, " hs %d hw %d ls %d lw %d is %d iw %d tr %d", node->has_strong_ref, node->has_weak_ref, node->local_strong_refs, node->local_weak_refs, node->internal_strong_refs, count, node->tmp_refs); @@ -6489,7 +6500,8 @@ static void print_binder_node_nilocked(struct seq_file *m, if (node->proc) { list_for_each_entry(w, &node->async_todo, entry) print_binder_work_ilocked(m, node->proc, " ", - " pending async transaction", w); + " pending async transaction", + w, hash_ptrs); } } @@ -6505,8 +6517,54 @@ static void print_binder_ref_olocked(struct seq_file *m, binder_node_unlock(ref->node); } -static void print_binder_proc(struct seq_file *m, - struct binder_proc *proc, int print_all) +/** + * print_next_binder_node_ilocked() - Print binder_node from a locked list + * @m: struct seq_file for output via seq_printf() + * @proc: struct binder_proc we hold the inner_proc_lock to (if any) + * @node: struct binder_node to print fields of + * @prev_node: struct binder_node we hold a temporary reference to (if any) + * @hash_ptrs: whether to hash @node's binder_uintptr_t fields + * + * Helper function to handle synchronization around printing a struct + * binder_node while iterating through @proc->nodes or the dead nodes list. + * Caller must hold either @proc->inner_lock (for live nodes) or + * binder_dead_nodes_lock. This lock will be released during the body of this + * function, but it will be reacquired before returning to the caller. + * + * Return: pointer to the struct binder_node we hold a tmpref on + */ +static struct binder_node * +print_next_binder_node_ilocked(struct seq_file *m, struct binder_proc *proc, + struct binder_node *node, + struct binder_node *prev_node, bool hash_ptrs) +{ + /* + * Take a temporary reference on the node so that isn't freed while + * we print it. + */ + binder_inc_node_tmpref_ilocked(node); + /* + * Live nodes need to drop the inner proc lock and dead nodes need to + * drop the binder_dead_nodes_lock before trying to take the node lock. + */ + if (proc) + binder_inner_proc_unlock(proc); + else + spin_unlock(&binder_dead_nodes_lock); + if (prev_node) + binder_put_node(prev_node); + binder_node_inner_lock(node); + print_binder_node_nilocked(m, node, hash_ptrs); + binder_node_inner_unlock(node); + if (proc) + binder_inner_proc_lock(proc); + else + spin_lock(&binder_dead_nodes_lock); + return node; +} + +static void print_binder_proc(struct seq_file *m, struct binder_proc *proc, + bool print_all, bool hash_ptrs) { struct binder_work *w; struct rb_node *n; @@ -6519,31 +6577,19 @@ static void print_binder_proc(struct seq_file *m, header_pos = m->count; binder_inner_proc_lock(proc); - for (n = rb_first(&proc->threads); n != NULL; n = rb_next(n)) + for (n = rb_first(&proc->threads); n; n = rb_next(n)) print_binder_thread_ilocked(m, rb_entry(n, struct binder_thread, - rb_node), print_all); + rb_node), print_all, hash_ptrs); - for (n = rb_first(&proc->nodes); n != NULL; n = rb_next(n)) { + for (n = rb_first(&proc->nodes); n; n = rb_next(n)) { struct binder_node *node = rb_entry(n, struct binder_node, rb_node); if (!print_all && !node->has_async_transaction) continue; - /* - * take a temporary reference on the node so it - * survives and isn't removed from the tree - * while we print it. - */ - binder_inc_node_tmpref_ilocked(node); - /* Need to drop inner lock to take node lock */ - binder_inner_proc_unlock(proc); - if (last_node) - binder_put_node(last_node); - binder_node_inner_lock(node); - print_binder_node_nilocked(m, node); - binder_node_inner_unlock(node); - last_node = node; - binder_inner_proc_lock(proc); + last_node = print_next_binder_node_ilocked(m, proc, node, + last_node, + hash_ptrs); } binder_inner_proc_unlock(proc); if (last_node) @@ -6551,19 +6597,18 @@ static void print_binder_proc(struct seq_file *m, if (print_all) { binder_proc_lock(proc); - for (n = rb_first(&proc->refs_by_desc); - n != NULL; - n = rb_next(n)) + for (n = rb_first(&proc->refs_by_desc); n; n = rb_next(n)) print_binder_ref_olocked(m, rb_entry(n, - struct binder_ref, - rb_node_desc)); + struct binder_ref, + rb_node_desc)); binder_proc_unlock(proc); } binder_alloc_print_allocated(m, &proc->alloc); binder_inner_proc_lock(proc); list_for_each_entry(w, &proc->todo, entry) print_binder_work_ilocked(m, proc, " ", - " pending transaction", w); + " pending transaction", w, + hash_ptrs); list_for_each_entry(w, &proc->delivered_death, entry) { seq_puts(m, " has delivered dead binder\n"); break; @@ -6696,7 +6741,7 @@ static void print_binder_proc_stats(struct seq_file *m, count = 0; ready_threads = 0; binder_inner_proc_lock(proc); - for (n = rb_first(&proc->threads); n != NULL; n = rb_next(n)) + for (n = rb_first(&proc->threads); n; n = rb_next(n)) count++; list_for_each_entry(thread, &proc->waiting_threads, waiting_thread_node) @@ -6710,7 +6755,7 @@ static void print_binder_proc_stats(struct seq_file *m, ready_threads, free_async_space); count = 0; - for (n = rb_first(&proc->nodes); n != NULL; n = rb_next(n)) + for (n = rb_first(&proc->nodes); n; n = rb_next(n)) count++; binder_inner_proc_unlock(proc); seq_printf(m, " nodes: %d\n", count); @@ -6718,7 +6763,7 @@ static void print_binder_proc_stats(struct seq_file *m, strong = 0; weak = 0; binder_proc_lock(proc); - for (n = rb_first(&proc->refs_by_desc); n != NULL; n = rb_next(n)) { + for (n = rb_first(&proc->refs_by_desc); n; n = rb_next(n)) { struct binder_ref *ref = rb_entry(n, struct binder_ref, rb_node_desc); count++; @@ -6745,7 +6790,7 @@ static void print_binder_proc_stats(struct seq_file *m, print_binder_stats(m, " ", &proc->stats); } -static int state_show(struct seq_file *m, void *unused) +static void print_binder_state(struct seq_file *m, bool hash_ptrs) { struct binder_proc *proc; struct binder_node *node; @@ -6756,31 +6801,40 @@ static int state_show(struct seq_file *m, void *unused) spin_lock(&binder_dead_nodes_lock); if (!hlist_empty(&binder_dead_nodes)) seq_puts(m, "dead nodes:\n"); - hlist_for_each_entry(node, &binder_dead_nodes, dead_node) { - /* - * take a temporary reference on the node so it - * survives and isn't removed from the list - * while we print it. - */ - node->tmp_refs++; - spin_unlock(&binder_dead_nodes_lock); - if (last_node) - binder_put_node(last_node); - binder_node_lock(node); - print_binder_node_nilocked(m, node); - binder_node_unlock(node); - last_node = node; - spin_lock(&binder_dead_nodes_lock); - } + hlist_for_each_entry(node, &binder_dead_nodes, dead_node) + last_node = print_next_binder_node_ilocked(m, NULL, node, + last_node, + hash_ptrs); spin_unlock(&binder_dead_nodes_lock); if (last_node) binder_put_node(last_node); mutex_lock(&binder_procs_lock); hlist_for_each_entry(proc, &binder_procs, proc_node) - print_binder_proc(m, proc, 1); + print_binder_proc(m, proc, true, hash_ptrs); + mutex_unlock(&binder_procs_lock); +} + +static void print_binder_transactions(struct seq_file *m, bool hash_ptrs) +{ + struct binder_proc *proc; + + seq_puts(m, "binder transactions:\n"); + mutex_lock(&binder_procs_lock); + hlist_for_each_entry(proc, &binder_procs, proc_node) + print_binder_proc(m, proc, false, hash_ptrs); mutex_unlock(&binder_procs_lock); +} + +static int state_show(struct seq_file *m, void *unused) +{ + print_binder_state(m, false); + return 0; +} +static int state_hashed_show(struct seq_file *m, void *unused) +{ + print_binder_state(m, true); return 0; } @@ -6802,14 +6856,13 @@ static int stats_show(struct seq_file *m, void *unused) static int transactions_show(struct seq_file *m, void *unused) { - struct binder_proc *proc; - - seq_puts(m, "binder transactions:\n"); - mutex_lock(&binder_procs_lock); - hlist_for_each_entry(proc, &binder_procs, proc_node) - print_binder_proc(m, proc, 0); - mutex_unlock(&binder_procs_lock); + print_binder_transactions(m, false); + return 0; +} +static int transactions_hashed_show(struct seq_file *m, void *unused) +{ + print_binder_transactions(m, true); return 0; } @@ -6822,7 +6875,7 @@ static int proc_show(struct seq_file *m, void *unused) hlist_for_each_entry(itr, &binder_procs, proc_node) { if (itr->pid == pid) { seq_puts(m, "binder proc state:\n"); - print_binder_proc(m, itr, 1); + print_binder_proc(m, itr, true, false); } } mutex_unlock(&binder_procs_lock); @@ -6889,8 +6942,10 @@ const struct file_operations binder_fops = { }; DEFINE_SHOW_ATTRIBUTE(state); +DEFINE_SHOW_ATTRIBUTE(state_hashed); DEFINE_SHOW_ATTRIBUTE(stats); DEFINE_SHOW_ATTRIBUTE(transactions); +DEFINE_SHOW_ATTRIBUTE(transactions_hashed); DEFINE_SHOW_ATTRIBUTE(transaction_log); const struct binder_debugfs_entry binder_debugfs_entries[] = { @@ -6901,6 +6956,12 @@ const struct binder_debugfs_entry binder_debugfs_entries[] = { .data = NULL, }, { + .name = "state_hashed", + .mode = 0444, + .fops = &state_hashed_fops, + .data = NULL, + }, + { .name = "stats", .mode = 0444, .fops = &stats_fops, @@ -6913,6 +6974,12 @@ const struct binder_debugfs_entry binder_debugfs_entries[] = { .data = NULL, }, { + .name = "transactions_hashed", + .mode = 0444, + .fops = &transactions_hashed_fops, + .data = NULL, + }, + { .name = "transaction_log", .mode = 0444, .fops = &transaction_log_fops, @@ -6929,7 +6996,16 @@ const struct binder_debugfs_entry binder_debugfs_entries[] = { void binder_add_device(struct binder_device *device) { + spin_lock(&binder_devices_lock); hlist_add_head(&device->hlist, &binder_devices); + spin_unlock(&binder_devices_lock); +} + +void binder_remove_device(struct binder_device *device) +{ + spin_lock(&binder_devices_lock); + hlist_del_init(&device->hlist); + spin_unlock(&binder_devices_lock); } static int __init init_binder_device(const char *name) @@ -6956,7 +7032,7 @@ static int __init init_binder_device(const char *name) return ret; } - hlist_add_head(&binder_device->hlist, &binder_devices); + binder_add_device(binder_device); return ret; } @@ -7018,7 +7094,7 @@ static int __init binder_init(void) err_init_binder_device_failed: hlist_for_each_entry_safe(device, tmp, &binder_devices, hlist) { misc_deregister(&device->miscdev); - hlist_del(&device->hlist); + binder_remove_device(device); kfree(device); } diff --git a/drivers/android/binder_internal.h b/drivers/android/binder_internal.h index 6a66c9769c6c..1ba5caf1d88d 100644 --- a/drivers/android/binder_internal.h +++ b/drivers/android/binder_internal.h @@ -583,9 +583,13 @@ struct binder_object { /** * Add a binder device to binder_devices * @device: the new binder device to add to the global list - * - * Not reentrant as the list is not protected by any locks */ void binder_add_device(struct binder_device *device); +/** + * Remove a binder device to binder_devices + * @device: the binder device to remove from the global list + */ +void binder_remove_device(struct binder_device *device); + #endif /* _LINUX_BINDER_INTERNAL_H */ diff --git a/drivers/android/binderfs.c b/drivers/android/binderfs.c index 98da8c4eea59..024275dbfdd8 100644 --- a/drivers/android/binderfs.c +++ b/drivers/android/binderfs.c @@ -274,7 +274,7 @@ static void binderfs_evict_inode(struct inode *inode) mutex_unlock(&binderfs_minors_mutex); if (refcount_dec_and_test(&device->ref)) { - hlist_del_init(&device->hlist); + binder_remove_device(device); kfree(device->context.name); kfree(device); } diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index 22afa4ff860d..4e9c82f36df1 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -1034,7 +1034,7 @@ static void ahci_sw_activity(struct ata_link *link) static void ahci_sw_activity_blink(struct timer_list *t) { - struct ahci_em_priv *emp = from_timer(emp, t, timer); + struct ahci_em_priv *emp = timer_container_of(emp, t, timer); struct ata_link *link = emp->link; struct ata_port *ap = link->ap; diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index c11d8e634bf7..1f90fcd2b3c4 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -860,7 +860,7 @@ static unsigned int ata_eh_nr_in_flight(struct ata_port *ap) void ata_eh_fastdrain_timerfn(struct timer_list *t) { - struct ata_port *ap = from_timer(ap, t, fastdrain_timer); + struct ata_port *ap = timer_container_of(ap, t, fastdrain_timer); unsigned long flags; unsigned int cnt; diff --git a/drivers/atm/idt77252.c b/drivers/atm/idt77252.c index a876024d8a05..1206ab764ba9 100644 --- a/drivers/atm/idt77252.c +++ b/drivers/atm/idt77252.c @@ -1531,7 +1531,7 @@ idt77252_tx(struct idt77252_dev *card) static void tst_timer(struct timer_list *t) { - struct idt77252_dev *card = from_timer(card, t, tst_timer); + struct idt77252_dev *card = timer_container_of(card, t, tst_timer); unsigned long base, idle, jump; unsigned long flags; u32 pc; @@ -2070,7 +2070,7 @@ idt77252_rate_logindex(struct idt77252_dev *card, int pcr) static void idt77252_est_timer(struct timer_list *t) { - struct rate_estimator *est = from_timer(est, t, timer); + struct rate_estimator *est = timer_container_of(est, t, timer); struct vc_map *vc = est->vc; struct idt77252_dev *card = vc->card; unsigned long flags; diff --git a/drivers/atm/lanai.c b/drivers/atm/lanai.c index 00fe25b5b6a3..2a1fe3080712 100644 --- a/drivers/atm/lanai.c +++ b/drivers/atm/lanai.c @@ -1758,7 +1758,7 @@ static void iter_dequeue(struct lanai_dev *lanai, vci_t vci) static void lanai_timed_poll(struct timer_list *t) { - struct lanai_dev *lanai = from_timer(lanai, t, timer); + struct lanai_dev *lanai = timer_container_of(lanai, t, timer); #ifndef DEBUG_RW unsigned long flags; #ifdef USE_POWERDOWN diff --git a/drivers/auxdisplay/line-display.c b/drivers/auxdisplay/line-display.c index b6808c4f89b6..8590a4cd21e0 100644 --- a/drivers/auxdisplay/line-display.c +++ b/drivers/auxdisplay/line-display.c @@ -40,7 +40,7 @@ */ static void linedisp_scroll(struct timer_list *t) { - struct linedisp *linedisp = from_timer(linedisp, t, timer); + struct linedisp *linedisp = timer_container_of(linedisp, t, timer); unsigned int i, ch = linedisp->scroll_pos; unsigned int num_chars = linedisp->num_chars; diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 19fd55b8ac77..eebe699fdf4f 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -513,7 +513,7 @@ struct dpm_watchdog { */ static void dpm_watchdog_handler(struct timer_list *t) { - struct dpm_watchdog *wd = from_timer(wd, t, timer); + struct dpm_watchdog *wd = timer_container_of(wd, t, timer); struct timer_list *timer = &wd->timer; unsigned int time_left; @@ -638,6 +638,13 @@ static int dpm_async_with_cleanup(struct device *dev, void *fn) static void dpm_async_resume_children(struct device *dev, async_func_t func) { /* + * Prevent racing with dpm_clear_async_state() during initial list + * walks in dpm_noirq_resume_devices(), dpm_resume_early(), and + * dpm_resume(). + */ + guard(mutex)(&dpm_list_mtx); + + /* * Start processing "async" children of the device unless it's been * started already for them. * @@ -985,6 +992,8 @@ static void device_resume(struct device *dev, pm_message_t state, bool async) if (!dev->power.is_suspended) goto Complete; + dev->power.is_suspended = false; + if (dev->power.direct_complete) { /* * Allow new children to be added under the device after this @@ -1047,7 +1056,6 @@ static void device_resume(struct device *dev, pm_message_t state, bool async) End: error = dpm_run_callback(callback, dev, state, info); - dev->power.is_suspended = false; device_unlock(dev); dpm_watchdog_clear(&wd); @@ -1451,7 +1459,7 @@ static int dpm_noirq_suspend_devices(pm_message_t state) * Move all devices to the target list to resume them * properly. */ - list_splice(&dpm_late_early_list, &dpm_noirq_list); + list_splice_init(&dpm_late_early_list, &dpm_noirq_list); break; } } @@ -1653,7 +1661,7 @@ int dpm_suspend_late(pm_message_t state) * Move all devices to the target list to resume them * properly. */ - list_splice(&dpm_suspended_list, &dpm_late_early_list); + list_splice_init(&dpm_suspended_list, &dpm_late_early_list); break; } } @@ -1946,7 +1954,7 @@ int dpm_suspend(pm_message_t state) * Move all devices to the target list to resume them * properly. */ - list_splice(&dpm_prepared_list, &dpm_suspended_list); + list_splice_init(&dpm_prepared_list, &dpm_suspended_list); break; } } diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c index f7c96a3bf719..d1283ff1080b 100644 --- a/drivers/base/power/wakeup.c +++ b/drivers/base/power/wakeup.c @@ -759,7 +759,7 @@ EXPORT_SYMBOL_GPL(pm_relax); */ static void pm_wakeup_timer_fn(struct timer_list *t) { - struct wakeup_source *ws = from_timer(ws, t, timer); + struct wakeup_source *ws = timer_container_of(ws, t, timer); unsigned long flags; spin_lock_irqsave(&ws->lock, flags); diff --git a/drivers/base/property.c b/drivers/base/property.c index 805f75b35115..f626d5bbe806 100644 --- a/drivers/base/property.c +++ b/drivers/base/property.c @@ -945,6 +945,33 @@ unsigned int fwnode_get_child_node_count(const struct fwnode_handle *fwnode) } EXPORT_SYMBOL_GPL(fwnode_get_child_node_count); +/** + * fwnode_get_named_child_node_count - number of child nodes with given name + * @fwnode: Node which child nodes are counted. + * @name: String to match child node name against. + * + * Scan child nodes and count all the nodes with a specific name. Potential + * 'number' -ending after the 'at sign' for scanned names is ignored. + * E.g.:: + * fwnode_get_named_child_node_count(fwnode, "channel"); + * would match all the nodes:: + * channel { }, channel@0 {}, channel@0xabba {}... + * + * Return: the number of child nodes with a matching name for a given device. + */ +unsigned int fwnode_get_named_child_node_count(const struct fwnode_handle *fwnode, + const char *name) +{ + struct fwnode_handle *child; + unsigned int count = 0; + + fwnode_for_each_named_child_node(fwnode, child, name) + count++; + + return count; +} +EXPORT_SYMBOL_GPL(fwnode_get_named_child_node_count); + bool device_dma_supported(const struct device *dev) { return fwnode_call_bool_op(dev_fwnode(dev), device_dma_supported); diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c index 92b06d1de4cc..50cc90f6ab35 100644 --- a/drivers/block/aoe/aoecmd.c +++ b/drivers/block/aoe/aoecmd.c @@ -745,7 +745,7 @@ rexmit_timer(struct timer_list *timer) int utgts; /* number of aoetgt descriptors (not slots) */ int since; - d = from_timer(d, timer, timer); + d = timer_container_of(d, timer, timer); spin_lock_irqsave(&d->lock, flags); diff --git a/drivers/block/aoe/aoedev.c b/drivers/block/aoe/aoedev.c index 141b2a0e03f2..bba05f0c5bbd 100644 --- a/drivers/block/aoe/aoedev.c +++ b/drivers/block/aoe/aoedev.c @@ -149,7 +149,7 @@ dummy_timer(struct timer_list *t) { struct aoedev *d; - d = from_timer(d, t, timer); + d = timer_container_of(d, t, timer); if (d->flags & DEVFL_TKILL) return; d->timer.expires = jiffies + HZ; diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index ced2cc5f46f2..52724b79be30 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -3591,7 +3591,8 @@ int drbd_md_test_flag(struct drbd_backing_dev *bdev, int flag) static void md_sync_timer_fn(struct timer_list *t) { - struct drbd_device *device = from_timer(device, t, md_sync_timer); + struct drbd_device *device = timer_container_of(device, t, + md_sync_timer); drbd_device_post_work(device, MD_SYNC); } diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index 380e6584a4ee..d15826f6ee81 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -1699,7 +1699,8 @@ static bool net_timeout_reached(struct drbd_request *net_req, void request_timer_fn(struct timer_list *t) { - struct drbd_device *device = from_timer(device, t, request_timer); + struct drbd_device *device = timer_container_of(device, t, + request_timer); struct drbd_connection *connection = first_peer_device(device)->connection; struct drbd_request *req_read, *req_write, *req_peer; /* oldest request */ struct net_conf *nc; diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index 4352a50fbb3f..a6ea737b3b71 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -442,7 +442,8 @@ int w_resync_timer(struct drbd_work *w, int cancel) void resync_timer_fn(struct timer_list *t) { - struct drbd_device *device = from_timer(device, t, resync_timer); + struct drbd_device *device = timer_container_of(device, t, + resync_timer); drbd_queue_work_if_unqueued( &first_peer_device(device)->connection->sender_work, @@ -1698,7 +1699,8 @@ void drbd_rs_controller_reset(struct drbd_peer_device *peer_device) void start_resync_timer_fn(struct timer_list *t) { - struct drbd_device *device = from_timer(device, t, start_resync_timer); + struct drbd_device *device = timer_container_of(device, t, + start_resync_timer); drbd_device_post_work(device, RS_START); } diff --git a/drivers/block/loop.c b/drivers/block/loop.c index e2b1f377f585..f8d136684109 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -308,11 +308,14 @@ end_io: static void lo_rw_aio_do_completion(struct loop_cmd *cmd) { struct request *rq = blk_mq_rq_from_pdu(cmd); + struct loop_device *lo = rq->q->queuedata; if (!atomic_dec_and_test(&cmd->ref)) return; kfree(cmd->bvec); cmd->bvec = NULL; + if (req_op(rq) == REQ_OP_WRITE) + file_end_write(lo->lo_backing_file); if (likely(!blk_should_fake_timeout(rq->q))) blk_mq_complete_request(rq); } @@ -387,9 +390,10 @@ static int lo_rw_aio(struct loop_device *lo, struct loop_cmd *cmd, cmd->iocb.ki_flags = 0; } - if (rw == ITER_SOURCE) + if (rw == ITER_SOURCE) { + file_start_write(lo->lo_backing_file); ret = file->f_op->write_iter(&cmd->iocb, &iter); - else + } else ret = file->f_op->read_iter(&cmd->iocb, &iter); lo_rw_aio_do_completion(cmd); diff --git a/drivers/block/swim3.c b/drivers/block/swim3.c index ee6cade70222..01f7aef3fcfb 100644 --- a/drivers/block/swim3.c +++ b/drivers/block/swim3.c @@ -555,7 +555,7 @@ static void act(struct floppy_state *fs) static void scan_timeout(struct timer_list *t) { - struct floppy_state *fs = from_timer(fs, t, timeout); + struct floppy_state *fs = timer_container_of(fs, t, timeout); struct swim3 __iomem *sw = fs->swim3; unsigned long flags; @@ -579,7 +579,7 @@ static void scan_timeout(struct timer_list *t) static void seek_timeout(struct timer_list *t) { - struct floppy_state *fs = from_timer(fs, t, timeout); + struct floppy_state *fs = timer_container_of(fs, t, timeout); struct swim3 __iomem *sw = fs->swim3; unsigned long flags; @@ -598,7 +598,7 @@ static void seek_timeout(struct timer_list *t) static void settle_timeout(struct timer_list *t) { - struct floppy_state *fs = from_timer(fs, t, timeout); + struct floppy_state *fs = timer_container_of(fs, t, timeout); struct swim3 __iomem *sw = fs->swim3; unsigned long flags; @@ -627,7 +627,7 @@ static void settle_timeout(struct timer_list *t) static void xfer_timeout(struct timer_list *t) { - struct floppy_state *fs = from_timer(fs, t, timeout); + struct floppy_state *fs = timer_container_of(fs, t, timeout); struct swim3 __iomem *sw = fs->swim3; struct dbdma_regs __iomem *dr = fs->dma; unsigned long flags; diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c index 6f51072776f1..c637ea010d34 100644 --- a/drivers/block/ublk_drv.c +++ b/drivers/block/ublk_drv.c @@ -69,7 +69,8 @@ | UBLK_F_USER_RECOVERY_FAIL_IO \ | UBLK_F_UPDATE_SIZE \ | UBLK_F_AUTO_BUF_REG \ - | UBLK_F_QUIESCE) + | UBLK_F_QUIESCE \ + | UBLK_F_PER_IO_DAEMON) #define UBLK_F_ALL_RECOVERY_FLAGS (UBLK_F_USER_RECOVERY \ | UBLK_F_USER_RECOVERY_REISSUE \ @@ -166,6 +167,8 @@ struct ublk_io { /* valid if UBLK_IO_FLAG_OWNED_BY_SRV is set */ struct request *req; }; + + struct task_struct *task; }; struct ublk_queue { @@ -173,11 +176,9 @@ struct ublk_queue { int q_depth; unsigned long flags; - struct task_struct *ubq_daemon; struct ublksrv_io_desc *io_cmd_buf; bool force_abort; - bool timeout; bool canceling; bool fail_io; /* copy of dev->state == UBLK_S_DEV_FAIL_IO */ unsigned short nr_io_ready; /* how many ios setup */ @@ -1099,11 +1100,6 @@ static inline struct ublk_uring_cmd_pdu *ublk_get_uring_cmd_pdu( return io_uring_cmd_to_pdu(ioucmd, struct ublk_uring_cmd_pdu); } -static inline bool ubq_daemon_is_dying(struct ublk_queue *ubq) -{ - return !ubq->ubq_daemon || ubq->ubq_daemon->flags & PF_EXITING; -} - /* todo: handle partial completion */ static inline void __ublk_complete_rq(struct request *req) { @@ -1275,13 +1271,13 @@ static void ublk_dispatch_req(struct ublk_queue *ubq, /* * Task is exiting if either: * - * (1) current != ubq_daemon. + * (1) current != io->task. * io_uring_cmd_complete_in_task() tries to run task_work - * in a workqueue if ubq_daemon(cmd's task) is PF_EXITING. + * in a workqueue if cmd's task is PF_EXITING. * * (2) current->flags & PF_EXITING. */ - if (unlikely(current != ubq->ubq_daemon || current->flags & PF_EXITING)) { + if (unlikely(current != io->task || current->flags & PF_EXITING)) { __ublk_abort_rq(ubq, req); return; } @@ -1330,24 +1326,22 @@ static void ublk_cmd_list_tw_cb(struct io_uring_cmd *cmd, { struct ublk_uring_cmd_pdu *pdu = ublk_get_uring_cmd_pdu(cmd); struct request *rq = pdu->req_list; - struct ublk_queue *ubq = pdu->ubq; struct request *next; do { next = rq->rq_next; rq->rq_next = NULL; - ublk_dispatch_req(ubq, rq, issue_flags); + ublk_dispatch_req(rq->mq_hctx->driver_data, rq, issue_flags); rq = next; } while (rq); } -static void ublk_queue_cmd_list(struct ublk_queue *ubq, struct rq_list *l) +static void ublk_queue_cmd_list(struct ublk_io *io, struct rq_list *l) { - struct request *rq = rq_list_peek(l); - struct io_uring_cmd *cmd = ubq->ios[rq->tag].cmd; + struct io_uring_cmd *cmd = io->cmd; struct ublk_uring_cmd_pdu *pdu = ublk_get_uring_cmd_pdu(cmd); - pdu->req_list = rq; + pdu->req_list = rq_list_peek(l); rq_list_init(l); io_uring_cmd_complete_in_task(cmd, ublk_cmd_list_tw_cb); } @@ -1355,13 +1349,10 @@ static void ublk_queue_cmd_list(struct ublk_queue *ubq, struct rq_list *l) static enum blk_eh_timer_return ublk_timeout(struct request *rq) { struct ublk_queue *ubq = rq->mq_hctx->driver_data; + struct ublk_io *io = &ubq->ios[rq->tag]; if (ubq->flags & UBLK_F_UNPRIVILEGED_DEV) { - if (!ubq->timeout) { - send_sig(SIGKILL, ubq->ubq_daemon, 0); - ubq->timeout = true; - } - + send_sig(SIGKILL, io->task, 0); return BLK_EH_DONE; } @@ -1429,24 +1420,25 @@ static void ublk_queue_rqs(struct rq_list *rqlist) { struct rq_list requeue_list = { }; struct rq_list submit_list = { }; - struct ublk_queue *ubq = NULL; + struct ublk_io *io = NULL; struct request *req; while ((req = rq_list_pop(rqlist))) { struct ublk_queue *this_q = req->mq_hctx->driver_data; + struct ublk_io *this_io = &this_q->ios[req->tag]; - if (ubq && ubq != this_q && !rq_list_empty(&submit_list)) - ublk_queue_cmd_list(ubq, &submit_list); - ubq = this_q; + if (io && io->task != this_io->task && !rq_list_empty(&submit_list)) + ublk_queue_cmd_list(io, &submit_list); + io = this_io; - if (ublk_prep_req(ubq, req, true) == BLK_STS_OK) + if (ublk_prep_req(this_q, req, true) == BLK_STS_OK) rq_list_add_tail(&submit_list, req); else rq_list_add_tail(&requeue_list, req); } - if (ubq && !rq_list_empty(&submit_list)) - ublk_queue_cmd_list(ubq, &submit_list); + if (!rq_list_empty(&submit_list)) + ublk_queue_cmd_list(io, &submit_list); *rqlist = requeue_list; } @@ -1474,17 +1466,6 @@ static void ublk_queue_reinit(struct ublk_device *ub, struct ublk_queue *ubq) /* All old ioucmds have to be completed */ ubq->nr_io_ready = 0; - /* - * old daemon is PF_EXITING, put it now - * - * It could be NULL in case of closing one quisced device. - */ - if (ubq->ubq_daemon) - put_task_struct(ubq->ubq_daemon); - /* We have to reset it to NULL, otherwise ub won't accept new FETCH_REQ */ - ubq->ubq_daemon = NULL; - ubq->timeout = false; - for (i = 0; i < ubq->q_depth; i++) { struct ublk_io *io = &ubq->ios[i]; @@ -1495,6 +1476,17 @@ static void ublk_queue_reinit(struct ublk_device *ub, struct ublk_queue *ubq) io->flags &= UBLK_IO_FLAG_CANCELED; io->cmd = NULL; io->addr = 0; + + /* + * old task is PF_EXITING, put it now + * + * It could be NULL in case of closing one quiesced + * device. + */ + if (io->task) { + put_task_struct(io->task); + io->task = NULL; + } } } @@ -1516,7 +1508,7 @@ static void ublk_reset_ch_dev(struct ublk_device *ub) for (i = 0; i < ub->dev_info.nr_hw_queues; i++) ublk_queue_reinit(ub, ublk_get_queue(ub, i)); - /* set to NULL, otherwise new ubq_daemon cannot mmap the io_cmd_buf */ + /* set to NULL, otherwise new tasks cannot mmap io_cmd_buf */ ub->mm = NULL; ub->nr_queues_ready = 0; ub->nr_privileged_daemon = 0; @@ -1783,6 +1775,7 @@ static void ublk_uring_cmd_cancel_fn(struct io_uring_cmd *cmd, struct ublk_uring_cmd_pdu *pdu = ublk_get_uring_cmd_pdu(cmd); struct ublk_queue *ubq = pdu->ubq; struct task_struct *task; + struct ublk_io *io; if (WARN_ON_ONCE(!ubq)) return; @@ -1791,13 +1784,14 @@ static void ublk_uring_cmd_cancel_fn(struct io_uring_cmd *cmd, return; task = io_uring_cmd_get_task(cmd); - if (WARN_ON_ONCE(task && task != ubq->ubq_daemon)) + io = &ubq->ios[pdu->tag]; + if (WARN_ON_ONCE(task && task != io->task)) return; if (!ubq->canceling) ublk_start_cancel(ubq); - WARN_ON_ONCE(ubq->ios[pdu->tag].cmd != cmd); + WARN_ON_ONCE(io->cmd != cmd); ublk_cancel_cmd(ubq, pdu->tag, issue_flags); } @@ -1930,8 +1924,6 @@ static void ublk_mark_io_ready(struct ublk_device *ub, struct ublk_queue *ubq) { ubq->nr_io_ready++; if (ublk_queue_ready(ubq)) { - ubq->ubq_daemon = current; - get_task_struct(ubq->ubq_daemon); ub->nr_queues_ready++; if (capable(CAP_SYS_ADMIN)) @@ -2084,6 +2076,7 @@ static int ublk_fetch(struct io_uring_cmd *cmd, struct ublk_queue *ubq, } ublk_fill_io_cmd(io, cmd, buf_addr); + WRITE_ONCE(io->task, get_task_struct(current)); ublk_mark_io_ready(ub, ubq); out: mutex_unlock(&ub->mutex); @@ -2179,6 +2172,7 @@ static int __ublk_ch_uring_cmd(struct io_uring_cmd *cmd, const struct ublksrv_io_cmd *ub_cmd) { struct ublk_device *ub = cmd->file->private_data; + struct task_struct *task; struct ublk_queue *ubq; struct ublk_io *io; u32 cmd_op = cmd->cmd_op; @@ -2193,13 +2187,14 @@ static int __ublk_ch_uring_cmd(struct io_uring_cmd *cmd, goto out; ubq = ublk_get_queue(ub, ub_cmd->q_id); - if (ubq->ubq_daemon && ubq->ubq_daemon != current) - goto out; if (tag >= ubq->q_depth) goto out; io = &ubq->ios[tag]; + task = READ_ONCE(io->task); + if (task && task != current) + goto out; /* there is pending io cmd, something must be wrong */ if (io->flags & UBLK_IO_FLAG_ACTIVE) { @@ -2449,9 +2444,14 @@ static void ublk_deinit_queue(struct ublk_device *ub, int q_id) { int size = ublk_queue_cmd_buf_size(ub, q_id); struct ublk_queue *ubq = ublk_get_queue(ub, q_id); + int i; + + for (i = 0; i < ubq->q_depth; i++) { + struct ublk_io *io = &ubq->ios[i]; + if (io->task) + put_task_struct(io->task); + } - if (ubq->ubq_daemon) - put_task_struct(ubq->ubq_daemon); if (ubq->io_cmd_buf) free_pages((unsigned long)ubq->io_cmd_buf, get_order(size)); } @@ -2923,7 +2923,8 @@ static int ublk_ctrl_add_dev(const struct ublksrv_ctrl_cmd *header) ub->dev_info.flags &= UBLK_F_ALL; ub->dev_info.flags |= UBLK_F_CMD_IOCTL_ENCODE | - UBLK_F_URING_CMD_COMP_IN_TASK; + UBLK_F_URING_CMD_COMP_IN_TASK | + UBLK_F_PER_IO_DAEMON; /* GET_DATA isn't needed any more with USER_COPY or ZERO COPY */ if (ub->dev_info.flags & (UBLK_F_USER_COPY | UBLK_F_SUPPORT_ZERO_COPY | @@ -3188,14 +3189,14 @@ static int ublk_ctrl_end_recovery(struct ublk_device *ub, int ublksrv_pid = (int)header->data[0]; int ret = -EINVAL; - pr_devel("%s: Waiting for new ubq_daemons(nr: %d) are ready, dev id %d...\n", - __func__, ub->dev_info.nr_hw_queues, header->dev_id); - /* wait until new ubq_daemon sending all FETCH_REQ */ + pr_devel("%s: Waiting for all FETCH_REQs, dev id %d...\n", __func__, + header->dev_id); + if (wait_for_completion_interruptible(&ub->completion)) return -EINTR; - pr_devel("%s: All new ubq_daemons(nr: %d) are ready, dev id %d\n", - __func__, ub->dev_info.nr_hw_queues, header->dev_id); + pr_devel("%s: All FETCH_REQs received, dev id %d\n", __func__, + header->dev_id); mutex_lock(&ub->mutex); if (ublk_nosrv_should_stop_dev(ub)) diff --git a/drivers/bluetooth/bluecard_cs.c b/drivers/bluetooth/bluecard_cs.c index 1c7f89e134b3..1e3a56e9b139 100644 --- a/drivers/bluetooth/bluecard_cs.c +++ b/drivers/bluetooth/bluecard_cs.c @@ -158,7 +158,7 @@ static void bluecard_detach(struct pcmcia_device *p_dev); static void bluecard_activity_led_timeout(struct timer_list *t) { - struct bluecard_info *info = from_timer(info, t, timer); + struct bluecard_info *info = timer_container_of(info, t, timer); unsigned int iobase = info->p_dev->resource[0]->start; if (test_bit(CARD_ACTIVITY, &(info->hw_state))) { diff --git a/drivers/bluetooth/btnxpuart.c b/drivers/bluetooth/btnxpuart.c index 6b13feed06df..1088db6056a4 100644 --- a/drivers/bluetooth/btnxpuart.c +++ b/drivers/bluetooth/btnxpuart.c @@ -467,7 +467,7 @@ static void ps_work_func(struct work_struct *work) static void ps_timeout_func(struct timer_list *t) { - struct ps_data *data = from_timer(data, t, ps_timer); + struct ps_data *data = timer_container_of(data, t, ps_timer); struct hci_dev *hdev = data->hdev; struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev); diff --git a/drivers/bluetooth/hci_bcsp.c b/drivers/bluetooth/hci_bcsp.c index 610d0e3c36d4..664d82d1e613 100644 --- a/drivers/bluetooth/hci_bcsp.c +++ b/drivers/bluetooth/hci_bcsp.c @@ -688,7 +688,7 @@ static int bcsp_recv(struct hci_uart *hu, const void *data, int count) /* Arrange to retransmit all messages in the relq. */ static void bcsp_timed_event(struct timer_list *t) { - struct bcsp_struct *bcsp = from_timer(bcsp, t, tbcsp); + struct bcsp_struct *bcsp = timer_container_of(bcsp, t, tbcsp); struct hci_uart *hu = bcsp->hu; struct sk_buff *skb; unsigned long flags; diff --git a/drivers/bluetooth/hci_h5.c b/drivers/bluetooth/hci_h5.c index edafa228bf83..d0d4420c1a0f 100644 --- a/drivers/bluetooth/hci_h5.c +++ b/drivers/bluetooth/hci_h5.c @@ -149,7 +149,7 @@ static void h5_timed_event(struct timer_list *t) { const unsigned char sync_req[] = { 0x01, 0x7e }; unsigned char conf_req[3] = { 0x03, 0xfc }; - struct h5 *h5 = from_timer(h5, t, timer); + struct h5 *h5 = timer_container_of(h5, t, timer); struct hci_uart *hu = h5->hu; struct sk_buff *skb; unsigned long flags; diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c index a2dc39c005f4..5fe5879881f5 100644 --- a/drivers/bluetooth/hci_qca.c +++ b/drivers/bluetooth/hci_qca.c @@ -474,7 +474,7 @@ static void qca_wq_serial_tx_clock_vote_off(struct work_struct *work) static void hci_ibs_tx_idle_timeout(struct timer_list *t) { - struct qca_data *qca = from_timer(qca, t, tx_idle_timer); + struct qca_data *qca = timer_container_of(qca, t, tx_idle_timer); struct hci_uart *hu = qca->hu; unsigned long flags; @@ -507,7 +507,7 @@ static void hci_ibs_tx_idle_timeout(struct timer_list *t) static void hci_ibs_wake_retrans_timeout(struct timer_list *t) { - struct qca_data *qca = from_timer(qca, t, wake_retrans_timer); + struct qca_data *qca = timer_container_of(qca, t, wake_retrans_timer); struct hci_uart *hu = qca->hu; unsigned long flags, retrans_delay; bool retransmit = false; diff --git a/drivers/bus/mhi/ep/ring.c b/drivers/bus/mhi/ep/ring.c index aeb53b2c34a8..26357ee68dee 100644 --- a/drivers/bus/mhi/ep/ring.c +++ b/drivers/bus/mhi/ep/ring.c @@ -131,19 +131,23 @@ int mhi_ep_ring_add_element(struct mhi_ep_ring *ring, struct mhi_ring_element *e } old_offset = ring->rd_offset; - mhi_ep_ring_inc_index(ring); dev_dbg(dev, "Adding an element to ring at offset (%zu)\n", ring->rd_offset); + buf_info.host_addr = ring->rbase + (old_offset * sizeof(*el)); + buf_info.dev_addr = el; + buf_info.size = sizeof(*el); + + ret = mhi_cntrl->write_sync(mhi_cntrl, &buf_info); + if (ret) + return ret; + + mhi_ep_ring_inc_index(ring); /* Update rp in ring context */ rp = cpu_to_le64(ring->rd_offset * sizeof(*el) + ring->rbase); memcpy_toio((void __iomem *) &ring->ring_ctx->generic.rp, &rp, sizeof(u64)); - buf_info.host_addr = ring->rbase + (old_offset * sizeof(*el)); - buf_info.dev_addr = el; - buf_info.size = sizeof(*el); - - return mhi_cntrl->write_sync(mhi_cntrl, &buf_info); + return ret; } void mhi_ep_ring_init(struct mhi_ep_ring *ring, enum mhi_ep_ring_type type, u32 id) diff --git a/drivers/bus/mhi/host/pci_generic.c b/drivers/bus/mhi/host/pci_generic.c index 03aa88795209..589cb6722316 100644 --- a/drivers/bus/mhi/host/pci_generic.c +++ b/drivers/bus/mhi/host/pci_generic.c @@ -782,6 +782,42 @@ static const struct mhi_pci_dev_info mhi_telit_fe990a_info = { .mru_default = 32768, }; +static const struct mhi_channel_config mhi_telit_fn920c04_channels[] = { + MHI_CHANNEL_CONFIG_UL_SBL(2, "SAHARA", 32, 0), + MHI_CHANNEL_CONFIG_DL_SBL(3, "SAHARA", 32, 0), + MHI_CHANNEL_CONFIG_UL(4, "DIAG", 64, 1), + MHI_CHANNEL_CONFIG_DL(5, "DIAG", 64, 1), + MHI_CHANNEL_CONFIG_UL(14, "QMI", 32, 0), + MHI_CHANNEL_CONFIG_DL(15, "QMI", 32, 0), + MHI_CHANNEL_CONFIG_UL(32, "DUN", 32, 0), + MHI_CHANNEL_CONFIG_DL(33, "DUN", 32, 0), + MHI_CHANNEL_CONFIG_UL_FP(34, "FIREHOSE", 32, 0), + MHI_CHANNEL_CONFIG_DL_FP(35, "FIREHOSE", 32, 0), + MHI_CHANNEL_CONFIG_UL(92, "DUN2", 32, 1), + MHI_CHANNEL_CONFIG_DL(93, "DUN2", 32, 1), + MHI_CHANNEL_CONFIG_HW_UL(100, "IP_HW0", 128, 2), + MHI_CHANNEL_CONFIG_HW_DL(101, "IP_HW0", 128, 3), +}; + +static const struct mhi_controller_config modem_telit_fn920c04_config = { + .max_channels = 128, + .timeout_ms = 50000, + .num_channels = ARRAY_SIZE(mhi_telit_fn920c04_channels), + .ch_cfg = mhi_telit_fn920c04_channels, + .num_events = ARRAY_SIZE(mhi_telit_fn990_events), + .event_cfg = mhi_telit_fn990_events, +}; + +static const struct mhi_pci_dev_info mhi_telit_fn920c04_info = { + .name = "telit-fn920c04", + .config = &modem_telit_fn920c04_config, + .bar_num = MHI_PCI_DEFAULT_BAR_NUM, + .dma_data_width = 32, + .sideband_wake = false, + .mru_default = 32768, + .edl_trigger = true, +}; + static const struct mhi_pci_dev_info mhi_netprisma_lcur57_info = { .name = "netprisma-lcur57", .edl = "qcom/prog_firehose_sdx24.mbn", @@ -806,6 +842,9 @@ static const struct mhi_pci_dev_info mhi_netprisma_fcun69_info = { static const struct pci_device_id mhi_pci_id_table[] = { {PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x0116), .driver_data = (kernel_ulong_t) &mhi_qcom_sa8775p_info }, + /* Telit FN920C04 (sdx35) */ + {PCI_DEVICE_SUB(PCI_VENDOR_ID_QCOM, 0x011a, 0x1c5d, 0x2020), + .driver_data = (kernel_ulong_t) &mhi_telit_fn920c04_info }, { PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x0304), .driver_data = (kernel_ulong_t) &mhi_qcom_sdx24_info }, { PCI_DEVICE_SUB(PCI_VENDOR_ID_QCOM, 0x0306, PCI_VENDOR_ID_QCOM, 0x010c), @@ -996,10 +1035,6 @@ static int mhi_pci_claim(struct mhi_controller *mhi_cntrl, struct pci_dev *pdev = to_pci_dev(mhi_cntrl->cntrl_dev); int err; - err = pci_assign_resource(pdev, bar_num); - if (err) - return err; - err = pcim_enable_device(pdev); if (err) { dev_err(&pdev->dev, "failed to enable pci device: %d\n", err); @@ -1136,7 +1171,8 @@ err_try_reset: static void health_check(struct timer_list *t) { - struct mhi_pci_device *mhi_pdev = from_timer(mhi_pdev, t, health_check_timer); + struct mhi_pci_device *mhi_pdev = timer_container_of(mhi_pdev, t, + health_check_timer); struct mhi_controller *mhi_cntrl = &mhi_pdev->mhi_cntrl; if (!test_bit(MHI_PCI_DEV_STARTED, &mhi_pdev->status) || diff --git a/drivers/bus/mhi/host/pm.c b/drivers/bus/mhi/host/pm.c index 2fb27e6f8f88..33d92bf2fc3e 100644 --- a/drivers/bus/mhi/host/pm.c +++ b/drivers/bus/mhi/host/pm.c @@ -602,6 +602,7 @@ static void mhi_pm_sys_error_transition(struct mhi_controller *mhi_cntrl) struct mhi_cmd *mhi_cmd; struct mhi_event_ctxt *er_ctxt; struct device *dev = &mhi_cntrl->mhi_dev->dev; + bool reset_device = false; int ret, i; dev_dbg(dev, "Transitioning from PM state: %s to: %s\n", @@ -630,8 +631,23 @@ static void mhi_pm_sys_error_transition(struct mhi_controller *mhi_cntrl) /* Wake up threads waiting for state transition */ wake_up_all(&mhi_cntrl->state_event); - /* Trigger MHI RESET so that the device will not access host memory */ if (MHI_REG_ACCESS_VALID(prev_state)) { + /* + * If the device is in PBL or SBL, it will only respond to + * RESET if the device is in SYSERR state. SYSERR might + * already be cleared at this point. + */ + enum mhi_state cur_state = mhi_get_mhi_state(mhi_cntrl); + enum mhi_ee_type cur_ee = mhi_get_exec_env(mhi_cntrl); + + if (cur_state == MHI_STATE_SYS_ERR) + reset_device = true; + else if (cur_ee != MHI_EE_PBL && cur_ee != MHI_EE_SBL) + reset_device = true; + } + + /* Trigger MHI RESET so that the device will not access host memory */ + if (reset_device) { u32 in_reset = -1; unsigned long timeout = msecs_to_jiffies(mhi_cntrl->timeout_ms); diff --git a/drivers/cdx/cdx_msi.c b/drivers/cdx/cdx_msi.c index 06d723978232..3388a5d1462c 100644 --- a/drivers/cdx/cdx_msi.c +++ b/drivers/cdx/cdx_msi.c @@ -165,7 +165,7 @@ struct irq_domain *cdx_msi_domain_init(struct device *dev) struct device_node *parent_node; struct irq_domain *parent; - fwnode_handle = of_node_to_fwnode(np); + fwnode_handle = of_fwnode_handle(np); parent_node = of_parse_phandle(np, "msi-map", 1); if (!parent_node) { @@ -173,7 +173,7 @@ struct irq_domain *cdx_msi_domain_init(struct device *dev) return NULL; } - parent = irq_find_matching_fwnode(of_node_to_fwnode(parent_node), DOMAIN_BUS_NEXUS); + parent = irq_find_matching_fwnode(of_fwnode_handle(parent_node), DOMAIN_BUS_NEXUS); if (!parent || !msi_get_domain_info(parent)) { dev_err(dev, "unable to locate ITS domain\n"); return NULL; diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 8fb33c90482f..ae6196760556 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -404,7 +404,7 @@ config TELCLOCK configuration of the telecom clock configuration settings. This device is used for hardware synchronization across the ATCA backplane fabric. Upon loading, the driver exports a sysfs directory, - /sys/devices/platform/telco_clock, with a number of files for + /sys/devices/faux/telco_clock, with a number of files for controlling the behavior of this hardware. source "drivers/s390/char/Kconfig" diff --git a/drivers/char/apm-emulation.c b/drivers/char/apm-emulation.c index e795390b070f..53ce352f7197 100644 --- a/drivers/char/apm-emulation.c +++ b/drivers/char/apm-emulation.c @@ -141,9 +141,6 @@ static struct apm_queue kapmd_queue; static DEFINE_MUTEX(state_lock); -static const char driver_version[] = "1.13"; /* no spaces */ - - /* * Compatibility cruft until the IPAQ people move over to the new @@ -435,6 +432,8 @@ static struct miscdevice apm_device = { */ static int proc_apm_show(struct seq_file *m, void *v) { + static const char driver_version[] = "1.13"; /* no spaces */ + struct apm_power_info info; char *units; diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c index e110857824fc..0713ea2b2a51 100644 --- a/drivers/char/hpet.c +++ b/drivers/char/hpet.c @@ -1023,8 +1023,7 @@ static int __init hpet_init(void) result = acpi_bus_register_driver(&hpet_acpi_driver); if (result < 0) { - if (sysctl_header) - unregister_sysctl_table(sysctl_header); + unregister_sysctl_table(sysctl_header); misc_deregister(&hpet_misc); return result; } diff --git a/drivers/char/hw_random/xgene-rng.c b/drivers/char/hw_random/xgene-rng.c index a1a751074f7e..709a36507145 100644 --- a/drivers/char/hw_random/xgene-rng.c +++ b/drivers/char/hw_random/xgene-rng.c @@ -88,7 +88,7 @@ struct xgene_rng_dev { static void xgene_rng_expired_timer(struct timer_list *t) { - struct xgene_rng_dev *ctx = from_timer(ctx, t, failure_timer); + struct xgene_rng_dev *ctx = timer_container_of(ctx, t, failure_timer); /* Clear failure counter as timer expired */ disable_irq(ctx->irq); diff --git a/drivers/char/ipmi/bt-bmc.c b/drivers/char/ipmi/bt-bmc.c index 77146b5c762b..a179d4797011 100644 --- a/drivers/char/ipmi/bt-bmc.c +++ b/drivers/char/ipmi/bt-bmc.c @@ -347,7 +347,7 @@ static const struct file_operations bt_bmc_fops = { static void poll_timer(struct timer_list *t) { - struct bt_bmc *bt_bmc = from_timer(bt_bmc, t, poll_timer); + struct bt_bmc *bt_bmc = timer_container_of(bt_bmc, t, poll_timer); bt_bmc->poll_timer.expires += msecs_to_jiffies(500); wake_up(&bt_bmc->queue); diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 7fe891783a37..bb42dfe1c6a8 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -1076,7 +1076,8 @@ static void set_need_watch(void *send_info, unsigned int watch_mask) static void smi_timeout(struct timer_list *t) { - struct smi_info *smi_info = from_timer(smi_info, t, si_timer); + struct smi_info *smi_info = timer_container_of(smi_info, t, + si_timer); enum si_sm_result smi_result; unsigned long flags; unsigned long jiffies_now; diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c index 5bf038e620c7..1bc42830444d 100644 --- a/drivers/char/ipmi/ipmi_ssif.c +++ b/drivers/char/ipmi/ipmi_ssif.c @@ -539,7 +539,8 @@ static void start_resend(struct ssif_info *ssif_info); static void retry_timeout(struct timer_list *t) { - struct ssif_info *ssif_info = from_timer(ssif_info, t, retry_timer); + struct ssif_info *ssif_info = timer_container_of(ssif_info, t, + retry_timer); unsigned long oflags, *flags; bool waiting, resend; @@ -563,7 +564,8 @@ static void retry_timeout(struct timer_list *t) static void watch_timeout(struct timer_list *t) { - struct ssif_info *ssif_info = from_timer(ssif_info, t, watch_timer); + struct ssif_info *ssif_info = timer_container_of(ssif_info, t, + watch_timer); unsigned long oflags, *flags; if (ssif_info->stopping) diff --git a/drivers/char/ipmi/ssif_bmc.c b/drivers/char/ipmi/ssif_bmc.c index e4bd74585d4d..7a52e3ea49ed 100644 --- a/drivers/char/ipmi/ssif_bmc.c +++ b/drivers/char/ipmi/ssif_bmc.c @@ -297,7 +297,8 @@ static void complete_response(struct ssif_bmc_ctx *ssif_bmc) static void response_timeout(struct timer_list *t) { - struct ssif_bmc_ctx *ssif_bmc = from_timer(ssif_bmc, t, response_timer); + struct ssif_bmc_ctx *ssif_bmc = timer_container_of(ssif_bmc, t, + response_timer); unsigned long flags; spin_lock_irqsave(&ssif_bmc->lock, flags); diff --git a/drivers/char/misc.c b/drivers/char/misc.c index dda466f9181a..d5accc10a110 100644 --- a/drivers/char/misc.c +++ b/drivers/char/misc.c @@ -58,9 +58,8 @@ static LIST_HEAD(misc_list); static DEFINE_MUTEX(misc_mtx); /* - * Assigned numbers, used for dynamic minors + * Assigned numbers. */ -#define DYNAMIC_MINORS 128 /* like dynamic majors */ static DEFINE_IDA(misc_minors_ida); static int misc_minor_alloc(int minor) @@ -69,34 +68,17 @@ static int misc_minor_alloc(int minor) if (minor == MISC_DYNAMIC_MINOR) { /* allocate free id */ - ret = ida_alloc_max(&misc_minors_ida, DYNAMIC_MINORS - 1, GFP_KERNEL); - if (ret >= 0) { - ret = DYNAMIC_MINORS - ret - 1; - } else { - ret = ida_alloc_range(&misc_minors_ida, MISC_DYNAMIC_MINOR + 1, - MINORMASK, GFP_KERNEL); - } + ret = ida_alloc_range(&misc_minors_ida, MISC_DYNAMIC_MINOR + 1, + MINORMASK, GFP_KERNEL); } else { - /* specific minor, check if it is in dynamic or misc dynamic range */ - if (minor < DYNAMIC_MINORS) { - minor = DYNAMIC_MINORS - minor - 1; - ret = ida_alloc_range(&misc_minors_ida, minor, minor, GFP_KERNEL); - } else if (minor > MISC_DYNAMIC_MINOR) { - ret = ida_alloc_range(&misc_minors_ida, minor, minor, GFP_KERNEL); - } else { - /* case of non-dynamic minors, no need to allocate id */ - ret = 0; - } + ret = ida_alloc_range(&misc_minors_ida, minor, minor, GFP_KERNEL); } return ret; } static void misc_minor_free(int minor) { - if (minor < DYNAMIC_MINORS) - ida_free(&misc_minors_ida, DYNAMIC_MINORS - minor - 1); - else if (minor > MISC_DYNAMIC_MINOR) - ida_free(&misc_minors_ida, minor); + ida_free(&misc_minors_ida, minor); } #ifdef CONFIG_PROC_FS diff --git a/drivers/char/tpm/tpm-dev-common.c b/drivers/char/tpm/tpm-dev-common.c index 11deaf538e87..f2a5e09257dd 100644 --- a/drivers/char/tpm/tpm-dev-common.c +++ b/drivers/char/tpm/tpm-dev-common.c @@ -91,7 +91,7 @@ out: static void user_reader_timeout(struct timer_list *t) { - struct file_priv *priv = from_timer(priv, t, user_read_timer); + struct file_priv *priv = timer_container_of(priv, t, user_read_timer); pr_warn("TPM user space timeout is deprecated (pid=%d)\n", task_tgid_nr(current)); diff --git a/drivers/char/xillybus/xillybus_core.c b/drivers/char/xillybus/xillybus_core.c index 11b7c4749274..efb1ae834265 100644 --- a/drivers/char/xillybus/xillybus_core.c +++ b/drivers/char/xillybus/xillybus_core.c @@ -1184,8 +1184,7 @@ static int xillybus_flush(struct file *filp, fl_owner_t id) static void xillybus_autoflush(struct work_struct *work) { - struct delayed_work *workitem = container_of( - work, struct delayed_work, work); + struct delayed_work *workitem = to_delayed_work(work); struct xilly_channel *channel = container_of( workitem, struct xilly_channel, rd_workitem); int rc; diff --git a/drivers/comedi/comedi_buf.c b/drivers/comedi/comedi_buf.c index 393966c09740..002c0e76baff 100644 --- a/drivers/comedi/comedi_buf.c +++ b/drivers/comedi/comedi_buf.c @@ -27,14 +27,12 @@ static void comedi_buf_map_kref_release(struct kref *kref) if (bm->page_list) { if (bm->dma_dir != DMA_NONE) { - /* - * DMA buffer was allocated as a single block. - * Address is in page_list[0]. - */ - buf = &bm->page_list[0]; - dma_free_coherent(bm->dma_hw_dev, - PAGE_SIZE * bm->n_pages, - buf->virt_addr, buf->dma_addr); + for (i = 0; i < bm->n_pages; i++) { + buf = &bm->page_list[i]; + dma_free_coherent(bm->dma_hw_dev, PAGE_SIZE, + buf->virt_addr, + buf->dma_addr); + } } else { for (i = 0; i < bm->n_pages; i++) { buf = &bm->page_list[i]; @@ -56,13 +54,7 @@ static void __comedi_buf_free(struct comedi_device *dev, struct comedi_buf_map *bm; unsigned long flags; - if (async->prealloc_buf) { - if (s->async_dma_dir == DMA_NONE) - vunmap(async->prealloc_buf); - async->prealloc_buf = NULL; - async->prealloc_bufsz = 0; - } - + async->prealloc_bufsz = 0; spin_lock_irqsave(&s->spin_lock, flags); bm = async->buf_map; async->buf_map = NULL; @@ -94,26 +86,14 @@ comedi_buf_map_alloc(struct comedi_device *dev, enum dma_data_direction dma_dir, goto err; if (bm->dma_dir != DMA_NONE) { - void *virt_addr; - dma_addr_t dma_addr; - - /* - * Currently, the DMA buffer needs to be allocated as a - * single block so that it can be mmap()'ed. - */ - virt_addr = dma_alloc_coherent(bm->dma_hw_dev, - PAGE_SIZE * n_pages, &dma_addr, - GFP_KERNEL); - if (!virt_addr) - goto err; - for (i = 0; i < n_pages; i++) { buf = &bm->page_list[i]; - buf->virt_addr = virt_addr + (i << PAGE_SHIFT); - buf->dma_addr = dma_addr + (i << PAGE_SHIFT); + buf->virt_addr = + dma_alloc_coherent(bm->dma_hw_dev, PAGE_SIZE, + &buf->dma_addr, GFP_KERNEL); + if (!buf->virt_addr) + break; } - - bm->n_pages = i; } else { for (i = 0; i < n_pages; i++) { buf = &bm->page_list[i]; @@ -123,11 +103,10 @@ comedi_buf_map_alloc(struct comedi_device *dev, enum dma_data_direction dma_dir, SetPageReserved(virt_to_page(buf->virt_addr)); } - - bm->n_pages = i; - if (i < n_pages) - goto err; } + bm->n_pages = i; + if (i < n_pages) + goto err; return bm; @@ -141,11 +120,8 @@ static void __comedi_buf_alloc(struct comedi_device *dev, unsigned int n_pages) { struct comedi_async *async = s->async; - struct page **pages = NULL; struct comedi_buf_map *bm; - struct comedi_buf_page *buf; unsigned long flags; - unsigned int i; if (!IS_ENABLED(CONFIG_HAS_DMA) && s->async_dma_dir != DMA_NONE) { dev_err(dev->class_dev, @@ -160,30 +136,7 @@ static void __comedi_buf_alloc(struct comedi_device *dev, spin_lock_irqsave(&s->spin_lock, flags); async->buf_map = bm; spin_unlock_irqrestore(&s->spin_lock, flags); - - if (bm->dma_dir != DMA_NONE) { - /* - * DMA buffer was allocated as a single block. - * Address is in page_list[0]. - */ - buf = &bm->page_list[0]; - async->prealloc_buf = buf->virt_addr; - } else { - pages = vmalloc(sizeof(struct page *) * n_pages); - if (!pages) - return; - - for (i = 0; i < n_pages; i++) { - buf = &bm->page_list[i]; - pages[i] = virt_to_page(buf->virt_addr); - } - - /* vmap the pages to prealloc_buf */ - async->prealloc_buf = vmap(pages, n_pages, VM_MAP, - COMEDI_PAGE_PROTECTION); - - vfree(pages); - } + async->prealloc_bufsz = n_pages << PAGE_SHIFT; } void comedi_buf_map_get(struct comedi_buf_map *bm) @@ -264,7 +217,7 @@ int comedi_buf_alloc(struct comedi_device *dev, struct comedi_subdevice *s, new_size = (new_size + PAGE_SIZE - 1) & PAGE_MASK; /* if no change is required, do nothing */ - if (async->prealloc_buf && async->prealloc_bufsz == new_size) + if (async->prealloc_bufsz == new_size) return 0; /* deallocate old buffer */ @@ -275,14 +228,9 @@ int comedi_buf_alloc(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int n_pages = new_size >> PAGE_SHIFT; __comedi_buf_alloc(dev, s, n_pages); - - if (!async->prealloc_buf) { - /* allocation failed */ - __comedi_buf_free(dev, s); + if (!async->prealloc_bufsz) return -ENOMEM; - } } - async->prealloc_bufsz = new_size; return 0; } @@ -365,6 +313,7 @@ static unsigned int comedi_buf_munge(struct comedi_subdevice *s, unsigned int num_bytes) { struct comedi_async *async = s->async; + struct comedi_buf_page *buf_page_list = async->buf_map->page_list; unsigned int count = 0; const unsigned int num_sample_bytes = comedi_bytes_per_sample(s); @@ -376,15 +325,16 @@ static unsigned int comedi_buf_munge(struct comedi_subdevice *s, /* don't munge partial samples */ num_bytes -= num_bytes % num_sample_bytes; while (count < num_bytes) { - int block_size = num_bytes - count; - unsigned int buf_end; - - buf_end = async->prealloc_bufsz - async->munge_ptr; - if (block_size > buf_end) - block_size = buf_end; + /* + * Do not munge beyond page boundary. + * Note: prealloc_bufsz is a multiple of PAGE_SIZE. + */ + unsigned int page = async->munge_ptr >> PAGE_SHIFT; + unsigned int offset = offset_in_page(async->munge_ptr); + unsigned int block_size = + min(num_bytes - count, PAGE_SIZE - offset); - s->munge(s->device, s, - async->prealloc_buf + async->munge_ptr, + s->munge(s->device, s, buf_page_list[page].virt_addr + offset, block_size, async->munge_chan); /* @@ -397,7 +347,8 @@ static unsigned int comedi_buf_munge(struct comedi_subdevice *s, async->munge_chan %= async->cmd.chanlist_len; async->munge_count += block_size; async->munge_ptr += block_size; - async->munge_ptr %= async->prealloc_bufsz; + if (async->munge_ptr == async->prealloc_bufsz) + async->munge_ptr = 0; count += block_size; } @@ -558,46 +509,52 @@ static void comedi_buf_memcpy_to(struct comedi_subdevice *s, const void *data, unsigned int num_bytes) { struct comedi_async *async = s->async; + struct comedi_buf_page *buf_page_list = async->buf_map->page_list; unsigned int write_ptr = async->buf_write_ptr; while (num_bytes) { - unsigned int block_size; - - if (write_ptr + num_bytes > async->prealloc_bufsz) - block_size = async->prealloc_bufsz - write_ptr; - else - block_size = num_bytes; + /* + * Do not copy beyond page boundary. + * Note: prealloc_bufsz is a multiple of PAGE_SIZE. + */ + unsigned int page = write_ptr >> PAGE_SHIFT; + unsigned int offset = offset_in_page(write_ptr); + unsigned int block_size = min(num_bytes, PAGE_SIZE - offset); - memcpy(async->prealloc_buf + write_ptr, data, block_size); + memcpy(buf_page_list[page].virt_addr + offset, + data, block_size); data += block_size; num_bytes -= block_size; - - write_ptr = 0; + write_ptr += block_size; + if (write_ptr == async->prealloc_bufsz) + write_ptr = 0; } } static void comedi_buf_memcpy_from(struct comedi_subdevice *s, void *dest, unsigned int nbytes) { - void *src; struct comedi_async *async = s->async; + struct comedi_buf_page *buf_page_list = async->buf_map->page_list; unsigned int read_ptr = async->buf_read_ptr; while (nbytes) { - unsigned int block_size; - - src = async->prealloc_buf + read_ptr; - - if (nbytes >= async->prealloc_bufsz - read_ptr) - block_size = async->prealloc_bufsz - read_ptr; - else - block_size = nbytes; + /* + * Do not copy beyond page boundary. + * Note: prealloc_bufsz is a multiple of PAGE_SIZE. + */ + unsigned int page = read_ptr >> PAGE_SHIFT; + unsigned int offset = offset_in_page(read_ptr); + unsigned int block_size = min(nbytes, PAGE_SIZE - offset); - memcpy(dest, src, block_size); + memcpy(dest, buf_page_list[page].virt_addr + offset, + block_size); nbytes -= block_size; dest += block_size; - read_ptr = 0; + read_ptr += block_size; + if (read_ptr == async->prealloc_bufsz) + read_ptr = 0; } } diff --git a/drivers/comedi/comedi_fops.c b/drivers/comedi/comedi_fops.c index b9df9b19d4bd..3383a7ce27ff 100644 --- a/drivers/comedi/comedi_fops.c +++ b/drivers/comedi/comedi_fops.c @@ -2387,13 +2387,27 @@ static int comedi_mmap(struct file *file, struct vm_area_struct *vma) goto done; } if (bm->dma_dir != DMA_NONE) { + unsigned long vm_start = vma->vm_start; + unsigned long vm_end = vma->vm_end; + /* - * DMA buffer was allocated as a single block. - * Address is in page_list[0]. + * Buffer pages are not contiguous, so temporarily modify VMA + * start and end addresses for each buffer page. */ - buf = &bm->page_list[0]; - retval = dma_mmap_coherent(bm->dma_hw_dev, vma, buf->virt_addr, - buf->dma_addr, n_pages * PAGE_SIZE); + for (i = 0; i < n_pages; ++i) { + buf = &bm->page_list[i]; + vma->vm_start = start; + vma->vm_end = start + PAGE_SIZE; + retval = dma_mmap_coherent(bm->dma_hw_dev, vma, + buf->virt_addr, + buf->dma_addr, PAGE_SIZE); + if (retval) + break; + + start += PAGE_SIZE; + } + vma->vm_start = vm_start; + vma->vm_end = vm_end; } else { for (i = 0; i < n_pages; ++i) { unsigned long pfn; @@ -2407,19 +2421,18 @@ static int comedi_mmap(struct file *file, struct vm_area_struct *vma) start += PAGE_SIZE; } + } #ifdef CONFIG_MMU - /* - * Leaving behind a partial mapping of a buffer we're about to - * drop is unsafe, see remap_pfn_range_notrack(). - * We need to zap the range here ourselves instead of relying - * on the automatic zapping in remap_pfn_range() because we call - * remap_pfn_range() in a loop. - */ - if (retval) - zap_vma_ptes(vma, vma->vm_start, size); + /* + * Leaving behind a partial mapping of a buffer we're about to drop is + * unsafe, see remap_pfn_range_notrack(). We need to zap the range + * here ourselves instead of relying on the automatic zapping in + * remap_pfn_range() because we call remap_pfn_range() in a loop. + */ + if (retval) + zap_vma_ptes(vma, vma->vm_start, size); #endif - } if (retval == 0) { vma->vm_ops = &comedi_vm_ops; @@ -2475,6 +2488,62 @@ done: return mask; } +static unsigned int comedi_buf_copy_to_user(struct comedi_subdevice *s, + void __user *dest, unsigned int src_offset, unsigned int n) +{ + struct comedi_buf_map *bm = s->async->buf_map; + struct comedi_buf_page *buf_page_list = bm->page_list; + unsigned int page = src_offset >> PAGE_SHIFT; + unsigned int offset = offset_in_page(src_offset); + + while (n) { + unsigned int copy_amount = min(n, PAGE_SIZE - offset); + unsigned int uncopied; + + uncopied = copy_to_user(dest, buf_page_list[page].virt_addr + + offset, copy_amount); + copy_amount -= uncopied; + n -= copy_amount; + if (uncopied) + break; + + dest += copy_amount; + page++; + if (page == bm->n_pages) + page = 0; /* buffer wraparound */ + offset = 0; + } + return n; +} + +static unsigned int comedi_buf_copy_from_user(struct comedi_subdevice *s, + unsigned int dst_offset, const void __user *src, unsigned int n) +{ + struct comedi_buf_map *bm = s->async->buf_map; + struct comedi_buf_page *buf_page_list = bm->page_list; + unsigned int page = dst_offset >> PAGE_SHIFT; + unsigned int offset = offset_in_page(dst_offset); + + while (n) { + unsigned int copy_amount = min(n, PAGE_SIZE - offset); + unsigned int uncopied; + + uncopied = copy_from_user(buf_page_list[page].virt_addr + + offset, src, copy_amount); + copy_amount -= uncopied; + n -= copy_amount; + if (uncopied) + break; + + src += copy_amount; + page++; + if (page == bm->n_pages) + page = 0; /* buffer wraparound */ + offset = 0; + } + return n; +} + static ssize_t comedi_write(struct file *file, const char __user *buf, size_t nbytes, loff_t *offset) { @@ -2516,7 +2585,6 @@ static ssize_t comedi_write(struct file *file, const char __user *buf, add_wait_queue(&async->wait_head, &wait); while (count == 0 && !retval) { unsigned int runflags; - unsigned int wp, n1, n2; set_current_state(TASK_INTERRUPTIBLE); @@ -2555,14 +2623,7 @@ static ssize_t comedi_write(struct file *file, const char __user *buf, } set_current_state(TASK_RUNNING); - wp = async->buf_write_ptr; - n1 = min(n, async->prealloc_bufsz - wp); - n2 = n - n1; - m = copy_from_user(async->prealloc_buf + wp, buf, n1); - if (m) - m += n2; - else if (n2) - m = copy_from_user(async->prealloc_buf, buf + n1, n2); + m = comedi_buf_copy_from_user(s, async->buf_write_ptr, buf, n); if (m) { n -= m; retval = -EFAULT; @@ -2651,8 +2712,6 @@ static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes, add_wait_queue(&async->wait_head, &wait); while (count == 0 && !retval) { - unsigned int rp, n1, n2; - set_current_state(TASK_INTERRUPTIBLE); m = comedi_buf_read_n_available(s); @@ -2689,14 +2748,7 @@ static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes, } set_current_state(TASK_RUNNING); - rp = async->buf_read_ptr; - n1 = min(n, async->prealloc_bufsz - rp); - n2 = n - n1; - m = copy_to_user(buf, async->prealloc_buf + rp, n1); - if (m) - m += n2; - else if (n2) - m = copy_to_user(buf + n1, async->prealloc_buf, n2); + m = comedi_buf_copy_to_user(s, buf, async->buf_read_ptr, n); if (m) { n -= m; retval = -EFAULT; diff --git a/drivers/comedi/drivers/adl_pci9118.c b/drivers/comedi/drivers/adl_pci9118.c index a76e2666d583..67c663892e48 100644 --- a/drivers/comedi/drivers/adl_pci9118.c +++ b/drivers/comedi/drivers/adl_pci9118.c @@ -32,7 +32,7 @@ * ranges). * * There are some hardware limitations: - * a) You cann't use mixture of unipolar/bipoar ranges or differencial/single + * a) You can't use mixture of unipolar/bipolar ranges or differential/single * ended inputs. * b) DMA transfers must have the length aligned to two samples (32 bit), * so there is some problems if cmd->chanlist_len is odd. This driver tries @@ -227,7 +227,7 @@ struct pci9118_private { struct pci9118_dmabuf dmabuf[2]; int softsshdelay; /* * >0 use software S&H, - * numer is requested delay in ns + * number is requested delay in ns */ unsigned char softsshsample; /* * polarity of S&H signal diff --git a/drivers/comedi/drivers/comedi_test.c b/drivers/comedi/drivers/comedi_test.c index da17d891f0e5..9747e6d1f6eb 100644 --- a/drivers/comedi/drivers/comedi_test.c +++ b/drivers/comedi/drivers/comedi_test.c @@ -197,7 +197,8 @@ static unsigned short fake_waveform(struct comedi_device *dev, */ static void waveform_ai_timer(struct timer_list *t) { - struct waveform_private *devpriv = from_timer(devpriv, t, ai_timer); + struct waveform_private *devpriv = timer_container_of(devpriv, t, + ai_timer); struct comedi_device *dev = devpriv->dev; struct comedi_subdevice *s = dev->read_subdev; struct comedi_async *async = s->async; @@ -444,7 +445,8 @@ static int waveform_ai_insn_read(struct comedi_device *dev, */ static void waveform_ao_timer(struct timer_list *t) { - struct waveform_private *devpriv = from_timer(devpriv, t, ao_timer); + struct waveform_private *devpriv = timer_container_of(devpriv, t, + ao_timer); struct comedi_device *dev = devpriv->dev; struct comedi_subdevice *s = dev->write_subdev; struct comedi_async *async = s->async; diff --git a/drivers/comedi/drivers/das16.c b/drivers/comedi/drivers/das16.c index f5ca6c0d4d0c..1f85572c21b4 100644 --- a/drivers/comedi/drivers/das16.c +++ b/drivers/comedi/drivers/das16.c @@ -517,7 +517,8 @@ static void das16_interrupt(struct comedi_device *dev) static void das16_timer_interrupt(struct timer_list *t) { - struct das16_private_struct *devpriv = from_timer(devpriv, t, timer); + struct das16_private_struct *devpriv = timer_container_of(devpriv, t, + timer); struct comedi_device *dev = devpriv->dev; unsigned long flags; diff --git a/drivers/comedi/drivers/jr3_pci.c b/drivers/comedi/drivers/jr3_pci.c index 75dce1ff2419..61792d940a3d 100644 --- a/drivers/comedi/drivers/jr3_pci.c +++ b/drivers/comedi/drivers/jr3_pci.c @@ -562,7 +562,8 @@ jr3_pci_poll_subdevice(struct comedi_subdevice *s) static void jr3_pci_poll_dev(struct timer_list *t) { - struct jr3_pci_dev_private *devpriv = from_timer(devpriv, t, timer); + struct jr3_pci_dev_private *devpriv = timer_container_of(devpriv, t, + timer); struct comedi_device *dev = devpriv->dev; struct jr3_pci_subdev_private *spriv; struct comedi_subdevice *s; diff --git a/drivers/comedi/drivers/ni_atmio.c b/drivers/comedi/drivers/ni_atmio.c index 330ae1c58800..b4e759e5703f 100644 --- a/drivers/comedi/drivers/ni_atmio.c +++ b/drivers/comedi/drivers/ni_atmio.c @@ -215,7 +215,7 @@ static const int ni_irqpin[] = { #include "ni_mio_common.c" -static const struct pnp_device_id device_ids[] = { +static const struct pnp_device_id __maybe_unused device_ids[] = { {.id = "NIC1900", .driver_data = 0}, {.id = "NIC2400", .driver_data = 0}, {.id = "NIC2500", .driver_data = 0}, diff --git a/drivers/comedi/drivers/ni_pcidio.c b/drivers/comedi/drivers/ni_pcidio.c index 2d58e83420e8..2c7bb9c1ea5b 100644 --- a/drivers/comedi/drivers/ni_pcidio.c +++ b/drivers/comedi/drivers/ni_pcidio.c @@ -747,8 +747,6 @@ static int ni_pcidio_change(struct comedi_device *dev, if (ret < 0) return ret; - memset(s->async->prealloc_buf, 0xaa, s->async->prealloc_bufsz); - return 0; } diff --git a/drivers/counter/interrupt-cnt.c b/drivers/counter/interrupt-cnt.c index 949598d51575..6c0c1d2d7027 100644 --- a/drivers/counter/interrupt-cnt.c +++ b/drivers/counter/interrupt-cnt.c @@ -3,22 +3,25 @@ * Copyright (c) 2021 Pengutronix, Oleksij Rempel <kernel@pengutronix.de> */ +#include <linux/cleanup.h> #include <linux/counter.h> #include <linux/gpio/consumer.h> #include <linux/interrupt.h> #include <linux/irq.h> #include <linux/mod_devicetable.h> #include <linux/module.h> +#include <linux/mutex.h> #include <linux/platform_device.h> #include <linux/types.h> #define INTERRUPT_CNT_NAME "interrupt-cnt" struct interrupt_cnt_priv { - atomic_t count; + atomic_long_t count; struct gpio_desc *gpio; int irq; bool enabled; + struct mutex lock; struct counter_signal signals; struct counter_synapse synapses; struct counter_count cnts; @@ -29,7 +32,7 @@ static irqreturn_t interrupt_cnt_isr(int irq, void *dev_id) struct counter_device *counter = dev_id; struct interrupt_cnt_priv *priv = counter_priv(counter); - atomic_inc(&priv->count); + atomic_long_inc(&priv->count); counter_push_event(counter, COUNTER_EVENT_CHANGE_OF_STATE, 0); @@ -41,6 +44,8 @@ static int interrupt_cnt_enable_read(struct counter_device *counter, { struct interrupt_cnt_priv *priv = counter_priv(counter); + guard(mutex)(&priv->lock); + *enable = priv->enabled; return 0; @@ -51,6 +56,8 @@ static int interrupt_cnt_enable_write(struct counter_device *counter, { struct interrupt_cnt_priv *priv = counter_priv(counter); + guard(mutex)(&priv->lock); + if (priv->enabled == enable) return 0; @@ -89,7 +96,7 @@ static int interrupt_cnt_read(struct counter_device *counter, { struct interrupt_cnt_priv *priv = counter_priv(counter); - *val = atomic_read(&priv->count); + *val = atomic_long_read(&priv->count); return 0; } @@ -102,7 +109,7 @@ static int interrupt_cnt_write(struct counter_device *counter, if (val != (typeof(priv->count.counter))val) return -ERANGE; - atomic_set(&priv->count, val); + atomic_long_set(&priv->count, val); return 0; } @@ -227,6 +234,8 @@ static int interrupt_cnt_probe(struct platform_device *pdev) if (ret) return ret; + mutex_init(&priv->lock); + ret = devm_counter_add(dev, counter); if (ret < 0) return dev_err_probe(dev, ret, "Failed to add counter\n"); diff --git a/drivers/counter/microchip-tcb-capture.c b/drivers/counter/microchip-tcb-capture.c index 1de3c50b9804..1a299d1f350b 100644 --- a/drivers/counter/microchip-tcb-capture.c +++ b/drivers/counter/microchip-tcb-capture.c @@ -337,6 +337,28 @@ static struct counter_comp mchp_tc_count_ext[] = { COUNTER_COMP_COMPARE(mchp_tc_count_compare_read, mchp_tc_count_compare_write), }; +static int mchp_tc_watch_validate(struct counter_device *counter, + const struct counter_watch *watch) +{ + if (watch->channel == COUNTER_MCHP_EVCHN_CV || watch->channel == COUNTER_MCHP_EVCHN_RA) + switch (watch->event) { + case COUNTER_EVENT_CHANGE_OF_STATE: + case COUNTER_EVENT_OVERFLOW: + case COUNTER_EVENT_CAPTURE: + return 0; + default: + return -EINVAL; + } + + if (watch->channel == COUNTER_MCHP_EVCHN_RB && watch->event == COUNTER_EVENT_CAPTURE) + return 0; + + if (watch->channel == COUNTER_MCHP_EVCHN_RC && watch->event == COUNTER_EVENT_THRESHOLD) + return 0; + + return -EINVAL; +} + static struct counter_count mchp_tc_counts[] = { { .id = 0, @@ -356,7 +378,8 @@ static const struct counter_ops mchp_tc_ops = { .function_read = mchp_tc_count_function_read, .function_write = mchp_tc_count_function_write, .action_read = mchp_tc_count_action_read, - .action_write = mchp_tc_count_action_write + .action_write = mchp_tc_count_action_write, + .watch_validate = mchp_tc_watch_validate, }; static const struct atmel_tcb_config tcb_rm9200_config = { diff --git a/drivers/counter/stm32-timer-cnt.c b/drivers/counter/stm32-timer-cnt.c index e75b69476a00..3d3384cbea87 100644 --- a/drivers/counter/stm32-timer-cnt.c +++ b/drivers/counter/stm32-timer-cnt.c @@ -669,12 +669,14 @@ static void stm32_timer_cnt_detect_channels(struct device *dev, dev_dbg(dev, "has %d cc channels\n", priv->nchannels); } -/* encoder supported on TIM1 TIM2 TIM3 TIM4 TIM5 TIM8 */ -#define STM32_TIM_ENCODER_SUPPORTED (BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(7)) +/* encoder supported on TIM1 TIM2 TIM3 TIM4 TIM5 TIM8 TIM20 */ +#define STM32_TIM_ENCODER_SUPPORTED (BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(7) | \ + BIT(19)) static const char * const stm32_timer_trigger_compat[] = { "st,stm32-timer-trigger", "st,stm32h7-timer-trigger", + "st,stm32mp25-timer-trigger", }; static int stm32_timer_cnt_probe_encoder(struct device *dev, @@ -846,6 +848,7 @@ static SIMPLE_DEV_PM_OPS(stm32_timer_cnt_pm_ops, stm32_timer_cnt_suspend, static const struct of_device_id stm32_timer_cnt_of_match[] = { { .compatible = "st,stm32-timer-counter", }, + { .compatible = "st,stm32mp25-timer-counter", }, {}, }; MODULE_DEVICE_TABLE(of, stm32_timer_cnt_of_match); diff --git a/drivers/cpufreq/powernv-cpufreq.c b/drivers/cpufreq/powernv-cpufreq.c index afe5abf89d33..a8943e2a93be 100644 --- a/drivers/cpufreq/powernv-cpufreq.c +++ b/drivers/cpufreq/powernv-cpufreq.c @@ -667,7 +667,8 @@ static inline void queue_gpstate_timer(struct global_pstate_info *gpstates) */ static void gpstate_timer_handler(struct timer_list *t) { - struct global_pstate_info *gpstates = from_timer(gpstates, t, timer); + struct global_pstate_info *gpstates = timer_container_of(gpstates, t, + timer); struct cpufreq_policy *policy = gpstates->policy; int gpstate_idx, lpstate_idx; unsigned long val; diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index 5686369779be..9f8a3a5bed7e 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -180,6 +180,7 @@ config CRYPTO_PAES_S390 depends on PKEY select CRYPTO_ALGAPI select CRYPTO_SKCIPHER + select CRYPTO_ENGINE help This is the s390 hardware accelerated implementation of the AES cipher algorithms for use with protected key. diff --git a/drivers/crypto/axis/artpec6_crypto.c b/drivers/crypto/axis/artpec6_crypto.c index f8d50bd227a6..75ee065da1ec 100644 --- a/drivers/crypto/axis/artpec6_crypto.c +++ b/drivers/crypto/axis/artpec6_crypto.c @@ -2072,7 +2072,7 @@ static void artpec6_crypto_process_queue(struct artpec6_crypto *ac, static void artpec6_crypto_timeout(struct timer_list *t) { - struct artpec6_crypto *ac = from_timer(ac, t, timer); + struct artpec6_crypto *ac = timer_container_of(ac, t, timer); dev_info_ratelimited(artpec6_crypto_dev, "timeout\n"); diff --git a/drivers/dma-buf/st-dma-fence.c b/drivers/dma-buf/st-dma-fence.c index 261b38816226..27a36045410b 100644 --- a/drivers/dma-buf/st-dma-fence.c +++ b/drivers/dma-buf/st-dma-fence.c @@ -375,7 +375,7 @@ struct wait_timer { static void wait_timer(struct timer_list *timer) { - struct wait_timer *wt = from_timer(wt, timer, timer); + struct wait_timer *wt = timer_container_of(wt, timer, timer); dma_fence_signal(wt->f); } diff --git a/drivers/dma/imx-dma.c b/drivers/dma/imx-dma.c index b96cc0a83872..ba434657059a 100644 --- a/drivers/dma/imx-dma.c +++ b/drivers/dma/imx-dma.c @@ -337,7 +337,8 @@ static void imxdma_disable_hw(struct imxdma_channel *imxdmac) static void imxdma_watchdog(struct timer_list *t) { - struct imxdma_channel *imxdmac = from_timer(imxdmac, t, watchdog); + struct imxdma_channel *imxdmac = timer_container_of(imxdmac, t, + watchdog); struct imxdma_engine *imxdma = imxdmac->imxdma; int channel = imxdmac->channel; diff --git a/drivers/dma/ioat/dma.c b/drivers/dma/ioat/dma.c index 06a813cc7641..b8fff8333aef 100644 --- a/drivers/dma/ioat/dma.c +++ b/drivers/dma/ioat/dma.c @@ -901,7 +901,8 @@ static void ioat_reboot_chan(struct ioatdma_chan *ioat_chan) void ioat_timer_event(struct timer_list *t) { - struct ioatdma_chan *ioat_chan = from_timer(ioat_chan, t, timer); + struct ioatdma_chan *ioat_chan = timer_container_of(ioat_chan, t, + timer); dma_addr_t phys_complete; u64 status; diff --git a/drivers/eisa/Makefile b/drivers/eisa/Makefile index a1dd0eaec2d4..552bd9478340 100644 --- a/drivers/eisa/Makefile +++ b/drivers/eisa/Makefile @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 # Makefile for the Linux device tree +always-$(CONFIG_EISA) += devlist.h obj-$(CONFIG_EISA) += eisa-bus.o obj-${CONFIG_EISA_PCI_EISA} += pci_eisa.o @@ -9,14 +10,11 @@ obj-${CONFIG_EISA_PCI_EISA} += pci_eisa.o obj-${CONFIG_EISA_VIRTUAL_ROOT} += virtual_root.o -# Ugly hack to get DEVICE_NAME_SIZE value... -DEVICE_NAME_SIZE = 50 - $(obj)/eisa-bus.o: $(obj)/devlist.h quiet_cmd_eisaid = GEN $@ - cmd_eisaid = sed -e '/^\#/D' -e 's/^\([[:alnum:]]\{7\}\) \+"\([^"]\{1,$(DEVICE_NAME_SIZE)\}\).*"/EISA_DEVINFO ("\1", "\2"),/' $< > $@ + cmd_eisaid = sed -e '/^\#/D' -e 's/^\([[:alnum:]]\{7\}\) \+"\([^"]*\)"/EISA_DEVINFO ("\1", "\2"),/' $< > $@ clean-files := devlist.h -$(obj)/devlist.h: $(src)/eisa.ids include/linux/device.h - $(call cmd,eisaid) +$(obj)/devlist.h: $(src)/eisa.ids include/linux/device.h FORCE + $(call if_changed,eisaid) diff --git a/drivers/eisa/eisa-bus.c b/drivers/eisa/eisa-bus.c index cb586a362944..edceea083b98 100644 --- a/drivers/eisa/eisa-bus.c +++ b/drivers/eisa/eisa-bus.c @@ -21,7 +21,7 @@ struct eisa_device_info { struct eisa_device_id id; - char name[50]; + char name[EISA_DEVICE_INFO_NAME_SIZE]; }; #ifdef CONFIG_EISA_NAMES diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c index 18cacb9edbbc..2bd5deb9054e 100644 --- a/drivers/firewire/core-transaction.c +++ b/drivers/firewire/core-transaction.c @@ -114,7 +114,7 @@ EXPORT_SYMBOL(fw_cancel_transaction); static void split_transaction_timeout_callback(struct timer_list *timer) { - struct fw_transaction *t = from_timer(t, timer, split_timeout_timer); + struct fw_transaction *t = timer_container_of(t, timer, split_timeout_timer); struct fw_card *card = t->card; scoped_guard(spinlock_irqsave, &card->lock) { diff --git a/drivers/firmware/cirrus/test/cs_dsp_mock_wmfw.c b/drivers/firmware/cirrus/test/cs_dsp_mock_wmfw.c index 934d40a4d709..5e1d5a810afe 100644 --- a/drivers/firmware/cirrus/test/cs_dsp_mock_wmfw.c +++ b/drivers/firmware/cirrus/test/cs_dsp_mock_wmfw.c @@ -133,10 +133,11 @@ void cs_dsp_mock_wmfw_add_info(struct cs_dsp_mock_wmfw_builder *builder, if (info_len % 4) { /* Create a padded string with length a multiple of 4 */ + size_t copy_len = info_len; info_len = round_up(info_len, 4); tmp = kunit_kzalloc(builder->test_priv->test, info_len, GFP_KERNEL); KUNIT_ASSERT_NOT_ERR_OR_NULL(builder->test_priv->test, tmp); - memcpy(tmp, info, info_len); + memcpy(tmp, info, copy_len); info = tmp; } diff --git a/drivers/firmware/cirrus/test/cs_dsp_test_control_cache.c b/drivers/firmware/cirrus/test/cs_dsp_test_control_cache.c index 83386cc978e3..ebca3a4ab0f1 100644 --- a/drivers/firmware/cirrus/test/cs_dsp_test_control_cache.c +++ b/drivers/firmware/cirrus/test/cs_dsp_test_control_cache.c @@ -776,7 +776,6 @@ static void cs_dsp_ctl_cache_init_multiple_offsets(struct kunit *test) "dummyalg", NULL); /* Create controls identical except for offset */ - def.length_bytes = 8; def.offset_dsp_words = 0; def.shortname = "CtlA"; cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &def); diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile index 2f173391b63d..939a4955e00b 100644 --- a/drivers/firmware/efi/libstub/Makefile +++ b/drivers/firmware/efi/libstub/Makefile @@ -31,7 +31,7 @@ cflags-$(CONFIG_ARM) += -DEFI_HAVE_STRLEN -DEFI_HAVE_STRNLEN \ $(DISABLE_STACKLEAK_PLUGIN) cflags-$(CONFIG_RISCV) += -fpic -DNO_ALTERNATIVE -mno-relax \ $(DISABLE_STACKLEAK_PLUGIN) -cflags-$(CONFIG_LOONGARCH) += -fpie +cflags-$(CONFIG_LOONGARCH) += -fpie $(DISABLE_STACKLEAK_PLUGIN) cflags-$(CONFIG_EFI_PARAMS_FROM_FDT) += -I$(srctree)/scripts/dtc/libfdt @@ -101,7 +101,7 @@ lib-$(CONFIG_EFI_ZBOOT) += zboot.o $(zboot-obj-y) lib-$(CONFIG_UNACCEPTED_MEMORY) += unaccepted_memory.o bitmap.o find.o -extra-y := $(lib-y) +targets := $(lib-y) lib-y := $(patsubst %.o,%.stub.o,$(lib-y)) # Even when -mbranch-protection=none is set, Clang will generate a diff --git a/drivers/firmware/sysfb.c b/drivers/firmware/sysfb.c index 7c5c03f274b9..889e5b05c739 100644 --- a/drivers/firmware/sysfb.c +++ b/drivers/firmware/sysfb.c @@ -143,6 +143,7 @@ static __init int sysfb_init(void) { struct screen_info *si = &screen_info; struct device *parent; + unsigned int type; struct simplefb_platform_data mode; const char *name; bool compatible; @@ -170,17 +171,26 @@ static __init int sysfb_init(void) goto put_device; } + type = screen_info_video_type(si); + /* if the FB is incompatible, create a legacy framebuffer device */ - if (si->orig_video_isVGA == VIDEO_TYPE_EFI) - name = "efi-framebuffer"; - else if (si->orig_video_isVGA == VIDEO_TYPE_VLFB) - name = "vesa-framebuffer"; - else if (si->orig_video_isVGA == VIDEO_TYPE_VGAC) - name = "vga-framebuffer"; - else if (si->orig_video_isVGA == VIDEO_TYPE_EGAC) + switch (type) { + case VIDEO_TYPE_EGAC: name = "ega-framebuffer"; - else + break; + case VIDEO_TYPE_VGAC: + name = "vga-framebuffer"; + break; + case VIDEO_TYPE_VLFB: + name = "vesa-framebuffer"; + break; + case VIDEO_TYPE_EFI: + name = "efi-framebuffer"; + break; + default: name = "platform-framebuffer"; + break; + } pd = platform_device_alloc(name, 0); if (!pd) { diff --git a/drivers/fpga/tests/fpga-mgr-test.c b/drivers/fpga/tests/fpga-mgr-test.c index 8748babb0504..62975a39ee14 100644 --- a/drivers/fpga/tests/fpga-mgr-test.c +++ b/drivers/fpga/tests/fpga-mgr-test.c @@ -263,6 +263,7 @@ static void fpga_mgr_test_img_load_sgt(struct kunit *test) img_buf = init_test_buffer(test, IMAGE_SIZE); sgt = kunit_kzalloc(test, sizeof(*sgt), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sgt); ret = sg_alloc_table(sgt, 1, GFP_KERNEL); KUNIT_ASSERT_EQ(test, ret, 0); sg_init_one(sgt->sgl, img_buf, IMAGE_SIZE); diff --git a/drivers/gpu/drm/amd/amdgpu/Kconfig b/drivers/gpu/drm/amd/amdgpu/Kconfig index 058e3b3ad520..1acfed2f92ef 100644 --- a/drivers/gpu/drm/amd/amdgpu/Kconfig +++ b/drivers/gpu/drm/amd/amdgpu/Kconfig @@ -76,7 +76,7 @@ config DRM_AMDGPU_USERPTR config DRM_AMD_ISP bool "Enable AMD Image Signal Processor IP support" - depends on DRM_AMDGPU + depends on DRM_AMDGPU && ACPI select MFD_CORE select PM_GENERIC_DOMAINS if PM help diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 836ea081088a..a5ccd0ada16a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -1713,6 +1713,10 @@ static inline bool amdgpu_acpi_is_s0ix_active(struct amdgpu_device *adev) { retu static inline bool amdgpu_acpi_is_s3_active(struct amdgpu_device *adev) { return false; } #endif +#if defined(CONFIG_DRM_AMD_ISP) +int amdgpu_acpi_get_isp4_dev_hid(u8 (*hid)[ACPI_ID_LEN]); +#endif + void amdgpu_register_gpu_instance(struct amdgpu_device *adev); void amdgpu_unregister_gpu_instance(struct amdgpu_device *adev); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c index 707e131f89d2..f5466c592d94 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c @@ -1532,5 +1532,35 @@ bool amdgpu_acpi_is_s0ix_active(struct amdgpu_device *adev) return true; #endif /* CONFIG_AMD_PMC */ } - #endif /* CONFIG_SUSPEND */ + +#if IS_ENABLED(CONFIG_DRM_AMD_ISP) +static const struct acpi_device_id isp_sensor_ids[] = { + { "OMNI5C10" }, + { } +}; + +static int isp_match_acpi_device_ids(struct device *dev, const void *data) +{ + return acpi_match_device(data, dev) ? 1 : 0; +} + +int amdgpu_acpi_get_isp4_dev_hid(u8 (*hid)[ACPI_ID_LEN]) +{ + struct device *pdev __free(put_device) = NULL; + struct acpi_device *acpi_pdev; + + pdev = bus_find_device(&platform_bus_type, NULL, isp_sensor_ids, + isp_match_acpi_device_ids); + if (!pdev) + return -EINVAL; + + acpi_pdev = ACPI_COMPANION(pdev); + if (!acpi_pdev) + return -ENODEV; + + strscpy(*hid, acpi_device_hid(acpi_pdev)); + + return 0; +} +#endif /* CONFIG_DRM_AMD_ISP */ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c index 4cec3a873995..d8ac4b1051a8 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c @@ -368,6 +368,9 @@ void amdgpu_amdkfd_free_gtt_mem(struct amdgpu_device *adev, void **mem_obj) { struct amdgpu_bo **bo = (struct amdgpu_bo **) mem_obj; + if (!bo || !*bo) + return; + (void)amdgpu_bo_reserve(*bo, true); amdgpu_bo_kunmap(*bo); amdgpu_bo_unpin(*bo); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c index c43d1b6e5d66..85567d0d9545 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c @@ -919,7 +919,7 @@ long amdgpu_ctx_mgr_entity_flush(struct amdgpu_ctx_mgr *mgr, long timeout) return timeout; } -void amdgpu_ctx_mgr_entity_fini(struct amdgpu_ctx_mgr *mgr) +static void amdgpu_ctx_mgr_entity_fini(struct amdgpu_ctx_mgr *mgr) { struct amdgpu_ctx *ctx; struct idr *idp; @@ -949,19 +949,7 @@ void amdgpu_ctx_mgr_entity_fini(struct amdgpu_ctx_mgr *mgr) void amdgpu_ctx_mgr_fini(struct amdgpu_ctx_mgr *mgr) { - struct amdgpu_ctx *ctx; - struct idr *idp; - uint32_t id; - amdgpu_ctx_mgr_entity_fini(mgr); - - idp = &mgr->ctx_handles; - - idr_for_each_entry(idp, ctx, id) { - if (kref_put(&ctx->refcount, amdgpu_ctx_fini) != 1) - DRM_ERROR("ctx %p is still alive\n", ctx); - } - idr_destroy(&mgr->ctx_handles); mutex_destroy(&mgr->lock); } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.h index 85376baaa92f..090dfe86f75b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.h @@ -92,7 +92,6 @@ int amdgpu_ctx_wait_prev_fence(struct amdgpu_ctx *ctx, void amdgpu_ctx_mgr_init(struct amdgpu_ctx_mgr *mgr, struct amdgpu_device *adev); -void amdgpu_ctx_mgr_entity_fini(struct amdgpu_ctx_mgr *mgr); long amdgpu_ctx_mgr_entity_flush(struct amdgpu_ctx_mgr *mgr, long timeout); void amdgpu_ctx_mgr_fini(struct amdgpu_ctx_mgr *mgr); void amdgpu_ctx_mgr_usage(struct amdgpu_ctx_mgr *mgr, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 4d1b54f58495..e1bab6a96cb6 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -512,12 +512,13 @@ void amdgpu_device_detect_runtime_pm_mode(struct amdgpu_device *adev) break; case CHIP_VEGA10: /* enable BACO as runpm mode if noretry=0 */ - if (!adev->gmc.noretry) + if (!adev->gmc.noretry && !amdgpu_passthrough(adev)) adev->pm.rpm_mode = AMDGPU_RUNPM_BACO; break; default: /* enable BACO as runpm mode on CI+ */ - adev->pm.rpm_mode = AMDGPU_RUNPM_BACO; + if (!amdgpu_passthrough(adev)) + adev->pm.rpm_mode = AMDGPU_RUNPM_BACO; break; } @@ -4728,7 +4729,7 @@ fence_driver_init: amdgpu_fru_sysfs_init(adev); amdgpu_reg_state_sysfs_init(adev); - amdgpu_xcp_cfg_sysfs_init(adev); + amdgpu_xcp_sysfs_init(adev); if (IS_ENABLED(CONFIG_PERF_EVENTS)) r = amdgpu_pmu_init(adev); @@ -4858,7 +4859,7 @@ void amdgpu_device_fini_hw(struct amdgpu_device *adev) amdgpu_fru_sysfs_fini(adev); amdgpu_reg_state_sysfs_fini(adev); - amdgpu_xcp_cfg_sysfs_fini(adev); + amdgpu_xcp_sysfs_fini(adev); /* disable ras feature must before hw fini */ amdgpu_ras_pre_fini(adev); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c index 9e738fae2b74..a0e9bf9b2710 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c @@ -270,9 +270,10 @@ static int amdgpu_discovery_read_binary_from_sysmem(struct amdgpu_device *adev, static int amdgpu_discovery_read_binary_from_mem(struct amdgpu_device *adev, uint8_t *binary) { + bool sz_valid = true; uint64_t vram_size; - u32 msg; int i, ret = 0; + u32 msg; if (!amdgpu_sriov_vf(adev)) { /* It can take up to a second for IFWI init to complete on some dGPUs, @@ -291,9 +292,13 @@ static int amdgpu_discovery_read_binary_from_mem(struct amdgpu_device *adev, } } - vram_size = (uint64_t)RREG32(mmRCC_CONFIG_MEMSIZE) << 20; + vram_size = RREG32(mmRCC_CONFIG_MEMSIZE); + if (!vram_size || vram_size == U32_MAX) + sz_valid = false; + else + vram_size <<= 20; - if (vram_size) { + if (sz_valid) { uint64_t pos = vram_size - DISCOVERY_TMR_OFFSET; amdgpu_device_vram_access(adev, pos, (uint32_t *)binary, adev->mman.discovery_tmr_size, false); @@ -301,6 +306,11 @@ static int amdgpu_discovery_read_binary_from_mem(struct amdgpu_device *adev, ret = amdgpu_discovery_read_binary_from_sysmem(adev, binary); } + if (ret) + dev_err(adev->dev, + "failed to read discovery info from memory, vram size read: %llx", + vram_size); + return ret; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c index 4ddd08ce8885..4db92e0a60da 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c @@ -2913,8 +2913,8 @@ static int amdgpu_drm_release(struct inode *inode, struct file *filp) if (fpriv) { fpriv->evf_mgr.fd_closing = true; - amdgpu_userq_mgr_fini(&fpriv->userq_mgr); amdgpu_eviction_fence_destroy(&fpriv->evf_mgr); + amdgpu_userq_mgr_fini(&fpriv->userq_mgr); } return drm_release(inode, filp); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_eviction_fence.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_eviction_fence.c index 73b629b5f56f..8b919ad3af29 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_eviction_fence.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_eviction_fence.c @@ -108,13 +108,22 @@ amdgpu_eviction_fence_suspend_worker(struct work_struct *work) struct amdgpu_eviction_fence *ev_fence; mutex_lock(&uq_mgr->userq_mutex); + spin_lock(&evf_mgr->ev_fence_lock); ev_fence = evf_mgr->ev_fence; - if (!ev_fence) + if (ev_fence) + dma_fence_get(&ev_fence->base); + else goto unlock; + spin_unlock(&evf_mgr->ev_fence_lock); amdgpu_userq_evict(uq_mgr, ev_fence); + mutex_unlock(&uq_mgr->userq_mutex); + dma_fence_put(&ev_fence->base); + return; + unlock: + spin_unlock(&evf_mgr->ev_fence_lock); mutex_unlock(&uq_mgr->userq_mutex); } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c index 5f5c00ace96b..8cecf25996ed 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c @@ -322,8 +322,8 @@ bool amdgpu_fence_process(struct amdgpu_ring *ring) */ static void amdgpu_fence_fallback(struct timer_list *t) { - struct amdgpu_ring *ring = from_timer(ring, t, - fence_drv.fallback_timer); + struct amdgpu_ring *ring = timer_container_of(ring, t, + fence_drv.fallback_timer); if (amdgpu_fence_process(ring)) DRM_WARN("Fence fallback timer expired on ring %s\n", ring->name); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c index 2c68118fe9fd..0ecc88df7208 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c @@ -58,7 +58,7 @@ amdgpu_gem_add_input_fence(struct drm_file *filp, return 0; syncobj_handles = memdup_user(u64_to_user_ptr(syncobj_handles_array), - sizeof(uint32_t) * num_syncobj_handles); + size_mul(sizeof(uint32_t), num_syncobj_handles)); if (IS_ERR(syncobj_handles)) return PTR_ERR(syncobj_handles); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c index 1db1e6ec0184..c5646af055ab 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c @@ -2228,6 +2228,9 @@ void amdgpu_gfx_profile_ring_begin_use(struct amdgpu_ring *ring) enum PP_SMC_POWER_PROFILE profile; int r; + if (amdgpu_dpm_is_overdrive_enabled(adev)) + return; + if (adev->gfx.num_gfx_rings) profile = PP_SMC_POWER_PROFILE_FULLSCREEN3D; else @@ -2258,6 +2261,11 @@ void amdgpu_gfx_profile_ring_begin_use(struct amdgpu_ring *ring) void amdgpu_gfx_profile_ring_end_use(struct amdgpu_ring *ring) { + struct amdgpu_device *adev = ring->adev; + + if (amdgpu_dpm_is_overdrive_enabled(adev)) + return; + atomic_dec(&ring->adev->gfx.total_submission_cnt); schedule_delayed_work(&ring->adev->gfx.idle_work, GFX_PROFILE_IDLE_TIMEOUT); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c index 9fbb04aee97b..d2ce7d86dbc8 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c @@ -1502,11 +1502,6 @@ void amdgpu_driver_postclose_kms(struct drm_device *dev, amdgpu_bo_unreserve(pd); } - if (!fpriv->evf_mgr.fd_closing) { - fpriv->evf_mgr.fd_closing = true; - amdgpu_userq_mgr_fini(&fpriv->userq_mgr); - amdgpu_eviction_fence_destroy(&fpriv->evf_mgr); - } amdgpu_ctx_mgr_fini(&fpriv->ctx_mgr); amdgpu_vm_fini(adev, &fpriv->vm); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c index 2febb63ab232..6fa9fa11c8f3 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c @@ -300,7 +300,9 @@ int amdgpu_mes_map_legacy_queue(struct amdgpu_device *adev, queue_input.mqd_addr = amdgpu_bo_gpu_offset(ring->mqd_obj); queue_input.wptr_addr = ring->wptr_gpu_addr; + amdgpu_mes_lock(&adev->mes); r = adev->mes.funcs->map_legacy_queue(&adev->mes, &queue_input); + amdgpu_mes_unlock(&adev->mes); if (r) DRM_ERROR("failed to map legacy queue\n"); @@ -323,7 +325,9 @@ int amdgpu_mes_unmap_legacy_queue(struct amdgpu_device *adev, queue_input.trail_fence_addr = gpu_addr; queue_input.trail_fence_data = seq; + amdgpu_mes_lock(&adev->mes); r = adev->mes.funcs->unmap_legacy_queue(&adev->mes, &queue_input); + amdgpu_mes_unlock(&adev->mes); if (r) DRM_ERROR("failed to unmap legacy queue\n"); @@ -353,7 +357,9 @@ int amdgpu_mes_reset_legacy_queue(struct amdgpu_device *adev, if (ring->funcs->type == AMDGPU_RING_TYPE_GFX) queue_input.legacy_gfx = true; + amdgpu_mes_lock(&adev->mes); r = adev->mes.funcs->reset_hw_queue(&adev->mes, &queue_input); + amdgpu_mes_unlock(&adev->mes); if (r) DRM_ERROR("failed to reset legacy queue\n"); @@ -383,7 +389,9 @@ uint32_t amdgpu_mes_rreg(struct amdgpu_device *adev, uint32_t reg) goto error; } + amdgpu_mes_lock(&adev->mes); r = adev->mes.funcs->misc_op(&adev->mes, &op_input); + amdgpu_mes_unlock(&adev->mes); if (r) dev_err(adev->dev, "failed to read reg (0x%x)\n", reg); else @@ -411,7 +419,9 @@ int amdgpu_mes_wreg(struct amdgpu_device *adev, goto error; } + amdgpu_mes_lock(&adev->mes); r = adev->mes.funcs->misc_op(&adev->mes, &op_input); + amdgpu_mes_unlock(&adev->mes); if (r) dev_err(adev->dev, "failed to write reg (0x%x)\n", reg); @@ -438,32 +448,9 @@ int amdgpu_mes_reg_write_reg_wait(struct amdgpu_device *adev, goto error; } + amdgpu_mes_lock(&adev->mes); r = adev->mes.funcs->misc_op(&adev->mes, &op_input); - if (r) - dev_err(adev->dev, "failed to reg_write_reg_wait\n"); - -error: - return r; -} - -int amdgpu_mes_reg_wait(struct amdgpu_device *adev, uint32_t reg, - uint32_t val, uint32_t mask) -{ - struct mes_misc_op_input op_input; - int r; - - op_input.op = MES_MISC_OP_WRM_REG_WAIT; - op_input.wrm_reg.reg0 = reg; - op_input.wrm_reg.ref = val; - op_input.wrm_reg.mask = mask; - - if (!adev->mes.funcs->misc_op) { - dev_err(adev->dev, "mes reg wait is not supported!\n"); - r = -EINVAL; - goto error; - } - - r = adev->mes.funcs->misc_op(&adev->mes, &op_input); + amdgpu_mes_unlock(&adev->mes); if (r) dev_err(adev->dev, "failed to reg_write_reg_wait\n"); @@ -539,42 +526,6 @@ int amdgpu_mes_flush_shader_debugger(struct amdgpu_device *adev, return r; } -#define DEFINE_AMDGPU_MES_CTX_GET_OFFS_ENG(_eng) \ -do { \ - if (id_offs < AMDGPU_MES_CTX_MAX_OFFS) \ - return offsetof(struct amdgpu_mes_ctx_meta_data, \ - _eng[ring->idx].slots[id_offs]); \ - else if (id_offs == AMDGPU_MES_CTX_RING_OFFS) \ - return offsetof(struct amdgpu_mes_ctx_meta_data, \ - _eng[ring->idx].ring); \ - else if (id_offs == AMDGPU_MES_CTX_IB_OFFS) \ - return offsetof(struct amdgpu_mes_ctx_meta_data, \ - _eng[ring->idx].ib); \ - else if (id_offs == AMDGPU_MES_CTX_PADDING_OFFS) \ - return offsetof(struct amdgpu_mes_ctx_meta_data, \ - _eng[ring->idx].padding); \ -} while(0) - -int amdgpu_mes_ctx_get_offs(struct amdgpu_ring *ring, unsigned int id_offs) -{ - switch (ring->funcs->type) { - case AMDGPU_RING_TYPE_GFX: - DEFINE_AMDGPU_MES_CTX_GET_OFFS_ENG(gfx); - break; - case AMDGPU_RING_TYPE_COMPUTE: - DEFINE_AMDGPU_MES_CTX_GET_OFFS_ENG(compute); - break; - case AMDGPU_RING_TYPE_SDMA: - DEFINE_AMDGPU_MES_CTX_GET_OFFS_ENG(sdma); - break; - default: - break; - } - - WARN_ON(1); - return -EINVAL; -} - uint32_t amdgpu_mes_get_aggregated_doorbell_index(struct amdgpu_device *adev, enum amdgpu_mes_priority_level prio) { @@ -694,7 +645,9 @@ static int amdgpu_mes_set_enforce_isolation(struct amdgpu_device *adev, goto error; } + amdgpu_mes_lock(&adev->mes); r = adev->mes.funcs->misc_op(&adev->mes, &op_input); + amdgpu_mes_unlock(&adev->mes); if (r) dev_err(adev->dev, "failed to change_config.\n"); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h index a41f65b4f733..c0d2c195fe2e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h @@ -372,8 +372,6 @@ struct amdgpu_mes_funcs { #define amdgpu_mes_kiq_hw_init(adev) (adev)->mes.kiq_hw_init((adev)) #define amdgpu_mes_kiq_hw_fini(adev) (adev)->mes.kiq_hw_fini((adev)) -int amdgpu_mes_ctx_get_offs(struct amdgpu_ring *ring, unsigned int id_offs); - int amdgpu_mes_init_microcode(struct amdgpu_device *adev, int pipe); int amdgpu_mes_init(struct amdgpu_device *adev); void amdgpu_mes_fini(struct amdgpu_device *adev); @@ -395,8 +393,6 @@ int amdgpu_mes_reset_legacy_queue(struct amdgpu_device *adev, uint32_t amdgpu_mes_rreg(struct amdgpu_device *adev, uint32_t reg); int amdgpu_mes_wreg(struct amdgpu_device *adev, uint32_t reg, uint32_t val); -int amdgpu_mes_reg_wait(struct amdgpu_device *adev, uint32_t reg, - uint32_t val, uint32_t mask); int amdgpu_mes_reg_write_reg_wait(struct amdgpu_device *adev, uint32_t reg0, uint32_t reg1, uint32_t ref, uint32_t mask); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c index dc07936d2fcb..de0944947eaf 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c @@ -2859,6 +2859,15 @@ static int __amdgpu_ras_convert_rec_array_from_rom(struct amdgpu_device *adev, return -EINVAL; } } else { + if (bps[0].address == 0) { + /* for specific old eeprom data, mca address is not stored, + * calc it from pa + */ + if (amdgpu_umc_pa2mca(adev, bps[0].retired_page << AMDGPU_GPU_PAGE_SHIFT, + &(bps[0].address), AMDGPU_NPS1_PARTITION_MODE)) + return -EINVAL; + } + if (amdgpu_ras_mca2pa(adev, &bps[0], err_data)) { if (nps == AMDGPU_NPS1_PARTITION_MODE) memcpy(err_data->err_addr, bps, @@ -2886,8 +2895,20 @@ static int __amdgpu_ras_convert_rec_from_rom(struct amdgpu_device *adev, bps->retired_page << AMDGPU_GPU_PAGE_SHIFT)) return -EINVAL; } else { - if (amdgpu_ras_mca2pa_by_idx(adev, bps, err_data)) - return -EINVAL; + if (bps->address) { + if (amdgpu_ras_mca2pa_by_idx(adev, bps, err_data)) + return -EINVAL; + } else { + /* for specific old eeprom data, mca address is not stored, + * calc it from pa + */ + if (amdgpu_umc_pa2mca(adev, bps->retired_page << AMDGPU_GPU_PAGE_SHIFT, + &(bps->address), AMDGPU_NPS1_PARTITION_MODE)) + return -EINVAL; + + if (amdgpu_ras_mca2pa(adev, bps, err_data)) + return -EOPNOTSUPP; + } } return __amdgpu_ras_restore_bad_pages(adev, err_data->err_addr, @@ -3708,7 +3729,8 @@ static void amdgpu_ras_query_ras_capablity_from_vbios(struct amdgpu_device *adev */ if (amdgpu_ip_version(adev, VCN_HWIP, 0) == IP_VERSION(2, 6, 0) || amdgpu_ip_version(adev, VCN_HWIP, 0) == IP_VERSION(4, 0, 0) || - amdgpu_ip_version(adev, VCN_HWIP, 0) == IP_VERSION(4, 0, 3)) + amdgpu_ip_version(adev, VCN_HWIP, 0) == IP_VERSION(4, 0, 3) || + amdgpu_ip_version(adev, VCN_HWIP, 0) == IP_VERSION(5, 0, 1)) adev->ras_hw_enabled |= (1 << AMDGPU_RAS_BLOCK__VCN | 1 << AMDGPU_RAS_BLOCK__JPEG); else diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring_mux.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring_mux.c index 03ed14663107..7e7d6c3865bc 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring_mux.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring_mux.c @@ -135,7 +135,8 @@ static void amdgpu_ring_mux_schedule_resubmit(struct amdgpu_ring_mux *mux) static void amdgpu_mux_resubmit_fallback(struct timer_list *t) { - struct amdgpu_ring_mux *mux = from_timer(mux, t, resubmit_timer); + struct amdgpu_ring_mux *mux = timer_container_of(mux, t, + resubmit_timer); if (!spin_trylock(&mux->lock)) { amdgpu_ring_mux_schedule_resubmit(mux); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.h index 5605921212f0..e5f8951bbb6f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.h @@ -113,6 +113,7 @@ struct amdgpu_sdma { struct amdgpu_sdma_instance instance[AMDGPU_MAX_SDMA_INSTANCES]; struct amdgpu_irq_src trap_irq; struct amdgpu_irq_src illegal_inst_irq; + struct amdgpu_irq_src fence_irq; struct amdgpu_irq_src ecc_irq; struct amdgpu_irq_src vm_hole_irq; struct amdgpu_irq_src doorbell_invalid_irq; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_seq64.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_seq64.c index 3939761be31c..d45ebfb642ca 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_seq64.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_seq64.c @@ -139,7 +139,7 @@ void amdgpu_seq64_unmap(struct amdgpu_device *adev, struct amdgpu_fpriv *fpriv) vm = &fpriv->vm; - drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT, 0); + drm_exec_init(&exec, 0, 0); drm_exec_until_all_locked(&exec) { r = amdgpu_vm_lock_pd(vm, &exec, 0); if (likely(!r)) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c index 4a72c2bbd49e..2505c46a9c3d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c @@ -765,6 +765,7 @@ FW_VERSION_ATTR(sdma_fw_version, 0444, sdma.instance[0].fw_version); FW_VERSION_ATTR(sdma2_fw_version, 0444, sdma.instance[1].fw_version); FW_VERSION_ATTR(vcn_fw_version, 0444, vcn.fw_version); FW_VERSION_ATTR(dmcu_fw_version, 0444, dm.dmcu_fw_version); +FW_VERSION_ATTR(dmcub_fw_version, 0444, dm.dmcub_fw_version); FW_VERSION_ATTR(mes_fw_version, 0444, mes.sched_version & AMDGPU_MES_VERSION_MASK); FW_VERSION_ATTR(mes_kiq_fw_version, 0444, mes.kiq_version & AMDGPU_MES_VERSION_MASK); FW_VERSION_ATTR(pldm_fw_version, 0444, firmware.pldm_version); @@ -780,9 +781,10 @@ static struct attribute *fw_attrs[] = { &dev_attr_ta_ras_fw_version.attr, &dev_attr_ta_xgmi_fw_version.attr, &dev_attr_smc_fw_version.attr, &dev_attr_sdma_fw_version.attr, &dev_attr_sdma2_fw_version.attr, &dev_attr_vcn_fw_version.attr, - &dev_attr_dmcu_fw_version.attr, &dev_attr_imu_fw_version.attr, - &dev_attr_mes_fw_version.attr, &dev_attr_mes_kiq_fw_version.attr, - &dev_attr_pldm_fw_version.attr, NULL + &dev_attr_dmcu_fw_version.attr, &dev_attr_dmcub_fw_version.attr, + &dev_attr_imu_fw_version.attr, &dev_attr_mes_fw_version.attr, + &dev_attr_mes_kiq_fw_version.attr, &dev_attr_pldm_fw_version.attr, + NULL }; #define to_dev_attr(x) container_of(x, struct device_attribute, attr) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c index 8c6e55b5b967..c92b8794aa73 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c @@ -562,3 +562,26 @@ int amdgpu_umc_mca_to_addr(struct amdgpu_device *adev, return 0; } + +int amdgpu_umc_pa2mca(struct amdgpu_device *adev, + uint64_t pa, uint64_t *mca, enum amdgpu_memory_partition nps) +{ + struct ta_ras_query_address_input addr_in; + struct ta_ras_query_address_output addr_out; + int ret; + + /* nps: the pa belongs to */ + addr_in.pa.pa = pa | ((uint64_t)nps << 58); + addr_in.addr_type = TA_RAS_PA_TO_MCA; + ret = psp_ras_query_address(&adev->psp, &addr_in, &addr_out); + if (ret) { + dev_warn(adev->dev, "Failed to query RAS MCA address for 0x%llx", + pa); + + return ret; + } + + *mca = addr_out.ma.err_addr; + + return 0; +} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.h index 29ce6b1d214a..ec203f9e5ffa 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.h @@ -189,4 +189,6 @@ int amdgpu_umc_mca_to_addr(struct amdgpu_device *adev, uint64_t err_addr, uint32_t ch, uint32_t umc, uint32_t node, uint32_t socket, struct ta_ras_query_address_output *addr_out, bool dump_addr); +int amdgpu_umc_pa2mca(struct amdgpu_device *adev, + uint64_t pa, uint64_t *mca, enum amdgpu_memory_partition nps); #endif diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c index fc4d0d42e223..a86616c6deef 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c @@ -430,7 +430,7 @@ int amdgpu_userq_signal_ioctl(struct drm_device *dev, void *data, num_syncobj_handles = args->num_syncobj_handles; syncobj_handles = memdup_user(u64_to_user_ptr(args->syncobj_handles), - sizeof(u32) * num_syncobj_handles); + size_mul(sizeof(u32), num_syncobj_handles)); if (IS_ERR(syncobj_handles)) return PTR_ERR(syncobj_handles); @@ -612,13 +612,13 @@ int amdgpu_userq_wait_ioctl(struct drm_device *dev, void *data, num_read_bo_handles = wait_info->num_bo_read_handles; bo_handles_read = memdup_user(u64_to_user_ptr(wait_info->bo_read_handles), - sizeof(u32) * num_read_bo_handles); + size_mul(sizeof(u32), num_read_bo_handles)); if (IS_ERR(bo_handles_read)) return PTR_ERR(bo_handles_read); num_write_bo_handles = wait_info->num_bo_write_handles; bo_handles_write = memdup_user(u64_to_user_ptr(wait_info->bo_write_handles), - sizeof(u32) * num_write_bo_handles); + size_mul(sizeof(u32), num_write_bo_handles)); if (IS_ERR(bo_handles_write)) { r = PTR_ERR(bo_handles_write); goto free_bo_handles_read; @@ -626,7 +626,7 @@ int amdgpu_userq_wait_ioctl(struct drm_device *dev, void *data, num_syncobj = wait_info->num_syncobj_handles; syncobj_handles = memdup_user(u64_to_user_ptr(wait_info->syncobj_handles), - sizeof(u32) * num_syncobj); + size_mul(sizeof(u32), num_syncobj)); if (IS_ERR(syncobj_handles)) { r = PTR_ERR(syncobj_handles); goto free_bo_handles_write; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c index 2d7f82e98df9..abdc52b0895a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c @@ -463,7 +463,7 @@ static int amdgpu_vram_mgr_new(struct ttm_resource_manager *man, int r; lpfn = (u64)place->lpfn << PAGE_SHIFT; - if (!lpfn) + if (!lpfn || lpfn > man->size) lpfn = man->size; fpfn = (u64)place->fpfn << PAGE_SHIFT; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.c index b03c3895897b..322816805bfb 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.c @@ -27,6 +27,9 @@ #include <drm/drm_drv.h> #include "../amdxcp/amdgpu_xcp_drv.h" +static void amdgpu_xcp_sysfs_entries_init(struct amdgpu_xcp_mgr *xcp_mgr); +static void amdgpu_xcp_sysfs_entries_update(struct amdgpu_xcp_mgr *xcp_mgr); + static int __amdgpu_xcp_run(struct amdgpu_xcp_mgr *xcp_mgr, struct amdgpu_xcp_ip *xcp_ip, int xcp_state) { @@ -189,7 +192,7 @@ static int __amdgpu_xcp_switch_partition_mode(struct amdgpu_xcp_mgr *xcp_mgr, goto out; } - + amdgpu_xcp_sysfs_entries_update(xcp_mgr); out: mutex_unlock(&xcp_mgr->xcp_lock); @@ -263,9 +266,10 @@ static int amdgpu_xcp_dev_alloc(struct amdgpu_device *adev) if (ret == -ENOSPC) { dev_warn(adev->dev, "Skip xcp node #%d when out of drm node resource.", i); - return 0; + ret = 0; + goto out; } else if (ret) { - return ret; + goto out; } /* Redirect all IOCTLs to the primary device */ @@ -278,9 +282,14 @@ static int amdgpu_xcp_dev_alloc(struct amdgpu_device *adev) p_ddev->vma_offset_manager = ddev->vma_offset_manager; p_ddev->driver = &amdgpu_partition_driver; adev->xcp_mgr->xcp[i].ddev = p_ddev; + + dev_set_drvdata(p_ddev->dev, &adev->xcp_mgr->xcp[i]); } + ret = 0; +out: + amdgpu_xcp_sysfs_entries_init(adev->xcp_mgr); - return 0; + return ret; } int amdgpu_xcp_mgr_init(struct amdgpu_device *adev, int init_mode, @@ -288,6 +297,7 @@ int amdgpu_xcp_mgr_init(struct amdgpu_device *adev, int init_mode, struct amdgpu_xcp_mgr_funcs *xcp_funcs) { struct amdgpu_xcp_mgr *xcp_mgr; + int i; if (!xcp_funcs || !xcp_funcs->get_ip_details) return -EINVAL; @@ -306,6 +316,8 @@ int amdgpu_xcp_mgr_init(struct amdgpu_device *adev, int init_mode, amdgpu_xcp_init(xcp_mgr, init_num_xcps, init_mode); adev->xcp_mgr = xcp_mgr; + for (i = 0; i < MAX_XCP; ++i) + xcp_mgr->xcp[i].xcp_mgr = xcp_mgr; return amdgpu_xcp_dev_alloc(adev); } @@ -433,6 +445,7 @@ void amdgpu_xcp_release_sched(struct amdgpu_device *adev, } } +/*====================== xcp sysfs - configuration ======================*/ #define XCP_CFG_SYSFS_RES_ATTR_SHOW(_name) \ static ssize_t amdgpu_xcp_res_sysfs_##_name##_show( \ struct amdgpu_xcp_res_details *xcp_res, char *buf) \ @@ -635,7 +648,7 @@ static const struct attribute *xcp_attrs[] = { NULL, }; -void amdgpu_xcp_cfg_sysfs_init(struct amdgpu_device *adev) +static void amdgpu_xcp_cfg_sysfs_init(struct amdgpu_device *adev) { struct amdgpu_xcp_res_details *xcp_res; struct amdgpu_xcp_cfg *xcp_cfg; @@ -703,7 +716,7 @@ err1: kobject_put(&xcp_cfg->kobj); } -void amdgpu_xcp_cfg_sysfs_fini(struct amdgpu_device *adev) +static void amdgpu_xcp_cfg_sysfs_fini(struct amdgpu_device *adev) { struct amdgpu_xcp_res_details *xcp_res; struct amdgpu_xcp_cfg *xcp_cfg; @@ -722,3 +735,124 @@ void amdgpu_xcp_cfg_sysfs_fini(struct amdgpu_device *adev) sysfs_remove_files(&xcp_cfg->kobj, xcp_attrs); kobject_put(&xcp_cfg->kobj); } + +/*====================== xcp sysfs - data entries ======================*/ + +#define to_xcp(x) container_of(x, struct amdgpu_xcp, kobj) + +static ssize_t xcp_metrics_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + struct amdgpu_xcp *xcp = to_xcp(kobj); + struct amdgpu_xcp_mgr *xcp_mgr; + ssize_t size; + + xcp_mgr = xcp->xcp_mgr; + size = amdgpu_dpm_get_xcp_metrics(xcp_mgr->adev, xcp->id, NULL); + if (size <= 0) + return size; + + if (size > PAGE_SIZE) + return -ENOSPC; + + return amdgpu_dpm_get_xcp_metrics(xcp_mgr->adev, xcp->id, buf); +} + +static umode_t amdgpu_xcp_attrs_is_visible(struct kobject *kobj, + struct attribute *attr, int n) +{ + struct amdgpu_xcp *xcp = to_xcp(kobj); + + if (!xcp || !xcp->valid) + return 0; + + return attr->mode; +} + +static struct kobj_attribute xcp_sysfs_metrics = __ATTR_RO(xcp_metrics); + +static struct attribute *amdgpu_xcp_attrs[] = { + &xcp_sysfs_metrics.attr, + NULL, +}; + +static const struct attribute_group amdgpu_xcp_attrs_group = { + .attrs = amdgpu_xcp_attrs, + .is_visible = amdgpu_xcp_attrs_is_visible +}; + +static const struct kobj_type xcp_sysfs_ktype = { + .sysfs_ops = &kobj_sysfs_ops, +}; + +static void amdgpu_xcp_sysfs_entries_fini(struct amdgpu_xcp_mgr *xcp_mgr, int n) +{ + struct amdgpu_xcp *xcp; + + for (n--; n >= 0; n--) { + xcp = &xcp_mgr->xcp[n]; + if (!xcp->ddev || !xcp->valid) + continue; + sysfs_remove_group(&xcp->kobj, &amdgpu_xcp_attrs_group); + kobject_put(&xcp->kobj); + } +} + +static void amdgpu_xcp_sysfs_entries_init(struct amdgpu_xcp_mgr *xcp_mgr) +{ + struct amdgpu_xcp *xcp; + int i, r; + + for (i = 0; i < MAX_XCP; i++) { + /* Redirect all IOCTLs to the primary device */ + xcp = &xcp_mgr->xcp[i]; + if (!xcp->ddev) + break; + r = kobject_init_and_add(&xcp->kobj, &xcp_sysfs_ktype, + &xcp->ddev->dev->kobj, "xcp"); + if (r) + goto out; + + r = sysfs_create_group(&xcp->kobj, &amdgpu_xcp_attrs_group); + if (r) + goto out; + } + + return; +out: + kobject_put(&xcp->kobj); +} + +static void amdgpu_xcp_sysfs_entries_update(struct amdgpu_xcp_mgr *xcp_mgr) +{ + struct amdgpu_xcp *xcp; + int i; + + for (i = 0; i < MAX_XCP; i++) { + /* Redirect all IOCTLs to the primary device */ + xcp = &xcp_mgr->xcp[i]; + if (!xcp->ddev) + continue; + sysfs_update_group(&xcp->kobj, &amdgpu_xcp_attrs_group); + } + + return; +} + +void amdgpu_xcp_sysfs_init(struct amdgpu_device *adev) +{ + if (!adev->xcp_mgr) + return; + + amdgpu_xcp_cfg_sysfs_init(adev); + + return; +} + +void amdgpu_xcp_sysfs_fini(struct amdgpu_device *adev) +{ + if (!adev->xcp_mgr) + return; + amdgpu_xcp_sysfs_entries_fini(adev->xcp_mgr, MAX_XCP); + amdgpu_xcp_cfg_sysfs_fini(adev); +} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.h index b63f53242c57..454b33f889fb 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.h @@ -108,6 +108,8 @@ struct amdgpu_xcp { struct drm_driver *driver; struct drm_vma_offset_manager *vma_offset_manager; struct amdgpu_sched gpu_sched[AMDGPU_HW_IP_NUM][AMDGPU_RING_PRIO_MAX]; + struct amdgpu_xcp_mgr *xcp_mgr; + struct kobject kobj; }; struct amdgpu_xcp_mgr { @@ -175,8 +177,8 @@ int amdgpu_xcp_open_device(struct amdgpu_device *adev, void amdgpu_xcp_release_sched(struct amdgpu_device *adev, struct amdgpu_ctx_entity *entity); -void amdgpu_xcp_cfg_sysfs_init(struct amdgpu_device *adev); -void amdgpu_xcp_cfg_sysfs_fini(struct amdgpu_device *adev); +void amdgpu_xcp_sysfs_init(struct amdgpu_device *adev); +void amdgpu_xcp_sysfs_fini(struct amdgpu_device *adev); #define amdgpu_xcp_select_scheds(adev, e, c, d, x, y) \ ((adev)->xcp_mgr && (adev)->xcp_mgr->funcs && \ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c index f51ef4cf16e0..d9ad37711c3e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c @@ -294,6 +294,23 @@ static const struct amdgpu_pcs_ras_field xgmi3x16_pcs_ras_fields[] = { SOC15_REG_FIELD(PCS_XGMI3X16_PCS_ERROR_STATUS, RxCMDPktErr)}, }; +int amdgpu_xgmi_get_ext_link(struct amdgpu_device *adev, int link_num) +{ + int link_map_6_4_x[8] = { 0, 3, 1, 2, 7, 6, 4, 5 }; + + switch (amdgpu_ip_version(adev, XGMI_HWIP, 0)) { + case IP_VERSION(6, 4, 0): + case IP_VERSION(6, 4, 1): + if (link_num < ARRAY_SIZE(link_map_6_4_x)) + return link_map_6_4_x[link_num]; + break; + default: + return -EINVAL; + } + + return -EINVAL; +} + static u32 xgmi_v6_4_get_link_status(struct amdgpu_device *adev, int global_link_num) { const u32 smn_xgmi_6_4_pcs_state_hist1[2] = { 0x11a00070, 0x11b00070 }; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.h index 32dabba4062f..f994be985f42 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.h @@ -125,6 +125,7 @@ int amdgpu_xgmi_request_nps_change(struct amdgpu_device *adev, int req_nps_mode); int amdgpu_get_xgmi_link_status(struct amdgpu_device *adev, int global_link_num); +int amdgpu_xgmi_get_ext_link(struct amdgpu_device *adev, int link_num); void amdgpu_xgmi_early_init(struct amdgpu_device *adev); uint32_t amdgpu_xgmi_get_max_bandwidth(struct amdgpu_device *adev); diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0_cleaner_shader.h b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0_cleaner_shader.h index 5255378af53c..f67569ccf9f6 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0_cleaner_shader.h +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0_cleaner_shader.h @@ -43,9 +43,9 @@ static const u32 gfx_10_1_10_cleaner_shader_hex[] = { 0xd70f6a01, 0x000202ff, 0x00000400, 0x80828102, 0xbf84fff7, 0xbefc03ff, - 0x00000068, 0xbe803080, - 0xbe813080, 0xbe823080, - 0xbe833080, 0x80fc847c, + 0x00000068, 0xbe803000, + 0xbe813000, 0xbe823000, + 0xbe833000, 0x80fc847c, 0xbf84fffa, 0xbeea0480, 0xbeec0480, 0xbeee0480, 0xbef00480, 0xbef20480, diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v10_1_10_cleaner_shader.asm b/drivers/gpu/drm/amd/amdgpu/gfx_v10_1_10_cleaner_shader.asm index 9ba3359253c9..54f7ed9e2801 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v10_1_10_cleaner_shader.asm +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v10_1_10_cleaner_shader.asm @@ -40,7 +40,6 @@ shader main type(CS) wave_size(32) // Note: original source code from SQ team - // // Create 32 waves in a threadgroup (CS waves) // Each allocates 64 VGPRs @@ -71,8 +70,8 @@ label_0005: s_sub_u32 s2, s2, 8 s_cbranch_scc0 label_0005 // - s_mov_b32 s2, 0x80000000 // Bit31 is first_wave - s_and_b32 s2, s2, s0 // sgpr0 has tg_size (first_wave) term as in ucode only COMPUTE_PGM_RSRC2.tg_size_en is set + s_mov_b32 s2, 0x80000000 // Bit31 is first_wave + s_and_b32 s2, s2, s1 // sgpr0 has tg_size (first_wave) term as in ucode only COMPUTE_PGM_RSRC2.tg_size_en is set s_cbranch_scc0 label_0023 // Clean LDS if its first wave of ThreadGroup/WorkGroup // CLEAR LDS // @@ -99,10 +98,10 @@ label_001F: label_0023: s_mov_b32 m0, 0x00000068 // Loop 108/4=27 times (loop unrolled for performance) label_sgpr_loop: - s_movreld_b32 s0, 0 - s_movreld_b32 s1, 0 - s_movreld_b32 s2, 0 - s_movreld_b32 s3, 0 + s_movreld_b32 s0, s0 + s_movreld_b32 s1, s0 + s_movreld_b32 s2, s0 + s_movreld_b32 s3, s0 s_sub_u32 m0, m0, 4 s_cbranch_scc0 label_sgpr_loop diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c index f09d96bfee16..1234c8d64e20 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c @@ -36,7 +36,7 @@ #include "gc/gc_12_0_0_offset.h" #include "gc/gc_12_0_0_sh_mask.h" #include "soc24_enum.h" -#include "ivsrcid/gfx/irqsrcs_gfx_11_0_0.h" +#include "ivsrcid/gfx/irqsrcs_gfx_12_0_0.h" #include "soc15.h" #include "clearstate_gfx12.h" @@ -1453,28 +1453,28 @@ static int gfx_v12_0_sw_init(struct amdgpu_ip_block *ip_block) /* EOP Event */ r = amdgpu_irq_add_id(adev, SOC21_IH_CLIENTID_GRBM_CP, - GFX_11_0_0__SRCID__CP_EOP_INTERRUPT, + GFX_12_0_0__SRCID__CP_EOP_INTERRUPT, &adev->gfx.eop_irq); if (r) return r; /* Bad opcode Event */ r = amdgpu_irq_add_id(adev, SOC21_IH_CLIENTID_GRBM_CP, - GFX_11_0_0__SRCID__CP_BAD_OPCODE_ERROR, + GFX_12_0_0__SRCID__CP_BAD_OPCODE_ERROR, &adev->gfx.bad_op_irq); if (r) return r; /* Privileged reg */ r = amdgpu_irq_add_id(adev, SOC21_IH_CLIENTID_GRBM_CP, - GFX_11_0_0__SRCID__CP_PRIV_REG_FAULT, + GFX_12_0_0__SRCID__CP_PRIV_REG_FAULT, &adev->gfx.priv_reg_irq); if (r) return r; /* Privileged inst */ r = amdgpu_irq_add_id(adev, SOC21_IH_CLIENTID_GRBM_CP, - GFX_11_0_0__SRCID__CP_PRIV_INSTR_FAULT, + GFX_12_0_0__SRCID__CP_PRIV_INSTR_FAULT, &adev->gfx.priv_inst_irq); if (r) return r; diff --git a/drivers/gpu/drm/amd/amdgpu/isp_v4_1_1.c b/drivers/gpu/drm/amd/amdgpu/isp_v4_1_1.c index 69dd92f6e86d..574880d67009 100644 --- a/drivers/gpu/drm/amd/amdgpu/isp_v4_1_1.c +++ b/drivers/gpu/drm/amd/amdgpu/isp_v4_1_1.c @@ -25,6 +25,7 @@ * */ +#include <linux/gpio/machine.h> #include "amdgpu.h" #include "isp_v4_1_1.h" @@ -39,15 +40,45 @@ static const unsigned int isp_4_1_1_int_srcid[MAX_ISP411_INT_SRC] = { ISP_4_1__SRCID__ISP_RINGBUFFER_WPT16 }; +static struct gpiod_lookup_table isp_gpio_table = { + .dev_id = "amd_isp_capture", + .table = { + GPIO_LOOKUP("AMDI0030:00", 85, "enable_isp", GPIO_ACTIVE_HIGH), + { } + }, +}; + +static struct gpiod_lookup_table isp_sensor_gpio_table = { + .dev_id = "i2c-ov05c10", + .table = { + GPIO_LOOKUP("amdisp-pinctrl", 0, "enable", GPIO_ACTIVE_HIGH), + { } + }, +}; + static int isp_v4_1_1_hw_init(struct amdgpu_isp *isp) { struct amdgpu_device *adev = isp->adev; int idx, int_idx, num_res, r; + u8 isp_dev_hid[ACPI_ID_LEN]; u64 isp_base; if (adev->rmmio_size == 0 || adev->rmmio_size < 0x5289) return -EINVAL; + r = amdgpu_acpi_get_isp4_dev_hid(&isp_dev_hid); + if (r) { + drm_dbg(&adev->ddev, "Invalid isp platform detected (%d)", r); + /* allow GPU init to progress */ + return 0; + } + + /* add GPIO resources required for OMNI5C10 sensor */ + if (!strcmp("OMNI5C10", isp_dev_hid)) { + gpiod_add_lookup_table(&isp_gpio_table); + gpiod_add_lookup_table(&isp_sensor_gpio_table); + } + isp_base = adev->rmmio_base; isp->isp_cell = kcalloc(3, sizeof(struct mfd_cell), GFP_KERNEL); diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c index a8ccae361ec7..79e342d5ab28 100644 --- a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c +++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c @@ -149,6 +149,18 @@ static int jpeg_v4_0_3_sw_init(struct amdgpu_ip_block *ip_block) return r; } + /* JPEG DJPEG POISON EVENT */ + r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_VCN, + VCN_4_0__SRCID_DJPEG0_POISON, &adev->jpeg.inst->ras_poison_irq); + if (r) + return r; + + /* JPEG EJPEG POISON EVENT */ + r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_VCN, + VCN_4_0__SRCID_EJPEG0_POISON, &adev->jpeg.inst->ras_poison_irq); + if (r) + return r; + r = amdgpu_jpeg_sw_init(adev); if (r) return r; @@ -434,6 +446,9 @@ static int jpeg_v4_0_3_hw_fini(struct amdgpu_ip_block *ip_block) ret = jpeg_v4_0_3_set_powergating_state(ip_block, AMD_PG_STATE_GATE); } + if (amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__JPEG)) + amdgpu_irq_put(adev, &adev->jpeg.inst->ras_poison_irq, 0); + return ret; } @@ -1041,6 +1056,14 @@ static int jpeg_v4_0_3_set_interrupt_state(struct amdgpu_device *adev, return 0; } +static int jpeg_v4_0_3_set_ras_interrupt_state(struct amdgpu_device *adev, + struct amdgpu_irq_src *source, + unsigned int type, + enum amdgpu_interrupt_state state) +{ + return 0; +} + static int jpeg_v4_0_3_process_interrupt(struct amdgpu_device *adev, struct amdgpu_irq_src *source, struct amdgpu_iv_entry *entry) @@ -1200,6 +1223,11 @@ static const struct amdgpu_irq_src_funcs jpeg_v4_0_3_irq_funcs = { .process = jpeg_v4_0_3_process_interrupt, }; +static const struct amdgpu_irq_src_funcs jpeg_v4_0_3_ras_irq_funcs = { + .set = jpeg_v4_0_3_set_ras_interrupt_state, + .process = amdgpu_jpeg_process_poison_irq, +}; + static void jpeg_v4_0_3_set_irq_funcs(struct amdgpu_device *adev) { int i; @@ -1208,6 +1236,9 @@ static void jpeg_v4_0_3_set_irq_funcs(struct amdgpu_device *adev) adev->jpeg.inst->irq.num_types += adev->jpeg.num_jpeg_rings; } adev->jpeg.inst->irq.funcs = &jpeg_v4_0_3_irq_funcs; + + adev->jpeg.inst->ras_poison_irq.num_types = 1; + adev->jpeg.inst->ras_poison_irq.funcs = &jpeg_v4_0_3_ras_irq_funcs; } const struct amdgpu_ip_block_version jpeg_v4_0_3_ip_block = { @@ -1304,9 +1335,47 @@ static void jpeg_v4_0_3_reset_ras_error_count(struct amdgpu_device *adev) jpeg_v4_0_3_inst_reset_ras_error_count(adev, i); } +static uint32_t jpeg_v4_0_3_query_poison_by_instance(struct amdgpu_device *adev, + uint32_t instance, uint32_t sub_block) +{ + uint32_t poison_stat = 0, reg_value = 0; + + switch (sub_block) { + case AMDGPU_JPEG_V4_0_3_JPEG0: + reg_value = RREG32_SOC15(JPEG, instance, regUVD_RAS_JPEG0_STATUS); + poison_stat = REG_GET_FIELD(reg_value, UVD_RAS_JPEG0_STATUS, POISONED_PF); + break; + case AMDGPU_JPEG_V4_0_3_JPEG1: + reg_value = RREG32_SOC15(JPEG, instance, regUVD_RAS_JPEG1_STATUS); + poison_stat = REG_GET_FIELD(reg_value, UVD_RAS_JPEG1_STATUS, POISONED_PF); + break; + default: + break; + } + + if (poison_stat) + dev_info(adev->dev, "Poison detected in JPEG%d sub_block%d\n", + instance, sub_block); + + return poison_stat; +} + +static bool jpeg_v4_0_3_query_ras_poison_status(struct amdgpu_device *adev) +{ + uint32_t inst = 0, sub = 0, poison_stat = 0; + + for (inst = 0; inst < adev->jpeg.num_jpeg_inst; inst++) + for (sub = 0; sub < AMDGPU_JPEG_V4_0_3_MAX_SUB_BLOCK; sub++) + poison_stat += + jpeg_v4_0_3_query_poison_by_instance(adev, inst, sub); + + return !!poison_stat; +} + static const struct amdgpu_ras_block_hw_ops jpeg_v4_0_3_ras_hw_ops = { .query_ras_error_count = jpeg_v4_0_3_query_ras_error_count, .reset_ras_error_count = jpeg_v4_0_3_reset_ras_error_count, + .query_poison_status = jpeg_v4_0_3_query_ras_poison_status, }; static int jpeg_v4_0_3_aca_bank_parser(struct aca_handle *handle, struct aca_bank *bank, @@ -1383,6 +1452,13 @@ static int jpeg_v4_0_3_ras_late_init(struct amdgpu_device *adev, struct ras_comm if (r) return r; + if (amdgpu_ras_is_supported(adev, ras_block->block) && + adev->jpeg.inst->ras_poison_irq.funcs) { + r = amdgpu_irq_get(adev, &adev->jpeg.inst->ras_poison_irq, 0); + if (r) + goto late_fini; + } + r = amdgpu_ras_bind_aca(adev, AMDGPU_RAS_BLOCK__JPEG, &jpeg_v4_0_3_aca_info, NULL); if (r) diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.h b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.h index a90bf370a002..2e110d04af84 100644 --- a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.h +++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.h @@ -46,6 +46,13 @@ #define JRBC_DEC_EXTERNAL_REG_WRITE_ADDR 0x18000 +enum amdgpu_jpeg_v4_0_3_sub_block { + AMDGPU_JPEG_V4_0_3_JPEG0 = 0, + AMDGPU_JPEG_V4_0_3_JPEG1, + + AMDGPU_JPEG_V4_0_3_MAX_SUB_BLOCK, +}; + extern const struct amdgpu_ip_block_version jpeg_v4_0_3_ip_block; void jpeg_v4_0_3_dec_ring_emit_ib(struct amdgpu_ring *ring, diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_1.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_1.c index cb94bd71300f..3b6f65a25646 100644 --- a/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_1.c +++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_1.c @@ -39,6 +39,7 @@ static void jpeg_v5_0_1_set_dec_ring_funcs(struct amdgpu_device *adev); static void jpeg_v5_0_1_set_irq_funcs(struct amdgpu_device *adev); static int jpeg_v5_0_1_set_powergating_state(struct amdgpu_ip_block *ip_block, enum amd_powergating_state state); +static void jpeg_v5_0_1_set_ras_funcs(struct amdgpu_device *adev); static void jpeg_v5_0_1_dec_ring_set_wptr(struct amdgpu_ring *ring); static int amdgpu_ih_srcid_jpeg[] = { @@ -120,6 +121,7 @@ static int jpeg_v5_0_1_early_init(struct amdgpu_ip_block *ip_block) adev->jpeg.num_jpeg_rings = AMDGPU_MAX_JPEG_RINGS; jpeg_v5_0_1_set_dec_ring_funcs(adev); jpeg_v5_0_1_set_irq_funcs(adev); + jpeg_v5_0_1_set_ras_funcs(adev); return 0; } @@ -144,6 +146,17 @@ static int jpeg_v5_0_1_sw_init(struct amdgpu_ip_block *ip_block) if (r) return r; } + /* JPEG DJPEG POISON EVENT */ + r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_VCN, + VCN_5_0__SRCID_DJPEG0_POISON, &adev->jpeg.inst->ras_poison_irq); + if (r) + return r; + + /* JPEG EJPEG POISON EVENT */ + r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_VCN, + VCN_5_0__SRCID_EJPEG0_POISON, &adev->jpeg.inst->ras_poison_irq); + if (r) + return r; r = amdgpu_jpeg_sw_init(adev); if (r) @@ -296,6 +309,9 @@ static int jpeg_v5_0_1_hw_fini(struct amdgpu_ip_block *ip_block) ret = jpeg_v5_0_1_set_powergating_state(ip_block, AMD_PG_STATE_GATE); } + if (amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__JPEG)) + amdgpu_irq_put(adev, &adev->jpeg.inst->ras_poison_irq, 0); + return ret; } @@ -723,6 +739,16 @@ static int jpeg_v5_0_1_set_interrupt_state(struct amdgpu_device *adev, return 0; } +static int jpeg_v5_0_1_set_ras_interrupt_state(struct amdgpu_device *adev, + struct amdgpu_irq_src *source, + unsigned int type, + enum amdgpu_interrupt_state state) +{ + return 0; +} + + + static int jpeg_v5_0_1_process_interrupt(struct amdgpu_device *adev, struct amdgpu_irq_src *source, struct amdgpu_iv_entry *entry) @@ -892,6 +918,11 @@ static const struct amdgpu_irq_src_funcs jpeg_v5_0_1_irq_funcs = { .process = jpeg_v5_0_1_process_interrupt, }; +static const struct amdgpu_irq_src_funcs jpeg_v5_0_1_ras_irq_funcs = { + .set = jpeg_v5_0_1_set_ras_interrupt_state, + .process = amdgpu_jpeg_process_poison_irq, +}; + static void jpeg_v5_0_1_set_irq_funcs(struct amdgpu_device *adev) { int i; @@ -900,6 +931,10 @@ static void jpeg_v5_0_1_set_irq_funcs(struct amdgpu_device *adev) adev->jpeg.inst->irq.num_types += adev->jpeg.num_jpeg_rings; adev->jpeg.inst->irq.funcs = &jpeg_v5_0_1_irq_funcs; + + adev->jpeg.inst->ras_poison_irq.num_types = 1; + adev->jpeg.inst->ras_poison_irq.funcs = &jpeg_v5_0_1_ras_irq_funcs; + } const struct amdgpu_ip_block_version jpeg_v5_0_1_ip_block = { @@ -909,3 +944,150 @@ const struct amdgpu_ip_block_version jpeg_v5_0_1_ip_block = { .rev = 1, .funcs = &jpeg_v5_0_1_ip_funcs, }; + +static uint32_t jpeg_v5_0_1_query_poison_by_instance(struct amdgpu_device *adev, + uint32_t instance, uint32_t sub_block) +{ + uint32_t poison_stat = 0, reg_value = 0; + + switch (sub_block) { + case AMDGPU_JPEG_V5_0_1_JPEG0: + reg_value = RREG32_SOC15(JPEG, instance, regUVD_RAS_JPEG0_STATUS); + poison_stat = REG_GET_FIELD(reg_value, UVD_RAS_JPEG0_STATUS, POISONED_PF); + break; + case AMDGPU_JPEG_V5_0_1_JPEG1: + reg_value = RREG32_SOC15(JPEG, instance, regUVD_RAS_JPEG1_STATUS); + poison_stat = REG_GET_FIELD(reg_value, UVD_RAS_JPEG1_STATUS, POISONED_PF); + break; + default: + break; + } + + if (poison_stat) + dev_info(adev->dev, "Poison detected in JPEG%d sub_block%d\n", + instance, sub_block); + + return poison_stat; +} + +static bool jpeg_v5_0_1_query_ras_poison_status(struct amdgpu_device *adev) +{ + uint32_t inst = 0, sub = 0, poison_stat = 0; + + for (inst = 0; inst < adev->jpeg.num_jpeg_inst; inst++) + for (sub = 0; sub < AMDGPU_JPEG_V5_0_1_MAX_SUB_BLOCK; sub++) + poison_stat += + jpeg_v5_0_1_query_poison_by_instance(adev, inst, sub); + + return !!poison_stat; +} + +static const struct amdgpu_ras_block_hw_ops jpeg_v5_0_1_ras_hw_ops = { + .query_poison_status = jpeg_v5_0_1_query_ras_poison_status, +}; + +static int jpeg_v5_0_1_aca_bank_parser(struct aca_handle *handle, struct aca_bank *bank, + enum aca_smu_type type, void *data) +{ + struct aca_bank_info info; + u64 misc0; + int ret; + + ret = aca_bank_info_decode(bank, &info); + if (ret) + return ret; + + misc0 = bank->regs[ACA_REG_IDX_MISC0]; + switch (type) { + case ACA_SMU_TYPE_UE: + bank->aca_err_type = ACA_ERROR_TYPE_UE; + ret = aca_error_cache_log_bank_error(handle, &info, ACA_ERROR_TYPE_UE, + 1ULL); + break; + case ACA_SMU_TYPE_CE: + bank->aca_err_type = ACA_ERROR_TYPE_CE; + ret = aca_error_cache_log_bank_error(handle, &info, bank->aca_err_type, + ACA_REG__MISC0__ERRCNT(misc0)); + break; + default: + return -EINVAL; + } + + return ret; +} + +/* reference to smu driver if header file */ +static int jpeg_v5_0_1_err_codes[] = { + 16, 17, 18, 19, 20, 21, 22, 23, /* JPEG[0-7][S|D] */ + 24, 25, 26, 27, 28, 29, 30, 31 +}; + +static bool jpeg_v5_0_1_aca_bank_is_valid(struct aca_handle *handle, struct aca_bank *bank, + enum aca_smu_type type, void *data) +{ + u32 instlo; + + instlo = ACA_REG__IPID__INSTANCEIDLO(bank->regs[ACA_REG_IDX_IPID]); + instlo &= GENMASK(31, 1); + + if (instlo != mmSMNAID_AID0_MCA_SMU) + return false; + + if (aca_bank_check_error_codes(handle->adev, bank, + jpeg_v5_0_1_err_codes, + ARRAY_SIZE(jpeg_v5_0_1_err_codes))) + return false; + + return true; +} + +static const struct aca_bank_ops jpeg_v5_0_1_aca_bank_ops = { + .aca_bank_parser = jpeg_v5_0_1_aca_bank_parser, + .aca_bank_is_valid = jpeg_v5_0_1_aca_bank_is_valid, +}; + +static const struct aca_info jpeg_v5_0_1_aca_info = { + .hwip = ACA_HWIP_TYPE_SMU, + .mask = ACA_ERROR_UE_MASK, + .bank_ops = &jpeg_v5_0_1_aca_bank_ops, +}; + +static int jpeg_v5_0_1_ras_late_init(struct amdgpu_device *adev, struct ras_common_if *ras_block) +{ + int r; + + r = amdgpu_ras_block_late_init(adev, ras_block); + if (r) + return r; + + if (amdgpu_ras_is_supported(adev, ras_block->block) && + adev->jpeg.inst->ras_poison_irq.funcs) { + r = amdgpu_irq_get(adev, &adev->jpeg.inst->ras_poison_irq, 0); + if (r) + goto late_fini; + } + + r = amdgpu_ras_bind_aca(adev, AMDGPU_RAS_BLOCK__JPEG, + &jpeg_v5_0_1_aca_info, NULL); + if (r) + goto late_fini; + + return 0; + +late_fini: + amdgpu_ras_block_late_fini(adev, ras_block); + + return r; +} + +static struct amdgpu_jpeg_ras jpeg_v5_0_1_ras = { + .ras_block = { + .hw_ops = &jpeg_v5_0_1_ras_hw_ops, + .ras_late_init = jpeg_v5_0_1_ras_late_init, + }, +}; + +static void jpeg_v5_0_1_set_ras_funcs(struct amdgpu_device *adev) +{ + adev->jpeg.ras = &jpeg_v5_0_1_ras; +} diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_1.h b/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_1.h index efdab57324e4..a7e58d5fb246 100644 --- a/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_1.h +++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_1.h @@ -26,6 +26,9 @@ extern const struct amdgpu_ip_block_version jpeg_v5_0_1_ip_block; +#define regUVD_JRBC0_UVD_JRBC_SCRATCH0_INTERNAL_OFFSET 0x4094 +#define regUVD_JRBC_EXTERNAL_MCM_ADDR_INTERNAL_OFFSET 0x1bffe + #define regUVD_JRBC0_UVD_JRBC_RB_WPTR 0x0640 #define regUVD_JRBC0_UVD_JRBC_RB_WPTR_BASE_IDX 1 #define regUVD_JRBC0_UVD_JRBC_STATUS 0x0649 @@ -98,4 +101,11 @@ extern const struct amdgpu_ip_block_version jpeg_v5_0_1_ip_block; #define regVCN_RRMT_CNTL 0x0940 #define regVCN_RRMT_CNTL_BASE_IDX 1 +enum amdgpu_jpeg_v5_0_1_sub_block { + AMDGPU_JPEG_V5_0_1_JPEG0 = 0, + AMDGPU_JPEG_V5_0_1_JPEG1, + + AMDGPU_JPEG_V5_0_1_MAX_SUB_BLOCK, +}; + #endif /* __JPEG_V5_0_1_H__ */ diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c index da5b5d64f137..5a70ae17be04 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c @@ -44,6 +44,7 @@ #include "sdma_v6_0.h" #include "v11_structs.h" #include "mes_userqueue.h" +#include "amdgpu_userq_fence.h" MODULE_FIRMWARE("amdgpu/sdma_6_0_0.bin"); MODULE_FIRMWARE("amdgpu/sdma_6_0_1.bin"); @@ -893,6 +894,9 @@ static int sdma_v6_0_mqd_init(struct amdgpu_device *adev, void *mqd, m->sdmax_rlcx_csa_addr_lo = lower_32_bits(prop->csa_addr); m->sdmax_rlcx_csa_addr_hi = upper_32_bits(prop->csa_addr); + m->sdmax_rlcx_f32_dbg0 = lower_32_bits(prop->fence_address); + m->sdmax_rlcx_f32_dbg1 = upper_32_bits(prop->fence_address); + return 0; } @@ -1315,6 +1319,13 @@ static int sdma_v6_0_sw_init(struct amdgpu_ip_block *ip_block) if (r) return r; + /* SDMA user fence event */ + r = amdgpu_irq_add_id(adev, SOC21_IH_CLIENTID_GFX, + GFX_11_0_0__SRCID__SDMA_FENCE, + &adev->sdma.fence_irq); + if (r) + return r; + for (i = 0; i < adev->sdma.num_instances; i++) { ring = &adev->sdma.instance[i].ring; ring->ring_obj = NULL; @@ -1575,25 +1586,9 @@ static int sdma_v6_0_process_trap_irq(struct amdgpu_device *adev, struct amdgpu_iv_entry *entry) { int instances, queue; - uint32_t mes_queue_id = entry->src_data[0]; DRM_DEBUG("IH: SDMA trap\n"); - if (adev->enable_mes && (mes_queue_id & AMDGPU_FENCE_MES_QUEUE_FLAG)) { - struct amdgpu_mes_queue *queue; - - mes_queue_id &= AMDGPU_FENCE_MES_QUEUE_ID_MASK; - - spin_lock(&adev->mes.queue_id_lock); - queue = idr_find(&adev->mes.queue_id_idr, mes_queue_id); - if (queue) { - DRM_DEBUG("process smda queue id = %d\n", mes_queue_id); - amdgpu_fence_process(queue->ring); - } - spin_unlock(&adev->mes.queue_id_lock); - return 0; - } - queue = entry->ring_id & 0xf; instances = (entry->ring_id & 0xf0) >> 4; if (instances > 1) { @@ -1615,6 +1610,29 @@ static int sdma_v6_0_process_trap_irq(struct amdgpu_device *adev, return 0; } +static int sdma_v6_0_process_fence_irq(struct amdgpu_device *adev, + struct amdgpu_irq_src *source, + struct amdgpu_iv_entry *entry) +{ + u32 doorbell_offset = entry->src_data[0]; + + if (adev->enable_mes && doorbell_offset) { + struct amdgpu_userq_fence_driver *fence_drv = NULL; + struct xarray *xa = &adev->userq_xa; + unsigned long flags; + + doorbell_offset >>= SDMA0_QUEUE0_DOORBELL_OFFSET__OFFSET__SHIFT; + + xa_lock_irqsave(xa, flags); + fence_drv = xa_load(xa, doorbell_offset); + if (fence_drv) + amdgpu_userq_fence_driver_process(fence_drv); + xa_unlock_irqrestore(xa, flags); + } + + return 0; +} + static int sdma_v6_0_process_illegal_inst_irq(struct amdgpu_device *adev, struct amdgpu_irq_src *source, struct amdgpu_iv_entry *entry) @@ -1751,6 +1769,10 @@ static const struct amdgpu_irq_src_funcs sdma_v6_0_trap_irq_funcs = { .process = sdma_v6_0_process_trap_irq, }; +static const struct amdgpu_irq_src_funcs sdma_v6_0_fence_irq_funcs = { + .process = sdma_v6_0_process_fence_irq, +}; + static const struct amdgpu_irq_src_funcs sdma_v6_0_illegal_inst_irq_funcs = { .process = sdma_v6_0_process_illegal_inst_irq, }; @@ -1760,6 +1782,7 @@ static void sdma_v6_0_set_irq_funcs(struct amdgpu_device *adev) adev->sdma.trap_irq.num_types = AMDGPU_SDMA_IRQ_INSTANCE0 + adev->sdma.num_instances; adev->sdma.trap_irq.funcs = &sdma_v6_0_trap_irq_funcs; + adev->sdma.fence_irq.funcs = &sdma_v6_0_fence_irq_funcs; adev->sdma.illegal_inst_irq.funcs = &sdma_v6_0_illegal_inst_irq_funcs; } diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v7_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v7_0.c index befe013b11a7..ad47d0bdf777 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v7_0.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v7_0.c @@ -33,7 +33,7 @@ #include "gc/gc_12_0_0_offset.h" #include "gc/gc_12_0_0_sh_mask.h" #include "hdp/hdp_6_0_0_offset.h" -#include "ivsrcid/gfx/irqsrcs_gfx_11_0_0.h" +#include "ivsrcid/gfx/irqsrcs_gfx_12_0_0.h" #include "soc15_common.h" #include "soc15.h" @@ -43,6 +43,7 @@ #include "sdma_v7_0.h" #include "v12_structs.h" #include "mes_userqueue.h" +#include "amdgpu_userq_fence.h" MODULE_FIRMWARE("amdgpu/sdma_7_0_0.bin"); MODULE_FIRMWARE("amdgpu/sdma_7_0_1.bin"); @@ -910,6 +911,9 @@ static int sdma_v7_0_mqd_init(struct amdgpu_device *adev, void *mqd, m->sdmax_rlcx_csa_addr_lo = lower_32_bits(prop->csa_addr); m->sdmax_rlcx_csa_addr_hi = upper_32_bits(prop->csa_addr); + m->sdmax_rlcx_mcu_dbg0 = lower_32_bits(prop->fence_address); + m->sdmax_rlcx_mcu_dbg1 = upper_32_bits(prop->fence_address); + return 0; } @@ -1296,11 +1300,18 @@ static int sdma_v7_0_sw_init(struct amdgpu_ip_block *ip_block) /* SDMA trap event */ r = amdgpu_irq_add_id(adev, SOC21_IH_CLIENTID_GFX, - GFX_11_0_0__SRCID__SDMA_TRAP, + GFX_12_0_0__SRCID__SDMA_TRAP, &adev->sdma.trap_irq); if (r) return r; + /* SDMA user fence event */ + r = amdgpu_irq_add_id(adev, SOC21_IH_CLIENTID_GFX, + GFX_12_0_0__SRCID__SDMA_FENCE, + &adev->sdma.fence_irq); + if (r) + return r; + for (i = 0; i < adev->sdma.num_instances; i++) { ring = &adev->sdma.instance[i].ring; ring->ring_obj = NULL; @@ -1526,25 +1537,9 @@ static int sdma_v7_0_process_trap_irq(struct amdgpu_device *adev, struct amdgpu_iv_entry *entry) { int instances, queue; - uint32_t mes_queue_id = entry->src_data[0]; DRM_DEBUG("IH: SDMA trap\n"); - if (adev->enable_mes && (mes_queue_id & AMDGPU_FENCE_MES_QUEUE_FLAG)) { - struct amdgpu_mes_queue *queue; - - mes_queue_id &= AMDGPU_FENCE_MES_QUEUE_ID_MASK; - - spin_lock(&adev->mes.queue_id_lock); - queue = idr_find(&adev->mes.queue_id_idr, mes_queue_id); - if (queue) { - DRM_DEBUG("process smda queue id = %d\n", mes_queue_id); - amdgpu_fence_process(queue->ring); - } - spin_unlock(&adev->mes.queue_id_lock); - return 0; - } - queue = entry->ring_id & 0xf; instances = (entry->ring_id & 0xf0) >> 4; if (instances > 1) { @@ -1566,6 +1561,29 @@ static int sdma_v7_0_process_trap_irq(struct amdgpu_device *adev, return 0; } +static int sdma_v7_0_process_fence_irq(struct amdgpu_device *adev, + struct amdgpu_irq_src *source, + struct amdgpu_iv_entry *entry) +{ + u32 doorbell_offset = entry->src_data[0]; + + if (adev->enable_mes && doorbell_offset) { + struct amdgpu_userq_fence_driver *fence_drv = NULL; + struct xarray *xa = &adev->userq_xa; + unsigned long flags; + + doorbell_offset >>= SDMA0_QUEUE0_DOORBELL_OFFSET__OFFSET__SHIFT; + + xa_lock_irqsave(xa, flags); + fence_drv = xa_load(xa, doorbell_offset); + if (fence_drv) + amdgpu_userq_fence_driver_process(fence_drv); + xa_unlock_irqrestore(xa, flags); + } + + return 0; +} + static int sdma_v7_0_process_illegal_inst_irq(struct amdgpu_device *adev, struct amdgpu_irq_src *source, struct amdgpu_iv_entry *entry) @@ -1703,6 +1721,10 @@ static const struct amdgpu_irq_src_funcs sdma_v7_0_trap_irq_funcs = { .process = sdma_v7_0_process_trap_irq, }; +static const struct amdgpu_irq_src_funcs sdma_v7_0_fence_irq_funcs = { + .process = sdma_v7_0_process_fence_irq, +}; + static const struct amdgpu_irq_src_funcs sdma_v7_0_illegal_inst_irq_funcs = { .process = sdma_v7_0_process_illegal_inst_irq, }; @@ -1712,6 +1734,7 @@ static void sdma_v7_0_set_irq_funcs(struct amdgpu_device *adev) adev->sdma.trap_irq.num_types = AMDGPU_SDMA_IRQ_INSTANCE0 + adev->sdma.num_instances; adev->sdma.trap_irq.funcs = &sdma_v7_0_trap_irq_funcs; + adev->sdma.fence_irq.funcs = &sdma_v7_0_fence_irq_funcs; adev->sdma.illegal_inst_irq.funcs = &sdma_v7_0_illegal_inst_irq_funcs; } diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c index 21b57c29bf7d..c74947705d77 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c @@ -1009,6 +1009,11 @@ static int vcn_v1_0_start_spg_mode(struct amdgpu_vcn_inst *vinst) jpeg_v1_0_start(adev, 0); + /* Keeping one read-back to ensure all register writes are done, + * otherwise it may introduce race conditions. + */ + RREG32_SOC15(UVD, 0, mmUVD_STATUS); + return 0; } @@ -1154,6 +1159,11 @@ static int vcn_v1_0_start_dpg_mode(struct amdgpu_vcn_inst *vinst) jpeg_v1_0_start(adev, 1); + /* Keeping one read-back to ensure all register writes are done, + * otherwise it may introduce race conditions. + */ + RREG32_SOC15(UVD, 0, mmUVD_STATUS); + return 0; } @@ -1216,6 +1226,12 @@ static int vcn_v1_0_stop_spg_mode(struct amdgpu_vcn_inst *vinst) vcn_v1_0_enable_clock_gating(vinst); vcn_1_0_enable_static_power_gating(vinst); + + /* Keeping one read-back to ensure all register writes are done, + * otherwise it may introduce race conditions. + */ + RREG32_SOC15(UVD, 0, mmUVD_STATUS); + return 0; } @@ -1250,6 +1266,11 @@ static int vcn_v1_0_stop_dpg_mode(struct amdgpu_vcn_inst *vinst) WREG32_P(SOC15_REG_OFFSET(UVD, 0, mmUVD_POWER_STATUS), 0, ~UVD_POWER_STATUS__UVD_PG_MODE_MASK); + /* Keeping one read-back to ensure all register writes are done, + * otherwise it may introduce race conditions. + */ + RREG32_SOC15(UVD, 0, mmUVD_STATUS); + return 0; } diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c index b8d835c9e17e..148b651be7ca 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c @@ -978,6 +978,12 @@ static int vcn_v2_0_start_dpg_mode(struct amdgpu_vcn_inst *vinst, bool indirect) /* Unstall DPG */ WREG32_P(SOC15_REG_OFFSET(UVD, 0, mmUVD_POWER_STATUS), 0, ~UVD_POWER_STATUS__STALL_DPG_POWER_UP_MASK); + + /* Keeping one read-back to ensure all register writes are done, + * otherwise it may introduce race conditions. + */ + RREG32_SOC15(UVD, 0, mmUVD_STATUS); + return 0; } @@ -1152,6 +1158,11 @@ static int vcn_v2_0_start(struct amdgpu_vcn_inst *vinst) WREG32_SOC15(UVD, 0, mmUVD_RB_SIZE2, ring->ring_size / 4); fw_shared->multi_queue.encode_lowlatency_queue_mode &= ~FW_QUEUE_RING_RESET; + /* Keeping one read-back to ensure all register writes are done, + * otherwise it may introduce race conditions. + */ + RREG32_SOC15(UVD, 0, mmUVD_STATUS); + return 0; } @@ -1183,6 +1194,11 @@ static int vcn_v2_0_stop_dpg_mode(struct amdgpu_vcn_inst *vinst) WREG32_P(SOC15_REG_OFFSET(UVD, 0, mmUVD_POWER_STATUS), 0, ~UVD_POWER_STATUS__UVD_PG_MODE_MASK); + /* Keeping one read-back to ensure all register writes are done, + * otherwise it may introduce race conditions. + */ + RREG32_SOC15(UVD, 0, mmUVD_STATUS); + return 0; } @@ -1248,6 +1264,11 @@ static int vcn_v2_0_stop(struct amdgpu_vcn_inst *vinst) vcn_v2_0_enable_clock_gating(vinst); vcn_v2_0_enable_static_power_gating(vinst); + /* Keeping one read-back to ensure all register writes are done, + * otherwise it may introduce race conditions. + */ + RREG32_SOC15(VCN, 0, mmUVD_STATUS); + power_off: if (adev->pm.dpm_enabled) amdgpu_dpm_enable_vcn(adev, false, 0); diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c index 3eec1b8feaee..58b527a6b795 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c @@ -1158,6 +1158,11 @@ static int vcn_v2_5_start_dpg_mode(struct amdgpu_vcn_inst *vinst, bool indirect) WREG32_P(SOC15_REG_OFFSET(VCN, inst_idx, mmUVD_POWER_STATUS), 0, ~UVD_POWER_STATUS__STALL_DPG_POWER_UP_MASK); + /* Keeping one read-back to ensure all register writes are done, + * otherwise it may introduce race conditions. + */ + RREG32_SOC15(VCN, inst_idx, mmUVD_STATUS); + return 0; } @@ -1343,6 +1348,11 @@ static int vcn_v2_5_start(struct amdgpu_vcn_inst *vinst) WREG32_SOC15(VCN, i, mmUVD_RB_SIZE2, ring->ring_size / 4); fw_shared->multi_queue.encode_lowlatency_queue_mode &= ~FW_QUEUE_RING_RESET; + /* Keeping one read-back to ensure all register writes are done, + * otherwise it may introduce race conditions. + */ + RREG32_SOC15(VCN, i, mmUVD_STATUS); + return 0; } @@ -1569,6 +1579,11 @@ static int vcn_v2_5_stop_dpg_mode(struct amdgpu_vcn_inst *vinst) WREG32_P(SOC15_REG_OFFSET(VCN, inst_idx, mmUVD_POWER_STATUS), 0, ~UVD_POWER_STATUS__UVD_PG_MODE_MASK); + /* Keeping one read-back to ensure all register writes are done, + * otherwise it may introduce race conditions. + */ + RREG32_SOC15(VCN, inst_idx, mmUVD_STATUS); + return 0; } @@ -1635,6 +1650,10 @@ static int vcn_v2_5_stop(struct amdgpu_vcn_inst *vinst) UVD_POWER_STATUS__UVD_POWER_STATUS_MASK, ~UVD_POWER_STATUS__UVD_POWER_STATUS_MASK); + /* Keeping one read-back to ensure all register writes are done, + * otherwise it may introduce race conditions. + */ + RREG32_SOC15(VCN, i, mmUVD_STATUS); done: if (adev->pm.dpm_enabled) amdgpu_dpm_enable_vcn(adev, false, i); diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c index 0b19f0ab4480..9fb0d5380589 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c @@ -1173,6 +1173,11 @@ static int vcn_v3_0_start_dpg_mode(struct amdgpu_vcn_inst *vinst, bool indirect) WREG32_P(SOC15_REG_OFFSET(VCN, inst_idx, mmUVD_POWER_STATUS), 0, ~UVD_POWER_STATUS__STALL_DPG_POWER_UP_MASK); + /* Keeping one read-back to ensure all register writes are done, + * otherwise it may introduce race conditions. + */ + RREG32_SOC15(VCN, inst_idx, mmUVD_STATUS); + return 0; } @@ -1360,6 +1365,11 @@ static int vcn_v3_0_start(struct amdgpu_vcn_inst *vinst) fw_shared->multi_queue.encode_lowlatency_queue_mode &= cpu_to_le32(~FW_QUEUE_RING_RESET); } + /* Keeping one read-back to ensure all register writes are done, + * otherwise it may introduce race conditions. + */ + RREG32_SOC15(VCN, i, mmUVD_STATUS); + return 0; } @@ -1602,6 +1612,11 @@ static int vcn_v3_0_stop_dpg_mode(struct amdgpu_vcn_inst *vinst) WREG32_P(SOC15_REG_OFFSET(VCN, inst_idx, mmUVD_POWER_STATUS), 0, ~UVD_POWER_STATUS__UVD_PG_MODE_MASK); + /* Keeping one read-back to ensure all register writes are done, + * otherwise it may introduce race conditions. + */ + RREG32_SOC15(VCN, inst_idx, mmUVD_STATUS); + return 0; } @@ -1674,6 +1689,11 @@ static int vcn_v3_0_stop(struct amdgpu_vcn_inst *vinst) /* enable VCN power gating */ vcn_v3_0_enable_static_power_gating(vinst); + /* Keeping one read-back to ensure all register writes are done, + * otherwise it may introduce race conditions. + */ + RREG32_SOC15(VCN, i, mmUVD_STATUS); + done: if (adev->pm.dpm_enabled) amdgpu_dpm_enable_vcn(adev, false, i); diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c index 8fff470bce87..b5071f77f78d 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c @@ -1122,6 +1122,11 @@ static int vcn_v4_0_start_dpg_mode(struct amdgpu_vcn_inst *vinst, bool indirect) ring->doorbell_index << VCN_RB1_DB_CTRL__OFFSET__SHIFT | VCN_RB1_DB_CTRL__EN_MASK); + /* Keeping one read-back to ensure all register writes are done, + * otherwise it may introduce race conditions. + */ + RREG32_SOC15(VCN, inst_idx, regUVD_STATUS); + return 0; } @@ -1303,6 +1308,11 @@ static int vcn_v4_0_start(struct amdgpu_vcn_inst *vinst) WREG32_SOC15(VCN, i, regVCN_RB_ENABLE, tmp); fw_shared->sq.queue_mode &= ~(FW_QUEUE_RING_RESET | FW_QUEUE_DPG_HOLD_OFF); + /* Keeping one read-back to ensure all register writes are done, + * otherwise it may introduce race conditions. + */ + RREG32_SOC15(VCN, i, regUVD_STATUS); + return 0; } @@ -1583,6 +1593,11 @@ static void vcn_v4_0_stop_dpg_mode(struct amdgpu_vcn_inst *vinst) /* disable dynamic power gating mode */ WREG32_P(SOC15_REG_OFFSET(VCN, inst_idx, regUVD_POWER_STATUS), 0, ~UVD_POWER_STATUS__UVD_PG_MODE_MASK); + + /* Keeping one read-back to ensure all register writes are done, + * otherwise it may introduce race conditions. + */ + RREG32_SOC15(VCN, inst_idx, regUVD_STATUS); } /** @@ -1666,6 +1681,11 @@ static int vcn_v4_0_stop(struct amdgpu_vcn_inst *vinst) /* enable VCN power gating */ vcn_v4_0_enable_static_power_gating(vinst); + /* Keeping one read-back to ensure all register writes are done, + * otherwise it may introduce race conditions. + */ + RREG32_SOC15(VCN, i, regUVD_STATUS); + done: if (adev->pm.dpm_enabled) amdgpu_dpm_enable_vcn(adev, false, i); diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c index 712e1fba33ce..5a33140f5723 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c @@ -169,6 +169,10 @@ static int vcn_v4_0_3_sw_init(struct amdgpu_ip_block *ip_block) if (r) return r; + /* VCN POISON TRAP */ + r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_VCN, + VCN_4_0__SRCID_UVD_POISON, &adev->vcn.inst->ras_poison_irq); + for (i = 0; i < adev->vcn.num_vcn_inst; i++) { r = amdgpu_vcn_sw_init(adev, i); @@ -387,6 +391,9 @@ static int vcn_v4_0_3_hw_fini(struct amdgpu_ip_block *ip_block) vinst->set_pg_state(vinst, AMD_PG_STATE_GATE); } + if (amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__VCN)) + amdgpu_irq_put(adev, &adev->vcn.inst->ras_poison_irq, 0); + return 0; } @@ -970,6 +977,11 @@ static int vcn_v4_0_3_start_dpg_mode(struct amdgpu_vcn_inst *vinst, /*resetting done, fw can check RB ring */ fw_shared->sq.queue_mode &= cpu_to_le32(~FW_QUEUE_RING_RESET); + /* Keeping one read-back to ensure all register writes are done, + * otherwise it may introduce race conditions. + */ + RREG32_SOC15(VCN, vcn_inst, regUVD_STATUS); + return 0; } @@ -1363,6 +1375,12 @@ static int vcn_v4_0_3_stop_dpg_mode(struct amdgpu_vcn_inst *vinst) /* disable dynamic power gating mode */ WREG32_P(SOC15_REG_OFFSET(VCN, vcn_inst, regUVD_POWER_STATUS), 0, ~UVD_POWER_STATUS__UVD_PG_MODE_MASK); + + /* Keeping one read-back to ensure all register writes are done, + * otherwise it may introduce race conditions. + */ + RREG32_SOC15(VCN, vcn_inst, regUVD_STATUS); + return 0; } @@ -1446,6 +1464,11 @@ static int vcn_v4_0_3_stop(struct amdgpu_vcn_inst *vinst) /* apply HW clock gating */ vcn_v4_0_3_enable_clock_gating(vinst); + /* Keeping one read-back to ensure all register writes are done, + * otherwise it may introduce race conditions. + */ + RREG32_SOC15(VCN, vcn_inst, regUVD_STATUS); + Done: return 0; } @@ -1814,11 +1837,24 @@ static int vcn_v4_0_3_process_interrupt(struct amdgpu_device *adev, return 0; } +static int vcn_v4_0_3_set_ras_interrupt_state(struct amdgpu_device *adev, + struct amdgpu_irq_src *source, + unsigned int type, + enum amdgpu_interrupt_state state) +{ + return 0; +} + static const struct amdgpu_irq_src_funcs vcn_v4_0_3_irq_funcs = { .set = vcn_v4_0_3_set_interrupt_state, .process = vcn_v4_0_3_process_interrupt, }; +static const struct amdgpu_irq_src_funcs vcn_v4_0_3_ras_irq_funcs = { + .set = vcn_v4_0_3_set_ras_interrupt_state, + .process = amdgpu_vcn_process_poison_irq, +}; + /** * vcn_v4_0_3_set_irq_funcs - set VCN block interrupt irq functions * @@ -1834,6 +1870,9 @@ static void vcn_v4_0_3_set_irq_funcs(struct amdgpu_device *adev) adev->vcn.inst->irq.num_types++; } adev->vcn.inst->irq.funcs = &vcn_v4_0_3_irq_funcs; + + adev->vcn.inst->ras_poison_irq.num_types = 1; + adev->vcn.inst->ras_poison_irq.funcs = &vcn_v4_0_3_ras_irq_funcs; } static void vcn_v4_0_3_print_ip_state(struct amdgpu_ip_block *ip_block, struct drm_printer *p) @@ -1981,9 +2020,44 @@ static void vcn_v4_0_3_reset_ras_error_count(struct amdgpu_device *adev) vcn_v4_0_3_inst_reset_ras_error_count(adev, i); } +static uint32_t vcn_v4_0_3_query_poison_by_instance(struct amdgpu_device *adev, + uint32_t instance, uint32_t sub_block) +{ + uint32_t poison_stat = 0, reg_value = 0; + + switch (sub_block) { + case AMDGPU_VCN_V4_0_3_VCPU_VCODEC: + reg_value = RREG32_SOC15(VCN, instance, regUVD_RAS_VCPU_VCODEC_STATUS); + poison_stat = REG_GET_FIELD(reg_value, UVD_RAS_VCPU_VCODEC_STATUS, POISONED_PF); + break; + default: + break; + } + + if (poison_stat) + dev_info(adev->dev, "Poison detected in VCN%d, sub_block%d\n", + instance, sub_block); + + return poison_stat; +} + +static bool vcn_v4_0_3_query_poison_status(struct amdgpu_device *adev) +{ + uint32_t inst, sub; + uint32_t poison_stat = 0; + + for (inst = 0; inst < adev->vcn.num_vcn_inst; inst++) + for (sub = 0; sub < AMDGPU_VCN_V4_0_3_MAX_SUB_BLOCK; sub++) + poison_stat += + vcn_v4_0_3_query_poison_by_instance(adev, inst, sub); + + return !!poison_stat; +} + static const struct amdgpu_ras_block_hw_ops vcn_v4_0_3_ras_hw_ops = { .query_ras_error_count = vcn_v4_0_3_query_ras_error_count, .reset_ras_error_count = vcn_v4_0_3_reset_ras_error_count, + .query_poison_status = vcn_v4_0_3_query_poison_status, }; static int vcn_v4_0_3_aca_bank_parser(struct aca_handle *handle, struct aca_bank *bank, @@ -2059,6 +2133,13 @@ static int vcn_v4_0_3_ras_late_init(struct amdgpu_device *adev, struct ras_commo if (r) return r; + if (amdgpu_ras_is_supported(adev, ras_block->block) && + adev->vcn.inst->ras_poison_irq.funcs) { + r = amdgpu_irq_get(adev, &adev->vcn.inst->ras_poison_irq, 0); + if (r) + goto late_fini; + } + r = amdgpu_ras_bind_aca(adev, AMDGPU_RAS_BLOCK__VCN, &vcn_v4_0_3_aca_info, NULL); if (r) diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.h b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.h index 03572a1d0c9c..aeab89853a92 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.h +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.h @@ -24,6 +24,12 @@ #ifndef __VCN_V4_0_3_H__ #define __VCN_V4_0_3_H__ +enum amdgpu_vcn_v4_0_3_sub_block { + AMDGPU_VCN_V4_0_3_VCPU_VCODEC = 0, + + AMDGPU_VCN_V4_0_3_MAX_SUB_BLOCK, +}; + extern const struct amdgpu_ip_block_version vcn_v4_0_3_ip_block; void vcn_v4_0_3_enc_ring_emit_reg_wait(struct amdgpu_ring *ring, uint32_t reg, diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c index a09f9a2dd471..16ade84facc7 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c @@ -1254,6 +1254,11 @@ static void vcn_v4_0_5_stop_dpg_mode(struct amdgpu_vcn_inst *vinst) /* disable dynamic power gating mode */ WREG32_P(SOC15_REG_OFFSET(VCN, inst_idx, regUVD_POWER_STATUS), 0, ~UVD_POWER_STATUS__UVD_PG_MODE_MASK); + + /* Keeping one read-back to ensure all register writes are done, + * otherwise it may introduce race conditions. + */ + RREG32_SOC15(VCN, inst_idx, regUVD_STATUS); } /** @@ -1337,6 +1342,11 @@ static int vcn_v4_0_5_stop(struct amdgpu_vcn_inst *vinst) /* enable VCN power gating */ vcn_v4_0_5_enable_static_power_gating(vinst); + /* Keeping one read-back to ensure all register writes are done, + * otherwise it may introduce race conditions. + */ + RREG32_SOC15(VCN, i, regUVD_STATUS); + done: if (adev->pm.dpm_enabled) amdgpu_dpm_enable_vcn(adev, false, i); diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c index 27dcc6f37a73..f8e3f0b882da 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c @@ -794,6 +794,11 @@ static int vcn_v5_0_0_start_dpg_mode(struct amdgpu_vcn_inst *vinst, ring->doorbell_index << VCN_RB1_DB_CTRL__OFFSET__SHIFT | VCN_RB1_DB_CTRL__EN_MASK); + /* Keeping one read-back to ensure all register writes are done, + * otherwise it may introduce race conditions. + */ + RREG32_SOC15(VCN, inst_idx, regUVD_STATUS); + return 0; } @@ -946,6 +951,11 @@ static int vcn_v5_0_0_start(struct amdgpu_vcn_inst *vinst) WREG32_SOC15(VCN, i, regVCN_RB_ENABLE, tmp); fw_shared->sq.queue_mode &= ~(FW_QUEUE_RING_RESET | FW_QUEUE_DPG_HOLD_OFF); + /* Keeping one read-back to ensure all register writes are done, + * otherwise it may introduce race conditions. + */ + RREG32_SOC15(VCN, i, regUVD_STATUS); + return 0; } @@ -977,6 +987,11 @@ static void vcn_v5_0_0_stop_dpg_mode(struct amdgpu_vcn_inst *vinst) WREG32_P(SOC15_REG_OFFSET(VCN, inst_idx, regUVD_POWER_STATUS), 0, ~UVD_POWER_STATUS__UVD_PG_MODE_MASK); + /* Keeping one read-back to ensure all register writes are done, + * otherwise it may introduce race conditions. + */ + RREG32_SOC15(VCN, inst_idx, regUVD_STATUS); + return; } @@ -1058,6 +1073,11 @@ static int vcn_v5_0_0_stop(struct amdgpu_vcn_inst *vinst) /* enable VCN power gating */ vcn_v5_0_0_enable_static_power_gating(vinst); + /* Keeping one read-back to ensure all register writes are done, + * otherwise it may introduce race conditions. + */ + RREG32_SOC15(VCN, i, regUVD_STATUS); + done: if (adev->pm.dpm_enabled) amdgpu_dpm_enable_vcn(adev, false, i); diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_1.c b/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_1.c index 8e843011703c..338cf43c45fe 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_1.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_1.c @@ -46,7 +46,7 @@ static void vcn_v5_0_1_set_irq_funcs(struct amdgpu_device *adev); static int vcn_v5_0_1_set_pg_state(struct amdgpu_vcn_inst *vinst, enum amd_powergating_state state); static void vcn_v5_0_1_unified_ring_set_wptr(struct amdgpu_ring *ring); - +static void vcn_v5_0_1_set_ras_funcs(struct amdgpu_device *adev); /** * vcn_v5_0_1_early_init - set function pointers and load microcode * @@ -66,6 +66,7 @@ static int vcn_v5_0_1_early_init(struct amdgpu_ip_block *ip_block) vcn_v5_0_1_set_unified_ring_funcs(adev); vcn_v5_0_1_set_irq_funcs(adev); + vcn_v5_0_1_set_ras_funcs(adev); for (i = 0; i < adev->vcn.num_vcn_inst; ++i) { adev->vcn.inst[i].set_pg_state = vcn_v5_0_1_set_pg_state; @@ -113,6 +114,10 @@ static int vcn_v5_0_1_sw_init(struct amdgpu_ip_block *ip_block) if (r) return r; + /* VCN POISON TRAP */ + r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_VCN, + VCN_5_0__SRCID_UVD_POISON, &adev->vcn.inst->ras_poison_irq); + for (i = 0; i < adev->vcn.num_vcn_inst; i++) { vcn_inst = GET_INST(VCN, i); @@ -279,6 +284,9 @@ static int vcn_v5_0_1_hw_fini(struct amdgpu_ip_block *ip_block) vinst->set_pg_state(vinst, AMD_PG_STATE_GATE); } + if (amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__VCN)) + amdgpu_irq_put(adev, &adev->vcn.inst->ras_poison_irq, 0); + return 0; } @@ -1030,6 +1038,11 @@ static int vcn_v5_0_1_start(struct amdgpu_vcn_inst *vinst) WREG32_SOC15(VCN, vcn_inst, regVCN_RB_ENABLE, tmp); fw_shared->sq.queue_mode &= ~(FW_QUEUE_RING_RESET | FW_QUEUE_DPG_HOLD_OFF); + /* Keeping one read-back to ensure all register writes are done, + * otherwise it may introduce race conditions. + */ + RREG32_SOC15(VCN, vcn_inst, regUVD_STATUS); + return 0; } @@ -1064,6 +1077,11 @@ static void vcn_v5_0_1_stop_dpg_mode(struct amdgpu_vcn_inst *vinst) /* disable dynamic power gating mode */ WREG32_P(SOC15_REG_OFFSET(VCN, vcn_inst, regUVD_POWER_STATUS), 0, ~UVD_POWER_STATUS__UVD_PG_MODE_MASK); + + /* Keeping one read-back to ensure all register writes are done, + * otherwise it may introduce race conditions. + */ + RREG32_SOC15(VCN, vcn_inst, regUVD_STATUS); } /** @@ -1139,6 +1157,11 @@ static int vcn_v5_0_1_stop(struct amdgpu_vcn_inst *vinst) /* clear status */ WREG32_SOC15(VCN, vcn_inst, regUVD_STATUS, 0); + /* Keeping one read-back to ensure all register writes are done, + * otherwise it may introduce race conditions. + */ + RREG32_SOC15(VCN, vcn_inst, regUVD_STATUS); + return 0; } @@ -1391,10 +1414,24 @@ static int vcn_v5_0_1_process_interrupt(struct amdgpu_device *adev, struct amdgp return 0; } +static int vcn_v5_0_1_set_ras_interrupt_state(struct amdgpu_device *adev, + struct amdgpu_irq_src *source, + unsigned int type, + enum amdgpu_interrupt_state state) +{ + return 0; +} + static const struct amdgpu_irq_src_funcs vcn_v5_0_1_irq_funcs = { .process = vcn_v5_0_1_process_interrupt, }; +static const struct amdgpu_irq_src_funcs vcn_v5_0_1_ras_irq_funcs = { + .set = vcn_v5_0_1_set_ras_interrupt_state, + .process = amdgpu_vcn_process_poison_irq, +}; + + /** * vcn_v5_0_1_set_irq_funcs - set VCN block interrupt irq functions * @@ -1408,7 +1445,12 @@ static void vcn_v5_0_1_set_irq_funcs(struct amdgpu_device *adev) for (i = 0; i < adev->vcn.num_vcn_inst; ++i) adev->vcn.inst->irq.num_types++; + adev->vcn.inst->irq.funcs = &vcn_v5_0_1_irq_funcs; + + adev->vcn.inst->ras_poison_irq.num_types = 1; + adev->vcn.inst->ras_poison_irq.funcs = &vcn_v5_0_1_ras_irq_funcs; + } static const struct amd_ip_funcs vcn_v5_0_1_ip_funcs = { @@ -1440,3 +1482,139 @@ const struct amdgpu_ip_block_version vcn_v5_0_1_ip_block = { .rev = 1, .funcs = &vcn_v5_0_1_ip_funcs, }; + +static uint32_t vcn_v5_0_1_query_poison_by_instance(struct amdgpu_device *adev, + uint32_t instance, uint32_t sub_block) +{ + uint32_t poison_stat = 0, reg_value = 0; + + switch (sub_block) { + case AMDGPU_VCN_V5_0_1_VCPU_VCODEC: + reg_value = RREG32_SOC15(VCN, instance, regUVD_RAS_VCPU_VCODEC_STATUS); + poison_stat = REG_GET_FIELD(reg_value, UVD_RAS_VCPU_VCODEC_STATUS, POISONED_PF); + break; + default: + break; + } + + if (poison_stat) + dev_info(adev->dev, "Poison detected in VCN%d, sub_block%d\n", + instance, sub_block); + + return poison_stat; +} + +static bool vcn_v5_0_1_query_poison_status(struct amdgpu_device *adev) +{ + uint32_t inst, sub; + uint32_t poison_stat = 0; + + for (inst = 0; inst < adev->vcn.num_vcn_inst; inst++) + for (sub = 0; sub < AMDGPU_VCN_V5_0_1_MAX_SUB_BLOCK; sub++) + poison_stat += + vcn_v5_0_1_query_poison_by_instance(adev, inst, sub); + + return !!poison_stat; +} + +static const struct amdgpu_ras_block_hw_ops vcn_v5_0_1_ras_hw_ops = { + .query_poison_status = vcn_v5_0_1_query_poison_status, +}; + +static int vcn_v5_0_1_aca_bank_parser(struct aca_handle *handle, struct aca_bank *bank, + enum aca_smu_type type, void *data) +{ + struct aca_bank_info info; + u64 misc0; + int ret; + + ret = aca_bank_info_decode(bank, &info); + if (ret) + return ret; + + misc0 = bank->regs[ACA_REG_IDX_MISC0]; + switch (type) { + case ACA_SMU_TYPE_UE: + bank->aca_err_type = ACA_ERROR_TYPE_UE; + ret = aca_error_cache_log_bank_error(handle, &info, ACA_ERROR_TYPE_UE, + 1ULL); + break; + case ACA_SMU_TYPE_CE: + bank->aca_err_type = ACA_ERROR_TYPE_CE; + ret = aca_error_cache_log_bank_error(handle, &info, bank->aca_err_type, + ACA_REG__MISC0__ERRCNT(misc0)); + break; + default: + return -EINVAL; + } + + return ret; +} + +/* reference to smu driver if header file */ +static int vcn_v5_0_1_err_codes[] = { + 14, 15, /* VCN */ +}; + +static bool vcn_v5_0_1_aca_bank_is_valid(struct aca_handle *handle, struct aca_bank *bank, + enum aca_smu_type type, void *data) +{ + u32 instlo; + + instlo = ACA_REG__IPID__INSTANCEIDLO(bank->regs[ACA_REG_IDX_IPID]); + instlo &= GENMASK(31, 1); + + if (instlo != mmSMNAID_AID0_MCA_SMU) + return false; + + if (aca_bank_check_error_codes(handle->adev, bank, + vcn_v5_0_1_err_codes, + ARRAY_SIZE(vcn_v5_0_1_err_codes))) + return false; + + return true; +} + +static const struct aca_bank_ops vcn_v5_0_1_aca_bank_ops = { + .aca_bank_parser = vcn_v5_0_1_aca_bank_parser, + .aca_bank_is_valid = vcn_v5_0_1_aca_bank_is_valid, +}; + +static const struct aca_info vcn_v5_0_1_aca_info = { + .hwip = ACA_HWIP_TYPE_SMU, + .mask = ACA_ERROR_UE_MASK, + .bank_ops = &vcn_v5_0_1_aca_bank_ops, +}; + +static int vcn_v5_0_1_ras_late_init(struct amdgpu_device *adev, struct ras_common_if *ras_block) +{ + int r; + + r = amdgpu_ras_block_late_init(adev, ras_block); + if (r) + return r; + + r = amdgpu_ras_bind_aca(adev, AMDGPU_RAS_BLOCK__VCN, + &vcn_v5_0_1_aca_info, NULL); + if (r) + goto late_fini; + + return 0; + +late_fini: + amdgpu_ras_block_late_fini(adev, ras_block); + + return r; +} + +static struct amdgpu_vcn_ras vcn_v5_0_1_ras = { + .ras_block = { + .hw_ops = &vcn_v5_0_1_ras_hw_ops, + .ras_late_init = vcn_v5_0_1_ras_late_init, + }, +}; + +static void vcn_v5_0_1_set_ras_funcs(struct amdgpu_device *adev) +{ + adev->vcn.ras = &vcn_v5_0_1_ras; +} diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_1.h b/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_1.h index 8fd90bd10807..b72e4da68317 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_1.h +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_1.h @@ -27,6 +27,13 @@ #define regVCN_RRMT_CNTL 0x0940 #define regVCN_RRMT_CNTL_BASE_IDX 1 + +enum amdgpu_vcn_v5_0_1_sub_block { + AMDGPU_VCN_V5_0_1_VCPU_VCODEC = 0, + + AMDGPU_VCN_V5_0_1_MAX_SUB_BLOCK, +}; + extern const struct amdgpu_ip_block_version vcn_v5_0_1_ip_block; #endif /* __VCN_v5_0_1_H__ */ diff --git a/drivers/gpu/drm/amd/amdkfd/Kconfig b/drivers/gpu/drm/amd/amdkfd/Kconfig index d3c3d3ab7225..62e88e5362e9 100644 --- a/drivers/gpu/drm/amd/amdkfd/Kconfig +++ b/drivers/gpu/drm/amd/amdkfd/Kconfig @@ -5,7 +5,7 @@ config HSA_AMD bool "HSA kernel driver for AMD GPU devices" - depends on DRM_AMDGPU && (X86_64 || ARM64 || PPC64) + depends on DRM_AMDGPU && (X86_64 || ARM64 || PPC64 || (RISCV && 64BIT)) select HMM_MIRROR select MMU_NOTIFIER select DRM_AMDGPU_USERPTR diff --git a/drivers/gpu/drm/amd/amdkfd/cik_event_interrupt.c b/drivers/gpu/drm/amd/amdkfd/cik_event_interrupt.c index 981d9adcc5e1..73acbe0b7c21 100644 --- a/drivers/gpu/drm/amd/amdkfd/cik_event_interrupt.c +++ b/drivers/gpu/drm/amd/amdkfd/cik_event_interrupt.c @@ -91,7 +91,6 @@ static void cik_event_interrupt_wq(struct kfd_node *dev, const struct cik_ih_ring_entry *ihre = (const struct cik_ih_ring_entry *)ih_ring_entry; uint32_t context_id = ihre->data & 0xfffffff; - unsigned int vmid = (ihre->ring_id & 0x0000ff00) >> 8; u32 pasid = (ihre->ring_id & 0xffff0000) >> 16; if (pasid == 0) @@ -125,11 +124,7 @@ static void cik_event_interrupt_wq(struct kfd_node *dev, return; } - if (info.vmid == vmid) - kfd_signal_vm_fault_event(pdd, &info, NULL); - else - kfd_signal_vm_fault_event(pdd, &info, NULL); - + kfd_signal_vm_fault_event(pdd, &info, NULL); kfd_unref_process(p); } } diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c index 1e9dd00620bf..a2149afa5803 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c @@ -2039,9 +2039,7 @@ static int criu_get_process_object_info(struct kfd_process *p, num_events = kfd_get_num_events(p); - ret = svm_range_get_info(p, &num_svm_ranges, &svm_priv_data_size); - if (ret) - return ret; + svm_range_get_info(p, &num_svm_ranges, &svm_priv_data_size); *num_objects = num_queues + num_events + num_svm_ranges; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_events.c b/drivers/gpu/drm/amd/amdkfd/kfd_events.c index e54e708ed82d..2b294ada3ec0 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_events.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_events.c @@ -1350,6 +1350,7 @@ void kfd_signal_poison_consumed_event(struct kfd_node *dev, u32 pasid) user_gpu_id = kfd_process_get_user_gpu_id(p, dev->id); if (unlikely(user_gpu_id == -EINVAL)) { WARN_ONCE(1, "Could not get user_gpu_id from dev->id:%x\n", dev->id); + kfd_unref_process(p); return; } diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c index 6d5fa57d4a23..c643e0ccec52 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c @@ -279,20 +279,17 @@ static int init_user_queue(struct process_queue_manager *pqm, /* Starting with GFX11, wptr BOs must be mapped to GART for MES to determine work * on unmapped queues for usermode queue oversubscription (no aggregated doorbell) */ - if (((dev->adev->mes.sched_version & AMDGPU_MES_API_VERSION_MASK) - >> AMDGPU_MES_API_VERSION_SHIFT) >= 2) { - if (dev->adev != amdgpu_ttm_adev(q_properties->wptr_bo->tbo.bdev)) { - pr_err("Queue memory allocated to wrong device\n"); - retval = -EINVAL; - goto free_gang_ctx_bo; - } + if (dev->adev != amdgpu_ttm_adev(q_properties->wptr_bo->tbo.bdev)) { + pr_err("Queue memory allocated to wrong device\n"); + retval = -EINVAL; + goto free_gang_ctx_bo; + } - retval = amdgpu_amdkfd_map_gtt_bo_to_gart(q_properties->wptr_bo, - &(*q)->wptr_bo_gart); - if (retval) { - pr_err("Failed to map wptr bo to GART\n"); - goto free_gang_ctx_bo; - } + retval = amdgpu_amdkfd_map_gtt_bo_to_gart(q_properties->wptr_bo, + &(*q)->wptr_bo_gart); + if (retval) { + pr_err("Failed to map wptr bo to GART\n"); + goto free_gang_ctx_bo; } } diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c index 72be6e152e88..865dca2547de 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c @@ -4075,8 +4075,8 @@ exit: return ret; } -int svm_range_get_info(struct kfd_process *p, uint32_t *num_svm_ranges, - uint64_t *svm_priv_data_size) +void svm_range_get_info(struct kfd_process *p, uint32_t *num_svm_ranges, + uint64_t *svm_priv_data_size) { uint64_t total_size, accessibility_size, common_attr_size; int nattr_common = 4, nattr_accessibility = 1; @@ -4088,8 +4088,6 @@ int svm_range_get_info(struct kfd_process *p, uint32_t *num_svm_ranges, *svm_priv_data_size = 0; svms = &p->svms; - if (!svms) - return -EINVAL; mutex_lock(&svms->lock); list_for_each_entry(prange, &svms->list, list) { @@ -4131,7 +4129,6 @@ int svm_range_get_info(struct kfd_process *p, uint32_t *num_svm_ranges, pr_debug("num_svm_ranges %u total_priv_size %llu\n", *num_svm_ranges, *svm_priv_data_size); - return 0; } int kfd_criu_checkpoint_svm(struct kfd_process *p, @@ -4148,8 +4145,6 @@ int kfd_criu_checkpoint_svm(struct kfd_process *p, struct mm_struct *mm; svms = &p->svms; - if (!svms) - return -EINVAL; mm = get_task_mm(p->lead_thread); if (!mm) { diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.h b/drivers/gpu/drm/amd/amdkfd/kfd_svm.h index 6ea23c78009c..01c7a4877904 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.h @@ -184,8 +184,8 @@ void schedule_deferred_list_work(struct svm_range_list *svms); void svm_range_dma_unmap_dev(struct device *dev, dma_addr_t *dma_addr, unsigned long offset, unsigned long npages); void svm_range_dma_unmap(struct svm_range *prange); -int svm_range_get_info(struct kfd_process *p, uint32_t *num_svm_ranges, - uint64_t *svm_priv_data_size); +void svm_range_get_info(struct kfd_process *p, uint32_t *num_svm_ranges, + uint64_t *svm_priv_data_size); int kfd_criu_checkpoint_svm(struct kfd_process *p, uint8_t __user *user_priv_data, uint64_t *priv_offset); @@ -237,13 +237,12 @@ static inline int svm_range_schedule_evict_svm_bo( return -EINVAL; } -static inline int svm_range_get_info(struct kfd_process *p, - uint32_t *num_svm_ranges, - uint64_t *svm_priv_data_size) +static inline void svm_range_get_info(struct kfd_process *p, + uint32_t *num_svm_ranges, + uint64_t *svm_priv_data_size) { *num_svm_ranges = 0; *svm_priv_data_size = 0; - return 0; } static inline int kfd_criu_checkpoint_svm(struct kfd_process *p, diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 742b10881112..d3100f641ac6 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -676,21 +676,15 @@ static void dm_crtc_high_irq(void *interrupt_params) spin_lock_irqsave(&adev_to_drm(adev)->event_lock, flags); if (acrtc->dm_irq_params.stream && - acrtc->dm_irq_params.vrr_params.supported) { - bool replay_en = acrtc->dm_irq_params.stream->link->replay_settings.replay_feature_enabled; - bool psr_en = acrtc->dm_irq_params.stream->link->psr_settings.psr_feature_enabled; - bool fs_active_var_en = acrtc->dm_irq_params.freesync_config.state == VRR_STATE_ACTIVE_VARIABLE; - + acrtc->dm_irq_params.vrr_params.supported && + acrtc->dm_irq_params.freesync_config.state == + VRR_STATE_ACTIVE_VARIABLE) { mod_freesync_handle_v_update(adev->dm.freesync_module, acrtc->dm_irq_params.stream, &acrtc->dm_irq_params.vrr_params); - /* update vmin_vmax only if freesync is enabled, or only if PSR and REPLAY are disabled */ - if (fs_active_var_en || (!fs_active_var_en && !replay_en && !psr_en)) { - dc_stream_adjust_vmin_vmax(adev->dm.dc, - acrtc->dm_irq_params.stream, - &acrtc->dm_irq_params.vrr_params.adjust); - } + dc_stream_adjust_vmin_vmax(adev->dm.dc, acrtc->dm_irq_params.stream, + &acrtc->dm_irq_params.vrr_params.adjust); } /* @@ -2006,8 +2000,10 @@ static int amdgpu_dm_init(struct amdgpu_device *adev) if (amdgpu_dc_debug_mask & DC_FORCE_SUBVP_MCLK_SWITCH) adev->dm.dc->debug.force_subvp_mclk_switch = true; - if (amdgpu_dc_debug_mask & DC_DISABLE_SUBVP) + if (amdgpu_dc_debug_mask & DC_DISABLE_SUBVP_FAMS) { adev->dm.dc->debug.force_disable_subvp = true; + adev->dm.dc->debug.fams2_config.bits.enable = false; + } if (amdgpu_dc_debug_mask & DC_ENABLE_DML2) { adev->dm.dc->debug.using_dml2 = true; @@ -2020,6 +2016,9 @@ static int amdgpu_dm_init(struct amdgpu_device *adev) if (amdgpu_dc_debug_mask & DC_HDCP_LC_ENABLE_SW_FALLBACK) adev->dm.dc->debug.hdcp_lc_enable_sw_fallback = true; + if (amdgpu_dc_debug_mask & DC_SKIP_DETECTION_LT) + adev->dm.dc->debug.skip_detection_link_training = true; + adev->dm.dc->debug.visual_confirm = amdgpu_dc_visual_confirm; /* TODO: Remove after DP2 receiver gets proper support of Cable ID feature */ @@ -4911,6 +4910,7 @@ amdgpu_dm_register_backlight_device(struct amdgpu_dm_connector *aconnector) struct backlight_properties props = { 0 }; struct amdgpu_dm_backlight_caps caps = { 0 }; char bl_name[16]; + int min, max; if (aconnector->bl_idx == -1) return; @@ -4923,11 +4923,15 @@ amdgpu_dm_register_backlight_device(struct amdgpu_dm_connector *aconnector) } amdgpu_acpi_get_backlight_caps(&caps); - if (caps.caps_valid) { + if (caps.caps_valid && get_brightness_range(&caps, &min, &max)) { if (power_supply_is_system_supplied() > 0) - props.brightness = caps.ac_level; + props.brightness = (max - min) * DIV_ROUND_CLOSEST(caps.ac_level, 100); else - props.brightness = caps.dc_level; + props.brightness = (max - min) * DIV_ROUND_CLOSEST(caps.dc_level, 100); + /* min is zero, so max needs to be adjusted */ + props.max_brightness = max - min; + drm_dbg(drm, "Backlight caps: min: %d, max: %d, ac %d, dc %d\n", min, max, + caps.ac_level, caps.dc_level); } else props.brightness = AMDGPU_MAX_BL_LEVEL; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c index e8bdd7f0c460..87058271b00c 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c @@ -246,8 +246,6 @@ static void amdgpu_dm_crtc_vblank_control_worker(struct work_struct *work) struct vblank_control_work *vblank_work = container_of(work, struct vblank_control_work, work); struct amdgpu_display_manager *dm = vblank_work->dm; - struct amdgpu_device *adev = drm_to_adev(dm->ddev); - int r; mutex_lock(&dm->dc_lock); @@ -275,15 +273,8 @@ static void amdgpu_dm_crtc_vblank_control_worker(struct work_struct *work) vblank_work->acrtc->dm_irq_params.allow_sr_entry); } - if (dm->active_vblank_irq_count == 0) { - r = amdgpu_dpm_pause_power_profile(adev, true); - if (r) - dev_warn(adev->dev, "failed to set default power profile mode\n"); + if (dm->active_vblank_irq_count == 0) dc_allow_idle_optimizations(dm->dc, true); - r = amdgpu_dpm_pause_power_profile(adev, false); - if (r) - dev_warn(adev->dev, "failed to restore the power profile mode\n"); - } mutex_unlock(&dm->dc_lock); diff --git a/drivers/gpu/drm/amd/display/dc/basics/dce_calcs.c b/drivers/gpu/drm/amd/display/dc/basics/dce_calcs.c index 681799468487..d897f8a30ede 100644 --- a/drivers/gpu/drm/amd/display/dc/basics/dce_calcs.c +++ b/drivers/gpu/drm/amd/display/dc/basics/dce_calcs.c @@ -1393,7 +1393,7 @@ static void calculate_bandwidth( if ((bw_mtn(data->dram_speed_change_margin, bw_int_to_fixed(0)) && bw_ltn(data->dram_speed_change_margin, bw_int_to_fixed(9999)))) { /*determine the minimum dram clock change margin for each set of clock frequencies*/ data->min_dram_speed_change_margin[i][j] = bw_min2(data->min_dram_speed_change_margin[i][j], data->dram_speed_change_margin); - /*compute the maximum clock frequuency required for the dram clock change at each set of clock frequencies*/ + /*compute the maximum clock frequency required for the dram clock change at each set of clock frequencies*/ data->dispclk_required_for_dram_speed_change_pipe[i][j] = bw_max2(bw_div(bw_div(bw_mul(data->src_pixels_for_first_output_pixel[k], dceip->display_pipe_throughput_factor), dceip->lb_write_pixels_per_dispclk), (bw_sub(bw_sub(bw_sub(data->maximum_latency_hiding_with_cursor[k], vbios->nbp_state_change_latency), data->dmif_burst_time[i][j]), data->dram_speed_change_line_source_transfer_time[k][i][j]))), bw_div(bw_div(bw_mul(data->src_pixels_for_last_output_pixel[k], dceip->display_pipe_throughput_factor), dceip->lb_write_pixels_per_dispclk), (bw_add(bw_sub(bw_sub(bw_sub(data->maximum_latency_hiding_with_cursor[k], vbios->nbp_state_change_latency), data->dmif_burst_time[i][j]), data->dram_speed_change_line_source_transfer_time[k][i][j]), data->active_time[k])))); if ((bw_ltn(data->dispclk_required_for_dram_speed_change_pipe[i][j], vbios->high_voltage_max_dispclk))) { data->display_pstate_change_enable[k] = 1; @@ -1407,7 +1407,7 @@ static void calculate_bandwidth( if ((bw_mtn(data->dram_speed_change_margin, bw_int_to_fixed(0)) && bw_ltn(data->dram_speed_change_margin, bw_int_to_fixed(9999)))) { /*determine the minimum dram clock change margin for each display pipe*/ data->min_dram_speed_change_margin[i][j] = bw_min2(data->min_dram_speed_change_margin[i][j], data->dram_speed_change_margin); - /*compute the maximum clock frequuency required for the dram clock change at each set of clock frequencies*/ + /*compute the maximum clock frequency required for the dram clock change at each set of clock frequencies*/ data->dispclk_required_for_dram_speed_change_pipe[i][j] = bw_max2(bw_div(bw_div(bw_mul(data->src_pixels_for_first_output_pixel[k], dceip->display_pipe_throughput_factor), dceip->lb_write_pixels_per_dispclk), (bw_sub(bw_sub(bw_sub(bw_sub(data->maximum_latency_hiding_with_cursor[k], vbios->nbp_state_change_latency), data->dmif_burst_time[i][j]), data->dram_speed_change_line_source_transfer_time[k][i][j]), data->mcifwr_burst_time[i][j]))), bw_div(bw_div(bw_mul(data->src_pixels_for_last_output_pixel[k], dceip->display_pipe_throughput_factor), dceip->lb_write_pixels_per_dispclk), (bw_add(bw_sub(bw_sub(bw_sub(bw_sub(data->maximum_latency_hiding_with_cursor[k], vbios->nbp_state_change_latency), data->dmif_burst_time[i][j]), data->dram_speed_change_line_source_transfer_time[k][i][j]), data->mcifwr_burst_time[i][j]), data->active_time[k])))); if ((bw_ltn(data->dispclk_required_for_dram_speed_change_pipe[i][j], vbios->high_voltage_max_dispclk))) { data->display_pstate_change_enable[k] = 1; diff --git a/drivers/gpu/drm/amd/display/dc/gpio/hw_hpd.c b/drivers/gpu/drm/amd/display/dc/gpio/hw_hpd.c index 3f13a744d07d..01ec451004f7 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/hw_hpd.c +++ b/drivers/gpu/drm/amd/display/dc/gpio/hw_hpd.c @@ -62,7 +62,7 @@ static void dal_hw_hpd_destroy( *ptr = NULL; } -static enum gpio_result get_value( +static enum gpio_result dal_hw_hpd_get_value( const struct hw_gpio_pin *ptr, uint32_t *value) { @@ -85,7 +85,7 @@ static enum gpio_result get_value( return dal_hw_gpio_get_value(ptr, value); } -static enum gpio_result set_config( +static enum gpio_result dal_hw_hpd_set_config( struct hw_gpio_pin *ptr, const struct gpio_config_data *config_data) { @@ -104,9 +104,9 @@ static enum gpio_result set_config( static const struct hw_gpio_pin_funcs funcs = { .destroy = dal_hw_hpd_destroy, .open = dal_hw_gpio_open, - .get_value = get_value, + .get_value = dal_hw_hpd_get_value, .set_value = dal_hw_gpio_set_value, - .set_config = set_config, + .set_config = dal_hw_hpd_set_config, .change_mode = dal_hw_gpio_change_mode, .close = dal_hw_gpio_close, }; diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c index 23bec5d25ed6..e8730cc40edb 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c @@ -952,8 +952,8 @@ void dce110_edp_backlight_control( struct dc_context *ctx = link->ctx; struct bp_transmitter_control cntl = { 0 }; uint8_t pwrseq_instance = 0; - unsigned int pre_T11_delay = OLED_PRE_T11_DELAY; - unsigned int post_T7_delay = OLED_POST_T7_DELAY; + unsigned int pre_T11_delay = (link->dpcd_sink_ext_caps.bits.oled ? OLED_PRE_T11_DELAY : 0); + unsigned int post_T7_delay = (link->dpcd_sink_ext_caps.bits.oled ? OLED_POST_T7_DELAY : 0); if (dal_graphics_object_id_get_connector_id(link->link_enc->connector) != CONNECTOR_ID_EDP) { @@ -1069,7 +1069,8 @@ void dce110_edp_backlight_control( if (!enable) { /*follow oem panel config's requirement*/ pre_T11_delay += link->panel_config.pps.extra_pre_t11_ms; - msleep(pre_T11_delay); + if (pre_T11_delay) + msleep(pre_T11_delay); } } @@ -1220,6 +1221,9 @@ void dce110_blank_stream(struct pipe_ctx *pipe_ctx) struct dc_link *link = stream->link; struct dce_hwseq *hws = link->dc->hwseq; + if (hws && hws->wa_state.skip_blank_stream) + return; + if (link->local_sink && link->local_sink->sink_signal == SIGNAL_TYPE_EDP) { if (!link->skip_implict_edp_power_control) hws->funcs.edp_backlight_control(link, false); diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c index 858288c3b1ac..c277df12c817 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c @@ -76,6 +76,7 @@ void dcn20_log_color_state(struct dc *dc, { struct dc_context *dc_ctx = dc->ctx; struct resource_pool *pool = dc->res_pool; + bool is_gamut_remap_available = false; int i; DTN_INFO("DPP: DGAM mode SHAPER mode 3DLUT mode 3DLUT bit depth" @@ -89,15 +90,15 @@ void dcn20_log_color_state(struct dc *dc, struct dcn_dpp_state s = {0}; dpp->funcs->dpp_read_state(dpp, &s); - dpp->funcs->dpp_get_gamut_remap(dpp, &s.gamut_remap); + if (dpp->funcs->dpp_get_gamut_remap) { + dpp->funcs->dpp_get_gamut_remap(dpp, &s.gamut_remap); + is_gamut_remap_available = true; + } if (!s.is_enabled) continue; - DTN_INFO("[%2d]: %8s %11s %10s %15s %10s %9s %12s " - "%010lld %010lld %010lld %010lld " - "%010lld %010lld %010lld %010lld " - "%010lld %010lld %010lld %010lld", + DTN_INFO("[%2d]: %8s %11s %10s %15s %10s %9s", dpp->inst, (s.dgam_lut_mode == 0) ? "Bypass" : ((s.dgam_lut_mode == 1) ? "sRGB" : @@ -114,10 +115,17 @@ void dcn20_log_color_state(struct dc *dc, (s.lut3d_bit_depth <= 0) ? "12-bit" : "10-bit", (s.lut3d_size == 0) ? "17x17x17" : "9x9x9", (s.rgam_lut_mode == 1) ? "RAM A" : - ((s.rgam_lut_mode == 1) ? "RAM B" : "Bypass"), + ((s.rgam_lut_mode == 1) ? "RAM B" : "Bypass")); + + if (is_gamut_remap_available) { + DTN_INFO(" %12s " + "%010lld %010lld %010lld %010lld " + "%010lld %010lld %010lld %010lld " + "%010lld %010lld %010lld %010lld", + (s.gamut_remap.gamut_adjust_type == 0) ? "Bypass" : - ((s.gamut_remap.gamut_adjust_type == 1) ? "HW" : - "SW"), + ((s.gamut_remap.gamut_adjust_type == 1) ? "HW" : + "SW"), s.gamut_remap.temperature_matrix[0].value, s.gamut_remap.temperature_matrix[1].value, s.gamut_remap.temperature_matrix[2].value, @@ -130,6 +138,8 @@ void dcn20_log_color_state(struct dc *dc, s.gamut_remap.temperature_matrix[9].value, s.gamut_remap.temperature_matrix[10].value, s.gamut_remap.temperature_matrix[11].value); + } + DTN_INFO("\n"); } DTN_INFO("\n"); diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c index e89ebfda4873..37a239219dfe 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c @@ -74,6 +74,7 @@ void dcn30_log_color_state(struct dc *dc, { struct dc_context *dc_ctx = dc->ctx; struct resource_pool *pool = dc->res_pool; + bool is_gamut_remap_available = false; int i; DTN_INFO("DPP: DGAM ROM DGAM ROM type DGAM LUT SHAPER mode" @@ -88,16 +89,16 @@ void dcn30_log_color_state(struct dc *dc, struct dcn_dpp_state s = {0}; dpp->funcs->dpp_read_state(dpp, &s); - dpp->funcs->dpp_get_gamut_remap(dpp, &s.gamut_remap); + + if (dpp->funcs->dpp_get_gamut_remap) { + dpp->funcs->dpp_get_gamut_remap(dpp, &s.gamut_remap); + is_gamut_remap_available = true; + } if (!s.is_enabled) continue; - DTN_INFO("[%2d]: %7x %13s %8s %11s %10s %15s %10s %9s" - " %12s " - "%010lld %010lld %010lld %010lld " - "%010lld %010lld %010lld %010lld " - "%010lld %010lld %010lld %010lld", + DTN_INFO("[%2d]: %7x %13s %8s %11s %10s %15s %10s %9s", dpp->inst, s.pre_dgam_mode, (s.pre_dgam_select == 0) ? "sRGB" : @@ -121,7 +122,14 @@ void dcn30_log_color_state(struct dc *dc, (s.lut3d_size == 0) ? "17x17x17" : "9x9x9", (s.rgam_lut_mode == 0) ? "Bypass" : ((s.rgam_lut_mode == 1) ? "RAM A" : - "RAM B"), + "RAM B")); + + if (is_gamut_remap_available) { + DTN_INFO(" %12s " + "%010lld %010lld %010lld %010lld " + "%010lld %010lld %010lld %010lld " + "%010lld %010lld %010lld %010lld", + (s.gamut_remap.gamut_adjust_type == 0) ? "Bypass" : ((s.gamut_remap.gamut_adjust_type == 1) ? "HW" : "SW"), @@ -137,6 +145,8 @@ void dcn30_log_color_state(struct dc *dc, s.gamut_remap.temperature_matrix[9].value, s.gamut_remap.temperature_matrix[10].value, s.gamut_remap.temperature_matrix[11].value); + } + DTN_INFO("\n"); } DTN_INFO("\n"); diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.c index f38340aa3f15..5ba3999991b0 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.c @@ -526,9 +526,15 @@ static void dcn31_reset_back_end_for_pipe( link = pipe_ctx->stream->link; + if (dc->hwseq) + dc->hwseq->wa_state.skip_blank_stream = false; + if ((!pipe_ctx->stream->dpms_off || link->link_status.link_active) && - (link->connector_signal == SIGNAL_TYPE_EDP)) + (link->connector_signal == SIGNAL_TYPE_EDP)) { dc->hwss.blank_stream(pipe_ctx); + if (dc->hwseq) + dc->hwseq->wa_state.skip_blank_stream = true; + } pipe_ctx->stream_res.tg->funcs->set_dsc_config( pipe_ctx->stream_res.tg, @@ -570,7 +576,8 @@ static void dcn31_reset_back_end_for_pipe( pipe_ctx->stream_res.audio = NULL; } } - + if (dc->hwseq) + dc->hwseq->wa_state.skip_blank_stream = false; pipe_ctx->stream = NULL; DC_LOG_DEBUG("Reset back end for pipe %d, tg:%d\n", pipe_ctx->pipe_idx, pipe_ctx->stream_res.tg->inst); diff --git a/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer_private.h b/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer_private.h index 09bc65c2fa23..1e2d247fbbac 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer_private.h +++ b/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer_private.h @@ -49,6 +49,7 @@ struct hwseq_wa_state { bool DEGVIDCN10_253_applied; bool disallow_self_refresh_during_multi_plane_transition_applied; unsigned int disallow_self_refresh_during_multi_plane_transition_applied_on_frame; + bool skip_blank_stream; }; struct pipe_ctx; diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c index 8f79881ad9f1..a5127c2d47ef 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c @@ -2023,7 +2023,7 @@ static bool retrieve_link_cap(struct dc_link *link) /* Read DP tunneling information. */ status = dpcd_get_tunneling_device_data(link); if (status != DC_OK) - dm_error("%s: Read DP tunneling device data failed.\n", __func__); + DC_LOG_DP2("%s: Read DP tunneling device data failed.\n", __func__); retrieve_cable_id(link); dpcd_write_cable_id_to_dprx(link); diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn20/dcn20_optc.c b/drivers/gpu/drm/amd/display/dc/optc/dcn20/dcn20_optc.c index 81857ce6d68d..e7a90a437fff 100644 --- a/drivers/gpu/drm/amd/display/dc/optc/dcn20/dcn20_optc.c +++ b/drivers/gpu/drm/amd/display/dc/optc/dcn20/dcn20_optc.c @@ -502,7 +502,7 @@ void optc2_get_last_used_drr_vtotal(struct timing_generator *optc, uint32_t *ref REG_GET(OTG_DRR_CONTROL, OTG_V_TOTAL_LAST_USED_BY_DRR, refresh_rate); } -static struct timing_generator_funcs dcn20_tg_funcs = { +static const struct timing_generator_funcs dcn20_tg_funcs = { .validate_timing = optc1_validate_timing, .program_timing = optc1_program_timing, .setup_vertical_interrupt0 = optc1_setup_vertical_interrupt0, diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn201/dcn201_optc.c b/drivers/gpu/drm/amd/display/dc/optc/dcn201/dcn201_optc.c index f2415eebdc09..772a8bfb949c 100644 --- a/drivers/gpu/drm/amd/display/dc/optc/dcn201/dcn201_optc.c +++ b/drivers/gpu/drm/amd/display/dc/optc/dcn201/dcn201_optc.c @@ -129,7 +129,7 @@ static void optc201_get_optc_source(struct timing_generator *optc, *num_of_src_opp = 1; } -static struct timing_generator_funcs dcn201_tg_funcs = { +static const struct timing_generator_funcs dcn201_tg_funcs = { .validate_timing = optc201_validate_timing, .program_timing = optc1_program_timing, .setup_vertical_interrupt0 = optc1_setup_vertical_interrupt0, diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn30/dcn30_optc.c b/drivers/gpu/drm/amd/display/dc/optc/dcn30/dcn30_optc.c index 78b58a449fa4..ee4665aa49e9 100644 --- a/drivers/gpu/drm/amd/display/dc/optc/dcn30/dcn30_optc.c +++ b/drivers/gpu/drm/amd/display/dc/optc/dcn30/dcn30_optc.c @@ -357,7 +357,7 @@ void optc3_tg_init(struct timing_generator *optc) optc1_clear_optc_underflow(optc); } -static struct timing_generator_funcs dcn30_tg_funcs = { +static const struct timing_generator_funcs dcn30_tg_funcs = { .validate_timing = optc1_validate_timing, .program_timing = optc1_program_timing, .setup_vertical_interrupt0 = optc1_setup_vertical_interrupt0, diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn301/dcn301_optc.c b/drivers/gpu/drm/amd/display/dc/optc/dcn301/dcn301_optc.c index 65e9089b7f31..38f85bc2681a 100644 --- a/drivers/gpu/drm/amd/display/dc/optc/dcn301/dcn301_optc.c +++ b/drivers/gpu/drm/amd/display/dc/optc/dcn301/dcn301_optc.c @@ -109,7 +109,7 @@ void optc301_setup_manual_trigger(struct timing_generator *optc) OTG_TRIGA_CLEAR, 1); } -static struct timing_generator_funcs dcn30_tg_funcs = { +static const struct timing_generator_funcs dcn30_tg_funcs = { .validate_timing = optc1_validate_timing, .program_timing = optc1_program_timing, .setup_vertical_interrupt0 = optc1_setup_vertical_interrupt0, diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn31/dcn31_optc.c b/drivers/gpu/drm/amd/display/dc/optc/dcn31/dcn31_optc.c index ef536f37b4ed..4f1830ba619f 100644 --- a/drivers/gpu/drm/amd/display/dc/optc/dcn31/dcn31_optc.c +++ b/drivers/gpu/drm/amd/display/dc/optc/dcn31/dcn31_optc.c @@ -315,7 +315,7 @@ void optc31_read_otg_state(struct timing_generator *optc, s->otg_double_buffer_control = REG_READ(OTG_DOUBLE_BUFFER_CONTROL); } -static struct timing_generator_funcs dcn31_tg_funcs = { +static const struct timing_generator_funcs dcn31_tg_funcs = { .validate_timing = optc1_validate_timing, .program_timing = optc1_program_timing, .setup_vertical_interrupt0 = optc1_setup_vertical_interrupt0, diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn314/dcn314_optc.c b/drivers/gpu/drm/amd/display/dc/optc/dcn314/dcn314_optc.c index 0e603bad0d12..4a2caca37255 100644 --- a/drivers/gpu/drm/amd/display/dc/optc/dcn314/dcn314_optc.c +++ b/drivers/gpu/drm/amd/display/dc/optc/dcn314/dcn314_optc.c @@ -192,7 +192,7 @@ static void optc314_set_h_timing_div_manual_mode(struct timing_generator *optc, } -static struct timing_generator_funcs dcn314_tg_funcs = { +static const struct timing_generator_funcs dcn314_tg_funcs = { .validate_timing = optc1_validate_timing, .program_timing = optc1_program_timing, .setup_vertical_interrupt0 = optc1_setup_vertical_interrupt0, diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn32/dcn32_optc.c b/drivers/gpu/drm/amd/display/dc/optc/dcn32/dcn32_optc.c index 2cdd19ba634b..b2b226bcd871 100644 --- a/drivers/gpu/drm/amd/display/dc/optc/dcn32/dcn32_optc.c +++ b/drivers/gpu/drm/amd/display/dc/optc/dcn32/dcn32_optc.c @@ -297,7 +297,7 @@ static void optc32_set_drr( optc32_setup_manual_trigger(optc); } -static struct timing_generator_funcs dcn32_tg_funcs = { +static const struct timing_generator_funcs dcn32_tg_funcs = { .validate_timing = optc1_validate_timing, .program_timing = optc1_program_timing, .setup_vertical_interrupt0 = optc1_setup_vertical_interrupt0, diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn35/dcn35_optc.c b/drivers/gpu/drm/amd/display/dc/optc/dcn35/dcn35_optc.c index 4cfc6c0fa147..72bff94cb57d 100644 --- a/drivers/gpu/drm/amd/display/dc/optc/dcn35/dcn35_optc.c +++ b/drivers/gpu/drm/amd/display/dc/optc/dcn35/dcn35_optc.c @@ -428,7 +428,7 @@ static void optc35_set_long_vtotal( } } -static struct timing_generator_funcs dcn35_tg_funcs = { +static const struct timing_generator_funcs dcn35_tg_funcs = { .validate_timing = optc1_validate_timing, .program_timing = optc1_program_timing, .setup_vertical_interrupt0 = optc1_setup_vertical_interrupt0, diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn401/dcn401_optc.c b/drivers/gpu/drm/amd/display/dc/optc/dcn401/dcn401_optc.c index 382ac18e7854..ff79c38287df 100644 --- a/drivers/gpu/drm/amd/display/dc/optc/dcn401/dcn401_optc.c +++ b/drivers/gpu/drm/amd/display/dc/optc/dcn401/dcn401_optc.c @@ -459,7 +459,7 @@ bool optc401_wait_update_lock_status(struct timing_generator *tg, bool locked) return true; } -static struct timing_generator_funcs dcn401_tg_funcs = { +static const struct timing_generator_funcs dcn401_tg_funcs = { .validate_timing = optc1_validate_timing, .program_timing = optc1_program_timing, .setup_vertical_interrupt0 = optc1_setup_vertical_interrupt0, diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn401/dcn401_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn401/dcn401_resource.c index e0e32975ca34..f420c4dafa03 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn401/dcn401_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn401/dcn401_resource.c @@ -1938,8 +1938,8 @@ static bool dcn401_resource_construct( dc->caps.color.dpp.gamma_corr = 1; dc->caps.color.dpp.dgam_rom_for_yuv = 0; - dc->caps.color.dpp.hw_3d_lut = 1; - dc->caps.color.dpp.ogam_ram = 1; + dc->caps.color.dpp.hw_3d_lut = 0; + dc->caps.color.dpp.ogam_ram = 0; // no OGAM ROM on DCN2 and later ASICs dc->caps.color.dpp.ogam_rom_caps.srgb = 0; dc->caps.color.dpp.ogam_rom_caps.bt2020 = 0; diff --git a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h index 57fa05bddb45..b66bd10cdc9b 100644 --- a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h +++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h @@ -2139,11 +2139,6 @@ union dmub_cmd_fams2_config { } stream_v1; //v1 }; -struct dmub_fams2_config_v2 { - struct dmub_cmd_fams2_global_config global; - struct dmub_fams2_stream_static_state_v1 stream_v1[DMUB_MAX_STREAMS]; //v1 -}; - /** * DMUB rb command definition for FAMS2 (merged SubVP, FPO, Legacy) */ @@ -2153,22 +2148,6 @@ struct dmub_rb_cmd_fams2 { }; /** - * Indirect buffer descriptor - */ -struct dmub_ib_data { - union dmub_addr src; // location of indirect buffer in memory - uint16_t size; // indirect buffer size in bytes -}; - -/** - * DMUB rb command definition for commands passed over indirect buffer - */ -struct dmub_rb_cmd_ib { - struct dmub_cmd_header header; - struct dmub_ib_data ib_data; -}; - -/** * enum dmub_cmd_idle_opt_type - Idle optimization command type. */ enum dmub_cmd_idle_opt_type { @@ -2191,11 +2170,6 @@ enum dmub_cmd_idle_opt_type { * DCN hardware notify power state. */ DMUB_CMD__IDLE_OPT_SET_DC_POWER_STATE = 3, - - /** - * DCN notify to release HW. - */ - DMUB_CMD__IDLE_OPT_RELEASE_HW = 4, }; /** @@ -2957,9 +2931,8 @@ enum dmub_cmd_fams_type { */ DMUB_CMD__FAMS_SET_MANUAL_TRIGGER = 3, DMUB_CMD__FAMS2_CONFIG = 4, - DMUB_CMD__FAMS2_IB_CONFIG = 5, - DMUB_CMD__FAMS2_DRR_UPDATE = 6, - DMUB_CMD__FAMS2_FLIP = 7, + DMUB_CMD__FAMS2_DRR_UPDATE = 5, + DMUB_CMD__FAMS2_FLIP = 6, }; /** @@ -5953,11 +5926,8 @@ union dmub_rb_cmd { * Definition of a DMUB_CMD__PSP_ASSR_ENABLE command. */ struct dmub_rb_cmd_assr_enable assr_enable; - struct dmub_rb_cmd_fams2 fams2_config; - struct dmub_rb_cmd_ib ib_fams2_config; - struct dmub_rb_cmd_fams2_drr_update fams2_drr_update; struct dmub_rb_cmd_fams2_flip fams2_flip; diff --git a/drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h b/drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h index 813463ffe15c..cc467031651d 100644 --- a/drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h +++ b/drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h @@ -424,7 +424,7 @@ struct integrated_info { /* * DFS-bypass flag */ -/* Copy of SYS_INFO_GPUCAPS__ENABEL_DFS_BYPASS from atombios.h */ +/* Copy of SYS_INFO_GPUCAPS__ENABLE_DFS_BYPASS from atombios.h */ enum { DFS_BYPASS_ENABLE = 0x10 }; diff --git a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_psp.c b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_psp.c index 8c137d7c032e..e58e7b93810b 100644 --- a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_psp.c +++ b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_psp.c @@ -368,6 +368,9 @@ enum mod_hdcp_status mod_hdcp_hdcp1_enable_encryption(struct mod_hdcp *hdcp) struct mod_hdcp_display *display = get_first_active_display(hdcp); enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS; + if (!display) + return MOD_HDCP_STATUS_DISPLAY_NOT_FOUND; + mutex_lock(&psp->hdcp_context.mutex); hdcp_cmd = (struct ta_hdcp_shared_memory *)psp->hdcp_context.context.mem_context.shared_buf; memset(hdcp_cmd, 0, sizeof(struct ta_hdcp_shared_memory)); diff --git a/drivers/gpu/drm/amd/include/amd_shared.h b/drivers/gpu/drm/amd/include/amd_shared.h index c8eccee9b023..11374a2cbab8 100644 --- a/drivers/gpu/drm/amd/include/amd_shared.h +++ b/drivers/gpu/drm/amd/include/amd_shared.h @@ -351,9 +351,10 @@ enum DC_DEBUG_MASK { DC_DISABLE_HDMI_CEC = 0x10000, /** - * @DC_DISABLE_SUBVP: If set, disable DCN Sub-Viewport feature in amdgpu driver. + * @DC_DISABLE_SUBVP_FAMS: If set, disable DCN Sub-Viewport & Firmware Assisted + * Memory Clock Switching (FAMS) feature in amdgpu driver. */ - DC_DISABLE_SUBVP = 0x20000, + DC_DISABLE_SUBVP_FAMS = 0x20000, /** * @DC_DISABLE_CUSTOM_BRIGHTNESS_CURVE: If set, disable support for custom brightness curves */ @@ -370,6 +371,11 @@ enum DC_DEBUG_MASK { * path failure, retry using legacy SW path. */ DC_HDCP_LC_ENABLE_SW_FALLBACK = 0x100000, + + /** + * @DC_SKIP_DETECTION_LT: If set, skip detection link training + */ + DC_SKIP_DETECTION_LT = 0x200000, }; enum amd_dpm_forced_level; diff --git a/drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_4_1_0_offset.h b/drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_4_1_0_offset.h index 15e5a65cf492..70ee6be94a9b 100644 --- a/drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_4_1_0_offset.h +++ b/drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_4_1_0_offset.h @@ -9776,6 +9776,14 @@ #define regDIG0_DIG_BE_CNTL_BASE_IDX 2 #define regDIG0_DIG_BE_EN_CNTL 0x20bd #define regDIG0_DIG_BE_EN_CNTL_BASE_IDX 2 +#define regDIG0_HDCP_INT_CONTROL 0x20c0 +#define regDIG0_HDCP_INT_CONTROL_BASE_IDX 2 +#define regDIG0_HDCP_LINK0_STATUS 0x20c1 +#define regDIG0_HDCP_LINK0_STATUS_BASE_IDX 2 +#define regDIG0_HDCP_I2C_CONTROL_0 0x20c2 +#define regDIG0_HDCP_I2C_CONTROL_0_BASE_IDX 2 +#define regDIG0_HDCP_I2C_CONTROL_1 0x20c3 +#define regDIG0_HDCP_I2C_CONTROL_1_BASE_IDX 2 #define regDIG0_TMDS_CNTL 0x20e4 #define regDIG0_TMDS_CNTL_BASE_IDX 2 #define regDIG0_TMDS_CONTROL_CHAR 0x20e5 @@ -10081,6 +10089,12 @@ #define regDIG1_DIG_BE_CNTL_BASE_IDX 2 #define regDIG1_DIG_BE_EN_CNTL 0x21e1 #define regDIG1_DIG_BE_EN_CNTL_BASE_IDX 2 +#define regDIG1_HDCP_INT_CONTROL 0x21e4 +#define regDIG1_HDCP_INT_CONTROL_BASE_IDX 2 +#define regDIG1_HDCP_I2C_CONTROL_0 0x21e6 +#define regDIG1_HDCP_I2C_CONTROL_0_BASE_IDX 2 +#define regDIG1_HDCP_I2C_CONTROL_1 0x21e7 +#define regDIG1_HDCP_I2C_CONTROL_1_BASE_IDX 2 #define regDIG1_TMDS_CNTL 0x2208 #define regDIG1_TMDS_CNTL_BASE_IDX 2 #define regDIG1_TMDS_CONTROL_CHAR 0x2209 @@ -10386,6 +10400,12 @@ #define regDIG2_DIG_BE_CNTL_BASE_IDX 2 #define regDIG2_DIG_BE_EN_CNTL 0x2305 #define regDIG2_DIG_BE_EN_CNTL_BASE_IDX 2 +#define regDIG2_HDCP_INT_CONTROL 0x2308 +#define regDIG2_HDCP_INT_CONTROL_BASE_IDX 2 +#define regDIG2_HDCP_I2C_CONTROL_0 0x230a +#define regDIG2_HDCP_I2C_CONTROL_0_BASE_IDX 2 +#define regDIG2_HDCP_I2C_CONTROL_1 0x230b +#define regDIG2_HDCP_I2C_CONTROL_1_BASE_IDX 2 #define regDIG2_TMDS_CNTL 0x232c #define regDIG2_TMDS_CNTL_BASE_IDX 2 #define regDIG2_TMDS_CONTROL_CHAR 0x232d @@ -10691,6 +10711,12 @@ #define regDIG3_DIG_BE_CNTL_BASE_IDX 2 #define regDIG3_DIG_BE_EN_CNTL 0x2429 #define regDIG3_DIG_BE_EN_CNTL_BASE_IDX 2 +#define regDIG3_HDCP_INT_CONTROL 0x242c +#define regDIG3_HDCP_INT_CONTROL_BASE_IDX 2 +#define regDIG3_HDCP_I2C_CONTROL_0 0x242e +#define regDIG3_HDCP_I2C_CONTROL_0_BASE_IDX 2 +#define regDIG3_HDCP_I2C_CONTROL_1 0x242f +#define regDIG3_HDCP_I2C_CONTROL_1_BASE_IDX 2 #define regDIG3_TMDS_CNTL 0x2450 #define regDIG3_TMDS_CNTL_BASE_IDX 2 #define regDIG3_TMDS_CONTROL_CHAR 0x2451 diff --git a/drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_4_1_0_sh_mask.h b/drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_4_1_0_sh_mask.h index 5d9d5fea6e06..e3d841b2e9af 100644 --- a/drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_4_1_0_sh_mask.h +++ b/drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_4_1_0_sh_mask.h @@ -2847,6 +2847,14 @@ #define HDCP_INTERRUPT_DEST__DOUT_IHC_HDCP0_AUTH_FAIL_INTERRUPT_DEST__SHIFT 0x1 #define HDCP_INTERRUPT_DEST__DOUT_IHC_HDCP0_I2C_XFER_REQ_INTERRUPT_DEST__SHIFT 0x2 #define HDCP_INTERRUPT_DEST__DOUT_IHC_HDCP0_I2C_XFER_DONE_INTERRUPT_DEST__SHIFT 0x3 +#define HDCP_INTERRUPT_DEST__DOUT_IHC_HDCP1_AUTH_SUCCESS_INTERRUPT_DEST__SHIFT 0x4 +#define HDCP_INTERRUPT_DEST__DOUT_IHC_HDCP1_AUTH_FAIL_INTERRUPT_DEST__SHIFT 0x5 +#define HDCP_INTERRUPT_DEST__DOUT_IHC_HDCP1_I2C_XFER_REQ_INTERRUPT_DEST__SHIFT 0x6 +#define HDCP_INTERRUPT_DEST__DOUT_IHC_HDCP1_I2C_XFER_DONE_INTERRUPT_DEST__SHIFT 0x7 +#define HDCP_INTERRUPT_DEST__DOUT_IHC_HDCP2_AUTH_SUCCESS_INTERRUPT_DEST__SHIFT 0x8 +#define HDCP_INTERRUPT_DEST__DOUT_IHC_HDCP2_AUTH_FAIL_INTERRUPT_DEST__SHIFT 0x9 +#define HDCP_INTERRUPT_DEST__DOUT_IHC_HDCP2_I2C_XFER_REQ_INTERRUPT_DEST__SHIFT 0xa +#define HDCP_INTERRUPT_DEST__DOUT_IHC_HDCP2_I2C_XFER_DONE_INTERRUPT_DEST__SHIFT 0xb #define HDCP_INTERRUPT_DEST__DOUT_IHC_HDCP3_AUTH_SUCCESS_INTERRUPT_DEST__SHIFT 0xc #define HDCP_INTERRUPT_DEST__DOUT_IHC_HDCP3_AUTH_FAIL_INTERRUPT_DEST__SHIFT 0xd #define HDCP_INTERRUPT_DEST__DOUT_IHC_HDCP3_I2C_XFER_REQ_INTERRUPT_DEST__SHIFT 0xe @@ -2871,6 +2879,14 @@ #define HDCP_INTERRUPT_DEST__DOUT_IHC_HDCP0_AUTH_FAIL_INTERRUPT_DEST_MASK 0x00000002L #define HDCP_INTERRUPT_DEST__DOUT_IHC_HDCP0_I2C_XFER_REQ_INTERRUPT_DEST_MASK 0x00000004L #define HDCP_INTERRUPT_DEST__DOUT_IHC_HDCP0_I2C_XFER_DONE_INTERRUPT_DEST_MASK 0x00000008L +#define HDCP_INTERRUPT_DEST__DOUT_IHC_HDCP1_AUTH_SUCCESS_INTERRUPT_DEST_MASK 0x00000010L +#define HDCP_INTERRUPT_DEST__DOUT_IHC_HDCP1_AUTH_FAIL_INTERRUPT_DEST_MASK 0x00000020L +#define HDCP_INTERRUPT_DEST__DOUT_IHC_HDCP1_I2C_XFER_REQ_INTERRUPT_DEST_MASK 0x00000040L +#define HDCP_INTERRUPT_DEST__DOUT_IHC_HDCP1_I2C_XFER_DONE_INTERRUPT_DEST_MASK 0x00000080L +#define HDCP_INTERRUPT_DEST__DOUT_IHC_HDCP2_AUTH_SUCCESS_INTERRUPT_DEST_MASK 0x00000100L +#define HDCP_INTERRUPT_DEST__DOUT_IHC_HDCP2_AUTH_FAIL_INTERRUPT_DEST_MASK 0x00000200L +#define HDCP_INTERRUPT_DEST__DOUT_IHC_HDCP2_I2C_XFER_REQ_INTERRUPT_DEST_MASK 0x00000400L +#define HDCP_INTERRUPT_DEST__DOUT_IHC_HDCP2_I2C_XFER_DONE_INTERRUPT_DEST_MASK 0x00000800L #define HDCP_INTERRUPT_DEST__DOUT_IHC_HDCP3_AUTH_SUCCESS_INTERRUPT_DEST_MASK 0x00001000L #define HDCP_INTERRUPT_DEST__DOUT_IHC_HDCP3_AUTH_FAIL_INTERRUPT_DEST_MASK 0x00002000L #define HDCP_INTERRUPT_DEST__DOUT_IHC_HDCP3_I2C_XFER_REQ_INTERRUPT_DEST_MASK 0x00004000L diff --git a/drivers/gpu/drm/amd/include/asic_reg/vcn/vcn_5_0_0_offset.h b/drivers/gpu/drm/amd/include/asic_reg/vcn/vcn_5_0_0_offset.h index c4aaa86a95e2..72a118b2af69 100644 --- a/drivers/gpu/drm/amd/include/asic_reg/vcn/vcn_5_0_0_offset.h +++ b/drivers/gpu/drm/amd/include/asic_reg/vcn/vcn_5_0_0_offset.h @@ -1067,7 +1067,13 @@ #define regVCN_FEATURES_BASE_IDX 1 #define regUVD_GPUIOV_STATUS 0x0055 #define regUVD_GPUIOV_STATUS_BASE_IDX 1 +#define regUVD_RAS_VCPU_VCODEC_STATUS 0x0057 +#define regUVD_RAS_VCPU_VCODEC_STATUS_BASE_IDX 1 #define regUVD_SCRATCH15 0x005c +#define regUVD_RAS_JPEG0_STATUS 0x0059 +#define regUVD_RAS_JPEG0_STATUS_BASE_IDX 1 +#define regUVD_RAS_JPEG1_STATUS 0x005a +#define regUVD_RAS_JPEG1_STATUS_BASE_IDX 1 #define regUVD_SCRATCH15_BASE_IDX 1 #define regUVD_VERSION 0x005d #define regUVD_VERSION_BASE_IDX 1 diff --git a/drivers/gpu/drm/amd/include/asic_reg/vcn/vcn_5_0_0_sh_mask.h b/drivers/gpu/drm/amd/include/asic_reg/vcn/vcn_5_0_0_sh_mask.h index bd7242e4e9c6..c78b09d6fbae 100644 --- a/drivers/gpu/drm/amd/include/asic_reg/vcn/vcn_5_0_0_sh_mask.h +++ b/drivers/gpu/drm/amd/include/asic_reg/vcn/vcn_5_0_0_sh_mask.h @@ -5714,6 +5714,22 @@ //UVD_GPUIOV_STATUS #define UVD_GPUIOV_STATUS__UVD_GPUIOV_STATUS_VF_ENABLE__SHIFT 0x0 #define UVD_GPUIOV_STATUS__UVD_GPUIOV_STATUS_VF_ENABLE_MASK 0x00000001L +//UVD_RAS_VCPU_VCODEC_STATUS +#define UVD_RAS_VCPU_VCODEC_STATUS__POISONED_VF__SHIFT 0x0 +#define UVD_RAS_VCPU_VCODEC_STATUS__POISONED_PF__SHIFT 0x1f +#define UVD_RAS_VCPU_VCODEC_STATUS__POISONED_VF_MASK 0x7FFFFFFFL +#define UVD_RAS_VCPU_VCODEC_STATUS__POISONED_PF_MASK 0x80000000L + +//UVD_RAS_JPEG0_STATUS +#define UVD_RAS_JPEG0_STATUS__POISONED_VF__SHIFT 0x0 +#define UVD_RAS_JPEG0_STATUS__POISONED_PF__SHIFT 0x1f +#define UVD_RAS_JPEG0_STATUS__POISONED_VF_MASK 0x7FFFFFFFL +#define UVD_RAS_JPEG0_STATUS__POISONED_PF_MASK 0x80000000L +//UVD_RAS_JPEG1_STATUS +#define UVD_RAS_JPEG1_STATUS__POISONED_VF__SHIFT 0x0 +#define UVD_RAS_JPEG1_STATUS__POISONED_PF__SHIFT 0x1f +#define UVD_RAS_JPEG1_STATUS__POISONED_VF_MASK 0x7FFFFFFFL +#define UVD_RAS_JPEG1_STATUS__POISONED_PF_MASK 0x80000000L //UVD_SCRATCH15 #define UVD_SCRATCH15__SCRATCH15_DATA__SHIFT 0x0 #define UVD_SCRATCH15__SCRATCH15_DATA_MASK 0xFFFFFFFFL diff --git a/drivers/gpu/drm/amd/include/atombios.h b/drivers/gpu/drm/amd/include/atombios.h index 52bac19fb404..b344acefc606 100644 --- a/drivers/gpu/drm/amd/include/atombios.h +++ b/drivers/gpu/drm/amd/include/atombios.h @@ -6017,7 +6017,7 @@ typedef struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_7 #define SYS_INFO_GPUCAPS__TMDSHDMI_COHERENT_SINGLEPLL_MODE 0x01 #define SYS_INFO_GPUCAPS__DP_SINGLEPLL_MODE 0x02 #define SYS_INFO_GPUCAPS__DISABLE_AUX_MODE_DETECT 0x08 -#define SYS_INFO_GPUCAPS__ENABEL_DFS_BYPASS 0x10 +#define SYS_INFO_GPUCAPS__ENABLE_DFS_BYPASS 0x10 //ulGPUCapInfo[16]=1 indicate SMC firmware is able to support GNB fast resume function, so that driver can call SMC to program most of GNB register during resuming, from ML #define SYS_INFO_GPUCAPS__GNB_FAST_RESUME_CAPABLE 0x00010000 @@ -6460,7 +6460,7 @@ typedef struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_9 // ulGPUCapInfo #define SYS_INFO_V1_9_GPUCAPSINFO_DISABLE_AUX_MODE_DETECT 0x08 -#define SYS_INFO_V1_9_GPUCAPSINFO_ENABEL_DFS_BYPASS 0x10 +#define SYS_INFO_V1_9_GPUCAPSINFO_ENABLE_DFS_BYPASS 0x10 //ulGPUCapInfo[16]=1 indicate SMC firmware is able to support GNB fast resume function, so that driver can call SMC to program most of GNB register during resuming, from ML #define SYS_INFO_V1_9_GPUCAPSINFO_GNB_FAST_RESUME_CAPABLE 0x00010000 //ulGPUCapInfo[18]=1 indicate the IOMMU is not available diff --git a/drivers/gpu/drm/amd/include/atomfirmware.h b/drivers/gpu/drm/amd/include/atomfirmware.h index 2d1135bdc4b9..5c86423c2e92 100644 --- a/drivers/gpu/drm/amd/include/atomfirmware.h +++ b/drivers/gpu/drm/amd/include/atomfirmware.h @@ -1714,7 +1714,7 @@ enum atom_system_vbiosmisc_def{ // gpucapinfo enum atom_system_gpucapinf_def{ - SYS_INFO_GPUCAPS__ENABEL_DFS_BYPASS = 0x10, + SYS_INFO_GPUCAPS__ENABLE_DFS_BYPASS = 0x10, }; //dpphy_override diff --git a/drivers/gpu/drm/amd/include/ivsrcid/gfx/irqsrcs_gfx_11_0_0.h b/drivers/gpu/drm/amd/include/ivsrcid/gfx/irqsrcs_gfx_11_0_0.h index 3a4670bc4449..b98b7ae551b5 100644 --- a/drivers/gpu/drm/amd/include/ivsrcid/gfx/irqsrcs_gfx_11_0_0.h +++ b/drivers/gpu/drm/amd/include/ivsrcid/gfx/irqsrcs_gfx_11_0_0.h @@ -48,6 +48,7 @@ #define GFX_11_0_0__SRCID__SDMA_SRAM_ECC 64 // 0x40 SRAM ECC Error #define GFX_11_0_0__SRCID__SDMA_SEM_INCOMPLETE_TIMEOUT 65 // 0x41 GPF(Sem incomplete timeout) #define GFX_11_0_0__SRCID__SDMA_SEM_WAIT_FAIL_TIMEOUT 66 // 0x42 Semaphore wait fail timeout +#define GFX_11_0_0__SRCID__SDMA_FENCE 67 // 0x43 User fence #define GFX_11_0_0__SRCID__RLC_GC_FED_INTERRUPT 128 // 0x80 FED Interrupt (for data poisoning) diff --git a/drivers/gpu/drm/amd/include/ivsrcid/gfx/irqsrcs_gfx_12_0_0.h b/drivers/gpu/drm/amd/include/ivsrcid/gfx/irqsrcs_gfx_12_0_0.h new file mode 100644 index 000000000000..467897ec2e65 --- /dev/null +++ b/drivers/gpu/drm/amd/include/ivsrcid/gfx/irqsrcs_gfx_12_0_0.h @@ -0,0 +1,74 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright 2024 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + */ +#ifndef __IRQSRCS_GFX_12_0_0_H__ +#define __IRQSRCS_GFX_12_0_0_H__ + +#define GFX_12_0_0__SRCID__UTCL2_FAULT 0 // UTCL2 has encountered a fault or retry scenario +#define GFX_12_0_0__SRCID__UTCL2_DATA_POISONING 1 // UTCL2 for data poisoning +#define GFX_12_0_0__SRCID__MEM_ACCES_MON 10 // 0x0A EA memory access monitor interrupt +#define GFX_12_0_0__SRCID__SDMA_ATOMIC_RTN_DONE 48 // 0x30 SDMA atomic*_rtn ops complete +#define GFX_12_0_0__SRCID__SDMA_TRAP 49 // 0x31 Trap +#define GFX_12_0_0__SRCID__SDMA_SRBMWRITE 50 // 0x32 SRBM write Protection +#define GFX_12_0_0__SRCID__SDMA_CTXEMPTY 51 // 0x33 Context Empty +#define GFX_12_0_0__SRCID__SDMA_PREEMPT 52 // 0x34 SDMA New Run List +#define GFX_12_0_0__SRCID__SDMA_IB_PREEMPT 53 // 0x35 sdma mid - command buffer preempt interrupt +#define GFX_12_0_0__SRCID__SDMA_DOORBELL_INVALID 54 // 0x36 Doorbell BE invalid +#define GFX_12_0_0__SRCID__SDMA_QUEUE_HANG 55 // 0x37 Queue hang or Command timeout +#define GFX_12_0_0__SRCID__SDMA_ATOMIC_TIMEOUT 56 // 0x38 SDMA atomic CMPSWAP loop timeout +#define GFX_12_0_0__SRCID__SDMA_POLL_TIMEOUT 57 // 0x39 SRBM read poll timeout +#define GFX_12_0_0__SRCID__SDMA_PAGE_TIMEOUT 58 // 0x3A Page retry timeout after UTCL2 return nack = 1 +#define GFX_12_0_0__SRCID__SDMA_PAGE_NULL 59 // 0x3B Page Null from UTCL2 when nack = 2 +#define GFX_12_0_0__SRCID__SDMA_PAGE_FAULT 60 // 0x3C Page Fault Error from UTCL2 when nack = 3 +#define GFX_12_0_0__SRCID__SDMA_VM_HOLE 61 // 0x3D MC or SEM address in VM hole +#define GFX_12_0_0__SRCID__SDMA_ECC 62 // 0x3E ECC Error +#define GFX_12_0_0__SRCID__SDMA_FROZEN 63 // 0x3F SDMA Frozen +#define GFX_12_0_0__SRCID__SDMA_SRAM_ECC 64 // 0x40 SRAM ECC Error +#define GFX_12_0_0__SRCID__SDMA_SEM_INCOMPLETE_TIMEOUT 65 // 0x41 GPF(Sem incomplete timeout) +#define GFX_12_0_0__SRCID__SDMA_SEM_WAIT_FAIL_TIMEOUT 66 // 0x42 Semaphore wait fail timeout +#define GFX_12_0_0__SRCID__SDMA_FENCE 70 // 0x46 User fence +#define GFX_12_0_0__SRCID__RLC_GC_FED_INTERRUPT 128 // 0x80 FED Interrupt (for data poisoning) +#define GFX_12_0_0__SRCID__CP_GENERIC_INT 177 // 0xB1 CP_GENERIC int +#define GFX_12_0_0__SRCID__CP_PM4_PKT_RSVD_BIT_ERROR 180 // 0xB4 PM4 Pkt Rsvd Bits Error +#define GFX_12_0_0__SRCID__CP_EOP_INTERRUPT 181 // 0xB5 End-of-Pipe Interrupt +#define GFX_12_0_0__SRCID__CP_BAD_OPCODE_ERROR 183 // 0xB7 Bad Opcode Error +#define GFX_12_0_0__SRCID__CP_PRIV_REG_FAULT 184 // 0xB8 Privileged Register Fault +#define GFX_12_0_0__SRCID__CP_PRIV_INSTR_FAULT 185 // 0xB9 Privileged Instr Fault +#define GFX_12_0_0__SRCID__CP_WAIT_MEM_SEM_FAULT 186 // 0xBA Wait Memory Semaphore Fault (Sync Object Fault) +#define GFX_12_0_0__SRCID__CP_CTX_EMPTY_INTERRUPT 187 // 0xBB Context Empty Interrupt +#define GFX_12_0_0__SRCID__CP_CTX_BUSY_INTERRUPT 188 // 0xBC Context Busy Interrupt +#define GFX_12_0_0__SRCID__CP_ME_WAIT_REG_MEM_POLL_TIMEOUT 192 // 0xC0 CP.ME Wait_Reg_Mem Poll Timeout +#define GFX_12_0_0__SRCID__CP_SIG_INCOMPLETE 193 // 0xC1 "Surface Probe Fault Signal Incomplete" +#define GFX_12_0_0__SRCID__CP_PREEMPT_ACK 194 // 0xC2 Preemption Ack-wledge +#define GFX_12_0_0__SRCID__CP_GPF 195 // 0xC3 General Protection Fault (GPF) +#define GFX_12_0_0__SRCID__CP_GDS_ALLOC_ERROR 196 // 0xC4 GDS Alloc Error +#define GFX_12_0_0__SRCID__CP_ECC_ERROR 197 // 0xC5 ECC Error +#define GFX_12_0_0__SRCID__CP_COMPUTE_QUERY_STATUS 199 // 0xC7 Compute query status +#define GFX_12_0_0__SRCID__CP_VM_DOORBELL 200 // 0xC8 Unattached VM Doorbell Received +#define GFX_12_0_0__SRCID__CP_FUE_ERROR 201 // 0xC9 ECC FUE Error +#define GFX_12_0_0__SRCID__RLC_STRM_PERF_MONITOR_INTERRUPT 202 // 0xCA Streaming Perf Monitor Interrupt +#define GFX_12_0_0__SRCID__GRBM_RD_TIMEOUT_ERROR 232 // 0xE8 CRead timeout error +#define GFX_12_0_0__SRCID__GRBM_REG_GUI_IDLE 233 // 0xE9 Register GUI Idle +#define GFX_12_0_0__SRCID__SQ_INTERRUPT_ID 239 // 0xEF SQ Interrupt (ttrace wrap, errors) + +#endif diff --git a/drivers/gpu/drm/amd/include/kgd_pp_interface.h b/drivers/gpu/drm/amd/include/kgd_pp_interface.h index 0f7542d7074b..f4d914dc731f 100644 --- a/drivers/gpu/drm/amd/include/kgd_pp_interface.h +++ b/drivers/gpu/drm/amd/include/kgd_pp_interface.h @@ -494,6 +494,7 @@ struct amd_pm_funcs { int (*set_df_cstate)(void *handle, enum pp_df_cstate state); int (*set_xgmi_pstate)(void *handle, uint32_t pstate); ssize_t (*get_gpu_metrics)(void *handle, void **table); + ssize_t (*get_xcp_metrics)(void *handle, int xcp_id, void *table); ssize_t (*get_pm_metrics)(void *handle, void *pmmetrics, size_t size); int (*set_watermarks_for_clock_ranges)(void *handle, struct pp_smu_wm_range_sets *ranges); @@ -1592,4 +1593,27 @@ struct amdgpu_pm_metrics { uint8_t data[]; }; +struct amdgpu_partition_metrics_v1_0 { + struct metrics_table_header common_header; + /* Current clocks (Mhz) */ + uint16_t current_gfxclk[MAX_XCC]; + uint16_t current_socclk[MAX_CLKS]; + uint16_t current_vclk0[MAX_CLKS]; + uint16_t current_dclk0[MAX_CLKS]; + uint16_t current_uclk; + uint16_t padding; + + /* Utilization Instantaneous (%) */ + uint32_t gfx_busy_inst[MAX_XCC]; + uint16_t jpeg_busy[NUM_JPEG_ENG_V1]; + uint16_t vcn_busy[NUM_VCN]; + /* Utilization Accumulated (%) */ + uint64_t gfx_busy_acc[MAX_XCC]; + /* Total App Clock Counter Accumulated */ + uint64_t gfx_below_host_limit_ppt_acc[MAX_XCC]; + uint64_t gfx_below_host_limit_thm_acc[MAX_XCC]; + uint64_t gfx_low_utilization_acc[MAX_XCC]; + uint64_t gfx_below_host_limit_total_acc[MAX_XCC]; +}; + #endif diff --git a/drivers/gpu/drm/amd/pm/amdgpu_dpm.c b/drivers/gpu/drm/amd/pm/amdgpu_dpm.c index 2148c8db5a59..5c1cbdc122d2 100644 --- a/drivers/gpu/drm/amd/pm/amdgpu_dpm.c +++ b/drivers/gpu/drm/amd/pm/amdgpu_dpm.c @@ -1697,6 +1697,28 @@ int amdgpu_dpm_is_overdrive_supported(struct amdgpu_device *adev) } } +int amdgpu_dpm_is_overdrive_enabled(struct amdgpu_device *adev) +{ + if (is_support_sw_smu(adev)) { + struct smu_context *smu = adev->powerplay.pp_handle; + + return smu->od_enabled; + } else { + struct pp_hwmgr *hwmgr; + + /* + * dpm on some legacy asics don't carry od_enabled member + * as its pp_handle is casted directly from adev. + */ + if (amdgpu_dpm_is_legacy_dpm(adev)) + return false; + + hwmgr = (struct pp_hwmgr *)adev->powerplay.pp_handle; + + return hwmgr->od_enabled; + } +} + int amdgpu_dpm_set_pp_table(struct amdgpu_device *adev, const char *buf, size_t size) @@ -2019,3 +2041,35 @@ int amdgpu_dpm_get_dpm_clock_table(struct amdgpu_device *adev, return ret; } + +/** + * amdgpu_dpm_get_xcp_metrics - Retrieve metrics for a specific compute + * partition + * @adev: Pointer to the device. + * @xcp_id: Identifier of the XCP for which metrics are to be retrieved. + * @table: Pointer to a buffer where the metrics will be stored. If NULL, the + * function returns the size of the metrics structure. + * + * This function retrieves metrics for a specific XCP, including details such as + * VCN/JPEG activity, clock frequencies, and other performance metrics. If the + * table parameter is NULL, the function returns the size of the metrics + * structure without populating it. + * + * Return: Size of the metrics structure on success, or a negative error code on failure. + */ +ssize_t amdgpu_dpm_get_xcp_metrics(struct amdgpu_device *adev, int xcp_id, + void *table) +{ + const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; + int ret = 0; + + if (!pp_funcs->get_xcp_metrics) + return 0; + + mutex_lock(&adev->pm.mutex); + ret = pp_funcs->get_xcp_metrics(adev->powerplay.pp_handle, xcp_id, + table); + mutex_unlock(&adev->pm.mutex); + + return ret; +} diff --git a/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h b/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h index 2c3c97587dd5..768317ee1486 100644 --- a/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h +++ b/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h @@ -524,6 +524,8 @@ int amdgpu_dpm_get_power_profile_mode(struct amdgpu_device *adev, int amdgpu_dpm_set_power_profile_mode(struct amdgpu_device *adev, long *input, uint32_t size); int amdgpu_dpm_get_gpu_metrics(struct amdgpu_device *adev, void **table); +ssize_t amdgpu_dpm_get_xcp_metrics(struct amdgpu_device *adev, int xcp_id, + void *table); /** * @get_pm_metrics: Get one snapshot of power management metrics from PMFW. The @@ -561,6 +563,7 @@ int amdgpu_dpm_get_smu_prv_buf_details(struct amdgpu_device *adev, void **addr, size_t *size); int amdgpu_dpm_is_overdrive_supported(struct amdgpu_device *adev); +int amdgpu_dpm_is_overdrive_enabled(struct amdgpu_device *adev); int amdgpu_dpm_set_pp_table(struct amdgpu_device *adev, const char *buf, size_t size); diff --git a/drivers/gpu/drm/amd/pm/legacy-dpm/kv_dpm.c b/drivers/gpu/drm/amd/pm/legacy-dpm/kv_dpm.c index 59fae668dc3f..34e71727b27d 100644 --- a/drivers/gpu/drm/amd/pm/legacy-dpm/kv_dpm.c +++ b/drivers/gpu/drm/amd/pm/legacy-dpm/kv_dpm.c @@ -2594,7 +2594,7 @@ static int kv_parse_sys_info_table(struct amdgpu_device *adev) le32_to_cpu(igp_info->info_8.ulNbpStateNClkFreq[i]); } if (le32_to_cpu(igp_info->info_8.ulGPUCapInfo) & - SYS_INFO_GPUCAPS__ENABEL_DFS_BYPASS) + SYS_INFO_GPUCAPS__ENABLE_DFS_BYPASS) pi->caps_enable_dfs_bypass = true; sumo_construct_sclk_voltage_mapping_table(adev, diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu8_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu8_hwmgr.c index 9d3b33446adc..9b20076e26c0 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu8_hwmgr.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu8_hwmgr.c @@ -394,7 +394,7 @@ static int smu8_get_system_info_data(struct pp_hwmgr *hwmgr) } if (le32_to_cpu(info->ulGPUCapInfo) & - SYS_INFO_GPUCAPS__ENABEL_DFS_BYPASS) { + SYS_INFO_GPUCAPS__ENABLE_DFS_BYPASS) { phm_cap_set(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_EnableDFSBypass); } diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c index f24a1d8c77db..d79a1d94661a 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c @@ -3758,6 +3758,19 @@ int smu_set_pm_policy(struct smu_context *smu, enum pp_pm_policy p_type, return ret; } +static ssize_t smu_sys_get_xcp_metrics(void *handle, int xcp_id, void *table) +{ + struct smu_context *smu = handle; + + if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) + return -EOPNOTSUPP; + + if (!smu->adev->xcp_mgr || !smu->ppt_funcs->get_xcp_metrics) + return -EOPNOTSUPP; + + return smu->ppt_funcs->get_xcp_metrics(smu, xcp_id, table); +} + static const struct amd_pm_funcs swsmu_pm_funcs = { /* export for sysfs */ .set_fan_control_mode = smu_set_fan_control_mode, @@ -3816,6 +3829,7 @@ static const struct amd_pm_funcs swsmu_pm_funcs = { .get_uclk_dpm_states = smu_get_uclk_dpm_states, .get_dpm_clock_table = smu_get_dpm_clock_table, .get_smu_prv_buf_details = smu_get_prv_buffer_details, + .get_xcp_metrics = smu_sys_get_xcp_metrics, }; int smu_wait_for_event(struct smu_context *smu, enum smu_event_type event, diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h index d47e32ae4671..9aacc7bc1c69 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h @@ -1466,6 +1466,12 @@ struct pptable_funcs { */ int (*set_wbrf_exclusion_ranges)(struct smu_context *smu, struct freq_band_range *exclusion_ranges); + /** + * @get_xcp_metrics: Get a copy of the partition metrics table from SMU. + * Return: Size of table + */ + ssize_t (*get_xcp_metrics)(struct smu_context *smu, int xcp_id, + void *table); }; typedef enum { diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_6_pmfw.h b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_6_pmfw.h index 3d9e5e967c94..01790a927930 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_6_pmfw.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_6_pmfw.h @@ -127,7 +127,7 @@ typedef enum { VOLTAGE_GUARDBAND_COUNT } GFX_GUARDBAND_e; -#define SMU_METRICS_TABLE_VERSION 0x10 +#define SMU_METRICS_TABLE_VERSION 0x11 // Unified metrics table for smu_v13_0_6 typedef struct __attribute__((packed, aligned(4))) { @@ -463,6 +463,8 @@ typedef struct __attribute__((packed, aligned(4))) { typedef struct { // Telemetry uint32_t InputTelemetryVoltageInmV; + // General info + uint32_t pldmVersion[2]; } StaticMetricsTable_t; #pragma pack(pop) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c index 533d58e57d05..e0d356f93ab0 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c @@ -322,7 +322,63 @@ int smu_v13_0_12_get_smu_metrics_data(struct smu_context *smu, return ret; } -ssize_t smu_v13_0_12_get_gpu_metrics(struct smu_context *smu, void **table) +ssize_t smu_v13_0_12_get_xcp_metrics(struct smu_context *smu, struct amdgpu_xcp *xcp, void *table, void *smu_metrics) +{ + const u8 num_jpeg_rings = NUM_JPEG_RINGS_FW; + struct amdgpu_partition_metrics_v1_0 *xcp_metrics; + struct amdgpu_device *adev = smu->adev; + MetricsTable_t *metrics; + int inst, j, k, idx; + u32 inst_mask; + + metrics = (MetricsTable_t *)smu_metrics; + xcp_metrics = (struct amdgpu_partition_metrics_v1_0 *) table; + smu_cmn_init_partition_metrics(xcp_metrics, 1, 0); + amdgpu_xcp_get_inst_details(xcp, AMDGPU_XCP_VCN, &inst_mask); + idx = 0; + for_each_inst(k, inst_mask) { + /* Both JPEG and VCN has same instance */ + inst = GET_INST(VCN, k); + for (j = 0; j < num_jpeg_rings; ++j) { + xcp_metrics->jpeg_busy[(idx * num_jpeg_rings) + j] = + SMUQ10_ROUND(metrics-> + JpegBusy[(inst * num_jpeg_rings) + j]); + } + xcp_metrics->vcn_busy[idx] = + SMUQ10_ROUND(metrics->VcnBusy[inst]); + xcp_metrics->current_vclk0[idx] = SMUQ10_ROUND( + metrics->VclkFrequency[inst]); + xcp_metrics->current_dclk0[idx] = SMUQ10_ROUND( + metrics->DclkFrequency[inst]); + xcp_metrics->current_socclk[idx] = SMUQ10_ROUND( + metrics->SocclkFrequency[inst]); + + idx++; + } + + xcp_metrics->current_uclk = + SMUQ10_ROUND(metrics->UclkFrequency); + + amdgpu_xcp_get_inst_details(xcp, AMDGPU_XCP_GFX, &inst_mask); + idx = 0; + for_each_inst(k, inst_mask) { + inst = GET_INST(GC, k); + xcp_metrics->current_gfxclk[idx] = SMUQ10_ROUND(metrics->GfxclkFrequency[inst]); + xcp_metrics->gfx_busy_inst[idx] = SMUQ10_ROUND(metrics->GfxBusy[inst]); + xcp_metrics->gfx_busy_acc[idx] = SMUQ10_ROUND(metrics->GfxBusyAcc[inst]); + if (smu_v13_0_6_cap_supported(smu, SMU_CAP(HST_LIMIT_METRICS))) { + xcp_metrics->gfx_below_host_limit_ppt_acc[idx] = SMUQ10_ROUND(metrics->GfxclkBelowHostLimitPptAcc[inst]); + xcp_metrics->gfx_below_host_limit_thm_acc[idx] = SMUQ10_ROUND(metrics->GfxclkBelowHostLimitThmAcc[inst]); + xcp_metrics->gfx_low_utilization_acc[idx] = SMUQ10_ROUND(metrics->GfxclkLowUtilizationAcc[inst]); + xcp_metrics->gfx_below_host_limit_total_acc[idx] = SMUQ10_ROUND(metrics->GfxclkBelowHostLimitTotalAcc[inst]); + } + idx++; + } + + return sizeof(*xcp_metrics); +} + +ssize_t smu_v13_0_12_get_gpu_metrics(struct smu_context *smu, void **table, void *smu_metrics) { struct smu_table_context *smu_table = &smu->smu_table; struct gpu_metrics_v1_8 *gpu_metrics = @@ -334,8 +390,7 @@ ssize_t smu_v13_0_12_get_gpu_metrics(struct smu_context *smu, void **table) struct amdgpu_xcp *xcp; u32 inst_mask; - metrics = kzalloc(sizeof(MetricsTable_t), GFP_KERNEL); - memcpy(metrics, smu_table->metrics_table, sizeof(MetricsTable_t)); + metrics = (MetricsTable_t *)smu_metrics; smu_cmn_init_soft_gpu_metrics(gpu_metrics, 1, 8); @@ -416,13 +471,16 @@ ssize_t smu_v13_0_12_get_gpu_metrics(struct smu_context *smu, void **table) gpu_metrics->mem_activity_acc = SMUQ10_ROUND(metrics->DramBandwidthUtilizationAcc); for (i = 0; i < NUM_XGMI_LINKS; i++) { - gpu_metrics->xgmi_read_data_acc[i] = + j = amdgpu_xgmi_get_ext_link(adev, i); + if (j < 0 || j >= NUM_XGMI_LINKS) + continue; + gpu_metrics->xgmi_read_data_acc[j] = SMUQ10_ROUND(metrics->XgmiReadDataSizeAcc[i]); - gpu_metrics->xgmi_write_data_acc[i] = + gpu_metrics->xgmi_write_data_acc[j] = SMUQ10_ROUND(metrics->XgmiWriteDataSizeAcc[i]); ret = amdgpu_get_xgmi_link_status(adev, i); if (ret >= 0) - gpu_metrics->xgmi_link_status[i] = ret; + gpu_metrics->xgmi_link_status[j] = ret; } gpu_metrics->num_partition = adev->xcp_mgr->num_xcps; @@ -474,7 +532,6 @@ ssize_t smu_v13_0_12_get_gpu_metrics(struct smu_context *smu, void **table) gpu_metrics->firmware_timestamp = metrics->Timestamp; *table = (void *)gpu_metrics; - kfree(metrics); return sizeof(*gpu_metrics); } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c index 7d4ff09be7e8..f00ef7f3f355 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c @@ -312,6 +312,11 @@ static void smu_v13_0_14_init_caps(struct smu_context *smu) smu_v13_0_6_cap_set(smu, SMU_CAP(PER_INST_METRICS)); if (fw_ver >= 0x5551200) smu_v13_0_6_cap_set(smu, SMU_CAP(SDMA_RESET)); + if (fw_ver >= 0x5551600) { + smu_v13_0_6_cap_set(smu, SMU_CAP(STATIC_METRICS)); + smu_v13_0_6_cap_set(smu, SMU_CAP(BOARD_VOLTAGE)); + smu_v13_0_6_cap_set(smu, SMU_CAP(PLDM_VERSION)); + } } static void smu_v13_0_12_init_caps(struct smu_context *smu) @@ -392,10 +397,14 @@ static void smu_v13_0_6_init_caps(struct smu_context *smu) if ((pgm == 7 && fw_ver >= 0x7550E00) || (pgm == 0 && fw_ver >= 0x00557E00)) smu_v13_0_6_cap_set(smu, SMU_CAP(HST_LIMIT_METRICS)); - if (fw_ver >= 0x00557F01) { + if ((pgm == 0 && fw_ver >= 0x00557F01) || + (pgm == 7 && fw_ver >= 0x7551000)) { smu_v13_0_6_cap_set(smu, SMU_CAP(STATIC_METRICS)); smu_v13_0_6_cap_set(smu, SMU_CAP(BOARD_VOLTAGE)); } + if ((pgm == 0 && fw_ver >= 0x00558000) || + (pgm == 7 && fw_ver >= 0x7551000)) + smu_v13_0_6_cap_set(smu, SMU_CAP(PLDM_VERSION)); } if (((pgm == 7) && (fw_ver >= 0x7550700)) || ((pgm == 0) && (fw_ver >= 0x00557900)) || @@ -752,6 +761,11 @@ static void smu_v13_0_6_fill_static_metrics_table(struct smu_context *smu, } dpm_context->board_volt = static_metrics->InputTelemetryVoltageInmV; + + if (smu_v13_0_6_cap_supported(smu, SMU_CAP(PLDM_VERSION)) && + static_metrics->pldmVersion[0] != 0xFFFFFFFF) + smu->adev->firmware.pldm_version = + static_metrics->pldmVersion[0]; } int smu_v13_0_6_get_static_metrics_table(struct smu_context *smu) @@ -2529,6 +2543,126 @@ static int smu_v13_0_6_get_current_pcie_link_speed(struct smu_context *smu) return pcie_gen_to_speed(speed_level + 1); } +static ssize_t smu_v13_0_6_get_xcp_metrics(struct smu_context *smu, int xcp_id, + void *table) +{ + const u8 num_jpeg_rings = AMDGPU_MAX_JPEG_RINGS_4_0_3; + int version = smu_v13_0_6_get_metrics_version(smu); + struct amdgpu_partition_metrics_v1_0 *xcp_metrics; + struct amdgpu_device *adev = smu->adev; + int ret, inst, i, j, k, idx; + MetricsTableV0_t *metrics_v0; + MetricsTableV1_t *metrics_v1; + MetricsTableV2_t *metrics_v2; + struct amdgpu_xcp *xcp; + u32 inst_mask; + bool per_inst; + + if (!table) + return sizeof(*xcp_metrics); + + for_each_xcp(adev->xcp_mgr, xcp, i) { + if (xcp->id == xcp_id) + break; + } + if (i == adev->xcp_mgr->num_xcps) + return -EINVAL; + + xcp_metrics = (struct amdgpu_partition_metrics_v1_0 *)table; + smu_cmn_init_partition_metrics(xcp_metrics, 1, 0); + + metrics_v0 = kzalloc(METRICS_TABLE_SIZE, GFP_KERNEL); + if (!metrics_v0) + return -ENOMEM; + + ret = smu_v13_0_6_get_metrics_table(smu, metrics_v0, false); + if (ret) { + kfree(metrics_v0); + return ret; + } + + if (amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == + IP_VERSION(13, 0, 12) && + smu_v13_0_6_cap_supported(smu, SMU_CAP(STATIC_METRICS))) { + ret = smu_v13_0_12_get_xcp_metrics(smu, xcp, table, metrics_v0); + goto out; + } + + metrics_v1 = (MetricsTableV1_t *)metrics_v0; + metrics_v2 = (MetricsTableV2_t *)metrics_v0; + + per_inst = smu_v13_0_6_cap_supported(smu, SMU_CAP(PER_INST_METRICS)); + + amdgpu_xcp_get_inst_details(xcp, AMDGPU_XCP_VCN, &inst_mask); + idx = 0; + for_each_inst(k, inst_mask) { + /* Both JPEG and VCN has same instances */ + inst = GET_INST(VCN, k); + + for (j = 0; j < num_jpeg_rings; ++j) { + xcp_metrics->jpeg_busy[(idx * num_jpeg_rings) + j] = + SMUQ10_ROUND(GET_METRIC_FIELD( + JpegBusy, + version)[(inst * num_jpeg_rings) + j]); + } + xcp_metrics->vcn_busy[idx] = + SMUQ10_ROUND(GET_METRIC_FIELD(VcnBusy, version)[inst]); + + xcp_metrics->current_vclk0[idx] = SMUQ10_ROUND( + GET_METRIC_FIELD(VclkFrequency, version)[inst]); + xcp_metrics->current_dclk0[idx] = SMUQ10_ROUND( + GET_METRIC_FIELD(DclkFrequency, version)[inst]); + xcp_metrics->current_socclk[idx] = SMUQ10_ROUND( + GET_METRIC_FIELD(SocclkFrequency, version)[inst]); + + idx++; + } + + xcp_metrics->current_uclk = + SMUQ10_ROUND(GET_METRIC_FIELD(UclkFrequency, version)); + + if (per_inst) { + amdgpu_xcp_get_inst_details(xcp, AMDGPU_XCP_GFX, &inst_mask); + idx = 0; + for_each_inst(k, inst_mask) { + inst = GET_INST(GC, k); + xcp_metrics->current_gfxclk[idx] = + SMUQ10_ROUND(GET_METRIC_FIELD(GfxclkFrequency, + version)[inst]); + + xcp_metrics->gfx_busy_inst[idx] = SMUQ10_ROUND( + GET_GPU_METRIC_FIELD(GfxBusy, version)[inst]); + xcp_metrics->gfx_busy_acc[idx] = SMUQ10_ROUND( + GET_GPU_METRIC_FIELD(GfxBusyAcc, + version)[inst]); + if (smu_v13_0_6_cap_supported( + smu, SMU_CAP(HST_LIMIT_METRICS))) { + xcp_metrics->gfx_below_host_limit_ppt_acc + [idx] = SMUQ10_ROUND( + metrics_v0->GfxclkBelowHostLimitPptAcc + [inst]); + xcp_metrics->gfx_below_host_limit_thm_acc + [idx] = SMUQ10_ROUND( + metrics_v0->GfxclkBelowHostLimitThmAcc + [inst]); + xcp_metrics->gfx_low_utilization_acc + [idx] = SMUQ10_ROUND( + metrics_v0 + ->GfxclkLowUtilizationAcc[inst]); + xcp_metrics->gfx_below_host_limit_total_acc + [idx] = SMUQ10_ROUND( + metrics_v0->GfxclkBelowHostLimitTotalAcc + [inst]); + } + idx++; + } + } +out: + kfree(metrics_v0); + + return sizeof(*xcp_metrics); +} + static ssize_t smu_v13_0_6_get_gpu_metrics(struct smu_context *smu, void **table) { struct smu_table_context *smu_table = &smu->smu_table; @@ -2542,6 +2676,7 @@ static ssize_t smu_v13_0_6_get_gpu_metrics(struct smu_context *smu, void **table MetricsTableV2_t *metrics_v2; struct amdgpu_xcp *xcp; u16 link_width_level; + ssize_t num_bytes; u8 num_jpeg_rings; u32 inst_mask; bool per_inst; @@ -2554,8 +2689,11 @@ static ssize_t smu_v13_0_6_get_gpu_metrics(struct smu_context *smu, void **table } if (amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 12) && - smu_v13_0_6_cap_supported(smu, SMU_CAP(STATIC_METRICS))) - return smu_v13_0_12_get_gpu_metrics(smu, table); + smu_v13_0_6_cap_supported(smu, SMU_CAP(STATIC_METRICS))) { + num_bytes = smu_v13_0_12_get_gpu_metrics(smu, table, metrics_v0); + kfree(metrics_v0); + return num_bytes; + } metrics_v1 = (MetricsTableV1_t *)metrics_v0; metrics_v2 = (MetricsTableV2_t *)metrics_v0; @@ -2670,13 +2808,16 @@ static ssize_t smu_v13_0_6_get_gpu_metrics(struct smu_context *smu, void **table SMUQ10_ROUND(GET_METRIC_FIELD(DramBandwidthUtilizationAcc, version)); for (i = 0; i < NUM_XGMI_LINKS; i++) { - gpu_metrics->xgmi_read_data_acc[i] = - SMUQ10_ROUND(GET_METRIC_FIELD(XgmiReadDataSizeAcc, version)[i]); - gpu_metrics->xgmi_write_data_acc[i] = - SMUQ10_ROUND(GET_METRIC_FIELD(XgmiWriteDataSizeAcc, version)[i]); + j = amdgpu_xgmi_get_ext_link(adev, i); + if (j < 0 || j >= NUM_XGMI_LINKS) + continue; + gpu_metrics->xgmi_read_data_acc[j] = SMUQ10_ROUND( + GET_METRIC_FIELD(XgmiReadDataSizeAcc, version)[i]); + gpu_metrics->xgmi_write_data_acc[j] = SMUQ10_ROUND( + GET_METRIC_FIELD(XgmiWriteDataSizeAcc, version)[i]); ret = amdgpu_get_xgmi_link_status(adev, i); if (ret >= 0) - gpu_metrics->xgmi_link_status[i] = ret; + gpu_metrics->xgmi_link_status[j] = ret; } gpu_metrics->num_partition = adev->xcp_mgr->num_xcps; @@ -3673,6 +3814,7 @@ static const struct pptable_funcs smu_v13_0_6_ppt_funcs = { .get_pp_feature_mask = smu_cmn_get_pp_feature_mask, .get_gpu_metrics = smu_v13_0_6_get_gpu_metrics, .get_pm_metrics = smu_v13_0_6_get_pm_metrics, + .get_xcp_metrics = smu_v13_0_6_get_xcp_metrics, .get_thermal_temperature_range = smu_v13_0_6_get_thermal_temperature_range, .mode1_reset_is_support = smu_v13_0_6_is_mode1_reset_supported, .link_reset_is_support = smu_v13_0_6_is_link_reset_supported, diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.h b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.h index d151bcd0cca7..d38d6d76b1e7 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.h +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.h @@ -67,6 +67,7 @@ enum smu_v13_0_6_caps { SMU_CAP(STATIC_METRICS), SMU_CAP(HST_LIMIT_METRICS), SMU_CAP(BOARD_VOLTAGE), + SMU_CAP(PLDM_VERSION), SMU_CAP(ALL), }; @@ -79,7 +80,10 @@ int smu_v13_0_12_get_max_metrics_size(void); int smu_v13_0_12_setup_driver_pptable(struct smu_context *smu); int smu_v13_0_12_get_smu_metrics_data(struct smu_context *smu, MetricsMember_t member, uint32_t *value); -ssize_t smu_v13_0_12_get_gpu_metrics(struct smu_context *smu, void **table); +ssize_t smu_v13_0_12_get_gpu_metrics(struct smu_context *smu, void **table, void *smu_metrics); +ssize_t smu_v13_0_12_get_xcp_metrics(struct smu_context *smu, + struct amdgpu_xcp *xcp, void *table, + void *smu_metrics); extern const struct cmn2asic_mapping smu_v13_0_12_feature_mask_map[]; extern const struct cmn2asic_msg_mapping smu_v13_0_12_message_map[]; #endif diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c index 80eb1a03b3ca..7eaf58fd7f9a 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c @@ -1051,73 +1051,6 @@ int smu_cmn_get_combo_pptable(struct smu_context *smu) false); } -void smu_cmn_init_soft_gpu_metrics(void *table, uint8_t frev, uint8_t crev) -{ - struct metrics_table_header *header = (struct metrics_table_header *)table; - uint16_t structure_size; - -#define METRICS_VERSION(a, b) ((a << 16) | b) - - switch (METRICS_VERSION(frev, crev)) { - case METRICS_VERSION(1, 0): - structure_size = sizeof(struct gpu_metrics_v1_0); - break; - case METRICS_VERSION(1, 1): - structure_size = sizeof(struct gpu_metrics_v1_1); - break; - case METRICS_VERSION(1, 2): - structure_size = sizeof(struct gpu_metrics_v1_2); - break; - case METRICS_VERSION(1, 3): - structure_size = sizeof(struct gpu_metrics_v1_3); - break; - case METRICS_VERSION(1, 4): - structure_size = sizeof(struct gpu_metrics_v1_4); - break; - case METRICS_VERSION(1, 5): - structure_size = sizeof(struct gpu_metrics_v1_5); - break; - case METRICS_VERSION(1, 6): - structure_size = sizeof(struct gpu_metrics_v1_6); - break; - case METRICS_VERSION(1, 7): - structure_size = sizeof(struct gpu_metrics_v1_7); - break; - case METRICS_VERSION(1, 8): - structure_size = sizeof(struct gpu_metrics_v1_8); - break; - case METRICS_VERSION(2, 0): - structure_size = sizeof(struct gpu_metrics_v2_0); - break; - case METRICS_VERSION(2, 1): - structure_size = sizeof(struct gpu_metrics_v2_1); - break; - case METRICS_VERSION(2, 2): - structure_size = sizeof(struct gpu_metrics_v2_2); - break; - case METRICS_VERSION(2, 3): - structure_size = sizeof(struct gpu_metrics_v2_3); - break; - case METRICS_VERSION(2, 4): - structure_size = sizeof(struct gpu_metrics_v2_4); - break; - case METRICS_VERSION(3, 0): - structure_size = sizeof(struct gpu_metrics_v3_0); - break; - default: - return; - } - -#undef METRICS_VERSION - - memset(header, 0xFF, structure_size); - - header->format_revision = frev; - header->content_revision = crev; - header->structure_size = structure_size; - -} - int smu_cmn_set_mp1_state(struct smu_context *smu, enum pp_mp1_state mp1_state) { diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h index a020277dec3e..7473672abd2a 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h @@ -40,6 +40,30 @@ #define SMU_IH_INTERRUPT_CONTEXT_ID_FAN_ABNORMAL 0x8 #define SMU_IH_INTERRUPT_CONTEXT_ID_FAN_RECOVERY 0x9 +#define smu_cmn_init_soft_gpu_metrics(ptr, frev, crev) \ + do { \ + typecheck(struct gpu_metrics_v##frev##_##crev, \ + typeof(*(ptr))); \ + struct metrics_table_header *header = \ + (struct metrics_table_header *)(ptr); \ + memset(header, 0xFF, sizeof(*(ptr))); \ + header->format_revision = frev; \ + header->content_revision = crev; \ + header->structure_size = sizeof(*(ptr)); \ + } while (0) + +#define smu_cmn_init_partition_metrics(ptr, frev, crev) \ + do { \ + typecheck(struct amdgpu_partition_metrics_v##frev##_##crev, \ + typeof(*(ptr))); \ + struct metrics_table_header *header = \ + (struct metrics_table_header *)(ptr); \ + memset(header, 0xFF, sizeof(*(ptr))); \ + header->format_revision = frev; \ + header->content_revision = crev; \ + header->structure_size = sizeof(*(ptr)); \ + } while (0) + extern const int link_speed[]; /* Helper to Convert from PCIE Gen 1/2/3/4/5/6 to 0.1 GT/s speed units */ @@ -125,8 +149,6 @@ int smu_cmn_get_metrics_table(struct smu_context *smu, int smu_cmn_get_combo_pptable(struct smu_context *smu); -void smu_cmn_init_soft_gpu_metrics(void *table, uint8_t frev, uint8_t crev); - int smu_cmn_set_mp1_state(struct smu_context *smu, enum pp_mp1_state mp1_state); diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index a761941bc3c2..505eec6b819b 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -1531,10 +1531,8 @@ analogix_dp_probe(struct device *dev, struct analogix_dp_plat_data *plat_data) } dp->reg_base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(dp->reg_base)) { - ret = PTR_ERR(dp->reg_base); - goto err_disable_clk; - } + if (IS_ERR(dp->reg_base)) + return ERR_CAST(dp->reg_base); dp->force_hpd = of_property_read_bool(dev->of_node, "force-hpd"); @@ -1546,8 +1544,7 @@ analogix_dp_probe(struct device *dev, struct analogix_dp_plat_data *plat_data) if (IS_ERR(dp->hpd_gpiod)) { dev_err(dev, "error getting HDP GPIO: %ld\n", PTR_ERR(dp->hpd_gpiod)); - ret = PTR_ERR(dp->hpd_gpiod); - goto err_disable_clk; + return ERR_CAST(dp->hpd_gpiod); } if (dp->hpd_gpiod) { @@ -1567,8 +1564,7 @@ analogix_dp_probe(struct device *dev, struct analogix_dp_plat_data *plat_data) if (dp->irq == -ENXIO) { dev_err(&pdev->dev, "failed to get irq\n"); - ret = -ENODEV; - goto err_disable_clk; + return ERR_PTR(-ENODEV); } ret = devm_request_threaded_irq(&pdev->dev, dp->irq, @@ -1577,7 +1573,7 @@ analogix_dp_probe(struct device *dev, struct analogix_dp_plat_data *plat_data) irq_flags, "analogix-dp", dp); if (ret) { dev_err(&pdev->dev, "failed to request irq\n"); - goto err_disable_clk; + return ERR_PTR(ret); } dp->aux.name = "DP-AUX"; @@ -1590,13 +1586,9 @@ analogix_dp_probe(struct device *dev, struct analogix_dp_plat_data *plat_data) pm_runtime_set_autosuspend_delay(dp->dev, 100); ret = devm_pm_runtime_enable(dp->dev); if (ret) - goto err_disable_clk; + return ERR_PTR(ret); return dp; - -err_disable_clk: - clk_disable_unprepare(dp->clock); - return ERR_PTR(ret); } EXPORT_SYMBOL_GPL(analogix_dp_probe); diff --git a/drivers/gpu/drm/bridge/tda998x_drv.c b/drivers/gpu/drm/bridge/tda998x_drv.c index 850909f78a7b..e636459d9185 100644 --- a/drivers/gpu/drm/bridge/tda998x_drv.c +++ b/drivers/gpu/drm/bridge/tda998x_drv.c @@ -751,7 +751,8 @@ tda998x_reset(struct tda998x_priv *priv) */ static void tda998x_edid_delay_done(struct timer_list *t) { - struct tda998x_priv *priv = from_timer(priv, t, edid_delay_timer); + struct tda998x_priv *priv = timer_container_of(priv, t, + edid_delay_timer); priv->edid_delay_active = false; wake_up(&priv->edid_delay_waitq); diff --git a/drivers/gpu/drm/display/drm_hdmi_audio_helper.c b/drivers/gpu/drm/display/drm_hdmi_audio_helper.c index 05afc9f0bdd6..ae8a0cf595fc 100644 --- a/drivers/gpu/drm/display/drm_hdmi_audio_helper.c +++ b/drivers/gpu/drm/display/drm_hdmi_audio_helper.c @@ -103,7 +103,8 @@ static int drm_connector_hdmi_audio_hook_plugged_cb(struct device *dev, connector->hdmi_audio.plugged_cb = fn; connector->hdmi_audio.plugged_cb_dev = codec_dev; - fn(codec_dev, connector->hdmi_audio.last_state); + if (fn) + fn(codec_dev, connector->hdmi_audio.last_state); mutex_unlock(&connector->hdmi_audio.lock); diff --git a/drivers/gpu/drm/drm_vblank.c b/drivers/gpu/drm/drm_vblank.c index 78958ddf8485..46f59883183d 100644 --- a/drivers/gpu/drm/drm_vblank.c +++ b/drivers/gpu/drm/drm_vblank.c @@ -487,7 +487,8 @@ out: static void vblank_disable_fn(struct timer_list *t) { - struct drm_vblank_crtc *vblank = from_timer(vblank, t, disable_timer); + struct drm_vblank_crtc *vblank = timer_container_of(vblank, t, + disable_timer); struct drm_device *dev = vblank->dev; unsigned int pipe = vblank->pipe; unsigned long irqflags; diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c index e644e2382d77..e094b8bbc0f1 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c @@ -159,7 +159,7 @@ static const struct exynos_drm_crtc_ops vidi_crtc_ops = { static void vidi_fake_vblank_timer(struct timer_list *t) { - struct vidi_context *ctx = from_timer(ctx, t, timer); + struct vidi_context *ctx = timer_container_of(ctx, t, timer); if (drm_crtc_handle_vblank(&ctx->crtc->base)) mod_timer(&ctx->timer, diff --git a/drivers/gpu/drm/gud/gud_pipe.c b/drivers/gpu/drm/gud/gud_pipe.c index feff73cc0005..adadd526641d 100644 --- a/drivers/gpu/drm/gud/gud_pipe.c +++ b/drivers/gpu/drm/gud/gud_pipe.c @@ -234,7 +234,7 @@ struct gud_usb_bulk_context { static void gud_usb_bulk_timeout(struct timer_list *t) { - struct gud_usb_bulk_context *ctx = from_timer(ctx, t, timer); + struct gud_usb_bulk_context *ctx = timer_container_of(ctx, t, timer); usb_sg_cancel(&ctx->sgr); } diff --git a/drivers/gpu/drm/i915/display/intel_audio.c b/drivers/gpu/drm/i915/display/intel_audio.c index 40d8bbd8107d..55af3a553c58 100644 --- a/drivers/gpu/drm/i915/display/intel_audio.c +++ b/drivers/gpu/drm/i915/display/intel_audio.c @@ -397,6 +397,19 @@ hsw_audio_config_update(struct intel_encoder *encoder, hsw_hdmi_audio_config_update(encoder, crtc_state); } +static void intel_audio_sdp_split_update(const struct intel_crtc_state *crtc_state, + bool enable) +{ + struct intel_display *display = to_intel_display(crtc_state); + enum transcoder trans = crtc_state->cpu_transcoder; + + if (!HAS_DP20(display)) + return; + + intel_de_rmw(display, AUD_DP_2DOT0_CTRL(trans), AUD_ENABLE_SDP_SPLIT, + enable && crtc_state->sdp_split_enable ? AUD_ENABLE_SDP_SPLIT : 0); +} + static void hsw_audio_codec_disable(struct intel_encoder *encoder, const struct intel_crtc_state *old_crtc_state, const struct drm_connector_state *old_conn_state) @@ -430,6 +443,8 @@ static void hsw_audio_codec_disable(struct intel_encoder *encoder, if (needs_wa_14020863754(display)) intel_de_rmw(display, AUD_CHICKENBIT_REG3, DACBE_DISABLE_MIN_HBLANK_FIX, 0); + intel_audio_sdp_split_update(old_crtc_state, false); + mutex_unlock(&display->audio.mutex); } @@ -555,6 +570,8 @@ static void hsw_audio_codec_enable(struct intel_encoder *encoder, if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP)) enable_audio_dsc_wa(encoder, crtc_state); + intel_audio_sdp_split_update(crtc_state, true); + if (needs_wa_14020863754(display)) intel_de_rmw(display, AUD_CHICKENBIT_REG3, 0, DACBE_DISABLE_MIN_HBLANK_FIX); @@ -681,16 +698,6 @@ static void ibx_audio_codec_enable(struct intel_encoder *encoder, mutex_unlock(&display->audio.mutex); } -void intel_audio_sdp_split_update(const struct intel_crtc_state *crtc_state) -{ - struct intel_display *display = to_intel_display(crtc_state); - enum transcoder trans = crtc_state->cpu_transcoder; - - if (HAS_DP20(display)) - intel_de_rmw(display, AUD_DP_2DOT0_CTRL(trans), AUD_ENABLE_SDP_SPLIT, - crtc_state->sdp_split_enable ? AUD_ENABLE_SDP_SPLIT : 0); -} - bool intel_audio_compute_config(struct intel_encoder *encoder, struct intel_crtc_state *crtc_state, struct drm_connector_state *conn_state) diff --git a/drivers/gpu/drm/i915/display/intel_audio.h b/drivers/gpu/drm/i915/display/intel_audio.h index ad49eefa7182..42cf886f3d24 100644 --- a/drivers/gpu/drm/i915/display/intel_audio.h +++ b/drivers/gpu/drm/i915/display/intel_audio.h @@ -31,6 +31,5 @@ int intel_audio_min_cdclk(const struct intel_crtc_state *crtc_state); void intel_audio_init(struct intel_display *display); void intel_audio_register(struct intel_display *display); void intel_audio_deinit(struct intel_display *display); -void intel_audio_sdp_split_update(const struct intel_crtc_state *crtc_state); #endif /* __INTEL_AUDIO_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 74132c1d6385..d58f8fc37326 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -3507,9 +3507,6 @@ static void intel_ddi_enable(struct intel_atomic_state *state, intel_vrr_transcoder_enable(crtc_state); - /* Enable/Disable DP2.0 SDP split config before transcoder */ - intel_audio_sdp_split_update(crtc_state); - /* 128b/132b SST */ if (!is_hdmi && intel_dp_is_uhbr(crtc_state)) { struct intel_dp *intel_dp = enc_to_intel_dp(encoder); diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c index 06f4ad8de591..e1501b13f08f 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c @@ -1328,8 +1328,6 @@ static void mst_stream_enable(struct intel_atomic_state *state, FECSTALL_DIS_DPTSTREAM_DPTTG, pipe_config->fec_enable ? FECSTALL_DIS_DPTSTREAM_DPTTG : 0); - intel_audio_sdp_split_update(pipe_config); - intel_enable_transcoder(pipe_config); for_each_pipe_crtc_modeset_enable(display, pipe_crtc, pipe_config, i) { diff --git a/drivers/gpu/drm/i915/display/intel_psr_regs.h b/drivers/gpu/drm/i915/display/intel_psr_regs.h index 795e6b9cc575..248136456048 100644 --- a/drivers/gpu/drm/i915/display/intel_psr_regs.h +++ b/drivers/gpu/drm/i915/display/intel_psr_regs.h @@ -325,8 +325,8 @@ #define PORT_ALPM_LFPS_CTL_LFPS_HALF_CYCLE_DURATION_MASK REG_GENMASK(20, 16) #define PORT_ALPM_LFPS_CTL_LFPS_HALF_CYCLE_DURATION(val) REG_FIELD_PREP(PORT_ALPM_LFPS_CTL_LFPS_HALF_CYCLE_DURATION_MASK, val) #define PORT_ALPM_LFPS_CTL_FIRST_LFPS_HALF_CYCLE_DURATION_MASK REG_GENMASK(12, 8) -#define PORT_ALPM_LFPS_CTL_FIRST_LFPS_HALF_CYCLE_DURATION(val) REG_FIELD_PREP(PORT_ALPM_LFPS_CTL_LFPS_HALF_CYCLE_DURATION_MASK, val) +#define PORT_ALPM_LFPS_CTL_FIRST_LFPS_HALF_CYCLE_DURATION(val) REG_FIELD_PREP(PORT_ALPM_LFPS_CTL_FIRST_LFPS_HALF_CYCLE_DURATION_MASK, val) #define PORT_ALPM_LFPS_CTL_LAST_LFPS_HALF_CYCLE_DURATION_MASK REG_GENMASK(4, 0) -#define PORT_ALPM_LFPS_CTL_LAST_LFPS_HALF_CYCLE_DURATION(val) REG_FIELD_PREP(PORT_ALPM_LFPS_CTL_LFPS_HALF_CYCLE_DURATION_MASK, val) +#define PORT_ALPM_LFPS_CTL_LAST_LFPS_HALF_CYCLE_DURATION(val) REG_FIELD_PREP(PORT_ALPM_LFPS_CTL_LAST_LFPS_HALF_CYCLE_DURATION_MASK, val) #endif /* __INTEL_PSR_REGS_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_snps_hdmi_pll.c b/drivers/gpu/drm/i915/display/intel_snps_hdmi_pll.c index c6321dafef4f..74bb3bedf30f 100644 --- a/drivers/gpu/drm/i915/display/intel_snps_hdmi_pll.c +++ b/drivers/gpu/drm/i915/display/intel_snps_hdmi_pll.c @@ -41,12 +41,12 @@ static s64 interp(s64 x, s64 x1, s64 x2, s64 y1, s64 y2) { s64 dydx; - dydx = DIV_ROUND_UP_ULL((y2 - y1) * 100000, (x2 - x1)); + dydx = DIV64_U64_ROUND_UP((y2 - y1) * 100000, (x2 - x1)); - return (y1 + DIV_ROUND_UP_ULL(dydx * (x - x1), 100000)); + return (y1 + DIV64_U64_ROUND_UP(dydx * (x - x1), 100000)); } -static void get_ana_cp_int_prop(u32 vco_clk, +static void get_ana_cp_int_prop(u64 vco_clk, u32 refclk_postscalar, int mpll_ana_v2i, int c, int a, @@ -115,16 +115,16 @@ static void get_ana_cp_int_prop(u32 vco_clk, CURVE0_MULTIPLIER)); scaled_interpolated_sqrt = - int_sqrt(DIV_ROUND_UP_ULL(interpolated_product, vco_div_refclk_float) * + int_sqrt(DIV64_U64_ROUND_UP(interpolated_product, vco_div_refclk_float) * DIV_ROUND_DOWN_ULL(1000000000000ULL, 55)); /* Scale vco_div_refclk for ana_cp_int */ scaled_vco_div_refclk2 = DIV_ROUND_UP_ULL(vco_div_refclk_float, 1000000); - adjusted_vco_clk2 = 1460281 * DIV_ROUND_UP_ULL(scaled_interpolated_sqrt * + adjusted_vco_clk2 = 1460281 * DIV64_U64_ROUND_UP(scaled_interpolated_sqrt * scaled_vco_div_refclk2, curve_1_interpolated); - *ana_cp_prop = DIV_ROUND_UP_ULL(adjusted_vco_clk2, curve_2_scaled2); + *ana_cp_prop = DIV64_U64_ROUND_UP(adjusted_vco_clk2, curve_2_scaled2); *ana_cp_prop = max(1, min(*ana_cp_prop, 127)); } @@ -165,10 +165,10 @@ static void compute_hdmi_tmds_pll(u64 pixel_clock, u32 refclk, /* Select appropriate v2i point */ if (datarate <= INTEL_SNPS_PHY_HDMI_9999MHZ) { mpll_ana_v2i = 2; - tx_clk_div = ilog2(DIV_ROUND_DOWN_ULL(INTEL_SNPS_PHY_HDMI_9999MHZ, datarate)); + tx_clk_div = ilog2(div64_u64(INTEL_SNPS_PHY_HDMI_9999MHZ, datarate)); } else { mpll_ana_v2i = 3; - tx_clk_div = ilog2(DIV_ROUND_DOWN_ULL(INTEL_SNPS_PHY_HDMI_16GHZ, datarate)); + tx_clk_div = ilog2(div64_u64(INTEL_SNPS_PHY_HDMI_16GHZ, datarate)); } vco_clk = (datarate << tx_clk_div) >> 1; diff --git a/drivers/gpu/drm/i915/gt/intel_rps.c b/drivers/gpu/drm/i915/gt/intel_rps.c index 5abc5fcc2514..eb89948cc112 100644 --- a/drivers/gpu/drm/i915/gt/intel_rps.c +++ b/drivers/gpu/drm/i915/gt/intel_rps.c @@ -74,7 +74,7 @@ static void set(struct intel_uncore *uncore, i915_reg_t reg, u32 val) static void rps_timer(struct timer_list *t) { - struct intel_rps *rps = from_timer(rps, t, timer); + struct intel_rps *rps = timer_container_of(rps, t, timer); struct intel_gt *gt = rps_to_gt(rps); struct intel_engine_cs *engine; ktime_t dt, last, timestamp; diff --git a/drivers/gpu/drm/i915/gt/mock_engine.c b/drivers/gpu/drm/i915/gt/mock_engine.c index 64315b714743..79741f043f03 100644 --- a/drivers/gpu/drm/i915/gt/mock_engine.c +++ b/drivers/gpu/drm/i915/gt/mock_engine.c @@ -108,7 +108,7 @@ static void advance(struct i915_request *request) static void hw_delay_complete(struct timer_list *t) { - struct mock_engine *engine = from_timer(engine, t, hw_delay); + struct mock_engine *engine = timer_container_of(engine, t, hw_delay); struct i915_request *request; unsigned long flags; diff --git a/drivers/gpu/drm/i915/gt/selftest_migrate.c b/drivers/gpu/drm/i915/gt/selftest_migrate.c index 32c762eb79ed..54bc447efce0 100644 --- a/drivers/gpu/drm/i915/gt/selftest_migrate.c +++ b/drivers/gpu/drm/i915/gt/selftest_migrate.c @@ -537,7 +537,7 @@ struct spinner_timer { static void spinner_kill(struct timer_list *timer) { - struct spinner_timer *st = from_timer(st, timer, timer); + struct spinner_timer *st = timer_container_of(st, timer, timer); igt_spinner_end(&st->spin); pr_info("%s\n", __func__); diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c index f8cb7c630d5b..127316d2c8aa 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c @@ -633,7 +633,7 @@ static int guc_submission_send_busy_loop(struct intel_guc *guc, atomic_inc(&guc->outstanding_submission_g2h); ret = intel_guc_send_busy_loop(guc, action, len, g2h_len_dw, loop); - if (ret) + if (ret && g2h_len_dw) atomic_dec(&guc->outstanding_submission_g2h); return ret; @@ -3443,18 +3443,29 @@ static inline int guc_lrc_desc_unpin(struct intel_context *ce) * GuC is active, lets destroy this context, but at this point we can still be racing * with suspend, so we undo everything if the H2G fails in deregister_context so * that GuC reset will find this context during clean up. + * + * There is a race condition where the reset code could have altered + * this context's state and done a wakeref put before we try to + * deregister it here. So check if the context is still set to be + * destroyed before undoing earlier changes, to avoid two wakeref puts + * on the same context. */ ret = deregister_context(ce, ce->guc_id.id); if (ret) { + bool pending_destroyed; spin_lock_irqsave(&ce->guc_state.lock, flags); - set_context_registered(ce); - clr_context_destroyed(ce); + pending_destroyed = context_destroyed(ce); + if (pending_destroyed) { + set_context_registered(ce); + clr_context_destroyed(ce); + } spin_unlock_irqrestore(&ce->guc_state.lock, flags); /* * As gt-pm is awake at function entry, intel_wakeref_put_async merely decrements * the wakeref immediately but per function spec usage call this after unlock. */ - intel_wakeref_put_async(>->wakeref); + if (pending_destroyed) + intel_wakeref_put_async(>->wakeref); } return ret; diff --git a/drivers/gpu/drm/i915/i915_sw_fence.c b/drivers/gpu/drm/i915/i915_sw_fence.c index 1d4cc91c0e40..a4902ee08b6e 100644 --- a/drivers/gpu/drm/i915/i915_sw_fence.c +++ b/drivers/gpu/drm/i915/i915_sw_fence.c @@ -427,7 +427,8 @@ static void dma_i915_sw_fence_wake(struct dma_fence *dma, static void timer_i915_sw_fence_wake(struct timer_list *t) { - struct i915_sw_dma_fence_cb_timer *cb = from_timer(cb, t, timer); + struct i915_sw_dma_fence_cb_timer *cb = timer_container_of(cb, t, + timer); struct i915_sw_fence *fence; fence = xchg(&cb->base.fence, NULL); diff --git a/drivers/gpu/drm/i915/intel_wakeref.c b/drivers/gpu/drm/i915/intel_wakeref.c index 07e81be4d392..51561b190b93 100644 --- a/drivers/gpu/drm/i915/intel_wakeref.c +++ b/drivers/gpu/drm/i915/intel_wakeref.c @@ -135,7 +135,7 @@ int intel_wakeref_wait_for_idle(struct intel_wakeref *wf) static void wakeref_auto_timeout(struct timer_list *t) { - struct intel_wakeref_auto *wf = from_timer(wf, t, timer); + struct intel_wakeref_auto *wf = timer_container_of(wf, t, timer); intel_wakeref_t wakeref; unsigned long flags; diff --git a/drivers/gpu/drm/i915/selftests/lib_sw_fence.c b/drivers/gpu/drm/i915/selftests/lib_sw_fence.c index 522ad49406ce..d79e4defb71d 100644 --- a/drivers/gpu/drm/i915/selftests/lib_sw_fence.c +++ b/drivers/gpu/drm/i915/selftests/lib_sw_fence.c @@ -55,7 +55,7 @@ void onstack_fence_fini(struct i915_sw_fence *fence) static void timed_fence_wake(struct timer_list *t) { - struct timed_fence *tf = from_timer(tf, t, timer); + struct timed_fence *tf = timer_container_of(tf, t, timer); i915_sw_fence_commit(&tf->fence); } diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c b/drivers/gpu/drm/mediatek/mtk_dp.c index b2408abb9d49..58279ddaab3c 100644 --- a/drivers/gpu/drm/mediatek/mtk_dp.c +++ b/drivers/gpu/drm/mediatek/mtk_dp.c @@ -2569,7 +2569,7 @@ static const struct drm_bridge_funcs mtk_dp_bridge_funcs = { static void mtk_dp_debounce_timer(struct timer_list *t) { - struct mtk_dp *mtk_dp = from_timer(mtk_dp, t, debounce_timer); + struct mtk_dp *mtk_dp = timer_container_of(mtk_dp, t, debounce_timer); mtk_dp->need_debounce = true; } diff --git a/drivers/gpu/drm/msm/adreno/a5xx_preempt.c b/drivers/gpu/drm/msm/adreno/a5xx_preempt.c index 36f72c43eae8..b5f9d40687d5 100644 --- a/drivers/gpu/drm/msm/adreno/a5xx_preempt.c +++ b/drivers/gpu/drm/msm/adreno/a5xx_preempt.c @@ -79,7 +79,8 @@ static struct msm_ringbuffer *get_next_ring(struct msm_gpu *gpu) static void a5xx_preempt_timer(struct timer_list *t) { - struct a5xx_gpu *a5xx_gpu = from_timer(a5xx_gpu, t, preempt_timer); + struct a5xx_gpu *a5xx_gpu = timer_container_of(a5xx_gpu, t, + preempt_timer); struct msm_gpu *gpu = &a5xx_gpu->base.base; struct drm_device *dev = gpu->dev; diff --git a/drivers/gpu/drm/msm/adreno/a6xx_preempt.c b/drivers/gpu/drm/msm/adreno/a6xx_preempt.c index 9b5e27d2373c..3b17fd2dba89 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_preempt.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_preempt.c @@ -87,7 +87,8 @@ static struct msm_ringbuffer *get_next_ring(struct msm_gpu *gpu) static void a6xx_preempt_timer(struct timer_list *t) { - struct a6xx_gpu *a6xx_gpu = from_timer(a6xx_gpu, t, preempt_timer); + struct a6xx_gpu *a6xx_gpu = timer_container_of(a6xx_gpu, t, + preempt_timer); struct msm_gpu *gpu = &a6xx_gpu->base.base; struct drm_device *dev = gpu->dev; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c index 7020098360e4..c0ed110a7d30 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c @@ -2693,8 +2693,8 @@ static int dpu_encoder_setup_display(struct dpu_encoder_virt *dpu_enc, static void dpu_encoder_frame_done_timeout(struct timer_list *t) { - struct dpu_encoder_virt *dpu_enc = from_timer(dpu_enc, t, - frame_done_timer); + struct dpu_encoder_virt *dpu_enc = timer_container_of(dpu_enc, t, + frame_done_timer); struct drm_encoder *drm_enc = &dpu_enc->base; u32 event; diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c index c380d9d9f5af..197871fdf508 100644 --- a/drivers/gpu/drm/msm/msm_gpu.c +++ b/drivers/gpu/drm/msm/msm_gpu.c @@ -521,7 +521,7 @@ static bool made_progress(struct msm_gpu *gpu, struct msm_ringbuffer *ring) static void hangcheck_handler(struct timer_list *t) { - struct msm_gpu *gpu = from_timer(gpu, t, hangcheck_timer); + struct msm_gpu *gpu = timer_container_of(gpu, t, hangcheck_timer); struct drm_device *dev = gpu->dev; struct msm_ringbuffer *ring = gpu->funcs->active_ring(gpu); uint32_t fence = ring->memptrs->fence; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/vfn/r535.c b/drivers/gpu/drm/nouveau/nvkm/subdev/vfn/r535.c index 9446049642e1..d294844d9eae 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/vfn/r535.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/vfn/r535.c @@ -42,7 +42,7 @@ r535_vfn_new(const struct nvkm_vfn_func *hw, return -ENOMEM; rm->dtor = r535_vfn_dtor; - rm->intr = &tu102_vfn_intr, + rm->intr = &tu102_vfn_intr; rm->user.addr = 0x030000; rm->user.size = 0x010000; rm->user.base.minver = -1; diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index 721581d425b4..cfebb08e8a62 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -522,6 +522,8 @@ config DRM_PANEL_NOVATEK_NT37801 depends on OF depends on DRM_MIPI_DSI depends on BACKLIGHT_CLASS_DEVICE + select DRM_DISPLAY_DSC_HELPER + select DRM_DISPLAY_HELPER help Say Y here if you want to enable support for Novatek NT37801 (or NT37810) AMOLED DSI Video Mode LCD panel module with 1440x3200 diff --git a/drivers/gpu/drm/panel/panel-novatek-nt37801.c b/drivers/gpu/drm/panel/panel-novatek-nt37801.c index 84d367eab058..d6a37d7e0cc6 100644 --- a/drivers/gpu/drm/panel/panel-novatek-nt37801.c +++ b/drivers/gpu/drm/panel/panel-novatek-nt37801.c @@ -257,8 +257,8 @@ static int novatek_nt37801_probe(struct mipi_dsi_device *dsi) ctx = devm_drm_panel_alloc(dev, struct novatek_nt37801, panel, &novatek_nt37801_panel_funcs, DRM_MODE_CONNECTOR_DSI); - if (!ctx) - return -ENOMEM; + if (IS_ERR(ctx)) + return PTR_ERR(ctx); ret = devm_regulator_bulk_get_const(dev, ARRAY_SIZE(novatek_nt37801_supplies), diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index 82ee2f12b8d2..0a3b26bb4d73 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -2198,13 +2198,14 @@ static const struct display_timing evervision_vgg644804_timing = { static const struct panel_desc evervision_vgg644804 = { .timings = &evervision_vgg644804_timing, .num_timings = 1, - .bpc = 8, + .bpc = 6, .size = { .width = 115, .height = 86, }, .bus_format = MEDIA_BUS_FMT_RGB666_1X7X3_SPWG, - .bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE, + .bus_flags = DRM_BUS_FLAG_DE_HIGH, + .connector_type = DRM_MODE_CONNECTOR_LVDS, }; static const struct display_timing evervision_vgg804821_timing = { diff --git a/drivers/gpu/drm/radeon/atombios.h b/drivers/gpu/drm/radeon/atombios.h index a7caac5b8ac8..1afa70566985 100644 --- a/drivers/gpu/drm/radeon/atombios.h +++ b/drivers/gpu/drm/radeon/atombios.h @@ -5071,7 +5071,7 @@ typedef struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_7 #define SYS_INFO_GPUCAPS__TMDSHDMI_COHERENT_SINGLEPLL_MODE 0x01 #define SYS_INFO_GPUCAPS__DP_SINGLEPLL_MODE 0x02 #define SYS_INFO_GPUCAPS__DISABLE_AUX_MODE_DETECT 0x08 -#define SYS_INFO_GPUCAPS__ENABEL_DFS_BYPASS 0x10 +#define SYS_INFO_GPUCAPS__ENABLE_DFS_BYPASS 0x10 /********************************************************************************************************************** ATOM_INTEGRATED_SYSTEM_INFO_V1_7 Description diff --git a/drivers/gpu/drm/radeon/kv_dpm.c b/drivers/gpu/drm/radeon/kv_dpm.c index 55dbf450bd9c..4aa050385284 100644 --- a/drivers/gpu/drm/radeon/kv_dpm.c +++ b/drivers/gpu/drm/radeon/kv_dpm.c @@ -2329,7 +2329,7 @@ static int kv_parse_sys_info_table(struct radeon_device *rdev) le32_to_cpu(igp_info->info_8.ulNbpStateNClkFreq[i]); } if (le32_to_cpu(igp_info->info_8.ulGPUCapInfo) & - SYS_INFO_GPUCAPS__ENABEL_DFS_BYPASS) + SYS_INFO_GPUCAPS__ENABLE_DFS_BYPASS) pi->caps_enable_dfs_bypass = true; sumo_construct_sclk_voltage_mapping_table(rdev, diff --git a/drivers/gpu/drm/scheduler/sched_entity.c b/drivers/gpu/drm/scheduler/sched_entity.c index bd39db7bb240..e671aa241720 100644 --- a/drivers/gpu/drm/scheduler/sched_entity.c +++ b/drivers/gpu/drm/scheduler/sched_entity.c @@ -176,6 +176,7 @@ static void drm_sched_entity_kill_jobs_work(struct work_struct *wrk) { struct drm_sched_job *job = container_of(wrk, typeof(*job), work); + drm_sched_fence_scheduled(job->s_fence, NULL); drm_sched_fence_finished(job->s_fence, -ESRCH); WARN_ON(job->s_fence->parent); job->sched->ops->free_job(job); diff --git a/drivers/gpu/drm/ttm/tests/ttm_bo_test.c b/drivers/gpu/drm/ttm/tests/ttm_bo_test.c index 560d12e50e9e..6c77550c51af 100644 --- a/drivers/gpu/drm/ttm/tests/ttm_bo_test.c +++ b/drivers/gpu/drm/ttm/tests/ttm_bo_test.c @@ -175,7 +175,7 @@ struct signal_timer { static void signal_for_ttm_bo_reserve(struct timer_list *t) { - struct signal_timer *s_timer = from_timer(s_timer, t, timer); + struct signal_timer *s_timer = timer_container_of(s_timer, t, timer); struct task_struct *task = s_timer->ctx->task; do_send_sig_info(SIGTERM, SEND_SIG_PRIV, task, PIDTYPE_PID); diff --git a/drivers/gpu/drm/vc4/vc4_bo.c b/drivers/gpu/drm/vc4/vc4_bo.c index 7125773889f1..4aaa587be3a5 100644 --- a/drivers/gpu/drm/vc4/vc4_bo.c +++ b/drivers/gpu/drm/vc4/vc4_bo.c @@ -679,7 +679,7 @@ void vc4_bo_dec_usecnt(struct vc4_bo *bo) static void vc4_bo_cache_time_timer(struct timer_list *t) { - struct vc4_dev *vc4 = from_timer(vc4, t, bo_cache.time_timer); + struct vc4_dev *vc4 = timer_container_of(vc4, t, bo_cache.time_timer); schedule_work(&vc4->bo_cache.time_work); } diff --git a/drivers/gpu/drm/vc4/vc4_gem.c b/drivers/gpu/drm/vc4/vc4_gem.c index 8125f87edc60..255e5817618e 100644 --- a/drivers/gpu/drm/vc4/vc4_gem.c +++ b/drivers/gpu/drm/vc4/vc4_gem.c @@ -326,7 +326,7 @@ vc4_reset_work(struct work_struct *work) static void vc4_hangcheck_elapsed(struct timer_list *t) { - struct vc4_dev *vc4 = from_timer(vc4, t, hangcheck.timer); + struct vc4_dev *vc4 = timer_container_of(vc4, t, hangcheck.timer); struct drm_device *dev = &vc4->base; uint32_t ct0ca, ct1ca; unsigned long irqflags; diff --git a/drivers/gpu/drm/vgem/vgem_fence.c b/drivers/gpu/drm/vgem/vgem_fence.c index b611c7c8ca2d..fd76730fd38c 100644 --- a/drivers/gpu/drm/vgem/vgem_fence.c +++ b/drivers/gpu/drm/vgem/vgem_fence.c @@ -61,7 +61,7 @@ static const struct dma_fence_ops vgem_fence_ops = { static void vgem_fence_timeout(struct timer_list *t) { - struct vgem_fence *fence = from_timer(fence, t, timer); + struct vgem_fence *fence = timer_container_of(fence, t, timer); dma_fence_signal(&fence->base); } diff --git a/drivers/gpu/drm/xe/Kconfig b/drivers/gpu/drm/xe/Kconfig index 2169bc969ea1..fcc2677a4229 100644 --- a/drivers/gpu/drm/xe/Kconfig +++ b/drivers/gpu/drm/xe/Kconfig @@ -2,6 +2,8 @@ config DRM_XE tristate "Intel Xe Graphics" depends on DRM && PCI && (m || (y && KUNIT=y)) + depends on INTEL_VSEC || !INTEL_VSEC + depends on X86_PLATFORM_DEVICES || !(X86 && ACPI) select INTERVAL_TREE # we need shmfs for the swappable backing store, and in particular # the shmem_readpage() which depends upon tmpfs @@ -27,7 +29,6 @@ config DRM_XE select BACKLIGHT_CLASS_DEVICE if ACPI select INPUT if ACPI select ACPI_VIDEO if X86 && ACPI - select X86_PLATFORM_DEVICES if X86 && ACPI select ACPI_WMI if X86 && ACPI select SYNC_FILE select IOSF_MBI diff --git a/drivers/gpu/drm/xe/regs/xe_mchbar_regs.h b/drivers/gpu/drm/xe/regs/xe_mchbar_regs.h index f5e5234857c1..5394a1373a6b 100644 --- a/drivers/gpu/drm/xe/regs/xe_mchbar_regs.h +++ b/drivers/gpu/drm/xe/regs/xe_mchbar_regs.h @@ -38,10 +38,10 @@ #define TEMP_MASK REG_GENMASK(7, 0) #define PCU_CR_PACKAGE_RAPL_LIMIT XE_REG(MCHBAR_MIRROR_BASE_SNB + 0x59a0) -#define PKG_PWR_LIM_1 REG_GENMASK(14, 0) -#define PKG_PWR_LIM_1_EN REG_BIT(15) -#define PKG_PWR_LIM_1_TIME REG_GENMASK(23, 17) -#define PKG_PWR_LIM_1_TIME_X REG_GENMASK(23, 22) -#define PKG_PWR_LIM_1_TIME_Y REG_GENMASK(21, 17) +#define PWR_LIM_VAL REG_GENMASK(14, 0) +#define PWR_LIM_EN REG_BIT(15) +#define PWR_LIM_TIME REG_GENMASK(23, 17) +#define PWR_LIM_TIME_X REG_GENMASK(23, 22) +#define PWR_LIM_TIME_Y REG_GENMASK(21, 17) #endif /* _XE_MCHBAR_REGS_H_ */ diff --git a/drivers/gpu/drm/xe/regs/xe_pcode_regs.h b/drivers/gpu/drm/xe/regs/xe_pcode_regs.h index c7d5d782e3f9..c556a04670ee 100644 --- a/drivers/gpu/drm/xe/regs/xe_pcode_regs.h +++ b/drivers/gpu/drm/xe/regs/xe_pcode_regs.h @@ -18,16 +18,12 @@ #define PVC_GT0_PLATFORM_ENERGY_STATUS XE_REG(0x28106c) #define PVC_GT0_PACKAGE_POWER_SKU XE_REG(0x281080) -#define BMG_PACKAGE_POWER_SKU XE_REG(0x138098) -#define BMG_PACKAGE_POWER_SKU_UNIT XE_REG(0x1380dc) #define BMG_PACKAGE_ENERGY_STATUS XE_REG(0x138120) #define BMG_FAN_1_SPEED XE_REG(0x138140) #define BMG_FAN_2_SPEED XE_REG(0x138170) #define BMG_FAN_3_SPEED XE_REG(0x1381a0) #define BMG_VRAM_TEMPERATURE XE_REG(0x1382c0) #define BMG_PACKAGE_TEMPERATURE XE_REG(0x138434) -#define BMG_PACKAGE_RAPL_LIMIT XE_REG(0x138440) #define BMG_PLATFORM_ENERGY_STATUS XE_REG(0x138458) -#define BMG_PLATFORM_POWER_LIMIT XE_REG(0x138460) #endif /* _XE_PCODE_REGS_H_ */ diff --git a/drivers/gpu/drm/xe/xe_bo.c b/drivers/gpu/drm/xe/xe_bo.c index d99d91fe8aa9..7aa2c17825da 100644 --- a/drivers/gpu/drm/xe/xe_bo.c +++ b/drivers/gpu/drm/xe/xe_bo.c @@ -841,21 +841,6 @@ static int xe_bo_move(struct ttm_buffer_object *ttm_bo, bool evict, goto out; } - /* Reject BO eviction if BO is bound to current VM. */ - if (evict && ctx->resv) { - struct drm_gpuvm_bo *vm_bo; - - drm_gem_for_each_gpuvm_bo(vm_bo, &bo->ttm.base) { - struct xe_vm *vm = gpuvm_to_vm(vm_bo->vm); - - if (xe_vm_resv(vm) == ctx->resv && - xe_vm_in_preempt_fence_mode(vm)) { - ret = -EBUSY; - goto out; - } - } - } - /* * Failed multi-hop where the old_mem is still marked as * TTM_PL_FLAG_TEMPORARY, should just be a dummy move. @@ -1013,6 +998,25 @@ static long xe_bo_shrink_purge(struct ttm_operation_ctx *ctx, return lret; } +static bool +xe_bo_eviction_valuable(struct ttm_buffer_object *bo, const struct ttm_place *place) +{ + struct drm_gpuvm_bo *vm_bo; + + if (!ttm_bo_eviction_valuable(bo, place)) + return false; + + if (!xe_bo_is_xe_bo(bo)) + return true; + + drm_gem_for_each_gpuvm_bo(vm_bo, &bo->base) { + if (xe_vm_is_validating(gpuvm_to_vm(vm_bo->vm))) + return false; + } + + return true; +} + /** * xe_bo_shrink() - Try to shrink an xe bo. * @ctx: The struct ttm_operation_ctx used for shrinking. @@ -1047,7 +1051,7 @@ long xe_bo_shrink(struct ttm_operation_ctx *ctx, struct ttm_buffer_object *bo, (flags.purge && !xe_tt->purgeable)) return -EBUSY; - if (!ttm_bo_eviction_valuable(bo, &place)) + if (!xe_bo_eviction_valuable(bo, &place)) return -EBUSY; if (!xe_bo_is_xe_bo(bo) || !xe_bo_get_unless_zero(xe_bo)) @@ -1588,7 +1592,7 @@ const struct ttm_device_funcs xe_ttm_funcs = { .io_mem_pfn = xe_ttm_io_mem_pfn, .access_memory = xe_ttm_access_memory, .release_notify = xe_ttm_bo_release_notify, - .eviction_valuable = ttm_bo_eviction_valuable, + .eviction_valuable = xe_bo_eviction_valuable, .delete_mem_notify = xe_ttm_bo_delete_mem_notify, .swap_notify = xe_ttm_bo_swap_notify, }; @@ -2431,6 +2435,8 @@ int xe_bo_validate(struct xe_bo *bo, struct xe_vm *vm, bool allow_res_evict) .no_wait_gpu = false, .gfp_retry_mayfail = true, }; + struct pin_cookie cookie; + int ret; if (vm) { lockdep_assert_held(&vm->lock); @@ -2440,8 +2446,12 @@ int xe_bo_validate(struct xe_bo *bo, struct xe_vm *vm, bool allow_res_evict) ctx.resv = xe_vm_resv(vm); } + cookie = xe_vm_set_validating(vm, allow_res_evict); trace_xe_bo_validate(bo); - return ttm_bo_validate(&bo->ttm, &bo->placement, &ctx); + ret = ttm_bo_validate(&bo->ttm, &bo->placement, &ctx); + xe_vm_clear_validating(vm, allow_res_evict, cookie); + + return ret; } bool xe_bo_is_xe_bo(struct ttm_buffer_object *bo) @@ -2557,7 +2567,7 @@ typedef int (*xe_gem_create_set_property_fn)(struct xe_device *xe, u64 value); static const xe_gem_create_set_property_fn gem_create_set_property_funcs[] = { - [DRM_XE_GEM_CREATE_EXTENSION_SET_PROPERTY] = gem_create_set_pxp_type, + [DRM_XE_GEM_CREATE_SET_PROPERTY_PXP_TYPE] = gem_create_set_pxp_type, }; static int gem_create_user_ext_set_property(struct xe_device *xe, diff --git a/drivers/gpu/drm/xe/xe_device_sysfs.c b/drivers/gpu/drm/xe/xe_device_sysfs.c index 2e657692e5b5..b9440f8c781e 100644 --- a/drivers/gpu/drm/xe/xe_device_sysfs.c +++ b/drivers/gpu/drm/xe/xe_device_sysfs.c @@ -115,7 +115,7 @@ auto_link_downgrade_capable_show(struct device *dev, struct device_attribute *at xe_pm_runtime_put(xe); cap = REG_FIELD_GET(LINK_DOWNGRADE, val); - return sysfs_emit(buf, "%u\n", cap == DOWNGRADE_CAPABLE ? true : false); + return sysfs_emit(buf, "%u\n", cap == DOWNGRADE_CAPABLE); } static DEVICE_ATTR_ADMIN_RO(auto_link_downgrade_capable); diff --git a/drivers/gpu/drm/xe/xe_device_types.h b/drivers/gpu/drm/xe/xe_device_types.h index c8fa2c011666..6383a1c0d478 100644 --- a/drivers/gpu/drm/xe/xe_device_types.h +++ b/drivers/gpu/drm/xe/xe_device_types.h @@ -325,6 +325,10 @@ struct xe_device { u8 has_heci_gscfi:1; /** @info.has_llc: Device has a shared CPU+GPU last level cache */ u8 has_llc:1; + /** @info.has_mbx_power_limits: Device has support to manage power limits using + * pcode mailbox commands. + */ + u8 has_mbx_power_limits:1; /** @info.has_pxp: Device has PXP support */ u8 has_pxp:1; /** @info.has_range_tlb_invalidation: Has range based TLB invalidations */ diff --git a/drivers/gpu/drm/xe/xe_exec_queue.c b/drivers/gpu/drm/xe/xe_exec_queue.c index ce78cee5dec6..fee22358cc09 100644 --- a/drivers/gpu/drm/xe/xe_exec_queue.c +++ b/drivers/gpu/drm/xe/xe_exec_queue.c @@ -114,7 +114,6 @@ static struct xe_exec_queue *__xe_exec_queue_alloc(struct xe_device *xe, static int __xe_exec_queue_init(struct xe_exec_queue *q) { - struct xe_vm *vm = q->vm; int i, err; u32 flags = 0; @@ -132,32 +131,20 @@ static int __xe_exec_queue_init(struct xe_exec_queue *q) flags |= XE_LRC_CREATE_RUNALONE; } - if (vm) { - err = xe_vm_lock(vm, true); - if (err) - return err; - } - for (i = 0; i < q->width; ++i) { q->lrc[i] = xe_lrc_create(q->hwe, q->vm, SZ_16K, q->msix_vec, flags); if (IS_ERR(q->lrc[i])) { err = PTR_ERR(q->lrc[i]); - goto err_unlock; + goto err_lrc; } } - if (vm) - xe_vm_unlock(vm); - err = q->ops->init(q); if (err) goto err_lrc; return 0; -err_unlock: - if (vm) - xe_vm_unlock(vm); err_lrc: for (i = i - 1; i >= 0; --i) xe_lrc_put(q->lrc[i]); diff --git a/drivers/gpu/drm/xe/xe_gpu_scheduler.h b/drivers/gpu/drm/xe/xe_gpu_scheduler.h index c250ea773491..308061f0cf37 100644 --- a/drivers/gpu/drm/xe/xe_gpu_scheduler.h +++ b/drivers/gpu/drm/xe/xe_gpu_scheduler.h @@ -51,7 +51,15 @@ static inline void xe_sched_tdr_queue_imm(struct xe_gpu_scheduler *sched) static inline void xe_sched_resubmit_jobs(struct xe_gpu_scheduler *sched) { - drm_sched_resubmit_jobs(&sched->base); + struct drm_sched_job *s_job; + + list_for_each_entry(s_job, &sched->base.pending_list, list) { + struct drm_sched_fence *s_fence = s_job->s_fence; + struct dma_fence *hw_fence = s_fence->parent; + + if (hw_fence && !dma_fence_is_signaled(hw_fence)) + sched->base.ops->run_job(s_job); + } } static inline bool diff --git a/drivers/gpu/drm/xe/xe_gt_freq.c b/drivers/gpu/drm/xe/xe_gt_freq.c index 868a5d2c1a52..60d9354e7dbf 100644 --- a/drivers/gpu/drm/xe/xe_gt_freq.c +++ b/drivers/gpu/drm/xe/xe_gt_freq.c @@ -32,13 +32,18 @@ * Xe's Freq provides a sysfs API for frequency management: * * device/tile#/gt#/freq0/<item>_freq *read-only* files: + * * - act_freq: The actual resolved frequency decided by PCODE. * - cur_freq: The current one requested by GuC PC to the PCODE. * - rpn_freq: The Render Performance (RP) N level, which is the minimal one. + * - rpa_freq: The Render Performance (RP) A level, which is the achiveable one. + * Calculated by PCODE at runtime based on multiple running conditions * - rpe_freq: The Render Performance (RP) E level, which is the efficient one. + * Calculated by PCODE at runtime based on multiple running conditions * - rp0_freq: The Render Performance (RP) 0 level, which is the maximum one. * * device/tile#/gt#/freq0/<item>_freq *read-write* files: + * * - min_freq: Min frequency request. * - max_freq: Max frequency request. * If max <= min, then freq_min becomes a fixed frequency request. diff --git a/drivers/gpu/drm/xe/xe_guc_submit.c b/drivers/gpu/drm/xe/xe_guc_submit.c index 2ad38f6b103e..6d84a52b660a 100644 --- a/drivers/gpu/drm/xe/xe_guc_submit.c +++ b/drivers/gpu/drm/xe/xe_guc_submit.c @@ -229,6 +229,17 @@ static bool exec_queue_killed_or_banned_or_wedged(struct xe_exec_queue *q) static void guc_submit_fini(struct drm_device *drm, void *arg) { struct xe_guc *guc = arg; + struct xe_device *xe = guc_to_xe(guc); + struct xe_gt *gt = guc_to_gt(guc); + int ret; + + ret = wait_event_timeout(guc->submission_state.fini_wq, + xa_empty(&guc->submission_state.exec_queue_lookup), + HZ * 5); + + drain_workqueue(xe->destroy_wq); + + xe_gt_assert(gt, ret); xa_destroy(&guc->submission_state.exec_queue_lookup); } diff --git a/drivers/gpu/drm/xe/xe_hwmon.c b/drivers/gpu/drm/xe/xe_hwmon.c index eb293aec36a0..74f31639b37f 100644 --- a/drivers/gpu/drm/xe/xe_hwmon.c +++ b/drivers/gpu/drm/xe/xe_hwmon.c @@ -52,6 +52,14 @@ enum xe_fan_channel { }; /* + * For platforms that support mailbox commands for power limits, REG_PKG_POWER_SKU_UNIT is + * not supported and below are SKU units to be used. + */ +#define PWR_UNIT 0x3 +#define ENERGY_UNIT 0xe +#define TIME_UNIT 0xa + +/* * SF_* - scale factors for particular quantities according to hwmon spec. */ #define SF_POWER 1000000 /* microwatts */ @@ -60,6 +68,18 @@ enum xe_fan_channel { #define SF_ENERGY 1000000 /* microjoules */ #define SF_TIME 1000 /* milliseconds */ +/* + * PL*_HWMON_ATTR - mapping of hardware power limits to corresponding hwmon power attribute. + */ +#define PL1_HWMON_ATTR hwmon_power_max + +#define PWR_ATTR_TO_STR(attr) (((attr) == hwmon_power_max) ? "PL1" : "Invalid") + +/* + * Timeout for power limit write mailbox command. + */ +#define PL_WRITE_MBX_TIMEOUT_MS (1) + /** * struct xe_hwmon_energy_info - to accumulate energy */ @@ -100,8 +120,80 @@ struct xe_hwmon { struct xe_hwmon_energy_info ei[CHANNEL_MAX]; /** @fi: Fan info for fanN_input */ struct xe_hwmon_fan_info fi[FAN_MAX]; + /** @boot_power_limit_read: is boot power limits read */ + bool boot_power_limit_read; + /** @pl1_on_boot: power limit PL1 on boot */ + u32 pl1_on_boot[CHANNEL_MAX]; }; +static int xe_hwmon_pcode_read_power_limit(const struct xe_hwmon *hwmon, u32 attr, int channel, + u32 *uval) +{ + struct xe_tile *root_tile = xe_device_get_root_tile(hwmon->xe); + u32 val0 = 0, val1 = 0; + int ret = 0; + + ret = xe_pcode_read(root_tile, PCODE_MBOX(PCODE_POWER_SETUP, + (channel == CHANNEL_CARD) ? + READ_PSYSGPU_POWER_LIMIT : + READ_PACKAGE_POWER_LIMIT, + hwmon->boot_power_limit_read ? + READ_PL_FROM_PCODE : READ_PL_FROM_FW), + &val0, &val1); + + if (ret) { + drm_dbg(&hwmon->xe->drm, "read failed ch %d val0 0x%08x, val1 0x%08x, ret %d\n", + channel, val0, val1, ret); + *uval = 0; + return ret; + } + + /* return the value only if limit is enabled */ + if (attr == PL1_HWMON_ATTR) + *uval = (val0 & PWR_LIM_EN) ? val0 : 0; + else if (attr == hwmon_power_label) + *uval = (val0 & PWR_LIM_EN) ? 1 : 0; + else + *uval = 0; + + return ret; +} + +static int xe_hwmon_pcode_write_power_limit(const struct xe_hwmon *hwmon, u32 attr, u8 channel, + u32 uval) +{ + struct xe_tile *root_tile = xe_device_get_root_tile(hwmon->xe); + u32 val0, val1; + int ret = 0; + + ret = xe_pcode_read(root_tile, PCODE_MBOX(PCODE_POWER_SETUP, + (channel == CHANNEL_CARD) ? + READ_PSYSGPU_POWER_LIMIT : + READ_PACKAGE_POWER_LIMIT, + hwmon->boot_power_limit_read ? + READ_PL_FROM_PCODE : READ_PL_FROM_FW), + &val0, &val1); + + if (ret) + drm_dbg(&hwmon->xe->drm, "read failed ch %d val0 0x%08x, val1 0x%08x, ret %d\n", + channel, val0, val1, ret); + + if (attr == PL1_HWMON_ATTR) + val0 = uval; + else + return -EIO; + + ret = xe_pcode_write64_timeout(root_tile, PCODE_MBOX(PCODE_POWER_SETUP, + (channel == CHANNEL_CARD) ? + WRITE_PSYSGPU_POWER_LIMIT : + WRITE_PACKAGE_POWER_LIMIT, 0), + val0, val1, PL_WRITE_MBX_TIMEOUT_MS); + if (ret) + drm_dbg(&hwmon->xe->drm, "write failed ch %d val0 0x%08x, val1 0x%08x, ret %d\n", + channel, val0, val1, ret); + return ret; +} + static struct xe_reg xe_hwmon_get_reg(struct xe_hwmon *hwmon, enum xe_hwmon_reg hwmon_reg, int channel) { @@ -122,29 +214,19 @@ static struct xe_reg xe_hwmon_get_reg(struct xe_hwmon *hwmon, enum xe_hwmon_reg } break; case REG_PKG_RAPL_LIMIT: - if (xe->info.platform == XE_BATTLEMAGE) { - if (channel == CHANNEL_PKG) - return BMG_PACKAGE_RAPL_LIMIT; - else - return BMG_PLATFORM_POWER_LIMIT; - } else if (xe->info.platform == XE_PVC && channel == CHANNEL_PKG) { + if (xe->info.platform == XE_PVC && channel == CHANNEL_PKG) return PVC_GT0_PACKAGE_RAPL_LIMIT; - } else if ((xe->info.platform == XE_DG2) && (channel == CHANNEL_PKG)) { + else if ((xe->info.platform == XE_DG2) && (channel == CHANNEL_PKG)) return PCU_CR_PACKAGE_RAPL_LIMIT; - } break; case REG_PKG_POWER_SKU: - if (xe->info.platform == XE_BATTLEMAGE) - return BMG_PACKAGE_POWER_SKU; - else if (xe->info.platform == XE_PVC && channel == CHANNEL_PKG) + if (xe->info.platform == XE_PVC && channel == CHANNEL_PKG) return PVC_GT0_PACKAGE_POWER_SKU; else if ((xe->info.platform == XE_DG2) && (channel == CHANNEL_PKG)) return PCU_CR_PACKAGE_POWER_SKU; break; case REG_PKG_POWER_SKU_UNIT: - if (xe->info.platform == XE_BATTLEMAGE) - return BMG_PACKAGE_POWER_SKU_UNIT; - else if (xe->info.platform == XE_PVC) + if (xe->info.platform == XE_PVC) return PVC_GT0_PACKAGE_POWER_SKU_UNIT; else if (xe->info.platform == XE_DG2) return PCU_CR_PACKAGE_POWER_SKU_UNIT; @@ -181,7 +263,7 @@ static struct xe_reg xe_hwmon_get_reg(struct xe_hwmon *hwmon, enum xe_hwmon_reg return XE_REG(0); } -#define PL1_DISABLE 0 +#define PL_DISABLE 0 /* * HW allows arbitrary PL1 limits to be set but silently clamps these values to @@ -189,67 +271,83 @@ static struct xe_reg xe_hwmon_get_reg(struct xe_hwmon *hwmon, enum xe_hwmon_reg * same pattern for sysfs, allow arbitrary PL1 limits to be set but display * clamped values when read. */ -static void xe_hwmon_power_max_read(struct xe_hwmon *hwmon, int channel, long *value) +static void xe_hwmon_power_max_read(struct xe_hwmon *hwmon, u32 attr, int channel, long *value) { u64 reg_val, min, max; struct xe_device *xe = hwmon->xe; struct xe_reg rapl_limit, pkg_power_sku; struct xe_mmio *mmio = xe_root_tile_mmio(xe); - rapl_limit = xe_hwmon_get_reg(hwmon, REG_PKG_RAPL_LIMIT, channel); - pkg_power_sku = xe_hwmon_get_reg(hwmon, REG_PKG_POWER_SKU, channel); + mutex_lock(&hwmon->hwmon_lock); - /* - * Valid check of REG_PKG_RAPL_LIMIT is already done in xe_hwmon_power_is_visible. - * So not checking it again here. - */ - if (!xe_reg_is_valid(pkg_power_sku)) { - drm_warn(&xe->drm, "pkg_power_sku invalid\n"); - *value = 0; - return; + if (hwmon->xe->info.has_mbx_power_limits) { + xe_hwmon_pcode_read_power_limit(hwmon, attr, channel, (u32 *)®_val); + } else { + rapl_limit = xe_hwmon_get_reg(hwmon, REG_PKG_RAPL_LIMIT, channel); + pkg_power_sku = xe_hwmon_get_reg(hwmon, REG_PKG_POWER_SKU, channel); + + /* + * Valid check of REG_PKG_RAPL_LIMIT is already done in xe_hwmon_power_is_visible. + * So not checking it again here. + */ + if (!xe_reg_is_valid(pkg_power_sku)) { + drm_warn(&xe->drm, "pkg_power_sku invalid\n"); + *value = 0; + goto unlock; + } + reg_val = xe_mmio_read32(mmio, rapl_limit); } - mutex_lock(&hwmon->hwmon_lock); - - reg_val = xe_mmio_read32(mmio, rapl_limit); - /* Check if PL1 limit is disabled */ - if (!(reg_val & PKG_PWR_LIM_1_EN)) { - *value = PL1_DISABLE; + /* Check if PL limits are disabled. */ + if (!(reg_val & PWR_LIM_EN)) { + *value = PL_DISABLE; + drm_info(&hwmon->xe->drm, "%s disabled for channel %d, val 0x%016llx\n", + PWR_ATTR_TO_STR(attr), channel, reg_val); goto unlock; } - reg_val = REG_FIELD_GET(PKG_PWR_LIM_1, reg_val); + reg_val = REG_FIELD_GET(PWR_LIM_VAL, reg_val); *value = mul_u64_u32_shr(reg_val, SF_POWER, hwmon->scl_shift_power); - reg_val = xe_mmio_read64_2x32(mmio, pkg_power_sku); - min = REG_FIELD_GET(PKG_MIN_PWR, reg_val); - min = mul_u64_u32_shr(min, SF_POWER, hwmon->scl_shift_power); - max = REG_FIELD_GET(PKG_MAX_PWR, reg_val); - max = mul_u64_u32_shr(max, SF_POWER, hwmon->scl_shift_power); - - if (min && max) - *value = clamp_t(u64, *value, min, max); + /* For platforms with mailbox power limit support clamping would be done by pcode. */ + if (!hwmon->xe->info.has_mbx_power_limits) { + reg_val = xe_mmio_read64_2x32(mmio, pkg_power_sku); + min = REG_FIELD_GET(PKG_MIN_PWR, reg_val); + max = REG_FIELD_GET(PKG_MAX_PWR, reg_val); + min = mul_u64_u32_shr(min, SF_POWER, hwmon->scl_shift_power); + max = mul_u64_u32_shr(max, SF_POWER, hwmon->scl_shift_power); + if (min && max) + *value = clamp_t(u64, *value, min, max); + } unlock: mutex_unlock(&hwmon->hwmon_lock); } -static int xe_hwmon_power_max_write(struct xe_hwmon *hwmon, int channel, long value) +static int xe_hwmon_power_max_write(struct xe_hwmon *hwmon, u32 attr, int channel, long value) { struct xe_mmio *mmio = xe_root_tile_mmio(hwmon->xe); int ret = 0; - u64 reg_val; + u32 reg_val; struct xe_reg rapl_limit; + mutex_lock(&hwmon->hwmon_lock); + rapl_limit = xe_hwmon_get_reg(hwmon, REG_PKG_RAPL_LIMIT, channel); - mutex_lock(&hwmon->hwmon_lock); + /* Disable Power Limit and verify, as limit cannot be disabled on all platforms. */ + if (value == PL_DISABLE) { + if (hwmon->xe->info.has_mbx_power_limits) { + drm_dbg(&hwmon->xe->drm, "disabling %s on channel %d\n", + PWR_ATTR_TO_STR(attr), channel); + xe_hwmon_pcode_write_power_limit(hwmon, attr, channel, 0); + xe_hwmon_pcode_read_power_limit(hwmon, attr, channel, ®_val); + } else { + reg_val = xe_mmio_rmw32(mmio, rapl_limit, PWR_LIM_EN, 0); + reg_val = xe_mmio_read32(mmio, rapl_limit); + } - /* Disable PL1 limit and verify, as limit cannot be disabled on all platforms */ - if (value == PL1_DISABLE) { - reg_val = xe_mmio_rmw32(mmio, rapl_limit, PKG_PWR_LIM_1_EN, 0); - reg_val = xe_mmio_read32(mmio, rapl_limit); - if (reg_val & PKG_PWR_LIM_1_EN) { - drm_warn(&hwmon->xe->drm, "PL1 disable is not supported!\n"); + if (reg_val & PWR_LIM_EN) { + drm_warn(&hwmon->xe->drm, "Power limit disable is not supported!\n"); ret = -EOPNOTSUPP; } goto unlock; @@ -257,26 +355,50 @@ static int xe_hwmon_power_max_write(struct xe_hwmon *hwmon, int channel, long va /* Computation in 64-bits to avoid overflow. Round to nearest. */ reg_val = DIV_ROUND_CLOSEST_ULL((u64)value << hwmon->scl_shift_power, SF_POWER); - reg_val = PKG_PWR_LIM_1_EN | REG_FIELD_PREP(PKG_PWR_LIM_1, reg_val); - reg_val = xe_mmio_rmw32(mmio, rapl_limit, PKG_PWR_LIM_1_EN | PKG_PWR_LIM_1, reg_val); + reg_val = PWR_LIM_EN | REG_FIELD_PREP(PWR_LIM_VAL, reg_val); + /* + * Clamp power limit to card-firmware default as maximum, as an additional protection to + * pcode clamp. + */ + if (hwmon->xe->info.has_mbx_power_limits) { + if (reg_val > REG_FIELD_GET(PWR_LIM_VAL, hwmon->pl1_on_boot[channel])) { + reg_val = REG_FIELD_GET(PWR_LIM_VAL, hwmon->pl1_on_boot[channel]); + drm_dbg(&hwmon->xe->drm, "Clamping power limit to firmware default 0x%x\n", + reg_val); + } + } + + if (hwmon->xe->info.has_mbx_power_limits) + ret = xe_hwmon_pcode_write_power_limit(hwmon, attr, channel, reg_val); + else + reg_val = xe_mmio_rmw32(mmio, rapl_limit, PWR_LIM_EN | PWR_LIM_VAL, + reg_val); unlock: mutex_unlock(&hwmon->hwmon_lock); return ret; } -static void xe_hwmon_power_rated_max_read(struct xe_hwmon *hwmon, int channel, long *value) +static void xe_hwmon_power_rated_max_read(struct xe_hwmon *hwmon, u32 attr, int channel, + long *value) { struct xe_mmio *mmio = xe_root_tile_mmio(hwmon->xe); - struct xe_reg reg = xe_hwmon_get_reg(hwmon, REG_PKG_POWER_SKU, channel); - u64 reg_val; + u32 reg_val; + + if (hwmon->xe->info.has_mbx_power_limits) { + /* PL1 is rated max if supported. */ + xe_hwmon_pcode_read_power_limit(hwmon, PL1_HWMON_ATTR, channel, ®_val); + } else { + /* + * This sysfs file won't be visible if REG_PKG_POWER_SKU is invalid, so valid check + * for this register can be skipped. + * See xe_hwmon_power_is_visible. + */ + struct xe_reg reg = xe_hwmon_get_reg(hwmon, REG_PKG_POWER_SKU, channel); + + reg_val = xe_mmio_read32(mmio, reg); + } - /* - * This sysfs file won't be visible if REG_PKG_POWER_SKU is invalid, so valid check - * for this register can be skipped. - * See xe_hwmon_power_is_visible. - */ - reg_val = xe_mmio_read32(mmio, reg); reg_val = REG_FIELD_GET(PKG_TDP, reg_val); *value = mul_u64_u32_shr(reg_val, SF_POWER, hwmon->scl_shift_power); } @@ -330,23 +452,35 @@ xe_hwmon_power_max_interval_show(struct device *dev, struct device_attribute *at struct xe_mmio *mmio = xe_root_tile_mmio(hwmon->xe); u32 x, y, x_w = 2; /* 2 bits */ u64 r, tau4, out; - int sensor_index = to_sensor_dev_attr(attr)->index; + int channel = to_sensor_dev_attr(attr)->index; + u32 power_attr = PL1_HWMON_ATTR; + int ret = 0; xe_pm_runtime_get(hwmon->xe); mutex_lock(&hwmon->hwmon_lock); - r = xe_mmio_read32(mmio, xe_hwmon_get_reg(hwmon, REG_PKG_RAPL_LIMIT, sensor_index)); + if (hwmon->xe->info.has_mbx_power_limits) { + ret = xe_hwmon_pcode_read_power_limit(hwmon, power_attr, channel, (u32 *)&r); + if (ret) { + drm_err(&hwmon->xe->drm, + "power interval read fail, ch %d, attr %d, r 0%llx, ret %d\n", + channel, power_attr, r, ret); + r = 0; + } + } else { + r = xe_mmio_read32(mmio, xe_hwmon_get_reg(hwmon, REG_PKG_RAPL_LIMIT, channel)); + } mutex_unlock(&hwmon->hwmon_lock); xe_pm_runtime_put(hwmon->xe); - x = REG_FIELD_GET(PKG_PWR_LIM_1_TIME_X, r); - y = REG_FIELD_GET(PKG_PWR_LIM_1_TIME_Y, r); + x = REG_FIELD_GET(PWR_LIM_TIME_X, r); + y = REG_FIELD_GET(PWR_LIM_TIME_Y, r); /* - * tau = 1.x * power(2,y), x = bits(23:22), y = bits(21:17) + * tau = (1 + (x / 4)) * power(2,y), x = bits(23:22), y = bits(21:17) * = (4 | x) << (y - 2) * * Here (y - 2) ensures a 1.x fixed point representation of 1.x @@ -373,14 +507,15 @@ xe_hwmon_power_max_interval_store(struct device *dev, struct device_attribute *a u64 tau4, r, max_win; unsigned long val; int ret; - int sensor_index = to_sensor_dev_attr(attr)->index; + int channel = to_sensor_dev_attr(attr)->index; + u32 power_attr = PL1_HWMON_ATTR; ret = kstrtoul(buf, 0, &val); if (ret) return ret; /* - * Max HW supported tau in '1.x * power(2,y)' format, x = 0, y = 0x12. + * Max HW supported tau in '(1 + (x / 4)) * power(2,y)' format, x = 0, y = 0x12. * The hwmon->scl_shift_time default of 0xa results in a max tau of 256 seconds. * * The ideal scenario is for PKG_MAX_WIN to be read from the PKG_PWR_SKU register. @@ -400,11 +535,13 @@ xe_hwmon_power_max_interval_store(struct device *dev, struct device_attribute *a tau4 = (u64)((1 << x_w) | x) << y; max_win = mul_u64_u32_shr(tau4, SF_TIME, hwmon->scl_shift_time + x_w); - if (val > max_win) + if (val > max_win) { + drm_warn(&hwmon->xe->drm, "power_interval invalid val 0x%lx\n", val); return -EINVAL; + } /* val in hw units */ - val = DIV_ROUND_CLOSEST_ULL((u64)val << hwmon->scl_shift_time, SF_TIME); + val = DIV_ROUND_CLOSEST_ULL((u64)val << hwmon->scl_shift_time, SF_TIME) + 1; /* * Convert val to 1.x * power(2,y) @@ -419,14 +556,21 @@ xe_hwmon_power_max_interval_store(struct device *dev, struct device_attribute *a x = (val - (1ul << y)) << x_w >> y; } - rxy = REG_FIELD_PREP(PKG_PWR_LIM_1_TIME_X, x) | REG_FIELD_PREP(PKG_PWR_LIM_1_TIME_Y, y); + rxy = REG_FIELD_PREP(PWR_LIM_TIME_X, x) | + REG_FIELD_PREP(PWR_LIM_TIME_Y, y); xe_pm_runtime_get(hwmon->xe); mutex_lock(&hwmon->hwmon_lock); - r = xe_mmio_rmw32(mmio, xe_hwmon_get_reg(hwmon, REG_PKG_RAPL_LIMIT, sensor_index), - PKG_PWR_LIM_1_TIME, rxy); + if (hwmon->xe->info.has_mbx_power_limits) { + ret = xe_hwmon_pcode_read_power_limit(hwmon, power_attr, channel, (u32 *)&r); + r = (r & ~PWR_LIM_TIME) | rxy; + xe_hwmon_pcode_write_power_limit(hwmon, power_attr, channel, r); + } else { + r = xe_mmio_rmw32(mmio, xe_hwmon_get_reg(hwmon, REG_PKG_RAPL_LIMIT, channel), + PWR_LIM_TIME, rxy); + } mutex_unlock(&hwmon->hwmon_lock); @@ -435,6 +579,7 @@ xe_hwmon_power_max_interval_store(struct device *dev, struct device_attribute *a return count; } +/* PSYS PL1 */ static SENSOR_DEVICE_ATTR(power1_max_interval, 0664, xe_hwmon_power_max_interval_show, xe_hwmon_power_max_interval_store, CHANNEL_CARD); @@ -455,10 +600,19 @@ static umode_t xe_hwmon_attributes_visible(struct kobject *kobj, struct device *dev = kobj_to_dev(kobj); struct xe_hwmon *hwmon = dev_get_drvdata(dev); int ret = 0; + int channel = index ? CHANNEL_PKG : CHANNEL_CARD; + u32 power_attr = PL1_HWMON_ATTR; + u32 uval; xe_pm_runtime_get(hwmon->xe); - ret = xe_reg_is_valid(xe_hwmon_get_reg(hwmon, REG_PKG_RAPL_LIMIT, index)) ? attr->mode : 0; + if (hwmon->xe->info.has_mbx_power_limits) { + xe_hwmon_pcode_read_power_limit(hwmon, power_attr, channel, &uval); + ret = (uval & PWR_LIM_EN) ? attr->mode : 0; + } else { + ret = xe_reg_is_valid(xe_hwmon_get_reg(hwmon, REG_PKG_RAPL_LIMIT, + channel)) ? attr->mode : 0; + } xe_pm_runtime_put(hwmon->xe); @@ -478,8 +632,8 @@ static const struct attribute_group *hwmon_groups[] = { static const struct hwmon_channel_info * const hwmon_info[] = { HWMON_CHANNEL_INFO(temp, HWMON_T_LABEL, HWMON_T_INPUT | HWMON_T_LABEL, HWMON_T_INPUT | HWMON_T_LABEL), - HWMON_CHANNEL_INFO(power, HWMON_P_MAX | HWMON_P_RATED_MAX | HWMON_P_LABEL, - HWMON_P_MAX | HWMON_P_RATED_MAX | HWMON_P_CRIT | HWMON_P_LABEL), + HWMON_CHANNEL_INFO(power, HWMON_P_MAX | HWMON_P_RATED_MAX | HWMON_P_LABEL | HWMON_P_CRIT, + HWMON_P_MAX | HWMON_P_RATED_MAX | HWMON_P_LABEL), HWMON_CHANNEL_INFO(curr, HWMON_C_LABEL, HWMON_C_CRIT | HWMON_C_LABEL), HWMON_CHANNEL_INFO(in, HWMON_I_INPUT | HWMON_I_LABEL, HWMON_I_INPUT | HWMON_I_LABEL), HWMON_CHANNEL_INFO(energy, HWMON_E_INPUT | HWMON_E_LABEL, HWMON_E_INPUT | HWMON_E_LABEL), @@ -604,19 +758,27 @@ xe_hwmon_power_is_visible(struct xe_hwmon *hwmon, u32 attr, int channel) switch (attr) { case hwmon_power_max: - return xe_reg_is_valid(xe_hwmon_get_reg(hwmon, REG_PKG_RAPL_LIMIT, + if (hwmon->xe->info.has_mbx_power_limits) { + xe_hwmon_pcode_read_power_limit(hwmon, attr, channel, &uval); + return (uval) ? 0664 : 0; + } else { + return xe_reg_is_valid(xe_hwmon_get_reg(hwmon, REG_PKG_RAPL_LIMIT, channel)) ? 0664 : 0; + } case hwmon_power_rated_max: - return xe_reg_is_valid(xe_hwmon_get_reg(hwmon, REG_PKG_POWER_SKU, - channel)) ? 0444 : 0; + if (hwmon->xe->info.has_mbx_power_limits) + return 0; + else + return xe_reg_is_valid(xe_hwmon_get_reg(hwmon, REG_PKG_POWER_SKU, + channel)) ? 0444 : 0; case hwmon_power_crit: - if (channel == CHANNEL_PKG) - return (xe_hwmon_pcode_read_i1(hwmon, &uval) || - !(uval & POWER_SETUP_I1_WATTS)) ? 0 : 0644; - break; case hwmon_power_label: - return xe_reg_is_valid(xe_hwmon_get_reg(hwmon, REG_PKG_POWER_SKU_UNIT, - channel)) ? 0444 : 0; + if (channel == CHANNEL_CARD) { + xe_hwmon_pcode_read_i1(hwmon, &uval); + return (uval & POWER_SETUP_I1_WATTS) ? (attr == hwmon_power_label) ? + 0444 : 0644 : 0; + } + break; default: return 0; } @@ -628,10 +790,10 @@ xe_hwmon_power_read(struct xe_hwmon *hwmon, u32 attr, int channel, long *val) { switch (attr) { case hwmon_power_max: - xe_hwmon_power_max_read(hwmon, channel, val); + xe_hwmon_power_max_read(hwmon, attr, channel, val); return 0; case hwmon_power_rated_max: - xe_hwmon_power_rated_max_read(hwmon, channel, val); + xe_hwmon_power_rated_max_read(hwmon, attr, channel, val); return 0; case hwmon_power_crit: return xe_hwmon_power_curr_crit_read(hwmon, channel, val, SF_POWER); @@ -645,7 +807,7 @@ xe_hwmon_power_write(struct xe_hwmon *hwmon, u32 attr, int channel, long val) { switch (attr) { case hwmon_power_max: - return xe_hwmon_power_max_write(hwmon, channel, val); + return xe_hwmon_power_max_write(hwmon, attr, channel, val); case hwmon_power_crit: return xe_hwmon_power_curr_crit_write(hwmon, channel, val, SF_POWER); default: @@ -965,18 +1127,42 @@ xe_hwmon_get_preregistration_info(struct xe_hwmon *hwmon) int channel; struct xe_reg pkg_power_sku_unit; - /* - * The contents of register PKG_POWER_SKU_UNIT do not change, - * so read it once and store the shift values. - */ - pkg_power_sku_unit = xe_hwmon_get_reg(hwmon, REG_PKG_POWER_SKU_UNIT, 0); - if (xe_reg_is_valid(pkg_power_sku_unit)) { - val_sku_unit = xe_mmio_read32(mmio, pkg_power_sku_unit); - hwmon->scl_shift_power = REG_FIELD_GET(PKG_PWR_UNIT, val_sku_unit); - hwmon->scl_shift_energy = REG_FIELD_GET(PKG_ENERGY_UNIT, val_sku_unit); - hwmon->scl_shift_time = REG_FIELD_GET(PKG_TIME_UNIT, val_sku_unit); + if (hwmon->xe->info.has_mbx_power_limits) { + /* Check if card firmware support mailbox power limits commands. */ + if (xe_hwmon_pcode_read_power_limit(hwmon, PL1_HWMON_ATTR, CHANNEL_CARD, + &hwmon->pl1_on_boot[CHANNEL_CARD]) | + xe_hwmon_pcode_read_power_limit(hwmon, PL1_HWMON_ATTR, CHANNEL_PKG, + &hwmon->pl1_on_boot[CHANNEL_PKG])) { + drm_warn(&hwmon->xe->drm, + "Failed to read power limits, check card firmware !\n"); + } else { + drm_info(&hwmon->xe->drm, "Using mailbox commands for power limits\n"); + /* Write default limits to read from pcode from now on. */ + xe_hwmon_pcode_write_power_limit(hwmon, PL1_HWMON_ATTR, + CHANNEL_CARD, + hwmon->pl1_on_boot[CHANNEL_CARD]); + xe_hwmon_pcode_write_power_limit(hwmon, PL1_HWMON_ATTR, + CHANNEL_PKG, + hwmon->pl1_on_boot[CHANNEL_PKG]); + hwmon->scl_shift_power = PWR_UNIT; + hwmon->scl_shift_energy = ENERGY_UNIT; + hwmon->scl_shift_time = TIME_UNIT; + hwmon->boot_power_limit_read = true; + } + } else { + drm_info(&hwmon->xe->drm, "Using register for power limits\n"); + /* + * The contents of register PKG_POWER_SKU_UNIT do not change, + * so read it once and store the shift values. + */ + pkg_power_sku_unit = xe_hwmon_get_reg(hwmon, REG_PKG_POWER_SKU_UNIT, 0); + if (xe_reg_is_valid(pkg_power_sku_unit)) { + val_sku_unit = xe_mmio_read32(mmio, pkg_power_sku_unit); + hwmon->scl_shift_power = REG_FIELD_GET(PKG_PWR_UNIT, val_sku_unit); + hwmon->scl_shift_energy = REG_FIELD_GET(PKG_ENERGY_UNIT, val_sku_unit); + hwmon->scl_shift_time = REG_FIELD_GET(PKG_TIME_UNIT, val_sku_unit); + } } - /* * Initialize 'struct xe_hwmon_energy_info', i.e. set fields to the * first value of the energy register read diff --git a/drivers/gpu/drm/xe/xe_lrc.c b/drivers/gpu/drm/xe/xe_lrc.c index 61a2e87990a9..63d74e27f54c 100644 --- a/drivers/gpu/drm/xe/xe_lrc.c +++ b/drivers/gpu/drm/xe/xe_lrc.c @@ -909,10 +909,7 @@ static void xe_lrc_set_ppgtt(struct xe_lrc *lrc, struct xe_vm *vm) static void xe_lrc_finish(struct xe_lrc *lrc) { xe_hw_fence_ctx_finish(&lrc->fence_ctx); - xe_bo_lock(lrc->bo, false); - xe_bo_unpin(lrc->bo); - xe_bo_unlock(lrc->bo); - xe_bo_put(lrc->bo); + xe_bo_unpin_map_no_vm(lrc->bo); xe_bo_unpin_map_no_vm(lrc->bb_per_ctx_bo); } @@ -1007,7 +1004,7 @@ static int xe_lrc_init(struct xe_lrc *lrc, struct xe_hw_engine *hwe, * FIXME: Perma-pinning LRC as we don't yet support moving GGTT address * via VM bind calls. */ - lrc->bo = xe_bo_create_pin_map(xe, tile, vm, lrc_size, + lrc->bo = xe_bo_create_pin_map(xe, tile, NULL, lrc_size, ttm_bo_type_kernel, bo_flags); if (IS_ERR(lrc->bo)) @@ -1795,9 +1792,6 @@ struct xe_lrc_snapshot *xe_lrc_snapshot_capture(struct xe_lrc *lrc) if (!snapshot) return NULL; - if (lrc->bo->vm) - xe_vm_get(lrc->bo->vm); - snapshot->context_desc = xe_lrc_ggtt_addr(lrc); snapshot->ring_addr = __xe_lrc_ring_ggtt_addr(lrc); snapshot->indirect_context_desc = xe_lrc_indirect_ring_ggtt_addr(lrc); @@ -1819,14 +1813,12 @@ struct xe_lrc_snapshot *xe_lrc_snapshot_capture(struct xe_lrc *lrc) void xe_lrc_snapshot_capture_delayed(struct xe_lrc_snapshot *snapshot) { struct xe_bo *bo; - struct xe_vm *vm; struct iosys_map src; if (!snapshot) return; bo = snapshot->lrc_bo; - vm = bo->vm; snapshot->lrc_bo = NULL; snapshot->lrc_snapshot = kvmalloc(snapshot->lrc_size, GFP_KERNEL); @@ -1846,8 +1838,6 @@ void xe_lrc_snapshot_capture_delayed(struct xe_lrc_snapshot *snapshot) xe_bo_unlock(bo); put_bo: xe_bo_put(bo); - if (vm) - xe_vm_put(vm); } void xe_lrc_snapshot_print(struct xe_lrc_snapshot *snapshot, struct drm_printer *p) @@ -1900,14 +1890,9 @@ void xe_lrc_snapshot_free(struct xe_lrc_snapshot *snapshot) return; kvfree(snapshot->lrc_snapshot); - if (snapshot->lrc_bo) { - struct xe_vm *vm; - - vm = snapshot->lrc_bo->vm; + if (snapshot->lrc_bo) xe_bo_put(snapshot->lrc_bo); - if (vm) - xe_vm_put(vm); - } + kfree(snapshot); } diff --git a/drivers/gpu/drm/xe/xe_pci.c b/drivers/gpu/drm/xe/xe_pci.c index 024175cfe61e..ac4beaed58ff 100644 --- a/drivers/gpu/drm/xe/xe_pci.c +++ b/drivers/gpu/drm/xe/xe_pci.c @@ -66,6 +66,7 @@ struct xe_device_desc { u8 has_heci_gscfi:1; u8 has_heci_cscfi:1; u8 has_llc:1; + u8 has_mbx_power_limits:1; u8 has_pxp:1; u8 has_sriov:1; u8 needs_scratch:1; @@ -306,6 +307,7 @@ static const struct xe_device_desc dg2_desc = { DG2_FEATURES, .has_display = true, .has_fan_control = true, + .has_mbx_power_limits = false, }; static const __maybe_unused struct xe_device_desc pvc_desc = { @@ -317,6 +319,7 @@ static const __maybe_unused struct xe_device_desc pvc_desc = { .has_heci_gscfi = 1, .max_remote_tiles = 1, .require_force_probe = true, + .has_mbx_power_limits = false, }; static const struct xe_device_desc mtl_desc = { @@ -342,6 +345,7 @@ static const struct xe_device_desc bmg_desc = { .dma_mask_size = 46, .has_display = true, .has_fan_control = true, + .has_mbx_power_limits = true, .has_heci_cscfi = 1, .needs_scratch = true, }; @@ -584,6 +588,7 @@ static int xe_info_init_early(struct xe_device *xe, xe->info.dma_mask_size = desc->dma_mask_size; xe->info.is_dgfx = desc->is_dgfx; xe->info.has_fan_control = desc->has_fan_control; + xe->info.has_mbx_power_limits = desc->has_mbx_power_limits; xe->info.has_heci_gscfi = desc->has_heci_gscfi; xe->info.has_heci_cscfi = desc->has_heci_cscfi; xe->info.has_llc = desc->has_llc; diff --git a/drivers/gpu/drm/xe/xe_pcode.c b/drivers/gpu/drm/xe/xe_pcode.c index cf955b3ed52c..9189117fe825 100644 --- a/drivers/gpu/drm/xe/xe_pcode.c +++ b/drivers/gpu/drm/xe/xe_pcode.c @@ -109,6 +109,17 @@ int xe_pcode_write_timeout(struct xe_tile *tile, u32 mbox, u32 data, int timeout return err; } +int xe_pcode_write64_timeout(struct xe_tile *tile, u32 mbox, u32 data0, u32 data1, int timeout) +{ + int err; + + mutex_lock(&tile->pcode.lock); + err = pcode_mailbox_rw(tile, mbox, &data0, &data1, timeout, false, false); + mutex_unlock(&tile->pcode.lock); + + return err; +} + int xe_pcode_read(struct xe_tile *tile, u32 mbox, u32 *val, u32 *val1) { int err; diff --git a/drivers/gpu/drm/xe/xe_pcode.h b/drivers/gpu/drm/xe/xe_pcode.h index ba33991d72a7..de38f44f3201 100644 --- a/drivers/gpu/drm/xe/xe_pcode.h +++ b/drivers/gpu/drm/xe/xe_pcode.h @@ -18,6 +18,9 @@ int xe_pcode_init_min_freq_table(struct xe_tile *tile, u32 min_gt_freq, int xe_pcode_read(struct xe_tile *tile, u32 mbox, u32 *val, u32 *val1); int xe_pcode_write_timeout(struct xe_tile *tile, u32 mbox, u32 val, int timeout_ms); +int xe_pcode_write64_timeout(struct xe_tile *tile, u32 mbox, u32 data0, + u32 data1, int timeout); + #define xe_pcode_write(tile, mbox, val) \ xe_pcode_write_timeout(tile, mbox, val, 1) diff --git a/drivers/gpu/drm/xe/xe_pcode_api.h b/drivers/gpu/drm/xe/xe_pcode_api.h index 127d4d26c4cf..0befdea77db1 100644 --- a/drivers/gpu/drm/xe/xe_pcode_api.h +++ b/drivers/gpu/drm/xe/xe_pcode_api.h @@ -43,6 +43,13 @@ #define POWER_SETUP_I1_SHIFT 6 /* 10.6 fixed point format */ #define POWER_SETUP_I1_DATA_MASK REG_GENMASK(15, 0) +#define READ_PSYSGPU_POWER_LIMIT 0x6 +#define WRITE_PSYSGPU_POWER_LIMIT 0x7 +#define READ_PACKAGE_POWER_LIMIT 0x8 +#define WRITE_PACKAGE_POWER_LIMIT 0x9 +#define READ_PL_FROM_FW 0x1 +#define READ_PL_FROM_PCODE 0x0 + #define PCODE_FREQUENCY_CONFIG 0x6e /* Frequency Config Sub Commands (param1) */ #define PCODE_MBOX_FC_SC_READ_FUSED_P0 0x0 diff --git a/drivers/gpu/drm/xe/xe_pxp.c b/drivers/gpu/drm/xe/xe_pxp.c index 454ea7dc08ac..b5bc15f436fa 100644 --- a/drivers/gpu/drm/xe/xe_pxp.c +++ b/drivers/gpu/drm/xe/xe_pxp.c @@ -541,10 +541,14 @@ int xe_pxp_exec_queue_add(struct xe_pxp *pxp, struct xe_exec_queue *q) */ xe_pm_runtime_get(pxp->xe); - if (!pxp_prerequisites_done(pxp)) { - ret = -EBUSY; + /* get_readiness_status() returns 0 for in-progress and 1 for done */ + ret = xe_pxp_get_readiness_status(pxp); + if (ret <= 0) { + if (!ret) + ret = -EBUSY; goto out; } + ret = 0; wait_for_idle: /* diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c index 79323c78130f..861577746929 100644 --- a/drivers/gpu/drm/xe/xe_vm.c +++ b/drivers/gpu/drm/xe/xe_vm.c @@ -1678,13 +1678,21 @@ struct xe_vm *xe_vm_create(struct xe_device *xe, u32 flags) * scheduler drops all the references of it, hence protecting the VM * for this case is necessary. */ - if (flags & XE_VM_FLAG_LR_MODE) + if (flags & XE_VM_FLAG_LR_MODE) { + INIT_WORK(&vm->preempt.rebind_work, preempt_rebind_work_func); xe_pm_runtime_get_noresume(xe); + } + + if (flags & XE_VM_FLAG_FAULT_MODE) { + err = xe_svm_init(vm); + if (err) + goto err_no_resv; + } vm_resv_obj = drm_gpuvm_resv_object_alloc(&xe->drm); if (!vm_resv_obj) { err = -ENOMEM; - goto err_no_resv; + goto err_svm_fini; } drm_gpuvm_init(&vm->gpuvm, "Xe VM", DRM_GPUVM_RESV_PROTECTED, &xe->drm, @@ -1724,10 +1732,8 @@ struct xe_vm *xe_vm_create(struct xe_device *xe, u32 flags) vm->batch_invalidate_tlb = true; } - if (vm->flags & XE_VM_FLAG_LR_MODE) { - INIT_WORK(&vm->preempt.rebind_work, preempt_rebind_work_func); + if (vm->flags & XE_VM_FLAG_LR_MODE) vm->batch_invalidate_tlb = false; - } /* Fill pt_root after allocating scratch tables */ for_each_tile(tile, xe, id) { @@ -1757,12 +1763,6 @@ struct xe_vm *xe_vm_create(struct xe_device *xe, u32 flags) } } - if (flags & XE_VM_FLAG_FAULT_MODE) { - err = xe_svm_init(vm); - if (err) - goto err_close; - } - if (number_tiles > 1) vm->composite_fence_ctx = dma_fence_context_alloc(1); @@ -1776,6 +1776,11 @@ err_close: xe_vm_close_and_put(vm); return ERR_PTR(err); +err_svm_fini: + if (flags & XE_VM_FLAG_FAULT_MODE) { + vm->size = 0; /* close the vm */ + xe_svm_fini(vm); + } err_no_resv: mutex_destroy(&vm->snap_mutex); for_each_tile(tile, xe, id) diff --git a/drivers/gpu/drm/xe/xe_vm.h b/drivers/gpu/drm/xe/xe_vm.h index 0ef811fc2bde..494af6bdc646 100644 --- a/drivers/gpu/drm/xe/xe_vm.h +++ b/drivers/gpu/drm/xe/xe_vm.h @@ -301,6 +301,75 @@ void xe_vm_snapshot_capture_delayed(struct xe_vm_snapshot *snap); void xe_vm_snapshot_print(struct xe_vm_snapshot *snap, struct drm_printer *p); void xe_vm_snapshot_free(struct xe_vm_snapshot *snap); +/** + * xe_vm_set_validating() - Register this task as currently making bos resident + * @allow_res_evict: Allow eviction of buffer objects bound to @vm when + * validating. + * @vm: Pointer to the vm or NULL. + * + * Register this task as currently making bos resident for the vm. Intended + * to avoid eviction by the same task of shared bos bound to the vm. + * Call with the vm's resv lock held. + * + * Return: A pin cookie that should be used for xe_vm_clear_validating(). + */ +static inline struct pin_cookie xe_vm_set_validating(struct xe_vm *vm, + bool allow_res_evict) +{ + struct pin_cookie cookie = {}; + + if (vm && !allow_res_evict) { + xe_vm_assert_held(vm); + cookie = lockdep_pin_lock(&xe_vm_resv(vm)->lock.base); + /* Pairs with READ_ONCE in xe_vm_is_validating() */ + WRITE_ONCE(vm->validating, current); + } + + return cookie; +} + +/** + * xe_vm_clear_validating() - Unregister this task as currently making bos resident + * @vm: Pointer to the vm or NULL + * @allow_res_evict: Eviction from @vm was allowed. Must be set to the same + * value as for xe_vm_set_validation(). + * @cookie: Cookie obtained from xe_vm_set_validating(). + * + * Register this task as currently making bos resident for the vm. Intended + * to avoid eviction by the same task of shared bos bound to the vm. + * Call with the vm's resv lock held. + */ +static inline void xe_vm_clear_validating(struct xe_vm *vm, bool allow_res_evict, + struct pin_cookie cookie) +{ + if (vm && !allow_res_evict) { + lockdep_unpin_lock(&xe_vm_resv(vm)->lock.base, cookie); + /* Pairs with READ_ONCE in xe_vm_is_validating() */ + WRITE_ONCE(vm->validating, NULL); + } +} + +/** + * xe_vm_is_validating() - Whether bos bound to the vm are currently being made resident + * by the current task. + * @vm: Pointer to the vm. + * + * If this function returns %true, we should be in a vm resv locked region, since + * the current process is the same task that called xe_vm_set_validating(). + * The function asserts that that's indeed the case. + * + * Return: %true if the task is currently making bos resident, %false otherwise. + */ +static inline bool xe_vm_is_validating(struct xe_vm *vm) +{ + /* Pairs with WRITE_ONCE in xe_vm_is_validating() */ + if (READ_ONCE(vm->validating) == current) { + xe_vm_assert_held(vm); + return true; + } + return false; +} + #if IS_ENABLED(CONFIG_DRM_XE_USERPTR_INVAL_INJECT) void xe_vma_userptr_force_invalidate(struct xe_userptr_vma *uvma); #else diff --git a/drivers/gpu/drm/xe/xe_vm_types.h b/drivers/gpu/drm/xe/xe_vm_types.h index 1662604c4486..1979e9bdbdf3 100644 --- a/drivers/gpu/drm/xe/xe_vm_types.h +++ b/drivers/gpu/drm/xe/xe_vm_types.h @@ -310,6 +310,14 @@ struct xe_vm { * protected by the vm resv. */ u64 tlb_flush_seqno; + /** + * @validating: The task that is currently making bos resident for this vm. + * Protected by the VM's resv for writing. Opportunistic reading can be done + * using READ_ONCE. Note: This is a workaround for the + * TTM eviction_valuable() callback not being passed a struct + * ttm_operation_context(). Future work might want to address this. + */ + struct task_struct *validating; /** @batch_invalidate_tlb: Always invalidate TLB before batch start */ bool batch_invalidate_tlb; /** @xef: XE file handle for tracking this VM's drm client */ diff --git a/drivers/greybus/operation.c b/drivers/greybus/operation.c index f6beeebf974c..54ccc434a1f7 100644 --- a/drivers/greybus/operation.c +++ b/drivers/greybus/operation.c @@ -295,7 +295,8 @@ static void gb_operation_work(struct work_struct *work) static void gb_operation_timeout(struct timer_list *t) { - struct gb_operation *operation = from_timer(operation, t, timer); + struct gb_operation *operation = timer_container_of(operation, t, + timer); if (gb_operation_result_set(operation, -ETIMEDOUT)) { /* diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c index ed34f5cd5a91..0639b1f43d88 100644 --- a/drivers/hid/hid-apple.c +++ b/drivers/hid/hid-apple.c @@ -614,7 +614,7 @@ static int apple_fetch_battery(struct hid_device *hdev) static void apple_battery_timer_tick(struct timer_list *t) { - struct apple_sc *asc = from_timer(asc, t, battery_timer); + struct apple_sc *asc = timer_container_of(asc, t, battery_timer); struct hid_device *hdev = asc->hdev; if (apple_fetch_battery(hdev) == 0) { diff --git a/drivers/hid/hid-appleir.c b/drivers/hid/hid-appleir.c index bb7db9ae41c2..5e8ced7bc05a 100644 --- a/drivers/hid/hid-appleir.c +++ b/drivers/hid/hid-appleir.c @@ -167,7 +167,7 @@ static void battery_flat(struct appleir *appleir) static void key_up_tick(struct timer_list *t) { - struct appleir *appleir = from_timer(appleir, t, key_up_timer); + struct appleir *appleir = timer_container_of(appleir, t, key_up_timer); struct hid_device *hid = appleir->hid; unsigned long flags; diff --git a/drivers/hid/hid-appletb-kbd.c b/drivers/hid/hid-appletb-kbd.c index ef51b2c06872..6f251b284018 100644 --- a/drivers/hid/hid-appletb-kbd.c +++ b/drivers/hid/hid-appletb-kbd.c @@ -166,7 +166,7 @@ static int appletb_tb_key_to_slot(unsigned int code) static void appletb_inactivity_timer(struct timer_list *t) { - struct appletb_kbd *kbd = from_timer(kbd, t, inactivity_timer); + struct appletb_kbd *kbd = timer_container_of(kbd, t, inactivity_timer); if (kbd->backlight_dev && appletb_tb_autodim) { if (!kbd->has_dimmed) { diff --git a/drivers/hid/hid-letsketch.c b/drivers/hid/hid-letsketch.c index 8602c63ed9c6..11e21f988723 100644 --- a/drivers/hid/hid-letsketch.c +++ b/drivers/hid/hid-letsketch.c @@ -155,7 +155,8 @@ static int letsketch_setup_input_tablet_pad(struct letsketch_data *data) static void letsketch_inrange_timeout(struct timer_list *t) { - struct letsketch_data *data = from_timer(data, t, inrange_timer); + struct letsketch_data *data = timer_container_of(data, t, + inrange_timer); struct input_dev *input = data->input_tablet; input_report_key(input, BTN_TOOL_PEN, 0); diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c index d4d91e49bbe8..36f034ac605d 100644 --- a/drivers/hid/hid-magicmouse.c +++ b/drivers/hid/hid-magicmouse.c @@ -822,7 +822,7 @@ static int magicmouse_fetch_battery(struct hid_device *hdev) static void magicmouse_battery_timer_tick(struct timer_list *t) { - struct magicmouse_sc *msc = from_timer(msc, t, battery_timer); + struct magicmouse_sc *msc = timer_container_of(msc, t, battery_timer); struct hid_device *hdev = msc->hdev; if (magicmouse_fetch_battery(hdev) == 0) { diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index ded0fef7d8c7..b41001e02da7 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -1745,7 +1745,7 @@ static void mt_release_contacts(struct hid_device *hid) static void mt_expired_timeout(struct timer_list *t) { - struct mt_device *td = from_timer(td, t, release_timer); + struct mt_device *td = timer_container_of(td, t, release_timer); struct hid_device *hdev = td->hdev; /* diff --git a/drivers/hid/hid-prodikeys.c b/drivers/hid/hid-prodikeys.c index c6b922c2adba..74bddb2c3e82 100644 --- a/drivers/hid/hid-prodikeys.c +++ b/drivers/hid/hid-prodikeys.c @@ -227,7 +227,7 @@ drop_note: static void pcmidi_sustained_note_release(struct timer_list *t) { - struct pcmidi_sustain *pms = from_timer(pms, t, timer); + struct pcmidi_sustain *pms = timer_container_of(pms, t, timer); pcmidi_send_note(pms->pm, pms->status, pms->note, pms->velocity); pms->in_use = 0; diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index a2be652b7bbd..b966e4044238 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -545,7 +545,7 @@ static void ghl_magic_poke_cb(struct urb *urb) static void ghl_magic_poke(struct timer_list *t) { int ret; - struct sony_sc *sc = from_timer(sc, t, ghl_poke_timer); + struct sony_sc *sc = timer_container_of(sc, t, ghl_poke_timer); ret = usb_submit_urb(sc->ghl_urb, GFP_ATOMIC); if (ret < 0) diff --git a/drivers/hid/hid-uclogic-core.c b/drivers/hid/hid-uclogic-core.c index 61a4019ddc74..af98398d9247 100644 --- a/drivers/hid/hid-uclogic-core.c +++ b/drivers/hid/hid-uclogic-core.c @@ -32,8 +32,8 @@ */ static void uclogic_inrange_timeout(struct timer_list *t) { - struct uclogic_drvdata *drvdata = from_timer(drvdata, t, - inrange_timer); + struct uclogic_drvdata *drvdata = timer_container_of(drvdata, t, + inrange_timer); struct input_dev *input = drvdata->pen_input; if (input == NULL) diff --git a/drivers/hid/hid-wiimote-core.c b/drivers/hid/hid-wiimote-core.c index 8080083121d3..5b5fc460a4c5 100644 --- a/drivers/hid/hid-wiimote-core.c +++ b/drivers/hid/hid-wiimote-core.c @@ -1240,7 +1240,7 @@ static void wiimote_schedule(struct wiimote_data *wdata) static void wiimote_init_timeout(struct timer_list *t) { - struct wiimote_data *wdata = from_timer(wdata, t, timer); + struct wiimote_data *wdata = timer_container_of(wdata, t, timer); wiimote_schedule(wdata); } diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index d4cbecc668ec..aac0051a2cf6 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c @@ -106,7 +106,7 @@ static int hid_start_in(struct hid_device *hid) /* I/O retry timer routine */ static void hid_retry_timeout(struct timer_list *t) { - struct usbhid_device *usbhid = from_timer(usbhid, t, io_retry); + struct usbhid_device *usbhid = timer_container_of(usbhid, t, io_retry); struct hid_device *hid = usbhid->hid; dev_dbg(&usbhid->intf->dev, "retrying intr urb\n"); diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index 5107a676e24f..955b39d22524 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -63,7 +63,7 @@ static void wacom_force_proxout(struct wacom_wac *wacom_wac) void wacom_idleprox_timeout(struct timer_list *list) { - struct wacom *wacom = from_timer(wacom, list, idleprox_timer); + struct wacom *wacom = timer_container_of(wacom, list, idleprox_timer); struct wacom_wac *wacom_wac = &wacom->wacom_wac; if (!wacom_wac->hid_data.sense_state) { diff --git a/drivers/hsi/clients/ssi_protocol.c b/drivers/hsi/clients/ssi_protocol.c index cbc5e72857de..d10a01f3eb9e 100644 --- a/drivers/hsi/clients/ssi_protocol.c +++ b/drivers/hsi/clients/ssi_protocol.c @@ -453,7 +453,7 @@ static void ssip_error(struct hsi_client *cl) static void ssip_keep_alive(struct timer_list *t) { - struct ssi_protocol *ssi = from_timer(ssi, t, keep_alive); + struct ssi_protocol *ssi = timer_container_of(ssi, t, keep_alive); struct hsi_client *cl = ssi->cl; dev_dbg(&cl->device, "Keep alive kick in: m(%d) r(%d) s(%d)\n", @@ -480,7 +480,7 @@ static void ssip_keep_alive(struct timer_list *t) static void ssip_rx_wd(struct timer_list *t) { - struct ssi_protocol *ssi = from_timer(ssi, t, rx_wd); + struct ssi_protocol *ssi = timer_container_of(ssi, t, rx_wd); struct hsi_client *cl = ssi->cl; dev_err(&cl->device, "Watchdog triggered\n"); @@ -489,7 +489,7 @@ static void ssip_rx_wd(struct timer_list *t) static void ssip_tx_wd(struct timer_list *t) { - struct ssi_protocol *ssi = from_timer(ssi, t, tx_wd); + struct ssi_protocol *ssi = timer_container_of(ssi, t, tx_wd); struct hsi_client *cl = ssi->cl; dev_err(&cl->device, "Watchdog triggered\n"); diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 1b1d64493909..079620dd4286 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -1905,16 +1905,6 @@ config SENSORS_SBTSI This driver can also be built as a module. If so, the module will be called sbtsi_temp. -config SENSORS_SBRMI - tristate "Emulated SB-RMI sensor" - depends on I2C - help - If you say yes here you get support for emulated RMI - sensors on AMD SoCs with APML interface connected to a BMC device. - - This driver can also be built as a module. If so, the module will - be called sbrmi. - config SENSORS_SHT15 tristate "Sensiron humidity and temperature sensors. SHT15 and compat." depends on GPIOLIB || COMPILE_TEST diff --git a/drivers/hwmon/npcm750-pwm-fan.c b/drivers/hwmon/npcm750-pwm-fan.c index db3b551828eb..802c73def428 100644 --- a/drivers/hwmon/npcm750-pwm-fan.c +++ b/drivers/hwmon/npcm750-pwm-fan.c @@ -331,7 +331,7 @@ static void npcm7xx_fan_polling(struct timer_list *t) struct npcm7xx_pwm_fan_data *data; int i; - data = from_timer(data, t, fan_timer); + data = timer_container_of(data, t, fan_timer); /* * Polling two module per one round, diff --git a/drivers/hwmon/pwm-fan.c b/drivers/hwmon/pwm-fan.c index 2df294793f6e..d0fe53451bdf 100644 --- a/drivers/hwmon/pwm-fan.c +++ b/drivers/hwmon/pwm-fan.c @@ -78,7 +78,7 @@ static irqreturn_t pulse_handler(int irq, void *dev_id) static void sample_timer(struct timer_list *t) { - struct pwm_fan_ctx *ctx = from_timer(ctx, t, rpm_timer); + struct pwm_fan_ctx *ctx = timer_container_of(ctx, t, rpm_timer); unsigned int delta = ktime_ms_delta(ktime_get(), ctx->sample_start); int i; diff --git a/drivers/hwmon/sbrmi.c b/drivers/hwmon/sbrmi.c deleted file mode 100644 index d48d8e5460ff..000000000000 --- a/drivers/hwmon/sbrmi.c +++ /dev/null @@ -1,357 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * sbrmi.c - hwmon driver for a SB-RMI mailbox - * compliant AMD SoC device. - * - * Copyright (C) 2020-2021 Advanced Micro Devices, Inc. - */ - -#include <linux/delay.h> -#include <linux/err.h> -#include <linux/hwmon.h> -#include <linux/i2c.h> -#include <linux/init.h> -#include <linux/module.h> -#include <linux/mutex.h> -#include <linux/of.h> - -/* Do not allow setting negative power limit */ -#define SBRMI_PWR_MIN 0 -/* Mask for Status Register bit[1] */ -#define SW_ALERT_MASK 0x2 - -/* Software Interrupt for triggering */ -#define START_CMD 0x80 -#define TRIGGER_MAILBOX 0x01 - -/* - * SB-RMI supports soft mailbox service request to MP1 (power management - * firmware) through SBRMI inbound/outbound message registers. - * SB-RMI message IDs - */ -enum sbrmi_msg_id { - SBRMI_READ_PKG_PWR_CONSUMPTION = 0x1, - SBRMI_WRITE_PKG_PWR_LIMIT, - SBRMI_READ_PKG_PWR_LIMIT, - SBRMI_READ_PKG_MAX_PWR_LIMIT, -}; - -/* SB-RMI registers */ -enum sbrmi_reg { - SBRMI_CTRL = 0x01, - SBRMI_STATUS, - SBRMI_OUTBNDMSG0 = 0x30, - SBRMI_OUTBNDMSG1, - SBRMI_OUTBNDMSG2, - SBRMI_OUTBNDMSG3, - SBRMI_OUTBNDMSG4, - SBRMI_OUTBNDMSG5, - SBRMI_OUTBNDMSG6, - SBRMI_OUTBNDMSG7, - SBRMI_INBNDMSG0, - SBRMI_INBNDMSG1, - SBRMI_INBNDMSG2, - SBRMI_INBNDMSG3, - SBRMI_INBNDMSG4, - SBRMI_INBNDMSG5, - SBRMI_INBNDMSG6, - SBRMI_INBNDMSG7, - SBRMI_SW_INTERRUPT, -}; - -/* Each client has this additional data */ -struct sbrmi_data { - struct i2c_client *client; - struct mutex lock; - u32 pwr_limit_max; -}; - -struct sbrmi_mailbox_msg { - u8 cmd; - bool read; - u32 data_in; - u32 data_out; -}; - -static int sbrmi_enable_alert(struct i2c_client *client) -{ - int ctrl; - - /* - * Enable the SB-RMI Software alert status - * by writing 0 to bit 4 of Control register(0x1) - */ - ctrl = i2c_smbus_read_byte_data(client, SBRMI_CTRL); - if (ctrl < 0) - return ctrl; - - if (ctrl & 0x10) { - ctrl &= ~0x10; - return i2c_smbus_write_byte_data(client, - SBRMI_CTRL, ctrl); - } - - return 0; -} - -static int rmi_mailbox_xfer(struct sbrmi_data *data, - struct sbrmi_mailbox_msg *msg) -{ - int i, ret, retry = 10; - int sw_status; - u8 byte; - - mutex_lock(&data->lock); - - /* Indicate firmware a command is to be serviced */ - ret = i2c_smbus_write_byte_data(data->client, - SBRMI_INBNDMSG7, START_CMD); - if (ret < 0) - goto exit_unlock; - - /* Write the command to SBRMI::InBndMsg_inst0 */ - ret = i2c_smbus_write_byte_data(data->client, - SBRMI_INBNDMSG0, msg->cmd); - if (ret < 0) - goto exit_unlock; - - /* - * For both read and write the initiator (BMC) writes - * Command Data In[31:0] to SBRMI::InBndMsg_inst[4:1] - * SBRMI_x3C(MSB):SBRMI_x39(LSB) - */ - for (i = 0; i < 4; i++) { - byte = (msg->data_in >> i * 8) & 0xff; - ret = i2c_smbus_write_byte_data(data->client, - SBRMI_INBNDMSG1 + i, byte); - if (ret < 0) - goto exit_unlock; - } - - /* - * Write 0x01 to SBRMI::SoftwareInterrupt to notify firmware to - * perform the requested read or write command - */ - ret = i2c_smbus_write_byte_data(data->client, - SBRMI_SW_INTERRUPT, TRIGGER_MAILBOX); - if (ret < 0) - goto exit_unlock; - - /* - * Firmware will write SBRMI::Status[SwAlertSts]=1 to generate - * an ALERT (if enabled) to initiator (BMC) to indicate completion - * of the requested command - */ - do { - sw_status = i2c_smbus_read_byte_data(data->client, - SBRMI_STATUS); - if (sw_status < 0) { - ret = sw_status; - goto exit_unlock; - } - if (sw_status & SW_ALERT_MASK) - break; - usleep_range(50, 100); - } while (retry--); - - if (retry < 0) { - dev_err(&data->client->dev, - "Firmware fail to indicate command completion\n"); - ret = -EIO; - goto exit_unlock; - } - - /* - * For a read operation, the initiator (BMC) reads the firmware - * response Command Data Out[31:0] from SBRMI::OutBndMsg_inst[4:1] - * {SBRMI_x34(MSB):SBRMI_x31(LSB)}. - */ - if (msg->read) { - for (i = 0; i < 4; i++) { - ret = i2c_smbus_read_byte_data(data->client, - SBRMI_OUTBNDMSG1 + i); - if (ret < 0) - goto exit_unlock; - msg->data_out |= ret << i * 8; - } - } - - /* - * BMC must write 1'b1 to SBRMI::Status[SwAlertSts] to clear the - * ALERT to initiator - */ - ret = i2c_smbus_write_byte_data(data->client, SBRMI_STATUS, - sw_status | SW_ALERT_MASK); - -exit_unlock: - mutex_unlock(&data->lock); - return ret; -} - -static int sbrmi_read(struct device *dev, enum hwmon_sensor_types type, - u32 attr, int channel, long *val) -{ - struct sbrmi_data *data = dev_get_drvdata(dev); - struct sbrmi_mailbox_msg msg = { 0 }; - int ret; - - if (type != hwmon_power) - return -EINVAL; - - msg.read = true; - switch (attr) { - case hwmon_power_input: - msg.cmd = SBRMI_READ_PKG_PWR_CONSUMPTION; - ret = rmi_mailbox_xfer(data, &msg); - break; - case hwmon_power_cap: - msg.cmd = SBRMI_READ_PKG_PWR_LIMIT; - ret = rmi_mailbox_xfer(data, &msg); - break; - case hwmon_power_cap_max: - msg.data_out = data->pwr_limit_max; - ret = 0; - break; - default: - return -EINVAL; - } - if (ret < 0) - return ret; - /* hwmon power attributes are in microWatt */ - *val = (long)msg.data_out * 1000; - return ret; -} - -static int sbrmi_write(struct device *dev, enum hwmon_sensor_types type, - u32 attr, int channel, long val) -{ - struct sbrmi_data *data = dev_get_drvdata(dev); - struct sbrmi_mailbox_msg msg = { 0 }; - - if (type != hwmon_power && attr != hwmon_power_cap) - return -EINVAL; - /* - * hwmon power attributes are in microWatt - * mailbox read/write is in mWatt - */ - val /= 1000; - - val = clamp_val(val, SBRMI_PWR_MIN, data->pwr_limit_max); - - msg.cmd = SBRMI_WRITE_PKG_PWR_LIMIT; - msg.data_in = val; - msg.read = false; - - return rmi_mailbox_xfer(data, &msg); -} - -static umode_t sbrmi_is_visible(const void *data, - enum hwmon_sensor_types type, - u32 attr, int channel) -{ - switch (type) { - case hwmon_power: - switch (attr) { - case hwmon_power_input: - case hwmon_power_cap_max: - return 0444; - case hwmon_power_cap: - return 0644; - } - break; - default: - break; - } - return 0; -} - -static const struct hwmon_channel_info * const sbrmi_info[] = { - HWMON_CHANNEL_INFO(power, - HWMON_P_INPUT | HWMON_P_CAP | HWMON_P_CAP_MAX), - NULL -}; - -static const struct hwmon_ops sbrmi_hwmon_ops = { - .is_visible = sbrmi_is_visible, - .read = sbrmi_read, - .write = sbrmi_write, -}; - -static const struct hwmon_chip_info sbrmi_chip_info = { - .ops = &sbrmi_hwmon_ops, - .info = sbrmi_info, -}; - -static int sbrmi_get_max_pwr_limit(struct sbrmi_data *data) -{ - struct sbrmi_mailbox_msg msg = { 0 }; - int ret; - - msg.cmd = SBRMI_READ_PKG_MAX_PWR_LIMIT; - msg.read = true; - ret = rmi_mailbox_xfer(data, &msg); - if (ret < 0) - return ret; - data->pwr_limit_max = msg.data_out; - - return ret; -} - -static int sbrmi_probe(struct i2c_client *client) -{ - struct device *dev = &client->dev; - struct device *hwmon_dev; - struct sbrmi_data *data; - int ret; - - data = devm_kzalloc(dev, sizeof(struct sbrmi_data), GFP_KERNEL); - if (!data) - return -ENOMEM; - - data->client = client; - mutex_init(&data->lock); - - /* Enable alert for SB-RMI sequence */ - ret = sbrmi_enable_alert(client); - if (ret < 0) - return ret; - - /* Cache maximum power limit */ - ret = sbrmi_get_max_pwr_limit(data); - if (ret < 0) - return ret; - - hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, data, - &sbrmi_chip_info, NULL); - - return PTR_ERR_OR_ZERO(hwmon_dev); -} - -static const struct i2c_device_id sbrmi_id[] = { - {"sbrmi"}, - {} -}; -MODULE_DEVICE_TABLE(i2c, sbrmi_id); - -static const struct of_device_id __maybe_unused sbrmi_of_match[] = { - { - .compatible = "amd,sbrmi", - }, - { }, -}; -MODULE_DEVICE_TABLE(of, sbrmi_of_match); - -static struct i2c_driver sbrmi_driver = { - .driver = { - .name = "sbrmi", - .of_match_table = of_match_ptr(sbrmi_of_match), - }, - .probe = sbrmi_probe, - .id_table = sbrmi_id, -}; - -module_i2c_driver(sbrmi_driver); - -MODULE_AUTHOR("Akshay Gupta <akshay.gupta@amd.com>"); -MODULE_DESCRIPTION("Hwmon driver for AMD SB-RMI emulated sensor"); -MODULE_LICENSE("GPL"); diff --git a/drivers/hwtracing/coresight/Kconfig b/drivers/hwtracing/coresight/Kconfig index ecd7086a5b83..f064e3d172b3 100644 --- a/drivers/hwtracing/coresight/Kconfig +++ b/drivers/hwtracing/coresight/Kconfig @@ -259,4 +259,13 @@ config CORESIGHT_DUMMY To compile this driver as a module, choose M here: the module will be called coresight-dummy. + +config CORESIGHT_KUNIT_TESTS + tristate "Enable Coresight unit tests" + depends on KUNIT + default KUNIT_ALL_TESTS + help + Enable Coresight unit tests. Only useful for development and not + intended for production. + endif diff --git a/drivers/hwtracing/coresight/Makefile b/drivers/hwtracing/coresight/Makefile index 8e62c3150aeb..4e7cc3c5bf99 100644 --- a/drivers/hwtracing/coresight/Makefile +++ b/drivers/hwtracing/coresight/Makefile @@ -22,6 +22,8 @@ condflags := \ $(call cc-option, -Wstringop-truncation) subdir-ccflags-y += $(condflags) +CFLAGS_coresight-stm.o := -D__DISABLE_TRACE_MMIO__ + obj-$(CONFIG_CORESIGHT) += coresight.o coresight-y := coresight-core.o coresight-etm-perf.o coresight-platform.o \ coresight-sysfs.o coresight-syscfg.o coresight-config.o \ @@ -53,3 +55,4 @@ obj-$(CONFIG_ULTRASOC_SMB) += ultrasoc-smb.o obj-$(CONFIG_CORESIGHT_DUMMY) += coresight-dummy.o obj-$(CONFIG_CORESIGHT_CTCU) += coresight-ctcu.o coresight-ctcu-y := coresight-ctcu-core.o +obj-$(CONFIG_CORESIGHT_KUNIT_TESTS) += coresight-kunit-tests.o diff --git a/drivers/hwtracing/coresight/coresight-catu.c b/drivers/hwtracing/coresight/coresight-catu.c index fa170c966bc3..5058432233da 100644 --- a/drivers/hwtracing/coresight/coresight-catu.c +++ b/drivers/hwtracing/coresight/coresight-catu.c @@ -113,9 +113,8 @@ typedef u64 cate_t; * containing the data page pointer for @offset. If @daddrp is not NULL, * @daddrp points the DMA address of the beginning of the table. */ -static inline cate_t *catu_get_table(struct tmc_sg_table *catu_table, - unsigned long offset, - dma_addr_t *daddrp) +static cate_t *catu_get_table(struct tmc_sg_table *catu_table, unsigned long offset, + dma_addr_t *daddrp) { unsigned long buf_size = tmc_sg_table_buf_size(catu_table); unsigned int table_nr, pg_idx, pg_offset; @@ -165,12 +164,12 @@ static void catu_dump_table(struct tmc_sg_table *catu_table) } #else -static inline void catu_dump_table(struct tmc_sg_table *catu_table) +static void catu_dump_table(struct tmc_sg_table *catu_table) { } #endif -static inline cate_t catu_make_entry(dma_addr_t addr) +static cate_t catu_make_entry(dma_addr_t addr) { return addr ? CATU_VALID_ENTRY(addr) : 0; } @@ -390,7 +389,7 @@ static const struct attribute_group *catu_groups[] = { }; -static inline int catu_wait_for_ready(struct catu_drvdata *drvdata) +static int catu_wait_for_ready(struct catu_drvdata *drvdata) { struct csdev_access *csa = &drvdata->csdev->access; @@ -458,12 +457,17 @@ static int catu_enable_hw(struct catu_drvdata *drvdata, enum cs_mode cs_mode, static int catu_enable(struct coresight_device *csdev, enum cs_mode mode, void *data) { - int rc; + int rc = 0; struct catu_drvdata *catu_drvdata = csdev_to_catu_drvdata(csdev); - CS_UNLOCK(catu_drvdata->base); - rc = catu_enable_hw(catu_drvdata, mode, data); - CS_LOCK(catu_drvdata->base); + guard(raw_spinlock_irqsave)(&catu_drvdata->spinlock); + if (csdev->refcnt == 0) { + CS_UNLOCK(catu_drvdata->base); + rc = catu_enable_hw(catu_drvdata, mode, data); + CS_LOCK(catu_drvdata->base); + } + if (!rc) + csdev->refcnt++; return rc; } @@ -486,12 +490,15 @@ static int catu_disable_hw(struct catu_drvdata *drvdata) static int catu_disable(struct coresight_device *csdev, void *__unused) { - int rc; + int rc = 0; struct catu_drvdata *catu_drvdata = csdev_to_catu_drvdata(csdev); - CS_UNLOCK(catu_drvdata->base); - rc = catu_disable_hw(catu_drvdata); - CS_LOCK(catu_drvdata->base); + guard(raw_spinlock_irqsave)(&catu_drvdata->spinlock); + if (--csdev->refcnt == 0) { + CS_UNLOCK(catu_drvdata->base); + rc = catu_disable_hw(catu_drvdata); + CS_LOCK(catu_drvdata->base); + } return rc; } @@ -550,6 +557,7 @@ static int __catu_probe(struct device *dev, struct resource *res) dev->platform_data = pdata; drvdata->base = base; + raw_spin_lock_init(&drvdata->spinlock); catu_desc.access = CSDEV_ACCESS_IOMEM(base); catu_desc.pdata = pdata; catu_desc.dev = dev; @@ -558,6 +566,7 @@ static int __catu_probe(struct device *dev, struct resource *res) catu_desc.subtype.helper_subtype = CORESIGHT_DEV_SUBTYPE_HELPER_CATU; catu_desc.ops = &catu_ops; + coresight_clear_self_claim_tag(&catu_desc.access); drvdata->csdev = coresight_register(&catu_desc); if (IS_ERR(drvdata->csdev)) ret = PTR_ERR(drvdata->csdev); @@ -702,7 +711,7 @@ static int __init catu_init(void) { int ret; - ret = coresight_init_driver("catu", &catu_driver, &catu_platform_driver); + ret = coresight_init_driver("catu", &catu_driver, &catu_platform_driver, THIS_MODULE); tmc_etr_set_catu_ops(&etr_catu_buf_ops); return ret; } diff --git a/drivers/hwtracing/coresight/coresight-catu.h b/drivers/hwtracing/coresight/coresight-catu.h index 141feac1c14b..755776cd19c5 100644 --- a/drivers/hwtracing/coresight/coresight-catu.h +++ b/drivers/hwtracing/coresight/coresight-catu.h @@ -65,6 +65,7 @@ struct catu_drvdata { void __iomem *base; struct coresight_device *csdev; int irq; + raw_spinlock_t spinlock; }; #define CATU_REG32(name, offset) \ diff --git a/drivers/hwtracing/coresight/coresight-config.h b/drivers/hwtracing/coresight/coresight-config.h index b9ebc9fcfb7f..90fd937d3bd8 100644 --- a/drivers/hwtracing/coresight/coresight-config.h +++ b/drivers/hwtracing/coresight/coresight-config.h @@ -228,7 +228,7 @@ struct cscfg_feature_csdev { * @feats_csdev:references to the device features to enable. */ struct cscfg_config_csdev { - const struct cscfg_config_desc *config_desc; + struct cscfg_config_desc *config_desc; struct coresight_device *csdev; bool enabled; struct list_head node; diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c index fb43ef6a3b1f..fa758cc21827 100644 --- a/drivers/hwtracing/coresight/coresight-core.c +++ b/drivers/hwtracing/coresight/coresight-core.c @@ -129,34 +129,36 @@ coresight_find_out_connection(struct coresight_device *csdev, return ERR_PTR(-ENODEV); } -static inline u32 coresight_read_claim_tags(struct coresight_device *csdev) +static u32 coresight_read_claim_tags_unlocked(struct coresight_device *csdev) { - return csdev_access_relaxed_read32(&csdev->access, CORESIGHT_CLAIMCLR); + return FIELD_GET(CORESIGHT_CLAIM_MASK, + csdev_access_relaxed_read32(&csdev->access, CORESIGHT_CLAIMCLR)); } -static inline bool coresight_is_claimed_self_hosted(struct coresight_device *csdev) -{ - return coresight_read_claim_tags(csdev) == CORESIGHT_CLAIM_SELF_HOSTED; -} - -static inline bool coresight_is_claimed_any(struct coresight_device *csdev) -{ - return coresight_read_claim_tags(csdev) != 0; -} - -static inline void coresight_set_claim_tags(struct coresight_device *csdev) +static void coresight_set_self_claim_tag_unlocked(struct coresight_device *csdev) { csdev_access_relaxed_write32(&csdev->access, CORESIGHT_CLAIM_SELF_HOSTED, CORESIGHT_CLAIMSET); isb(); } -static inline void coresight_clear_claim_tags(struct coresight_device *csdev) +void coresight_clear_self_claim_tag(struct csdev_access *csa) { - csdev_access_relaxed_write32(&csdev->access, CORESIGHT_CLAIM_SELF_HOSTED, + if (csa->io_mem) + CS_UNLOCK(csa->base); + coresight_clear_self_claim_tag_unlocked(csa); + if (csa->io_mem) + CS_LOCK(csa->base); +} +EXPORT_SYMBOL_GPL(coresight_clear_self_claim_tag); + +void coresight_clear_self_claim_tag_unlocked(struct csdev_access *csa) +{ + csdev_access_relaxed_write32(csa, CORESIGHT_CLAIM_SELF_HOSTED, CORESIGHT_CLAIMCLR); isb(); } +EXPORT_SYMBOL_GPL(coresight_clear_self_claim_tag_unlocked); /* * coresight_claim_device_unlocked : Claim the device for self-hosted usage @@ -170,18 +172,41 @@ static inline void coresight_clear_claim_tags(struct coresight_device *csdev) */ int coresight_claim_device_unlocked(struct coresight_device *csdev) { + int tag; + struct csdev_access *csa; + if (WARN_ON(!csdev)) return -EINVAL; - if (coresight_is_claimed_any(csdev)) + csa = &csdev->access; + tag = coresight_read_claim_tags_unlocked(csdev); + + switch (tag) { + case CORESIGHT_CLAIM_FREE: + coresight_set_self_claim_tag_unlocked(csdev); + if (coresight_read_claim_tags_unlocked(csdev) == CORESIGHT_CLAIM_SELF_HOSTED) + return 0; + + /* There was a race setting the tag, clean up and fail */ + coresight_clear_self_claim_tag_unlocked(csa); + dev_dbg(&csdev->dev, "Busy: Couldn't set self claim tag"); return -EBUSY; - coresight_set_claim_tags(csdev); - if (coresight_is_claimed_self_hosted(csdev)) - return 0; - /* There was a race setting the tags, clean up and fail */ - coresight_clear_claim_tags(csdev); - return -EBUSY; + case CORESIGHT_CLAIM_EXTERNAL: + /* External debug is an expected state, so log and report BUSY */ + dev_dbg(&csdev->dev, "Busy: Claimed by external debugger"); + return -EBUSY; + + default: + case CORESIGHT_CLAIM_SELF_HOSTED: + case CORESIGHT_CLAIM_INVALID: + /* + * Warn here because we clear a lingering self hosted tag + * on probe, so other tag combinations are impossible. + */ + dev_err_once(&csdev->dev, "Invalid claim tag state: %x", tag); + return -EBUSY; + } } EXPORT_SYMBOL_GPL(coresight_claim_device_unlocked); @@ -201,7 +226,7 @@ int coresight_claim_device(struct coresight_device *csdev) EXPORT_SYMBOL_GPL(coresight_claim_device); /* - * coresight_disclaim_device_unlocked : Clear the claim tags for the device. + * coresight_disclaim_device_unlocked : Clear the claim tag for the device. * Called with CS_UNLOCKed for the component. */ void coresight_disclaim_device_unlocked(struct coresight_device *csdev) @@ -210,15 +235,15 @@ void coresight_disclaim_device_unlocked(struct coresight_device *csdev) if (WARN_ON(!csdev)) return; - if (coresight_is_claimed_self_hosted(csdev)) - coresight_clear_claim_tags(csdev); + if (coresight_read_claim_tags_unlocked(csdev) == CORESIGHT_CLAIM_SELF_HOSTED) + coresight_clear_self_claim_tag_unlocked(&csdev->access); else /* * The external agent may have not honoured our claim * and has manipulated it. Or something else has seriously * gone wrong in our driver. */ - WARN_ON_ONCE(1); + dev_WARN_ONCE(&csdev->dev, 1, "External agent took claim tag"); } EXPORT_SYMBOL_GPL(coresight_disclaim_device_unlocked); @@ -367,6 +392,28 @@ void coresight_disable_source(struct coresight_device *csdev, void *data) } EXPORT_SYMBOL_GPL(coresight_disable_source); +void coresight_pause_source(struct coresight_device *csdev) +{ + if (!coresight_is_percpu_source(csdev)) + return; + + if (source_ops(csdev)->pause_perf) + source_ops(csdev)->pause_perf(csdev); +} +EXPORT_SYMBOL_GPL(coresight_pause_source); + +int coresight_resume_source(struct coresight_device *csdev) +{ + if (!coresight_is_percpu_source(csdev)) + return -EOPNOTSUPP; + + if (!source_ops(csdev)->resume_perf) + return -EOPNOTSUPP; + + return source_ops(csdev)->resume_perf(csdev); +} +EXPORT_SYMBOL_GPL(coresight_resume_source); + /* * coresight_disable_path_from : Disable components in the given path beyond * @nd in the list. If @nd is NULL, all the components, except the SOURCE are @@ -465,7 +512,7 @@ int coresight_enable_path(struct coresight_path *path, enum cs_mode mode, /* Enable all helpers adjacent to the path first */ ret = coresight_enable_helpers(csdev, mode, path); if (ret) - goto err; + goto err_disable_path; /* * ETF devices are tricky... They can be a link or a sink, * depending on how they are configured. If an ETF has been @@ -486,8 +533,10 @@ int coresight_enable_path(struct coresight_path *path, enum cs_mode mode, * that need disabling. Disabling the path here * would mean we could disrupt an existing session. */ - if (ret) + if (ret) { + coresight_disable_helpers(csdev, path); goto out; + } break; case CORESIGHT_DEV_TYPE_SOURCE: /* sources are enabled from either sysFS or Perf */ @@ -497,16 +546,19 @@ int coresight_enable_path(struct coresight_path *path, enum cs_mode mode, child = list_next_entry(nd, link)->csdev; ret = coresight_enable_link(csdev, parent, child, source); if (ret) - goto err; + goto err_disable_helpers; break; default: - goto err; + ret = -EINVAL; + goto err_disable_helpers; } } out: return ret; -err: +err_disable_helpers: + coresight_disable_helpers(csdev, path); +err_disable_path: coresight_disable_path_from(path, nd); goto out; } @@ -579,7 +631,7 @@ struct coresight_device *coresight_get_sink_by_id(u32 id) * Return true in successful case and power up the device. * Return false when failed to get reference of module. */ -static inline bool coresight_get_ref(struct coresight_device *csdev) +static bool coresight_get_ref(struct coresight_device *csdev) { struct device *dev = csdev->dev.parent; @@ -598,7 +650,7 @@ static inline bool coresight_get_ref(struct coresight_device *csdev) * * @csdev: The coresight device to decrement a reference from. */ -static inline void coresight_put_ref(struct coresight_device *csdev) +static void coresight_put_ref(struct coresight_device *csdev) { struct device *dev = csdev->dev.parent; @@ -821,7 +873,7 @@ void coresight_release_path(struct coresight_path *path) } /* return true if the device is a suitable type for a default sink */ -static inline bool coresight_is_def_sink_type(struct coresight_device *csdev) +static bool coresight_is_def_sink_type(struct coresight_device *csdev) { /* sink & correct subtype */ if (((csdev->type == CORESIGHT_DEV_TYPE_SINK) || @@ -959,6 +1011,7 @@ coresight_find_default_sink(struct coresight_device *csdev) } return csdev->def_sink; } +EXPORT_SYMBOL_GPL(coresight_find_default_sink); static int coresight_remove_sink_ref(struct device *dev, void *data) { @@ -1385,8 +1438,8 @@ EXPORT_SYMBOL_GPL(coresight_unregister); * * Returns the index of the entry, when found. Otherwise, -ENOENT. */ -static inline int coresight_search_device_idx(struct coresight_dev_list *dict, - struct fwnode_handle *fwnode) +static int coresight_search_device_idx(struct coresight_dev_list *dict, + struct fwnode_handle *fwnode) { int i; @@ -1585,17 +1638,17 @@ module_init(coresight_init); module_exit(coresight_exit); int coresight_init_driver(const char *drv, struct amba_driver *amba_drv, - struct platform_driver *pdev_drv) + struct platform_driver *pdev_drv, struct module *owner) { int ret; - ret = amba_driver_register(amba_drv); + ret = __amba_driver_register(amba_drv, owner); if (ret) { pr_err("%s: error registering AMBA driver\n", drv); return ret; } - ret = platform_driver_register(pdev_drv); + ret = __platform_driver_register(pdev_drv, owner); if (!ret) return 0; diff --git a/drivers/hwtracing/coresight/coresight-cpu-debug.c b/drivers/hwtracing/coresight/coresight-cpu-debug.c index 342c3aaf414d..a871d997330b 100644 --- a/drivers/hwtracing/coresight/coresight-cpu-debug.c +++ b/drivers/hwtracing/coresight/coresight-cpu-debug.c @@ -774,7 +774,8 @@ static struct platform_driver debug_platform_driver = { static int __init debug_init(void) { - return coresight_init_driver("debug", &debug_driver, &debug_platform_driver); + return coresight_init_driver("debug", &debug_driver, &debug_platform_driver, + THIS_MODULE); } static void __exit debug_exit(void) diff --git a/drivers/hwtracing/coresight/coresight-cti-core.c b/drivers/hwtracing/coresight/coresight-cti-core.c index 80f6265e3740..8fb30dd73fd2 100644 --- a/drivers/hwtracing/coresight/coresight-cti-core.c +++ b/drivers/hwtracing/coresight/coresight-cti-core.c @@ -931,6 +931,8 @@ static int cti_probe(struct amba_device *adev, const struct amba_id *id) cti_desc.ops = &cti_ops; cti_desc.groups = drvdata->ctidev.con_groups; cti_desc.dev = dev; + + coresight_clear_self_claim_tag(&cti_desc.access); drvdata->csdev = coresight_register(&cti_desc); if (IS_ERR(drvdata->csdev)) { ret = PTR_ERR(drvdata->csdev); diff --git a/drivers/hwtracing/coresight/coresight-cti.h b/drivers/hwtracing/coresight/coresight-cti.h index 16e310e7e9d4..8362a47c939c 100644 --- a/drivers/hwtracing/coresight/coresight-cti.h +++ b/drivers/hwtracing/coresight/coresight-cti.h @@ -9,7 +9,6 @@ #include <linux/coresight.h> #include <linux/device.h> -#include <linux/fwnode.h> #include <linux/list.h> #include <linux/spinlock.h> #include <linux/sysfs.h> @@ -17,6 +16,8 @@ #include "coresight-priv.h" +struct fwnode_handle; + /* * Device registers * 0x000 - 0x144: CTI programming and status diff --git a/drivers/hwtracing/coresight/coresight-etb10.c b/drivers/hwtracing/coresight/coresight-etb10.c index 7948597d483d..d5efb085b30d 100644 --- a/drivers/hwtracing/coresight/coresight-etb10.c +++ b/drivers/hwtracing/coresight/coresight-etb10.c @@ -95,7 +95,7 @@ struct etb_drvdata { static int etb_set_buffer(struct coresight_device *csdev, struct perf_output_handle *handle); -static inline unsigned int etb_get_buffer_depth(struct etb_drvdata *drvdata) +static unsigned int etb_get_buffer_depth(struct etb_drvdata *drvdata) { return readl_relaxed(drvdata->base + ETB_RAM_DEPTH_REG); } @@ -772,6 +772,8 @@ static int etb_probe(struct amba_device *adev, const struct amba_id *id) desc.pdata = pdata; desc.dev = dev; desc.groups = coresight_etb_groups; + + coresight_clear_self_claim_tag(&desc.access); drvdata->csdev = coresight_register(&desc); if (IS_ERR(drvdata->csdev)) return PTR_ERR(drvdata->csdev); diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.c b/drivers/hwtracing/coresight/coresight-etm-perf.c index f4cccd68e625..f1551c08ecb2 100644 --- a/drivers/hwtracing/coresight/coresight-etm-perf.c +++ b/drivers/hwtracing/coresight/coresight-etm-perf.c @@ -366,6 +366,18 @@ static void *etm_setup_aux(struct perf_event *event, void **pages, } /* + * If AUX pause feature is enabled but the ETM driver does not + * support the operations, clear this CPU from the mask and + * continue to next one. + */ + if (event->attr.aux_start_paused && + (!source_ops(csdev)->pause_perf || !source_ops(csdev)->resume_perf)) { + dev_err_once(&csdev->dev, "AUX pause is not supported.\n"); + cpumask_clear_cpu(cpu, mask); + continue; + } + + /* * No sink provided - look for a default sink for all the ETMs, * where this event can be scheduled. * We allocate the sink specific buffers only once for this @@ -450,6 +462,15 @@ err: goto out; } +static int etm_event_resume(struct coresight_device *csdev, + struct etm_ctxt *ctxt) +{ + if (!ctxt->event_data) + return 0; + + return coresight_resume_source(csdev); +} + static void etm_event_start(struct perf_event *event, int flags) { int cpu = smp_processor_id(); @@ -463,6 +484,14 @@ static void etm_event_start(struct perf_event *event, int flags) if (!csdev) goto fail; + if (flags & PERF_EF_RESUME) { + if (etm_event_resume(csdev, ctxt) < 0) { + dev_err(&csdev->dev, "Failed to resume ETM event.\n"); + goto fail; + } + return; + } + /* Have we messed up our tracking ? */ if (WARN_ON(ctxt->event_data)) goto fail; @@ -545,6 +574,55 @@ fail: return; } +static void etm_event_pause(struct perf_event *event, + struct coresight_device *csdev, + struct etm_ctxt *ctxt) +{ + int cpu = smp_processor_id(); + struct coresight_device *sink; + struct perf_output_handle *handle = &ctxt->handle; + struct coresight_path *path; + unsigned long size; + + if (!ctxt->event_data) + return; + + /* Stop tracer */ + coresight_pause_source(csdev); + + path = etm_event_cpu_path(ctxt->event_data, cpu); + sink = coresight_get_sink(path); + if (WARN_ON_ONCE(!sink)) + return; + + /* + * The per CPU sink has own interrupt handling, it might have + * race condition with updating buffer on AUX trace pause if + * it is invoked from NMI. To avoid the race condition, + * disallows updating buffer for the per CPU sink case. + */ + if (coresight_is_percpu_sink(sink)) + return; + + if (WARN_ON_ONCE(handle->event != event)) + return; + + if (!sink_ops(sink)->update_buffer) + return; + + size = sink_ops(sink)->update_buffer(sink, handle, + ctxt->event_data->snk_config); + if (READ_ONCE(handle->event)) { + if (!size) + return; + + perf_aux_output_end(handle, size); + perf_aux_output_begin(handle, event); + } else { + WARN_ON_ONCE(size); + } +} + static void etm_event_stop(struct perf_event *event, int mode) { int cpu = smp_processor_id(); @@ -555,6 +633,9 @@ static void etm_event_stop(struct perf_event *event, int mode) struct etm_event_data *event_data; struct coresight_path *path; + if (mode & PERF_EF_PAUSE) + return etm_event_pause(event, csdev, ctxt); + /* * If we still have access to the event_data via handle, * confirm that we haven't messed up the tracking. @@ -899,7 +980,8 @@ int __init etm_perf_init(void) int ret; etm_pmu.capabilities = (PERF_PMU_CAP_EXCLUSIVE | - PERF_PMU_CAP_ITRACE); + PERF_PMU_CAP_ITRACE | + PERF_PMU_CAP_AUX_PAUSE); etm_pmu.attr_groups = etm_pmu_attr_groups; etm_pmu.task_ctx_nr = perf_sw_context; diff --git a/drivers/hwtracing/coresight/coresight-etm.h b/drivers/hwtracing/coresight/coresight-etm.h index 171f1384f7c0..1d753cca2943 100644 --- a/drivers/hwtracing/coresight/coresight-etm.h +++ b/drivers/hwtracing/coresight/coresight-etm.h @@ -229,7 +229,7 @@ struct etm_config { * @config: structure holding configuration parameters. */ struct etm_drvdata { - void __iomem *base; + struct csdev_access csa; struct clk *atclk; struct coresight_device *csdev; spinlock_t spinlock; @@ -260,7 +260,7 @@ static inline void etm_writel(struct etm_drvdata *drvdata, "invalid CP14 access to ETM reg: %#x", off); } } else { - writel_relaxed(val, drvdata->base + off); + writel_relaxed(val, drvdata->csa.base + off); } } @@ -274,7 +274,7 @@ static inline unsigned int etm_readl(struct etm_drvdata *drvdata, u32 off) "invalid CP14 access to ETM reg: %#x", off); } } else { - val = readl_relaxed(drvdata->base + off); + val = readl_relaxed(drvdata->csa.base + off); } return val; diff --git a/drivers/hwtracing/coresight/coresight-etm3x-core.c b/drivers/hwtracing/coresight/coresight-etm3x-core.c index 8927bfaf3af2..1c6204e14422 100644 --- a/drivers/hwtracing/coresight/coresight-etm3x-core.c +++ b/drivers/hwtracing/coresight/coresight-etm3x-core.c @@ -86,9 +86,9 @@ static void etm_set_pwrup(struct etm_drvdata *drvdata) { u32 etmpdcr; - etmpdcr = readl_relaxed(drvdata->base + ETMPDCR); + etmpdcr = readl_relaxed(drvdata->csa.base + ETMPDCR); etmpdcr |= ETMPDCR_PWD_UP; - writel_relaxed(etmpdcr, drvdata->base + ETMPDCR); + writel_relaxed(etmpdcr, drvdata->csa.base + ETMPDCR); /* Ensure pwrup completes before subsequent cp14 accesses */ mb(); isb(); @@ -101,9 +101,9 @@ static void etm_clr_pwrup(struct etm_drvdata *drvdata) /* Ensure pending cp14 accesses complete before clearing pwrup */ mb(); isb(); - etmpdcr = readl_relaxed(drvdata->base + ETMPDCR); + etmpdcr = readl_relaxed(drvdata->csa.base + ETMPDCR); etmpdcr &= ~ETMPDCR_PWD_UP; - writel_relaxed(etmpdcr, drvdata->base + ETMPDCR); + writel_relaxed(etmpdcr, drvdata->csa.base + ETMPDCR); } /** @@ -365,7 +365,7 @@ static int etm_enable_hw(struct etm_drvdata *drvdata) struct etm_config *config = &drvdata->config; struct coresight_device *csdev = drvdata->csdev; - CS_UNLOCK(drvdata->base); + CS_UNLOCK(drvdata->csa.base); rc = coresight_claim_device_unlocked(csdev); if (rc) @@ -427,7 +427,7 @@ static int etm_enable_hw(struct etm_drvdata *drvdata) etm_clr_prog(drvdata); done: - CS_LOCK(drvdata->base); + CS_LOCK(drvdata->csa.base); dev_dbg(&drvdata->csdev->dev, "cpu: %d enable smp call done: %d\n", drvdata->cpu, rc); @@ -549,7 +549,7 @@ static void etm_disable_hw(void *info) struct etm_config *config = &drvdata->config; struct coresight_device *csdev = drvdata->csdev; - CS_UNLOCK(drvdata->base); + CS_UNLOCK(drvdata->csa.base); etm_set_prog(drvdata); /* Read back sequencer and counters for post trace analysis */ @@ -561,7 +561,7 @@ static void etm_disable_hw(void *info) etm_set_pwrdwn(drvdata); coresight_disclaim_device_unlocked(csdev); - CS_LOCK(drvdata->base); + CS_LOCK(drvdata->csa.base); dev_dbg(&drvdata->csdev->dev, "cpu: %d disable smp call done\n", drvdata->cpu); @@ -574,7 +574,7 @@ static void etm_disable_perf(struct coresight_device *csdev) if (WARN_ON_ONCE(drvdata->cpu != smp_processor_id())) return; - CS_UNLOCK(drvdata->base); + CS_UNLOCK(drvdata->csa.base); /* Setting the prog bit disables tracing immediately */ etm_set_prog(drvdata); @@ -586,7 +586,7 @@ static void etm_disable_perf(struct coresight_device *csdev) etm_set_pwrdwn(drvdata); coresight_disclaim_device_unlocked(csdev); - CS_LOCK(drvdata->base); + CS_LOCK(drvdata->csa.base); /* * perf will release trace ids when _free_aux() @@ -733,7 +733,7 @@ static void etm_init_arch_data(void *info) /* Make sure all registers are accessible */ etm_os_unlock(drvdata); - CS_UNLOCK(drvdata->base); + CS_UNLOCK(drvdata->csa.base); /* First dummy read */ (void)etm_readl(drvdata, ETMPDSR); @@ -764,9 +764,10 @@ static void etm_init_arch_data(void *info) drvdata->nr_ext_out = BMVAL(etmccr, 20, 22); drvdata->nr_ctxid_cmp = BMVAL(etmccr, 24, 25); + coresight_clear_self_claim_tag_unlocked(&drvdata->csa); etm_set_pwrdwn(drvdata); etm_clr_pwrup(drvdata); - CS_LOCK(drvdata->base); + CS_LOCK(drvdata->csa.base); } static int __init etm_hp_setup(void) @@ -827,8 +828,7 @@ static int etm_probe(struct amba_device *adev, const struct amba_id *id) if (IS_ERR(base)) return PTR_ERR(base); - drvdata->base = base; - desc.access = CSDEV_ACCESS_IOMEM(base); + desc.access = drvdata->csa = CSDEV_ACCESS_IOMEM(base); spin_lock_init(&drvdata->spinlock); diff --git a/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c b/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c index b9006451f515..762109307b86 100644 --- a/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c +++ b/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c @@ -50,11 +50,11 @@ static ssize_t etmsr_show(struct device *dev, pm_runtime_get_sync(dev->parent); spin_lock_irqsave(&drvdata->spinlock, flags); - CS_UNLOCK(drvdata->base); + CS_UNLOCK(drvdata->csa.base); val = etm_readl(drvdata, ETMSR); - CS_LOCK(drvdata->base); + CS_LOCK(drvdata->csa.base); spin_unlock_irqrestore(&drvdata->spinlock, flags); pm_runtime_put(dev->parent); @@ -949,9 +949,9 @@ static ssize_t seq_curr_state_show(struct device *dev, pm_runtime_get_sync(dev->parent); spin_lock_irqsave(&drvdata->spinlock, flags); - CS_UNLOCK(drvdata->base); + CS_UNLOCK(drvdata->csa.base); val = (etm_readl(drvdata, ETMSQR) & ETM_SQR_MASK); - CS_LOCK(drvdata->base); + CS_LOCK(drvdata->csa.base); spin_unlock_irqrestore(&drvdata->spinlock, flags); pm_runtime_put(dev->parent); diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c index 2b8f10463840..42e5d37403ad 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x-core.c +++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c @@ -84,7 +84,7 @@ static int etm4_probe_cpu(unsigned int cpu); * TRCIDR4.NUMPC > 0b0000 . * TRCSSCSR<n>.PC == 0b1 */ -static inline bool etm4x_sspcicrn_present(struct etmv4_drvdata *drvdata, int n) +static bool etm4x_sspcicrn_present(struct etmv4_drvdata *drvdata, int n) { return (n < drvdata->nr_ss_cmp) && drvdata->nr_pe && @@ -185,7 +185,7 @@ static void etm_write_os_lock(struct etmv4_drvdata *drvdata, isb(); } -static inline void etm4_os_unlock_csa(struct etmv4_drvdata *drvdata, +static void etm4_os_unlock_csa(struct etmv4_drvdata *drvdata, struct csdev_access *csa) { WARN_ON(drvdata->cpu != smp_processor_id()); @@ -431,6 +431,44 @@ static int etm4x_wait_status(struct csdev_access *csa, int pos, int val) return coresight_timeout(csa, TRCSTATR, pos, val); } +static int etm4_enable_trace_unit(struct etmv4_drvdata *drvdata) +{ + struct coresight_device *csdev = drvdata->csdev; + struct device *etm_dev = &csdev->dev; + struct csdev_access *csa = &csdev->access; + + /* + * ETE mandates that the TRCRSR is written to before + * enabling it. + */ + if (etm4x_is_ete(drvdata)) + etm4x_relaxed_write32(csa, TRCRSR_TA, TRCRSR); + + etm4x_allow_trace(drvdata); + /* Enable the trace unit */ + etm4x_relaxed_write32(csa, 1, TRCPRGCTLR); + + /* Synchronize the register updates for sysreg access */ + if (!csa->io_mem) + isb(); + + /* wait for TRCSTATR.IDLE to go back down to '0' */ + if (etm4x_wait_status(csa, TRCSTATR_IDLE_BIT, 0)) { + dev_err(etm_dev, + "timeout while waiting for Idle Trace Status\n"); + return -ETIME; + } + + /* + * As recommended by section 4.3.7 ("Synchronization when using the + * memory-mapped interface") of ARM IHI 0064D + */ + dsb(sy); + isb(); + + return 0; +} + static int etm4_enable_hw(struct etmv4_drvdata *drvdata) { int i, rc; @@ -539,33 +577,8 @@ static int etm4_enable_hw(struct etmv4_drvdata *drvdata) etm4x_relaxed_write32(csa, trcpdcr | TRCPDCR_PU, TRCPDCR); } - /* - * ETE mandates that the TRCRSR is written to before - * enabling it. - */ - if (etm4x_is_ete(drvdata)) - etm4x_relaxed_write32(csa, TRCRSR_TA, TRCRSR); - - etm4x_allow_trace(drvdata); - /* Enable the trace unit */ - etm4x_relaxed_write32(csa, 1, TRCPRGCTLR); - - /* Synchronize the register updates for sysreg access */ - if (!csa->io_mem) - isb(); - - /* wait for TRCSTATR.IDLE to go back down to '0' */ - if (etm4x_wait_status(csa, TRCSTATR_IDLE_BIT, 0)) - dev_err(etm_dev, - "timeout while waiting for Idle Trace Status\n"); - - /* - * As recommended by section 4.3.7 ("Synchronization when using the - * memory-mapped interface") of ARM IHI 0064D - */ - dsb(sy); - isb(); - + if (!drvdata->paused) + rc = etm4_enable_trace_unit(drvdata); done: etm4_cs_lock(drvdata, csa); @@ -808,6 +821,9 @@ static int etm4_enable_perf(struct coresight_device *csdev, drvdata->trcid = path->trace_id; + /* Populate pause state */ + drvdata->paused = !!READ_ONCE(event->hw.aux_paused); + /* And enable it */ ret = etm4_enable_hw(drvdata); @@ -834,6 +850,9 @@ static int etm4_enable_sysfs(struct coresight_device *csdev, struct coresight_pa drvdata->trcid = path->trace_id; + /* Tracer will never be paused in sysfs mode */ + drvdata->paused = false; + /* * Executing etm4_enable_hw on the cpu whose ETM is being enabled * ensures that register writes occur when cpu is powered. @@ -884,25 +903,12 @@ static int etm4_enable(struct coresight_device *csdev, struct perf_event *event, return ret; } -static void etm4_disable_hw(void *info) +static void etm4_disable_trace_unit(struct etmv4_drvdata *drvdata) { u32 control; - struct etmv4_drvdata *drvdata = info; - struct etmv4_config *config = &drvdata->config; struct coresight_device *csdev = drvdata->csdev; struct device *etm_dev = &csdev->dev; struct csdev_access *csa = &csdev->access; - int i; - - etm4_cs_unlock(drvdata, csa); - etm4_disable_arch_specific(drvdata); - - if (!drvdata->skip_power_up) { - /* power can be removed from the trace unit now */ - control = etm4x_relaxed_read32(csa, TRCPDCR); - control &= ~TRCPDCR_PU; - etm4x_relaxed_write32(csa, control, TRCPDCR); - } control = etm4x_relaxed_read32(csa, TRCPRGCTLR); @@ -943,6 +949,28 @@ static void etm4_disable_hw(void *info) * of ARM IHI 0064H.b. */ isb(); +} + +static void etm4_disable_hw(void *info) +{ + u32 control; + struct etmv4_drvdata *drvdata = info; + struct etmv4_config *config = &drvdata->config; + struct coresight_device *csdev = drvdata->csdev; + struct csdev_access *csa = &csdev->access; + int i; + + etm4_cs_unlock(drvdata, csa); + etm4_disable_arch_specific(drvdata); + + if (!drvdata->skip_power_up) { + /* power can be removed from the trace unit now */ + control = etm4x_relaxed_read32(csa, TRCPDCR); + control &= ~TRCPDCR_PU; + etm4x_relaxed_write32(csa, control, TRCPDCR); + } + + etm4_disable_trace_unit(drvdata); /* read the status of the single shot comparators */ for (i = 0; i < drvdata->nr_ss_cmp; i++) { @@ -1020,6 +1048,9 @@ static void etm4_disable_sysfs(struct coresight_device *csdev) smp_call_function_single(drvdata->cpu, etm4_disable_hw, drvdata, 1); raw_spin_unlock(&drvdata->spinlock); + + cscfg_csdev_disable_active_config(csdev); + cpus_read_unlock(); /* @@ -1059,10 +1090,43 @@ static void etm4_disable(struct coresight_device *csdev, coresight_set_mode(csdev, CS_MODE_DISABLED); } +static int etm4_resume_perf(struct coresight_device *csdev) +{ + struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); + struct csdev_access *csa = &csdev->access; + + if (coresight_get_mode(csdev) != CS_MODE_PERF) + return -EINVAL; + + etm4_cs_unlock(drvdata, csa); + etm4_enable_trace_unit(drvdata); + etm4_cs_lock(drvdata, csa); + + drvdata->paused = false; + return 0; +} + +static void etm4_pause_perf(struct coresight_device *csdev) +{ + struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); + struct csdev_access *csa = &csdev->access; + + if (coresight_get_mode(csdev) != CS_MODE_PERF) + return; + + etm4_cs_unlock(drvdata, csa); + etm4_disable_trace_unit(drvdata); + etm4_cs_lock(drvdata, csa); + + drvdata->paused = true; +} + static const struct coresight_ops_source etm4_source_ops = { .cpu_id = etm4_cpu_id, .enable = etm4_enable, .disable = etm4_disable, + .resume_perf = etm4_resume_perf, + .pause_perf = etm4_pause_perf, }; static const struct coresight_ops etm4_cs_ops = { @@ -1070,7 +1134,7 @@ static const struct coresight_ops etm4_cs_ops = { .source_ops = &etm4_source_ops, }; -static inline bool cpu_supports_sysreg_trace(void) +static bool cpu_supports_sysreg_trace(void) { u64 dfr0 = read_sysreg_s(SYS_ID_AA64DFR0_EL1); @@ -1176,7 +1240,7 @@ static void cpu_detect_trace_filtering(struct etmv4_drvdata *drvdata) * tracing at the kernel EL and EL0, forcing to use the * virtual time as the timestamp. */ - trfcr = (TRFCR_EL1_TS_VIRTUAL | + trfcr = (FIELD_PREP(TRFCR_EL1_TS_MASK, TRFCR_EL1_TS_VIRTUAL) | TRFCR_EL1_ExTRE | TRFCR_EL1_E0TRE); @@ -1372,11 +1436,13 @@ static void etm4_init_arch_data(void *info) drvdata->nrseqstate = FIELD_GET(TRCIDR5_NUMSEQSTATE_MASK, etmidr5); /* NUMCNTR, bits[30:28] number of counters available for tracing */ drvdata->nr_cntr = FIELD_GET(TRCIDR5_NUMCNTR_MASK, etmidr5); + + coresight_clear_self_claim_tag_unlocked(csa); etm4_cs_lock(drvdata, csa); cpu_detect_trace_filtering(drvdata); } -static inline u32 etm4_get_victlr_access_type(struct etmv4_config *config) +static u32 etm4_get_victlr_access_type(struct etmv4_config *config) { return etm4_get_access_type(config) << __bf_shf(TRCVICTLR_EXLEVEL_MASK); } diff --git a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c index fdd0956fecb3..ab251865b893 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c +++ b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c @@ -2320,11 +2320,11 @@ static ssize_t ts_source_show(struct device *dev, goto out; } - switch (drvdata->trfcr & TRFCR_EL1_TS_MASK) { + val = FIELD_GET(TRFCR_EL1_TS_MASK, drvdata->trfcr); + switch (val) { case TRFCR_EL1_TS_VIRTUAL: case TRFCR_EL1_TS_GUEST_PHYSICAL: case TRFCR_EL1_TS_PHYSICAL: - val = FIELD_GET(TRFCR_EL1_TS_MASK, drvdata->trfcr); break; default: val = -1; @@ -2440,7 +2440,7 @@ static u32 etmv4_cross_read(const struct etmv4_drvdata *drvdata, u32 offset) return reg.data; } -static inline u32 coresight_etm4x_attr_to_offset(struct device_attribute *attr) +static u32 coresight_etm4x_attr_to_offset(struct device_attribute *attr) { struct dev_ext_attribute *eattr; @@ -2464,7 +2464,7 @@ static ssize_t coresight_etm4x_reg_show(struct device *dev, return scnprintf(buf, PAGE_SIZE, "0x%x\n", val); } -static inline bool +static bool etm4x_register_implemented(struct etmv4_drvdata *drvdata, u32 offset) { switch (offset) { diff --git a/drivers/hwtracing/coresight/coresight-etm4x.h b/drivers/hwtracing/coresight/coresight-etm4x.h index bd7db36ba197..ac649515054d 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x.h +++ b/drivers/hwtracing/coresight/coresight-etm4x.h @@ -983,6 +983,7 @@ struct etmv4_save_state { * @state_needs_restore: True when there is context to restore after PM exit * @skip_power_up: Indicates if an implementation can skip powering up * the trace unit. + * @paused: Indicates if the trace unit is paused. * @arch_features: Bitmap of arch features of etmv4 devices. */ struct etmv4_drvdata { @@ -1036,6 +1037,7 @@ struct etmv4_drvdata { struct etmv4_save_state *save_state; bool state_needs_restore; bool skip_power_up; + bool paused; DECLARE_BITMAP(arch_features, ETM4_IMPDEF_FEATURE_MAX); }; diff --git a/drivers/hwtracing/coresight/coresight-funnel.c b/drivers/hwtracing/coresight/coresight-funnel.c index 0541712b2bcb..b1922dbe9292 100644 --- a/drivers/hwtracing/coresight/coresight-funnel.c +++ b/drivers/hwtracing/coresight/coresight-funnel.c @@ -255,6 +255,7 @@ static int funnel_probe(struct device *dev, struct resource *res) drvdata->base = base; desc.groups = coresight_funnel_groups; desc.access = CSDEV_ACCESS_IOMEM(base); + coresight_clear_self_claim_tag(&desc.access); } dev_set_drvdata(dev, drvdata); @@ -433,7 +434,8 @@ static struct amba_driver dynamic_funnel_driver = { static int __init funnel_init(void) { - return coresight_init_driver("funnel", &dynamic_funnel_driver, &funnel_driver); + return coresight_init_driver("funnel", &dynamic_funnel_driver, &funnel_driver, + THIS_MODULE); } static void __exit funnel_exit(void) diff --git a/drivers/hwtracing/coresight/coresight-kunit-tests.c b/drivers/hwtracing/coresight/coresight-kunit-tests.c new file mode 100644 index 000000000000..c8f361767c45 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-kunit-tests.c @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include <kunit/test.h> +#include <kunit/device.h> +#include <linux/coresight.h> + +#include "coresight-priv.h" + +static struct coresight_device *coresight_test_device(struct device *dev) +{ + struct coresight_device *csdev = devm_kcalloc(dev, 1, + sizeof(struct coresight_device), + GFP_KERNEL); + csdev->pdata = devm_kcalloc(dev, 1, + sizeof(struct coresight_platform_data), + GFP_KERNEL); + return csdev; +} + +static void test_default_sink(struct kunit *test) +{ + /* + * Source -> ETF -> ETR -> CATU + * ^ + * | default + */ + struct device *dev = kunit_device_register(test, "coresight_kunit"); + struct coresight_device *src = coresight_test_device(dev), + *etf = coresight_test_device(dev), + *etr = coresight_test_device(dev), + *catu = coresight_test_device(dev); + struct coresight_connection conn = {}; + + src->type = CORESIGHT_DEV_TYPE_SOURCE; + /* + * Don't use CORESIGHT_DEV_SUBTYPE_SOURCE_PROC, that would always return + * a TRBE sink if one is registered. + */ + src->subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_BUS; + etf->type = CORESIGHT_DEV_TYPE_LINKSINK; + etf->subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_BUFFER; + etr->type = CORESIGHT_DEV_TYPE_SINK; + etr->subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_SYSMEM; + catu->type = CORESIGHT_DEV_TYPE_HELPER; + + conn.src_dev = src; + conn.dest_dev = etf; + coresight_add_out_conn(dev, src->pdata, &conn); + + conn.src_dev = etf; + conn.dest_dev = etr; + coresight_add_out_conn(dev, etf->pdata, &conn); + + conn.src_dev = etr; + conn.dest_dev = catu; + coresight_add_out_conn(dev, etr->pdata, &conn); + + KUNIT_ASSERT_PTR_EQ(test, coresight_find_default_sink(src), etr); +} + +static struct kunit_case coresight_testcases[] = { + KUNIT_CASE(test_default_sink), + {} +}; + +static struct kunit_suite coresight_test_suite = { + .name = "coresight_test_suite", + .test_cases = coresight_testcases, +}; + +kunit_test_suites(&coresight_test_suite); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("James Clark <james.clark@linaro.org>"); +MODULE_DESCRIPTION("Arm CoreSight KUnit tests"); diff --git a/drivers/hwtracing/coresight/coresight-platform.c b/drivers/hwtracing/coresight/coresight-platform.c index 8192ba3279f0..0db64c5f4995 100644 --- a/drivers/hwtracing/coresight/coresight-platform.c +++ b/drivers/hwtracing/coresight/coresight-platform.c @@ -139,7 +139,7 @@ coresight_find_csdev_by_fwnode(struct fwnode_handle *r_fwnode) EXPORT_SYMBOL_GPL(coresight_find_csdev_by_fwnode); #ifdef CONFIG_OF -static inline bool of_coresight_legacy_ep_is_input(struct device_node *ep) +static bool of_coresight_legacy_ep_is_input(struct device_node *ep) { return of_property_read_bool(ep, "slave-mode"); } @@ -159,7 +159,7 @@ static struct device_node *of_coresight_get_port_parent(struct device_node *ep) return parent; } -static inline struct device_node * +static struct device_node * of_coresight_get_output_ports_node(const struct device_node *node) { return of_get_child_by_name(node, "out-ports"); @@ -327,14 +327,14 @@ static int of_get_coresight_platform_data(struct device *dev, return 0; } #else -static inline int +static int of_get_coresight_platform_data(struct device *dev, struct coresight_platform_data *pdata) { return -ENOENT; } -static inline int of_coresight_get_cpu(struct device *dev) +static int of_coresight_get_cpu(struct device *dev) { return -ENODEV; } @@ -356,7 +356,7 @@ static const guid_t coresight_graph_uuid = GUID_INIT(0x3ecbc8b6, 0x1d0e, 0x4fb3, #define ACPI_CORESIGHT_LINK_SLAVE 0 #define ACPI_CORESIGHT_LINK_MASTER 1 -static inline bool is_acpi_guid(const union acpi_object *obj) +static bool is_acpi_guid(const union acpi_object *obj) { return (obj->type == ACPI_TYPE_BUFFER) && (obj->buffer.length == 16); } @@ -365,24 +365,24 @@ static inline bool is_acpi_guid(const union acpi_object *obj) * acpi_guid_matches - Checks if the given object is a GUID object and * that it matches the supplied the GUID. */ -static inline bool acpi_guid_matches(const union acpi_object *obj, +static bool acpi_guid_matches(const union acpi_object *obj, const guid_t *guid) { return is_acpi_guid(obj) && guid_equal((guid_t *)obj->buffer.pointer, guid); } -static inline bool is_acpi_dsd_graph_guid(const union acpi_object *obj) +static bool is_acpi_dsd_graph_guid(const union acpi_object *obj) { return acpi_guid_matches(obj, &acpi_graph_uuid); } -static inline bool is_acpi_coresight_graph_guid(const union acpi_object *obj) +static bool is_acpi_coresight_graph_guid(const union acpi_object *obj) { return acpi_guid_matches(obj, &coresight_graph_uuid); } -static inline bool is_acpi_coresight_graph(const union acpi_object *obj) +static bool is_acpi_coresight_graph(const union acpi_object *obj) { const union acpi_object *graphid, *guid, *links; @@ -469,7 +469,7 @@ static inline bool is_acpi_coresight_graph(const union acpi_object *obj) * }, // End of ACPI Graph Property * }) */ -static inline bool acpi_validate_dsd_graph(const union acpi_object *graph) +static bool acpi_validate_dsd_graph(const union acpi_object *graph) { int i, n; const union acpi_object *rev, *nr_graphs; @@ -553,7 +553,7 @@ acpi_get_dsd_graph(struct acpi_device *adev, struct acpi_buffer *buf) return NULL; } -static inline bool +static bool acpi_validate_coresight_graph(const union acpi_object *cs_graph) { int nlinks; @@ -794,14 +794,14 @@ acpi_get_coresight_platform_data(struct device *dev, #else -static inline int +static int acpi_get_coresight_platform_data(struct device *dev, struct coresight_platform_data *pdata) { return -ENOENT; } -static inline int acpi_coresight_get_cpu(struct device *dev) +static int acpi_coresight_get_cpu(struct device *dev) { return -ENODEV; } diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/hwtracing/coresight/coresight-priv.h index 82644aff8d2b..33e22b1ba043 100644 --- a/drivers/hwtracing/coresight/coresight-priv.h +++ b/drivers/hwtracing/coresight/coresight-priv.h @@ -35,7 +35,11 @@ extern const struct device_type coresight_dev_type[]; * Coresight device CLAIM protocol. * See PSCI - ARM DEN 0022D, Section: 6.8.1 Debug and Trace save and restore. */ -#define CORESIGHT_CLAIM_SELF_HOSTED BIT(1) +#define CORESIGHT_CLAIM_MASK GENMASK(1, 0) +#define CORESIGHT_CLAIM_FREE 0 +#define CORESIGHT_CLAIM_EXTERNAL 1 +#define CORESIGHT_CLAIM_SELF_HOSTED 2 +#define CORESIGHT_CLAIM_INVALID 3 #define TIMEOUT_US 100 #define BMVAL(val, lsb, msb) ((val & GENMASK(msb, lsb)) >> lsb) @@ -56,10 +60,8 @@ struct cs_off_attribute { u32 off; }; -extern ssize_t coresight_simple_show32(struct device *_dev, - struct device_attribute *attr, char *buf); -extern ssize_t coresight_simple_show_pair(struct device *_dev, - struct device_attribute *attr, char *buf); +ssize_t coresight_simple_show32(struct device *_dev, struct device_attribute *attr, char *buf); +ssize_t coresight_simple_show_pair(struct device *_dev, struct device_attribute *attr, char *buf); #define coresight_simple_reg32(name, offset) \ (&((struct cs_off_attribute[]) { \ @@ -156,8 +158,8 @@ void coresight_path_assign_trace_id(struct coresight_path *path, enum cs_mode mode); #if IS_ENABLED(CONFIG_CORESIGHT_SOURCE_ETM3X) -extern int etm_readl_cp14(u32 off, unsigned int *val); -extern int etm_writel_cp14(u32 off, u32 val); +int etm_readl_cp14(u32 off, unsigned int *val); +int etm_writel_cp14(u32 off, u32 val); #else static inline int etm_readl_cp14(u32 off, unsigned int *val) { return 0; } static inline int etm_writel_cp14(u32 off, u32 val) { return 0; } @@ -168,8 +170,8 @@ struct cti_assoc_op { void (*remove)(struct coresight_device *csdev); }; -extern void coresight_set_cti_ops(const struct cti_assoc_op *cti_op); -extern void coresight_remove_cti_ops(void); +void coresight_set_cti_ops(const struct cti_assoc_op *cti_op); +void coresight_remove_cti_ops(void); /* * Macros and inline functions to handle CoreSight UCI data and driver @@ -249,5 +251,7 @@ void coresight_add_helper(struct coresight_device *csdev, void coresight_set_percpu_sink(int cpu, struct coresight_device *csdev); struct coresight_device *coresight_get_percpu_sink(int cpu); void coresight_disable_source(struct coresight_device *csdev, void *data); +void coresight_pause_source(struct coresight_device *csdev); +int coresight_resume_source(struct coresight_device *csdev); #endif diff --git a/drivers/hwtracing/coresight/coresight-replicator.c b/drivers/hwtracing/coresight/coresight-replicator.c index ee7ee79f6cf7..06efd2b01a0f 100644 --- a/drivers/hwtracing/coresight/coresight-replicator.c +++ b/drivers/hwtracing/coresight/coresight-replicator.c @@ -63,7 +63,7 @@ static void dynamic_replicator_reset(struct replicator_drvdata *drvdata) /* * replicator_reset : Reset the replicator configuration to sane values. */ -static inline void replicator_reset(struct replicator_drvdata *drvdata) +static void replicator_reset(struct replicator_drvdata *drvdata) { if (drvdata->base) dynamic_replicator_reset(drvdata); @@ -262,6 +262,7 @@ static int replicator_probe(struct device *dev, struct resource *res) drvdata->base = base; desc.groups = replicator_groups; desc.access = CSDEV_ACCESS_IOMEM(base); + coresight_clear_self_claim_tag(&desc.access); } if (fwnode_property_present(dev_fwnode(dev), @@ -438,7 +439,8 @@ static struct amba_driver dynamic_replicator_driver = { static int __init replicator_init(void) { - return coresight_init_driver("replicator", &dynamic_replicator_driver, &replicator_driver); + return coresight_init_driver("replicator", &dynamic_replicator_driver, &replicator_driver, + THIS_MODULE); } static void __exit replicator_exit(void) diff --git a/drivers/hwtracing/coresight/coresight-stm.c b/drivers/hwtracing/coresight/coresight-stm.c index 26f9339f38b9..e45c6c7204b4 100644 --- a/drivers/hwtracing/coresight/coresight-stm.c +++ b/drivers/hwtracing/coresight/coresight-stm.c @@ -301,7 +301,7 @@ static const struct coresight_ops stm_cs_ops = { .source_ops = &stm_source_ops, }; -static inline bool stm_addr_unaligned(const void *addr, u8 write_bytes) +static bool stm_addr_unaligned(const void *addr, u8 write_bytes) { return ((unsigned long)addr & (write_bytes - 1)); } @@ -685,7 +685,7 @@ static int of_stm_get_stimulus_area(struct device *dev, struct resource *res) return of_address_to_resource(np, index, res); } #else -static inline int of_stm_get_stimulus_area(struct device *dev, +static int of_stm_get_stimulus_area(struct device *dev, struct resource *res) { return -ENOENT; @@ -729,7 +729,7 @@ static int acpi_stm_get_stimulus_area(struct device *dev, struct resource *res) return rc; } #else -static inline int acpi_stm_get_stimulus_area(struct device *dev, +static int acpi_stm_get_stimulus_area(struct device *dev, struct resource *res) { return -ENOENT; @@ -1058,7 +1058,7 @@ static struct platform_driver stm_platform_driver = { static int __init stm_init(void) { - return coresight_init_driver("stm", &stm_driver, &stm_platform_driver); + return coresight_init_driver("stm", &stm_driver, &stm_platform_driver, THIS_MODULE); } static void __exit stm_exit(void) diff --git a/drivers/hwtracing/coresight/coresight-syscfg-configfs.c b/drivers/hwtracing/coresight/coresight-syscfg-configfs.c index 213b4159b062..2b40e556be87 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg-configfs.c +++ b/drivers/hwtracing/coresight/coresight-syscfg-configfs.c @@ -10,7 +10,7 @@ #include "coresight-syscfg-configfs.h" /* create a default ci_type. */ -static inline struct config_item_type *cscfg_create_ci_type(void) +static struct config_item_type *cscfg_create_ci_type(void) { struct config_item_type *ci_type; diff --git a/drivers/hwtracing/coresight/coresight-syscfg.c b/drivers/hwtracing/coresight/coresight-syscfg.c index a70c1454b410..83dad24e0116 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.c +++ b/drivers/hwtracing/coresight/coresight-syscfg.c @@ -395,6 +395,8 @@ static void cscfg_remove_owned_csdev_configs(struct coresight_device *csdev, voi if (list_empty(&csdev->config_csdev_list)) return; + guard(raw_spinlock_irqsave)(&csdev->cscfg_csdev_lock); + list_for_each_entry_safe(config_csdev, tmp, &csdev->config_csdev_list, node) { if (config_csdev->config_desc->load_owner == load_owner) list_del(&config_csdev->node); @@ -867,6 +869,25 @@ unlock_exit: } EXPORT_SYMBOL_GPL(cscfg_csdev_reset_feats); +static bool cscfg_config_desc_get(struct cscfg_config_desc *config_desc) +{ + if (!atomic_fetch_inc(&config_desc->active_cnt)) { + /* must ensure that config cannot be unloaded in use */ + if (unlikely(cscfg_owner_get(config_desc->load_owner))) { + atomic_dec(&config_desc->active_cnt); + return false; + } + } + + return true; +} + +static void cscfg_config_desc_put(struct cscfg_config_desc *config_desc) +{ + if (!atomic_dec_return(&config_desc->active_cnt)) + cscfg_owner_put(config_desc->load_owner); +} + /* * This activate configuration for either perf or sysfs. Perf can have multiple * active configs, selected per event, sysfs is limited to one. @@ -890,22 +911,17 @@ static int _cscfg_activate_config(unsigned long cfg_hash) if (config_desc->available == false) return -EBUSY; - /* must ensure that config cannot be unloaded in use */ - err = cscfg_owner_get(config_desc->load_owner); - if (err) + if (!cscfg_config_desc_get(config_desc)) { + err = -EINVAL; break; + } + /* * increment the global active count - control changes to * active configurations */ atomic_inc(&cscfg_mgr->sys_active_cnt); - /* - * mark the descriptor as active so enable config on a - * device instance will use it - */ - atomic_inc(&config_desc->active_cnt); - err = 0; dev_dbg(cscfg_device(), "Activate config %s.\n", config_desc->name); break; @@ -920,9 +936,8 @@ static void _cscfg_deactivate_config(unsigned long cfg_hash) list_for_each_entry(config_desc, &cscfg_mgr->config_desc_list, item) { if ((unsigned long)config_desc->event_ea->var == cfg_hash) { - atomic_dec(&config_desc->active_cnt); atomic_dec(&cscfg_mgr->sys_active_cnt); - cscfg_owner_put(config_desc->load_owner); + cscfg_config_desc_put(config_desc); dev_dbg(cscfg_device(), "Deactivate config %s.\n", config_desc->name); break; } @@ -1047,7 +1062,7 @@ int cscfg_csdev_enable_active_config(struct coresight_device *csdev, unsigned long cfg_hash, int preset) { struct cscfg_config_csdev *config_csdev_active = NULL, *config_csdev_item; - const struct cscfg_config_desc *config_desc; + struct cscfg_config_desc *config_desc; unsigned long flags; int err = 0; @@ -1062,8 +1077,8 @@ int cscfg_csdev_enable_active_config(struct coresight_device *csdev, raw_spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags); list_for_each_entry(config_csdev_item, &csdev->config_csdev_list, node) { config_desc = config_csdev_item->config_desc; - if ((atomic_read(&config_desc->active_cnt)) && - ((unsigned long)config_desc->event_ea->var == cfg_hash)) { + if (((unsigned long)config_desc->event_ea->var == cfg_hash) && + cscfg_config_desc_get(config_desc)) { config_csdev_active = config_csdev_item; csdev->active_cscfg_ctxt = (void *)config_csdev_active; break; @@ -1097,7 +1112,11 @@ int cscfg_csdev_enable_active_config(struct coresight_device *csdev, err = -EBUSY; raw_spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags); } + + if (err) + cscfg_config_desc_put(config_desc); } + return err; } EXPORT_SYMBOL_GPL(cscfg_csdev_enable_active_config); @@ -1136,8 +1155,10 @@ void cscfg_csdev_disable_active_config(struct coresight_device *csdev) raw_spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags); /* true if there was an enabled active config */ - if (config_csdev) + if (config_csdev) { cscfg_csdev_disable_config(config_csdev); + cscfg_config_desc_put(config_csdev->config_desc); + } } EXPORT_SYMBOL_GPL(cscfg_csdev_disable_active_config); diff --git a/drivers/hwtracing/coresight/coresight-tmc-core.c b/drivers/hwtracing/coresight/coresight-tmc-core.c index a7814e8e657b..88afb16bb6be 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-core.c +++ b/drivers/hwtracing/coresight/coresight-tmc-core.c @@ -287,8 +287,8 @@ static int tmc_open(struct inode *inode, struct file *file) return 0; } -static inline ssize_t tmc_get_sysfs_trace(struct tmc_drvdata *drvdata, - loff_t pos, size_t len, char **bufpp) +static ssize_t tmc_get_sysfs_trace(struct tmc_drvdata *drvdata, loff_t pos, size_t len, + char **bufpp) { switch (drvdata->config_type) { case TMC_CONFIG_TYPE_ETB: @@ -591,7 +591,7 @@ static const struct attribute_group *coresight_etr_groups[] = { NULL, }; -static inline bool tmc_etr_can_use_sg(struct device *dev) +static bool tmc_etr_can_use_sg(struct device *dev) { int ret; u8 val_u8; @@ -621,7 +621,7 @@ static inline bool tmc_etr_can_use_sg(struct device *dev) return false; } -static inline bool tmc_etr_has_non_secure_access(struct tmc_drvdata *drvdata) +static bool tmc_etr_has_non_secure_access(struct tmc_drvdata *drvdata) { u32 auth = readl_relaxed(drvdata->base + TMC_AUTHSTATUS); @@ -869,6 +869,7 @@ static int __tmc_probe(struct device *dev, struct resource *res) dev->platform_data = pdata; desc.pdata = pdata; + coresight_clear_self_claim_tag(&desc.access); drvdata->csdev = coresight_register(&desc); if (IS_ERR(drvdata->csdev)) { ret = PTR_ERR(drvdata->csdev); @@ -1060,7 +1061,7 @@ static struct platform_driver tmc_platform_driver = { static int __init tmc_init(void) { - return coresight_init_driver("tmc", &tmc_driver, &tmc_platform_driver); + return coresight_init_driver("tmc", &tmc_driver, &tmc_platform_driver, THIS_MODULE); } static void __exit tmc_exit(void) diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/drivers/hwtracing/coresight/coresight-tmc-etf.c index d858740001c2..0f45ab5e5249 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-etf.c +++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c @@ -482,6 +482,7 @@ static unsigned long tmc_update_etf_buffer(struct coresight_device *csdev, unsigned long offset, to_read = 0, flags; struct cs_buffers *buf = sink_config; struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); + struct perf_event *event = handle->event; if (!buf) return 0; @@ -586,6 +587,14 @@ static unsigned long tmc_update_etf_buffer(struct coresight_device *csdev, * is expected by the perf ring buffer. */ CS_LOCK(drvdata->base); + + /* + * If the event is active, it is triggered during an AUX pause. + * Re-enable the sink so that it is ready when AUX resume is invoked. + */ + if (!event->hw.state) + __tmc_etb_enable_hw(drvdata); + out: raw_spin_unlock_irqrestore(&drvdata->spinlock, flags); @@ -747,7 +756,6 @@ int tmc_read_unprepare_etb(struct tmc_drvdata *drvdata) char *buf = NULL; enum tmc_mode mode; unsigned long flags; - int rc = 0; /* config types are set a boot time and never change */ if (WARN_ON_ONCE(drvdata->config_type != TMC_CONFIG_TYPE_ETB && @@ -773,11 +781,11 @@ int tmc_read_unprepare_etb(struct tmc_drvdata *drvdata) * can't be NULL. */ memset(drvdata->buf, 0, drvdata->size); - rc = __tmc_etb_enable_hw(drvdata); - if (rc) { - raw_spin_unlock_irqrestore(&drvdata->spinlock, flags); - return rc; - } + /* + * Ignore failures to enable the TMC to make sure, we don't + * leave the TMC in a "reading" state. + */ + __tmc_etb_enable_hw(drvdata); } else { /* * The ETB/ETF is not tracing and the buffer was just read. diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c index 76a8cb29b68a..b07fcdb3fe1a 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c @@ -125,7 +125,7 @@ struct etr_sg_table { * If we spill over to a new page for mapping 1 entry, we could as * well replace the link entry of the previous page with the last entry. */ -static inline unsigned long __attribute_const__ +static unsigned long __attribute_const__ tmc_etr_sg_table_entries(int nr_pages) { unsigned long nr_sgpages = nr_pages * ETR_SG_PAGES_PER_SYSPAGE; @@ -239,13 +239,13 @@ err: return -ENOMEM; } -static inline long +static long tmc_sg_get_data_page_offset(struct tmc_sg_table *sg_table, dma_addr_t addr) { return tmc_pages_get_offset(&sg_table->data_pages, addr); } -static inline void tmc_free_table_pages(struct tmc_sg_table *sg_table) +static void tmc_free_table_pages(struct tmc_sg_table *sg_table) { if (sg_table->table_vaddr) vunmap(sg_table->table_vaddr); @@ -481,7 +481,7 @@ static void tmc_etr_sg_table_dump(struct etr_sg_table *etr_table) dev_dbg(sg_table->dev, "******* End of Table *****\n"); } #else -static inline void tmc_etr_sg_table_dump(struct etr_sg_table *etr_table) {} +static void tmc_etr_sg_table_dump(struct etr_sg_table *etr_table) {} #endif /* @@ -886,10 +886,8 @@ void tmc_etr_remove_catu_ops(void) } EXPORT_SYMBOL_GPL(tmc_etr_remove_catu_ops); -static inline int tmc_etr_mode_alloc_buf(int mode, - struct tmc_drvdata *drvdata, - struct etr_buf *etr_buf, int node, - void **pages) +static int tmc_etr_mode_alloc_buf(int mode, struct tmc_drvdata *drvdata, struct etr_buf *etr_buf, + int node, void **pages) { int rc = -EINVAL; @@ -1009,7 +1007,7 @@ static ssize_t tmc_etr_buf_get_data(struct etr_buf *etr_buf, return etr_buf->ops->get_data(etr_buf, (u64)offset, len, bufpp); } -static inline s64 +static s64 tmc_etr_buf_insert_barrier_packet(struct etr_buf *etr_buf, u64 offset) { ssize_t len; @@ -1636,6 +1634,7 @@ tmc_update_etr_buffer(struct coresight_device *csdev, struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); struct etr_perf_buffer *etr_perf = config; struct etr_buf *etr_buf = etr_perf->etr_buf; + struct perf_event *event = handle->event; raw_spin_lock_irqsave(&drvdata->spinlock, flags); @@ -1705,6 +1704,15 @@ tmc_update_etr_buffer(struct coresight_device *csdev, */ smp_wmb(); + /* + * If the event is active, it is triggered during an AUX pause. + * Re-enable the sink so that it is ready when AUX resume is invoked. + */ + raw_spin_lock_irqsave(&drvdata->spinlock, flags); + if (csdev->refcnt && !event->hw.state) + __tmc_etr_enable_hw(drvdata); + raw_spin_unlock_irqrestore(&drvdata->spinlock, flags); + out: /* * Don't set the TRUNCATED flag in snapshot mode because 1) the diff --git a/drivers/hwtracing/coresight/coresight-tpiu.c b/drivers/hwtracing/coresight/coresight-tpiu.c index 97ef36f03ec2..3e0159288428 100644 --- a/drivers/hwtracing/coresight/coresight-tpiu.c +++ b/drivers/hwtracing/coresight/coresight-tpiu.c @@ -318,7 +318,7 @@ static struct platform_driver tpiu_platform_driver = { static int __init tpiu_init(void) { - return coresight_init_driver("tpiu", &tpiu_driver, &tpiu_platform_driver); + return coresight_init_driver("tpiu", &tpiu_driver, &tpiu_platform_driver, THIS_MODULE); } static void __exit tpiu_exit(void) diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c index fff67aac8418..8267dd1a2130 100644 --- a/drivers/hwtracing/coresight/coresight-trbe.c +++ b/drivers/hwtracing/coresight/coresight-trbe.c @@ -160,22 +160,22 @@ static void trbe_check_errata(struct trbe_cpudata *cpudata) } } -static inline bool trbe_has_erratum(struct trbe_cpudata *cpudata, int i) +static bool trbe_has_erratum(struct trbe_cpudata *cpudata, int i) { return (i < TRBE_ERRATA_MAX) && test_bit(i, cpudata->errata); } -static inline bool trbe_may_overwrite_in_fill_mode(struct trbe_cpudata *cpudata) +static bool trbe_may_overwrite_in_fill_mode(struct trbe_cpudata *cpudata) { return trbe_has_erratum(cpudata, TRBE_WORKAROUND_OVERWRITE_FILL_MODE); } -static inline bool trbe_may_write_out_of_range(struct trbe_cpudata *cpudata) +static bool trbe_may_write_out_of_range(struct trbe_cpudata *cpudata) { return trbe_has_erratum(cpudata, TRBE_WORKAROUND_WRITE_OUT_OF_RANGE); } -static inline bool trbe_needs_drain_after_disable(struct trbe_cpudata *cpudata) +static bool trbe_needs_drain_after_disable(struct trbe_cpudata *cpudata) { /* * Errata affected TRBE implementation will need TSB CSYNC and @@ -185,7 +185,7 @@ static inline bool trbe_needs_drain_after_disable(struct trbe_cpudata *cpudata) return trbe_has_erratum(cpudata, TRBE_NEEDS_DRAIN_AFTER_DISABLE); } -static inline bool trbe_needs_ctxt_sync_after_enable(struct trbe_cpudata *cpudata) +static bool trbe_needs_ctxt_sync_after_enable(struct trbe_cpudata *cpudata) { /* * Errata affected TRBE implementation will need an additional @@ -196,7 +196,7 @@ static inline bool trbe_needs_ctxt_sync_after_enable(struct trbe_cpudata *cpudat return trbe_has_erratum(cpudata, TRBE_NEEDS_CTXT_SYNC_AFTER_ENABLE); } -static inline bool trbe_is_broken(struct trbe_cpudata *cpudata) +static bool trbe_is_broken(struct trbe_cpudata *cpudata) { return trbe_has_erratum(cpudata, TRBE_IS_BROKEN); } @@ -208,13 +208,13 @@ static int trbe_alloc_node(struct perf_event *event) return cpu_to_node(event->cpu); } -static inline void trbe_drain_buffer(void) +static void trbe_drain_buffer(void) { tsb_csync(); dsb(nsh); } -static inline void set_trbe_enabled(struct trbe_cpudata *cpudata, u64 trblimitr) +static void set_trbe_enabled(struct trbe_cpudata *cpudata, u64 trblimitr) { /* * Enable the TRBE without clearing LIMITPTR which @@ -231,7 +231,7 @@ static inline void set_trbe_enabled(struct trbe_cpudata *cpudata, u64 trblimitr) isb(); } -static inline void set_trbe_disabled(struct trbe_cpudata *cpudata) +static void set_trbe_disabled(struct trbe_cpudata *cpudata) { u64 trblimitr = read_sysreg_s(SYS_TRBLIMITR_EL1); diff --git a/drivers/i2c/busses/i2c-img-scb.c b/drivers/i2c/busses/i2c-img-scb.c index 5d8b82ae6fd6..3278707bb885 100644 --- a/drivers/i2c/busses/i2c-img-scb.c +++ b/drivers/i2c/busses/i2c-img-scb.c @@ -831,7 +831,7 @@ next_atomic_cmd: */ static void img_i2c_check_timer(struct timer_list *t) { - struct img_i2c *i2c = from_timer(i2c, t, check_timer); + struct img_i2c *i2c = timer_container_of(i2c, t, check_timer); unsigned long flags; unsigned int line_status; diff --git a/drivers/iio/accel/adxl345.h b/drivers/iio/accel/adxl345.h index bc6d634bd85c..7d482dd595fa 100644 --- a/drivers/iio/accel/adxl345.h +++ b/drivers/iio/accel/adxl345.h @@ -111,6 +111,10 @@ */ #define ADXL375_USCALE 480000 +struct regmap; + +bool adxl345_is_volatile_reg(struct device *dev, unsigned int reg); + struct adxl345_chip_info { const char *name; int uscale; diff --git a/drivers/iio/accel/adxl345_core.c b/drivers/iio/accel/adxl345_core.c index 375c27d16827..2e5fdd479e8d 100644 --- a/drivers/iio/accel/adxl345_core.c +++ b/drivers/iio/accel/adxl345_core.c @@ -8,6 +8,7 @@ */ #include <linux/bitfield.h> +#include <linux/bitops.h> #include <linux/interrupt.h> #include <linux/module.h> #include <linux/property.h> @@ -17,6 +18,7 @@ #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> #include <linux/iio/buffer.h> +#include <linux/iio/events.h> #include <linux/iio/kfifo_buf.h> #include "adxl345.h" @@ -31,18 +33,71 @@ #define ADXL345_INT1 0 #define ADXL345_INT2 1 +#define ADXL345_REG_TAP_AXIS_MSK GENMASK(2, 0) +#define ADXL345_REG_TAP_SUPPRESS_MSK BIT(3) +#define ADXL345_REG_TAP_SUPPRESS BIT(3) + +#define ADXL345_TAP_Z_EN BIT(0) +#define ADXL345_TAP_Y_EN BIT(1) +#define ADXL345_TAP_X_EN BIT(2) + +/* single/double tap */ +enum adxl345_tap_type { + ADXL345_SINGLE_TAP, + ADXL345_DOUBLE_TAP, +}; + +static const unsigned int adxl345_tap_int_reg[] = { + [ADXL345_SINGLE_TAP] = ADXL345_INT_SINGLE_TAP, + [ADXL345_DOUBLE_TAP] = ADXL345_INT_DOUBLE_TAP, +}; + +enum adxl345_tap_time_type { + ADXL345_TAP_TIME_LATENT, + ADXL345_TAP_TIME_WINDOW, + ADXL345_TAP_TIME_DUR, +}; + +static const unsigned int adxl345_tap_time_reg[] = { + [ADXL345_TAP_TIME_LATENT] = ADXL345_REG_LATENT, + [ADXL345_TAP_TIME_WINDOW] = ADXL345_REG_WINDOW, + [ADXL345_TAP_TIME_DUR] = ADXL345_REG_DUR, +}; + struct adxl345_state { const struct adxl345_chip_info *info; struct regmap *regmap; bool fifo_delay; /* delay: delay is needed for SPI */ int irq; - u8 intio; - u8 int_map; u8 watermark; u8 fifo_mode; + + u32 tap_duration_us; + u32 tap_latent_us; + u32 tap_window_us; + __le16 fifo_buf[ADXL345_DIRS * ADXL345_FIFO_SIZE + 1] __aligned(IIO_DMA_MINALIGN); }; +static struct iio_event_spec adxl345_events[] = { + { + /* single tap */ + .type = IIO_EV_TYPE_GESTURE, + .dir = IIO_EV_DIR_SINGLETAP, + .mask_separate = BIT(IIO_EV_INFO_ENABLE), + .mask_shared_by_type = BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_TIMEOUT), + }, + { + /* double tap */ + .type = IIO_EV_TYPE_GESTURE, + .dir = IIO_EV_DIR_DOUBLETAP, + .mask_shared_by_type = BIT(IIO_EV_INFO_ENABLE) | + BIT(IIO_EV_INFO_RESET_TIMEOUT) | + BIT(IIO_EV_INFO_TAP2_MIN_DELAY), + }, +}; + #define ADXL345_CHANNEL(index, reg, axis) { \ .type = IIO_ACCEL, \ .modified = 1, \ @@ -59,6 +114,8 @@ struct adxl345_state { .storagebits = 16, \ .endianness = IIO_LE, \ }, \ + .event_spec = adxl345_events, \ + .num_event_specs = ARRAY_SIZE(adxl345_events), \ } enum adxl345_chans { @@ -76,6 +133,25 @@ static const unsigned long adxl345_scan_masks[] = { 0 }; +bool adxl345_is_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case ADXL345_REG_DATA_AXIS(0): + case ADXL345_REG_DATA_AXIS(1): + case ADXL345_REG_DATA_AXIS(2): + case ADXL345_REG_DATA_AXIS(3): + case ADXL345_REG_DATA_AXIS(4): + case ADXL345_REG_DATA_AXIS(5): + case ADXL345_REG_ACT_TAP_STATUS: + case ADXL345_REG_FIFO_STATUS: + case ADXL345_REG_INT_SOURCE: + return true; + default: + return false; + } +} +EXPORT_SYMBOL_NS_GPL(adxl345_is_volatile_reg, "IIO_ADXL345"); + /** * adxl345_set_measure_en() - Enable and disable measuring. * @@ -96,24 +172,215 @@ static int adxl345_set_measure_en(struct adxl345_state *st, bool en) return regmap_write(st->regmap, ADXL345_REG_POWER_CTL, val); } -static int adxl345_set_interrupts(struct adxl345_state *st) +/* tap */ + +static int _adxl345_set_tap_int(struct adxl345_state *st, + enum adxl345_tap_type type, bool state) { + unsigned int int_map = 0x00; + unsigned int tap_threshold; + bool axis_valid; + bool singletap_args_valid = false; + bool doubletap_args_valid = false; + bool en = false; + u32 axis_ctrl; int ret; - unsigned int int_enable = st->int_map; - unsigned int int_map; + + ret = regmap_read(st->regmap, ADXL345_REG_TAP_AXIS, &axis_ctrl); + if (ret) + return ret; + + axis_valid = FIELD_GET(ADXL345_REG_TAP_AXIS_MSK, axis_ctrl) > 0; + + ret = regmap_read(st->regmap, ADXL345_REG_THRESH_TAP, &tap_threshold); + if (ret) + return ret; /* - * Any bits set to 0 in the INT map register send their respective - * interrupts to the INT1 pin, whereas bits set to 1 send their respective - * interrupts to the INT2 pin. The intio shall convert this accordingly. + * Note: A value of 0 for threshold and/or dur may result in undesirable + * behavior if single tap/double tap interrupts are enabled. */ - int_map = st->intio ? st->int_map : ~st->int_map; + singletap_args_valid = tap_threshold > 0 && st->tap_duration_us > 0; - ret = regmap_write(st->regmap, ADXL345_REG_INT_MAP, int_map); + if (type == ADXL345_SINGLE_TAP) { + en = axis_valid && singletap_args_valid; + } else { + /* doubletap: Window must be equal or greater than latent! */ + doubletap_args_valid = st->tap_latent_us > 0 && + st->tap_window_us > 0 && + st->tap_window_us >= st->tap_latent_us; + + en = axis_valid && singletap_args_valid && doubletap_args_valid; + } + + if (state && en) + int_map |= adxl345_tap_int_reg[type]; + + return regmap_update_bits(st->regmap, ADXL345_REG_INT_ENABLE, + adxl345_tap_int_reg[type], int_map); +} + +static int adxl345_is_tap_en(struct adxl345_state *st, + enum iio_modifier axis, + enum adxl345_tap_type type, bool *en) +{ + unsigned int regval; + u32 axis_ctrl; + int ret; + + ret = regmap_read(st->regmap, ADXL345_REG_TAP_AXIS, &axis_ctrl); if (ret) return ret; - return regmap_write(st->regmap, ADXL345_REG_INT_ENABLE, int_enable); + /* Verify if axis is enabled for the tap detection. */ + switch (axis) { + case IIO_MOD_X: + *en = FIELD_GET(ADXL345_TAP_X_EN, axis_ctrl); + break; + case IIO_MOD_Y: + *en = FIELD_GET(ADXL345_TAP_Y_EN, axis_ctrl); + break; + case IIO_MOD_Z: + *en = FIELD_GET(ADXL345_TAP_Z_EN, axis_ctrl); + break; + default: + *en = false; + return -EINVAL; + } + + if (*en) { + /* + * If axis allow for tap detection, verify if the interrupt is + * enabled for tap detection. + */ + ret = regmap_read(st->regmap, ADXL345_REG_INT_ENABLE, ®val); + if (ret) + return ret; + + *en = adxl345_tap_int_reg[type] & regval; + } + + return 0; +} + +static int adxl345_set_singletap_en(struct adxl345_state *st, + enum iio_modifier axis, bool en) +{ + int ret; + u32 axis_ctrl; + + switch (axis) { + case IIO_MOD_X: + axis_ctrl = ADXL345_TAP_X_EN; + break; + case IIO_MOD_Y: + axis_ctrl = ADXL345_TAP_Y_EN; + break; + case IIO_MOD_Z: + axis_ctrl = ADXL345_TAP_Z_EN; + break; + default: + return -EINVAL; + } + + if (en) + ret = regmap_set_bits(st->regmap, ADXL345_REG_TAP_AXIS, + axis_ctrl); + else + ret = regmap_clear_bits(st->regmap, ADXL345_REG_TAP_AXIS, + axis_ctrl); + if (ret) + return ret; + + return _adxl345_set_tap_int(st, ADXL345_SINGLE_TAP, en); +} + +static int adxl345_set_doubletap_en(struct adxl345_state *st, bool en) +{ + int ret; + + /* + * Generally suppress detection of spikes during the latency period as + * double taps here, this is fully optional for double tap detection + */ + ret = regmap_update_bits(st->regmap, ADXL345_REG_TAP_AXIS, + ADXL345_REG_TAP_SUPPRESS_MSK, + en ? ADXL345_REG_TAP_SUPPRESS : 0x00); + if (ret) + return ret; + + return _adxl345_set_tap_int(st, ADXL345_DOUBLE_TAP, en); +} + +static int _adxl345_set_tap_time(struct adxl345_state *st, + enum adxl345_tap_time_type type, u32 val_us) +{ + unsigned int regval; + + switch (type) { + case ADXL345_TAP_TIME_WINDOW: + st->tap_window_us = val_us; + break; + case ADXL345_TAP_TIME_LATENT: + st->tap_latent_us = val_us; + break; + case ADXL345_TAP_TIME_DUR: + st->tap_duration_us = val_us; + break; + } + + /* + * The scale factor is 1250us / LSB for tap_window_us and tap_latent_us. + * For tap_duration_us the scale factor is 625us / LSB. + */ + if (type == ADXL345_TAP_TIME_DUR) + regval = DIV_ROUND_CLOSEST(val_us, 625); + else + regval = DIV_ROUND_CLOSEST(val_us, 1250); + + return regmap_write(st->regmap, adxl345_tap_time_reg[type], regval); +} + +static int adxl345_set_tap_duration(struct adxl345_state *st, u32 val_int, + u32 val_fract_us) +{ + /* + * Max value is 255 * 625 us = 0.159375 seconds + * + * Note: the scaling is similar to the scaling in the ADXL380 + */ + if (val_int || val_fract_us > 159375) + return -EINVAL; + + return _adxl345_set_tap_time(st, ADXL345_TAP_TIME_DUR, val_fract_us); +} + +static int adxl345_set_tap_window(struct adxl345_state *st, u32 val_int, + u32 val_fract_us) +{ + /* + * Max value is 255 * 1250 us = 0.318750 seconds + * + * Note: the scaling is similar to the scaling in the ADXL380 + */ + if (val_int || val_fract_us > 318750) + return -EINVAL; + + return _adxl345_set_tap_time(st, ADXL345_TAP_TIME_WINDOW, val_fract_us); +} + +static int adxl345_set_tap_latent(struct adxl345_state *st, u32 val_int, + u32 val_fract_us) +{ + /* + * Max value is 255 * 1250 us = 0.318750 seconds + * + * Note: the scaling is similar to the scaling in the ADXL380 + */ + if (val_int || val_fract_us > 318750) + return -EINVAL; + + return _adxl345_set_tap_time(st, ADXL345_TAP_TIME_LATENT, val_fract_us); } static int adxl345_read_raw(struct iio_dev *indio_dev, @@ -136,7 +403,7 @@ static int adxl345_read_raw(struct iio_dev *indio_dev, ret = regmap_bulk_read(st->regmap, ADXL345_REG_DATA_AXIS(chan->address), &accel, sizeof(accel)); - if (ret < 0) + if (ret) return ret; *val = sign_extend32(le16_to_cpu(accel), 12); @@ -148,7 +415,7 @@ static int adxl345_read_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_CALIBBIAS: ret = regmap_read(st->regmap, ADXL345_REG_OFS_AXIS(chan->address), ®val); - if (ret < 0) + if (ret) return ret; /* * 8-bit resolution at +/- 2g, that is 4x accel data scale @@ -159,7 +426,7 @@ static int adxl345_read_raw(struct iio_dev *indio_dev, return IIO_VAL_INT; case IIO_CHAN_INFO_SAMP_FREQ: ret = regmap_read(st->regmap, ADXL345_REG_BW_RATE, ®val); - if (ret < 0) + if (ret) return ret; samp_freq_nhz = ADXL345_BASE_RATE_NANO_HZ << @@ -201,6 +468,157 @@ static int adxl345_write_raw(struct iio_dev *indio_dev, return -EINVAL; } +static int adxl345_read_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir) +{ + struct adxl345_state *st = iio_priv(indio_dev); + bool int_en; + int ret; + + switch (type) { + case IIO_EV_TYPE_GESTURE: + switch (dir) { + case IIO_EV_DIR_SINGLETAP: + ret = adxl345_is_tap_en(st, chan->channel2, + ADXL345_SINGLE_TAP, &int_en); + if (ret) + return ret; + return int_en; + case IIO_EV_DIR_DOUBLETAP: + ret = adxl345_is_tap_en(st, chan->channel2, + ADXL345_DOUBLE_TAP, &int_en); + if (ret) + return ret; + return int_en; + default: + return -EINVAL; + } + default: + return -EINVAL; + } +} + +static int adxl345_write_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + bool state) +{ + struct adxl345_state *st = iio_priv(indio_dev); + + switch (type) { + case IIO_EV_TYPE_GESTURE: + switch (dir) { + case IIO_EV_DIR_SINGLETAP: + return adxl345_set_singletap_en(st, chan->channel2, state); + case IIO_EV_DIR_DOUBLETAP: + return adxl345_set_doubletap_en(st, state); + default: + return -EINVAL; + } + default: + return -EINVAL; + } +} + +static int adxl345_read_event_value(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int *val, int *val2) +{ + struct adxl345_state *st = iio_priv(indio_dev); + unsigned int tap_threshold; + int ret; + + switch (type) { + case IIO_EV_TYPE_GESTURE: + switch (info) { + case IIO_EV_INFO_VALUE: + /* + * The scale factor would be 62.5mg/LSB (i.e. 0xFF = 16g) but + * not applied here. In context of this general purpose sensor, + * what imports is rather signal intensity than the absolute + * measured g value. + */ + ret = regmap_read(st->regmap, ADXL345_REG_THRESH_TAP, + &tap_threshold); + if (ret) + return ret; + *val = sign_extend32(tap_threshold, 7); + return IIO_VAL_INT; + case IIO_EV_INFO_TIMEOUT: + *val = st->tap_duration_us; + *val2 = 1000000; + return IIO_VAL_FRACTIONAL; + case IIO_EV_INFO_RESET_TIMEOUT: + *val = st->tap_window_us; + *val2 = 1000000; + return IIO_VAL_FRACTIONAL; + case IIO_EV_INFO_TAP2_MIN_DELAY: + *val = st->tap_latent_us; + *val2 = 1000000; + return IIO_VAL_FRACTIONAL; + default: + return -EINVAL; + } + default: + return -EINVAL; + } +} + +static int adxl345_write_event_value(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int val, int val2) +{ + struct adxl345_state *st = iio_priv(indio_dev); + int ret; + + ret = adxl345_set_measure_en(st, false); + if (ret) + return ret; + + switch (type) { + case IIO_EV_TYPE_GESTURE: + switch (info) { + case IIO_EV_INFO_VALUE: + ret = regmap_write(st->regmap, ADXL345_REG_THRESH_TAP, + min(val, 0xFF)); + if (ret) + return ret; + break; + case IIO_EV_INFO_TIMEOUT: + ret = adxl345_set_tap_duration(st, val, val2); + if (ret) + return ret; + break; + case IIO_EV_INFO_RESET_TIMEOUT: + ret = adxl345_set_tap_window(st, val, val2); + if (ret) + return ret; + break; + case IIO_EV_INFO_TAP2_MIN_DELAY: + ret = adxl345_set_tap_latent(st, val, val2); + if (ret) + return ret; + break; + default: + return -EINVAL; + } + break; + default: + return -EINVAL; + } + + return adxl345_set_measure_en(st, true); +} + static int adxl345_reg_access(struct iio_dev *indio_dev, unsigned int reg, unsigned int writeval, unsigned int *readval) { @@ -214,7 +632,7 @@ static int adxl345_reg_access(struct iio_dev *indio_dev, unsigned int reg, static int adxl345_set_watermark(struct iio_dev *indio_dev, unsigned int value) { struct adxl345_state *st = iio_priv(indio_dev); - unsigned int fifo_mask = 0x1F; + const unsigned int fifo_mask = 0x1F, watermark_mask = 0x02; int ret; value = min(value, ADXL345_FIFO_SIZE - 1); @@ -224,9 +642,8 @@ static int adxl345_set_watermark(struct iio_dev *indio_dev, unsigned int value) return ret; st->watermark = value; - st->int_map |= ADXL345_INT_WATERMARK; - - return 0; + return regmap_update_bits(st->regmap, ADXL345_REG_INT_ENABLE, + watermark_mask, ADXL345_INT_WATERMARK); } static int adxl345_write_raw_get_fmt(struct iio_dev *indio_dev, @@ -265,21 +682,25 @@ static const struct attribute_group adxl345_attrs_group = { static int adxl345_set_fifo(struct adxl345_state *st) { + unsigned int intio; int ret; /* FIFO should only be configured while in standby mode */ ret = adxl345_set_measure_en(st, false); - if (ret < 0) + if (ret) + return ret; + + ret = regmap_read(st->regmap, ADXL345_REG_INT_MAP, &intio); + if (ret) return ret; ret = regmap_write(st->regmap, ADXL345_REG_FIFO_CTL, FIELD_PREP(ADXL345_FIFO_CTL_SAMPLES_MSK, st->watermark) | - FIELD_PREP(ADXL345_FIFO_CTL_TRIGGER_MSK, - st->intio) | + FIELD_PREP(ADXL345_FIFO_CTL_TRIGGER_MSK, intio) | FIELD_PREP(ADXL345_FIFO_CTL_MODE_MSK, st->fifo_mode)); - if (ret < 0) + if (ret) return ret; return adxl345_set_measure_en(st, true); @@ -300,7 +721,7 @@ static int adxl345_get_samples(struct adxl345_state *st) int ret; ret = regmap_read(st->regmap, ADXL345_REG_FIFO_STATUS, ®val); - if (ret < 0) + if (ret) return ret; return FIELD_GET(ADXL345_REG_FIFO_STATUS_MSK, regval); @@ -328,7 +749,7 @@ static int adxl345_fifo_transfer(struct adxl345_state *st, int samples) /* read 3x 2 byte elements from base address into next fifo_buf position */ ret = regmap_bulk_read(st->regmap, ADXL345_REG_XYZ_BASE, st->fifo_buf + (i * count / 2), count); - if (ret < 0) + if (ret) return ret; /* @@ -374,11 +795,6 @@ static void adxl345_fifo_reset(struct adxl345_state *st) static int adxl345_buffer_postenable(struct iio_dev *indio_dev) { struct adxl345_state *st = iio_priv(indio_dev); - int ret; - - ret = adxl345_set_interrupts(st); - if (ret < 0) - return ret; st->fifo_mode = ADXL345_FIFO_STREAM; return adxl345_set_fifo(st); @@ -391,11 +807,10 @@ static int adxl345_buffer_predisable(struct iio_dev *indio_dev) st->fifo_mode = ADXL345_FIFO_BYPASS; ret = adxl345_set_fifo(st); - if (ret < 0) + if (ret) return ret; - st->int_map = 0x00; - return adxl345_set_interrupts(st); + return regmap_write(st->regmap, ADXL345_REG_INT_ENABLE, 0x00); } static const struct iio_buffer_setup_ops adxl345_buffer_ops = { @@ -422,6 +837,48 @@ static int adxl345_fifo_push(struct iio_dev *indio_dev, return 0; } +static int adxl345_push_event(struct iio_dev *indio_dev, int int_stat, + enum iio_modifier tap_dir) +{ + s64 ts = iio_get_time_ns(indio_dev); + struct adxl345_state *st = iio_priv(indio_dev); + int samples; + int ret = -ENOENT; + + if (FIELD_GET(ADXL345_INT_SINGLE_TAP, int_stat)) { + ret = iio_push_event(indio_dev, + IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, tap_dir, + IIO_EV_TYPE_GESTURE, + IIO_EV_DIR_SINGLETAP), + ts); + if (ret) + return ret; + } + + if (FIELD_GET(ADXL345_INT_DOUBLE_TAP, int_stat)) { + ret = iio_push_event(indio_dev, + IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, tap_dir, + IIO_EV_TYPE_GESTURE, + IIO_EV_DIR_DOUBLETAP), + ts); + if (ret) + return ret; + } + + if (FIELD_GET(ADXL345_INT_WATERMARK, int_stat)) { + samples = adxl345_get_samples(st); + if (samples < 0) + return -EINVAL; + + if (adxl345_fifo_push(indio_dev, samples) < 0) + return -EINVAL; + + ret = 0; + } + + return ret; +} + /** * adxl345_irq_handler() - Handle irqs of the ADXL345. * @irq: The irq being handled. @@ -433,21 +890,35 @@ static irqreturn_t adxl345_irq_handler(int irq, void *p) { struct iio_dev *indio_dev = p; struct adxl345_state *st = iio_priv(indio_dev); + unsigned int regval; + enum iio_modifier tap_dir = IIO_NO_MOD; + u32 axis_ctrl; int int_stat; - int samples; + int ret; - if (regmap_read(st->regmap, ADXL345_REG_INT_SOURCE, &int_stat)) + ret = regmap_read(st->regmap, ADXL345_REG_TAP_AXIS, &axis_ctrl); + if (ret) return IRQ_NONE; - if (FIELD_GET(ADXL345_INT_WATERMARK, int_stat)) { - samples = adxl345_get_samples(st); - if (samples < 0) - goto err; - - if (adxl345_fifo_push(indio_dev, samples) < 0) - goto err; + if (FIELD_GET(ADXL345_REG_TAP_AXIS_MSK, axis_ctrl)) { + ret = regmap_read(st->regmap, ADXL345_REG_ACT_TAP_STATUS, ®val); + if (ret) + return IRQ_NONE; + + if (FIELD_GET(ADXL345_TAP_Z_EN, regval)) + tap_dir = IIO_MOD_Z; + else if (FIELD_GET(ADXL345_TAP_Y_EN, regval)) + tap_dir = IIO_MOD_Y; + else if (FIELD_GET(ADXL345_TAP_X_EN, regval)) + tap_dir = IIO_MOD_X; } + if (regmap_read(st->regmap, ADXL345_REG_INT_SOURCE, &int_stat)) + return IRQ_NONE; + + if (adxl345_push_event(indio_dev, int_stat, tap_dir)) + goto err; + if (FIELD_GET(ADXL345_INT_OVERRUN, int_stat)) goto err; @@ -464,6 +935,10 @@ static const struct iio_info adxl345_info = { .read_raw = adxl345_read_raw, .write_raw = adxl345_write_raw, .write_raw_get_fmt = adxl345_write_raw_get_fmt, + .read_event_config = adxl345_read_event_config, + .write_event_config = adxl345_write_event_config, + .read_event_value = adxl345_read_event_value, + .write_event_value = adxl345_write_event_value, .debugfs_reg_access = &adxl345_reg_access, .hwfifo_set_watermark = adxl345_set_watermark, }; @@ -492,10 +967,12 @@ int adxl345_core_probe(struct device *dev, struct regmap *regmap, struct adxl345_state *st; struct iio_dev *indio_dev; u32 regval; + u8 intio = ADXL345_INT1; unsigned int data_format_mask = (ADXL345_DATA_FORMAT_RANGE | ADXL345_DATA_FORMAT_JUSTIFY | ADXL345_DATA_FORMAT_FULL_RES | ADXL345_DATA_FORMAT_SELF_TEST); + unsigned int tap_threshold; int ret; indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); @@ -509,6 +986,12 @@ int adxl345_core_probe(struct device *dev, struct regmap *regmap, return -ENODEV; st->fifo_delay = fifo_delay_default; + /* Init with reasonable values */ + tap_threshold = 48; /* 48 [0x30] -> ~3g */ + st->tap_duration_us = 16; /* 16 [0x10] -> .010 */ + st->tap_window_us = 64; /* 64 [0x40] -> .080 */ + st->tap_latent_us = 16; /* 16 [0x10] -> .020 */ + indio_dev->name = st->info->name; indio_dev->info = &adxl345_info; indio_dev->modes = INDIO_DIRECT_MODE; @@ -516,6 +999,11 @@ int adxl345_core_probe(struct device *dev, struct regmap *regmap, indio_dev->num_channels = ARRAY_SIZE(adxl345_channels); indio_dev->available_scan_masks = adxl345_scan_masks; + /* Reset interrupts at start up */ + ret = regmap_write(st->regmap, ADXL345_REG_INT_ENABLE, 0x00); + if (ret) + return ret; + if (setup) { /* Perform optional initial bus specific configuration */ ret = setup(dev, st->regmap); @@ -540,7 +1028,7 @@ int adxl345_core_probe(struct device *dev, struct regmap *regmap, } ret = regmap_read(st->regmap, ADXL345_REG_DEVID, ®val); - if (ret < 0) + if (ret) return dev_err_probe(dev, ret, "Error reading device ID\n"); if (regval != ADXL345_DEVID) @@ -549,23 +1037,37 @@ int adxl345_core_probe(struct device *dev, struct regmap *regmap, /* Enable measurement mode */ ret = adxl345_set_measure_en(st, true); - if (ret < 0) + if (ret) return dev_err_probe(dev, ret, "Failed to enable measurement mode\n"); ret = devm_add_action_or_reset(dev, adxl345_powerdown, st); - if (ret < 0) + if (ret) return ret; - st->intio = ADXL345_INT1; st->irq = fwnode_irq_get_byname(dev_fwnode(dev), "INT1"); if (st->irq < 0) { - st->intio = ADXL345_INT2; + intio = ADXL345_INT2; st->irq = fwnode_irq_get_byname(dev_fwnode(dev), "INT2"); if (st->irq < 0) - st->intio = ADXL345_INT_NONE; + intio = ADXL345_INT_NONE; } - if (st->intio != ADXL345_INT_NONE) { + if (intio != ADXL345_INT_NONE) { + /* + * Any bits set to 0 in the INT map register send their respective + * interrupts to the INT1 pin, whereas bits set to 1 send their respective + * interrupts to the INT2 pin. The intio shall convert this accordingly. + */ + regval = intio ? 0xff : 0; + + ret = regmap_write(st->regmap, ADXL345_REG_INT_MAP, regval); + if (ret) + return ret; + + ret = regmap_write(st->regmap, ADXL345_REG_THRESH_TAP, tap_threshold); + if (ret) + return ret; + /* FIFO_STREAM mode is going to be activated later */ ret = devm_iio_kfifo_buffer_setup(dev, indio_dev, &adxl345_buffer_ops); if (ret) @@ -581,7 +1083,7 @@ int adxl345_core_probe(struct device *dev, struct regmap *regmap, ret = regmap_write(st->regmap, ADXL345_REG_FIFO_CTL, FIELD_PREP(ADXL345_FIFO_CTL_MODE_MSK, ADXL345_FIFO_BYPASS)); - if (ret < 0) + if (ret) return ret; } diff --git a/drivers/iio/accel/adxl345_i2c.c b/drivers/iio/accel/adxl345_i2c.c index 8c385dd6c01d..af84c0043c6c 100644 --- a/drivers/iio/accel/adxl345_i2c.c +++ b/drivers/iio/accel/adxl345_i2c.c @@ -17,6 +17,8 @@ static const struct regmap_config adxl345_i2c_regmap_config = { .reg_bits = 8, .val_bits = 8, + .volatile_reg = adxl345_is_volatile_reg, + .cache_type = REGCACHE_MAPLE, }; static int adxl345_i2c_probe(struct i2c_client *client) diff --git a/drivers/iio/accel/adxl345_spi.c b/drivers/iio/accel/adxl345_spi.c index 7e518aea17bf..0315f4bfd69a 100644 --- a/drivers/iio/accel/adxl345_spi.c +++ b/drivers/iio/accel/adxl345_spi.c @@ -19,6 +19,8 @@ static const struct regmap_config adxl345_spi_regmap_config = { .val_bits = 8, /* Setting bits 7 and 6 enables multiple-byte read */ .read_flag_mask = BIT(7) | BIT(6), + .volatile_reg = adxl345_is_volatile_reg, + .cache_type = REGCACHE_MAPLE, }; static int adxl345_spi_setup(struct device *dev, struct regmap *regmap) diff --git a/drivers/iio/accel/adxl355_core.c b/drivers/iio/accel/adxl355_core.c index cbac622ef821..2e00fd51b4d5 100644 --- a/drivers/iio/accel/adxl355_core.c +++ b/drivers/iio/accel/adxl355_core.c @@ -666,8 +666,8 @@ static irqreturn_t adxl355_trigger_handler(int irq, void *p) if (ret) goto out_unlock_notify; - iio_push_to_buffers_with_timestamp(indio_dev, &data->buffer, - pf->timestamp); + iio_push_to_buffers_with_ts(indio_dev, &data->buffer, + sizeof(data->buffer), pf->timestamp); out_unlock_notify: mutex_unlock(&data->lock); diff --git a/drivers/iio/accel/adxl367_i2c.c b/drivers/iio/accel/adxl367_i2c.c index 80f0b642b9b0..1c7d2eb054a2 100644 --- a/drivers/iio/accel/adxl367_i2c.c +++ b/drivers/iio/accel/adxl367_i2c.c @@ -68,7 +68,7 @@ MODULE_DEVICE_TABLE(i2c, adxl367_i2c_id); static const struct of_device_id adxl367_of_match[] = { { .compatible = "adi,adxl367" }, - { }, + { } }; MODULE_DEVICE_TABLE(of, adxl367_of_match); diff --git a/drivers/iio/accel/adxl367_spi.c b/drivers/iio/accel/adxl367_spi.c index 49d7c8fbe8ed..3fed56bb9054 100644 --- a/drivers/iio/accel/adxl367_spi.c +++ b/drivers/iio/accel/adxl367_spi.c @@ -139,13 +139,13 @@ static int adxl367_spi_probe(struct spi_device *spi) static const struct spi_device_id adxl367_spi_id[] = { { "adxl367", 0 }, - { }, + { } }; MODULE_DEVICE_TABLE(spi, adxl367_spi_id); static const struct of_device_id adxl367_of_match[] = { { .compatible = "adi,adxl367" }, - { }, + { } }; MODULE_DEVICE_TABLE(of, adxl367_of_match); diff --git a/drivers/iio/accel/adxl372_i2c.c b/drivers/iio/accel/adxl372_i2c.c index 43d5fd921be7..186d4fe9a556 100644 --- a/drivers/iio/accel/adxl372_i2c.c +++ b/drivers/iio/accel/adxl372_i2c.c @@ -43,7 +43,7 @@ static int adxl372_i2c_probe(struct i2c_client *client) static const struct i2c_device_id adxl372_i2c_id[] = { { "adxl372" }, - {} + { } }; MODULE_DEVICE_TABLE(i2c, adxl372_i2c_id); diff --git a/drivers/iio/accel/adxl372_spi.c b/drivers/iio/accel/adxl372_spi.c index 1ab1997a55b1..39941b519c3b 100644 --- a/drivers/iio/accel/adxl372_spi.c +++ b/drivers/iio/accel/adxl372_spi.c @@ -34,7 +34,7 @@ static int adxl372_spi_probe(struct spi_device *spi) static const struct spi_device_id adxl372_spi_id[] = { { "adxl372", 0 }, - {} + { } }; MODULE_DEVICE_TABLE(spi, adxl372_spi_id); diff --git a/drivers/iio/accel/bma180.c b/drivers/iio/accel/bma180.c index aa664a923f91..93a868678722 100644 --- a/drivers/iio/accel/bma180.c +++ b/drivers/iio/accel/bma180.c @@ -887,7 +887,7 @@ static irqreturn_t bma180_trigger_handler(int irq, void *p) mutex_unlock(&data->mutex); - iio_push_to_buffers_with_timestamp(indio_dev, &data->scan, time_ns); + iio_push_to_buffers_with_ts(indio_dev, &data->scan, sizeof(data->scan), time_ns); err: iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/accel/bma220_spi.c b/drivers/iio/accel/bma220_spi.c index 96ba028157ee..38f7498431ee 100644 --- a/drivers/iio/accel/bma220_spi.c +++ b/drivers/iio/accel/bma220_spi.c @@ -103,8 +103,8 @@ static irqreturn_t bma220_trigger_handler(int irq, void *p) if (ret < 0) goto err; - iio_push_to_buffers_with_timestamp(indio_dev, &data->scan, - pf->timestamp); + iio_push_to_buffers_with_ts(indio_dev, &data->scan, sizeof(data->scan), + pf->timestamp); err: mutex_unlock(&data->lock); iio_trigger_notify_done(indio_dev->trig); @@ -307,12 +307,12 @@ static DEFINE_SIMPLE_DEV_PM_OPS(bma220_pm_ops, bma220_suspend, bma220_resume); static const struct spi_device_id bma220_spi_id[] = { {"bma220", 0}, - {} + { } }; static const struct acpi_device_id bma220_acpi_id[] = { {"BMA0220", 0}, - {} + { } }; MODULE_DEVICE_TABLE(spi, bma220_spi_id); diff --git a/drivers/iio/accel/bma400_core.c b/drivers/iio/accel/bma400_core.c index 23f5e1ce9cc4..85e23badf733 100644 --- a/drivers/iio/accel/bma400_core.c +++ b/drivers/iio/accel/bma400_core.c @@ -1591,8 +1591,9 @@ static irqreturn_t bma400_trigger_handler(int irq, void *p) data->buffer.temperature = temp; } - iio_push_to_buffers_with_timestamp(indio_dev, &data->buffer, - iio_get_time_ns(indio_dev)); + iio_push_to_buffers_with_ts(indio_dev, &data->buffer, + sizeof(data->buffer), + iio_get_time_ns(indio_dev)); mutex_unlock(&data->mutex); iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/accel/bmc150-accel-i2c.c b/drivers/iio/accel/bmc150-accel-i2c.c index 0d4ce6c38931..b4604f441553 100644 --- a/drivers/iio/accel/bmc150-accel-i2c.c +++ b/drivers/iio/accel/bmc150-accel-i2c.c @@ -240,7 +240,7 @@ static const struct acpi_device_id bmc150_accel_acpi_match[] = { {"BOSC0200"}, {"BSBA0150"}, {"DUAL250E"}, - { }, + { } }; MODULE_DEVICE_TABLE(acpi, bmc150_accel_acpi_match); @@ -255,7 +255,7 @@ static const struct i2c_device_id bmc150_accel_id[] = { {"bmc150_accel"}, {"bmc156_accel", BOSCH_BMC156}, {"bmi055_accel"}, - {} + { } }; MODULE_DEVICE_TABLE(i2c, bmc150_accel_id); @@ -271,7 +271,7 @@ static const struct of_device_id bmc150_accel_of_match[] = { { .compatible = "bosch,bmc150_accel" }, { .compatible = "bosch,bmc156_accel" }, { .compatible = "bosch,bmi055_accel" }, - { }, + { } }; MODULE_DEVICE_TABLE(of, bmc150_accel_of_match); diff --git a/drivers/iio/accel/bmc150-accel-spi.c b/drivers/iio/accel/bmc150-accel-spi.c index 70b3642656ab..26ce50b37716 100644 --- a/drivers/iio/accel/bmc150-accel-spi.c +++ b/drivers/iio/accel/bmc150-accel-spi.c @@ -48,7 +48,7 @@ static const struct acpi_device_id bmc150_accel_acpi_match[] = { {"BMC150A"}, {"BMI055A"}, {"BSBA0150"}, - { }, + { } }; MODULE_DEVICE_TABLE(acpi, bmc150_accel_acpi_match); @@ -62,7 +62,7 @@ static const struct spi_device_id bmc150_accel_id[] = { {"bmc150_accel"}, {"bmc156_accel", BOSCH_BMC156}, {"bmi055_accel"}, - {} + { } }; MODULE_DEVICE_TABLE(spi, bmc150_accel_id); diff --git a/drivers/iio/accel/bmi088-accel-i2c.c b/drivers/iio/accel/bmi088-accel-i2c.c index bd22bd0d3c25..310f863029bb 100644 --- a/drivers/iio/accel/bmi088-accel-i2c.c +++ b/drivers/iio/accel/bmi088-accel-i2c.c @@ -40,7 +40,7 @@ static const struct of_device_id bmi088_of_match[] = { { .compatible = "bosch,bmi085-accel" }, { .compatible = "bosch,bmi088-accel" }, { .compatible = "bosch,bmi090l-accel" }, - {} + { } }; MODULE_DEVICE_TABLE(of, bmi088_of_match); @@ -48,7 +48,7 @@ static const struct i2c_device_id bmi088_accel_id[] = { { "bmi085-accel", BOSCH_BMI085 }, { "bmi088-accel", BOSCH_BMI088 }, { "bmi090l-accel", BOSCH_BMI090L }, - {} + { } }; MODULE_DEVICE_TABLE(i2c, bmi088_accel_id); diff --git a/drivers/iio/accel/bmi088-accel-spi.c b/drivers/iio/accel/bmi088-accel-spi.c index c9d51a74c07f..44cb50c76cb1 100644 --- a/drivers/iio/accel/bmi088-accel-spi.c +++ b/drivers/iio/accel/bmi088-accel-spi.c @@ -67,7 +67,7 @@ static const struct of_device_id bmi088_of_match[] = { { .compatible = "bosch,bmi085-accel" }, { .compatible = "bosch,bmi088-accel" }, { .compatible = "bosch,bmi090l-accel" }, - {} + { } }; MODULE_DEVICE_TABLE(of, bmi088_of_match); @@ -75,7 +75,7 @@ static const struct spi_device_id bmi088_accel_id[] = { {"bmi085-accel", BOSCH_BMI085}, {"bmi088-accel", BOSCH_BMI088}, {"bmi090l-accel", BOSCH_BMI090L}, - {} + { } }; MODULE_DEVICE_TABLE(spi, bmi088_accel_id); diff --git a/drivers/iio/accel/da280.c b/drivers/iio/accel/da280.c index 992286828844..c2dd123b9021 100644 --- a/drivers/iio/accel/da280.c +++ b/drivers/iio/accel/da280.c @@ -157,7 +157,7 @@ static const struct da280_match_data da280_match_data = { "da280", 3 }; static const struct acpi_device_id da280_acpi_match[] = { { "NSA2513", (kernel_ulong_t)&da217_match_data }, { "MIRAACC", (kernel_ulong_t)&da280_match_data }, - {} + { } }; MODULE_DEVICE_TABLE(acpi, da280_acpi_match); @@ -165,7 +165,7 @@ static const struct i2c_device_id da280_i2c_id[] = { { "da217", (kernel_ulong_t)&da217_match_data }, { "da226", (kernel_ulong_t)&da226_match_data }, { "da280", (kernel_ulong_t)&da280_match_data }, - {} + { } }; MODULE_DEVICE_TABLE(i2c, da280_i2c_id); diff --git a/drivers/iio/accel/da311.c b/drivers/iio/accel/da311.c index 94f827acdd1c..e1df7b009d89 100644 --- a/drivers/iio/accel/da311.c +++ b/drivers/iio/accel/da311.c @@ -269,7 +269,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(da311_pm_ops, da311_suspend, da311_resume); static const struct i2c_device_id da311_i2c_id[] = { { "da311" }, - {} + { } }; MODULE_DEVICE_TABLE(i2c, da311_i2c_id); diff --git a/drivers/iio/accel/dmard10.c b/drivers/iio/accel/dmard10.c index 35c0eefb741e..71cd1928baa6 100644 --- a/drivers/iio/accel/dmard10.c +++ b/drivers/iio/accel/dmard10.c @@ -232,7 +232,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(dmard10_pm_ops, dmard10_suspend, static const struct i2c_device_id dmard10_i2c_id[] = { { "dmard10" }, - {} + { } }; MODULE_DEVICE_TABLE(i2c, dmard10_i2c_id); diff --git a/drivers/iio/accel/fxls8962af-core.c b/drivers/iio/accel/fxls8962af-core.c index bf1d3923a181..12598feaa693 100644 --- a/drivers/iio/accel/fxls8962af-core.c +++ b/drivers/iio/accel/fxls8962af-core.c @@ -23,6 +23,7 @@ #include <linux/regulator/consumer.h> #include <linux/regmap.h> #include <linux/types.h> +#include <linux/units.h> #include <linux/iio/buffer.h> #include <linux/iio/events.h> @@ -439,8 +440,16 @@ static int fxls8962af_read_raw(struct iio_dev *indio_dev, *val = FXLS8962AF_TEMP_CENTER_VAL; return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: - *val = 0; - return fxls8962af_read_full_scale(data, val2); + switch (chan->type) { + case IIO_TEMP: + *val = MILLIDEGREE_PER_DEGREE; + return IIO_VAL_INT; + case IIO_ACCEL: + *val = 0; + return fxls8962af_read_full_scale(data, val2); + default: + return -EINVAL; + } case IIO_CHAN_INFO_SAMP_FREQ: return fxls8962af_read_samp_freq(data, val, val2); default: @@ -736,9 +745,11 @@ static const struct iio_event_spec fxls8962af_event[] = { .type = IIO_TEMP, \ .address = FXLS8962AF_TEMP_OUT, \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SCALE) | \ BIT(IIO_CHAN_INFO_OFFSET),\ .scan_index = -1, \ .scan_type = { \ + .sign = 's', \ .realbits = 8, \ .storagebits = 8, \ }, \ @@ -983,8 +994,8 @@ static int fxls8962af_fifo_flush(struct iio_dev *indio_dev) sizeof(data->scan.channels[0])); } - iio_push_to_buffers_with_timestamp(indio_dev, &data->scan, - tstamp); + iio_push_to_buffers_with_ts(indio_dev, &data->scan, + sizeof(data->scan), tstamp); tstamp += sample_period; } diff --git a/drivers/iio/accel/fxls8962af-i2c.c b/drivers/iio/accel/fxls8962af-i2c.c index 1b9156b6b2e3..106198a12474 100644 --- a/drivers/iio/accel/fxls8962af-i2c.c +++ b/drivers/iio/accel/fxls8962af-i2c.c @@ -32,14 +32,14 @@ static const struct i2c_device_id fxls8962af_id[] = { { "fxls8964af", fxls8964af }, { "fxls8967af", fxls8967af }, { "fxls8974cf", fxls8974cf }, - {} + { } }; MODULE_DEVICE_TABLE(i2c, fxls8962af_id); static const struct of_device_id fxls8962af_of_match[] = { { .compatible = "nxp,fxls8962af" }, { .compatible = "nxp,fxls8964af" }, - {} + { } }; MODULE_DEVICE_TABLE(of, fxls8962af_of_match); diff --git a/drivers/iio/accel/fxls8962af-spi.c b/drivers/iio/accel/fxls8962af-spi.c index 46fc6e002714..bdafd1f615d9 100644 --- a/drivers/iio/accel/fxls8962af-spi.c +++ b/drivers/iio/accel/fxls8962af-spi.c @@ -30,14 +30,14 @@ static int fxls8962af_probe(struct spi_device *spi) static const struct of_device_id fxls8962af_spi_of_match[] = { { .compatible = "nxp,fxls8962af" }, { .compatible = "nxp,fxls8964af" }, - {} + { } }; MODULE_DEVICE_TABLE(of, fxls8962af_spi_of_match); static const struct spi_device_id fxls8962af_spi_id_table[] = { { "fxls8962af", fxls8962af }, { "fxls8964af", fxls8964af }, - {} + { } }; MODULE_DEVICE_TABLE(spi, fxls8962af_spi_id_table); diff --git a/drivers/iio/accel/hid-sensor-accel-3d.c b/drivers/iio/accel/hid-sensor-accel-3d.c index 078fab2abb68..2ff591b3458f 100644 --- a/drivers/iio/accel/hid-sensor-accel-3d.c +++ b/drivers/iio/accel/hid-sensor-accel-3d.c @@ -228,7 +228,7 @@ static void hid_sensor_push_data(struct iio_dev *indio_dev, void *data, int len, int64_t timestamp) { dev_dbg(&indio_dev->dev, "hid_sensor_push_data\n"); - iio_push_to_buffers_with_timestamp(indio_dev, data, timestamp); + iio_push_to_buffers_with_ts(indio_dev, data, len, timestamp); } /* Callback handler to send event after all samples are received and captured */ @@ -440,7 +440,7 @@ static const struct platform_device_id hid_accel_3d_ids[] = { { /* gravity sensor */ .name = "HID-SENSOR-20007b", }, - { /* sentinel */ } + { } }; MODULE_DEVICE_TABLE(platform, hid_accel_3d_ids); diff --git a/drivers/iio/accel/kxcjk-1013.c b/drivers/iio/accel/kxcjk-1013.c index f2496cad8ec2..910d7b5716e1 100644 --- a/drivers/iio/accel/kxcjk-1013.c +++ b/drivers/iio/accel/kxcjk-1013.c @@ -674,8 +674,8 @@ static int kxcjk1013_chip_update_thresholds(struct kxcjk1013_data *data) return 0; } -static int kxcjk1013_setup_any_motion_interrupt(struct kxcjk1013_data *data, - bool status) +static int kxcjk1013_setup_interrupt(struct kxcjk1013_data *data, + bool status, bool is_new_data) { const struct kx_chipset_regs *regs = data->info->regs; int ret; @@ -690,69 +690,12 @@ static int kxcjk1013_setup_any_motion_interrupt(struct kxcjk1013_data *data, if (ret < 0) return ret; - ret = kxcjk1013_chip_update_thresholds(data); - if (ret < 0) - return ret; - - ret = i2c_smbus_read_byte_data(data->client, regs->int_ctrl1); - if (ret < 0) { - dev_err(&data->client->dev, "Error reading reg_int_ctrl1\n"); - return ret; - } - - if (status) - ret |= KXCJK1013_REG_INT_CTRL1_BIT_IEN; - else - ret &= ~KXCJK1013_REG_INT_CTRL1_BIT_IEN; - - ret = i2c_smbus_write_byte_data(data->client, regs->int_ctrl1, ret); - if (ret < 0) { - dev_err(&data->client->dev, "Error writing reg_int_ctrl1\n"); - return ret; - } - - ret = i2c_smbus_read_byte_data(data->client, regs->ctrl1); - if (ret < 0) { - dev_err(&data->client->dev, "Error reading reg_ctrl1\n"); - return ret; - } - - if (status) - ret |= KXCJK1013_REG_CTRL1_BIT_WUFE; - else - ret &= ~KXCJK1013_REG_CTRL1_BIT_WUFE; - - ret = i2c_smbus_write_byte_data(data->client, regs->ctrl1, ret); - if (ret < 0) { - dev_err(&data->client->dev, "Error writing reg_ctrl1\n"); - return ret; - } - - if (store_mode == OPERATION) { - ret = kxcjk1013_set_mode(data, OPERATION); + if (is_new_data == true) { + ret = kxcjk1013_chip_update_thresholds(data); if (ret < 0) return ret; } - return 0; -} - -static int kxcjk1013_setup_new_data_interrupt(struct kxcjk1013_data *data, - bool status) -{ - const struct kx_chipset_regs *regs = data->info->regs; - int ret; - enum kxcjk1013_mode store_mode; - - ret = kxcjk1013_get_mode(data, &store_mode); - if (ret < 0) - return ret; - - /* This is requirement by spec to change state to STANDBY */ - ret = kxcjk1013_set_mode(data, STANDBY); - if (ret < 0) - return ret; - ret = i2c_smbus_read_byte_data(data->client, regs->int_ctrl1); if (ret < 0) { dev_err(&data->client->dev, "Error reading reg_int_ctrl1\n"); @@ -776,10 +719,17 @@ static int kxcjk1013_setup_new_data_interrupt(struct kxcjk1013_data *data, return ret; } - if (status) - ret |= KXCJK1013_REG_CTRL1_BIT_DRDY; - else - ret &= ~KXCJK1013_REG_CTRL1_BIT_DRDY; + if (is_new_data) { + if (status) + ret |= KXCJK1013_REG_CTRL1_BIT_DRDY; + else + ret &= ~KXCJK1013_REG_CTRL1_BIT_DRDY; + } else { + if (status) + ret |= KXCJK1013_REG_CTRL1_BIT_WUFE; + else + ret &= ~KXCJK1013_REG_CTRL1_BIT_WUFE; + } ret = i2c_smbus_write_byte_data(data->client, regs->ctrl1, ret); if (ret < 0) { @@ -1112,7 +1062,7 @@ static int kxcjk1013_write_event_config(struct iio_dev *indio_dev, return ret; } - ret = kxcjk1013_setup_any_motion_interrupt(data, state); + ret = kxcjk1013_setup_interrupt(data, state, false); if (ret < 0) { kxcjk1013_set_power_state(data, false); data->ev_enable_state = 0; @@ -1253,8 +1203,8 @@ static irqreturn_t kxcjk1013_trigger_handler(int irq, void *p) if (ret < 0) goto err; - iio_push_to_buffers_with_timestamp(indio_dev, &data->scan, - data->timestamp); + iio_push_to_buffers_with_ts(indio_dev, &data->scan, sizeof(data->scan), + data->timestamp); err: iio_trigger_notify_done(indio_dev->trig); @@ -1293,10 +1243,7 @@ static int kxcjk1013_data_rdy_trigger_set_state(struct iio_trigger *trig, mutex_unlock(&data->mutex); return ret; } - if (data->motion_trig == trig) - ret = kxcjk1013_setup_any_motion_interrupt(data, state); - else - ret = kxcjk1013_setup_new_data_interrupt(data, state); + ret = kxcjk1013_setup_interrupt(data, state, data->motion_trig != trig); if (ret < 0) { kxcjk1013_set_power_state(data, false); mutex_unlock(&data->mutex); diff --git a/drivers/iio/accel/kxsd9-i2c.c b/drivers/iio/accel/kxsd9-i2c.c index 3857d2edf250..1fa88b99149e 100644 --- a/drivers/iio/accel/kxsd9-i2c.c +++ b/drivers/iio/accel/kxsd9-i2c.c @@ -38,7 +38,7 @@ static void kxsd9_i2c_remove(struct i2c_client *client) static const struct of_device_id kxsd9_of_match[] = { { .compatible = "kionix,kxsd9", }, - { }, + { } }; MODULE_DEVICE_TABLE(of, kxsd9_of_match); diff --git a/drivers/iio/accel/kxsd9-spi.c b/drivers/iio/accel/kxsd9-spi.c index a05f4467d94a..cbb6c6412665 100644 --- a/drivers/iio/accel/kxsd9-spi.c +++ b/drivers/iio/accel/kxsd9-spi.c @@ -38,7 +38,7 @@ static void kxsd9_spi_remove(struct spi_device *spi) static const struct spi_device_id kxsd9_spi_id[] = { {"kxsd9", 0}, - { }, + { } }; MODULE_DEVICE_TABLE(spi, kxsd9_spi_id); diff --git a/drivers/iio/accel/kxsd9.c b/drivers/iio/accel/kxsd9.c index 0ededf8cfdca..cfc31265cdd0 100644 --- a/drivers/iio/accel/kxsd9.c +++ b/drivers/iio/accel/kxsd9.c @@ -229,9 +229,8 @@ static irqreturn_t kxsd9_trigger_handler(int irq, void *p) goto out; } - iio_push_to_buffers_with_timestamp(indio_dev, - &hw_values, - iio_get_time_ns(indio_dev)); + iio_push_to_buffers_with_ts(indio_dev, &hw_values, sizeof(hw_values), + iio_get_time_ns(indio_dev)); out: iio_trigger_notify_done(indio_dev->trig); @@ -273,7 +272,7 @@ kxsd9_get_mount_matrix(const struct iio_dev *indio_dev, static const struct iio_chan_spec_ext_info kxsd9_ext_info[] = { IIO_MOUNT_MATRIX(IIO_SHARED_BY_TYPE, kxsd9_get_mount_matrix), - { }, + { } }; #define KXSD9_ACCEL_CHAN(axis, index) \ diff --git a/drivers/iio/accel/mma7455_core.c b/drivers/iio/accel/mma7455_core.c index 30746621052c..a2b5bdf14dde 100644 --- a/drivers/iio/accel/mma7455_core.c +++ b/drivers/iio/accel/mma7455_core.c @@ -103,8 +103,9 @@ static irqreturn_t mma7455_trigger_handler(int irq, void *p) if (ret) goto done; - iio_push_to_buffers_with_timestamp(indio_dev, &mma7455->scan, - iio_get_time_ns(indio_dev)); + iio_push_to_buffers_with_ts(indio_dev, &mma7455->scan, + sizeof(mma7455->scan), + iio_get_time_ns(indio_dev)); done: iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/accel/mma7660.c b/drivers/iio/accel/mma7660.c index 2894aff80161..d0a16f227903 100644 --- a/drivers/iio/accel/mma7660.c +++ b/drivers/iio/accel/mma7660.c @@ -262,7 +262,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(mma7660_pm_ops, mma7660_suspend, static const struct i2c_device_id mma7660_i2c_id[] = { { "mma7660" }, - {} + { } }; MODULE_DEVICE_TABLE(i2c, mma7660_i2c_id); @@ -274,7 +274,7 @@ MODULE_DEVICE_TABLE(of, mma7660_of_match); static const struct acpi_device_id mma7660_acpi_id[] = { {"MMA7660", 0}, - {} + { } }; MODULE_DEVICE_TABLE(acpi, mma7660_acpi_id); diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c index 05f5482f366e..aba444a980d9 100644 --- a/drivers/iio/accel/mma8452.c +++ b/drivers/iio/accel/mma8452.c @@ -1103,8 +1103,9 @@ static irqreturn_t mma8452_trigger_handler(int irq, void *p) if (ret < 0) goto done; - iio_push_to_buffers_with_timestamp(indio_dev, &data->buffer, - iio_get_time_ns(indio_dev)); + iio_push_to_buffers_with_ts(indio_dev, &data->buffer, + sizeof(data->buffer), + iio_get_time_ns(indio_dev)); done: iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/accel/mma9551.c b/drivers/iio/accel/mma9551.c index 1b96687da01a..b89bad9e6fe6 100644 --- a/drivers/iio/accel/mma9551.c +++ b/drivers/iio/accel/mma9551.c @@ -578,14 +578,14 @@ static const struct dev_pm_ops mma9551_pm_ops = { static const struct acpi_device_id mma9551_acpi_match[] = { {"MMA9551", 0}, - {}, + { } }; MODULE_DEVICE_TABLE(acpi, mma9551_acpi_match); static const struct i2c_device_id mma9551_id[] = { { "mma9551" }, - {} + { } }; MODULE_DEVICE_TABLE(i2c, mma9551_id); diff --git a/drivers/iio/accel/mma9553.c b/drivers/iio/accel/mma9553.c index 00e224efc8ed..1bbe660b254f 100644 --- a/drivers/iio/accel/mma9553.c +++ b/drivers/iio/accel/mma9553.c @@ -919,7 +919,7 @@ static const struct iio_enum mma9553_calibgender_enum = { static const struct iio_chan_spec_ext_info mma9553_ext_info[] = { IIO_ENUM("calibgender", IIO_SHARED_BY_TYPE, &mma9553_calibgender_enum), IIO_ENUM_AVAILABLE("calibgender", IIO_SHARED_BY_TYPE, &mma9553_calibgender_enum), - {}, + { } }; #define MMA9553_PEDOMETER_CHANNEL(_type, _mask) { \ @@ -1216,14 +1216,14 @@ static const struct dev_pm_ops mma9553_pm_ops = { static const struct acpi_device_id mma9553_acpi_match[] = { {"MMA9553", 0}, - {}, + { } }; MODULE_DEVICE_TABLE(acpi, mma9553_acpi_match); static const struct i2c_device_id mma9553_id[] = { { "mma9553" }, - {} + { } }; MODULE_DEVICE_TABLE(i2c, mma9553_id); diff --git a/drivers/iio/accel/msa311.c b/drivers/iio/accel/msa311.c index d31c11fbbe68..c31c53abc3d0 100644 --- a/drivers/iio/accel/msa311.c +++ b/drivers/iio/accel/msa311.c @@ -919,8 +919,8 @@ static irqreturn_t msa311_buffer_thread(int irq, void *p) mutex_unlock(&msa311->lock); - iio_push_to_buffers_with_timestamp(indio_dev, &buf, - iio_get_time_ns(indio_dev)); + iio_push_to_buffers_with_ts(indio_dev, &buf, sizeof(buf), + iio_get_time_ns(indio_dev)); notify_done: iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/accel/mxc4005.c b/drivers/iio/accel/mxc4005.c index cb5c4e354fc0..1075c8ce0e37 100644 --- a/drivers/iio/accel/mxc4005.c +++ b/drivers/iio/accel/mxc4005.c @@ -335,8 +335,8 @@ static irqreturn_t mxc4005_trigger_handler(int irq, void *private) if (ret < 0) goto err; - iio_push_to_buffers_with_timestamp(indio_dev, &data->scan, - pf->timestamp); + iio_push_to_buffers_with_ts(indio_dev, &data->scan, sizeof(data->scan), + pf->timestamp); err: iio_trigger_notify_done(indio_dev->trig); @@ -573,14 +573,14 @@ static const struct acpi_device_id mxc4005_acpi_match[] = { {"MXC4005", 0}, {"MXC6655", 0}, {"MDA6655", 0}, - { }, + { } }; MODULE_DEVICE_TABLE(acpi, mxc4005_acpi_match); static const struct of_device_id mxc4005_of_match[] = { { .compatible = "memsic,mxc4005", }, { .compatible = "memsic,mxc6655", }, - { }, + { } }; MODULE_DEVICE_TABLE(of, mxc4005_of_match); diff --git a/drivers/iio/accel/sca3000.c b/drivers/iio/accel/sca3000.c index 3fb0f386c3db..aabe4491efd7 100644 --- a/drivers/iio/accel/sca3000.c +++ b/drivers/iio/accel/sca3000.c @@ -1541,7 +1541,7 @@ static const struct spi_device_id sca3000_id[] = { {"sca3000_e02", e02}, {"sca3000_e04", e04}, {"sca3000_e05", e05}, - {} + { } }; MODULE_DEVICE_TABLE(spi, sca3000_id); diff --git a/drivers/iio/accel/sca3300.c b/drivers/iio/accel/sca3300.c index ca0ce83e42b2..67416a406e2f 100644 --- a/drivers/iio/accel/sca3300.c +++ b/drivers/iio/accel/sca3300.c @@ -58,15 +58,6 @@ enum sca3300_scan_indexes { SCA3300_SCAN_MAX }; -/* - * Buffer size max case: - * Three accel channels, two bytes per channel. - * Temperature channel, two bytes. - * Three incli channels, two bytes per channel. - * Timestamp channel, eight bytes. - */ -#define SCA3300_MAX_BUFFER_SIZE (ALIGN(sizeof(s16) * SCA3300_SCAN_MAX, sizeof(s64)) + sizeof(s64)) - #define SCA3300_ACCEL_CHANNEL(index, reg, axis) { \ .type = IIO_ACCEL, \ .address = reg, \ @@ -193,9 +184,6 @@ struct sca3300_chip_info { * @spi: SPI device structure * @lock: Data buffer lock * @chip: Sensor chip specific information - * @buffer: Triggered buffer: - * -SCA3300: 4 channel 16-bit data + 64-bit timestamp - * -SCL3300: 7 channel 16-bit data + 64-bit timestamp * @txbuf: Transmit buffer * @rxbuf: Receive buffer */ @@ -203,7 +191,6 @@ struct sca3300_data { struct spi_device *spi; struct mutex lock; const struct sca3300_chip_info *chip; - u8 buffer[SCA3300_MAX_BUFFER_SIZE] __aligned(sizeof(s64)); u8 txbuf[4] __aligned(IIO_DMA_MINALIGN); u8 rxbuf[4]; }; @@ -492,7 +479,7 @@ static irqreturn_t sca3300_trigger_handler(int irq, void *p) struct iio_dev *indio_dev = pf->indio_dev; struct sca3300_data *data = iio_priv(indio_dev); int bit, ret, val, i = 0; - s16 *channels = (s16 *)data->buffer; + IIO_DECLARE_BUFFER_WITH_TS(s16, channels, SCA3300_SCAN_MAX); iio_for_each_active_channel(indio_dev, bit) { ret = sca3300_read_reg(data, indio_dev->channels[bit].address, &val); @@ -505,8 +492,8 @@ static irqreturn_t sca3300_trigger_handler(int irq, void *p) channels[i++] = val; } - iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, - iio_get_time_ns(indio_dev)); + iio_push_to_buffers_with_ts(indio_dev, channels, sizeof(channels), + iio_get_time_ns(indio_dev)); out: iio_trigger_notify_done(indio_dev->trig); @@ -674,14 +661,14 @@ static int sca3300_probe(struct spi_device *spi) static const struct of_device_id sca3300_dt_ids[] = { { .compatible = "murata,sca3300"}, { .compatible = "murata,scl3300"}, - {} + { } }; MODULE_DEVICE_TABLE(of, sca3300_dt_ids); static const struct spi_device_id sca3300_ids[] = { { "sca3300" }, { "scl3300" }, - {} + { } }; MODULE_DEVICE_TABLE(spi, sca3300_ids); diff --git a/drivers/iio/accel/st_accel_i2c.c b/drivers/iio/accel/st_accel_i2c.c index ab4fdba75a0a..f24449500533 100644 --- a/drivers/iio/accel/st_accel_i2c.c +++ b/drivers/iio/accel/st_accel_i2c.c @@ -126,14 +126,14 @@ static const struct of_device_id st_accel_of_match[] = { .compatible = "st,iis328dq", .data = IIS328DQ_ACCEL_DEV_NAME, }, - {}, + { } }; MODULE_DEVICE_TABLE(of, st_accel_of_match); static const struct acpi_device_id st_accel_acpi_match[] = { {"SMO8840", (kernel_ulong_t)LIS2DH12_ACCEL_DEV_NAME}, {"SMO8A90", (kernel_ulong_t)LNG2DM_ACCEL_DEV_NAME}, - { }, + { } }; MODULE_DEVICE_TABLE(acpi, st_accel_acpi_match); @@ -164,7 +164,7 @@ static const struct i2c_device_id st_accel_id_table[] = { { LSM303C_ACCEL_DEV_NAME }, { SC7A20_ACCEL_DEV_NAME }, { IIS328DQ_ACCEL_DEV_NAME }, - {}, + { } }; MODULE_DEVICE_TABLE(i2c, st_accel_id_table); diff --git a/drivers/iio/accel/st_accel_spi.c b/drivers/iio/accel/st_accel_spi.c index 6146754fe47f..d8ec0555f42a 100644 --- a/drivers/iio/accel/st_accel_spi.c +++ b/drivers/iio/accel/st_accel_spi.c @@ -108,7 +108,7 @@ static const struct of_device_id st_accel_of_match[] = { .compatible = "st,iis328dq", .data = IIS328DQ_ACCEL_DEV_NAME, }, - {} + { } }; MODULE_DEVICE_TABLE(of, st_accel_of_match); @@ -167,7 +167,7 @@ static const struct spi_device_id st_accel_id_table[] = { { LIS302DL_ACCEL_DEV_NAME }, { LSM303C_ACCEL_DEV_NAME }, { IIS328DQ_ACCEL_DEV_NAME }, - {}, + { } }; MODULE_DEVICE_TABLE(spi, st_accel_id_table); diff --git a/drivers/iio/accel/stk8312.c b/drivers/iio/accel/stk8312.c index 471c154c3631..dfac2e44191f 100644 --- a/drivers/iio/accel/stk8312.c +++ b/drivers/iio/accel/stk8312.c @@ -460,8 +460,8 @@ static irqreturn_t stk8312_trigger_handler(int irq, void *p) } mutex_unlock(&data->lock); - iio_push_to_buffers_with_timestamp(indio_dev, &data->scan, - pf->timestamp); + iio_push_to_buffers_with_ts(indio_dev, &data->scan, sizeof(data->scan), + pf->timestamp); err: iio_trigger_notify_done(indio_dev->trig); @@ -635,7 +635,7 @@ static const struct i2c_device_id stk8312_i2c_id[] = { /* Deprecated in favour of lowercase form */ { "STK8312" }, { "stk8312" }, - {} + { } }; MODULE_DEVICE_TABLE(i2c, stk8312_i2c_id); diff --git a/drivers/iio/accel/stk8ba50.c b/drivers/iio/accel/stk8ba50.c index cab592a68622..05d4fd540eb2 100644 --- a/drivers/iio/accel/stk8ba50.c +++ b/drivers/iio/accel/stk8ba50.c @@ -340,8 +340,8 @@ static irqreturn_t stk8ba50_trigger_handler(int irq, void *p) data->scan.chans[i++] = ret; } } - iio_push_to_buffers_with_timestamp(indio_dev, &data->scan, - pf->timestamp); + iio_push_to_buffers_with_ts(indio_dev, &data->scan, sizeof(data->scan), + pf->timestamp); err: mutex_unlock(&data->lock); iio_trigger_notify_done(indio_dev->trig); @@ -526,13 +526,13 @@ static DEFINE_SIMPLE_DEV_PM_OPS(stk8ba50_pm_ops, stk8ba50_suspend, static const struct i2c_device_id stk8ba50_i2c_id[] = { { "stk8ba50" }, - {} + { } }; MODULE_DEVICE_TABLE(i2c, stk8ba50_i2c_id); static const struct acpi_device_id stk8ba50_acpi_id[] = { {"STK8BA50", 0}, - {} + { } }; MODULE_DEVICE_TABLE(acpi, stk8ba50_acpi_id); diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 6529df1a498c..ea3ba1397392 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -6,6 +6,9 @@ menu "Analog to digital converters" +config IIO_ADC_HELPER + tristate + config AB8500_GPADC bool "ST-Ericsson AB8500 GPADC driver" depends on AB8500_CORE && REGULATOR_AB8500 @@ -25,10 +28,15 @@ config AD4000 tristate "Analog Devices AD4000 ADC Driver" depends on SPI select IIO_BUFFER + select IIO_BUFFER_DMAENGINE select IIO_TRIGGERED_BUFFER + select SPI_OFFLOAD help Say yes here to build support for Analog Devices AD4000 high speed - SPI analog to digital converters (ADC). + SPI analog to digital converters (ADC). If intended to use with + SPI offloading support, it is recommended to enable + CONFIG_SPI_AXI_SPI_ENGINE, CONFIG_PWM_AXI_PWMGEN, and + CONFIG_SPI_OFFLOAD_TRIGGER_PWM. To compile this driver as a module, choose M here: the module will be called ad4000. @@ -129,8 +137,9 @@ config AD7173 tristate "Analog Devices AD7173 driver" depends on SPI_MASTER select AD_SIGMA_DELTA - select GPIO_REGMAP if GPIOLIB - select REGMAP_SPI if GPIOLIB + select GPIOLIB + select GPIO_REGMAP + select REGMAP_SPI help Say yes here to build support for Analog Devices AD7173 and similar ADC Currently supported models: @@ -281,6 +290,8 @@ config AD7606_IFACE_SPI tristate "Analog Devices AD7606 ADC driver with spi interface support" depends on SPI select AD7606 + select IIO_BUFFER_DMAENGINE + select SPI_OFFLOAD help Say yes here to build spi interface support for Analog Devices: ad7605-4, ad7606, ad7606-6, ad7606-4 analog to digital converters (ADC). @@ -319,6 +330,7 @@ config AD7766 config AD7768_1 tristate "Analog Devices AD7768-1 ADC driver" depends on SPI + select REGMAP_SPI select IIO_BUFFER select IIO_TRIGGER select IIO_TRIGGERED_BUFFER @@ -1092,6 +1104,17 @@ config NAU7802 To compile this driver as a module, choose M here: the module will be called nau7802. +config NCT7201 + tristate "Nuvoton Instruments NCT7201 and NCT7202 Power Monitor" + depends on I2C + select REGMAP_I2C + help + If you say yes here you get support for the Nuvoton NCT7201 and + NCT7202 Voltage Monitor. + + This driver can also be built as a module. If so, the module + will be called nct7201. + config NPCM_ADC tristate "Nuvoton NPCM ADC driver" depends on ARCH_NPCM || COMPILE_TEST @@ -1232,6 +1255,18 @@ config RN5T618_ADC This driver can also be built as a module. If so, the module will be called rn5t618-adc. +config ROHM_BD79124 + tristate "Rohm BD79124 ADC driver" + depends on I2C + select REGMAP_I2C + select IIO_ADC_HELPER + help + Say yes here to build support for the ROHM BD79124 ADC. The + ROHM BD79124 is a 12-bit, 8-channel, SAR ADC. The ADC supports + also an automatic measurement mode, with an alarm interrupt for + out-of-window measurements. The window is configurable for each + channel. + config ROCKCHIP_SARADC tristate "Rockchip SARADC driver" depends on ARCH_ROCKCHIP || COMPILE_TEST @@ -1263,6 +1298,7 @@ config RICHTEK_RTQ6056 config RZG2L_ADC tristate "Renesas RZ/G2L ADC driver" depends on ARCH_RZG2L || COMPILE_TEST + select IIO_ADC_HELPER help Say yes here to build support for the ADC found in Renesas RZ/G2L family. @@ -1397,6 +1433,7 @@ config SUN4I_GPADC config SUN20I_GPADC tristate "Allwinner D1/T113s/T507/R329 and similar GPADCs driver" depends on ARCH_SUNXI || COMPILE_TEST + select IIO_ADC_HELPER help Say yes here to build support for Allwinner (D1, T113, T507 and R329) SoCs GPADC. This ADC provides up to 16 channels. @@ -1440,18 +1477,6 @@ config TI_ADC084S021 This driver can also be built as a module. If so, the module will be called ti-adc084s021. -config TI_ADC12138 - tristate "Texas Instruments ADC12130/ADC12132/ADC12138" - depends on SPI - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - help - If you say yes here you get support for Texas Instruments ADC12130, - ADC12132 and ADC12138 chips. - - This driver can also be built as a module. If so, the module will be - called ti-adc12138. - config TI_ADC108S102 tristate "Texas Instruments ADC108S102 and ADC128S102 driver" depends on SPI @@ -1464,12 +1489,24 @@ config TI_ADC108S102 To compile this driver as a module, choose M here: the module will be called ti-adc108s102. +config TI_ADC12138 + tristate "Texas Instruments ADC12130/ADC12132/ADC12138" + depends on SPI + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + help + If you say yes here you get support for Texas Instruments ADC12130, + ADC12132 and ADC12138 chips. + + This driver can also be built as a module. If so, the module will be + called ti-adc12138. + config TI_ADC128S052 tristate "Texas Instruments ADC128S052/ADC122S021/ADC124S021" depends on SPI help If you say yes here you get support for Texas Instruments ADC128S052, - ADC122S021 and ADC124S021 chips. + ADC122S021, ADC124S021 and ROHM Semiconductor BD79104 chips. This driver can also be built as a module. If so, the module will be called ti-adc128s052. @@ -1499,6 +1536,16 @@ config TI_ADS1015 This driver can also be built as a module. If so, the module will be called ti-ads1015. +config TI_ADS1100 + tristate "Texas Instruments ADS1100 and ADS1000 ADC" + depends on I2C + help + If you say yes here you get support for Texas Instruments ADS1100 and + ADS1000 ADC chips. + + This driver can also be built as a module. If so, the module will be + called ti-ads1100. + config TI_ADS1119 tristate "Texas Instruments ADS1119 ADC" depends on I2C @@ -1511,6 +1558,42 @@ config TI_ADS1119 This driver can also be built as a module. If so, the module will be called ti-ads1119. +config TI_ADS124S08 + tristate "Texas Instruments ADS124S08" + depends on SPI + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + help + If you say yes here you get support for Texas Instruments ADS124S08 + and ADS124S06 ADC chips + + This driver can also be built as a module. If so, the module will be + called ti-ads124s08. + +config TI_ADS1298 + tristate "Texas Instruments ADS1298" + depends on SPI + select IIO_BUFFER + select IIO_KFIFO_BUF + help + If you say yes here you get support for Texas Instruments ADS1298 + medical ADC chips + + This driver can also be built as a module. If so, the module will be + called ti-ads1298. + +config TI_ADS131E08 + tristate "Texas Instruments ADS131E08" + depends on SPI + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + help + Say yes here to get support for Texas Instruments ADS131E04, ADS131E06 + and ADS131E08 chips. + + This driver can also be built as a module. If so, the module will be + called ti-ads131e08. + config TI_ADS7138 tristate "Texas Instruments ADS7128 and ADS7138 ADC driver" depends on I2C @@ -1532,27 +1615,6 @@ config TI_ADS7924 This driver can also be built as a module. If so, the module will be called ti-ads7924. -config TI_ADS1100 - tristate "Texas Instruments ADS1100 and ADS1000 ADC" - depends on I2C - help - If you say yes here you get support for Texas Instruments ADS1100 and - ADS1000 ADC chips. - - This driver can also be built as a module. If so, the module will be - called ti-ads1100. - -config TI_ADS1298 - tristate "Texas Instruments ADS1298" - depends on SPI - select IIO_BUFFER - help - If you say yes here you get support for Texas Instruments ADS1298 - medical ADC chips - - This driver can also be built as a module. If so, the module will be - called ti-ads1298. - config TI_ADS7950 tristate "Texas Instruments ADS7950 ADC driver" depends on SPI && GPIOLIB @@ -1588,30 +1650,6 @@ config TI_ADS8688 This driver can also be built as a module. If so, the module will be called ti-ads8688. -config TI_ADS124S08 - tristate "Texas Instruments ADS124S08" - depends on SPI - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - help - If you say yes here you get support for Texas Instruments ADS124S08 - and ADS124S06 ADC chips - - This driver can also be built as a module. If so, the module will be - called ti-ads124s08. - -config TI_ADS131E08 - tristate "Texas Instruments ADS131E08" - depends on SPI - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - help - Say yes here to get support for Texas Instruments ADS131E04, ADS131E06 - and ADS131E08 chips. - - This driver can also be built as a module. If so, the module will be - called ti-ads131e08. - config TI_AM335X_ADC tristate "TI's AM335X ADC driver" depends on MFD_TI_AM335X_TSCADC && HAS_DMA diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index 3e918c3eec69..09ae6edb2650 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -3,6 +3,8 @@ # Makefile for IIO ADC drivers # +obj-$(CONFIG_IIO_ADC_HELPER) += industrialio-adc.o + # When adding new entries keep the list in alphabetical order obj-$(CONFIG_AB8500_GPADC) += ab8500-gpadc.o obj-$(CONFIG_AD_SIGMA_DELTA) += ad_sigma_delta.o @@ -97,6 +99,7 @@ obj-$(CONFIG_MESON_SARADC) += meson_saradc.o obj-$(CONFIG_MP2629_ADC) += mp2629_adc.o obj-$(CONFIG_MXS_LRADC_ADC) += mxs-lradc-adc.o obj-$(CONFIG_NAU7802) += nau7802.o +obj-$(CONFIG_NCT7201) += nct7201.o obj-$(CONFIG_NPCM_ADC) += npcm_adc.o obj-$(CONFIG_PAC1921) += pac1921.o obj-$(CONFIG_PAC1934) += pac1934.o @@ -110,6 +113,7 @@ obj-$(CONFIG_QCOM_VADC_COMMON) += qcom-vadc-common.o obj-$(CONFIG_RCAR_GYRO_ADC) += rcar-gyroadc.o obj-$(CONFIG_RICHTEK_RTQ6056) += rtq6056.o obj-$(CONFIG_RN5T618_ADC) += rn5t618-adc.o +obj-$(CONFIG_ROHM_BD79124) += rohm-bd79124.o obj-$(CONFIG_ROCKCHIP_SARADC) += rockchip_saradc.o obj-$(CONFIG_RZG2L_ADC) += rzg2l_adc.o obj-$(CONFIG_SC27XX_ADC) += sc27xx_adc.o diff --git a/drivers/iio/adc/ad4000.c b/drivers/iio/adc/ad4000.c index 4fe8dee48da9..5609a7845b6f 100644 --- a/drivers/iio/adc/ad4000.c +++ b/drivers/iio/adc/ad4000.c @@ -15,12 +15,14 @@ #include <linux/mod_devicetable.h> #include <linux/gpio/consumer.h> #include <linux/regulator/consumer.h> +#include <linux/spi/offload/consumer.h> #include <linux/spi/spi.h> #include <linux/units.h> #include <linux/util_macros.h> -#include <linux/iio/iio.h> +#include <linux/iio/iio.h> #include <linux/iio/buffer.h> +#include <linux/iio/buffer-dmaengine.h> #include <linux/iio/triggered_buffer.h> #include <linux/iio/trigger_consumer.h> @@ -32,10 +34,11 @@ /* AD4000 Configuration Register programmable bits */ #define AD4000_CFG_SPAN_COMP BIT(3) /* Input span compression */ #define AD4000_CFG_HIGHZ BIT(2) /* High impedance mode */ +#define AD4000_CFG_TURBO BIT(1) /* Turbo mode */ #define AD4000_SCALE_OPTIONS 2 -#define __AD4000_DIFF_CHANNEL(_sign, _real_bits, _storage_bits, _reg_access) \ +#define __AD4000_DIFF_CHANNEL(_sign, _real_bits, _storage_bits, _reg_access, _offl)\ { \ .type = IIO_VOLTAGE, \ .indexed = 1, \ @@ -43,54 +46,65 @@ .channel = 0, \ .channel2 = 1, \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ - BIT(IIO_CHAN_INFO_SCALE), \ + BIT(IIO_CHAN_INFO_SCALE) | \ + (_offl ? BIT(IIO_CHAN_INFO_SAMP_FREQ) : 0), \ .info_mask_separate_available = _reg_access ? BIT(IIO_CHAN_INFO_SCALE) : 0,\ .scan_index = 0, \ .scan_type = { \ .sign = _sign, \ .realbits = _real_bits, \ .storagebits = _storage_bits, \ - .shift = _storage_bits - _real_bits, \ - .endianness = IIO_BE, \ + .shift = (_offl ? 0 : _storage_bits - _real_bits), \ + .endianness = _offl ? IIO_CPU : IIO_BE \ }, \ } -#define AD4000_DIFF_CHANNEL(_sign, _real_bits, _reg_access) \ +#define AD4000_DIFF_CHANNEL(_sign, _real_bits, _reg_access, _offl) \ __AD4000_DIFF_CHANNEL((_sign), (_real_bits), \ - ((_real_bits) > 16 ? 32 : 16), (_reg_access)) + (((_offl) || ((_real_bits) > 16)) ? 32 : 16), \ + (_reg_access), (_offl)) +/* + * When SPI offload is configured, transfers are executed without CPU + * intervention so no soft timestamp can be recorded when transfers run. + * Because of that, the macros that set timestamp channel are only used when + * transfers are not offloaded. + */ #define AD4000_DIFF_CHANNELS(_sign, _real_bits, _reg_access) \ { \ - AD4000_DIFF_CHANNEL(_sign, _real_bits, _reg_access), \ + AD4000_DIFF_CHANNEL(_sign, _real_bits, _reg_access, 0), \ IIO_CHAN_SOFT_TIMESTAMP(1), \ } -#define __AD4000_PSEUDO_DIFF_CHANNEL(_sign, _real_bits, _storage_bits, _reg_access)\ +#define __AD4000_PSEUDO_DIFF_CHANNEL(_sign, _real_bits, _storage_bits, \ + _reg_access, _offl) \ { \ .type = IIO_VOLTAGE, \ .indexed = 1, \ .channel = 0, \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ BIT(IIO_CHAN_INFO_SCALE) | \ - BIT(IIO_CHAN_INFO_OFFSET), \ + BIT(IIO_CHAN_INFO_OFFSET) | \ + (_offl ? BIT(IIO_CHAN_INFO_SAMP_FREQ) : 0), \ .info_mask_separate_available = _reg_access ? BIT(IIO_CHAN_INFO_SCALE) : 0,\ .scan_index = 0, \ .scan_type = { \ .sign = _sign, \ .realbits = _real_bits, \ .storagebits = _storage_bits, \ - .shift = _storage_bits - _real_bits, \ - .endianness = IIO_BE, \ + .shift = (_offl ? 0 : _storage_bits - _real_bits), \ + .endianness = _offl ? IIO_CPU : IIO_BE \ }, \ } -#define AD4000_PSEUDO_DIFF_CHANNEL(_sign, _real_bits, _reg_access) \ +#define AD4000_PSEUDO_DIFF_CHANNEL(_sign, _real_bits, _reg_access, _offl) \ __AD4000_PSEUDO_DIFF_CHANNEL((_sign), (_real_bits), \ - ((_real_bits) > 16 ? 32 : 16), (_reg_access)) + (((_offl) || ((_real_bits) > 16)) ? 32 : 16),\ + (_reg_access), (_offl)) #define AD4000_PSEUDO_DIFF_CHANNELS(_sign, _real_bits, _reg_access) \ { \ - AD4000_PSEUDO_DIFF_CHANNEL(_sign, _real_bits, _reg_access), \ + AD4000_PSEUDO_DIFF_CHANNEL(_sign, _real_bits, _reg_access, 0), \ IIO_CHAN_SOFT_TIMESTAMP(1), \ } @@ -184,212 +198,298 @@ struct ad4000_chip_info { const char *dev_name; struct iio_chan_spec chan_spec[2]; struct iio_chan_spec reg_access_chan_spec[2]; + struct iio_chan_spec offload_chan_spec; + struct iio_chan_spec reg_access_offload_chan_spec; const struct ad4000_time_spec *time_spec; bool has_hardware_gain; + int max_rate_hz; }; static const struct ad4000_chip_info ad4000_chip_info = { .dev_name = "ad4000", .chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 16, 0), .reg_access_chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 16, 1), + .offload_chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 16, 0, 1), + .reg_access_offload_chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 16, 1, 1), .time_spec = &ad4000_t_spec, + .max_rate_hz = 2 * MEGA, }; static const struct ad4000_chip_info ad4001_chip_info = { .dev_name = "ad4001", .chan_spec = AD4000_DIFF_CHANNELS('s', 16, 0), .reg_access_chan_spec = AD4000_DIFF_CHANNELS('s', 16, 1), + .offload_chan_spec = AD4000_DIFF_CHANNEL('s', 16, 0, 1), + .reg_access_offload_chan_spec = AD4000_DIFF_CHANNEL('s', 16, 1, 1), .time_spec = &ad4000_t_spec, + .max_rate_hz = 2 * MEGA, }; static const struct ad4000_chip_info ad4002_chip_info = { .dev_name = "ad4002", .chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 18, 0), .reg_access_chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 18, 1), + .offload_chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 18, 0, 1), + .reg_access_offload_chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 18, 1, 1), .time_spec = &ad4000_t_spec, + .max_rate_hz = 2 * MEGA, }; static const struct ad4000_chip_info ad4003_chip_info = { .dev_name = "ad4003", .chan_spec = AD4000_DIFF_CHANNELS('s', 18, 0), .reg_access_chan_spec = AD4000_DIFF_CHANNELS('s', 18, 1), + .offload_chan_spec = AD4000_DIFF_CHANNEL('s', 18, 0, 1), + .reg_access_offload_chan_spec = AD4000_DIFF_CHANNEL('s', 18, 1, 1), .time_spec = &ad4000_t_spec, + .max_rate_hz = 2 * MEGA, }; static const struct ad4000_chip_info ad4004_chip_info = { .dev_name = "ad4004", .chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 16, 0), .reg_access_chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 16, 1), + .offload_chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 16, 0, 1), + .reg_access_offload_chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 16, 1, 1), .time_spec = &ad4000_t_spec, + .max_rate_hz = 1 * MEGA, }; static const struct ad4000_chip_info ad4005_chip_info = { .dev_name = "ad4005", .chan_spec = AD4000_DIFF_CHANNELS('s', 16, 0), .reg_access_chan_spec = AD4000_DIFF_CHANNELS('s', 16, 1), + .offload_chan_spec = AD4000_DIFF_CHANNEL('s', 16, 0, 1), + .reg_access_offload_chan_spec = AD4000_DIFF_CHANNEL('s', 16, 1, 1), .time_spec = &ad4000_t_spec, + .max_rate_hz = 1 * MEGA, }; static const struct ad4000_chip_info ad4006_chip_info = { .dev_name = "ad4006", .chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 18, 0), .reg_access_chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 18, 1), + .offload_chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 18, 0, 1), + .reg_access_offload_chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 18, 1, 1), .time_spec = &ad4000_t_spec, + .max_rate_hz = 1 * MEGA, }; static const struct ad4000_chip_info ad4007_chip_info = { .dev_name = "ad4007", .chan_spec = AD4000_DIFF_CHANNELS('s', 18, 0), .reg_access_chan_spec = AD4000_DIFF_CHANNELS('s', 18, 1), + .offload_chan_spec = AD4000_DIFF_CHANNEL('s', 18, 0, 1), + .reg_access_offload_chan_spec = AD4000_DIFF_CHANNEL('s', 18, 1, 1), .time_spec = &ad4000_t_spec, + .max_rate_hz = 1 * MEGA, }; static const struct ad4000_chip_info ad4008_chip_info = { .dev_name = "ad4008", .chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 16, 0), .reg_access_chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 16, 1), + .offload_chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 16, 0, 1), + .reg_access_offload_chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 16, 1, 1), .time_spec = &ad4000_t_spec, + .max_rate_hz = 500 * KILO, }; static const struct ad4000_chip_info ad4010_chip_info = { .dev_name = "ad4010", .chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 18, 0), .reg_access_chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 18, 1), + .offload_chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 18, 0, 1), + .reg_access_offload_chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 18, 1, 1), .time_spec = &ad4000_t_spec, + .max_rate_hz = 500 * KILO, }; static const struct ad4000_chip_info ad4011_chip_info = { .dev_name = "ad4011", .chan_spec = AD4000_DIFF_CHANNELS('s', 18, 0), .reg_access_chan_spec = AD4000_DIFF_CHANNELS('s', 18, 1), + .offload_chan_spec = AD4000_DIFF_CHANNEL('s', 18, 0, 1), + .reg_access_offload_chan_spec = AD4000_DIFF_CHANNEL('s', 18, 1, 1), .time_spec = &ad4000_t_spec, + .max_rate_hz = 500 * KILO, }; static const struct ad4000_chip_info ad4020_chip_info = { .dev_name = "ad4020", .chan_spec = AD4000_DIFF_CHANNELS('s', 20, 0), .reg_access_chan_spec = AD4000_DIFF_CHANNELS('s', 20, 1), + .offload_chan_spec = AD4000_DIFF_CHANNEL('s', 20, 0, 1), + .reg_access_offload_chan_spec = AD4000_DIFF_CHANNEL('s', 20, 1, 1), .time_spec = &ad4020_t_spec, + .max_rate_hz = 1800 * KILO, }; static const struct ad4000_chip_info ad4021_chip_info = { .dev_name = "ad4021", .chan_spec = AD4000_DIFF_CHANNELS('s', 20, 0), .reg_access_chan_spec = AD4000_DIFF_CHANNELS('s', 20, 1), + .offload_chan_spec = AD4000_DIFF_CHANNEL('s', 20, 0, 1), + .reg_access_offload_chan_spec = AD4000_DIFF_CHANNEL('s', 20, 1, 1), .time_spec = &ad4020_t_spec, + .max_rate_hz = 1 * MEGA, }; static const struct ad4000_chip_info ad4022_chip_info = { .dev_name = "ad4022", .chan_spec = AD4000_DIFF_CHANNELS('s', 20, 0), .reg_access_chan_spec = AD4000_DIFF_CHANNELS('s', 20, 1), + .offload_chan_spec = AD4000_DIFF_CHANNEL('s', 20, 0, 1), + .reg_access_offload_chan_spec = AD4000_DIFF_CHANNEL('s', 20, 1, 1), .time_spec = &ad4020_t_spec, + .max_rate_hz = 500 * KILO, }; static const struct ad4000_chip_info adaq4001_chip_info = { .dev_name = "adaq4001", .chan_spec = AD4000_DIFF_CHANNELS('s', 16, 0), .reg_access_chan_spec = AD4000_DIFF_CHANNELS('s', 16, 1), + .offload_chan_spec = AD4000_DIFF_CHANNEL('s', 16, 0, 1), + .reg_access_offload_chan_spec = AD4000_DIFF_CHANNEL('s', 16, 1, 1), .time_spec = &ad4000_t_spec, .has_hardware_gain = true, + .max_rate_hz = 2 * MEGA, }; static const struct ad4000_chip_info adaq4003_chip_info = { .dev_name = "adaq4003", .chan_spec = AD4000_DIFF_CHANNELS('s', 18, 0), .reg_access_chan_spec = AD4000_DIFF_CHANNELS('s', 18, 1), + .offload_chan_spec = AD4000_DIFF_CHANNEL('s', 18, 0, 1), + .reg_access_offload_chan_spec = AD4000_DIFF_CHANNEL('s', 18, 1, 1), .time_spec = &ad4000_t_spec, .has_hardware_gain = true, + .max_rate_hz = 2 * MEGA, }; static const struct ad4000_chip_info ad7685_chip_info = { .dev_name = "ad7685", .chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 16, 0), + .offload_chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 16, 0, 1), .time_spec = &ad7687_t_spec, + .max_rate_hz = 250 * KILO, }; static const struct ad4000_chip_info ad7686_chip_info = { .dev_name = "ad7686", .chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 16, 0), + .offload_chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 16, 0, 1), .time_spec = &ad7686_t_spec, + .max_rate_hz = 500 * KILO, }; static const struct ad4000_chip_info ad7687_chip_info = { .dev_name = "ad7687", .chan_spec = AD4000_DIFF_CHANNELS('s', 16, 0), + .offload_chan_spec = AD4000_DIFF_CHANNEL('s', 16, 0, 1), .time_spec = &ad7687_t_spec, + .max_rate_hz = 250 * KILO, }; static const struct ad4000_chip_info ad7688_chip_info = { .dev_name = "ad7688", .chan_spec = AD4000_DIFF_CHANNELS('s', 16, 0), + .offload_chan_spec = AD4000_DIFF_CHANNEL('s', 16, 0, 1), .time_spec = &ad7686_t_spec, + .max_rate_hz = 500 * KILO, }; static const struct ad4000_chip_info ad7690_chip_info = { .dev_name = "ad7690", .chan_spec = AD4000_DIFF_CHANNELS('s', 18, 0), + .offload_chan_spec = AD4000_DIFF_CHANNEL('s', 18, 0, 1), .time_spec = &ad7690_t_spec, + .max_rate_hz = 400 * KILO, }; static const struct ad4000_chip_info ad7691_chip_info = { .dev_name = "ad7691", .chan_spec = AD4000_DIFF_CHANNELS('s', 18, 0), + .offload_chan_spec = AD4000_DIFF_CHANNEL('s', 18, 0, 1), .time_spec = &ad7691_t_spec, + .max_rate_hz = 250 * KILO, }; static const struct ad4000_chip_info ad7693_chip_info = { .dev_name = "ad7693", .chan_spec = AD4000_DIFF_CHANNELS('s', 16, 0), + .offload_chan_spec = AD4000_DIFF_CHANNEL('s', 16, 0, 1), .time_spec = &ad7686_t_spec, + .max_rate_hz = 500 * KILO, }; static const struct ad4000_chip_info ad7942_chip_info = { .dev_name = "ad7942", .chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 14, 0), + .offload_chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 14, 0, 1), .time_spec = &ad7687_t_spec, + .max_rate_hz = 250 * KILO, }; static const struct ad4000_chip_info ad7946_chip_info = { .dev_name = "ad7946", .chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 14, 0), + .offload_chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 14, 0, 1), .time_spec = &ad7686_t_spec, + .max_rate_hz = 500 * KILO, }; static const struct ad4000_chip_info ad7980_chip_info = { .dev_name = "ad7980", .chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 16, 0), + .offload_chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 16, 0, 1), .time_spec = &ad7980_t_spec, + .max_rate_hz = 1 * MEGA, }; static const struct ad4000_chip_info ad7982_chip_info = { .dev_name = "ad7982", .chan_spec = AD4000_DIFF_CHANNELS('s', 18, 0), + .offload_chan_spec = AD4000_DIFF_CHANNEL('s', 18, 0, 1), .time_spec = &ad7980_t_spec, + .max_rate_hz = 1 * MEGA, }; static const struct ad4000_chip_info ad7983_chip_info = { .dev_name = "ad7983", .chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 16, 0), + .offload_chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 16, 0, 1), .time_spec = &ad7983_t_spec, + .max_rate_hz = 1 * MEGA + 333 * KILO + 333, }; static const struct ad4000_chip_info ad7984_chip_info = { .dev_name = "ad7984", .chan_spec = AD4000_DIFF_CHANNELS('s', 18, 0), + .offload_chan_spec = AD4000_DIFF_CHANNEL('s', 18, 0, 1), .time_spec = &ad7983_t_spec, + .max_rate_hz = 1 * MEGA + 333 * KILO + 333, }; static const struct ad4000_chip_info ad7988_1_chip_info = { .dev_name = "ad7988-1", .chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 16, 0), + .offload_chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 16, 0, 1), .time_spec = &ad7988_1_t_spec, + .max_rate_hz = 100 * KILO, }; static const struct ad4000_chip_info ad7988_5_chip_info = { .dev_name = "ad7988-5", .chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 16, 0), + .offload_chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 16, 0, 1), .time_spec = &ad7686_t_spec, + .max_rate_hz = 500 * KILO, +}; + +static const struct spi_offload_config ad4000_offload_config = { + .capability_flags = SPI_OFFLOAD_CAP_TRIGGER | + SPI_OFFLOAD_CAP_RX_STREAM_DMA, }; struct ad4000_state { @@ -397,6 +497,13 @@ struct ad4000_state { struct gpio_desc *cnv_gpio; struct spi_transfer xfers[2]; struct spi_message msg; + struct spi_transfer offload_xfer; + struct spi_message offload_msg; + struct spi_offload *offload; + struct spi_offload_trigger *offload_trigger; + bool using_offload; + unsigned long offload_trigger_hz; + int max_rate_hz; struct mutex lock; /* Protect read modify write cycle */ int vref_mv; enum ad4000_sdi sdi_pin; @@ -411,8 +518,10 @@ struct ad4000_state { */ struct { union { - __be16 sample_buf16; - __be32 sample_buf32; + __be16 sample_buf16_be; + __be32 sample_buf32_be; + u16 sample_buf16; + u32 sample_buf32; } data; aligned_s64 timestamp; } scan __aligned(IIO_DMA_MINALIGN); @@ -487,6 +596,25 @@ static int ad4000_read_reg(struct ad4000_state *st, unsigned int *val) return ret; } +static int ad4000_set_sampling_freq(struct ad4000_state *st, int freq) +{ + struct spi_offload_trigger_config config = { + .type = SPI_OFFLOAD_TRIGGER_PERIODIC, + .periodic = { + .frequency_hz = freq, + }, + }; + int ret; + + ret = spi_offload_trigger_validate(st->offload_trigger, &config); + if (ret) + return ret; + + st->offload_trigger_hz = config.periodic.frequency_hz; + + return 0; +} + static int ad4000_convert_and_acquire(struct ad4000_state *st) { int ret; @@ -515,10 +643,17 @@ static int ad4000_single_conversion(struct iio_dev *indio_dev, if (ret < 0) return ret; - if (chan->scan_type.storagebits > 16) - sample = be32_to_cpu(st->scan.data.sample_buf32); - else - sample = be16_to_cpu(st->scan.data.sample_buf16); + if (chan->scan_type.endianness == IIO_BE) { + if (chan->scan_type.realbits > 16) + sample = be32_to_cpu(st->scan.data.sample_buf32_be); + else + sample = be16_to_cpu(st->scan.data.sample_buf16_be); + } else { + if (chan->scan_type.realbits > 16) + sample = st->scan.data.sample_buf32; + else + sample = st->scan.data.sample_buf16; + } sample >>= chan->scan_type.shift; @@ -555,6 +690,9 @@ static int ad4000_read_raw(struct iio_dev *indio_dev, *val = mult_frac(st->vref_mv, 1, 10); return IIO_VAL_INT; + case IIO_CHAN_INFO_SAMP_FREQ: + *val = st->offload_trigger_hz; + return IIO_VAL_INT; default: return -EINVAL; } @@ -620,6 +758,7 @@ static int ad4000_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, int val2, long mask) { + struct ad4000_state *st = iio_priv(indio_dev); int ret; switch (mask) { @@ -629,6 +768,15 @@ static int ad4000_write_raw(struct iio_dev *indio_dev, ret = __ad4000_write_raw(indio_dev, chan, val2); iio_device_release_direct(indio_dev); return ret; + case IIO_CHAN_INFO_SAMP_FREQ: + if (val < 1 || val > st->max_rate_hz) + return -EINVAL; + + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; + ret = ad4000_set_sampling_freq(st, val); + iio_device_release_direct(indio_dev); + return ret; default: return -EINVAL; } @@ -645,7 +793,8 @@ static irqreturn_t ad4000_trigger_handler(int irq, void *p) if (ret < 0) goto err_out; - iio_push_to_buffers_with_timestamp(indio_dev, &st->scan, pf->timestamp); + iio_push_to_buffers_with_ts(indio_dev, &st->scan, sizeof(st->scan), + pf->timestamp); err_out: iio_trigger_notify_done(indio_dev->trig); @@ -659,10 +808,114 @@ static const struct iio_info ad4000_reg_access_info = { .write_raw_get_fmt = &ad4000_write_raw_get_fmt, }; +static const struct iio_info ad4000_offload_info = { + .read_raw = &ad4000_read_raw, + .write_raw = &ad4000_write_raw, + .write_raw_get_fmt = &ad4000_write_raw_get_fmt, +}; + static const struct iio_info ad4000_info = { .read_raw = &ad4000_read_raw, }; +static int ad4000_offload_buffer_postenable(struct iio_dev *indio_dev) +{ + struct ad4000_state *st = iio_priv(indio_dev); + struct spi_offload_trigger_config config = { + .type = SPI_OFFLOAD_TRIGGER_PERIODIC, + .periodic = { + .frequency_hz = st->offload_trigger_hz, + }, + }; + + return spi_offload_trigger_enable(st->offload, st->offload_trigger, + &config); +} + +static int ad4000_offload_buffer_predisable(struct iio_dev *indio_dev) +{ + struct ad4000_state *st = iio_priv(indio_dev); + + spi_offload_trigger_disable(st->offload, st->offload_trigger); + + return 0; +} + +static const struct iio_buffer_setup_ops ad4000_offload_buffer_setup_ops = { + .postenable = &ad4000_offload_buffer_postenable, + .predisable = &ad4000_offload_buffer_predisable, +}; + +static int ad4000_spi_offload_setup(struct iio_dev *indio_dev, + struct ad4000_state *st) +{ + struct spi_device *spi = st->spi; + struct device *dev = &spi->dev; + struct dma_chan *rx_dma; + int ret; + + st->offload_trigger = devm_spi_offload_trigger_get(dev, st->offload, + SPI_OFFLOAD_TRIGGER_PERIODIC); + if (IS_ERR(st->offload_trigger)) + return dev_err_probe(dev, PTR_ERR(st->offload_trigger), + "Failed to get offload trigger\n"); + + ret = ad4000_set_sampling_freq(st, st->max_rate_hz); + if (ret) + return dev_err_probe(dev, ret, + "Failed to set sampling frequency\n"); + + rx_dma = devm_spi_offload_rx_stream_request_dma_chan(dev, st->offload); + if (IS_ERR(rx_dma)) + return dev_err_probe(dev, PTR_ERR(rx_dma), + "Failed to get offload RX DMA\n"); + + ret = devm_iio_dmaengine_buffer_setup_with_handle(dev, indio_dev, rx_dma, + IIO_BUFFER_DIRECTION_IN); + if (ret) + return dev_err_probe(dev, ret, "Failed to setup DMA buffer\n"); + + return 0; +} + +/* + * This executes a data sample transfer when using SPI offloading. The device + * connections should be in "3-wire" mode, selected either when the adi,sdi-pin + * device tree property is absent or set to "high". Also, the ADC CNV pin must + * be connected to a SPI controller CS (it can't be connected to a GPIO). + * + * In order to achieve the maximum sample rate, we only do one transfer per + * SPI offload trigger. Because the ADC output has a one sample latency (delay) + * when the device is wired in "3-wire" mode and only one transfer per sample is + * being made in turbo mode, the first data sample is not valid because it + * contains the output of an earlier conversion result. We also set transfer + * `bits_per_word` to achieve higher throughput by using the minimum number of + * SCLK cycles. Also, a delay is added to make sure we meet the minimum quiet + * time before releasing the CS line. + * + * Note that, with `bits_per_word` set to the number of ADC precision bits, + * transfers use larger word sizes that get stored in 'in-memory wordsizes' that + * are always in native CPU byte order. Because of that, IIO buffer elements + * ought to be read in CPU endianness which requires setting IIO scan_type + * endianness accordingly (i.e. IIO_CPU). + */ +static int ad4000_prepare_offload_message(struct ad4000_state *st, + const struct iio_chan_spec *chan) +{ + struct spi_transfer *xfer = &st->offload_xfer; + + xfer->bits_per_word = chan->scan_type.realbits; + xfer->len = chan->scan_type.realbits > 16 ? 4 : 2; + xfer->delay.value = st->time_spec->t_quiet2_ns; + xfer->delay.unit = SPI_DELAY_UNIT_NSECS; + xfer->offload_flags = SPI_OFFLOAD_XFER_RX_STREAM; + + spi_message_init_with_transfers(&st->offload_msg, xfer, 1); + st->offload_msg.offload = st->offload; + + return devm_spi_optimize_message(&st->spi->dev, st->spi, &st->offload_msg); +} + /* * This executes a data sample transfer for when the device connections are * in "3-wire" mode, selected when the adi,sdi-pin device tree property is @@ -689,7 +942,16 @@ static int ad4000_prepare_3wire_mode_message(struct ad4000_state *st, xfers[0].cs_change_delay.unit = SPI_DELAY_UNIT_NSECS; xfers[1].rx_buf = &st->scan.data; - xfers[1].len = BITS_TO_BYTES(chan->scan_type.storagebits); + xfers[1].len = chan->scan_type.realbits > 16 ? 4 : 2; + + /* + * If the device is set up for SPI offloading, IIO channel scan_type is + * set to IIO_CPU. When that is the case, use larger SPI word sizes for + * single-shot reads too. Thus, sample data can be correctly handled in + * ad4000_single_conversion() according to scan_type endianness. + */ + if (chan->scan_type.endianness != IIO_BE) + xfers[1].bits_per_word = chan->scan_type.realbits; xfers[1].delay.value = st->time_spec->t_quiet2_ns; xfers[1].delay.unit = SPI_DELAY_UNIT_NSECS; @@ -733,6 +995,9 @@ static int ad4000_config(struct ad4000_state *st) if (device_property_present(&st->spi->dev, "adi,high-z-input")) reg_val |= FIELD_PREP(AD4000_CFG_HIGHZ, 1); + if (st->using_offload) + reg_val |= FIELD_PREP(AD4000_CFG_TURBO, 1); + return ad4000_write_reg(st, reg_val); } @@ -755,6 +1020,7 @@ static int ad4000_probe(struct spi_device *spi) st = iio_priv(indio_dev); st->spi = spi; st->time_spec = chip->time_spec; + st->max_rate_hz = chip->max_rate_hz; ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(ad4000_power_supplies), ad4000_power_supplies); @@ -772,6 +1038,26 @@ static int ad4000_probe(struct spi_device *spi) return dev_err_probe(dev, PTR_ERR(st->cnv_gpio), "Failed to get CNV GPIO"); + st->offload = devm_spi_offload_get(dev, spi, &ad4000_offload_config); + ret = PTR_ERR_OR_ZERO(st->offload); + if (ret && ret != -ENODEV) + return dev_err_probe(dev, ret, "Failed to get offload\n"); + + st->using_offload = !IS_ERR(st->offload); + if (st->using_offload) { + indio_dev->setup_ops = &ad4000_offload_buffer_setup_ops; + ret = ad4000_spi_offload_setup(indio_dev, st); + if (ret) + return ret; + } else { + ret = devm_iio_triggered_buffer_setup(dev, indio_dev, + &iio_pollfunc_store_time, + &ad4000_trigger_handler, + NULL); + if (ret) + return ret; + } + ret = device_property_match_property_string(dev, "adi,sdi-pin", ad4000_sdi_pin, ARRAY_SIZE(ad4000_sdi_pin)); @@ -784,7 +1070,6 @@ static int ad4000_probe(struct spi_device *spi) switch (st->sdi_pin) { case AD4000_SDI_MOSI: indio_dev->info = &ad4000_reg_access_info; - indio_dev->channels = chip->reg_access_chan_spec; /* * In "3-wire mode", the ADC SDI line must be kept high when @@ -796,9 +1081,26 @@ static int ad4000_probe(struct spi_device *spi) if (ret < 0) return ret; + if (st->using_offload) { + indio_dev->channels = &chip->reg_access_offload_chan_spec; + indio_dev->num_channels = 1; + ret = ad4000_prepare_offload_message(st, indio_dev->channels); + if (ret) + return dev_err_probe(dev, ret, + "Failed to optimize SPI msg\n"); + } else { + indio_dev->channels = chip->reg_access_chan_spec; + indio_dev->num_channels = ARRAY_SIZE(chip->reg_access_chan_spec); + } + + /* + * Call ad4000_prepare_3wire_mode_message() so single-shot read + * SPI messages are always initialized. + */ ret = ad4000_prepare_3wire_mode_message(st, &indio_dev->channels[0]); if (ret) - return ret; + return dev_err_probe(dev, ret, + "Failed to optimize SPI msg\n"); ret = ad4000_config(st); if (ret < 0) @@ -806,19 +1108,38 @@ static int ad4000_probe(struct spi_device *spi) break; case AD4000_SDI_VIO: - indio_dev->info = &ad4000_info; - indio_dev->channels = chip->chan_spec; + if (st->using_offload) { + indio_dev->info = &ad4000_offload_info; + indio_dev->channels = &chip->offload_chan_spec; + indio_dev->num_channels = 1; + + ret = ad4000_prepare_offload_message(st, indio_dev->channels); + if (ret) + return dev_err_probe(dev, ret, + "Failed to optimize SPI msg\n"); + } else { + indio_dev->info = &ad4000_info; + indio_dev->channels = chip->chan_spec; + indio_dev->num_channels = ARRAY_SIZE(chip->chan_spec); + } + ret = ad4000_prepare_3wire_mode_message(st, &indio_dev->channels[0]); if (ret) - return ret; + return dev_err_probe(dev, ret, + "Failed to optimize SPI msg\n"); break; case AD4000_SDI_CS: + if (st->using_offload) + return dev_err_probe(dev, -EPROTONOSUPPORT, + "Unsupported sdi-pin + offload config\n"); indio_dev->info = &ad4000_info; indio_dev->channels = chip->chan_spec; + indio_dev->num_channels = ARRAY_SIZE(chip->chan_spec); ret = ad4000_prepare_4wire_mode_message(st, &indio_dev->channels[0]); if (ret) - return ret; + return dev_err_probe(dev, ret, + "Failed to optimize SPI msg\n"); break; case AD4000_SDI_GND: @@ -830,7 +1151,6 @@ static int ad4000_probe(struct spi_device *spi) } indio_dev->name = chip->dev_name; - indio_dev->num_channels = 2; ret = devm_mutex_init(dev, &st->lock); if (ret) @@ -853,12 +1173,6 @@ static int ad4000_probe(struct spi_device *spi) ad4000_fill_scale_tbl(st, &indio_dev->channels[0]); - ret = devm_iio_triggered_buffer_setup(dev, indio_dev, - &iio_pollfunc_store_time, - &ad4000_trigger_handler, NULL); - if (ret) - return ret; - return devm_iio_device_register(dev, indio_dev); } @@ -947,3 +1261,4 @@ module_spi_driver(ad4000_driver); MODULE_AUTHOR("Marcelo Schmitt <marcelo.schmitt@analog.com>"); MODULE_DESCRIPTION("Analog Devices AD4000 ADC driver"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("IIO_DMAENGINE_BUFFER"); diff --git a/drivers/iio/adc/ad4030.c b/drivers/iio/adc/ad4030.c index 9a020680885d..1bc2f9a22470 100644 --- a/drivers/iio/adc/ad4030.c +++ b/drivers/iio/adc/ad4030.c @@ -147,7 +147,6 @@ struct ad4030_state { struct spi_device *spi; struct regmap *regmap; const struct ad4030_chip_info *chip; - const struct iio_scan_type *current_scan_type; struct gpio_desc *cnv_gpio; int vref_uv; int vio_uv; @@ -245,7 +244,6 @@ static int ad4030_enter_config_mode(struct ad4030_state *st) struct spi_transfer xfer = { .tx_buf = st->tx_data, - .bits_per_word = 8, .len = 1, .speed_hz = AD4030_SPI_MAX_REG_XFER_SPEED, }; @@ -261,7 +259,6 @@ static int ad4030_exit_config_mode(struct ad4030_state *st) struct spi_transfer xfer = { .tx_buf = st->tx_data, - .bits_per_word = 8, .len = 3, .speed_hz = AD4030_SPI_MAX_REG_XFER_SPEED, }; @@ -277,7 +274,6 @@ static int ad4030_spi_read(void *context, const void *reg, size_t reg_size, struct spi_transfer xfer = { .tx_buf = st->tx_data, .rx_buf = st->rx_data.raw, - .bits_per_word = 8, .len = reg_size + val_size, .speed_hz = AD4030_SPI_MAX_REG_XFER_SPEED, }; @@ -312,7 +308,6 @@ static int ad4030_spi_write(void *context, const void *data, size_t count) ((u8 *)data)[2] == 0x81; struct spi_transfer xfer = { .tx_buf = st->tx_data, - .bits_per_word = 8, .len = count, .speed_hz = AD4030_SPI_MAX_REG_XFER_SPEED, }; @@ -390,16 +385,17 @@ static int ad4030_get_chan_scale(struct iio_dev *indio_dev, struct ad4030_state *st = iio_priv(indio_dev); const struct iio_scan_type *scan_type; - if (chan->differential) { - scan_type = iio_get_current_scan_type(indio_dev, - st->chip->channels); + scan_type = iio_get_current_scan_type(indio_dev, st->chip->channels); + if (IS_ERR(scan_type)) + return PTR_ERR(scan_type); + + if (chan->differential) *val = (st->vref_uv * 2) / MILLI; - *val2 = scan_type->realbits; - return IIO_VAL_FRACTIONAL_LOG2; - } + else + *val = st->vref_uv / MILLI; + + *val2 = scan_type->realbits; - *val = st->vref_uv / MILLI; - *val2 = chan->scan_type.realbits; return IIO_VAL_FRACTIONAL_LOG2; } @@ -561,11 +557,6 @@ static int ad4030_set_mode(struct iio_dev *indio_dev, unsigned long mask) st->mode = AD4030_OUT_DATA_MD_DIFF; } - st->current_scan_type = iio_get_current_scan_type(indio_dev, - st->chip->channels); - if (IS_ERR(st->current_scan_type)) - return PTR_ERR(st->current_scan_type); - return regmap_update_bits(st->regmap, AD4030_REG_MODES, AD4030_REG_MODES_MASK_OUT_DATA_MODE, st->mode); @@ -613,15 +604,20 @@ static void ad4030_extract_interleaved(u8 *src, u32 *ch0, u32 *ch1) static int ad4030_conversion(struct iio_dev *indio_dev) { struct ad4030_state *st = iio_priv(indio_dev); - unsigned char diff_realbytes = - BITS_TO_BYTES(st->current_scan_type->realbits); - unsigned char diff_storagebytes = - BITS_TO_BYTES(st->current_scan_type->storagebits); + const struct iio_scan_type *scan_type; + unsigned char diff_realbytes, diff_storagebytes; unsigned int bytes_to_read; unsigned long cnv_nb = BIT(st->avg_log2); unsigned int i; int ret; + scan_type = iio_get_current_scan_type(indio_dev, st->chip->channels); + if (IS_ERR(scan_type)) + return PTR_ERR(scan_type); + + diff_realbytes = BITS_TO_BYTES(scan_type->realbits); + diff_storagebytes = BITS_TO_BYTES(scan_type->storagebits); + /* Number of bytes for one differential channel */ bytes_to_read = diff_realbytes; /* Add one byte if we are using a differential + common byte mode */ @@ -646,6 +642,12 @@ static int ad4030_conversion(struct iio_dev *indio_dev) &st->rx_data.dual.diff[0], &st->rx_data.dual.diff[1]); + /* + * If no common mode voltage channel is enabled, we can use the raw + * data as is. Otherwise, we need to rearrange the data a bit to match + * the natural alignment of the IIO buffer. + */ + if (st->mode != AD4030_OUT_DATA_MD_16_DIFF_8_COM && st->mode != AD4030_OUT_DATA_MD_24_DIFF_8_COM) return 0; @@ -672,11 +674,6 @@ static int ad4030_single_conversion(struct iio_dev *indio_dev, if (ret) return ret; - st->current_scan_type = iio_get_current_scan_type(indio_dev, - st->chip->channels); - if (IS_ERR(st->current_scan_type)) - return PTR_ERR(st->current_scan_type); - ret = ad4030_conversion(indio_dev); if (ret) return ret; @@ -706,8 +703,8 @@ static irqreturn_t ad4030_trigger_handler(int irq, void *p) if (ret) goto out; - iio_push_to_buffers_with_timestamp(indio_dev, st->rx_data.raw, - pf->timestamp); + iio_push_to_buffers_with_ts(indio_dev, &st->rx_data, sizeof(st->rx_data), + pf->timestamp); out: iio_trigger_notify_done(indio_dev->trig); @@ -867,6 +864,12 @@ static int ad4030_get_current_scan_type(const struct iio_dev *indio_dev, return st->avg_log2 ? AD4030_SCAN_TYPE_AVG : AD4030_SCAN_TYPE_NORMAL; } +static int ad4030_update_scan_mode(struct iio_dev *indio_dev, + const unsigned long *scan_mask) +{ + return ad4030_set_mode(indio_dev, *scan_mask); +} + static const struct iio_info ad4030_iio_info = { .read_avail = ad4030_read_avail, .read_raw = ad4030_read_raw, @@ -874,13 +877,9 @@ static const struct iio_info ad4030_iio_info = { .debugfs_reg_access = ad4030_reg_access, .read_label = ad4030_read_label, .get_current_scan_type = ad4030_get_current_scan_type, + .update_scan_mode = ad4030_update_scan_mode, }; -static int ad4030_buffer_preenable(struct iio_dev *indio_dev) -{ - return ad4030_set_mode(indio_dev, *indio_dev->active_scan_mask); -} - static bool ad4030_validate_scan_mask(struct iio_dev *indio_dev, const unsigned long *scan_mask) { @@ -894,7 +893,6 @@ static bool ad4030_validate_scan_mask(struct iio_dev *indio_dev, } static const struct iio_buffer_setup_ops ad4030_buffer_setup_ops = { - .preenable = ad4030_buffer_preenable, .validate_scan_mask = ad4030_validate_scan_mask, }; diff --git a/drivers/iio/adc/ad4130.c b/drivers/iio/adc/ad4130.c index 0f4c9cd6c102..6cf790ff3eb5 100644 --- a/drivers/iio/adc/ad4130.c +++ b/drivers/iio/adc/ad4130.c @@ -522,15 +522,15 @@ static int ad4130_gpio_get_direction(struct gpio_chip *gc, unsigned int offset) return GPIO_LINE_DIRECTION_OUT; } -static void ad4130_gpio_set(struct gpio_chip *gc, unsigned int offset, - int value) +static int ad4130_gpio_set(struct gpio_chip *gc, unsigned int offset, + int value) { struct ad4130_state *st = gpiochip_get_data(gc); unsigned int mask = FIELD_PREP(AD4130_IO_CONTROL_GPIO_DATA_MASK, BIT(offset)); - regmap_update_bits(st->regmap, AD4130_IO_CONTROL_REG, mask, - value ? mask : 0); + return regmap_update_bits(st->regmap, AD4130_IO_CONTROL_REG, mask, + value ? mask : 0); } static int ad4130_set_mode(struct ad4130_state *st, enum ad4130_mode mode) @@ -2064,7 +2064,7 @@ static int ad4130_probe(struct spi_device *spi) st->gc.can_sleep = true; st->gc.init_valid_mask = ad4130_gpio_init_valid_mask; st->gc.get_direction = ad4130_gpio_get_direction; - st->gc.set = ad4130_gpio_set; + st->gc.set_rv = ad4130_gpio_set; ret = devm_gpiochip_add_data(dev, &st->gc, st); if (ret) diff --git a/drivers/iio/adc/ad4695.c b/drivers/iio/adc/ad4695.c index 8222c8ab2940..cda419638d9a 100644 --- a/drivers/iio/adc/ad4695.c +++ b/drivers/iio/adc/ad4695.c @@ -105,9 +105,7 @@ #define AD4695_REG_ACCESS_SCLK_HZ (10 * MEGA) /* Max number of voltage input channels. */ -#define AD4695_MAX_CHANNELS 16 -/* Max size of 1 raw sample in bytes. */ -#define AD4695_MAX_CHANNEL_SIZE 2 +#define AD4695_MAX_VIN_CHANNELS 16 enum ad4695_in_pair { AD4695_IN_PAIR_REFGND, @@ -145,8 +143,8 @@ struct ad4695_state { /* offload also requires separate gpio to manually control CNV */ struct gpio_desc *cnv_gpio; /* voltages channels plus temperature and timestamp */ - struct iio_chan_spec iio_chan[AD4695_MAX_CHANNELS + 2]; - struct ad4695_channel_config channels_cfg[AD4695_MAX_CHANNELS]; + struct iio_chan_spec iio_chan[AD4695_MAX_VIN_CHANNELS + 2]; + struct ad4695_channel_config channels_cfg[AD4695_MAX_VIN_CHANNELS]; const struct ad4695_chip_info *chip_info; int sample_freq_range[3]; /* Reference voltage. */ @@ -159,11 +157,10 @@ struct ad4695_state { * to control CS and add a delay between the last SCLK and next * CNV rising edges. */ - struct spi_transfer buf_read_xfer[AD4695_MAX_CHANNELS * 2 + 3]; + struct spi_transfer buf_read_xfer[AD4695_MAX_VIN_CHANNELS * 2 + 3]; struct spi_message buf_read_msg; /* Raw conversion data received. */ - u8 buf[ALIGN((AD4695_MAX_CHANNELS + 2) * AD4695_MAX_CHANNEL_SIZE, - sizeof(s64)) + sizeof(s64)] __aligned(IIO_DMA_MINALIGN); + IIO_DECLARE_DMA_BUFFER_WITH_TS(u16, buf, AD4695_MAX_VIN_CHANNELS + 1); u16 raw_data; /* Commands to send for single conversion. */ u16 cnv_cmd; @@ -660,9 +657,8 @@ static int ad4695_buffer_preenable(struct iio_dev *indio_dev) iio_for_each_active_channel(indio_dev, bit) { xfer = &st->buf_read_xfer[num_xfer]; xfer->bits_per_word = 16; - xfer->rx_buf = &st->buf[rx_buf_offset]; + xfer->rx_buf = &st->buf[rx_buf_offset++]; xfer->len = 2; - rx_buf_offset += xfer->len; if (bit == temp_chan_bit) { temp_en = 1; @@ -801,7 +797,8 @@ static irqreturn_t ad4695_trigger_handler(int irq, void *p) if (ret) goto out; - iio_push_to_buffers_with_timestamp(indio_dev, st->buf, pf->timestamp); + iio_push_to_buffers_with_ts(indio_dev, st->buf, sizeof(st->buf), + pf->timestamp); out: iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/adc/ad4851.c b/drivers/iio/adc/ad4851.c index 98ebc853db79..f1d2e2896f2a 100644 --- a/drivers/iio/adc/ad4851.c +++ b/drivers/iio/adc/ad4851.c @@ -1034,7 +1034,7 @@ static int ad4858_parse_channels(struct iio_dev *indio_dev) struct device *dev = &st->spi->dev; struct iio_chan_spec *ad4851_channels; const struct iio_chan_spec ad4851_chan = AD4858_IIO_CHANNEL; - int ret; + int ret, i = 0; ret = ad4851_parse_channels_common(indio_dev, &ad4851_channels, ad4851_chan); @@ -1042,15 +1042,15 @@ static int ad4858_parse_channels(struct iio_dev *indio_dev) return ret; device_for_each_child_node_scoped(dev, child) { - ad4851_channels->has_ext_scan_type = 1; + ad4851_channels[i].has_ext_scan_type = 1; if (fwnode_property_read_bool(child, "bipolar")) { - ad4851_channels->ext_scan_type = ad4851_scan_type_20_b; - ad4851_channels->num_ext_scan_type = ARRAY_SIZE(ad4851_scan_type_20_b); + ad4851_channels[i].ext_scan_type = ad4851_scan_type_20_b; + ad4851_channels[i].num_ext_scan_type = ARRAY_SIZE(ad4851_scan_type_20_b); } else { - ad4851_channels->ext_scan_type = ad4851_scan_type_20_u; - ad4851_channels->num_ext_scan_type = ARRAY_SIZE(ad4851_scan_type_20_u); + ad4851_channels[i].ext_scan_type = ad4851_scan_type_20_u; + ad4851_channels[i].num_ext_scan_type = ARRAY_SIZE(ad4851_scan_type_20_u); } - ad4851_channels++; + i++; } indio_dev->channels = ad4851_channels; diff --git a/drivers/iio/adc/ad7091r-base.c b/drivers/iio/adc/ad7091r-base.c index 931ff71b2888..647a7852dd8d 100644 --- a/drivers/iio/adc/ad7091r-base.c +++ b/drivers/iio/adc/ad7091r-base.c @@ -387,13 +387,8 @@ EXPORT_SYMBOL_NS_GPL(ad7091r_writeable_reg, "IIO_AD7091R"); bool ad7091r_volatile_reg(struct device *dev, unsigned int reg) { - switch (reg) { - case AD7091R_REG_RESULT: - case AD7091R_REG_ALERT: - return true; - default: - return false; - } + /* The volatile ad7091r registers are also the only RO ones. */ + return !ad7091r_writeable_reg(dev, reg); } EXPORT_SYMBOL_NS_GPL(ad7091r_volatile_reg, "IIO_AD7091R"); diff --git a/drivers/iio/adc/ad7124.c b/drivers/iio/adc/ad7124.c index 3ea81a98e455..92596f15e797 100644 --- a/drivers/iio/adc/ad7124.c +++ b/drivers/iio/adc/ad7124.c @@ -32,7 +32,7 @@ #define AD7124_IO_CONTROL_2 0x04 #define AD7124_ID 0x05 #define AD7124_ERROR 0x06 -#define AD7124_ERROR_EN 0x07 +#define AD7124_ERROR_EN 0x07 #define AD7124_MCLK_COUNT 0x08 #define AD7124_CHANNEL(x) (0x09 + (x)) #define AD7124_CONFIG(x) (0x19 + (x)) @@ -41,68 +41,58 @@ #define AD7124_GAIN(x) (0x31 + (x)) /* AD7124_STATUS */ -#define AD7124_STATUS_POR_FLAG_MSK BIT(4) +#define AD7124_STATUS_POR_FLAG BIT(4) /* AD7124_ADC_CONTROL */ -#define AD7124_ADC_STATUS_EN_MSK BIT(10) -#define AD7124_ADC_STATUS_EN(x) FIELD_PREP(AD7124_ADC_STATUS_EN_MSK, x) -#define AD7124_ADC_CTRL_REF_EN_MSK BIT(8) -#define AD7124_ADC_CTRL_REF_EN(x) FIELD_PREP(AD7124_ADC_CTRL_REF_EN_MSK, x) -#define AD7124_ADC_CTRL_PWR_MSK GENMASK(7, 6) -#define AD7124_ADC_CTRL_PWR(x) FIELD_PREP(AD7124_ADC_CTRL_PWR_MSK, x) -#define AD7124_ADC_CTRL_MODE_MSK GENMASK(5, 2) -#define AD7124_ADC_CTRL_MODE(x) FIELD_PREP(AD7124_ADC_CTRL_MODE_MSK, x) - -#define AD7124_MODE_CAL_INT_ZERO 0x5 /* Internal Zero-Scale Calibration */ -#define AD7124_MODE_CAL_INT_FULL 0x6 /* Internal Full-Scale Calibration */ -#define AD7124_MODE_CAL_SYS_ZERO 0x7 /* System Zero-Scale Calibration */ -#define AD7124_MODE_CAL_SYS_FULL 0x8 /* System Full-Scale Calibration */ - -/* AD7124 ID */ -#define AD7124_DEVICE_ID_MSK GENMASK(7, 4) -#define AD7124_DEVICE_ID_GET(x) FIELD_GET(AD7124_DEVICE_ID_MSK, x) -#define AD7124_SILICON_REV_MSK GENMASK(3, 0) -#define AD7124_SILICON_REV_GET(x) FIELD_GET(AD7124_SILICON_REV_MSK, x) - -#define CHIPID_AD7124_4 0x0 -#define CHIPID_AD7124_8 0x1 +#define AD7124_ADC_CONTROL_MODE GENMASK(5, 2) +#define AD7124_ADC_CONTROL_MODE_CONTINUOUS 0 +#define AD7124_ADC_CONTROL_MODE_SINGLE 1 +#define AD7124_ADC_CONTROL_MODE_STANDBY 2 +#define AD7124_ADC_CONTROL_MODE_POWERDOWN 3 +#define AD7124_ADC_CONTROL_MODE_IDLE 4 +#define AD7124_ADC_CONTROL_MODE_INT_OFFSET_CALIB 5 /* Internal Zero-Scale Calibration */ +#define AD7124_ADC_CONTROL_MODE_INT_GAIN_CALIB 6 /* Internal Full-Scale Calibration */ +#define AD7124_ADC_CONTROL_MODE_SYS_OFFSET_CALIB 7 /* System Zero-Scale Calibration */ +#define AD7124_ADC_CONTROL_MODE_SYS_GAIN_CALIB 8 /* System Full-Scale Calibration */ +#define AD7124_ADC_CONTROL_POWER_MODE GENMASK(7, 6) +#define AD7124_ADC_CONTROL_POWER_MODE_LOW 0 +#define AD7124_ADC_CONTROL_POWER_MODE_MID 1 +#define AD7124_ADC_CONTROL_POWER_MODE_FULL 2 +#define AD7124_ADC_CONTROL_REF_EN BIT(8) +#define AD7124_ADC_CONTROL_DATA_STATUS BIT(10) + +/* AD7124_ID */ +#define AD7124_ID_SILICON_REVISION GENMASK(3, 0) +#define AD7124_ID_DEVICE_ID GENMASK(7, 4) +#define AD7124_ID_DEVICE_ID_AD7124_4 0x0 +#define AD7124_ID_DEVICE_ID_AD7124_8 0x1 /* AD7124_CHANNEL_X */ -#define AD7124_CHANNEL_EN_MSK BIT(15) -#define AD7124_CHANNEL_EN(x) FIELD_PREP(AD7124_CHANNEL_EN_MSK, x) -#define AD7124_CHANNEL_SETUP_MSK GENMASK(14, 12) -#define AD7124_CHANNEL_SETUP(x) FIELD_PREP(AD7124_CHANNEL_SETUP_MSK, x) -#define AD7124_CHANNEL_AINP_MSK GENMASK(9, 5) -#define AD7124_CHANNEL_AINP(x) FIELD_PREP(AD7124_CHANNEL_AINP_MSK, x) -#define AD7124_CHANNEL_AINM_MSK GENMASK(4, 0) -#define AD7124_CHANNEL_AINM(x) FIELD_PREP(AD7124_CHANNEL_AINM_MSK, x) +#define AD7124_CHANNEL_ENABLE BIT(15) +#define AD7124_CHANNEL_SETUP GENMASK(14, 12) +#define AD7124_CHANNEL_AINP GENMASK(9, 5) +#define AD7124_CHANNEL_AINM GENMASK(4, 0) +#define AD7124_CHANNEL_AINx_TEMPSENSOR 16 +#define AD7124_CHANNEL_AINx_AVSS 17 /* AD7124_CONFIG_X */ -#define AD7124_CONFIG_BIPOLAR_MSK BIT(11) -#define AD7124_CONFIG_BIPOLAR(x) FIELD_PREP(AD7124_CONFIG_BIPOLAR_MSK, x) -#define AD7124_CONFIG_REF_SEL_MSK GENMASK(4, 3) -#define AD7124_CONFIG_REF_SEL(x) FIELD_PREP(AD7124_CONFIG_REF_SEL_MSK, x) -#define AD7124_CONFIG_PGA_MSK GENMASK(2, 0) -#define AD7124_CONFIG_PGA(x) FIELD_PREP(AD7124_CONFIG_PGA_MSK, x) -#define AD7124_CONFIG_IN_BUFF_MSK GENMASK(6, 5) -#define AD7124_CONFIG_IN_BUFF(x) FIELD_PREP(AD7124_CONFIG_IN_BUFF_MSK, x) +#define AD7124_CONFIG_BIPOLAR BIT(11) +#define AD7124_CONFIG_IN_BUFF GENMASK(6, 5) +#define AD7124_CONFIG_AIN_BUFP BIT(6) +#define AD7124_CONFIG_AIN_BUFM BIT(5) +#define AD7124_CONFIG_REF_SEL GENMASK(4, 3) +#define AD7124_CONFIG_PGA GENMASK(2, 0) /* AD7124_FILTER_X */ -#define AD7124_FILTER_FS_MSK GENMASK(10, 0) -#define AD7124_FILTER_FS(x) FIELD_PREP(AD7124_FILTER_FS_MSK, x) -#define AD7124_FILTER_TYPE_MSK GENMASK(23, 21) -#define AD7124_FILTER_TYPE_SEL(x) FIELD_PREP(AD7124_FILTER_TYPE_MSK, x) +#define AD7124_FILTER_FS GENMASK(10, 0) +#define AD7124_FILTER_FILTER GENMASK(23, 21) +#define AD7124_FILTER_FILTER_SINC4 0 +#define AD7124_FILTER_FILTER_SINC3 2 -#define AD7124_SINC3_FILTER 2 -#define AD7124_SINC4_FILTER 0 - -#define AD7124_CONF_ADDR_OFFSET 20 #define AD7124_MAX_CONFIGS 8 #define AD7124_MAX_CHANNELS 16 /* AD7124 input sources */ -#define AD7124_INPUT_TEMPSENSOR 16 -#define AD7124_INPUT_AVSS 17 enum ad7124_ids { ID_AD7124_4, @@ -206,12 +196,12 @@ struct ad7124_state { static struct ad7124_chip_info ad7124_chip_info_tbl[] = { [ID_AD7124_4] = { .name = "ad7124-4", - .chip_id = CHIPID_AD7124_4, + .chip_id = AD7124_ID_DEVICE_ID_AD7124_4, .num_inputs = 8, }, [ID_AD7124_8] = { .name = "ad7124-8", - .chip_id = CHIPID_AD7124_8, + .chip_id = AD7124_ID_DEVICE_ID_AD7124_8, .num_inputs = 16, }, }; @@ -260,8 +250,8 @@ static int ad7124_set_mode(struct ad_sigma_delta *sd, { struct ad7124_state *st = container_of(sd, struct ad7124_state, sd); - st->adc_control &= ~AD7124_ADC_CTRL_MODE_MSK; - st->adc_control |= AD7124_ADC_CTRL_MODE(mode); + st->adc_control &= ~AD7124_ADC_CONTROL_MODE; + st->adc_control |= FIELD_PREP(AD7124_ADC_CONTROL_MODE, mode); return ad_sd_write_reg(&st->sd, AD7124_ADC_CONTROL, 2, st->adc_control); } @@ -300,41 +290,15 @@ static int ad7124_get_3db_filter_freq(struct ad7124_state *st, fadc = st->channels[channel].cfg.odr; switch (st->channels[channel].cfg.filter_type) { - case AD7124_SINC3_FILTER: + case AD7124_FILTER_FILTER_SINC3: + return DIV_ROUND_CLOSEST(fadc * 272, 1000); + case AD7124_FILTER_FILTER_SINC4: return DIV_ROUND_CLOSEST(fadc * 230, 1000); - case AD7124_SINC4_FILTER: - return DIV_ROUND_CLOSEST(fadc * 262, 1000); default: return -EINVAL; } } -static void ad7124_set_3db_filter_freq(struct ad7124_state *st, unsigned int channel, - unsigned int freq) -{ - unsigned int sinc4_3db_odr; - unsigned int sinc3_3db_odr; - unsigned int new_filter; - unsigned int new_odr; - - sinc4_3db_odr = DIV_ROUND_CLOSEST(freq * 1000, 230); - sinc3_3db_odr = DIV_ROUND_CLOSEST(freq * 1000, 262); - - if (sinc4_3db_odr > sinc3_3db_odr) { - new_filter = AD7124_SINC3_FILTER; - new_odr = sinc4_3db_odr; - } else { - new_filter = AD7124_SINC4_FILTER; - new_odr = sinc3_3db_odr; - } - - if (new_odr != st->channels[channel].cfg.odr) - st->channels[channel].cfg.live = false; - - st->channels[channel].cfg.filter_type = new_filter; - st->channels[channel].cfg.odr = new_odr; -} - static struct ad7124_channel_config *ad7124_find_similar_live_cfg(struct ad7124_state *st, struct ad7124_channel_config *cfg) { @@ -413,8 +377,7 @@ static int ad7124_init_config_vref(struct ad7124_state *st, struct ad7124_channe return 0; case AD7124_INT_REF: cfg->vref_mv = 2500; - st->adc_control &= ~AD7124_ADC_CTRL_REF_EN_MSK; - st->adc_control |= AD7124_ADC_CTRL_REF_EN(1); + st->adc_control |= AD7124_ADC_CONTROL_REF_EN; return 0; default: return dev_err_probe(dev, -EINVAL, "Invalid reference %d\n", refsel); @@ -438,18 +401,20 @@ static int ad7124_write_config(struct ad7124_state *st, struct ad7124_channel_co if (ret) return ret; - tmp = (cfg->buf_positive << 1) + cfg->buf_negative; - val = AD7124_CONFIG_BIPOLAR(cfg->bipolar) | AD7124_CONFIG_REF_SEL(cfg->refsel) | - AD7124_CONFIG_IN_BUFF(tmp) | AD7124_CONFIG_PGA(cfg->pga_bits); + val = FIELD_PREP(AD7124_CONFIG_BIPOLAR, cfg->bipolar) | + FIELD_PREP(AD7124_CONFIG_REF_SEL, cfg->refsel) | + (cfg->buf_positive ? AD7124_CONFIG_AIN_BUFP : 0) | + (cfg->buf_negative ? AD7124_CONFIG_AIN_BUFM : 0) | + FIELD_PREP(AD7124_CONFIG_PGA, cfg->pga_bits); ret = ad_sd_write_reg(&st->sd, AD7124_CONFIG(cfg->cfg_slot), 2, val); if (ret < 0) return ret; - tmp = AD7124_FILTER_TYPE_SEL(cfg->filter_type) | - AD7124_FILTER_FS(cfg->odr_sel_bits); + tmp = FIELD_PREP(AD7124_FILTER_FILTER, cfg->filter_type) | + FIELD_PREP(AD7124_FILTER_FS, cfg->odr_sel_bits); return ad7124_spi_write_mask(st, AD7124_FILTER(cfg->cfg_slot), - AD7124_FILTER_TYPE_MSK | AD7124_FILTER_FS_MSK, + AD7124_FILTER_FILTER | AD7124_FILTER_FS, tmp, 3); } @@ -514,7 +479,8 @@ static int ad7124_enable_channel(struct ad7124_state *st, struct ad7124_channel { ch->cfg.live = true; return ad_sd_write_reg(&st->sd, AD7124_CHANNEL(ch->nr), 2, ch->ain | - AD7124_CHANNEL_SETUP(ch->cfg.cfg_slot) | AD7124_CHANNEL_EN(1)); + FIELD_PREP(AD7124_CHANNEL_SETUP, ch->cfg.cfg_slot) | + AD7124_CHANNEL_ENABLE); } static int ad7124_prepare_read(struct ad7124_state *st, int address) @@ -564,8 +530,10 @@ static int ad7124_append_status(struct ad_sigma_delta *sd, bool append) unsigned int adc_control = st->adc_control; int ret; - adc_control &= ~AD7124_ADC_STATUS_EN_MSK; - adc_control |= AD7124_ADC_STATUS_EN(append); + if (append) + adc_control |= AD7124_ADC_CONTROL_DATA_STATUS; + else + adc_control &= ~AD7124_ADC_CONTROL_DATA_STATUS; ret = ad_sd_write_reg(&st->sd, AD7124_ADC_CONTROL, 2, adc_control); if (ret < 0) @@ -580,7 +548,7 @@ static int ad7124_disable_one(struct ad_sigma_delta *sd, unsigned int chan) { struct ad7124_state *st = container_of(sd, struct ad7124_state, sd); - /* The relevant thing here is that AD7124_CHANNEL_EN_MSK is cleared. */ + /* The relevant thing here is that AD7124_CHANNEL_ENABLE is cleared. */ return ad_sd_write_reg(&st->sd, AD7124_CHANNEL(chan), 2, 0); } @@ -739,16 +707,8 @@ static int ad7124_write_raw(struct iio_dev *indio_dev, st->channels[chan->address].cfg.pga_bits = res; break; - case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: - if (val2 != 0) { - ret = -EINVAL; - break; - } - - ad7124_set_3db_filter_freq(st, chan->address, val); - break; default: - ret = -EINVAL; + ret = -EINVAL; } mutex_unlock(&st->cfgs_lock); @@ -802,7 +762,7 @@ static int ad7124_update_scan_mode(struct iio_dev *indio_dev, if (bit_set) ret = __ad7124_set_channel(&st->sd, i); else - ret = ad7124_spi_write_mask(st, AD7124_CHANNEL(i), AD7124_CHANNEL_EN_MSK, + ret = ad7124_spi_write_mask(st, AD7124_CHANNEL(i), AD7124_CHANNEL_ENABLE, 0, 2); if (ret < 0) { mutex_unlock(&st->cfgs_lock); @@ -843,14 +803,14 @@ static int ad7124_soft_reset(struct ad7124_state *st) if (ret < 0) return dev_err_probe(dev, ret, "Error reading status register\n"); - if (!(readval & AD7124_STATUS_POR_FLAG_MSK)) + if (!(readval & AD7124_STATUS_POR_FLAG)) break; /* The AD7124 requires typically 2ms to power up and settle */ usleep_range(100, 2000); } while (--timeout); - if (readval & AD7124_STATUS_POR_FLAG_MSK) + if (readval & AD7124_STATUS_POR_FLAG) return dev_err_probe(dev, -EIO, "Soft reset failed\n"); ret = ad_sd_read_reg(&st->sd, AD7124_GAIN(0), 3, &st->gain_default); @@ -872,8 +832,8 @@ static int ad7124_check_chip_id(struct ad7124_state *st) if (ret < 0) return dev_err_probe(dev, ret, "Failure to read ID register\n"); - chip_id = AD7124_DEVICE_ID_GET(readval); - silicon_rev = AD7124_SILICON_REV_GET(readval); + chip_id = FIELD_GET(AD7124_ID_DEVICE_ID, readval); + silicon_rev = FIELD_GET(AD7124_ID_SILICON_REVISION, readval); if (chip_id != st->chip_info->chip_id) return dev_err_probe(dev, -ENODEV, @@ -901,7 +861,7 @@ static int ad7124_syscalib_locked(struct ad7124_state *st, const struct iio_chan if (ch->syscalib_mode == AD7124_SYSCALIB_ZERO_SCALE) { ch->cfg.calibration_offset = 0x800000; - ret = ad_sd_calibrate(&st->sd, AD7124_MODE_CAL_SYS_ZERO, + ret = ad_sd_calibrate(&st->sd, AD7124_ADC_CONTROL_MODE_SYS_OFFSET_CALIB, chan->address); if (ret < 0) return ret; @@ -916,7 +876,7 @@ static int ad7124_syscalib_locked(struct ad7124_state *st, const struct iio_chan } else { ch->cfg.calibration_gain = st->gain_default; - ret = ad_sd_calibrate(&st->sd, AD7124_MODE_CAL_SYS_FULL, + ret = ad_sd_calibrate(&st->sd, AD7124_ADC_CONTROL_MODE_SYS_GAIN_CALIB, chan->address); if (ret < 0) return ret; @@ -1031,7 +991,7 @@ static bool ad7124_valid_input_select(unsigned int ain, const struct ad7124_chip if (ain >= info->num_inputs && ain < 16) return false; - return ain <= FIELD_MAX(AD7124_CHANNEL_AINM_MSK); + return ain <= FIELD_MAX(AD7124_CHANNEL_AINM); } static int ad7124_parse_channel_config(struct iio_dev *indio_dev, @@ -1096,8 +1056,8 @@ static int ad7124_parse_channel_config(struct iio_dev *indio_dev, "diff-channels property of %pfwP contains invalid data\n", child); st->channels[channel].nr = channel; - st->channels[channel].ain = AD7124_CHANNEL_AINP(ain[0]) | - AD7124_CHANNEL_AINM(ain[1]); + st->channels[channel].ain = FIELD_PREP(AD7124_CHANNEL_AINP, ain[0]) | + FIELD_PREP(AD7124_CHANNEL_AINM, ain[1]); cfg = &st->channels[channel].cfg; cfg->bipolar = fwnode_property_read_bool(child, "bipolar"); @@ -1123,8 +1083,8 @@ static int ad7124_parse_channel_config(struct iio_dev *indio_dev, if (num_channels < AD7124_MAX_CHANNELS) { st->channels[num_channels] = (struct ad7124_channel) { .nr = num_channels, - .ain = AD7124_CHANNEL_AINP(AD7124_INPUT_TEMPSENSOR) | - AD7124_CHANNEL_AINM(AD7124_INPUT_AVSS), + .ain = FIELD_PREP(AD7124_CHANNEL_AINP, AD7124_CHANNEL_AINx_TEMPSENSOR) | + FIELD_PREP(AD7124_CHANNEL_AINM, AD7124_CHANNEL_AINx_AVSS), .cfg = { .bipolar = true, }, @@ -1175,11 +1135,11 @@ static int ad7124_setup(struct ad7124_state *st) } /* Set the power mode */ - st->adc_control &= ~AD7124_ADC_CTRL_PWR_MSK; - st->adc_control |= AD7124_ADC_CTRL_PWR(power_mode); + st->adc_control &= ~AD7124_ADC_CONTROL_POWER_MODE; + st->adc_control |= FIELD_PREP(AD7124_ADC_CONTROL_POWER_MODE, power_mode); - st->adc_control &= ~AD7124_ADC_CTRL_MODE_MSK; - st->adc_control |= AD7124_ADC_CTRL_MODE(AD_SD_MODE_IDLE); + st->adc_control &= ~AD7124_ADC_CONTROL_MODE; + st->adc_control |= FIELD_PREP(AD7124_ADC_CONTROL_MODE, AD_SD_MODE_IDLE); mutex_init(&st->cfgs_lock); INIT_KFIFO(st->live_cfgs_fifo); @@ -1233,7 +1193,7 @@ static int __ad7124_calibrate_all(struct ad7124_state *st, struct iio_dev *indio * usual: first zero-scale then full-scale calibration. */ if (st->channels[i].cfg.pga_bits > 0) { - ret = ad_sd_calibrate(&st->sd, AD7124_MODE_CAL_INT_FULL, i); + ret = ad_sd_calibrate(&st->sd, AD7124_ADC_CONTROL_MODE_INT_GAIN_CALIB, i); if (ret < 0) return ret; @@ -1250,7 +1210,7 @@ static int __ad7124_calibrate_all(struct ad7124_state *st, struct iio_dev *indio return ret; } - ret = ad_sd_calibrate(&st->sd, AD7124_MODE_CAL_INT_ZERO, i); + ret = ad_sd_calibrate(&st->sd, AD7124_ADC_CONTROL_MODE_INT_OFFSET_CALIB, i); if (ret < 0) return ret; @@ -1279,9 +1239,9 @@ static int ad7124_calibrate_all(struct ad7124_state *st, struct iio_dev *indio_d * The resulting calibration is then also valid for high-speed, so just * restore adc_control afterwards. */ - if (FIELD_GET(AD7124_ADC_CTRL_PWR_MSK, adc_control) >= AD7124_FULL_POWER) { - st->adc_control &= ~AD7124_ADC_CTRL_PWR_MSK; - st->adc_control |= AD7124_ADC_CTRL_PWR(AD7124_MID_POWER); + if (FIELD_GET(AD7124_ADC_CONTROL_POWER_MODE, adc_control) >= AD7124_FULL_POWER) { + st->adc_control &= ~AD7124_ADC_CONTROL_POWER_MODE; + st->adc_control |= FIELD_PREP(AD7124_ADC_CONTROL_POWER_MODE, AD7124_MID_POWER); } ret = __ad7124_calibrate_all(st, indio_dev); diff --git a/drivers/iio/adc/ad7173.c b/drivers/iio/adc/ad7173.c index 69de5886474c..b3e6bd2a55d7 100644 --- a/drivers/iio/adc/ad7173.c +++ b/drivers/iio/adc/ad7173.c @@ -230,10 +230,8 @@ struct ad7173_state { unsigned long long *config_cnts; struct clk *ext_clk; struct clk_hw int_clk_hw; -#if IS_ENABLED(CONFIG_GPIOLIB) struct regmap *reg_gpiocon_regmap; struct gpio_regmap *gpio_regmap; -#endif }; static unsigned int ad4115_sinc5_data_rates[] = { @@ -288,8 +286,6 @@ static const char *const ad7173_clk_sel[] = { "ext-clk", "xtal" }; -#if IS_ENABLED(CONFIG_GPIOLIB) - static const struct regmap_range ad7173_range_gpio[] = { regmap_reg_range(AD7173_REG_GPIO, AD7173_REG_GPIO), }; @@ -543,12 +539,6 @@ static int ad7173_gpio_init(struct ad7173_state *st) return 0; } -#else -static int ad7173_gpio_init(struct ad7173_state *st) -{ - return 0; -} -#endif /* CONFIG_GPIOLIB */ static struct ad7173_state *ad_sigma_delta_to_ad7173(struct ad_sigma_delta *sd) { @@ -1797,10 +1787,7 @@ static int ad7173_probe(struct spi_device *spi) if (ret) return ret; - if (IS_ENABLED(CONFIG_GPIOLIB)) - return ad7173_gpio_init(st); - - return 0; + return ad7173_gpio_init(st); } static const struct of_device_id ad7173_of_match[] = { diff --git a/drivers/iio/adc/ad7266.c b/drivers/iio/adc/ad7266.c index 7fef2727f89e..3364ac6c4631 100644 --- a/drivers/iio/adc/ad7266.c +++ b/drivers/iio/adc/ad7266.c @@ -86,10 +86,9 @@ static irqreturn_t ad7266_trigger_handler(int irq, void *p) int ret; ret = spi_read(st->spi, st->data.sample, 4); - if (ret == 0) { - iio_push_to_buffers_with_timestamp(indio_dev, &st->data, - pf->timestamp); - } + if (ret == 0) + iio_push_to_buffers_with_ts(indio_dev, &st->data, sizeof(st->data), + pf->timestamp); iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/adc/ad7280a.c b/drivers/iio/adc/ad7280a.c index f9f32737db80..dda2986ccda0 100644 --- a/drivers/iio/adc/ad7280a.c +++ b/drivers/iio/adc/ad7280a.c @@ -572,7 +572,7 @@ static const struct iio_chan_spec_ext_info ad7280_cell_ext_info[] = { .write = ad7280_store_balance_timer, .shared = IIO_SEPARATE, }, - {} + { } }; static const struct iio_event_spec ad7280_events[] = { diff --git a/drivers/iio/adc/ad7298.c b/drivers/iio/adc/ad7298.c index 28b88092b4aa..7c0538ea15c8 100644 --- a/drivers/iio/adc/ad7298.c +++ b/drivers/iio/adc/ad7298.c @@ -155,8 +155,8 @@ static irqreturn_t ad7298_trigger_handler(int irq, void *p) if (b_sent) goto done; - iio_push_to_buffers_with_timestamp(indio_dev, st->rx_buf, - iio_get_time_ns(indio_dev)); + iio_push_to_buffers_with_ts(indio_dev, st->rx_buf, sizeof(st->rx_buf), + iio_get_time_ns(indio_dev)); done: iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/adc/ad7380.c b/drivers/iio/adc/ad7380.c index aef85093eb16..d96bd12dfea6 100644 --- a/drivers/iio/adc/ad7380.c +++ b/drivers/iio/adc/ad7380.c @@ -13,6 +13,7 @@ * ad7381-4 : https://www.analog.com/media/en/technical-documentation/data-sheets/ad7381-4.pdf * ad7383/4-4 : https://www.analog.com/media/en/technical-documentation/data-sheets/ad7383-4-ad7384-4.pdf * ad7386/7/8-4 : https://www.analog.com/media/en/technical-documentation/data-sheets/ad7386-4-7387-4-7388-4.pdf + * ad7389-4 : https://www.analog.com/media/en/technical-documentation/data-sheets/ad7389-4.pdf * adaq4370-4 : https://www.analog.com/media/en/technical-documentation/data-sheets/adaq4370-4.pdf * adaq4380-4 : https://www.analog.com/media/en/technical-documentation/data-sheets/adaq4380-4.pdf * adaq4381-4 : https://www.analog.com/media/en/technical-documentation/data-sheets/adaq4381-4.pdf @@ -119,7 +120,8 @@ struct ad7380_chip_info { const char * const *supplies; unsigned int num_supplies; bool external_ref_only; - bool adaq_internal_ref_only; + bool internal_ref_only; + unsigned int internal_ref_mv; const char * const *vcm_supplies; unsigned int num_vcm_supplies; const unsigned long *available_scan_masks; @@ -609,6 +611,7 @@ static const struct ad7380_chip_info ad7380_chip_info = { .num_simult_channels = 2, .supplies = ad7380_supplies, .num_supplies = ARRAY_SIZE(ad7380_supplies), + .internal_ref_mv = AD7380_INTERNAL_REF_MV, .available_scan_masks = ad7380_2_channel_scan_masks, .timing_specs = &ad7380_timing, .max_conversion_rate_hz = 4 * MEGA, @@ -622,6 +625,7 @@ static const struct ad7380_chip_info ad7381_chip_info = { .num_simult_channels = 2, .supplies = ad7380_supplies, .num_supplies = ARRAY_SIZE(ad7380_supplies), + .internal_ref_mv = AD7380_INTERNAL_REF_MV, .available_scan_masks = ad7380_2_channel_scan_masks, .timing_specs = &ad7380_timing, .max_conversion_rate_hz = 4 * MEGA, @@ -637,6 +641,7 @@ static const struct ad7380_chip_info ad7383_chip_info = { .num_supplies = ARRAY_SIZE(ad7380_supplies), .vcm_supplies = ad7380_2_channel_vcm_supplies, .num_vcm_supplies = ARRAY_SIZE(ad7380_2_channel_vcm_supplies), + .internal_ref_mv = AD7380_INTERNAL_REF_MV, .available_scan_masks = ad7380_2_channel_scan_masks, .timing_specs = &ad7380_timing, .max_conversion_rate_hz = 4 * MEGA, @@ -652,6 +657,7 @@ static const struct ad7380_chip_info ad7384_chip_info = { .num_supplies = ARRAY_SIZE(ad7380_supplies), .vcm_supplies = ad7380_2_channel_vcm_supplies, .num_vcm_supplies = ARRAY_SIZE(ad7380_2_channel_vcm_supplies), + .internal_ref_mv = AD7380_INTERNAL_REF_MV, .available_scan_masks = ad7380_2_channel_scan_masks, .timing_specs = &ad7380_timing, .max_conversion_rate_hz = 4 * MEGA, @@ -665,6 +671,7 @@ static const struct ad7380_chip_info ad7386_chip_info = { .num_simult_channels = 2, .supplies = ad7380_supplies, .num_supplies = ARRAY_SIZE(ad7380_supplies), + .internal_ref_mv = AD7380_INTERNAL_REF_MV, .has_mux = true, .available_scan_masks = ad7380_2x2_channel_scan_masks, .timing_specs = &ad7380_timing, @@ -679,6 +686,7 @@ static const struct ad7380_chip_info ad7387_chip_info = { .num_simult_channels = 2, .supplies = ad7380_supplies, .num_supplies = ARRAY_SIZE(ad7380_supplies), + .internal_ref_mv = AD7380_INTERNAL_REF_MV, .has_mux = true, .available_scan_masks = ad7380_2x2_channel_scan_masks, .timing_specs = &ad7380_timing, @@ -693,6 +701,7 @@ static const struct ad7380_chip_info ad7388_chip_info = { .num_simult_channels = 2, .supplies = ad7380_supplies, .num_supplies = ARRAY_SIZE(ad7380_supplies), + .internal_ref_mv = AD7380_INTERNAL_REF_MV, .has_mux = true, .available_scan_masks = ad7380_2x2_channel_scan_masks, .timing_specs = &ad7380_timing, @@ -721,6 +730,7 @@ static const struct ad7380_chip_info ad7381_4_chip_info = { .num_simult_channels = 4, .supplies = ad7380_supplies, .num_supplies = ARRAY_SIZE(ad7380_supplies), + .internal_ref_mv = AD7380_INTERNAL_REF_MV, .available_scan_masks = ad7380_4_channel_scan_masks, .timing_specs = &ad7380_4_timing, .max_conversion_rate_hz = 4 * MEGA, @@ -734,6 +744,7 @@ static const struct ad7380_chip_info ad7383_4_chip_info = { .num_simult_channels = 4, .supplies = ad7380_supplies, .num_supplies = ARRAY_SIZE(ad7380_supplies), + .internal_ref_mv = AD7380_INTERNAL_REF_MV, .vcm_supplies = ad7380_4_channel_vcm_supplies, .num_vcm_supplies = ARRAY_SIZE(ad7380_4_channel_vcm_supplies), .available_scan_masks = ad7380_4_channel_scan_masks, @@ -749,6 +760,7 @@ static const struct ad7380_chip_info ad7384_4_chip_info = { .num_simult_channels = 4, .supplies = ad7380_supplies, .num_supplies = ARRAY_SIZE(ad7380_supplies), + .internal_ref_mv = AD7380_INTERNAL_REF_MV, .vcm_supplies = ad7380_4_channel_vcm_supplies, .num_vcm_supplies = ARRAY_SIZE(ad7380_4_channel_vcm_supplies), .available_scan_masks = ad7380_4_channel_scan_masks, @@ -764,6 +776,7 @@ static const struct ad7380_chip_info ad7386_4_chip_info = { .num_simult_channels = 4, .supplies = ad7380_supplies, .num_supplies = ARRAY_SIZE(ad7380_supplies), + .internal_ref_mv = AD7380_INTERNAL_REF_MV, .has_mux = true, .available_scan_masks = ad7380_2x4_channel_scan_masks, .timing_specs = &ad7380_4_timing, @@ -778,6 +791,7 @@ static const struct ad7380_chip_info ad7387_4_chip_info = { .num_simult_channels = 4, .supplies = ad7380_supplies, .num_supplies = ARRAY_SIZE(ad7380_supplies), + .internal_ref_mv = AD7380_INTERNAL_REF_MV, .has_mux = true, .available_scan_masks = ad7380_2x4_channel_scan_masks, .timing_specs = &ad7380_4_timing, @@ -792,12 +806,28 @@ static const struct ad7380_chip_info ad7388_4_chip_info = { .num_simult_channels = 4, .supplies = ad7380_supplies, .num_supplies = ARRAY_SIZE(ad7380_supplies), + .internal_ref_mv = AD7380_INTERNAL_REF_MV, .has_mux = true, .available_scan_masks = ad7380_2x4_channel_scan_masks, .timing_specs = &ad7380_4_timing, .max_conversion_rate_hz = 4 * MEGA, }; +static const struct ad7380_chip_info ad7389_4_chip_info = { + .name = "ad7389-4", + .channels = ad7380_4_channels, + .offload_channels = ad7380_4_offload_channels, + .num_channels = ARRAY_SIZE(ad7380_4_channels), + .num_simult_channels = 4, + .supplies = ad7380_supplies, + .num_supplies = ARRAY_SIZE(ad7380_supplies), + .internal_ref_only = true, + .internal_ref_mv = AD7380_INTERNAL_REF_MV, + .available_scan_masks = ad7380_4_channel_scan_masks, + .timing_specs = &ad7380_4_timing, + .max_conversion_rate_hz = 4 * MEGA, +}; + static const struct ad7380_chip_info adaq4370_4_chip_info = { .name = "adaq4370-4", .channels = adaq4380_4_channels, @@ -806,7 +836,8 @@ static const struct ad7380_chip_info adaq4370_4_chip_info = { .num_simult_channels = 4, .supplies = adaq4380_supplies, .num_supplies = ARRAY_SIZE(adaq4380_supplies), - .adaq_internal_ref_only = true, + .internal_ref_only = true, + .internal_ref_mv = ADAQ4380_INTERNAL_REF_MV, .has_hardware_gain = true, .available_scan_masks = ad7380_4_channel_scan_masks, .timing_specs = &ad7380_4_timing, @@ -821,7 +852,8 @@ static const struct ad7380_chip_info adaq4380_4_chip_info = { .num_simult_channels = 4, .supplies = adaq4380_supplies, .num_supplies = ARRAY_SIZE(adaq4380_supplies), - .adaq_internal_ref_only = true, + .internal_ref_only = true, + .internal_ref_mv = ADAQ4380_INTERNAL_REF_MV, .has_hardware_gain = true, .available_scan_masks = ad7380_4_channel_scan_masks, .timing_specs = &ad7380_4_timing, @@ -836,7 +868,8 @@ static const struct ad7380_chip_info adaq4381_4_chip_info = { .num_simult_channels = 4, .supplies = adaq4380_supplies, .num_supplies = ARRAY_SIZE(adaq4380_supplies), - .adaq_internal_ref_only = true, + .internal_ref_only = true, + .internal_ref_mv = ADAQ4380_INTERNAL_REF_MV, .has_hardware_gain = true, .available_scan_masks = ad7380_4_channel_scan_masks, .timing_specs = &ad7380_4_timing, @@ -876,8 +909,7 @@ struct ad7380_state { * Make the buffer large enough for MAX_NUM_CHANNELS 32-bit samples and * one 64-bit aligned 64-bit timestamp. */ - u8 scan_data[ALIGN(MAX_NUM_CHANNELS * sizeof(u32), sizeof(s64)) - + sizeof(s64)] __aligned(IIO_DMA_MINALIGN); + IIO_DECLARE_DMA_BUFFER_WITH_TS(u8, scan_data, MAX_NUM_CHANNELS * sizeof(u32)); /* buffers for reading/writing registers */ u16 tx; u16 rx; @@ -1327,8 +1359,8 @@ static irqreturn_t ad7380_trigger_handler(int irq, void *p) if (ret) goto out; - iio_push_to_buffers_with_timestamp(indio_dev, &st->scan_data, - pf->timestamp); + iio_push_to_buffers_with_ts(indio_dev, &st->scan_data, sizeof(st->scan_data), + pf->timestamp); out: iio_trigger_notify_done(indio_dev->trig); @@ -1859,7 +1891,7 @@ static int ad7380_probe(struct spi_device *spi) "Failed to enable power supplies\n"); fsleep(T_POWERUP_US); - if (st->chip_info->adaq_internal_ref_only) { + if (st->chip_info->internal_ref_only) { /* * ADAQ chips use fixed internal reference but still * require a specific reference supply to power it. @@ -1867,7 +1899,7 @@ static int ad7380_probe(struct spi_device *spi) * in bulk_get_enable(). */ - st->vref_mv = ADAQ4380_INTERNAL_REF_MV; + st->vref_mv = st->chip_info->internal_ref_mv; /* these chips don't have a register bit for this */ external_ref_en = false; @@ -1892,7 +1924,8 @@ static int ad7380_probe(struct spi_device *spi) "Failed to get refio regulator\n"); external_ref_en = ret != -ENODEV; - st->vref_mv = external_ref_en ? ret / 1000 : AD7380_INTERNAL_REF_MV; + st->vref_mv = external_ref_en ? ret / 1000 + : st->chip_info->internal_ref_mv; } if (st->chip_info->num_vcm_supplies > ARRAY_SIZE(st->vcm_mv)) @@ -2045,6 +2078,7 @@ static const struct of_device_id ad7380_of_match_table[] = { { .compatible = "adi,ad7386-4", .data = &ad7386_4_chip_info }, { .compatible = "adi,ad7387-4", .data = &ad7387_4_chip_info }, { .compatible = "adi,ad7388-4", .data = &ad7388_4_chip_info }, + { .compatible = "adi,ad7389-4", .data = &ad7389_4_chip_info }, { .compatible = "adi,adaq4370-4", .data = &adaq4370_4_chip_info }, { .compatible = "adi,adaq4380-4", .data = &adaq4380_4_chip_info }, { .compatible = "adi,adaq4381-4", .data = &adaq4381_4_chip_info }, @@ -2066,6 +2100,7 @@ static const struct spi_device_id ad7380_id_table[] = { { "ad7386-4", (kernel_ulong_t)&ad7386_4_chip_info }, { "ad7387-4", (kernel_ulong_t)&ad7387_4_chip_info }, { "ad7388-4", (kernel_ulong_t)&ad7388_4_chip_info }, + { "ad7389-4", (kernel_ulong_t)&ad7389_4_chip_info }, { "adaq4370-4", (kernel_ulong_t)&adaq4370_4_chip_info }, { "adaq4380-4", (kernel_ulong_t)&adaq4380_4_chip_info }, { "adaq4381-4", (kernel_ulong_t)&adaq4381_4_chip_info }, diff --git a/drivers/iio/adc/ad7476.c b/drivers/iio/adc/ad7476.c index 37b0515cf4fc..ddb607ac1860 100644 --- a/drivers/iio/adc/ad7476.c +++ b/drivers/iio/adc/ad7476.c @@ -99,8 +99,8 @@ static irqreturn_t ad7476_trigger_handler(int irq, void *p) if (b_sent < 0) goto done; - iio_push_to_buffers_with_timestamp(indio_dev, st->data, - iio_get_time_ns(indio_dev)); + iio_push_to_buffers_with_ts(indio_dev, st->data, sizeof(st->data), + iio_get_time_ns(indio_dev)); done: iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/adc/ad7606.c b/drivers/iio/adc/ad7606.c index 703556eb7257..185243dee86e 100644 --- a/drivers/iio/adc/ad7606.c +++ b/drivers/iio/adc/ad7606.c @@ -13,6 +13,7 @@ #include <linux/interrupt.h> #include <linux/kernel.h> #include <linux/module.h> +#include <linux/mutex.h> #include <linux/property.h> #include <linux/pwm.h> #include <linux/regulator/consumer.h> @@ -94,121 +95,35 @@ static const unsigned int ad7616_oversampling_avail[8] = { 1, 2, 4, 8, 16, 32, 64, 128, }; -static const struct iio_chan_spec ad7605_channels[] = { - IIO_CHAN_SOFT_TIMESTAMP(4), - AD7605_CHANNEL(0), - AD7605_CHANNEL(1), - AD7605_CHANNEL(2), - AD7605_CHANNEL(3), -}; - -static const struct iio_chan_spec ad7606_channels_16bit[] = { - IIO_CHAN_SOFT_TIMESTAMP(8), - AD7606_CHANNEL(0, 16), - AD7606_CHANNEL(1, 16), - AD7606_CHANNEL(2, 16), - AD7606_CHANNEL(3, 16), - AD7606_CHANNEL(4, 16), - AD7606_CHANNEL(5, 16), - AD7606_CHANNEL(6, 16), - AD7606_CHANNEL(7, 16), -}; - -static const struct iio_chan_spec ad7606_channels_18bit[] = { - IIO_CHAN_SOFT_TIMESTAMP(8), - AD7606_CHANNEL(0, 18), - AD7606_CHANNEL(1, 18), - AD7606_CHANNEL(2, 18), - AD7606_CHANNEL(3, 18), - AD7606_CHANNEL(4, 18), - AD7606_CHANNEL(5, 18), - AD7606_CHANNEL(6, 18), - AD7606_CHANNEL(7, 18), -}; - -static const struct iio_chan_spec ad7607_channels[] = { - IIO_CHAN_SOFT_TIMESTAMP(8), - AD7606_CHANNEL(0, 14), - AD7606_CHANNEL(1, 14), - AD7606_CHANNEL(2, 14), - AD7606_CHANNEL(3, 14), - AD7606_CHANNEL(4, 14), - AD7606_CHANNEL(5, 14), - AD7606_CHANNEL(6, 14), - AD7606_CHANNEL(7, 14), -}; - -static const struct iio_chan_spec ad7608_channels[] = { - IIO_CHAN_SOFT_TIMESTAMP(8), - AD7606_CHANNEL(0, 18), - AD7606_CHANNEL(1, 18), - AD7606_CHANNEL(2, 18), - AD7606_CHANNEL(3, 18), - AD7606_CHANNEL(4, 18), - AD7606_CHANNEL(5, 18), - AD7606_CHANNEL(6, 18), - AD7606_CHANNEL(7, 18), -}; - -/* - * The current assumption that this driver makes for AD7616, is that it's - * working in Hardware Mode with Serial, Burst and Sequencer modes activated. - * To activate them, following pins must be pulled high: - * -SER/PAR - * -SEQEN - * And following pins must be pulled low: - * -WR/BURST - * -DB4/SER1W - */ -static const struct iio_chan_spec ad7616_channels[] = { - IIO_CHAN_SOFT_TIMESTAMP(16), - AD7606_CHANNEL(0, 16), - AD7606_CHANNEL(1, 16), - AD7606_CHANNEL(2, 16), - AD7606_CHANNEL(3, 16), - AD7606_CHANNEL(4, 16), - AD7606_CHANNEL(5, 16), - AD7606_CHANNEL(6, 16), - AD7606_CHANNEL(7, 16), - AD7606_CHANNEL(8, 16), - AD7606_CHANNEL(9, 16), - AD7606_CHANNEL(10, 16), - AD7606_CHANNEL(11, 16), - AD7606_CHANNEL(12, 16), - AD7606_CHANNEL(13, 16), - AD7606_CHANNEL(14, 16), - AD7606_CHANNEL(15, 16), -}; - static int ad7606c_18bit_chan_scale_setup(struct iio_dev *indio_dev, - struct iio_chan_spec *chan, int ch); + struct iio_chan_spec *chan); static int ad7606c_16bit_chan_scale_setup(struct iio_dev *indio_dev, - struct iio_chan_spec *chan, int ch); + struct iio_chan_spec *chan); static int ad7606_16bit_chan_scale_setup(struct iio_dev *indio_dev, - struct iio_chan_spec *chan, int ch); + struct iio_chan_spec *chan); static int ad7607_chan_scale_setup(struct iio_dev *indio_dev, - struct iio_chan_spec *chan, int ch); + struct iio_chan_spec *chan); static int ad7608_chan_scale_setup(struct iio_dev *indio_dev, - struct iio_chan_spec *chan, int ch); + struct iio_chan_spec *chan); static int ad7609_chan_scale_setup(struct iio_dev *indio_dev, - struct iio_chan_spec *chan, int ch); + struct iio_chan_spec *chan); static int ad7616_sw_mode_setup(struct iio_dev *indio_dev); static int ad7606b_sw_mode_setup(struct iio_dev *indio_dev); const struct ad7606_chip_info ad7605_4_info = { - .channels = ad7605_channels, + .max_samplerate = 300 * KILO, .name = "ad7605-4", + .bits = 16, .num_adc_channels = 4, - .num_channels = 5, .scale_setup_cb = ad7606_16bit_chan_scale_setup, }; EXPORT_SYMBOL_NS_GPL(ad7605_4_info, "IIO_AD7606"); const struct ad7606_chip_info ad7606_8_info = { - .channels = ad7606_channels_16bit, + .max_samplerate = 200 * KILO, .name = "ad7606-8", + .bits = 16, .num_adc_channels = 8, - .num_channels = 9, .oversampling_avail = ad7606_oversampling_avail, .oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail), .scale_setup_cb = ad7606_16bit_chan_scale_setup, @@ -216,108 +131,116 @@ const struct ad7606_chip_info ad7606_8_info = { EXPORT_SYMBOL_NS_GPL(ad7606_8_info, "IIO_AD7606"); const struct ad7606_chip_info ad7606_6_info = { - .channels = ad7606_channels_16bit, + .max_samplerate = 200 * KILO, .name = "ad7606-6", + .bits = 16, .num_adc_channels = 6, - .num_channels = 7, .oversampling_avail = ad7606_oversampling_avail, .oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail), .scale_setup_cb = ad7606_16bit_chan_scale_setup, + .offload_storagebits = 32, }; EXPORT_SYMBOL_NS_GPL(ad7606_6_info, "IIO_AD7606"); const struct ad7606_chip_info ad7606_4_info = { - .channels = ad7606_channels_16bit, + .max_samplerate = 200 * KILO, .name = "ad7606-4", + .bits = 16, .num_adc_channels = 4, - .num_channels = 5, .oversampling_avail = ad7606_oversampling_avail, .oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail), .scale_setup_cb = ad7606_16bit_chan_scale_setup, + .offload_storagebits = 32, }; EXPORT_SYMBOL_NS_GPL(ad7606_4_info, "IIO_AD7606"); const struct ad7606_chip_info ad7606b_info = { - .channels = ad7606_channels_16bit, .max_samplerate = 800 * KILO, .name = "ad7606b", + .bits = 16, .num_adc_channels = 8, - .num_channels = 9, .oversampling_avail = ad7606_oversampling_avail, .oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail), .scale_setup_cb = ad7606_16bit_chan_scale_setup, .sw_setup_cb = ad7606b_sw_mode_setup, + .offload_storagebits = 32, }; EXPORT_SYMBOL_NS_GPL(ad7606b_info, "IIO_AD7606"); const struct ad7606_chip_info ad7606c_16_info = { - .channels = ad7606_channels_16bit, + .max_samplerate = 1 * MEGA, .name = "ad7606c16", + .bits = 16, .num_adc_channels = 8, - .num_channels = 9, .oversampling_avail = ad7606_oversampling_avail, .oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail), .scale_setup_cb = ad7606c_16bit_chan_scale_setup, .sw_setup_cb = ad7606b_sw_mode_setup, + .offload_storagebits = 32, }; EXPORT_SYMBOL_NS_GPL(ad7606c_16_info, "IIO_AD7606"); const struct ad7606_chip_info ad7607_info = { - .channels = ad7607_channels, + .max_samplerate = 200 * KILO, .name = "ad7607", + .bits = 14, .num_adc_channels = 8, - .num_channels = 9, .oversampling_avail = ad7606_oversampling_avail, .oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail), .scale_setup_cb = ad7607_chan_scale_setup, + .offload_storagebits = 32, }; EXPORT_SYMBOL_NS_GPL(ad7607_info, "IIO_AD7606"); const struct ad7606_chip_info ad7608_info = { - .channels = ad7608_channels, + .max_samplerate = 200 * KILO, .name = "ad7608", + .bits = 18, .num_adc_channels = 8, - .num_channels = 9, .oversampling_avail = ad7606_oversampling_avail, .oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail), .scale_setup_cb = ad7608_chan_scale_setup, + .offload_storagebits = 32, }; EXPORT_SYMBOL_NS_GPL(ad7608_info, "IIO_AD7606"); const struct ad7606_chip_info ad7609_info = { - .channels = ad7608_channels, + .max_samplerate = 200 * KILO, .name = "ad7609", + .bits = 18, .num_adc_channels = 8, - .num_channels = 9, .oversampling_avail = ad7606_oversampling_avail, .oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail), .scale_setup_cb = ad7609_chan_scale_setup, + .offload_storagebits = 32, }; EXPORT_SYMBOL_NS_GPL(ad7609_info, "IIO_AD7606"); const struct ad7606_chip_info ad7606c_18_info = { - .channels = ad7606_channels_18bit, + .max_samplerate = 1 * MEGA, .name = "ad7606c18", + .bits = 18, .num_adc_channels = 8, - .num_channels = 9, .oversampling_avail = ad7606_oversampling_avail, .oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail), .scale_setup_cb = ad7606c_18bit_chan_scale_setup, .sw_setup_cb = ad7606b_sw_mode_setup, + .offload_storagebits = 32, }; EXPORT_SYMBOL_NS_GPL(ad7606c_18_info, "IIO_AD7606"); const struct ad7606_chip_info ad7616_info = { - .channels = ad7616_channels, + .max_samplerate = 1 * MEGA, .init_delay_ms = 15, .name = "ad7616", + .bits = 16, .num_adc_channels = 16, - .num_channels = 17, .oversampling_avail = ad7616_oversampling_avail, .oversampling_num = ARRAY_SIZE(ad7616_oversampling_avail), .os_req_reset = true, .scale_setup_cb = ad7606_16bit_chan_scale_setup, .sw_setup_cb = ad7616_sw_mode_setup, + .offload_storagebits = 16, }; EXPORT_SYMBOL_NS_GPL(ad7616_info, "IIO_AD7606"); @@ -335,10 +258,10 @@ int ad7606_reset(struct ad7606_state *st) EXPORT_SYMBOL_NS_GPL(ad7606_reset, "IIO_AD7606"); static int ad7606_16bit_chan_scale_setup(struct iio_dev *indio_dev, - struct iio_chan_spec *chan, int ch) + struct iio_chan_spec *chan) { struct ad7606_state *st = iio_priv(indio_dev); - struct ad7606_chan_scale *cs = &st->chan_scales[ch]; + struct ad7606_chan_scale *cs = &st->chan_scales[chan->scan_index]; if (!st->sw_mode_en) { /* tied to logic low, analog input range is +/- 5V */ @@ -362,7 +285,6 @@ static int ad7606_get_chan_config(struct iio_dev *indio_dev, int ch, { struct ad7606_state *st = iio_priv(indio_dev); unsigned int num_channels = st->chip_info->num_adc_channels; - unsigned int offset = indio_dev->num_channels - st->chip_info->num_adc_channels; struct device *dev = st->dev; int ret; @@ -378,7 +300,7 @@ static int ad7606_get_chan_config(struct iio_dev *indio_dev, int ch, continue; /* channel number (here) is from 1 to num_channels */ - if (reg < offset || reg > num_channels) { + if (reg < 1 || reg > num_channels) { dev_warn(dev, "Invalid channel number (ignoring): %d\n", reg); continue; @@ -414,10 +336,10 @@ static int ad7606_get_chan_config(struct iio_dev *indio_dev, int ch, } static int ad7606c_18bit_chan_scale_setup(struct iio_dev *indio_dev, - struct iio_chan_spec *chan, int ch) + struct iio_chan_spec *chan) { struct ad7606_state *st = iio_priv(indio_dev); - struct ad7606_chan_scale *cs = &st->chan_scales[ch]; + struct ad7606_chan_scale *cs = &st->chan_scales[chan->scan_index]; bool bipolar, differential; int ret; @@ -428,7 +350,8 @@ static int ad7606c_18bit_chan_scale_setup(struct iio_dev *indio_dev, return 0; } - ret = ad7606_get_chan_config(indio_dev, ch, &bipolar, &differential); + ret = ad7606_get_chan_config(indio_dev, chan->scan_index, &bipolar, + &differential); if (ret) return ret; @@ -471,10 +394,10 @@ static int ad7606c_18bit_chan_scale_setup(struct iio_dev *indio_dev, } static int ad7606c_16bit_chan_scale_setup(struct iio_dev *indio_dev, - struct iio_chan_spec *chan, int ch) + struct iio_chan_spec *chan) { struct ad7606_state *st = iio_priv(indio_dev); - struct ad7606_chan_scale *cs = &st->chan_scales[ch]; + struct ad7606_chan_scale *cs = &st->chan_scales[chan->scan_index]; bool bipolar, differential; int ret; @@ -485,7 +408,8 @@ static int ad7606c_16bit_chan_scale_setup(struct iio_dev *indio_dev, return 0; } - ret = ad7606_get_chan_config(indio_dev, ch, &bipolar, &differential); + ret = ad7606_get_chan_config(indio_dev, chan->scan_index, &bipolar, + &differential); if (ret) return ret; @@ -529,10 +453,10 @@ static int ad7606c_16bit_chan_scale_setup(struct iio_dev *indio_dev, } static int ad7607_chan_scale_setup(struct iio_dev *indio_dev, - struct iio_chan_spec *chan, int ch) + struct iio_chan_spec *chan) { struct ad7606_state *st = iio_priv(indio_dev); - struct ad7606_chan_scale *cs = &st->chan_scales[ch]; + struct ad7606_chan_scale *cs = &st->chan_scales[chan->scan_index]; cs->range = 0; cs->scale_avail = ad7607_hw_scale_avail; @@ -541,10 +465,10 @@ static int ad7607_chan_scale_setup(struct iio_dev *indio_dev, } static int ad7608_chan_scale_setup(struct iio_dev *indio_dev, - struct iio_chan_spec *chan, int ch) + struct iio_chan_spec *chan) { struct ad7606_state *st = iio_priv(indio_dev); - struct ad7606_chan_scale *cs = &st->chan_scales[ch]; + struct ad7606_chan_scale *cs = &st->chan_scales[chan->scan_index]; cs->range = 0; cs->scale_avail = ad7606_18bit_hw_scale_avail; @@ -553,10 +477,10 @@ static int ad7608_chan_scale_setup(struct iio_dev *indio_dev, } static int ad7609_chan_scale_setup(struct iio_dev *indio_dev, - struct iio_chan_spec *chan, int ch) + struct iio_chan_spec *chan) { struct ad7606_state *st = iio_priv(indio_dev); - struct ad7606_chan_scale *cs = &st->chan_scales[ch]; + struct ad7606_chan_scale *cs = &st->chan_scales[chan->scan_index]; cs->range = 0; cs->scale_avail = ad7609_hw_scale_avail; @@ -599,7 +523,7 @@ static int ad7606_pwm_set_high(struct ad7606_state *st) return ret; } -static int ad7606_pwm_set_low(struct ad7606_state *st) +int ad7606_pwm_set_low(struct ad7606_state *st) { struct pwm_state cnvst_pwm_state; int ret; @@ -612,8 +536,9 @@ static int ad7606_pwm_set_low(struct ad7606_state *st) return ret; } +EXPORT_SYMBOL_NS_GPL(ad7606_pwm_set_low, "IIO_AD7606"); -static int ad7606_pwm_set_swing(struct ad7606_state *st) +int ad7606_pwm_set_swing(struct ad7606_state *st) { struct pwm_state cnvst_pwm_state; @@ -623,6 +548,7 @@ static int ad7606_pwm_set_swing(struct ad7606_state *st) return pwm_apply_might_sleep(st->cnvst_pwm, &cnvst_pwm_state); } +EXPORT_SYMBOL_NS_GPL(ad7606_pwm_set_swing, "IIO_AD7606"); static bool ad7606_pwm_is_swinging(struct ad7606_state *st) { @@ -679,8 +605,8 @@ static irqreturn_t ad7606_trigger_handler(int irq, void *p) if (ret) goto error_ret; - iio_push_to_buffers_with_timestamp(indio_dev, &st->data, - iio_get_time_ns(indio_dev)); + iio_push_to_buffers_with_ts(indio_dev, &st->data, sizeof(st->data), + iio_get_time_ns(indio_dev)); error_ret: iio_trigger_notify_done(indio_dev->trig); /* The rising edge of the CONVST signal starts a new conversion. */ @@ -693,8 +619,8 @@ static int ad7606_scan_direct(struct iio_dev *indio_dev, unsigned int ch, int *val) { struct ad7606_state *st = iio_priv(indio_dev); - unsigned int realbits = st->chip_info->channels[1].scan_type.realbits; const struct iio_chan_spec *chan; + unsigned int realbits; int ret; if (st->gpio_convst) { @@ -711,7 +637,7 @@ static int ad7606_scan_direct(struct iio_dev *indio_dev, unsigned int ch, * will not happen because IIO_CHAN_INFO_RAW is not supported for the backend. * TODO: Add support for reading a single value when the backend is used. */ - if (!st->back) { + if (st->trig) { ret = wait_for_completion_timeout(&st->completion, msecs_to_jiffies(1000)); if (!ret) { @@ -719,25 +645,30 @@ static int ad7606_scan_direct(struct iio_dev *indio_dev, unsigned int ch, goto error_ret; } } else { - fsleep(1); + /* + * If the BUSY interrupt is not available, wait enough time for + * the longest possible conversion (max for the whole family is + * around 350us). + */ + fsleep(400); } ret = ad7606_read_samples(st); if (ret) goto error_ret; - chan = &indio_dev->channels[ch + 1]; - if (chan->scan_type.sign == 'u') { - if (realbits > 16) - *val = st->data.buf32[ch]; - else - *val = st->data.buf16[ch]; - } else { - if (realbits > 16) - *val = sign_extend32(st->data.buf32[ch], realbits - 1); - else - *val = sign_extend32(st->data.buf16[ch], realbits - 1); - } + chan = &indio_dev->channels[ch]; + realbits = chan->scan_type.realbits; + + if (realbits > 16) + *val = st->data.buf32[ch]; + else + *val = st->data.buf16[ch]; + + *val &= GENMASK(realbits - 1, 0); + + if (chan->scan_type.sign == 's') + *val = sign_extend32(*val, realbits - 1); error_ret: if (!st->gpio_convst) { @@ -765,14 +696,14 @@ static int ad7606_read_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_RAW: if (!iio_device_claim_direct(indio_dev)) return -EBUSY; - ret = ad7606_scan_direct(indio_dev, chan->address, val); + ret = ad7606_scan_direct(indio_dev, chan->scan_index, val); iio_device_release_direct(indio_dev); if (ret < 0) return ret; return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: if (st->sw_mode_en) - ch = chan->address; + ch = chan->scan_index; cs = &st->chan_scales[ch]; *val = cs->scale_avail[cs->range][0]; *val2 = cs->scale_avail[cs->range][1]; @@ -781,10 +712,6 @@ static int ad7606_read_raw(struct iio_dev *indio_dev, *val = st->oversampling; return IIO_VAL_INT; case IIO_CHAN_INFO_SAMP_FREQ: - /* - * TODO: return the real frequency intead of the requested one once - * pwm_get_state_hw comes upstream. - */ pwm_get_state(st->cnvst_pwm, &cnvst_pwm_state); *val = DIV_ROUND_CLOSEST_ULL(NSEC_PER_SEC, cnvst_pwm_state.period); return IIO_VAL_INT; @@ -854,7 +781,7 @@ static int ad7606_write_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_SCALE: if (st->sw_mode_en) - ch = chan->address; + ch = chan->scan_index; cs = &st->chan_scales[ch]; for (i = 0; i < cs->num_scales; i++) { scale_avail_uv[i] = cs->scale_avail[i][0] * MICRO + @@ -1061,7 +988,7 @@ static int ad7606_read_avail(struct iio_dev *indio_dev, case IIO_CHAN_INFO_SCALE: if (st->sw_mode_en) - ch = chan->address; + ch = chan->scan_index; cs = &st->chan_scales[ch]; *vals = (int *)cs->scale_avail; @@ -1276,29 +1203,91 @@ static int ad7606b_sw_mode_setup(struct iio_dev *indio_dev) return st->bops->sw_mode_config(indio_dev); } -static int ad7606_chan_scales_setup(struct iio_dev *indio_dev) +static int ad7606_probe_channels(struct iio_dev *indio_dev) { struct ad7606_state *st = iio_priv(indio_dev); - unsigned int offset = indio_dev->num_channels - st->chip_info->num_adc_channels; - struct iio_chan_spec *chans; - size_t size; - int ch, ret; - - /* Clone IIO channels, since some may be differential */ - size = indio_dev->num_channels * sizeof(*indio_dev->channels); - chans = devm_kzalloc(st->dev, size, GFP_KERNEL); - if (!chans) + struct device *dev = indio_dev->dev.parent; + struct iio_chan_spec *channels; + bool slow_bus; + int ret, i; + + slow_bus = !(st->bops->iio_backend_config || st->offload_en); + indio_dev->num_channels = st->chip_info->num_adc_channels; + + /* Slow buses also get 1 more channel for soft timestamp */ + if (slow_bus) + indio_dev->num_channels++; + + channels = devm_kcalloc(dev, indio_dev->num_channels, sizeof(*channels), + GFP_KERNEL); + if (!channels) return -ENOMEM; - memcpy(chans, indio_dev->channels, size); - indio_dev->channels = chans; + for (i = 0; i < st->chip_info->num_adc_channels; i++) { + struct iio_chan_spec *chan = &channels[i]; - for (ch = 0; ch < st->chip_info->num_adc_channels; ch++) { - ret = st->chip_info->scale_setup_cb(indio_dev, &chans[ch + offset], ch); + chan->type = IIO_VOLTAGE; + chan->indexed = 1; + chan->channel = i; + chan->scan_index = i; + chan->scan_type.sign = 's'; + chan->scan_type.realbits = st->chip_info->bits; + /* + * If in SPI offload mode, storagebits are set based + * on the spi-engine hw implementation. + */ + chan->scan_type.storagebits = st->offload_en ? + st->chip_info->offload_storagebits : + (st->chip_info->bits > 16 ? 32 : 16); + + chan->scan_type.endianness = IIO_CPU; + + if (indio_dev->modes & INDIO_DIRECT_MODE) + chan->info_mask_separate |= BIT(IIO_CHAN_INFO_RAW); + + if (st->sw_mode_en) { + chan->info_mask_separate |= BIT(IIO_CHAN_INFO_SCALE); + chan->info_mask_separate_available |= + BIT(IIO_CHAN_INFO_SCALE); + + /* + * All chips with software mode support oversampling, + * so we skip the oversampling_available check. And the + * shared_by_type instead of shared_by_all on slow + * buses is for backward compatibility. + */ + if (slow_bus) + chan->info_mask_shared_by_type |= + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO); + else + chan->info_mask_shared_by_all |= + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO); + + chan->info_mask_shared_by_all_available |= + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO); + } else { + chan->info_mask_shared_by_type |= + BIT(IIO_CHAN_INFO_SCALE); + + if (st->chip_info->oversampling_avail) + chan->info_mask_shared_by_all |= + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO); + } + + if (!slow_bus) + chan->info_mask_shared_by_all |= + BIT(IIO_CHAN_INFO_SAMP_FREQ); + + ret = st->chip_info->scale_setup_cb(indio_dev, chan); if (ret) return ret; } + if (slow_bus) + channels[i] = (struct iio_chan_spec)IIO_CHAN_SOFT_TIMESTAMP(i); + + indio_dev->channels = channels; + return 0; } @@ -1322,11 +1311,19 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address, st = iio_priv(indio_dev); dev_set_drvdata(dev, indio_dev); + ret = devm_mutex_init(dev, &st->lock); + if (ret) + return ret; + st->dev = dev; - mutex_init(&st->lock); st->bops = bops; st->base_address = base_address; st->oversampling = 1; + st->sw_mode_en = device_property_read_bool(dev, "adi,sw-mode"); + + if (st->sw_mode_en && !chip_info->sw_setup_cb) + return dev_err_probe(dev, -EINVAL, + "Software mode is not supported for this chip\n"); ret = devm_regulator_get_enable(dev, "avcc"); if (ret) @@ -1355,10 +1352,21 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address, else indio_dev->info = &ad7606_info_no_os_or_range; } - indio_dev->modes = INDIO_DIRECT_MODE; + + /* AXI ADC backend doesn't support single read. */ + indio_dev->modes = st->bops->iio_backend_config ? 0 : INDIO_DIRECT_MODE; indio_dev->name = chip_info->name; - indio_dev->channels = st->chip_info->channels; - indio_dev->num_channels = st->chip_info->num_channels; + + /* Using spi-engine with offload support ? */ + if (st->bops->offload_config) { + ret = st->bops->offload_config(dev, indio_dev); + if (ret) + return ret; + } + + ret = ad7606_probe_channels(indio_dev); + if (ret) + return ret; ret = ad7606_reset(st); if (ret) @@ -1371,7 +1379,7 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address, } /* If convst pin is not defined, setup PWM. */ - if (!st->gpio_convst) { + if (!st->gpio_convst || st->offload_en) { st->cnvst_pwm = devm_pwm_get(dev, NULL); if (IS_ERR(st->cnvst_pwm)) return PTR_ERR(st->cnvst_pwm); @@ -1401,8 +1409,7 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address, * If there is a backend, the PWM should not overpass the maximum sampling * frequency the chip supports. */ - ret = ad7606_set_sampling_freq(st, - chip_info->max_samplerate ? : 2 * KILO); + ret = ad7606_set_sampling_freq(st, chip_info->max_samplerate); if (ret) return ret; @@ -1411,8 +1418,7 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address, return ret; indio_dev->setup_ops = &ad7606_backend_buffer_ops; - } else { - + } else if (!st->offload_en) { /* Reserve the PWM use only for backend (force gpio_convst definition) */ if (!st->gpio_convst) return dev_err_probe(dev, -EINVAL, @@ -1450,17 +1456,12 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address, st->write_scale = ad7606_write_scale_hw; st->write_os = ad7606_write_os_hw; - st->sw_mode_en = st->chip_info->sw_setup_cb && - device_property_present(st->dev, "adi,sw-mode"); - if (st->sw_mode_en) { + /* Offload needs 1 DOUT line, applying this setting in sw_setup_cb. */ + if (st->sw_mode_en || st->offload_en) { indio_dev->info = &ad7606_info_sw_mode; st->chip_info->sw_setup_cb(indio_dev); } - ret = ad7606_chan_scales_setup(indio_dev); - if (ret) - return ret; - return devm_iio_device_register(dev, indio_dev); } EXPORT_SYMBOL_NS_GPL(ad7606_probe, "IIO_AD7606"); diff --git a/drivers/iio/adc/ad7606.h b/drivers/iio/adc/ad7606.h index 71a30525eaab..441e62c521bc 100644 --- a/drivers/iio/adc/ad7606.h +++ b/drivers/iio/adc/ad7606.h @@ -40,119 +40,48 @@ #define AD7606_RANGE_CH_ADDR(ch) (0x03 + ((ch) >> 1)) #define AD7606_OS_MODE 0x08 -#define AD760X_CHANNEL(num, mask_sep, mask_type, mask_all, \ - mask_sep_avail, mask_all_avail, bits) { \ - .type = IIO_VOLTAGE, \ - .indexed = 1, \ - .channel = num, \ - .address = num, \ - .info_mask_separate = mask_sep, \ - .info_mask_separate_available = \ - mask_sep_avail, \ - .info_mask_shared_by_type = mask_type, \ - .info_mask_shared_by_all = mask_all, \ - .info_mask_shared_by_all_available = \ - mask_all_avail, \ - .scan_index = num, \ - .scan_type = { \ - .sign = 's', \ - .realbits = (bits), \ - .storagebits = (bits) > 16 ? 32 : 16, \ - .endianness = IIO_CPU, \ - }, \ -} - -#define AD7606_SW_CHANNEL(num, bits) \ - AD760X_CHANNEL(num, \ - /* mask separate */ \ - BIT(IIO_CHAN_INFO_RAW) | \ - BIT(IIO_CHAN_INFO_SCALE), \ - /* mask type */ \ - BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ - /* mask all */ \ - 0, \ - /* mask separate available */ \ - BIT(IIO_CHAN_INFO_SCALE), \ - /* mask all available */ \ - BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ - bits) - -#define AD7605_CHANNEL(num) \ - AD760X_CHANNEL(num, BIT(IIO_CHAN_INFO_RAW), \ - BIT(IIO_CHAN_INFO_SCALE), 0, 0, 0, 16) - -#define AD7606_CHANNEL(num, bits) \ - AD760X_CHANNEL(num, BIT(IIO_CHAN_INFO_RAW), \ - BIT(IIO_CHAN_INFO_SCALE), \ - BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ - 0, 0, bits) - -#define AD7616_CHANNEL(num) AD7606_SW_CHANNEL(num, 16) - -#define AD7606_BI_CHANNEL(num) \ - AD760X_CHANNEL(num, 0, \ - BIT(IIO_CHAN_INFO_SCALE), \ - BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ - BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ - 0, 0, 16) - -#define AD7606_BI_SW_CHANNEL(num) \ - AD760X_CHANNEL(num, \ - /* mask separate */ \ - BIT(IIO_CHAN_INFO_SCALE), \ - /* mask type */ \ - 0, \ - /* mask all */ \ - BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ - BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ - /* mask separate available */ \ - BIT(IIO_CHAN_INFO_SCALE), \ - /* mask all available */ \ - BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ - 16) - struct ad7606_state; typedef int (*ad7606_scale_setup_cb_t)(struct iio_dev *indio_dev, - struct iio_chan_spec *chan, int ch); + struct iio_chan_spec *chan); typedef int (*ad7606_sw_setup_cb_t)(struct iio_dev *indio_dev); /** * struct ad7606_chip_info - chip specific information - * @channels: channel specification - * @max_samplerate: maximum supported samplerate - * @name device name - * @num_channels: number of channels - * @num_adc_channels the number of channels the ADC actually inputs. + * @max_samplerate: maximum supported sample rate + * @name: device name + * @bits: data width in bits + * @num_adc_channels: the number of physical voltage inputs * @scale_setup_cb: callback to setup the scales for each channel * @sw_setup_cb: callback to setup the software mode if available. - * @oversampling_avail pointer to the array which stores the available + * @oversampling_avail: pointer to the array which stores the available * oversampling ratios. - * @oversampling_num number of elements stored in oversampling_avail array - * @os_req_reset some devices require a reset to update oversampling - * @init_delay_ms required delay in milliseconds for initialization + * @oversampling_num: number of elements stored in oversampling_avail array + * @os_req_reset: some devices require a reset to update oversampling + * @init_delay_ms: required delay in milliseconds for initialization * after a restart + * @offload_storagebits: storage bits used by the offload hw implementation */ struct ad7606_chip_info { - const struct iio_chan_spec *channels; unsigned int max_samplerate; const char *name; + unsigned int bits; unsigned int num_adc_channels; - unsigned int num_channels; ad7606_scale_setup_cb_t scale_setup_cb; ad7606_sw_setup_cb_t sw_setup_cb; const unsigned int *oversampling_avail; unsigned int oversampling_num; bool os_req_reset; unsigned long init_delay_ms; + u8 offload_storagebits; }; /** * struct ad7606_chan_scale - channel scale configuration - * @scale_avail pointer to the array which stores the available scales - * @num_scales number of elements stored in the scale_avail array - * @range voltage range selection, selects which scale to apply - * @reg_offset offset for the register value, to be applied when + * @scale_avail: pointer to the array which stores the available scales + * @num_scales: number of elements stored in the scale_avail array + * @range: voltage range selection, selects which scale to apply + * @reg_offset: offset for the register value, to be applied when * writing the value of 'range' to the register value */ struct ad7606_chan_scale { @@ -165,32 +94,35 @@ struct ad7606_chan_scale { /** * struct ad7606_state - driver instance specific data - * @dev pointer to kernel device - * @chip_info entry in the table of chips that describes this device - * @bops bus operations (SPI or parallel) - * @chan_scales scale configuration for channels - * @oversampling oversampling selection - * @cnvst_pwm pointer to the PWM device connected to the cnvst pin - * @base_address address from where to read data in parallel operation - * @sw_mode_en software mode enabled - * @oversampling_avail pointer to the array which stores the available + * @dev: pointer to kernel device + * @chip_info: entry in the table of chips that describes this device + * @bops: bus operations (SPI or parallel) + * @chan_scales: scale configuration for channels + * @oversampling: oversampling selection + * @cnvst_pwm: pointer to the PWM device connected to the cnvst pin + * @base_address: address from where to read data in parallel operation + * @sw_mode_en: software mode enabled + * @oversampling_avail: pointer to the array which stores the available * oversampling ratios. - * @num_os_ratios number of elements stored in oversampling_avail array - * @write_scale pointer to the function which writes the scale - * @write_os pointer to the function which writes the os - * @lock protect sensor state from concurrent accesses to GPIOs - * @gpio_convst GPIO descriptor for conversion start signal (CONVST) - * @gpio_reset GPIO descriptor for device hard-reset - * @gpio_range GPIO descriptor for range selection - * @gpio_standby GPIO descriptor for stand-by signal (STBY), + * @num_os_ratios: number of elements stored in oversampling_avail array + * @back: pointer to the iio_backend structure, if used + * @write_scale: pointer to the function which writes the scale + * @write_os: pointer to the function which writes the os + * @lock: protect sensor state from concurrent accesses to GPIOs + * @gpio_convst: GPIO descriptor for conversion start signal (CONVST) + * @gpio_reset: GPIO descriptor for device hard-reset + * @gpio_range: GPIO descriptor for range selection + * @gpio_standby: GPIO descriptor for stand-by signal (STBY), * controls power-down mode of device - * @gpio_frstdata GPIO descriptor for reading from device when data + * @gpio_frstdata: GPIO descriptor for reading from device when data * is being read on the first channel - * @gpio_os GPIO descriptors to control oversampling on the device - * @complete completion to indicate end of conversion - * @trig The IIO trigger associated with the device. - * @data buffer for reading data from the device - * @d16 be16 buffer for reading data from the device + * @gpio_os: GPIO descriptors to control oversampling on the device + * @trig: The IIO trigger associated with the device. + * @completion: completion to indicate end of conversion + * @data: buffer for reading data from the device + * @offload_en: SPI offload enabled + * @bus_data: bus-specific variables + * @d16: be16 buffer for reading data from the device */ struct ad7606_state { struct device *dev; @@ -217,36 +149,44 @@ struct ad7606_state { struct iio_trigger *trig; struct completion completion; + bool offload_en; + void *bus_data; + /* * DMA (thus cache coherency maintenance) may require the * transfer buffers to live in their own cache lines. - * 16 * 16-bit samples + 64-bit timestamp - for AD7616 - * 8 * 32-bit samples + 64-bit timestamp - for AD7616C-18 (and similar) + * 16 * 16-bit samples for AD7616 + * 8 * 32-bit samples for AD7616C-18 (and similar) */ - union { - u16 buf16[20]; - u32 buf32[10]; + struct { + union { + u16 buf16[16]; + u32 buf32[8]; + }; + aligned_s64 timestamp; } data __aligned(IIO_DMA_MINALIGN); __be16 d16[2]; }; /** * struct ad7606_bus_ops - driver bus operations - * @iio_backend_config function pointer for configuring the iio_backend for + * @iio_backend_config: function pointer for configuring the iio_backend for * the compatibles that use it - * @read_block function pointer for reading blocks of data + * @read_block: function pointer for reading blocks of data * @sw_mode_config: pointer to a function which configured the device * for software mode - * @reg_read function pointer for reading spi register - * @reg_write function pointer for writing spi register - * @write_mask function pointer for write spi register with mask - * @update_scan_mode function pointer for handling the calls to iio_info's update_scan - * mode when enabling/disabling channels. - * @rd_wr_cmd pointer to the function which calculates the spi address + * @offload_config: function pointer for configuring offload support, + * where any + * @reg_read: function pointer for reading spi register + * @reg_write: function pointer for writing spi register + * @update_scan_mode: function pointer for handling the calls to iio_info's + * update_scan mode when enabling/disabling channels. + * @rd_wr_cmd: pointer to the function which calculates the spi address */ struct ad7606_bus_ops { /* more methods added in future? */ int (*iio_backend_config)(struct device *dev, struct iio_dev *indio_dev); + int (*offload_config)(struct device *dev, struct iio_dev *indio_dev); int (*read_block)(struct device *dev, int num, void *data); int (*sw_mode_config)(struct iio_dev *indio_dev); int (*reg_read)(struct ad7606_state *st, unsigned int addr); @@ -254,13 +194,13 @@ struct ad7606_bus_ops { unsigned int addr, unsigned int val); int (*update_scan_mode)(struct iio_dev *indio_dev, const unsigned long *scan_mask); - u16 (*rd_wr_cmd)(int addr, char isWriteOp); + u16 (*rd_wr_cmd)(int addr, char is_write_op); }; /** - * struct ad7606_bus_info - agregate ad7606_chip_info and ad7606_bus_ops - * @chip_info entry in the table of chips that describes this device - * @bops bus operations (SPI or parallel) + * struct ad7606_bus_info - aggregate ad7606_chip_info and ad7606_bus_ops + * @chip_info: entry in the table of chips that describes this device + * @bops: bus operations (SPI or parallel) */ struct ad7606_bus_info { const struct ad7606_chip_info *chip_info; @@ -272,6 +212,8 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address, const struct ad7606_bus_ops *bops); int ad7606_reset(struct ad7606_state *st); +int ad7606_pwm_set_swing(struct ad7606_state *st); +int ad7606_pwm_set_low(struct ad7606_state *st); extern const struct ad7606_chip_info ad7605_4_info; extern const struct ad7606_chip_info ad7606_8_info; diff --git a/drivers/iio/adc/ad7606_par.c b/drivers/iio/adc/ad7606_par.c index 335fb481bfde..634852c4bbd2 100644 --- a/drivers/iio/adc/ad7606_par.c +++ b/drivers/iio/adc/ad7606_par.c @@ -21,28 +21,6 @@ #include "ad7606.h" #include "ad7606_bus_iface.h" -static const struct iio_chan_spec ad7606b_bi_channels[] = { - AD7606_BI_CHANNEL(0), - AD7606_BI_CHANNEL(1), - AD7606_BI_CHANNEL(2), - AD7606_BI_CHANNEL(3), - AD7606_BI_CHANNEL(4), - AD7606_BI_CHANNEL(5), - AD7606_BI_CHANNEL(6), - AD7606_BI_CHANNEL(7), -}; - -static const struct iio_chan_spec ad7606b_bi_sw_channels[] = { - AD7606_BI_SW_CHANNEL(0), - AD7606_BI_SW_CHANNEL(1), - AD7606_BI_SW_CHANNEL(2), - AD7606_BI_SW_CHANNEL(3), - AD7606_BI_SW_CHANNEL(4), - AD7606_BI_SW_CHANNEL(5), - AD7606_BI_SW_CHANNEL(6), - AD7606_BI_SW_CHANNEL(7), -}; - static int ad7606_par_bus_update_scan_mode(struct iio_dev *indio_dev, const unsigned long *scan_mask) { @@ -94,9 +72,6 @@ static int ad7606_par_bus_setup_iio_backend(struct device *dev, return ret; } - indio_dev->channels = ad7606b_bi_channels; - indio_dev->num_channels = 8; - return 0; } @@ -120,19 +95,11 @@ static int ad7606_par_bus_reg_write(struct ad7606_state *st, unsigned int addr, return pdata->bus_reg_write(st->back, addr, val); } -static int ad7606_par_bus_sw_mode_config(struct iio_dev *indio_dev) -{ - indio_dev->channels = ad7606b_bi_sw_channels; - - return 0; -} - static const struct ad7606_bus_ops ad7606_bi_bops = { .iio_backend_config = ad7606_par_bus_setup_iio_backend, .update_scan_mode = ad7606_par_bus_update_scan_mode, .reg_read = ad7606_par_bus_reg_read, .reg_write = ad7606_par_bus_reg_write, - .sw_mode_config = ad7606_par_bus_sw_mode_config, }; static int ad7606_par16_read_block(struct device *dev, @@ -255,6 +222,8 @@ static const struct platform_device_id ad7606_driver_ids[] = { { .name = "ad7606-6", .driver_data = (kernel_ulong_t)&ad7606_6_info, }, { .name = "ad7606-8", .driver_data = (kernel_ulong_t)&ad7606_8_info, }, { .name = "ad7606b", .driver_data = (kernel_ulong_t)&ad7606b_info, }, + { .name = "ad7606c-16", .driver_data = (kernel_ulong_t)&ad7606c_16_info }, + { .name = "ad7606c-18", .driver_data = (kernel_ulong_t)&ad7606c_18_info }, { .name = "ad7607", .driver_data = (kernel_ulong_t)&ad7607_info, }, { .name = "ad7608", .driver_data = (kernel_ulong_t)&ad7608_info, }, { .name = "ad7609", .driver_data = (kernel_ulong_t)&ad7609_info, }, @@ -268,6 +237,8 @@ static const struct of_device_id ad7606_of_match[] = { { .compatible = "adi,ad7606-6", .data = &ad7606_6_info }, { .compatible = "adi,ad7606-8", .data = &ad7606_8_info }, { .compatible = "adi,ad7606b", .data = &ad7606b_info }, + { .compatible = "adi,ad7606c-16", .data = &ad7606c_16_info }, + { .compatible = "adi,ad7606c-18", .data = &ad7606c_18_info }, { .compatible = "adi,ad7607", .data = &ad7607_info }, { .compatible = "adi,ad7608", .data = &ad7608_info }, { .compatible = "adi,ad7609", .data = &ad7609_info }, diff --git a/drivers/iio/adc/ad7606_spi.c b/drivers/iio/adc/ad7606_spi.c index 179115e90988..f28e4ca37707 100644 --- a/drivers/iio/adc/ad7606_spi.c +++ b/drivers/iio/adc/ad7606_spi.c @@ -5,70 +5,43 @@ * Copyright 2011 Analog Devices Inc. */ +#include <linux/bitmap.h> #include <linux/err.h> +#include <linux/math.h> #include <linux/module.h> +#include <linux/pwm.h> +#include <linux/spi/offload/consumer.h> +#include <linux/spi/offload/provider.h> #include <linux/spi/spi.h> #include <linux/types.h> +#include <linux/units.h> +#include <linux/iio/buffer-dmaengine.h> #include <linux/iio/iio.h> -#include "ad7606.h" -#define MAX_SPI_FREQ_HZ 23500000 /* VDRIVE above 4.75 V */ +#include <dt-bindings/iio/adc/adi,ad7606.h> -static const struct iio_chan_spec ad7616_sw_channels[] = { - IIO_CHAN_SOFT_TIMESTAMP(16), - AD7616_CHANNEL(0), - AD7616_CHANNEL(1), - AD7616_CHANNEL(2), - AD7616_CHANNEL(3), - AD7616_CHANNEL(4), - AD7616_CHANNEL(5), - AD7616_CHANNEL(6), - AD7616_CHANNEL(7), - AD7616_CHANNEL(8), - AD7616_CHANNEL(9), - AD7616_CHANNEL(10), - AD7616_CHANNEL(11), - AD7616_CHANNEL(12), - AD7616_CHANNEL(13), - AD7616_CHANNEL(14), - AD7616_CHANNEL(15), -}; +#include "ad7606.h" -static const struct iio_chan_spec ad7606b_sw_channels[] = { - IIO_CHAN_SOFT_TIMESTAMP(8), - AD7606_SW_CHANNEL(0, 16), - AD7606_SW_CHANNEL(1, 16), - AD7606_SW_CHANNEL(2, 16), - AD7606_SW_CHANNEL(3, 16), - AD7606_SW_CHANNEL(4, 16), - AD7606_SW_CHANNEL(5, 16), - AD7606_SW_CHANNEL(6, 16), - AD7606_SW_CHANNEL(7, 16), -}; +#define MAX_SPI_FREQ_HZ 23500000 /* VDRIVE above 4.75 V */ -static const struct iio_chan_spec ad7606c_18_sw_channels[] = { - IIO_CHAN_SOFT_TIMESTAMP(8), - AD7606_SW_CHANNEL(0, 18), - AD7606_SW_CHANNEL(1, 18), - AD7606_SW_CHANNEL(2, 18), - AD7606_SW_CHANNEL(3, 18), - AD7606_SW_CHANNEL(4, 18), - AD7606_SW_CHANNEL(5, 18), - AD7606_SW_CHANNEL(6, 18), - AD7606_SW_CHANNEL(7, 18), +struct spi_bus_data { + struct spi_offload *offload; + struct spi_offload_trigger *offload_trigger; + struct spi_transfer offload_xfer; + struct spi_message offload_msg; }; -static u16 ad7616_spi_rd_wr_cmd(int addr, char isWriteOp) +static u16 ad7616_spi_rd_wr_cmd(int addr, char is_write_op) { /* * The address of register consist of one w/r bit * 6 bits of address followed by one reserved bit. */ - return ((addr & 0x7F) << 1) | ((isWriteOp & 0x1) << 7); + return ((addr & 0x7F) << 1) | ((is_write_op & 0x1) << 7); } -static u16 ad7606B_spi_rd_wr_cmd(int addr, char is_write_op) +static u16 ad7606b_spi_rd_wr_cmd(int addr, char is_write_op) { /* * The address of register consists of one bit which @@ -155,87 +128,275 @@ static int ad7606_spi_reg_write(struct ad7606_state *st, struct spi_device *spi = to_spi_device(st->dev); st->d16[0] = cpu_to_be16((st->bops->rd_wr_cmd(addr, 1) << 8) | - (val & 0x1FF)); + (val & 0xFF)); return spi_write(spi, &st->d16[0], sizeof(st->d16[0])); } -static int ad7616_sw_mode_config(struct iio_dev *indio_dev) +static int ad7606b_sw_mode_config(struct iio_dev *indio_dev) { + struct ad7606_state *st = iio_priv(indio_dev); + + /* Configure device spi to output on a single channel */ + return st->bops->reg_write(st, AD7606_CONFIGURATION_REGISTER, + AD7606_SINGLE_DOUT); +} + +static const struct spi_offload_config ad7606_spi_offload_config = { + .capability_flags = SPI_OFFLOAD_CAP_TRIGGER | + SPI_OFFLOAD_CAP_RX_STREAM_DMA, +}; + +static int ad7606_spi_offload_buffer_postenable(struct iio_dev *indio_dev) +{ + const struct iio_scan_type *scan_type; + struct ad7606_state *st = iio_priv(indio_dev); + struct spi_bus_data *bus_data = st->bus_data; + struct spi_transfer *xfer = &bus_data->offload_xfer; + struct spi_device *spi = to_spi_device(st->dev); + struct spi_offload_trigger_config config = { + .type = SPI_OFFLOAD_TRIGGER_DATA_READY, + }; + int ret; + + scan_type = &indio_dev->channels[0].scan_type; + + xfer->bits_per_word = scan_type->realbits; + xfer->offload_flags = SPI_OFFLOAD_XFER_RX_STREAM; /* - * Scale can be configured individually for each channel - * in software mode. + * Using SPI offload, storagebits are related to the spi-engine + * hw implementation, can be 16 or 32, so can't be used to compute + * struct spi_transfer.len. Using realbits instead. */ - indio_dev->channels = ad7616_sw_channels; + xfer->len = (scan_type->realbits > 16 ? 4 : 2) * + st->chip_info->num_adc_channels; + + spi_message_init_with_transfers(&bus_data->offload_msg, xfer, 1); + bus_data->offload_msg.offload = bus_data->offload; + + ret = spi_optimize_message(spi, &bus_data->offload_msg); + if (ret) { + dev_err(st->dev, "failed to prepare offload, err: %d\n", ret); + return ret; + } + + ret = spi_offload_trigger_enable(bus_data->offload, + bus_data->offload_trigger, + &config); + if (ret) + goto err_unoptimize_message; + + ret = ad7606_pwm_set_swing(st); + if (ret) + goto err_offload_exit_conversion_mode; return 0; + +err_offload_exit_conversion_mode: + spi_offload_trigger_disable(bus_data->offload, + bus_data->offload_trigger); + +err_unoptimize_message: + spi_unoptimize_message(&bus_data->offload_msg); + + return ret; } -static int ad7606B_sw_mode_config(struct iio_dev *indio_dev) +static int ad7606_spi_offload_buffer_predisable(struct iio_dev *indio_dev) { struct ad7606_state *st = iio_priv(indio_dev); + struct spi_bus_data *bus_data = st->bus_data; + int ret; - /* Configure device spi to output on a single channel */ - st->bops->reg_write(st, - AD7606_CONFIGURATION_REGISTER, - AD7606_SINGLE_DOUT); + ret = ad7606_pwm_set_low(st); + if (ret) + return ret; + + spi_offload_trigger_disable(bus_data->offload, + bus_data->offload_trigger); + spi_unoptimize_message(&bus_data->offload_msg); + + return 0; +} + +static const struct iio_buffer_setup_ops ad7606_offload_buffer_setup_ops = { + .postenable = ad7606_spi_offload_buffer_postenable, + .predisable = ad7606_spi_offload_buffer_predisable, +}; + +static bool ad7606_spi_offload_trigger_match( + struct spi_offload_trigger *trigger, + enum spi_offload_trigger_type type, + u64 *args, u32 nargs) +{ + if (type != SPI_OFFLOAD_TRIGGER_DATA_READY) + return false; /* - * Scale can be configured individually for each channel - * in software mode. + * Requires 1 arg: + * args[0] is the trigger event. */ - indio_dev->channels = ad7606b_sw_channels; + if (nargs != 1 || args[0] != AD7606_TRIGGER_EVENT_BUSY) + return false; + + return true; +} + +static int ad7606_spi_offload_trigger_request( + struct spi_offload_trigger *trigger, + enum spi_offload_trigger_type type, + u64 *args, u32 nargs) +{ + /* Should already be validated by match, but just in case. */ + if (nargs != 1) + return -EINVAL; + + return 0; +} + +static int ad7606_spi_offload_trigger_validate( + struct spi_offload_trigger *trigger, + struct spi_offload_trigger_config *config) +{ + if (config->type != SPI_OFFLOAD_TRIGGER_DATA_READY) + return -EINVAL; return 0; } -static int ad7606c_18_sw_mode_config(struct iio_dev *indio_dev) +static const struct spi_offload_trigger_ops ad7606_offload_trigger_ops = { + .match = ad7606_spi_offload_trigger_match, + .request = ad7606_spi_offload_trigger_request, + .validate = ad7606_spi_offload_trigger_validate, +}; + +static int ad7606_spi_offload_probe(struct device *dev, + struct iio_dev *indio_dev) { + struct ad7606_state *st = iio_priv(indio_dev); + struct spi_device *spi = to_spi_device(dev); + struct spi_bus_data *bus_data; + struct dma_chan *rx_dma; + struct spi_offload_trigger_info trigger_info = { + .fwnode = dev_fwnode(dev), + .ops = &ad7606_offload_trigger_ops, + .priv = st, + }; int ret; - ret = ad7606B_sw_mode_config(indio_dev); + bus_data = devm_kzalloc(dev, sizeof(*bus_data), GFP_KERNEL); + if (!bus_data) + return -ENOMEM; + st->bus_data = bus_data; + + bus_data->offload = devm_spi_offload_get(dev, spi, + &ad7606_spi_offload_config); + ret = PTR_ERR_OR_ZERO(bus_data->offload); + if (ret && ret != -ENODEV) + return dev_err_probe(dev, ret, "failed to get SPI offload\n"); + /* Allow main ad7606_probe function to continue. */ + if (ret == -ENODEV) + return 0; + + ret = devm_spi_offload_trigger_register(dev, &trigger_info); if (ret) - return ret; + return dev_err_probe(dev, ret, + "failed to register offload trigger\n"); + + bus_data->offload_trigger = devm_spi_offload_trigger_get(dev, + bus_data->offload, SPI_OFFLOAD_TRIGGER_DATA_READY); + if (IS_ERR(bus_data->offload_trigger)) + return dev_err_probe(dev, PTR_ERR(bus_data->offload_trigger), + "failed to get offload trigger\n"); + + /* TODO: PWM setup should be ok, done for the backend. PWM mutex ? */ + rx_dma = devm_spi_offload_rx_stream_request_dma_chan(dev, + bus_data->offload); + if (IS_ERR(rx_dma)) + return dev_err_probe(dev, PTR_ERR(rx_dma), + "failed to get offload RX DMA\n"); + + ret = devm_iio_dmaengine_buffer_setup_with_handle(dev, indio_dev, + rx_dma, IIO_BUFFER_DIRECTION_IN); + if (ret) + return dev_err_probe(dev, ret, + "failed to setup offload RX DMA\n"); + + /* Use offload ops. */ + indio_dev->setup_ops = &ad7606_offload_buffer_setup_ops; - indio_dev->channels = ad7606c_18_sw_channels; + st->offload_en = true; + + return 0; +} + +static int ad7606_spi_update_scan_mode(struct iio_dev *indio_dev, + const unsigned long *scan_mask) +{ + struct ad7606_state *st = iio_priv(indio_dev); + + if (st->offload_en) { + unsigned int num_adc_ch = st->chip_info->num_adc_channels; + + /* + * SPI offload requires that all channels are enabled since + * there isn't a way to selectively disable channels that get + * read (this is simultaneous sampling ADC) and the DMA buffer + * has no way of demuxing the data to filter out unwanted + * channels. + */ + if (bitmap_weight(scan_mask, num_adc_ch) != num_adc_ch) + return -EINVAL; + } return 0; } static const struct ad7606_bus_ops ad7606_spi_bops = { + .offload_config = ad7606_spi_offload_probe, .read_block = ad7606_spi_read_block, + .update_scan_mode = ad7606_spi_update_scan_mode, }; static const struct ad7606_bus_ops ad7607_spi_bops = { + .offload_config = ad7606_spi_offload_probe, .read_block = ad7606_spi_read_block14to16, + .update_scan_mode = ad7606_spi_update_scan_mode, }; static const struct ad7606_bus_ops ad7608_spi_bops = { + .offload_config = ad7606_spi_offload_probe, .read_block = ad7606_spi_read_block18to32, + .update_scan_mode = ad7606_spi_update_scan_mode, }; static const struct ad7606_bus_ops ad7616_spi_bops = { + .offload_config = ad7606_spi_offload_probe, .read_block = ad7606_spi_read_block, .reg_read = ad7606_spi_reg_read, .reg_write = ad7606_spi_reg_write, .rd_wr_cmd = ad7616_spi_rd_wr_cmd, - .sw_mode_config = ad7616_sw_mode_config, + .update_scan_mode = ad7606_spi_update_scan_mode, }; static const struct ad7606_bus_ops ad7606b_spi_bops = { + .offload_config = ad7606_spi_offload_probe, .read_block = ad7606_spi_read_block, .reg_read = ad7606_spi_reg_read, .reg_write = ad7606_spi_reg_write, - .rd_wr_cmd = ad7606B_spi_rd_wr_cmd, - .sw_mode_config = ad7606B_sw_mode_config, + .rd_wr_cmd = ad7606b_spi_rd_wr_cmd, + .sw_mode_config = ad7606b_sw_mode_config, + .update_scan_mode = ad7606_spi_update_scan_mode, }; static const struct ad7606_bus_ops ad7606c_18_spi_bops = { + .offload_config = ad7606_spi_offload_probe, .read_block = ad7606_spi_read_block18to32, .reg_read = ad7606_spi_reg_read, .reg_write = ad7606_spi_reg_write, - .rd_wr_cmd = ad7606B_spi_rd_wr_cmd, - .sw_mode_config = ad7606c_18_sw_mode_config, + .rd_wr_cmd = ad7606b_spi_rd_wr_cmd, + .sw_mode_config = ad7606b_sw_mode_config, + .update_scan_mode = ad7606_spi_update_scan_mode, }; static const struct ad7606_bus_info ad7605_4_bus_info = { @@ -348,3 +509,4 @@ MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>"); MODULE_DESCRIPTION("Analog Devices AD7606 ADC"); MODULE_LICENSE("GPL v2"); MODULE_IMPORT_NS("IIO_AD7606"); +MODULE_IMPORT_NS("IIO_DMAENGINE_BUFFER"); diff --git a/drivers/iio/adc/ad7768-1.c b/drivers/iio/adc/ad7768-1.c index 5e0be36af0c5..51134023534a 100644 --- a/drivers/iio/adc/ad7768-1.c +++ b/drivers/iio/adc/ad7768-1.c @@ -4,14 +4,17 @@ * * Copyright 2017 Analog Devices Inc. */ +#include <linux/array_size.h> #include <linux/bitfield.h> #include <linux/clk.h> +#include <linux/completion.h> #include <linux/delay.h> #include <linux/device.h> #include <linux/err.h> #include <linux/gpio/consumer.h> -#include <linux/kernel.h> +#include <linux/interrupt.h> #include <linux/module.h> +#include <linux/regmap.h> #include <linux/regulator/consumer.h> #include <linux/sysfs.h> #include <linux/spi/spi.h> @@ -53,12 +56,15 @@ #define AD7768_REG_SPI_DIAG_ENABLE 0x28 #define AD7768_REG_ADC_DIAG_ENABLE 0x29 #define AD7768_REG_DIG_DIAG_ENABLE 0x2A -#define AD7768_REG_ADC_DATA 0x2C +#define AD7768_REG24_ADC_DATA 0x2C #define AD7768_REG_MASTER_STATUS 0x2D #define AD7768_REG_SPI_DIAG_STATUS 0x2E #define AD7768_REG_ADC_DIAG_STATUS 0x2F #define AD7768_REG_DIG_DIAG_STATUS 0x30 #define AD7768_REG_MCLK_COUNTER 0x31 +#define AD7768_REG_COEFF_CONTROL 0x32 +#define AD7768_REG24_COEFF_DATA 0x33 +#define AD7768_REG_ACCESS_KEY 0x34 /* AD7768_REG_POWER_CLOCK */ #define AD7768_PWR_MCLK_DIV_MSK GENMASK(5, 4) @@ -76,9 +82,6 @@ #define AD7768_CONV_MODE_MSK GENMASK(2, 0) #define AD7768_CONV_MODE(x) FIELD_PREP(AD7768_CONV_MODE_MSK, x) -#define AD7768_RD_FLAG_MSK(x) (BIT(6) | ((x) & 0x3F)) -#define AD7768_WR_FLAG_MSK(x) ((x) & 0x3F) - enum ad7768_conv_mode { AD7768_CONTINUOUS, AD7768_ONE_SHOT, @@ -153,6 +156,8 @@ static const struct iio_chan_spec ad7768_channels[] = { struct ad7768_state { struct spi_device *spi; + struct regmap *regmap; + struct regmap *regmap24; struct regulator *vref; struct clk *mclk; unsigned int mclk_freq; @@ -160,6 +165,7 @@ struct ad7768_state { struct completion completion; struct iio_trigger *trig; struct gpio_desc *gpio_sync_in; + struct gpio_desc *gpio_reset; const char *labels[ARRAY_SIZE(ad7768_channels)]; /* * DMA (thus cache coherency maintenance) may require the @@ -175,46 +181,82 @@ struct ad7768_state { } data __aligned(IIO_DMA_MINALIGN); }; -static int ad7768_spi_reg_read(struct ad7768_state *st, unsigned int addr, - unsigned int len) -{ - unsigned int shift; - int ret; +static const struct regmap_range ad7768_regmap_rd_ranges[] = { + regmap_reg_range(AD7768_REG_CHIP_TYPE, AD7768_REG_CHIP_GRADE), + regmap_reg_range(AD7768_REG_SCRATCH_PAD, AD7768_REG_SCRATCH_PAD), + regmap_reg_range(AD7768_REG_VENDOR_L, AD7768_REG_VENDOR_H), + regmap_reg_range(AD7768_REG_INTERFACE_FORMAT, AD7768_REG_GAIN_LO), + regmap_reg_range(AD7768_REG_SPI_DIAG_ENABLE, AD7768_REG_DIG_DIAG_ENABLE), + regmap_reg_range(AD7768_REG_MASTER_STATUS, AD7768_REG_COEFF_CONTROL), + regmap_reg_range(AD7768_REG_ACCESS_KEY, AD7768_REG_ACCESS_KEY), +}; - shift = 32 - (8 * len); - st->data.d8[0] = AD7768_RD_FLAG_MSK(addr); +static const struct regmap_access_table ad7768_regmap_rd_table = { + .yes_ranges = ad7768_regmap_rd_ranges, + .n_yes_ranges = ARRAY_SIZE(ad7768_regmap_rd_ranges), +}; - ret = spi_write_then_read(st->spi, st->data.d8, 1, - &st->data.d32, len); - if (ret < 0) - return ret; +static const struct regmap_range ad7768_regmap_wr_ranges[] = { + regmap_reg_range(AD7768_REG_SCRATCH_PAD, AD7768_REG_SCRATCH_PAD), + regmap_reg_range(AD7768_REG_INTERFACE_FORMAT, AD7768_REG_GPIO_WRITE), + regmap_reg_range(AD7768_REG_OFFSET_HI, AD7768_REG_GAIN_LO), + regmap_reg_range(AD7768_REG_SPI_DIAG_ENABLE, AD7768_REG_DIG_DIAG_ENABLE), + regmap_reg_range(AD7768_REG_SPI_DIAG_STATUS, AD7768_REG_SPI_DIAG_STATUS), + regmap_reg_range(AD7768_REG_COEFF_CONTROL, AD7768_REG_COEFF_CONTROL), + regmap_reg_range(AD7768_REG_ACCESS_KEY, AD7768_REG_ACCESS_KEY), +}; - return (be32_to_cpu(st->data.d32) >> shift); -} +static const struct regmap_access_table ad7768_regmap_wr_table = { + .yes_ranges = ad7768_regmap_wr_ranges, + .n_yes_ranges = ARRAY_SIZE(ad7768_regmap_wr_ranges), +}; -static int ad7768_spi_reg_write(struct ad7768_state *st, - unsigned int addr, - unsigned int val) -{ - st->data.d8[0] = AD7768_WR_FLAG_MSK(addr); - st->data.d8[1] = val & 0xFF; +static const struct regmap_config ad7768_regmap_config = { + .name = "ad7768-1-8", + .reg_bits = 8, + .val_bits = 8, + .read_flag_mask = BIT(6), + .rd_table = &ad7768_regmap_rd_table, + .wr_table = &ad7768_regmap_wr_table, + .max_register = AD7768_REG_ACCESS_KEY, + .use_single_write = true, + .use_single_read = true, +}; - return spi_write(st->spi, st->data.d8, 2); -} +static const struct regmap_range ad7768_regmap24_rd_ranges[] = { + regmap_reg_range(AD7768_REG24_ADC_DATA, AD7768_REG24_ADC_DATA), + regmap_reg_range(AD7768_REG24_COEFF_DATA, AD7768_REG24_COEFF_DATA), +}; -static int ad7768_set_mode(struct ad7768_state *st, - enum ad7768_conv_mode mode) -{ - int regval; +static const struct regmap_access_table ad7768_regmap24_rd_table = { + .yes_ranges = ad7768_regmap24_rd_ranges, + .n_yes_ranges = ARRAY_SIZE(ad7768_regmap24_rd_ranges), +}; - regval = ad7768_spi_reg_read(st, AD7768_REG_CONVERSION, 1); - if (regval < 0) - return regval; +static const struct regmap_range ad7768_regmap24_wr_ranges[] = { + regmap_reg_range(AD7768_REG24_COEFF_DATA, AD7768_REG24_COEFF_DATA), +}; - regval &= ~AD7768_CONV_MODE_MSK; - regval |= AD7768_CONV_MODE(mode); +static const struct regmap_access_table ad7768_regmap24_wr_table = { + .yes_ranges = ad7768_regmap24_wr_ranges, + .n_yes_ranges = ARRAY_SIZE(ad7768_regmap24_wr_ranges), +}; - return ad7768_spi_reg_write(st, AD7768_REG_CONVERSION, regval); +static const struct regmap_config ad7768_regmap24_config = { + .name = "ad7768-1-24", + .reg_bits = 8, + .val_bits = 24, + .read_flag_mask = BIT(6), + .rd_table = &ad7768_regmap24_rd_table, + .wr_table = &ad7768_regmap24_wr_table, + .max_register = AD7768_REG24_COEFF_DATA, +}; + +static int ad7768_set_mode(struct ad7768_state *st, + enum ad7768_conv_mode mode) +{ + return regmap_update_bits(st->regmap, AD7768_REG_CONVERSION, + AD7768_CONV_MODE_MSK, AD7768_CONV_MODE(mode)); } static int ad7768_scan_direct(struct iio_dev *indio_dev) @@ -233,9 +275,10 @@ static int ad7768_scan_direct(struct iio_dev *indio_dev) if (!ret) return -ETIMEDOUT; - readval = ad7768_spi_reg_read(st, AD7768_REG_ADC_DATA, 3); - if (readval < 0) - return readval; + ret = regmap_read(st->regmap24, AD7768_REG24_ADC_DATA, &readval); + if (ret) + return ret; + /* * Any SPI configuration of the AD7768-1 can only be * performed in continuous conversion mode. @@ -258,16 +301,23 @@ static int ad7768_reg_access(struct iio_dev *indio_dev, if (!iio_device_claim_direct(indio_dev)) return -EBUSY; + ret = -EINVAL; if (readval) { - ret = ad7768_spi_reg_read(st, reg, 1); - if (ret < 0) - goto err_release; - *readval = ret; - ret = 0; + if (regmap_check_range_table(st->regmap, reg, &ad7768_regmap_rd_table)) + ret = regmap_read(st->regmap, reg, readval); + + if (regmap_check_range_table(st->regmap24, reg, &ad7768_regmap24_rd_table)) + ret = regmap_read(st->regmap24, reg, readval); + } else { - ret = ad7768_spi_reg_write(st, reg, writeval); + if (regmap_check_range_table(st->regmap, reg, &ad7768_regmap_wr_table)) + ret = regmap_write(st->regmap, reg, writeval); + + if (regmap_check_range_table(st->regmap24, reg, &ad7768_regmap24_wr_table)) + ret = regmap_write(st->regmap24, reg, writeval); + } -err_release: + iio_device_release_direct(indio_dev); return ret; @@ -284,7 +334,7 @@ static int ad7768_set_dig_fil(struct ad7768_state *st, else mode = AD7768_DIG_FIL_DEC_RATE(dec_rate); - ret = ad7768_spi_reg_write(st, AD7768_REG_DIGITAL_FILTER, mode); + ret = regmap_write(st->regmap, AD7768_REG_DIGITAL_FILTER, mode); if (ret < 0) return ret; @@ -321,7 +371,7 @@ static int ad7768_set_freq(struct ad7768_state *st, */ pwr_mode = AD7768_PWR_MCLK_DIV(ad7768_clk_config[idx].mclk_div) | AD7768_PWR_PWRMODE(ad7768_clk_config[idx].pwrmode); - ret = ad7768_spi_reg_write(st, AD7768_REG_POWER_CLOCK, pwr_mode); + ret = regmap_write(st->regmap, AD7768_REG_POWER_CLOCK, pwr_mode); if (ret < 0) return ret; @@ -440,19 +490,30 @@ static int ad7768_setup(struct ad7768_state *st) { int ret; - /* - * Two writes to the SPI_RESET[1:0] bits are required to initiate - * a software reset. The bits must first be set to 11, and then - * to 10. When the sequence is detected, the reset occurs. - * See the datasheet, page 70. - */ - ret = ad7768_spi_reg_write(st, AD7768_REG_SYNC_RESET, 0x3); - if (ret) - return ret; + st->gpio_reset = devm_gpiod_get_optional(&st->spi->dev, "reset", + GPIOD_OUT_HIGH); + if (IS_ERR(st->gpio_reset)) + return PTR_ERR(st->gpio_reset); - ret = ad7768_spi_reg_write(st, AD7768_REG_SYNC_RESET, 0x2); - if (ret) - return ret; + if (st->gpio_reset) { + fsleep(10); + gpiod_set_value_cansleep(st->gpio_reset, 0); + fsleep(200); + } else { + /* + * Two writes to the SPI_RESET[1:0] bits are required to initiate + * a software reset. The bits must first be set to 11, and then + * to 10. When the sequence is detected, the reset occurs. + * See the datasheet, page 70. + */ + ret = regmap_write(st->regmap, AD7768_REG_SYNC_RESET, 0x3); + if (ret) + return ret; + + ret = regmap_write(st->regmap, AD7768_REG_SYNC_RESET, 0x2); + if (ret) + return ret; + } st->gpio_sync_in = devm_gpiod_get(&st->spi->dev, "adi,sync-in", GPIOD_OUT_LOW); @@ -474,8 +535,9 @@ static irqreturn_t ad7768_trigger_handler(int irq, void *p) if (ret < 0) goto out; - iio_push_to_buffers_with_timestamp(indio_dev, &st->data.scan, - iio_get_time_ns(indio_dev)); + iio_push_to_buffers_with_ts(indio_dev, &st->data.scan, + sizeof(st->data.scan), + iio_get_time_ns(indio_dev)); out: iio_trigger_notify_done(indio_dev->trig); @@ -505,18 +567,19 @@ static int ad7768_buffer_postenable(struct iio_dev *indio_dev) * continuous read mode. Subsequent data reads do not require an * initial 8-bit write to query the ADC_DATA register. */ - return ad7768_spi_reg_write(st, AD7768_REG_INTERFACE_FORMAT, 0x01); + return regmap_write(st->regmap, AD7768_REG_INTERFACE_FORMAT, 0x01); } static int ad7768_buffer_predisable(struct iio_dev *indio_dev) { struct ad7768_state *st = iio_priv(indio_dev); + unsigned int unused; /* * To exit continuous read mode, perform a single read of the ADC_DATA * reg (0x2C), which allows further configuration of the device. */ - return ad7768_spi_reg_read(st, AD7768_REG_ADC_DATA, 3); + return regmap_read(st->regmap24, AD7768_REG24_ADC_DATA, &unused); } static const struct iio_buffer_setup_ops ad7768_buffer_ops = { @@ -559,6 +622,31 @@ static int ad7768_set_channel_label(struct iio_dev *indio_dev, return 0; } +static int ad7768_triggered_buffer_alloc(struct iio_dev *indio_dev) +{ + struct ad7768_state *st = iio_priv(indio_dev); + int ret; + + st->trig = devm_iio_trigger_alloc(indio_dev->dev.parent, "%s-dev%d", + indio_dev->name, + iio_device_id(indio_dev)); + if (!st->trig) + return -ENOMEM; + + st->trig->ops = &ad7768_trigger_ops; + iio_trigger_set_drvdata(st->trig, indio_dev); + ret = devm_iio_trigger_register(indio_dev->dev.parent, st->trig); + if (ret) + return ret; + + indio_dev->trig = iio_trigger_get(st->trig); + + return devm_iio_triggered_buffer_setup(indio_dev->dev.parent, indio_dev, + &iio_pollfunc_store_time, + &ad7768_trigger_handler, + &ad7768_buffer_ops); +} + static int ad7768_probe(struct spi_device *spi) { struct ad7768_state *st; @@ -587,6 +675,16 @@ static int ad7768_probe(struct spi_device *spi) st->spi = spi; + st->regmap = devm_regmap_init_spi(spi, &ad7768_regmap_config); + if (IS_ERR(st->regmap)) + return dev_err_probe(&spi->dev, PTR_ERR(st->regmap), + "Failed to initialize regmap"); + + st->regmap24 = devm_regmap_init_spi(spi, &ad7768_regmap24_config); + if (IS_ERR(st->regmap24)) + return dev_err_probe(&spi->dev, PTR_ERR(st->regmap24), + "Failed to initialize regmap24"); + st->vref = devm_regulator_get(&spi->dev, "vref"); if (IS_ERR(st->vref)) return PTR_ERR(st->vref); @@ -619,20 +717,6 @@ static int ad7768_probe(struct spi_device *spi) return ret; } - st->trig = devm_iio_trigger_alloc(&spi->dev, "%s-dev%d", - indio_dev->name, - iio_device_id(indio_dev)); - if (!st->trig) - return -ENOMEM; - - st->trig->ops = &ad7768_trigger_ops; - iio_trigger_set_drvdata(st->trig, indio_dev); - ret = devm_iio_trigger_register(&spi->dev, st->trig); - if (ret) - return ret; - - indio_dev->trig = iio_trigger_get(st->trig); - init_completion(&st->completion); ret = ad7768_set_channel_label(indio_dev, ARRAY_SIZE(ad7768_channels)); @@ -646,10 +730,7 @@ static int ad7768_probe(struct spi_device *spi) if (ret) return ret; - ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev, - &iio_pollfunc_store_time, - &ad7768_trigger_handler, - &ad7768_buffer_ops); + ret = ad7768_triggered_buffer_alloc(indio_dev); if (ret) return ret; @@ -658,7 +739,7 @@ static int ad7768_probe(struct spi_device *spi) static const struct spi_device_id ad7768_id_table[] = { { "ad7768-1", 0 }, - {} + { } }; MODULE_DEVICE_TABLE(spi, ad7768_id_table); diff --git a/drivers/iio/adc/ad7779.c b/drivers/iio/adc/ad7779.c index a5d87faa5e12..845adc510239 100644 --- a/drivers/iio/adc/ad7779.c +++ b/drivers/iio/adc/ad7779.c @@ -595,7 +595,8 @@ static irqreturn_t ad7779_trigger_handler(int irq, void *p) goto exit_handler; } - iio_push_to_buffers_with_timestamp(indio_dev, &st->data, pf->timestamp); + iio_push_to_buffers_with_ts(indio_dev, &st->data, sizeof(st->data), + pf->timestamp); exit_handler: iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/adc/ad7791.c b/drivers/iio/adc/ad7791.c index 597c2686ffa4..041fc25e3209 100644 --- a/drivers/iio/adc/ad7791.c +++ b/drivers/iio/adc/ad7791.c @@ -464,7 +464,7 @@ static const struct spi_device_id ad7791_spi_ids[] = { { "ad7789", AD7789 }, { "ad7790", AD7790 }, { "ad7791", AD7791 }, - {} + { } }; MODULE_DEVICE_TABLE(spi, ad7791_spi_ids); diff --git a/drivers/iio/adc/ad7923.c b/drivers/iio/adc/ad7923.c index 87945efb940b..0369151c7db1 100644 --- a/drivers/iio/adc/ad7923.c +++ b/drivers/iio/adc/ad7923.c @@ -207,8 +207,8 @@ static irqreturn_t ad7923_trigger_handler(int irq, void *p) if (b_sent) goto done; - iio_push_to_buffers_with_timestamp(indio_dev, st->rx_buf, - iio_get_time_ns(indio_dev)); + iio_push_to_buffers_with_ts(indio_dev, st->rx_buf, sizeof(st->rx_buf), + iio_get_time_ns(indio_dev)); done: iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/adc/ad7944.c b/drivers/iio/adc/ad7944.c index 2f949fe55873..7722cf9e8214 100644 --- a/drivers/iio/adc/ad7944.c +++ b/drivers/iio/adc/ad7944.c @@ -190,11 +190,6 @@ static int ad7944_3wire_cs_mode_init_msg(struct device *dev, struct ad7944_adc * struct spi_transfer *xfers = adc->xfers; /* - * NB: can get better performance from some SPI controllers if we use - * the same bits_per_word in every transfer. - */ - xfers[0].bits_per_word = chan->scan_type.realbits; - /* * CS is tied to CNV and we need a low to high transition to start the * conversion, so place CNV low for t_QUIET to prepare for this. */ @@ -208,7 +203,6 @@ static int ad7944_3wire_cs_mode_init_msg(struct device *dev, struct ad7944_adc * xfers[1].cs_off = 1; xfers[1].delay.value = t_conv_ns; xfers[1].delay.unit = SPI_DELAY_UNIT_NSECS; - xfers[1].bits_per_word = chan->scan_type.realbits; /* Then we can read the data during the acquisition phase */ xfers[2].rx_buf = &adc->sample.raw; @@ -228,11 +222,6 @@ static int ad7944_4wire_mode_init_msg(struct device *dev, struct ad7944_adc *adc struct spi_transfer *xfers = adc->xfers; /* - * NB: can get better performance from some SPI controllers if we use - * the same bits_per_word in every transfer. - */ - xfers[0].bits_per_word = chan->scan_type.realbits; - /* * CS has to be high for full conversion time to avoid triggering the * busy indication. */ @@ -377,6 +366,8 @@ static int ad7944_single_conversion(struct ad7944_adc *adc, if (chan->scan_type.sign == 's') *val = sign_extend32(*val, chan->scan_type.realbits - 1); + else + *val &= GENMASK(chan->scan_type.realbits - 1, 0); return IIO_VAL_INT; } diff --git a/drivers/iio/adc/ad799x.c b/drivers/iio/adc/ad799x.c index 993f4651b73a..9c02f9199139 100644 --- a/drivers/iio/adc/ad799x.c +++ b/drivers/iio/adc/ad799x.c @@ -958,7 +958,7 @@ static const struct i2c_device_id ad799x_id[] = { { "ad7994", ad7994 }, { "ad7997", ad7997 }, { "ad7998", ad7998 }, - {} + { } }; MODULE_DEVICE_TABLE(i2c, ad799x_id); diff --git a/drivers/iio/adc/ad_sigma_delta.c b/drivers/iio/adc/ad_sigma_delta.c index 6c37f8e21120..4c5f8d29a559 100644 --- a/drivers/iio/adc/ad_sigma_delta.c +++ b/drivers/iio/adc/ad_sigma_delta.c @@ -587,6 +587,10 @@ static irqreturn_t ad_sd_trigger_handler(int irq, void *p) * byte set to zero. */ ad_sd_read_reg_raw(sigma_delta, data_reg, transfer_size, &data[1]); break; + + default: + dev_err_ratelimited(&indio_dev->dev, "Unsupported reg_size: %u\n", reg_size); + goto irq_handled; } /* diff --git a/drivers/iio/adc/adi-axi-adc.c b/drivers/iio/adc/adi-axi-adc.c index cf942c043457..4116c44197b8 100644 --- a/drivers/iio/adc/adi-axi-adc.c +++ b/drivers/iio/adc/adi-axi-adc.c @@ -702,7 +702,7 @@ static const struct of_device_id adi_axi_adc_of_match[] = { { .compatible = "adi,axi-adc-10.0.a", .data = &adc_generic }, { .compatible = "adi,axi-ad485x", .data = &adi_axi_ad485x }, { .compatible = "adi,axi-ad7606x", .data = &adc_ad7606 }, - { /* end of list */ } + { } }; MODULE_DEVICE_TABLE(of, adi_axi_adc_of_match); diff --git a/drivers/iio/adc/at91-sama5d2_adc.c b/drivers/iio/adc/at91-sama5d2_adc.c index 414610afcb2c..c3450246730e 100644 --- a/drivers/iio/adc/at91-sama5d2_adc.c +++ b/drivers/iio/adc/at91-sama5d2_adc.c @@ -586,15 +586,6 @@ struct at91_adc_temp { u16 saved_oversampling; }; -/* - * Buffer size requirements: - * No channels * bytes_per_channel(2) + timestamp bytes (8) - * Divided by 2 because we need half words. - * We assume 32 channels for now, has to be increased if needed. - * Nobody minds a buffer being too big. - */ -#define AT91_BUFFER_MAX_HWORDS ((32 * 2 + 8) / 2) - struct at91_adc_state { void __iomem *base; int irq; @@ -616,8 +607,8 @@ struct at91_adc_state { struct at91_adc_temp temp_st; struct iio_dev *indio_dev; struct device *dev; - /* Ensure naturally aligned timestamp */ - u16 buffer[AT91_BUFFER_MAX_HWORDS] __aligned(8); + /* We assume 32 channels for now, has to be increased if needed. */ + IIO_DECLARE_BUFFER_WITH_TS(u16, buffer, 32); /* * lock to prevent concurrent 'single conversion' requests through * sysfs. diff --git a/drivers/iio/adc/axp20x_adc.c b/drivers/iio/adc/axp20x_adc.c index 9fd7027623d0..71584ffd3632 100644 --- a/drivers/iio/adc/axp20x_adc.c +++ b/drivers/iio/adc/axp20x_adc.c @@ -163,14 +163,14 @@ static const struct iio_map axp20x_maps[] = { IIO_MAP("batt_v", "axp20x-battery-power-supply", "batt_v"), IIO_MAP("batt_chrg_i", "axp20x-battery-power-supply", "batt_chrg_i"), IIO_MAP("batt_dischrg_i", "axp20x-battery-power-supply", "batt_dischrg_i"), - { /* sentinel */ } + { } }; static const struct iio_map axp22x_maps[] = { IIO_MAP("batt_v", "axp20x-battery-power-supply", "batt_v"), IIO_MAP("batt_chrg_i", "axp20x-battery-power-supply", "batt_chrg_i"), IIO_MAP("batt_dischrg_i", "axp20x-battery-power-supply", "batt_dischrg_i"), - { /* sentinel */ } + { } }; static struct iio_map axp717_maps[] = { @@ -1074,7 +1074,7 @@ static const struct of_device_id axp20x_adc_of_match[] = { { .compatible = "x-powers,axp221-adc", .data = (void *)&axp22x_data, }, { .compatible = "x-powers,axp717-adc", .data = (void *)&axp717_data, }, { .compatible = "x-powers,axp813-adc", .data = (void *)&axp813_data, }, - { /* sentinel */ } + { } }; MODULE_DEVICE_TABLE(of, axp20x_adc_of_match); @@ -1084,7 +1084,7 @@ static const struct platform_device_id axp20x_adc_id_match[] = { { .name = "axp22x-adc", .driver_data = (kernel_ulong_t)&axp22x_data, }, { .name = "axp717-adc", .driver_data = (kernel_ulong_t)&axp717_data, }, { .name = "axp813-adc", .driver_data = (kernel_ulong_t)&axp813_data, }, - { /* sentinel */ }, + { } }; MODULE_DEVICE_TABLE(platform, axp20x_adc_id_match); diff --git a/drivers/iio/adc/axp288_adc.c b/drivers/iio/adc/axp288_adc.c index 45542efc3ece..c8283279c477 100644 --- a/drivers/iio/adc/axp288_adc.c +++ b/drivers/iio/adc/axp288_adc.c @@ -110,7 +110,7 @@ static const struct iio_map axp288_adc_default_maps[] = { IIO_MAP("BATT_CHG_I", "axp288-chrg", "axp288-chrg-curr"), IIO_MAP("BATT_DISCHRG_I", "axp288-chrg", "axp288-chrg-d-curr"), IIO_MAP("BATT_V", "axp288-batt", "axp288-batt-volt"), - {}, + { } }; static int axp288_adc_read_channel(int *val, unsigned long address, @@ -207,7 +207,7 @@ static const struct dmi_system_id axp288_adc_ts_bias_override[] = { }, .driver_data = (void *)(uintptr_t)AXP288_ADC_TS_BIAS_80UA, }, - {} + { } }; static int axp288_adc_initialize(struct axp288_adc_info *info) diff --git a/drivers/iio/adc/cpcap-adc.c b/drivers/iio/adc/cpcap-adc.c index c218acf6c9c6..ba7cbd3b4822 100644 --- a/drivers/iio/adc/cpcap-adc.c +++ b/drivers/iio/adc/cpcap-adc.c @@ -942,7 +942,7 @@ static const struct of_device_id cpcap_adc_id_table[] = { .compatible = "motorola,mapphone-cpcap-adc", .data = &mapphone_adc, }, - { /* sentinel */ }, + { } }; MODULE_DEVICE_TABLE(of, cpcap_adc_id_table); diff --git a/drivers/iio/adc/da9150-gpadc.c b/drivers/iio/adc/da9150-gpadc.c index 0290345ade84..b99291ce2a45 100644 --- a/drivers/iio/adc/da9150-gpadc.c +++ b/drivers/iio/adc/da9150-gpadc.c @@ -296,7 +296,7 @@ static const struct iio_map da9150_gpadc_default_maps[] = { IIO_MAP("VBUS", "da9150-charger", "CHAN_VBUS"), IIO_MAP("TJUNC_CORE", "da9150-charger", "CHAN_TJUNC"), IIO_MAP("VBAT", "da9150-charger", "CHAN_VBAT"), - {}, + { } }; static int da9150_gpadc_probe(struct platform_device *pdev) diff --git a/drivers/iio/adc/dln2-adc.c b/drivers/iio/adc/dln2-adc.c index 359e26e3f5bc..9dbd2c87938c 100644 --- a/drivers/iio/adc/dln2-adc.c +++ b/drivers/iio/adc/dln2-adc.c @@ -488,8 +488,8 @@ static irqreturn_t dln2_adc_trigger_h(int irq, void *p) (void *)dev_data.values + t->from, t->length); } - iio_push_to_buffers_with_timestamp(indio_dev, &data, - iio_get_time_ns(indio_dev)); + iio_push_to_buffers_with_ts(indio_dev, &data, sizeof(data), + iio_get_time_ns(indio_dev)); done: iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/adc/envelope-detector.c b/drivers/iio/adc/envelope-detector.c index e911c25d106d..5b16fe737659 100644 --- a/drivers/iio/adc/envelope-detector.c +++ b/drivers/iio/adc/envelope-detector.c @@ -305,7 +305,7 @@ static const struct iio_chan_spec_ext_info envelope_detector_ext_info[] = { { .name = "compare_interval", .read = envelope_show_comp_interval, .write = envelope_store_comp_interval, }, - { /* sentinel */ } + { } }; static const struct iio_chan_spec envelope_detector_iio_channel = { @@ -390,7 +390,7 @@ static int envelope_detector_probe(struct platform_device *pdev) static const struct of_device_id envelope_detector_match[] = { { .compatible = "axentia,tse850-envelope-detector", }, - { /* sentinel */ } + { } }; MODULE_DEVICE_TABLE(of, envelope_detector_match); diff --git a/drivers/iio/adc/fsl-imx25-gcq.c b/drivers/iio/adc/fsl-imx25-gcq.c index b3f037510e35..f8c220f6a7b4 100644 --- a/drivers/iio/adc/fsl-imx25-gcq.c +++ b/drivers/iio/adc/fsl-imx25-gcq.c @@ -372,7 +372,7 @@ static int mx25_gcq_probe(struct platform_device *pdev) static const struct of_device_id mx25_gcq_ids[] = { { .compatible = "fsl,imx25-gcq", }, - { /* Sentinel */ } + { } }; MODULE_DEVICE_TABLE(of, mx25_gcq_ids); diff --git a/drivers/iio/adc/hi8435.c b/drivers/iio/adc/hi8435.c index 689e34f06987..b4562aae8477 100644 --- a/drivers/iio/adc/hi8435.c +++ b/drivers/iio/adc/hi8435.c @@ -351,7 +351,7 @@ static const struct iio_enum hi8435_sensing_mode = { static const struct iio_chan_spec_ext_info hi8435_ext_info[] = { IIO_ENUM("sensing_mode", IIO_SEPARATE, &hi8435_sensing_mode), IIO_ENUM_AVAILABLE("sensing_mode", IIO_SHARED_BY_TYPE, &hi8435_sensing_mode), - {}, + { } }; #define HI8435_VOLTAGE_CHANNEL(num) \ diff --git a/drivers/iio/adc/hx711.c b/drivers/iio/adc/hx711.c index 8da0419ecfa3..7235fa9e13d5 100644 --- a/drivers/iio/adc/hx711.c +++ b/drivers/iio/adc/hx711.c @@ -87,7 +87,10 @@ struct hx711_data { * triggered buffer * 2x32-bit channel + 64-bit naturally aligned timestamp */ - u32 buffer[4] __aligned(8); + struct { + u32 channel[2]; + aligned_s64 timestamp; + } buffer; /* * delay after a rising edge on SCK until the data is ready DOUT * this is dependent on the hx711 where the datasheet tells a @@ -361,15 +364,15 @@ static irqreturn_t hx711_trigger(int irq, void *p) mutex_lock(&hx711_data->lock); - memset(hx711_data->buffer, 0, sizeof(hx711_data->buffer)); + memset(&hx711_data->buffer, 0, sizeof(hx711_data->buffer)); iio_for_each_active_channel(indio_dev, i) { - hx711_data->buffer[j] = hx711_reset_read(hx711_data, + hx711_data->buffer.channel[j] = hx711_reset_read(hx711_data, indio_dev->channels[i].channel); j++; } - iio_push_to_buffers_with_timestamp(indio_dev, hx711_data->buffer, + iio_push_to_buffers_with_timestamp(indio_dev, &hx711_data->buffer, pf->timestamp); mutex_unlock(&hx711_data->lock); diff --git a/drivers/iio/adc/imx7d_adc.c b/drivers/iio/adc/imx7d_adc.c index 828d3fea6d43..09ce71f6e941 100644 --- a/drivers/iio/adc/imx7d_adc.c +++ b/drivers/iio/adc/imx7d_adc.c @@ -413,7 +413,7 @@ static const struct iio_info imx7d_adc_iio_info = { static const struct of_device_id imx7d_adc_match[] = { { .compatible = "fsl,imx7d-adc", }, - { /* sentinel */ } + { } }; MODULE_DEVICE_TABLE(of, imx7d_adc_match); diff --git a/drivers/iio/adc/imx8qxp-adc.c b/drivers/iio/adc/imx8qxp-adc.c index 3d19d7d744aa..be13a6ed7e00 100644 --- a/drivers/iio/adc/imx8qxp-adc.c +++ b/drivers/iio/adc/imx8qxp-adc.c @@ -481,7 +481,7 @@ static DEFINE_RUNTIME_DEV_PM_OPS(imx8qxp_adc_pm_ops, static const struct of_device_id imx8qxp_adc_match[] = { { .compatible = "nxp,imx8qxp-adc", }, - { /* sentinel */ } + { } }; MODULE_DEVICE_TABLE(of, imx8qxp_adc_match); diff --git a/drivers/iio/adc/imx93_adc.c b/drivers/iio/adc/imx93_adc.c index 002eb19587d6..7feaafd2316f 100644 --- a/drivers/iio/adc/imx93_adc.c +++ b/drivers/iio/adc/imx93_adc.c @@ -464,7 +464,7 @@ static DEFINE_RUNTIME_DEV_PM_OPS(imx93_adc_pm_ops, static const struct of_device_id imx93_adc_match[] = { { .compatible = "nxp,imx93-adc", }, - { /* sentinel */ } + { } }; MODULE_DEVICE_TABLE(of, imx93_adc_match); diff --git a/drivers/iio/adc/ina2xx-adc.c b/drivers/iio/adc/ina2xx-adc.c index 40d14faa71c5..857e1b69d6cd 100644 --- a/drivers/iio/adc/ina2xx-adc.c +++ b/drivers/iio/adc/ina2xx-adc.c @@ -766,7 +766,7 @@ static int ina2xx_work_buffer(struct iio_dev *indio_dev) chip->scan.chan[i++] = val; } - iio_push_to_buffers_with_timestamp(indio_dev, &chip->scan, time); + iio_push_to_buffers_with_ts(indio_dev, &chip->scan, sizeof(chip->scan), time); return 0; }; diff --git a/drivers/iio/adc/industrialio-adc.c b/drivers/iio/adc/industrialio-adc.c new file mode 100644 index 000000000000..b4057230e749 --- /dev/null +++ b/drivers/iio/adc/industrialio-adc.c @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Helpers for parsing common ADC information from a firmware node. + * + * Copyright (c) 2025 Matti Vaittinen <mazziesaccount@gmail.com> + */ + +#include <linux/device.h> +#include <linux/errno.h> +#include <linux/export.h> +#include <linux/module.h> +#include <linux/property.h> +#include <linux/types.h> + +#include <linux/iio/adc-helpers.h> +#include <linux/iio/iio.h> + +/** + * devm_iio_adc_device_alloc_chaninfo_se - allocate and fill iio_chan_spec for ADC + * + * Scan the device node for single-ended ADC channel information. Channel ID is + * expected to be found from the "reg" property. Allocate and populate the + * iio_chan_spec structure corresponding to channels that are found. The memory + * for iio_chan_spec structure will be freed upon device detach. + * + * @dev: Pointer to the ADC device. + * @template: Template iio_chan_spec from which the fields of all + * found and allocated channels are initialized. + * @max_chan_id: Maximum value of a channel ID. Use negative value if no + * checking is required. + * @cs: Location where pointer to allocated iio_chan_spec + * should be stored. + * + * Return: Number of found channels on success. Negative value to indicate + * failure. Specifically, -ENOENT if no channel nodes were found. + */ +int devm_iio_adc_device_alloc_chaninfo_se(struct device *dev, + const struct iio_chan_spec *template, + int max_chan_id, + struct iio_chan_spec **cs) +{ + struct iio_chan_spec *chan_array, *chan; + int num_chan, ret; + + num_chan = iio_adc_device_num_channels(dev); + if (num_chan < 0) + return num_chan; + + if (!num_chan) + return -ENOENT; + + chan_array = devm_kcalloc(dev, num_chan, sizeof(*chan_array), + GFP_KERNEL); + if (!chan_array) + return -ENOMEM; + + chan = &chan_array[0]; + + device_for_each_named_child_node_scoped(dev, child, "channel") { + u32 ch; + + ret = fwnode_property_read_u32(child, "reg", &ch); + if (ret) + return ret; + + if (max_chan_id >= 0 && ch > max_chan_id) + return -ERANGE; + + *chan = *template; + chan->channel = ch; + chan++; + } + + *cs = chan_array; + + return num_chan; +} +EXPORT_SYMBOL_NS_GPL(devm_iio_adc_device_alloc_chaninfo_se, "IIO_DRIVER"); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Matti Vaittinen <mazziesaccount@gmail.com>"); +MODULE_DESCRIPTION("IIO ADC fwnode parsing helpers"); diff --git a/drivers/iio/adc/intel_mrfld_adc.c b/drivers/iio/adc/intel_mrfld_adc.c index c178850eaaab..101c1a0ce591 100644 --- a/drivers/iio/adc/intel_mrfld_adc.c +++ b/drivers/iio/adc/intel_mrfld_adc.c @@ -174,7 +174,7 @@ static const struct iio_map iio_maps[] = { IIO_MAP("CH6", "bcove-temp", "SYSTEMP0"), IIO_MAP("CH7", "bcove-temp", "SYSTEMP1"), IIO_MAP("CH8", "bcove-temp", "SYSTEMP2"), - {} + { } }; static int mrfld_adc_probe(struct platform_device *pdev) @@ -222,7 +222,7 @@ static int mrfld_adc_probe(struct platform_device *pdev) static const struct platform_device_id mrfld_adc_id_table[] = { { .name = "mrfld_bcove_adc" }, - {} + { } }; MODULE_DEVICE_TABLE(platform, mrfld_adc_id_table); diff --git a/drivers/iio/adc/lpc18xx_adc.c b/drivers/iio/adc/lpc18xx_adc.c index 450a243d1f7c..7e5d181ff702 100644 --- a/drivers/iio/adc/lpc18xx_adc.c +++ b/drivers/iio/adc/lpc18xx_adc.c @@ -188,7 +188,7 @@ static int lpc18xx_adc_probe(struct platform_device *pdev) static const struct of_device_id lpc18xx_adc_match[] = { { .compatible = "nxp,lpc1850-adc" }, - { /* sentinel */ } + { } }; MODULE_DEVICE_TABLE(of, lpc18xx_adc_match); diff --git a/drivers/iio/adc/ltc2471.c b/drivers/iio/adc/ltc2471.c index 97c417c3a4eb..a579107fd5c9 100644 --- a/drivers/iio/adc/ltc2471.c +++ b/drivers/iio/adc/ltc2471.c @@ -138,7 +138,7 @@ static int ltc2471_i2c_probe(struct i2c_client *client) static const struct i2c_device_id ltc2471_i2c_id[] = { { "ltc2471", ltc2471 }, { "ltc2473", ltc2473 }, - {} + { } }; MODULE_DEVICE_TABLE(i2c, ltc2471_i2c_id); diff --git a/drivers/iio/adc/max1118.c b/drivers/iio/adc/max1118.c index 565ca2e21c0c..7d7001e8e3d9 100644 --- a/drivers/iio/adc/max1118.c +++ b/drivers/iio/adc/max1118.c @@ -188,8 +188,8 @@ static irqreturn_t max1118_trigger_handler(int irq, void *p) adc->scan.channels[i] = ret; i++; } - iio_push_to_buffers_with_timestamp(indio_dev, &adc->scan, - iio_get_time_ns(indio_dev)); + iio_push_to_buffers_with_ts(indio_dev, &adc->scan, sizeof(adc->scan), + iio_get_time_ns(indio_dev)); out: mutex_unlock(&adc->lock); diff --git a/drivers/iio/adc/max11410.c b/drivers/iio/adc/max11410.c index 437d9f24b5a1..511b2f14dfaf 100644 --- a/drivers/iio/adc/max11410.c +++ b/drivers/iio/adc/max11410.c @@ -632,8 +632,8 @@ static irqreturn_t max11410_trigger_handler(int irq, void *p) goto out; } - iio_push_to_buffers_with_timestamp(indio_dev, &st->scan, - iio_get_time_ns(indio_dev)); + iio_push_to_buffers_with_ts(indio_dev, &st->scan, sizeof(st->scan), + iio_get_time_ns(indio_dev)); out: iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/adc/max1363.c b/drivers/iio/adc/max1363.c index 35717ec082ce..a7e9912fb44a 100644 --- a/drivers/iio/adc/max1363.c +++ b/drivers/iio/adc/max1363.c @@ -1498,8 +1498,8 @@ static irqreturn_t max1363_trigger_handler(int irq, void *p) if (b_sent < 0) goto done; - iio_push_to_buffers_with_timestamp(indio_dev, &st->data, - iio_get_time_ns(indio_dev)); + iio_push_to_buffers_with_ts(indio_dev, &st->data, sizeof(st->data), + iio_get_time_ns(indio_dev)); done: iio_trigger_notify_done(indio_dev->trig); @@ -1551,7 +1551,7 @@ static const struct of_device_id max1363_of_match[] = { MAX1363_COMPATIBLE("maxim,max11645", max11645), MAX1363_COMPATIBLE("maxim,max11646", max11646), MAX1363_COMPATIBLE("maxim,max11647", max11647), - { /* sentinel */ } + { } }; MODULE_DEVICE_TABLE(of, max1363_of_match); @@ -1672,7 +1672,7 @@ static const struct i2c_device_id max1363_id[] = { MAX1363_ID_TABLE("max11645", max11645), MAX1363_ID_TABLE("max11646", max11646), MAX1363_ID_TABLE("max11647", max11647), - { /* sentinel */ } + { } }; MODULE_DEVICE_TABLE(i2c, max1363_id); diff --git a/drivers/iio/adc/max77541-adc.c b/drivers/iio/adc/max77541-adc.c index 21d024bde16b..0aa04d143ad4 100644 --- a/drivers/iio/adc/max77541-adc.c +++ b/drivers/iio/adc/max77541-adc.c @@ -176,7 +176,7 @@ static int max77541_adc_probe(struct platform_device *pdev) static const struct platform_device_id max77541_adc_platform_id[] = { { "max77541-adc" }, - { /* sentinel */ } + { } }; MODULE_DEVICE_TABLE(platform, max77541_adc_platform_id); diff --git a/drivers/iio/adc/mcp3911.c b/drivers/iio/adc/mcp3911.c index 6748b44d568d..a6f21791c685 100644 --- a/drivers/iio/adc/mcp3911.c +++ b/drivers/iio/adc/mcp3911.c @@ -6,11 +6,13 @@ * Copyright (C) 2018 Kent Gustavsson <kent@minoris.se> */ #include <linux/bitfield.h> -#include <linux/bits.h> +#include <linux/bitops.h> #include <linux/cleanup.h> #include <linux/clk.h> #include <linux/delay.h> +#include <linux/dev_printk.h> #include <linux/err.h> +#include <linux/gpio/consumer.h> #include <linux/module.h> #include <linux/mod_devicetable.h> #include <linux/property.h> @@ -79,6 +81,8 @@ #define MCP3910_CONFIG1_CLKEXT BIT(6) #define MCP3910_CONFIG1_VREFEXT BIT(7) +#define MCP3910_CHANNEL(ch) (MCP3911_REG_CHANNEL0 + (ch)) + #define MCP3910_REG_OFFCAL_CH0 0x0f #define MCP3910_OFFCAL(ch) (MCP3910_REG_OFFCAL_CH0 + (ch) * 6) @@ -110,6 +114,7 @@ struct mcp3911_chip_info { int (*get_offset)(struct mcp3911 *adc, int channel, int *val); int (*set_offset)(struct mcp3911 *adc, int channel, int val); int (*set_scale)(struct mcp3911 *adc, int channel, u32 val); + int (*get_raw)(struct mcp3911 *adc, int channel, int *val); }; struct mcp3911 { @@ -170,6 +175,18 @@ static int mcp3911_update(struct mcp3911 *adc, u8 reg, u32 mask, u32 val, u8 len return mcp3911_write(adc, reg, val, len); } +static int mcp3911_read_s24(struct mcp3911 *const adc, u8 const reg, s32 *const val) +{ + u32 uval; + int const ret = mcp3911_read(adc, reg, &uval, 3); + + if (ret) + return ret; + + *val = sign_extend32(uval, 23); + return ret; +} + static int mcp3910_enable_offset(struct mcp3911 *adc, bool enable) { unsigned int mask = MCP3910_CONFIG0_EN_OFFCAL; @@ -194,6 +211,11 @@ static int mcp3910_set_offset(struct mcp3911 *adc, int channel, int val) return adc->chip->enable_offset(adc, 1); } +static int mcp3910_get_raw(struct mcp3911 *adc, int channel, s32 *val) +{ + return mcp3911_read_s24(adc, MCP3910_CHANNEL(channel), val); +} + static int mcp3911_enable_offset(struct mcp3911 *adc, bool enable) { unsigned int mask = MCP3911_STATUSCOM_EN_OFFCAL; @@ -218,6 +240,11 @@ static int mcp3911_set_offset(struct mcp3911 *adc, int channel, int val) return adc->chip->enable_offset(adc, 1); } +static int mcp3911_get_raw(struct mcp3911 *adc, int channel, s32 *val) +{ + return mcp3911_read_s24(adc, MCP3911_CHANNEL(channel), val); +} + static int mcp3910_get_osr(struct mcp3911 *adc, u32 *val) { int ret; @@ -321,12 +348,9 @@ static int mcp3911_read_raw(struct iio_dev *indio_dev, guard(mutex)(&adc->lock); switch (mask) { case IIO_CHAN_INFO_RAW: - ret = mcp3911_read(adc, - MCP3911_CHANNEL(channel->channel), val, 3); + ret = adc->chip->get_raw(adc, channel->channel, val); if (ret) return ret; - - *val = sign_extend32(*val, 23); return IIO_VAL_INT; case IIO_CHAN_INFO_OFFSET: ret = adc->chip->get_offset(adc, channel->channel, val); @@ -516,8 +540,8 @@ static irqreturn_t mcp3911_trigger_handler(int irq, void *p) adc->scan.channels[i] = get_unaligned_be24(&adc->rx_buf[scan_chan->channel * 3]); i++; } - iio_push_to_buffers_with_timestamp(indio_dev, &adc->scan, - iio_get_time_ns(indio_dev)); + iio_push_to_buffers_with_ts(indio_dev, &adc->scan, sizeof(adc->scan), + iio_get_time_ns(indio_dev)); out: iio_trigger_notify_done(indio_dev->trig); @@ -684,6 +708,7 @@ static const struct iio_trigger_ops mcp3911_trigger_ops = { static int mcp3911_probe(struct spi_device *spi) { struct device *dev = &spi->dev; + struct gpio_desc *gpio_reset; struct iio_dev *indio_dev; struct mcp3911 *adc; bool external_vref; @@ -728,6 +753,22 @@ static int mcp3911_probe(struct spi_device *spi) } dev_dbg(dev, "use device address %i\n", adc->dev_addr); + gpio_reset = devm_gpiod_get_optional(&spi->dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(gpio_reset)) + return dev_err_probe(dev, PTR_ERR(gpio_reset), + "Cannot get reset GPIO\n"); + + if (gpio_reset) { + gpiod_set_value_cansleep(gpio_reset, 0); + + /* + * Settling time after Hard Reset Mode (determined experimentally): + * 330 micro-seconds are too few; 470 micro-seconds are sufficient. + * Just in case, we add some safety factor... + */ + fsleep(600); + } + ret = adc->chip->config(adc, external_vref); if (ret) return ret; @@ -799,6 +840,7 @@ static const struct mcp3911_chip_info mcp3911_chip_info[] = { .get_offset = mcp3910_get_offset, .set_offset = mcp3910_set_offset, .set_scale = mcp3910_set_scale, + .get_raw = mcp3910_get_raw, }, [MCP3911] = { .channels = mcp3911_channels, @@ -810,6 +852,7 @@ static const struct mcp3911_chip_info mcp3911_chip_info[] = { .get_offset = mcp3911_get_offset, .set_offset = mcp3911_set_offset, .set_scale = mcp3911_set_scale, + .get_raw = mcp3911_get_raw, }, [MCP3912] = { .channels = mcp3912_channels, @@ -821,6 +864,7 @@ static const struct mcp3911_chip_info mcp3911_chip_info[] = { .get_offset = mcp3910_get_offset, .set_offset = mcp3910_set_offset, .set_scale = mcp3910_set_scale, + .get_raw = mcp3910_get_raw, }, [MCP3913] = { .channels = mcp3913_channels, @@ -832,6 +876,7 @@ static const struct mcp3911_chip_info mcp3911_chip_info[] = { .get_offset = mcp3910_get_offset, .set_offset = mcp3910_set_offset, .set_scale = mcp3910_set_scale, + .get_raw = mcp3910_get_raw, }, [MCP3914] = { .channels = mcp3914_channels, @@ -843,6 +888,7 @@ static const struct mcp3911_chip_info mcp3911_chip_info[] = { .get_offset = mcp3910_get_offset, .set_offset = mcp3910_set_offset, .set_scale = mcp3910_set_scale, + .get_raw = mcp3910_get_raw, }, [MCP3918] = { .channels = mcp3918_channels, @@ -854,6 +900,7 @@ static const struct mcp3911_chip_info mcp3911_chip_info[] = { .get_offset = mcp3910_get_offset, .set_offset = mcp3910_set_offset, .set_scale = mcp3910_set_scale, + .get_raw = mcp3910_get_raw, }, [MCP3919] = { .channels = mcp3919_channels, @@ -865,6 +912,7 @@ static const struct mcp3911_chip_info mcp3911_chip_info[] = { .get_offset = mcp3910_get_offset, .set_offset = mcp3910_set_offset, .set_scale = mcp3910_set_scale, + .get_raw = mcp3910_get_raw, }, }; static const struct of_device_id mcp3911_dt_ids[] = { diff --git a/drivers/iio/adc/meson_saradc.c b/drivers/iio/adc/meson_saradc.c index 997def4a4d2f..4ff88603e4fc 100644 --- a/drivers/iio/adc/meson_saradc.c +++ b/drivers/iio/adc/meson_saradc.c @@ -160,6 +160,11 @@ #define MESON_SAR_ADC_REG11_EOC BIT(1) #define MESON_SAR_ADC_REG11_VREF_SEL BIT(0) +#define MESON_SAR_ADC_REG12 0x30 + #define MESON_SAR_ADC_REG12_MPLL0_UNKNOWN BIT(0) + #define MESON_SAR_ADC_REG12_MPLL1_UNKNOWN BIT(1) + #define MESON_SAR_ADC_REG12_MPLL2_UNKNOWN BIT(2) + #define MESON_SAR_ADC_REG13 0x34 #define MESON_SAR_ADC_REG13_12BIT_CALIBRATION_MASK GENMASK(13, 8) @@ -326,6 +331,7 @@ struct meson_sar_adc_param { u8 cmv_select; u8 adc_eoc; enum meson_sar_adc_vref_sel vref_voltage; + bool enable_mpll_clock_workaround; }; struct meson_sar_adc_data { @@ -995,6 +1001,15 @@ static int meson_sar_adc_init(struct iio_dev *indio_dev) priv->param->cmv_select); regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG11, MESON_SAR_ADC_REG11_CMV_SEL, regval); + + if (priv->param->enable_mpll_clock_workaround) { + dev_warn(dev, + "Enabling unknown bits to make the MPLL clocks work. This may change so always update dtbs and kernel together\n"); + regmap_write(priv->regmap, MESON_SAR_ADC_REG12, + MESON_SAR_ADC_REG12_MPLL0_UNKNOWN | + MESON_SAR_ADC_REG12_MPLL1_UNKNOWN | + MESON_SAR_ADC_REG12_MPLL2_UNKNOWN); + } } ret = clk_set_parent(priv->adc_sel_clk, priv->clkin); @@ -1219,6 +1234,17 @@ static const struct meson_sar_adc_param meson_sar_adc_gxl_param = { .cmv_select = 1, }; +static const struct meson_sar_adc_param meson_sar_adc_gxlx_param = { + .has_bl30_integration = true, + .clock_rate = 1200000, + .regmap_config = &meson_sar_adc_regmap_config_gxbb, + .resolution = 12, + .disable_ring_counter = 1, + .vref_voltage = 1, + .cmv_select = true, + .enable_mpll_clock_workaround = true, +}; + static const struct meson_sar_adc_param meson_sar_adc_axg_param = { .has_bl30_integration = true, .clock_rate = 1200000, @@ -1267,6 +1293,11 @@ static const struct meson_sar_adc_data meson_sar_adc_gxl_data = { .name = "meson-gxl-saradc", }; +static const struct meson_sar_adc_data meson_sar_adc_gxlx_data = { + .param = &meson_sar_adc_gxlx_param, + .name = "meson-gxlx-saradc", +}; + static const struct meson_sar_adc_data meson_sar_adc_gxm_data = { .param = &meson_sar_adc_gxl_param, .name = "meson-gxm-saradc", @@ -1299,6 +1330,9 @@ static const struct of_device_id meson_sar_adc_of_match[] = { .compatible = "amlogic,meson-gxl-saradc", .data = &meson_sar_adc_gxl_data, }, { + .compatible = "amlogic,meson-gxlx-saradc", + .data = &meson_sar_adc_gxlx_data, + }, { .compatible = "amlogic,meson-gxm-saradc", .data = &meson_sar_adc_gxm_data, }, { @@ -1308,7 +1342,7 @@ static const struct of_device_id meson_sar_adc_of_match[] = { .compatible = "amlogic,meson-g12a-saradc", .data = &meson_sar_adc_g12a_data, }, - { /* sentinel */ } + { } }; MODULE_DEVICE_TABLE(of, meson_sar_adc_of_match); diff --git a/drivers/iio/adc/mt6359-auxadc.c b/drivers/iio/adc/mt6359-auxadc.c index a4970cfb49a5..eecf88b05c6f 100644 --- a/drivers/iio/adc/mt6359-auxadc.c +++ b/drivers/iio/adc/mt6359-auxadc.c @@ -588,7 +588,7 @@ static const struct of_device_id mt6359_auxadc_of_match[] = { { .compatible = "mediatek,mt6357-auxadc", .data = &mt6357_chip_info }, { .compatible = "mediatek,mt6358-auxadc", .data = &mt6358_chip_info }, { .compatible = "mediatek,mt6359-auxadc", .data = &mt6359_chip_info }, - { /* sentinel */ } + { } }; MODULE_DEVICE_TABLE(of, mt6359_auxadc_of_match); diff --git a/drivers/iio/adc/mt6360-adc.c b/drivers/iio/adc/mt6360-adc.c index 4eb2455d6ffa..f8e98b6fa7e9 100644 --- a/drivers/iio/adc/mt6360-adc.c +++ b/drivers/iio/adc/mt6360-adc.c @@ -263,8 +263,8 @@ static irqreturn_t mt6360_adc_trigger_handler(int irq, void *p) struct mt6360_adc_data *mad = iio_priv(indio_dev); struct { u16 values[MT6360_CHAN_MAX]; - int64_t timestamp; - } data __aligned(8); + aligned_s64 timestamp; + } data; int i = 0, bit, val, ret; memset(&data, 0, sizeof(data)); diff --git a/drivers/iio/adc/mt6370-adc.c b/drivers/iio/adc/mt6370-adc.c index 0bc112135bca..7c71fe5e8d31 100644 --- a/drivers/iio/adc/mt6370-adc.c +++ b/drivers/iio/adc/mt6370-adc.c @@ -336,7 +336,7 @@ static int mt6370_adc_probe(struct platform_device *pdev) static const struct of_device_id mt6370_adc_of_id[] = { { .compatible = "mediatek,mt6370-adc", }, - {} + { } }; MODULE_DEVICE_TABLE(of, mt6370_adc_of_id); diff --git a/drivers/iio/adc/mxs-lradc-adc.c b/drivers/iio/adc/mxs-lradc-adc.c index 152cbe265e1a..92baf3f5f560 100644 --- a/drivers/iio/adc/mxs-lradc-adc.c +++ b/drivers/iio/adc/mxs-lradc-adc.c @@ -141,9 +141,8 @@ static int mxs_lradc_adc_read_single(struct iio_dev *iio_dev, int chan, * the same time, yet the code becomes horribly complicated. Therefore I * applied KISS principle here. */ - ret = iio_device_claim_direct_mode(iio_dev); - if (ret) - return ret; + if (!iio_device_claim_direct(iio_dev)) + return -EBUSY; reinit_completion(&adc->completion); @@ -192,7 +191,7 @@ err: writel(LRADC_CTRL1_LRADC_IRQ_EN(0), adc->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR); - iio_device_release_direct_mode(iio_dev); + iio_device_release_direct(iio_dev); return ret; } @@ -275,9 +274,8 @@ static int mxs_lradc_adc_write_raw(struct iio_dev *iio_dev, adc->scale_avail[chan->channel]; int ret; - ret = iio_device_claim_direct_mode(iio_dev); - if (ret) - return ret; + if (!iio_device_claim_direct(iio_dev)) + return -EBUSY; switch (m) { case IIO_CHAN_INFO_SCALE: @@ -300,7 +298,7 @@ static int mxs_lradc_adc_write_raw(struct iio_dev *iio_dev, break; } - iio_device_release_direct_mode(iio_dev); + iio_device_release_direct(iio_dev); return ret; } @@ -427,7 +425,8 @@ static irqreturn_t mxs_lradc_adc_trigger_handler(int irq, void *p) j++; } - iio_push_to_buffers_with_timestamp(iio, adc->buffer, pf->timestamp); + iio_push_to_buffers_with_ts(iio, adc->buffer, sizeof(adc->buffer), + pf->timestamp); iio_trigger_notify_done(iio->trig); diff --git a/drivers/iio/adc/nct7201.c b/drivers/iio/adc/nct7201.c new file mode 100644 index 000000000000..d87824e5490f --- /dev/null +++ b/drivers/iio/adc/nct7201.c @@ -0,0 +1,501 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Driver for Nuvoton nct7201 and nct7202 power monitor chips. + * + * Copyright (c) 2024-2025 Nuvoton Technology corporation. + */ + +#include <linux/array_size.h> +#include <linux/bitfield.h> +#include <linux/bits.h> +#include <linux/delay.h> +#include <linux/dev_printk.h> +#include <linux/err.h> +#include <linux/i2c.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/regmap.h> +#include <linux/time.h> +#include <linux/types.h> +#include <linux/unaligned.h> + +#include <linux/iio/events.h> +#include <linux/iio/iio.h> + +#define NCT7201_REG_INTERRUPT_STATUS 0x0C +#define NCT7201_REG_VOLT_LOW_BYTE 0x0F +#define NCT7201_REG_CONFIGURATION 0x10 +#define NCT7201_BIT_CONFIGURATION_START BIT(0) +#define NCT7201_BIT_CONFIGURATION_ALERT_MSK BIT(1) +#define NCT7201_BIT_CONFIGURATION_CONV_RATE BIT(2) +#define NCT7201_BIT_CONFIGURATION_RESET BIT(7) + +#define NCT7201_REG_ADVANCED_CONFIGURATION 0x11 +#define NCT7201_BIT_ADVANCED_CONF_MOD_ALERT BIT(0) +#define NCT7201_BIT_ADVANCED_CONF_MOD_STS BIT(1) +#define NCT7201_BIT_ADVANCED_CONF_FAULT_QUEUE BIT(2) +#define NCT7201_BIT_ADVANCED_CONF_EN_DEEP_SHUTDOWN BIT(4) +#define NCT7201_BIT_ADVANCED_CONF_EN_SMB_TIMEOUT BIT(5) +#define NCT7201_BIT_ADVANCED_CONF_MOD_RSTIN BIT(7) + +#define NCT7201_REG_CHANNEL_INPUT_MODE 0x12 +#define NCT7201_REG_CHANNEL_ENABLE 0x13 +#define NCT7201_REG_INTERRUPT_MASK_1 0x15 +#define NCT7201_REG_INTERRUPT_MASK_2 0x16 +#define NCT7201_REG_BUSY_STATUS 0x1E +#define NCT7201_BIT_BUSY BIT(0) +#define NCT7201_BIT_PWR_UP BIT(1) +#define NCT7201_REG_ONE_SHOT 0x1F +#define NCT7201_REG_SMUS_ADDRESS 0xFC +#define NCT7201_REG_VIN_MASK GENMASK(15, 3) + +#define NCT7201_REG_VIN(i) (0x00 + i) +#define NCT7201_REG_VIN_HIGH_LIMIT(i) (0x20 + (i) * 2) +#define NCT7201_REG_VIN_LOW_LIMIT(i) (0x21 + (i) * 2) +#define NCT7201_MAX_CHANNEL 12 + +static const struct regmap_range nct7201_read_reg_range[] = { + regmap_reg_range(NCT7201_REG_INTERRUPT_STATUS, NCT7201_REG_BUSY_STATUS), + regmap_reg_range(NCT7201_REG_SMUS_ADDRESS, NCT7201_REG_SMUS_ADDRESS), +}; + +static const struct regmap_access_table nct7201_readable_regs_tbl = { + .yes_ranges = nct7201_read_reg_range, + .n_yes_ranges = ARRAY_SIZE(nct7201_read_reg_range), +}; + +static const struct regmap_range nct7201_write_reg_range[] = { + regmap_reg_range(NCT7201_REG_CONFIGURATION, NCT7201_REG_INTERRUPT_MASK_2), + regmap_reg_range(NCT7201_REG_ONE_SHOT, NCT7201_REG_ONE_SHOT), +}; + +static const struct regmap_access_table nct7201_writeable_regs_tbl = { + .yes_ranges = nct7201_write_reg_range, + .n_yes_ranges = ARRAY_SIZE(nct7201_write_reg_range), +}; + +static const struct regmap_range nct7201_read_vin_reg_range[] = { + regmap_reg_range(NCT7201_REG_VIN(0), NCT7201_REG_VIN(NCT7201_MAX_CHANNEL - 1)), + regmap_reg_range(NCT7201_REG_VIN_HIGH_LIMIT(0), + NCT7201_REG_VIN_LOW_LIMIT(NCT7201_MAX_CHANNEL - 1)), +}; + +static const struct regmap_access_table nct7201_readable_vin_regs_tbl = { + .yes_ranges = nct7201_read_vin_reg_range, + .n_yes_ranges = ARRAY_SIZE(nct7201_read_vin_reg_range), +}; + +static const struct regmap_range nct7201_write_vin_reg_range[] = { + regmap_reg_range(NCT7201_REG_VIN_HIGH_LIMIT(0), + NCT7201_REG_VIN_LOW_LIMIT(NCT7201_MAX_CHANNEL - 1)), +}; + +static const struct regmap_access_table nct7201_writeable_vin_regs_tbl = { + .yes_ranges = nct7201_write_vin_reg_range, + .n_yes_ranges = ARRAY_SIZE(nct7201_write_vin_reg_range), +}; + +static const struct regmap_config nct7201_regmap8_config = { + .name = "vin-data-read-byte", + .reg_bits = 8, + .val_bits = 8, + .use_single_read = true, + .use_single_write = true, + .max_register = 0xff, + .rd_table = &nct7201_readable_regs_tbl, + .wr_table = &nct7201_writeable_regs_tbl, +}; + +static const struct regmap_config nct7201_regmap16_config = { + .name = "vin-data-read-word", + .reg_bits = 8, + .val_bits = 16, + .max_register = 0xff, + .rd_table = &nct7201_readable_vin_regs_tbl, + .wr_table = &nct7201_writeable_vin_regs_tbl, +}; + +struct nct7201_chip_info { + struct regmap *regmap; + struct regmap *regmap16; + int num_vin_channels; + __le16 vin_mask; +}; + +struct nct7201_adc_model_data { + const char *model_name; + const struct iio_chan_spec *channels; + unsigned int num_channels; + int num_vin_channels; +}; + +static const struct iio_event_spec nct7201_events[] = { + { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_RISING, + .mask_separate = BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_ENABLE), + }, { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_FALLING, + .mask_separate = BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_ENABLE), + }, +}; + +#define NCT7201_VOLTAGE_CHANNEL(num) \ + { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .channel = num + 1, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ + .address = num, \ + .event_spec = nct7201_events, \ + .num_event_specs = ARRAY_SIZE(nct7201_events), \ + } + +static const struct iio_chan_spec nct7201_channels[] = { + NCT7201_VOLTAGE_CHANNEL(0), + NCT7201_VOLTAGE_CHANNEL(1), + NCT7201_VOLTAGE_CHANNEL(2), + NCT7201_VOLTAGE_CHANNEL(3), + NCT7201_VOLTAGE_CHANNEL(4), + NCT7201_VOLTAGE_CHANNEL(5), + NCT7201_VOLTAGE_CHANNEL(6), + NCT7201_VOLTAGE_CHANNEL(7), +}; + +static const struct iio_chan_spec nct7202_channels[] = { + NCT7201_VOLTAGE_CHANNEL(0), + NCT7201_VOLTAGE_CHANNEL(1), + NCT7201_VOLTAGE_CHANNEL(2), + NCT7201_VOLTAGE_CHANNEL(3), + NCT7201_VOLTAGE_CHANNEL(4), + NCT7201_VOLTAGE_CHANNEL(5), + NCT7201_VOLTAGE_CHANNEL(6), + NCT7201_VOLTAGE_CHANNEL(7), + NCT7201_VOLTAGE_CHANNEL(8), + NCT7201_VOLTAGE_CHANNEL(9), + NCT7201_VOLTAGE_CHANNEL(10), + NCT7201_VOLTAGE_CHANNEL(11), +}; + +static int nct7201_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct nct7201_chip_info *chip = iio_priv(indio_dev); + unsigned int value; + int err; + + if (chan->type != IIO_VOLTAGE) + return -EOPNOTSUPP; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + err = regmap_read(chip->regmap16, NCT7201_REG_VIN(chan->address), &value); + if (err) + return err; + *val = FIELD_GET(NCT7201_REG_VIN_MASK, value); + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + /* From the datasheet, we have to multiply by 0.0004995 */ + *val = 0; + *val2 = 499500; + return IIO_VAL_INT_PLUS_NANO; + default: + return -EINVAL; + } +} + +static int nct7201_read_event_value(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int *val, int *val2) +{ + struct nct7201_chip_info *chip = iio_priv(indio_dev); + unsigned int value; + int err; + + if (chan->type != IIO_VOLTAGE) + return -EOPNOTSUPP; + + if (info != IIO_EV_INFO_VALUE) + return -EINVAL; + + if (dir == IIO_EV_DIR_FALLING) + err = regmap_read(chip->regmap16, NCT7201_REG_VIN_LOW_LIMIT(chan->address), + &value); + else + err = regmap_read(chip->regmap16, NCT7201_REG_VIN_HIGH_LIMIT(chan->address), + &value); + if (err) + return err; + + *val = FIELD_GET(NCT7201_REG_VIN_MASK, value); + + return IIO_VAL_INT; +} + +static int nct7201_write_event_value(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int val, int val2) +{ + struct nct7201_chip_info *chip = iio_priv(indio_dev); + int err; + + if (chan->type != IIO_VOLTAGE) + return -EOPNOTSUPP; + + if (info != IIO_EV_INFO_VALUE) + return -EOPNOTSUPP; + + if (dir == IIO_EV_DIR_FALLING) + err = regmap_write(chip->regmap16, NCT7201_REG_VIN_LOW_LIMIT(chan->address), + FIELD_PREP(NCT7201_REG_VIN_MASK, val)); + else + err = regmap_write(chip->regmap16, NCT7201_REG_VIN_HIGH_LIMIT(chan->address), + FIELD_PREP(NCT7201_REG_VIN_MASK, val)); + + return err; +} + +static int nct7201_read_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir) +{ + struct nct7201_chip_info *chip = iio_priv(indio_dev); + + if (chan->type != IIO_VOLTAGE) + return -EOPNOTSUPP; + + return !!(le16_to_cpu(chip->vin_mask) & BIT(chan->address)); +} + +static int nct7201_write_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + bool state) +{ + struct nct7201_chip_info *chip = iio_priv(indio_dev); + __le16 mask = cpu_to_le16(BIT(chan->address)); + int err; + + if (chan->type != IIO_VOLTAGE) + return -EOPNOTSUPP; + + if (state) + chip->vin_mask |= mask; + else + chip->vin_mask &= ~mask; + + if (chip->num_vin_channels <= 8) + err = regmap_write(chip->regmap, NCT7201_REG_CHANNEL_ENABLE, + le16_to_cpu(chip->vin_mask)); + else + err = regmap_bulk_write(chip->regmap, NCT7201_REG_CHANNEL_ENABLE, + &chip->vin_mask, sizeof(chip->vin_mask)); + + return err; +} + +static const struct iio_info nct7201_info = { + .read_raw = nct7201_read_raw, + .read_event_config = nct7201_read_event_config, + .write_event_config = nct7201_write_event_config, + .read_event_value = nct7201_read_event_value, + .write_event_value = nct7201_write_event_value, +}; + +static const struct iio_info nct7201_info_no_irq = { + .read_raw = nct7201_read_raw, +}; + +static const struct nct7201_adc_model_data nct7201_model_data = { + .model_name = "nct7201", + .channels = nct7201_channels, + .num_channels = ARRAY_SIZE(nct7201_channels), + .num_vin_channels = 8, +}; + +static const struct nct7201_adc_model_data nct7202_model_data = { + .model_name = "nct7202", + .channels = nct7202_channels, + .num_channels = ARRAY_SIZE(nct7202_channels), + .num_vin_channels = 12, +}; + +static int nct7201_init_chip(struct nct7201_chip_info *chip) +{ + struct device *dev = regmap_get_device(chip->regmap); + __le16 data = cpu_to_le16(GENMASK(chip->num_vin_channels - 1, 0)); + unsigned int value; + int err; + + err = regmap_write(chip->regmap, NCT7201_REG_CONFIGURATION, + NCT7201_BIT_CONFIGURATION_RESET); + if (err) + return dev_err_probe(dev, err, "Failed to reset chip\n"); + + /* + * After about 25 msecs, the device should be ready and then the power-up + * bit will be set to 1. + */ + fsleep(25 * USEC_PER_MSEC); + + err = regmap_read(chip->regmap, NCT7201_REG_BUSY_STATUS, &value); + if (err) + return dev_err_probe(dev, err, "Failed to read busy status\n"); + if (!(value & NCT7201_BIT_PWR_UP)) + return dev_err_probe(dev, -EIO, "Failed to power up after reset\n"); + + /* Enable Channels */ + if (chip->num_vin_channels <= 8) + err = regmap_write(chip->regmap, NCT7201_REG_CHANNEL_ENABLE, + le16_to_cpu(data)); + else + err = regmap_bulk_write(chip->regmap, NCT7201_REG_CHANNEL_ENABLE, + &data, sizeof(data)); + if (err) + return dev_err_probe(dev, err, "Failed to enable channels\n"); + + err = regmap_bulk_read(chip->regmap, NCT7201_REG_CHANNEL_ENABLE, + &chip->vin_mask, sizeof(chip->vin_mask)); + if (err) + return dev_err_probe(dev, err, + "Failed to read channel enable register\n"); + + /* Start monitoring if needed */ + err = regmap_set_bits(chip->regmap, NCT7201_REG_CONFIGURATION, + NCT7201_BIT_CONFIGURATION_START); + if (err) + return dev_err_probe(dev, err, "Failed to start monitoring\n"); + + return 0; +} + +static irqreturn_t nct7201_irq_handler(int irq, void *private) +{ + struct iio_dev *indio_dev = private; + struct nct7201_chip_info *chip = iio_priv(indio_dev); + __le16 data; + int err; + + err = regmap_bulk_read(chip->regmap, NCT7201_REG_INTERRUPT_STATUS, + &data, sizeof(data)); + if (err) + return IRQ_NONE; + + if (data) + iio_push_event(indio_dev, + IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, + 0, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_EITHER), + iio_get_time_ns(indio_dev)); + + return IRQ_HANDLED; +} + +static int nct7201_probe(struct i2c_client *client) +{ + const struct nct7201_adc_model_data *model_data; + struct device *dev = &client->dev; + struct nct7201_chip_info *chip; + struct iio_dev *indio_dev; + int ret; + + model_data = i2c_get_match_data(client); + if (!model_data) + return -ENODEV; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*chip)); + if (!indio_dev) + return -ENOMEM; + chip = iio_priv(indio_dev); + + chip->regmap = devm_regmap_init_i2c(client, &nct7201_regmap8_config); + if (IS_ERR(chip->regmap)) + return dev_err_probe(dev, PTR_ERR(chip->regmap), + "Failed to init regmap\n"); + + chip->regmap16 = devm_regmap_init_i2c(client, &nct7201_regmap16_config); + if (IS_ERR(chip->regmap16)) + return dev_err_probe(dev, PTR_ERR(chip->regmap16), + "Failed to init regmap16\n"); + + chip->num_vin_channels = model_data->num_vin_channels; + + ret = nct7201_init_chip(chip); + if (ret) + return ret; + + indio_dev->name = model_data->model_name; + indio_dev->channels = model_data->channels; + indio_dev->num_channels = model_data->num_channels; + if (client->irq) { + /* Enable alert function */ + ret = regmap_clear_bits(chip->regmap, NCT7201_REG_CONFIGURATION, + NCT7201_BIT_CONFIGURATION_ALERT_MSK); + if (ret) + return dev_err_probe(dev, ret, + "Failed to enable alert function\n"); + + ret = devm_request_threaded_irq(dev, client->irq, + NULL, nct7201_irq_handler, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, + client->name, indio_dev); + if (ret) + return dev_err_probe(dev, ret, + "Failed to assign interrupt.\n"); + + indio_dev->info = &nct7201_info; + } else { + indio_dev->info = &nct7201_info_no_irq; + } + indio_dev->modes = INDIO_DIRECT_MODE; + + return devm_iio_device_register(dev, indio_dev); +} + +static const struct i2c_device_id nct7201_id[] = { + { .name = "nct7201", .driver_data = (kernel_ulong_t)&nct7201_model_data }, + { .name = "nct7202", .driver_data = (kernel_ulong_t)&nct7202_model_data }, + { } +}; +MODULE_DEVICE_TABLE(i2c, nct7201_id); + +static const struct of_device_id nct7201_of_match[] = { + { + .compatible = "nuvoton,nct7201", + .data = &nct7201_model_data, + }, + { + .compatible = "nuvoton,nct7202", + .data = &nct7202_model_data, + }, + { } +}; +MODULE_DEVICE_TABLE(of, nct7201_of_match); + +static struct i2c_driver nct7201_driver = { + .driver = { + .name = "nct7201", + .of_match_table = nct7201_of_match, + }, + .probe = nct7201_probe, + .id_table = nct7201_id, +}; +module_i2c_driver(nct7201_driver); + +MODULE_AUTHOR("Eason Yang <j2anfernee@gmail.com>"); +MODULE_DESCRIPTION("Nuvoton NCT7201 voltage monitor driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/adc/npcm_adc.c b/drivers/iio/adc/npcm_adc.c index 7c1511ee3a4b..c8283873cdee 100644 --- a/drivers/iio/adc/npcm_adc.c +++ b/drivers/iio/adc/npcm_adc.c @@ -196,7 +196,7 @@ static const struct iio_info npcm_adc_iio_info = { static const struct of_device_id npcm_adc_match[] = { { .compatible = "nuvoton,npcm750-adc", .data = &npxm7xx_adc_info}, { .compatible = "nuvoton,npcm845-adc", .data = &npxm8xx_adc_info}, - { /* sentinel */ } + { } }; MODULE_DEVICE_TABLE(of, npcm_adc_match); diff --git a/drivers/iio/adc/pac1921.c b/drivers/iio/adc/pac1921.c index beb5511c4504..72aa4ca2e5a4 100644 --- a/drivers/iio/adc/pac1921.c +++ b/drivers/iio/adc/pac1921.c @@ -900,7 +900,7 @@ static ssize_t pac1921_read_scale_avail(struct iio_dev *indio_dev, static const struct iio_chan_spec_ext_info pac1921_ext_info_voltage[] = { PAC1921_EXT_INFO_SCALE_AVAIL, - {} + { } }; static const struct iio_chan_spec_ext_info pac1921_ext_info_current[] = { @@ -911,7 +911,7 @@ static const struct iio_chan_spec_ext_info pac1921_ext_info_current[] = { .write = pac1921_write_shunt_resistor, .shared = IIO_SEPARATE, }, - {} + { } }; static const struct iio_event_spec pac1921_overflow_event[] = { @@ -1044,7 +1044,8 @@ static irqreturn_t pac1921_trigger_handler(int irq, void *p) priv->scan.chan[ch++] = val; } - iio_push_to_buffers_with_timestamp(idev, &priv->scan, pf->timestamp); + iio_push_to_buffers_with_ts(idev, &priv->scan, sizeof(priv->scan), + pf->timestamp); done: iio_trigger_notify_done(idev->trig); diff --git a/drivers/iio/adc/pac1934.c b/drivers/iio/adc/pac1934.c index 20802b7f49ea..09fe88eb3fb0 100644 --- a/drivers/iio/adc/pac1934.c +++ b/drivers/iio/adc/pac1934.c @@ -1081,7 +1081,7 @@ static int pac1934_chip_identify(struct pac1934_chip_info *info) /* * documentation related to the ACPI device definition - * https://ww1.microchip.com/downloads/aemDocuments/documents/OTH/ApplicationNotes/ApplicationNotes/PAC1934-Integration-Notes-for-Microsoft-Windows-10-and-Windows-11-Driver-Support-DS00002534.pdf + * https://ww1.microchip.com/downloads/aemDocuments/documents/OTH/ApplicationNotes/ApplicationNotes/PAC193X-Integration-Notes-for-Microsoft-Windows-10-and-Windows-11-Driver-Support-DS00002534.pdf */ static int pac1934_acpi_parse_channel_config(struct i2c_client *client, struct pac1934_chip_info *info) diff --git a/drivers/iio/adc/palmas_gpadc.c b/drivers/iio/adc/palmas_gpadc.c index d283ee8fb1d2..7c01e33be04c 100644 --- a/drivers/iio/adc/palmas_gpadc.c +++ b/drivers/iio/adc/palmas_gpadc.c @@ -1164,7 +1164,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(palmas_pm_ops, palmas_gpadc_suspend, static const struct of_device_id of_palmas_gpadc_match_tbl[] = { { .compatible = "ti,palmas-gpadc", }, - { /* end */ } + { } }; MODULE_DEVICE_TABLE(of, of_palmas_gpadc_match_tbl); diff --git a/drivers/iio/adc/rcar-gyroadc.c b/drivers/iio/adc/rcar-gyroadc.c index 11170b5852d1..cc326f21d398 100644 --- a/drivers/iio/adc/rcar-gyroadc.c +++ b/drivers/iio/adc/rcar-gyroadc.c @@ -199,13 +199,12 @@ static int rcar_gyroadc_read_raw(struct iio_dev *indio_dev, if (!consumer) return -EINVAL; - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; ret = rcar_gyroadc_set_power(priv, true); if (ret < 0) { - iio_device_release_direct_mode(indio_dev); + iio_device_release_direct(indio_dev); return ret; } @@ -213,7 +212,7 @@ static int rcar_gyroadc_read_raw(struct iio_dev *indio_dev, *val &= BIT(priv->sample_width) - 1; ret = rcar_gyroadc_set_power(priv, false); - iio_device_release_direct_mode(indio_dev); + iio_device_release_direct(indio_dev); if (ret < 0) return ret; @@ -308,7 +307,7 @@ static const struct of_device_id rcar_gyroadc_child_match[] __maybe_unused = { .compatible = "maxim,max11100", .data = (void *)RCAR_GYROADC_MODE_SELECT_3_MAX1162, }, - { /* sentinel */ } + { } }; static int rcar_gyroadc_parse_subdevs(struct iio_dev *indio_dev) diff --git a/drivers/iio/adc/rn5t618-adc.c b/drivers/iio/adc/rn5t618-adc.c index b33536157adc..d6f6b351f2af 100644 --- a/drivers/iio/adc/rn5t618-adc.c +++ b/drivers/iio/adc/rn5t618-adc.c @@ -188,7 +188,7 @@ static const struct iio_chan_spec rn5t618_adc_iio_channels[] = { static const struct iio_map rn5t618_maps[] = { IIO_MAP("VADP", "rn5t618-power", "vadp"), IIO_MAP("VUSB", "rn5t618-power", "vusb"), - { /* sentinel */ } + { } }; static int rn5t618_adc_probe(struct platform_device *pdev) diff --git a/drivers/iio/adc/rockchip_saradc.c b/drivers/iio/adc/rockchip_saradc.c index 5e28bd28b81a..325e3747a134 100644 --- a/drivers/iio/adc/rockchip_saradc.c +++ b/drivers/iio/adc/rockchip_saradc.c @@ -425,7 +425,8 @@ static irqreturn_t rockchip_saradc_trigger_handler(int irq, void *p) j++; } - iio_push_to_buffers_with_timestamp(i_dev, &data, iio_get_time_ns(i_dev)); + iio_push_to_buffers_with_ts(i_dev, &data, sizeof(data), + iio_get_time_ns(i_dev)); out: mutex_unlock(&info->lock); diff --git a/drivers/iio/adc/rohm-bd79124.c b/drivers/iio/adc/rohm-bd79124.c new file mode 100644 index 000000000000..bb7c93ae4055 --- /dev/null +++ b/drivers/iio/adc/rohm-bd79124.c @@ -0,0 +1,1146 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * ROHM ADC driver for BD79124 ADC/GPO device + * https://fscdn.rohm.com/en/products/databook/datasheet/ic/data_converter/dac/bd79124muf-c-e.pdf + * + * Copyright (c) 2025, ROHM Semiconductor. + */ + +#include <linux/array_size.h> +#include <linux/bitfield.h> +#include <linux/bitmap.h> +#include <linux/bits.h> +#include <linux/device.h> +#include <linux/delay.h> +#include <linux/devm-helpers.h> +#include <linux/err.h> +#include <linux/gpio/driver.h> +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/irqreturn.h> +#include <linux/module.h> +#include <linux/mod_devicetable.h> +#include <linux/regmap.h> +#include <linux/types.h> + +#include <asm/byteorder.h> + +#include <linux/iio/events.h> +#include <linux/iio/iio.h> +#include <linux/iio/adc-helpers.h> + +#define BD79124_I2C_MULTI_READ 0x30 +#define BD79124_I2C_MULTI_WRITE 0x28 +#define BD79124_REG_MAX 0xaf + +#define BD79124_REG_SYSTEM_STATUS 0x00 +#define BD79124_REG_GEN_CFG 0x01 +#define BD79124_REG_OPMODE_CFG 0x04 +#define BD79124_REG_PINCFG 0x05 +#define BD79124_REG_GPO_VAL 0x0B +#define BD79124_REG_SEQ_CFG 0x10 +#define BD79124_REG_MANUAL_CHANNELS 0x11 +#define BD79124_REG_AUTO_CHANNELS 0x12 +#define BD79124_REG_ALERT_CH_SEL 0x14 +#define BD79124_REG_EVENT_FLAG 0x18 +#define BD79124_REG_EVENT_FLAG_HI 0x1a +#define BD79124_REG_EVENT_FLAG_LO 0x1c +#define BD79124_REG_HYSTERESIS_CH0 0x20 +#define BD79124_REG_EVENTCOUNT_CH0 0x22 +#define BD79124_REG_RECENT_CH0_LSB 0xa0 +#define BD79124_REG_RECENT_CH7_MSB 0xaf + +#define BD79124_ADC_BITS 12 + +/* Masks for the BD79124_REG_OPMODE_CFG */ +#define BD79124_MSK_CONV_MODE GENMASK(6, 5) +#define BD79124_CONV_MODE_MANSEQ 0 +#define BD79124_CONV_MODE_AUTO 1 +#define BD79124_MSK_AUTO_INTERVAL GENMASK(1, 0) +#define BD79124_INTERVAL_750_US 0 + +/* Masks for the BD79124_REG_GEN_CFG */ +#define BD79124_MSK_DWC_EN BIT(4) +#define BD79124_MSK_STATS_EN BIT(5) + +/* Masks for the BD79124_REG_SEQ_CFG */ +#define BD79124_MSK_SEQ_START BIT(4) +#define BD79124_MSK_SEQ_MODE GENMASK(1, 0) +#define BD79124_MSK_SEQ_MANUAL 0 +#define BD79124_MSK_SEQ_SEQ 1 + +#define BD79124_MSK_HYSTERESIS GENMASK(3, 0) +#define BD79124_LOW_LIMIT_MIN 0 +#define BD79124_HIGH_LIMIT_MAX GENMASK(11, 0) + +/* + * The high limit, low limit and last measurement result are each stored in + * 2 consequtive registers. 4 bits are in the high bits of the first register + * and 8 bits in the next register. + * + * These macros return the address of the first reg for the given channel. + */ +#define BD79124_GET_HIGH_LIMIT_REG(ch) (BD79124_REG_HYSTERESIS_CH0 + (ch) * 4) +#define BD79124_GET_LOW_LIMIT_REG(ch) (BD79124_REG_EVENTCOUNT_CH0 + (ch) * 4) +#define BD79124_GET_LIMIT_REG(ch, dir) ((dir) == IIO_EV_DIR_RISING ? \ + BD79124_GET_HIGH_LIMIT_REG(ch) : BD79124_GET_LOW_LIMIT_REG(ch)) +#define BD79124_GET_RECENT_RES_REG(ch) (BD79124_REG_RECENT_CH0_LSB + (ch) * 2) + +/* + * The hysteresis for a channel is stored in the same register where the + * 4 bits of high limit reside. + */ +#define BD79124_GET_HYSTERESIS_REG(ch) BD79124_GET_HIGH_LIMIT_REG(ch) + +#define BD79124_MAX_NUM_CHANNELS 8 + +struct bd79124_data { + s64 timestamp; + struct regmap *map; + struct device *dev; + int vmax; + /* + * Keep measurement status so read_raw() knows if the measurement needs + * to be started. + */ + int alarm_monitored[BD79124_MAX_NUM_CHANNELS]; + /* + * The BD79124 does not allow disabling/enabling limit separately for + * one direction only. Hence, we do the disabling by changing the limit + * to maximum/minimum measurable value. This means we need to cache + * the limit in order to maintain it over the time limit is disabled. + */ + u16 alarm_r_limit[BD79124_MAX_NUM_CHANNELS]; + u16 alarm_f_limit[BD79124_MAX_NUM_CHANNELS]; + /* Bitmask of disabled events (for rate limiting) for each channel. */ + int alarm_suppressed[BD79124_MAX_NUM_CHANNELS]; + /* + * The BD79124 is configured to run the measurements in the background. + * This is done for the event monitoring as well as for the read_raw(). + * Protect the measurement starting/stopping using a mutex. + */ + struct mutex mutex; + struct delayed_work alm_enable_work; + struct gpio_chip gc; + u8 gpio_valid_mask; +}; + +static const struct regmap_range bd79124_ro_ranges[] = { + { + .range_min = BD79124_REG_EVENT_FLAG, + .range_max = BD79124_REG_EVENT_FLAG, + }, { + .range_min = BD79124_REG_RECENT_CH0_LSB, + .range_max = BD79124_REG_RECENT_CH7_MSB, + }, +}; + +static const struct regmap_access_table bd79124_ro_regs = { + .no_ranges = &bd79124_ro_ranges[0], + .n_no_ranges = ARRAY_SIZE(bd79124_ro_ranges), +}; + +static const struct regmap_range bd79124_volatile_ranges[] = { + { + .range_min = BD79124_REG_RECENT_CH0_LSB, + .range_max = BD79124_REG_RECENT_CH7_MSB, + }, { + .range_min = BD79124_REG_EVENT_FLAG, + .range_max = BD79124_REG_EVENT_FLAG, + }, { + .range_min = BD79124_REG_EVENT_FLAG_HI, + .range_max = BD79124_REG_EVENT_FLAG_HI, + }, { + .range_min = BD79124_REG_EVENT_FLAG_LO, + .range_max = BD79124_REG_EVENT_FLAG_LO, + }, { + .range_min = BD79124_REG_SYSTEM_STATUS, + .range_max = BD79124_REG_SYSTEM_STATUS, + }, +}; + +static const struct regmap_access_table bd79124_volatile_regs = { + .yes_ranges = &bd79124_volatile_ranges[0], + .n_yes_ranges = ARRAY_SIZE(bd79124_volatile_ranges), +}; + +static const struct regmap_range bd79124_precious_ranges[] = { + { + .range_min = BD79124_REG_EVENT_FLAG_HI, + .range_max = BD79124_REG_EVENT_FLAG_HI, + }, { + .range_min = BD79124_REG_EVENT_FLAG_LO, + .range_max = BD79124_REG_EVENT_FLAG_LO, + }, +}; + +static const struct regmap_access_table bd79124_precious_regs = { + .yes_ranges = &bd79124_precious_ranges[0], + .n_yes_ranges = ARRAY_SIZE(bd79124_precious_ranges), +}; + +static const struct regmap_config bd79124_regmap = { + .reg_bits = 16, + .val_bits = 8, + .read_flag_mask = BD79124_I2C_MULTI_READ, + .write_flag_mask = BD79124_I2C_MULTI_WRITE, + .max_register = BD79124_REG_MAX, + .cache_type = REGCACHE_MAPLE, + .volatile_table = &bd79124_volatile_regs, + .wr_table = &bd79124_ro_regs, + .precious_table = &bd79124_precious_regs, +}; + +static int bd79124gpo_direction_get(struct gpio_chip *gc, unsigned int offset) +{ + return GPIO_LINE_DIRECTION_OUT; +} + +static int bd79124gpo_set(struct gpio_chip *gc, unsigned int offset, int value) +{ + struct bd79124_data *data = gpiochip_get_data(gc); + + return regmap_assign_bits(data->map, BD79124_REG_GPO_VAL, BIT(offset), + value); +} + +static int bd79124gpo_set_multiple(struct gpio_chip *gc, unsigned long *mask, + unsigned long *bits) +{ + unsigned int all_gpos; + int ret; + struct bd79124_data *data = gpiochip_get_data(gc); + + /* + * Ensure all GPIOs in 'mask' are set to be GPIOs + * The valid_mask was not obeyed by the gpiolib in all cases prior the + * https://lore.kernel.org/all/cd5e067b80e1bb590027bc3bfa817e7f794f21c3.1741180097.git.mazziesaccount@gmail.com/ + * + * Keep this check here for a couple of cycles. + */ + ret = regmap_read(data->map, BD79124_REG_PINCFG, &all_gpos); + if (ret) + return ret; + + if (all_gpos ^ *mask) { + dev_dbg(data->dev, "Invalid mux config. Can't set value.\n"); + + return -EINVAL; + } + + return regmap_update_bits(data->map, BD79124_REG_GPO_VAL, *mask, *bits); +} + +static int bd79124_init_valid_mask(struct gpio_chip *gc, + unsigned long *valid_mask, + unsigned int ngpios) +{ + struct bd79124_data *data = gpiochip_get_data(gc); + + *valid_mask = data->gpio_valid_mask; + + return 0; +} + +/* Template for GPIO chip */ +static const struct gpio_chip bd79124gpo_chip = { + .label = "bd79124-gpo", + .get_direction = bd79124gpo_direction_get, + .set_rv = bd79124gpo_set, + .set_multiple_rv = bd79124gpo_set_multiple, + .init_valid_mask = bd79124_init_valid_mask, + .can_sleep = true, + .ngpio = 8, + .base = -1, +}; + +struct bd79124_raw { + u8 val_bit3_0; /* Is set in high bits of the byte */ + u8 val_bit11_4; +}; +#define BD79124_RAW_TO_INT(r) ((r.val_bit11_4 << 4) | (r.val_bit3_0 >> 4)) +#define BD79124_INT_TO_RAW(val) { \ + .val_bit11_4 = (val) >> 4, \ + .val_bit3_0 = (val) << 4, \ +} + +/* + * The high and low limits as well as the recent result values are stored in + * the same way in 2 consequent registers. The first register contains 4 bits + * of the value. These bits are stored in the high bits [7:4] of register, but + * they represent the low bits [3:0] of the value. + * The value bits [11:4] are stored in the next register. + * + * Read data from register and convert to integer. + */ +static int bd79124_read_reg_to_int(struct bd79124_data *data, int reg, + unsigned int *val) +{ + int ret; + struct bd79124_raw raw; + + ret = regmap_bulk_read(data->map, reg, &raw, sizeof(raw)); + if (ret) { + dev_dbg(data->dev, "bulk_read failed %d\n", ret); + + return ret; + } + + *val = BD79124_RAW_TO_INT(raw); + + return 0; +} + +/* + * The high and low limits as well as the recent result values are stored in + * the same way in 2 consequent registers. The first register contains 4 bits + * of the value. These bits are stored in the high bits [7:4] of register, but + * they represent the low bits [3:0] of the value. + * The value bits [11:4] are stored in the next register. + * + * Convert the integer to register format and write it using rmw cycle. + */ +static int bd79124_write_int_to_reg(struct bd79124_data *data, int reg, + unsigned int val) +{ + struct bd79124_raw raw = BD79124_INT_TO_RAW(val); + unsigned int tmp; + int ret; + + ret = regmap_read(data->map, reg, &tmp); + if (ret) + return ret; + + raw.val_bit3_0 |= (tmp & 0xf); + + return regmap_bulk_write(data->map, reg, &raw, sizeof(raw)); +} + +static const struct iio_event_spec bd79124_events[] = { + { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_RISING, + .mask_separate = BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_ENABLE), + }, + { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_FALLING, + .mask_separate = BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_ENABLE), + }, + { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_EITHER, + .mask_separate = BIT(IIO_EV_INFO_HYSTERESIS), + }, +}; + +static const struct iio_chan_spec bd79124_chan_template_noirq = { + .type = IIO_VOLTAGE, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), + .indexed = 1, +}; + +static const struct iio_chan_spec bd79124_chan_template = { + .type = IIO_VOLTAGE, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), + .indexed = 1, + .event_spec = bd79124_events, + .num_event_specs = ARRAY_SIZE(bd79124_events), +}; + +static int bd79124_read_event_value(struct iio_dev *iio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, int *val, + int *val2) +{ + struct bd79124_data *data = iio_priv(iio_dev); + int ret, reg; + + if (chan->channel >= BD79124_MAX_NUM_CHANNELS) + return -EINVAL; + + switch (info) { + case IIO_EV_INFO_VALUE: + if (dir == IIO_EV_DIR_RISING) + *val = data->alarm_r_limit[chan->channel]; + else if (dir == IIO_EV_DIR_FALLING) + *val = data->alarm_f_limit[chan->channel]; + else + return -EINVAL; + + return IIO_VAL_INT; + + case IIO_EV_INFO_HYSTERESIS: + reg = BD79124_GET_HYSTERESIS_REG(chan->channel); + ret = regmap_read(data->map, reg, val); + if (ret) + return ret; + + *val &= BD79124_MSK_HYSTERESIS; + /* + * The data-sheet says the hysteresis register value needs to be + * shifted left by 3. + */ + *val <<= 3; + + return IIO_VAL_INT; + + default: + return -EINVAL; + } +} + +static int bd79124_start_measurement(struct bd79124_data *data, int chan) +{ + unsigned int val, regval; + int ret; + + /* See if already started */ + ret = regmap_read(data->map, BD79124_REG_AUTO_CHANNELS, &val); + if (val & BIT(chan)) + return 0; + + /* + * The sequencer must be stopped when channels are added/removed from + * the list of the measured channels to ensure the new channel + * configuration is used. + */ + ret = regmap_clear_bits(data->map, BD79124_REG_SEQ_CFG, + BD79124_MSK_SEQ_START); + if (ret) + return ret; + + ret = regmap_write(data->map, BD79124_REG_AUTO_CHANNELS, val | BIT(chan)); + if (ret) + return ret; + + ret = regmap_set_bits(data->map, BD79124_REG_SEQ_CFG, + BD79124_MSK_SEQ_START); + if (ret) + return ret; + + /* + * Start the measurement at the background. Don't bother checking if + * it was started, regmap has cache. + */ + regval = FIELD_PREP(BD79124_MSK_CONV_MODE, BD79124_CONV_MODE_AUTO); + + return regmap_update_bits(data->map, BD79124_REG_OPMODE_CFG, + BD79124_MSK_CONV_MODE, regval); +} + +static int bd79124_stop_measurement(struct bd79124_data *data, int chan) +{ + unsigned int enabled_chans; + int ret; + + /* See if already stopped */ + ret = regmap_read(data->map, BD79124_REG_AUTO_CHANNELS, &enabled_chans); + if (!(enabled_chans & BIT(chan))) + return 0; + + ret = regmap_clear_bits(data->map, BD79124_REG_SEQ_CFG, + BD79124_MSK_SEQ_START); + + /* Clear the channel from the measured channels */ + enabled_chans &= ~BIT(chan); + ret = regmap_write(data->map, BD79124_REG_AUTO_CHANNELS, + enabled_chans); + if (ret) + return ret; + + /* + * Stop background conversion for power saving if it was the last + * channel. + */ + if (!enabled_chans) { + int regval = FIELD_PREP(BD79124_MSK_CONV_MODE, + BD79124_CONV_MODE_MANSEQ); + + ret = regmap_update_bits(data->map, BD79124_REG_OPMODE_CFG, + BD79124_MSK_CONV_MODE, regval); + if (ret) + return ret; + } + + return regmap_set_bits(data->map, BD79124_REG_SEQ_CFG, + BD79124_MSK_SEQ_START); +} + +static int bd79124_read_event_config(struct iio_dev *iio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir) +{ + struct bd79124_data *data = iio_priv(iio_dev); + + if (chan->channel >= BD79124_MAX_NUM_CHANNELS) + return -EINVAL; + + return !!(data->alarm_monitored[chan->channel] & BIT(dir)); +} + +static int bd79124_disable_event(struct bd79124_data *data, + enum iio_event_direction dir, int channel) +{ + int dir_bit = BIT(dir); + int reg; + unsigned int limit; + + guard(mutex)(&data->mutex); + + /* + * Set thresholds either to 0 or to 2^12 - 1 as appropriate to prevent + * alerts and thus disable event generation. + */ + if (dir == IIO_EV_DIR_RISING) { + reg = BD79124_GET_HIGH_LIMIT_REG(channel); + limit = BD79124_HIGH_LIMIT_MAX; + } else if (dir == IIO_EV_DIR_FALLING) { + reg = BD79124_GET_LOW_LIMIT_REG(channel); + limit = BD79124_LOW_LIMIT_MIN; + } else { + return -EINVAL; + } + + data->alarm_monitored[channel] &= ~dir_bit; + + /* + * Stop measurement if there is no more events to monitor. + * We don't bother checking the retval because the limit + * setting should in any case effectively disable the alarm. + */ + if (!data->alarm_monitored[channel]) { + bd79124_stop_measurement(data, channel); + regmap_clear_bits(data->map, BD79124_REG_ALERT_CH_SEL, + BIT(channel)); + } + + return bd79124_write_int_to_reg(data, reg, limit); +} + +static int bd79124_enable_event(struct bd79124_data *data, + enum iio_event_direction dir, + unsigned int channel) +{ + int dir_bit = BIT(dir); + int reg, ret; + u16 *limit; + + guard(mutex)(&data->mutex); + ret = bd79124_start_measurement(data, channel); + if (ret) + return ret; + + data->alarm_monitored[channel] |= dir_bit; + + /* Add the channel to the list of monitored channels */ + ret = regmap_set_bits(data->map, BD79124_REG_ALERT_CH_SEL, BIT(channel)); + if (ret) + return ret; + + if (dir == IIO_EV_DIR_RISING) { + limit = &data->alarm_f_limit[channel]; + reg = BD79124_GET_HIGH_LIMIT_REG(channel); + } else { + limit = &data->alarm_f_limit[channel]; + reg = BD79124_GET_LOW_LIMIT_REG(channel); + } + /* + * Don't write the new limit to the hardware if we are in the + * rate-limit period. The timer which re-enables the event will set + * the limit. + */ + if (!(data->alarm_suppressed[channel] & dir_bit)) { + ret = bd79124_write_int_to_reg(data, reg, *limit); + if (ret) + return ret; + } + + /* + * Enable comparator. Trust the regmap cache, no need to check + * if it was already enabled. + * + * We could do this in the hw-init, but there may be users who + * never enable alarms and for them it makes sense to not + * enable the comparator at probe. + */ + return regmap_set_bits(data->map, BD79124_REG_GEN_CFG, + BD79124_MSK_DWC_EN); +} + +static int bd79124_write_event_config(struct iio_dev *iio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, bool state) +{ + struct bd79124_data *data = iio_priv(iio_dev); + + if (chan->channel >= BD79124_MAX_NUM_CHANNELS) + return -EINVAL; + + if (state) + return bd79124_enable_event(data, dir, chan->channel); + + return bd79124_disable_event(data, dir, chan->channel); +} + +static int bd79124_write_event_value(struct iio_dev *iio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, int val, + int val2) +{ + struct bd79124_data *data = iio_priv(iio_dev); + int reg; + + if (chan->channel >= BD79124_MAX_NUM_CHANNELS) + return -EINVAL; + + switch (info) { + case IIO_EV_INFO_VALUE: + { + guard(mutex)(&data->mutex); + + if (dir == IIO_EV_DIR_RISING) { + data->alarm_r_limit[chan->channel] = val; + reg = BD79124_GET_HIGH_LIMIT_REG(chan->channel); + } else if (dir == IIO_EV_DIR_FALLING) { + data->alarm_f_limit[chan->channel] = val; + reg = BD79124_GET_LOW_LIMIT_REG(chan->channel); + } else { + return -EINVAL; + } + /* + * We don't want to enable the alarm if it is not enabled or + * if it is suppressed. In that case skip writing to the + * register. + */ + if (!(data->alarm_monitored[chan->channel] & BIT(dir)) || + data->alarm_suppressed[chan->channel] & BIT(dir)) + return 0; + + return bd79124_write_int_to_reg(data, reg, val); + } + case IIO_EV_INFO_HYSTERESIS: + reg = BD79124_GET_HYSTERESIS_REG(chan->channel); + val >>= 3; + + return regmap_update_bits(data->map, reg, BD79124_MSK_HYSTERESIS, + val); + default: + return -EINVAL; + } +} + +static int bd79124_single_chan_seq(struct bd79124_data *data, int chan, unsigned int *old) +{ + int ret; + + ret = regmap_clear_bits(data->map, BD79124_REG_SEQ_CFG, + BD79124_MSK_SEQ_START); + if (ret) + return ret; + + /* + * It may be we have some channels monitored for alarms so we want to + * cache the old config and return it when the single channel + * measurement has been completed. + */ + ret = regmap_read(data->map, BD79124_REG_AUTO_CHANNELS, old); + if (ret) + return ret; + + ret = regmap_write(data->map, BD79124_REG_AUTO_CHANNELS, BIT(chan)); + if (ret) + return ret; + + /* Restart the sequencer */ + return regmap_set_bits(data->map, BD79124_REG_SEQ_CFG, + BD79124_MSK_SEQ_START); +} + +static int bd79124_single_chan_seq_end(struct bd79124_data *data, unsigned int old) +{ + int ret; + + ret = regmap_clear_bits(data->map, BD79124_REG_SEQ_CFG, + BD79124_MSK_SEQ_START); + if (ret) + return ret; + + ret = regmap_write(data->map, BD79124_REG_AUTO_CHANNELS, old); + if (ret) + return ret; + + return regmap_set_bits(data->map, BD79124_REG_SEQ_CFG, + BD79124_MSK_SEQ_START); +} + +static int bd79124_read_raw(struct iio_dev *iio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long m) +{ + struct bd79124_data *data = iio_priv(iio_dev); + int ret; + + if (chan->channel >= BD79124_MAX_NUM_CHANNELS) + return -EINVAL; + + switch (m) { + case IIO_CHAN_INFO_RAW: + { + unsigned int old_chan_cfg, regval; + int tmp; + + guard(mutex)(&data->mutex); + + /* + * Start the automatic conversion. This is needed here if no + * events have been enabled. + */ + regval = FIELD_PREP(BD79124_MSK_CONV_MODE, + BD79124_CONV_MODE_AUTO); + ret = regmap_update_bits(data->map, BD79124_REG_OPMODE_CFG, + BD79124_MSK_CONV_MODE, regval); + if (ret) + return ret; + + ret = bd79124_single_chan_seq(data, chan->channel, &old_chan_cfg); + if (ret) + return ret; + + /* The maximum conversion time is 6 uS. */ + udelay(6); + + ret = bd79124_read_reg_to_int(data, + BD79124_GET_RECENT_RES_REG(chan->channel), val); + /* + * Return the old chan config even if data reading failed in + * order to re-enable the event monitoring. + */ + tmp = bd79124_single_chan_seq_end(data, old_chan_cfg); + if (tmp) + dev_err(data->dev, + "Failed to return config. Alarms may be disabled\n"); + + if (ret) + return ret; + + return IIO_VAL_INT; + } + case IIO_CHAN_INFO_SCALE: + *val = data->vmax / 1000; + *val2 = BD79124_ADC_BITS; + return IIO_VAL_FRACTIONAL_LOG2; + default: + return -EINVAL; + } +} + +static const struct iio_info bd79124_info = { + .read_raw = bd79124_read_raw, + .read_event_config = &bd79124_read_event_config, + .write_event_config = &bd79124_write_event_config, + .read_event_value = &bd79124_read_event_value, + .write_event_value = &bd79124_write_event_value, +}; + +static void bd79124_re_enable_lo(struct bd79124_data *data, unsigned int channel) +{ + int ret, evbit = BIT(IIO_EV_DIR_FALLING); + + /* + * We should not re-enable the event if user has disabled it while + * rate-limiting was enabled. + */ + if (!(data->alarm_suppressed[channel] & evbit)) + return; + + data->alarm_suppressed[channel] &= ~evbit; + + if (!(data->alarm_monitored[channel] & evbit)) + return; + + ret = bd79124_write_int_to_reg(data, BD79124_GET_LOW_LIMIT_REG(channel), + data->alarm_f_limit[channel]); + if (ret) + dev_warn(data->dev, "Low limit enabling failed for channel%d\n", + channel); +} + +static void bd79124_re_enable_hi(struct bd79124_data *data, unsigned int channel) +{ + int ret, evbit = BIT(IIO_EV_DIR_RISING); + + /* + * We should not re-enable the event if user has disabled it while + * rate-limiting was enabled. + */ + if (!(data->alarm_suppressed[channel] & evbit)) + return; + + data->alarm_suppressed[channel] &= ~evbit; + + if (!(data->alarm_monitored[channel] & evbit)) + return; + + ret = bd79124_write_int_to_reg(data, BD79124_GET_HIGH_LIMIT_REG(channel), + data->alarm_r_limit[channel]); + if (ret) + dev_warn(data->dev, "High limit enabling failed for channel%d\n", + channel); +} + +static void bd79124_alm_enable_worker(struct work_struct *work) +{ + int i; + struct bd79124_data *data = container_of(work, struct bd79124_data, + alm_enable_work.work); + + /* Take the mutex so there is no race with user disabling the alarm */ + guard(mutex)(&data->mutex); + for (i = 0; i < BD79124_MAX_NUM_CHANNELS; i++) { + bd79124_re_enable_hi(data, i); + bd79124_re_enable_lo(data, i); + } +} + +static int __bd79124_event_ratelimit(struct bd79124_data *data, int reg, + unsigned int limit) +{ + int ret; + + if (limit > BD79124_HIGH_LIMIT_MAX) + return -EINVAL; + + ret = bd79124_write_int_to_reg(data, reg, limit); + if (ret) + return ret; + + /* + * We use 1 sec 'grace period'. At the moment I see no reason to make + * this user configurable. We need an ABI for this if configuration is + * needed. + */ + schedule_delayed_work(&data->alm_enable_work, msecs_to_jiffies(1000)); + + return 0; +} + +static int bd79124_event_ratelimit_hi(struct bd79124_data *data, + unsigned int channel) +{ + guard(mutex)(&data->mutex); + data->alarm_suppressed[channel] |= BIT(IIO_EV_DIR_RISING); + + return __bd79124_event_ratelimit(data, + BD79124_GET_HIGH_LIMIT_REG(channel), + BD79124_HIGH_LIMIT_MAX); +} + +static int bd79124_event_ratelimit_lo(struct bd79124_data *data, + unsigned int channel) +{ + guard(mutex)(&data->mutex); + data->alarm_suppressed[channel] |= BIT(IIO_EV_DIR_FALLING); + + return __bd79124_event_ratelimit(data, + BD79124_GET_LOW_LIMIT_REG(channel), + BD79124_LOW_LIMIT_MIN); +} + +static irqreturn_t bd79124_event_handler(int irq, void *priv) +{ + unsigned int i_hi, i_lo; + int i, ret; + struct iio_dev *iio_dev = priv; + struct bd79124_data *data = iio_priv(iio_dev); + + /* + * Return IRQ_NONE if bailing-out without acking. This allows the IRQ + * subsystem to disable the offending IRQ line if we get a hardware + * problem. This behaviour has saved my poor bottom a few times in the + * past as, instead of getting unusably unresponsive, the system has + * spilled out the magic words "...nobody cared". + */ + ret = regmap_read(data->map, BD79124_REG_EVENT_FLAG_HI, &i_hi); + if (ret) + return IRQ_NONE; + + ret = regmap_read(data->map, BD79124_REG_EVENT_FLAG_LO, &i_lo); + if (ret) + return IRQ_NONE; + + if (!i_lo && !i_hi) + return IRQ_NONE; + + for (i = 0; i < BD79124_MAX_NUM_CHANNELS; i++) { + u64 ecode; + + if (BIT(i) & i_hi) { + ecode = IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, i, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_RISING); + + iio_push_event(iio_dev, ecode, data->timestamp); + /* + * The BD79124 keeps the IRQ asserted for as long as + * the voltage exceeds the threshold. It causes the IRQ + * to keep firing. + * + * Disable the event for the channel and schedule the + * re-enabling the event later to prevent storm of + * events. + */ + ret = bd79124_event_ratelimit_hi(data, i); + if (ret) + return IRQ_NONE; + } + if (BIT(i) & i_lo) { + ecode = IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, i, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_FALLING); + + iio_push_event(iio_dev, ecode, data->timestamp); + ret = bd79124_event_ratelimit_lo(data, i); + if (ret) + return IRQ_NONE; + } + } + + ret = regmap_write(data->map, BD79124_REG_EVENT_FLAG_HI, i_hi); + if (ret) + return IRQ_NONE; + + ret = regmap_write(data->map, BD79124_REG_EVENT_FLAG_LO, i_lo); + if (ret) + return IRQ_NONE; + + return IRQ_HANDLED; +} + +static irqreturn_t bd79124_irq_handler(int irq, void *priv) +{ + struct iio_dev *iio_dev = priv; + struct bd79124_data *data = iio_priv(iio_dev); + + data->timestamp = iio_get_time_ns(iio_dev); + + return IRQ_WAKE_THREAD; +} + +static int bd79124_chan_init(struct bd79124_data *data, int channel) +{ + int ret; + + ret = regmap_write(data->map, BD79124_GET_HIGH_LIMIT_REG(channel), + BD79124_HIGH_LIMIT_MAX); + if (ret) + return ret; + + return regmap_write(data->map, BD79124_GET_LOW_LIMIT_REG(channel), + BD79124_LOW_LIMIT_MIN); +} + +static int bd79124_get_gpio_pins(const struct iio_chan_spec *cs, int num_channels) +{ + int i, gpio_channels; + + /* + * Let's initialize the mux config to say that all 8 channels are + * GPIOs. Then we can just loop through the iio_chan_spec and clear the + * bits for found ADC channels. + */ + gpio_channels = GENMASK(7, 0); + for (i = 0; i < num_channels; i++) + gpio_channels &= ~BIT(cs[i].channel); + + return gpio_channels; +} + +static int bd79124_hw_init(struct bd79124_data *data) +{ + unsigned int regval; + int ret, i; + + for (i = 0; i < BD79124_MAX_NUM_CHANNELS; i++) { + ret = bd79124_chan_init(data, i); + if (ret) + return ret; + data->alarm_r_limit[i] = BD79124_HIGH_LIMIT_MAX; + } + /* Stop auto sequencer */ + ret = regmap_clear_bits(data->map, BD79124_REG_SEQ_CFG, + BD79124_MSK_SEQ_START); + if (ret) + return ret; + + /* Enable writing the measured values to the regsters */ + ret = regmap_set_bits(data->map, BD79124_REG_GEN_CFG, + BD79124_MSK_STATS_EN); + if (ret) + return ret; + + /* Set no channels to be auto-measured */ + ret = regmap_write(data->map, BD79124_REG_AUTO_CHANNELS, 0x0); + if (ret) + return ret; + + /* Set no channels to be manually measured */ + ret = regmap_write(data->map, BD79124_REG_MANUAL_CHANNELS, 0x0); + if (ret) + return ret; + + regval = FIELD_PREP(BD79124_MSK_AUTO_INTERVAL, BD79124_INTERVAL_750_US); + ret = regmap_update_bits(data->map, BD79124_REG_OPMODE_CFG, + BD79124_MSK_AUTO_INTERVAL, regval); + if (ret) + return ret; + + /* Sequencer mode to auto */ + ret = regmap_set_bits(data->map, BD79124_REG_SEQ_CFG, + BD79124_MSK_SEQ_SEQ); + if (ret) + return ret; + + /* Don't start the measurement */ + regval = FIELD_PREP(BD79124_MSK_CONV_MODE, BD79124_CONV_MODE_MANSEQ); + return regmap_update_bits(data->map, BD79124_REG_OPMODE_CFG, + BD79124_MSK_CONV_MODE, regval); +} + +static int bd79124_probe(struct i2c_client *i2c) +{ + struct bd79124_data *data; + struct iio_dev *iio_dev; + const struct iio_chan_spec *template; + struct iio_chan_spec *cs; + struct device *dev = &i2c->dev; + unsigned int gpio_pins; + int ret; + + iio_dev = devm_iio_device_alloc(dev, sizeof(*data)); + if (!iio_dev) + return -ENOMEM; + + data = iio_priv(iio_dev); + data->dev = dev; + data->map = devm_regmap_init_i2c(i2c, &bd79124_regmap); + if (IS_ERR(data->map)) + return dev_err_probe(dev, PTR_ERR(data->map), + "Failed to initialize Regmap\n"); + + ret = devm_regulator_get_enable_read_voltage(dev, "vdd"); + if (ret < 0) + return dev_err_probe(dev, ret, "Failed to get the Vdd\n"); + + data->vmax = ret; + + ret = devm_regulator_get_enable(dev, "iovdd"); + if (ret < 0) + return dev_err_probe(dev, ret, "Failed to enable I/O voltage\n"); + + ret = devm_delayed_work_autocancel(dev, &data->alm_enable_work, + bd79124_alm_enable_worker); + if (ret) + return ret; + + if (i2c->irq) { + template = &bd79124_chan_template; + } else { + template = &bd79124_chan_template_noirq; + dev_dbg(dev, "No IRQ found, events disabled\n"); + } + + ret = devm_mutex_init(dev, &data->mutex); + if (ret) + return ret; + + ret = devm_iio_adc_device_alloc_chaninfo_se(dev, template, + BD79124_MAX_NUM_CHANNELS - 1, &cs); + if (ret < 0) { + /* Register all pins as GPOs if there are no ADC channels */ + if (ret == -ENOENT) + goto register_gpios; + return ret; + } + iio_dev->channels = cs; + iio_dev->num_channels = ret; + iio_dev->info = &bd79124_info; + iio_dev->name = "bd79124"; + iio_dev->modes = INDIO_DIRECT_MODE; + + ret = bd79124_hw_init(data); + if (ret) + return ret; + + if (i2c->irq > 0) { + ret = devm_request_threaded_irq(dev, i2c->irq, + bd79124_irq_handler, &bd79124_event_handler, + IRQF_ONESHOT, "adc-thresh-alert", iio_dev); + if (ret) + return dev_err_probe(data->dev, ret, + "Failed to register IRQ\n"); + } + + ret = devm_iio_device_register(data->dev, iio_dev); + if (ret) + return dev_err_probe(data->dev, ret, "Failed to register ADC\n"); + +register_gpios: + gpio_pins = bd79124_get_gpio_pins(iio_dev->channels, + iio_dev->num_channels); + + /* + * The mux should default to "all ADCs", but better to not trust it. + * Thus we do set the mux even when we have only ADCs and no GPOs. + */ + ret = regmap_write(data->map, BD79124_REG_PINCFG, gpio_pins); + if (ret) + return ret; + + /* No GPOs if all channels are reserved for ADC, so we're done. */ + if (!gpio_pins) + return 0; + + data->gpio_valid_mask = gpio_pins; + data->gc = bd79124gpo_chip; + data->gc.parent = dev; + + return devm_gpiochip_add_data(dev, &data->gc, data); +} + +static const struct of_device_id bd79124_of_match[] = { + { .compatible = "rohm,bd79124" }, + { } +}; +MODULE_DEVICE_TABLE(of, bd79124_of_match); + +static const struct i2c_device_id bd79124_id[] = { + { "bd79124" }, + { } +}; +MODULE_DEVICE_TABLE(i2c, bd79124_id); + +static struct i2c_driver bd79124_driver = { + .driver = { + .name = "bd79124", + .of_match_table = bd79124_of_match, + }, + .probe = bd79124_probe, + .id_table = bd79124_id, +}; +module_i2c_driver(bd79124_driver); + +MODULE_AUTHOR("Matti Vaittinen <mazziesaccount@gmail.com>"); +MODULE_DESCRIPTION("Driver for ROHM BD79124 ADC"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("IIO_DRIVER"); diff --git a/drivers/iio/adc/rtq6056.c b/drivers/iio/adc/rtq6056.c index 54239df61d86..6ff47415a222 100644 --- a/drivers/iio/adc/rtq6056.c +++ b/drivers/iio/adc/rtq6056.c @@ -666,7 +666,8 @@ static irqreturn_t rtq6056_buffer_trigger_handler(int irq, void *p) data.vals[i++] = raw; } - iio_push_to_buffers_with_timestamp(indio_dev, &data, iio_get_time_ns(indio_dev)); + iio_push_to_buffers_with_ts(indio_dev, &data, sizeof(data), + iio_get_time_ns(indio_dev)); out: pm_runtime_mark_last_busy(dev); diff --git a/drivers/iio/adc/rzg2l_adc.c b/drivers/iio/adc/rzg2l_adc.c index 883c167c0670..9674d48074c9 100644 --- a/drivers/iio/adc/rzg2l_adc.c +++ b/drivers/iio/adc/rzg2l_adc.c @@ -11,6 +11,7 @@ #include <linux/cleanup.h> #include <linux/completion.h> #include <linux/delay.h> +#include <linux/iio/adc-helpers.h> #include <linux/iio/iio.h> #include <linux/interrupt.h> #include <linux/io.h> @@ -324,48 +325,39 @@ static irqreturn_t rzg2l_adc_isr(int irq, void *dev_id) return IRQ_HANDLED; } +static const struct iio_chan_spec rzg2l_adc_chan_template = { + .indexed = 1, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), +}; + static int rzg2l_adc_parse_properties(struct platform_device *pdev, struct rzg2l_adc *adc) { const struct rzg2l_adc_hw_params *hw_params = adc->hw_params; struct iio_chan_spec *chan_array; struct rzg2l_adc_data *data; - unsigned int channel; int num_channels; - int ret; u8 i; data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; - num_channels = device_get_child_node_count(&pdev->dev); - if (!num_channels) - return dev_err_probe(&pdev->dev, -ENODEV, "no channel children\n"); + num_channels = devm_iio_adc_device_alloc_chaninfo_se(&pdev->dev, + &rzg2l_adc_chan_template, + hw_params->num_channels - 1, + &chan_array); + if (num_channels < 0) + return num_channels; if (num_channels > hw_params->num_channels) return dev_err_probe(&pdev->dev, -EINVAL, "num of channel children out of range\n"); - chan_array = devm_kcalloc(&pdev->dev, num_channels, sizeof(*chan_array), - GFP_KERNEL); - if (!chan_array) - return -ENOMEM; + for (i = 0; i < num_channels; i++) { + int channel = chan_array[i].channel; - i = 0; - device_for_each_child_node_scoped(&pdev->dev, fwnode) { - ret = fwnode_property_read_u32(fwnode, "reg", &channel); - if (ret) - return ret; - - if (channel >= hw_params->num_channels) - return -EINVAL; - - chan_array[i].type = rzg2l_adc_channels[channel].type; - chan_array[i].indexed = 1; - chan_array[i].channel = channel; - chan_array[i].info_mask_separate = BIT(IIO_CHAN_INFO_RAW); chan_array[i].datasheet_name = rzg2l_adc_channels[channel].name; - i++; + chan_array[i].type = rzg2l_adc_channels[channel].type; } data->num_channels = num_channels; @@ -515,7 +507,7 @@ static const struct rzg2l_adc_hw_params rzg3s_hw_params = { static const struct of_device_id rzg2l_adc_match[] = { { .compatible = "renesas,r9a08g045-adc", .data = &rzg3s_hw_params }, { .compatible = "renesas,rzg2l-adc", .data = &rzg2l_hw_params }, - { /* sentinel */ } + { } }; MODULE_DEVICE_TABLE(of, rzg2l_adc_match); @@ -626,3 +618,4 @@ module_platform_driver(rzg2l_adc_driver); MODULE_AUTHOR("Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>"); MODULE_DESCRIPTION("Renesas RZ/G2L ADC driver"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS("IIO_DRIVER"); diff --git a/drivers/iio/adc/spear_adc.c b/drivers/iio/adc/spear_adc.c index b6dd096391c1..e3a865c79686 100644 --- a/drivers/iio/adc/spear_adc.c +++ b/drivers/iio/adc/spear_adc.c @@ -345,7 +345,7 @@ static int spear_adc_probe(struct platform_device *pdev) static const struct of_device_id spear_adc_dt_ids[] = { { .compatible = "st,spear600-adc", }, - { /* sentinel */ } + { } }; MODULE_DEVICE_TABLE(of, spear_adc_dt_ids); diff --git a/drivers/iio/adc/stm32-adc-core.h b/drivers/iio/adc/stm32-adc-core.h index 73b2c2e91c08..db50a9f3b922 100644 --- a/drivers/iio/adc/stm32-adc-core.h +++ b/drivers/iio/adc/stm32-adc-core.h @@ -10,6 +10,9 @@ #ifndef __STM32_ADC_H #define __STM32_ADC_H +#include <linux/bitfield.h> +#include <linux/bits.h> + /* * STM32 - ADC global register map * ________________________________________________________ @@ -91,6 +94,7 @@ #define STM32H7_ADC_IER 0x04 #define STM32H7_ADC_CR 0x08 #define STM32H7_ADC_CFGR 0x0C +#define STM32H7_ADC_CFGR2 0x10 #define STM32H7_ADC_SMPR1 0x14 #define STM32H7_ADC_SMPR2 0x18 #define STM32H7_ADC_PCSEL 0x1C @@ -160,6 +164,13 @@ #define STM32H7_DMNGT_SHIFT 0 #define STM32H7_DMNGT_MASK GENMASK(1, 0) +/* STM32H7_ADC_CFGR2 bit fields */ +#define STM32H7_OVSR_MASK GENMASK(25, 16) /* Correspond to OSVR field in datasheet */ +#define STM32H7_OVSR(v) FIELD_PREP(STM32H7_OVSR_MASK, v) +#define STM32H7_OVSS_MASK GENMASK(8, 5) +#define STM32H7_OVSS(v) FIELD_PREP(STM32H7_OVSS_MASK, v) +#define STM32H7_ROVSE BIT(0) + enum stm32h7_adc_dmngt { STM32H7_DMNGT_DR_ONLY, /* Regular data in DR only */ STM32H7_DMNGT_DMA_ONESHOT, /* DMA one shot mode */ @@ -226,6 +237,12 @@ enum stm32h7_adc_dmngt { #define STM32MP13_RES_SHIFT 3 #define STM32MP13_RES_MASK GENMASK(4, 3) +/* STM32MP13_ADC_CFGR2 bit fields */ +#define STM32MP13_OVSR_MASK GENMASK(4, 2) +#define STM32MP13_OVSR(v) FIELD_PREP(STM32MP13_OVSR_MASK, v) +#define STM32MP13_OVSS_MASK GENMASK(8, 5) +#define STM32MP13_OVSS(v) FIELD_PREP(STM32MP13_OVSS_MASK, v) + /* STM32MP13_ADC_DIFSEL - bit fields */ #define STM32MP13_DIFSEL_MASK GENMASK(18, 0) diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c index 5dbf5f136768..e84babf43385 100644 --- a/drivers/iio/adc/stm32-adc.c +++ b/drivers/iio/adc/stm32-adc.c @@ -6,6 +6,7 @@ * Author: Fabrice Gasnier <fabrice.gasnier@st.com>. */ +#include <linux/array_size.h> #include <linux/clk.h> #include <linux/debugfs.h> #include <linux/delay.h> @@ -202,11 +203,13 @@ struct stm32_adc; * @has_boostmode: boost mode support flag * @has_linearcal: linear calibration support flag * @has_presel: channel preselection support flag + * @has_oversampling: oversampling support flag * @prepare: optional prepare routine (power-up, enable) * @start_conv: routine to start conversions * @stop_conv: routine to stop conversions * @unprepare: optional unprepare routine (disable, power-down) * @irq_clear: routine to clear irqs + * @set_ovs: routine to set oversampling configuration * @smp_cycles: programmable sampling time (ADC clock cycles) * @ts_int_ch: pointer to array of internal channels minimum sampling time in ns */ @@ -219,11 +222,13 @@ struct stm32_adc_cfg { bool has_boostmode; bool has_linearcal; bool has_presel; + bool has_oversampling; int (*prepare)(struct iio_dev *); void (*start_conv)(struct iio_dev *, bool dma); void (*stop_conv)(struct iio_dev *); void (*unprepare)(struct iio_dev *); void (*irq_clear)(struct iio_dev *indio_dev, u32 msk); + void (*set_ovs)(struct iio_dev *indio_dev, u32 ovs_idx); const unsigned int *smp_cycles; const unsigned int *ts_int_ch; }; @@ -255,6 +260,7 @@ struct stm32_adc_cfg { * @num_diff: number of differential channels * @int_ch: internal channel indexes array * @nsmps: number of channels with optional sample time + * @ovs_idx: current oversampling ratio index (in oversampling array) */ struct stm32_adc { struct stm32_adc_common *common; @@ -282,6 +288,7 @@ struct stm32_adc { u32 num_diff; int int_ch[STM32_ADC_INT_CH_NB]; int nsmps; + int ovs_idx; }; struct stm32_adc_diff_channel { @@ -293,12 +300,24 @@ struct stm32_adc_diff_channel { * struct stm32_adc_info - stm32 ADC, per instance config data * @max_channels: Number of channels * @resolutions: available resolutions + * @oversampling: available oversampling ratios * @num_res: number of available resolutions + * @num_ovs: number of available oversampling ratios */ struct stm32_adc_info { int max_channels; const unsigned int *resolutions; + const unsigned int *oversampling; const unsigned int num_res; + const unsigned int num_ovs; +}; + +static const unsigned int stm32h7_adc_oversampling_avail[] = { + 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, +}; + +static const unsigned int stm32mp13_adc_oversampling_avail[] = { + 1, 2, 4, 8, 16, 32, 64, 128, 256, }; static const unsigned int stm32f4_adc_resolutions[] = { @@ -322,14 +341,18 @@ static const unsigned int stm32h7_adc_resolutions[] = { static const struct stm32_adc_info stm32h7_adc_info = { .max_channels = STM32_ADC_CH_MAX, .resolutions = stm32h7_adc_resolutions, + .oversampling = stm32h7_adc_oversampling_avail, .num_res = ARRAY_SIZE(stm32h7_adc_resolutions), + .num_ovs = ARRAY_SIZE(stm32h7_adc_oversampling_avail), }; /* stm32mp13 can have up to 19 channels */ static const struct stm32_adc_info stm32mp13_adc_info = { .max_channels = 19, .resolutions = stm32f4_adc_resolutions, + .oversampling = stm32mp13_adc_oversampling_avail, .num_res = ARRAY_SIZE(stm32f4_adc_resolutions), + .num_ovs = ARRAY_SIZE(stm32mp13_adc_oversampling_avail), }; /* @@ -469,7 +492,7 @@ static struct stm32_adc_trig_info stm32h7_adc_trigs[] = { { LPTIM1_OUT, STM32_EXT18 }, { LPTIM2_OUT, STM32_EXT19 }, { LPTIM3_OUT, STM32_EXT20 }, - {}, + { } }; /* @@ -889,6 +912,56 @@ static void stm32mp13_adc_start_conv(struct iio_dev *indio_dev, bool dma) stm32_adc_set_bits(adc, STM32H7_ADC_CR, STM32H7_ADSTART); } +static void stm32h7_adc_set_ovs(struct iio_dev *indio_dev, u32 ovs_idx) +{ + struct stm32_adc *adc = iio_priv(indio_dev); + u32 ovsr_bits, bits, msk; + + msk = STM32H7_ROVSE | STM32H7_OVSR_MASK | STM32H7_OVSS_MASK; + stm32_adc_clr_bits(adc, STM32H7_ADC_CFGR2, msk); + + if (!ovs_idx) + return; + + /* + * Only the oversampling ratios corresponding to 2^ovs_idx are exposed in sysfs. + * Oversampling ratios [2,3,...,1024] are mapped on OVSR register values [1,2,...,1023]. + * OVSR = 2^ovs_idx - 1 + * These ratio increase the resolution by ovs_idx bits. Apply a right shift to keep initial + * resolution given by "assigned-resolution-bits" property. + * OVSS = ovs_idx + */ + ovsr_bits = GENMASK(ovs_idx - 1, 0); + bits = STM32H7_ROVSE | STM32H7_OVSS(ovs_idx) | STM32H7_OVSR(ovsr_bits); + + stm32_adc_set_bits(adc, STM32H7_ADC_CFGR2, bits & msk); +} + +static void stm32mp13_adc_set_ovs(struct iio_dev *indio_dev, u32 ovs_idx) +{ + struct stm32_adc *adc = iio_priv(indio_dev); + u32 bits, msk; + + msk = STM32H7_ROVSE | STM32MP13_OVSR_MASK | STM32MP13_OVSS_MASK; + stm32_adc_clr_bits(adc, STM32H7_ADC_CFGR2, msk); + + if (!ovs_idx) + return; + + /* + * The oversampling ratios [2,4,8,..,256] are mapped on OVSR register values [0,1,...,7]. + * OVSR = ovs_idx - 1 + * These ratio increase the resolution by ovs_idx bits. Apply a right shift to keep initial + * resolution given by "assigned-resolution-bits" property. + * OVSS = ovs_idx + */ + bits = STM32H7_ROVSE | STM32MP13_OVSS(ovs_idx); + if (ovs_idx - 1) + bits |= STM32MP13_OVSR(ovs_idx - 1); + + stm32_adc_set_bits(adc, STM32H7_ADC_CFGR2, bits & msk); +} + static int stm32h7_adc_exit_pwr_down(struct iio_dev *indio_dev) { struct stm32_adc *adc = iio_priv(indio_dev); @@ -1461,6 +1534,67 @@ static int stm32_adc_single_conv(struct iio_dev *indio_dev, return ret; } +static int stm32_adc_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct stm32_adc *adc = iio_priv(indio_dev); + struct device *dev = indio_dev->dev.parent; + int nb = adc->cfg->adc_info->num_ovs; + unsigned int idx; + int ret; + + switch (mask) { + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + if (val2) + return -EINVAL; + + for (idx = 0; idx < nb; idx++) + if (adc->cfg->adc_info->oversampling[idx] == val) + break; + if (idx >= nb) + return -EINVAL; + + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; + + ret = pm_runtime_resume_and_get(dev); + if (ret < 0) + goto err; + + adc->cfg->set_ovs(indio_dev, idx); + + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); + + adc->ovs_idx = idx; + +err: + iio_device_release_direct(indio_dev); + + return ret; + default: + return -EINVAL; + } +} + +static int stm32_adc_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, int *length, long m) +{ + struct stm32_adc *adc = iio_priv(indio_dev); + + switch (m) { + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + *type = IIO_VAL_INT; + *length = adc->cfg->adc_info->num_ovs; + *vals = adc->cfg->adc_info->oversampling; + return IIO_AVAIL_LIST; + default: + return -EINVAL; + } +} + static int stm32_adc_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long mask) @@ -1502,6 +1636,10 @@ static int stm32_adc_read_raw(struct iio_dev *indio_dev, *val = 0; return IIO_VAL_INT; + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + *val = adc->cfg->adc_info->oversampling[adc->ovs_idx]; + return IIO_VAL_INT; + default: return -EINVAL; } @@ -1678,6 +1816,8 @@ static int stm32_adc_debugfs_reg_access(struct iio_dev *indio_dev, static const struct iio_info stm32_adc_iio_info = { .read_raw = stm32_adc_read_raw, + .write_raw = stm32_adc_write_raw, + .read_avail = stm32_adc_read_avail, .validate_trigger = stm32_adc_validate_trigger, .hwfifo_set_watermark = stm32_adc_set_watermark, .update_scan_mode = stm32_adc_update_scan_mode, @@ -1858,8 +1998,8 @@ static irqreturn_t stm32_adc_trigger_handler(int irq, void *p) /* reset buffer index */ adc->bufi = 0; - iio_push_to_buffers_with_timestamp(indio_dev, adc->buffer, - pf->timestamp); + iio_push_to_buffers_with_ts(indio_dev, adc->buffer, sizeof(adc->buffer), + pf->timestamp); iio_trigger_notify_done(indio_dev->trig); /* re-enable eoc irq */ @@ -1876,7 +2016,7 @@ static const struct iio_chan_spec_ext_info stm32_adc_ext_info[] = { .read = iio_enum_available_read, .private = (uintptr_t)&stm32_adc_trig_pol, }, - {}, + { } }; static void stm32_adc_debugfs_init(struct iio_dev *indio_dev) @@ -1971,6 +2111,10 @@ static void stm32_adc_chan_init_one(struct iio_dev *indio_dev, chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW); chan->info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_OFFSET); + if (adc->cfg->has_oversampling) { + chan->info_mask_shared_by_all |= BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO); + chan->info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO); + } chan->scan_type.sign = 'u'; chan->scan_type.realbits = adc->cfg->adc_info->resolutions[adc->res]; chan->scan_type.storagebits = 16; @@ -2587,6 +2731,7 @@ static const struct stm32_adc_cfg stm32h7_adc_cfg = { .has_boostmode = true, .has_linearcal = true, .has_presel = true, + .has_oversampling = true, .start_conv = stm32h7_adc_start_conv, .stop_conv = stm32h7_adc_stop_conv, .prepare = stm32h7_adc_prepare, @@ -2594,6 +2739,7 @@ static const struct stm32_adc_cfg stm32h7_adc_cfg = { .smp_cycles = stm32h7_adc_smp_cycles, .irq_clear = stm32h7_adc_irq_clear, .ts_int_ch = stm32_adc_min_ts_h7, + .set_ovs = stm32h7_adc_set_ovs, }; static const unsigned int stm32_adc_min_ts_mp1[] = { 100, 100, 100, 4300, 9800 }; @@ -2607,6 +2753,7 @@ static const struct stm32_adc_cfg stm32mp1_adc_cfg = { .has_boostmode = true, .has_linearcal = true, .has_presel = true, + .has_oversampling = true, .start_conv = stm32h7_adc_start_conv, .stop_conv = stm32h7_adc_stop_conv, .prepare = stm32h7_adc_prepare, @@ -2614,6 +2761,7 @@ static const struct stm32_adc_cfg stm32mp1_adc_cfg = { .smp_cycles = stm32h7_adc_smp_cycles, .irq_clear = stm32h7_adc_irq_clear, .ts_int_ch = stm32_adc_min_ts_mp1, + .set_ovs = stm32h7_adc_set_ovs, }; static const unsigned int stm32_adc_min_ts_mp13[] = { 100, 0, 0, 4300, 9800 }; @@ -2623,6 +2771,7 @@ static const struct stm32_adc_cfg stm32mp13_adc_cfg = { .regs = &stm32mp13_adc_regspec, .adc_info = &stm32mp13_adc_info, .trigs = stm32h7_adc_trigs, + .has_oversampling = true, .start_conv = stm32mp13_adc_start_conv, .stop_conv = stm32h7_adc_stop_conv, .prepare = stm32h7_adc_prepare, @@ -2630,6 +2779,7 @@ static const struct stm32_adc_cfg stm32mp13_adc_cfg = { .smp_cycles = stm32mp13_adc_smp_cycles, .irq_clear = stm32h7_adc_irq_clear, .ts_int_ch = stm32_adc_min_ts_mp13, + .set_ovs = stm32mp13_adc_set_ovs, }; static const struct of_device_id stm32_adc_of_match[] = { diff --git a/drivers/iio/adc/stm32-dfsdm-adc.c b/drivers/iio/adc/stm32-dfsdm-adc.c index 726ddafc9f6d..f583924eb16b 100644 --- a/drivers/iio/adc/stm32-dfsdm-adc.c +++ b/drivers/iio/adc/stm32-dfsdm-adc.c @@ -108,7 +108,7 @@ static const struct stm32_dfsdm_str2field stm32_dfsdm_chan_type[] = { { "SPI_F", 1 }, /* SPI with data on falling edge */ { "MANCH_R", 2 }, /* Manchester codec, rising edge = logic 0 */ { "MANCH_F", 3 }, /* Manchester codec, falling edge = logic 1 */ - {}, + { } }; /* DFSDM channel clock source */ @@ -121,7 +121,7 @@ static const struct stm32_dfsdm_str2field stm32_dfsdm_chan_src[] = { { "CLKOUT_F", DFSDM_CHANNEL_SPI_CLOCK_INTERNAL_DIV2_FALLING }, /* Internal SPI clock divided by 2 (falling edge) */ { "CLKOUT_R", DFSDM_CHANNEL_SPI_CLOCK_INTERNAL_DIV2_RISING }, - {}, + { } }; static int stm32_dfsdm_str2val(const char *str, @@ -167,7 +167,7 @@ static const struct stm32_dfsdm_trig_info stm32_dfsdm_trigs[] = { { LPTIM1_OUT, 26 }, { LPTIM2_OUT, 27 }, { LPTIM3_OUT, 28 }, - {}, + { } }; static int stm32_dfsdm_get_jextsel(struct iio_dev *indio_dev, @@ -1747,7 +1747,7 @@ static const struct of_device_id stm32_dfsdm_adc_match[] = { .compatible = "st,stm32-dfsdm-dmic", .data = &stm32h7_dfsdm_audio_data, }, - {} + { } }; MODULE_DEVICE_TABLE(of, stm32_dfsdm_adc_match); diff --git a/drivers/iio/adc/sun20i-gpadc-iio.c b/drivers/iio/adc/sun20i-gpadc-iio.c index 136b8d9c294f..e4dfe76e6362 100644 --- a/drivers/iio/adc/sun20i-gpadc-iio.c +++ b/drivers/iio/adc/sun20i-gpadc-iio.c @@ -15,6 +15,7 @@ #include <linux/property.h> #include <linux/reset.h> +#include <linux/iio/adc-helpers.h> #include <linux/iio/iio.h> #define SUN20I_GPADC_DRIVER_NAME "sun20i-gpadc" @@ -149,36 +150,23 @@ static void sun20i_gpadc_reset_assert(void *data) reset_control_assert(rst); } +static const struct iio_chan_spec sun20i_gpadc_chan_template = { + .type = IIO_VOLTAGE, + .indexed = 1, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), +}; + static int sun20i_gpadc_alloc_channels(struct iio_dev *indio_dev, struct device *dev) { - unsigned int channel; - int num_channels, i, ret; + int num_channels; struct iio_chan_spec *channels; - num_channels = device_get_child_node_count(dev); - if (num_channels == 0) - return dev_err_probe(dev, -ENODEV, "no channel children\n"); - - channels = devm_kcalloc(dev, num_channels, sizeof(*channels), - GFP_KERNEL); - if (!channels) - return -ENOMEM; - - i = 0; - device_for_each_child_node_scoped(dev, node) { - ret = fwnode_property_read_u32(node, "reg", &channel); - if (ret) - return dev_err_probe(dev, ret, "invalid channel number\n"); - - channels[i].type = IIO_VOLTAGE; - channels[i].indexed = 1; - channels[i].channel = channel; - channels[i].info_mask_separate = BIT(IIO_CHAN_INFO_RAW); - channels[i].info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE); - - i++; - } + num_channels = devm_iio_adc_device_alloc_chaninfo_se(dev, + &sun20i_gpadc_chan_template, -1, &channels); + if (num_channels < 0) + return num_channels; indio_dev->channels = channels; indio_dev->num_channels = num_channels; @@ -255,7 +243,7 @@ static int sun20i_gpadc_probe(struct platform_device *pdev) static const struct of_device_id sun20i_gpadc_of_id[] = { { .compatible = "allwinner,sun20i-d1-gpadc" }, - { /* sentinel */ } + { } }; MODULE_DEVICE_TABLE(of, sun20i_gpadc_of_id); @@ -271,3 +259,4 @@ module_platform_driver(sun20i_gpadc_driver); MODULE_DESCRIPTION("ADC driver for sunxi platforms"); MODULE_AUTHOR("Maksim Kiselev <bigunclemax@gmail.com>"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("IIO_DRIVER"); diff --git a/drivers/iio/adc/sun4i-gpadc-iio.c b/drivers/iio/adc/sun4i-gpadc-iio.c index 8b27458dcd66..6b8d6bee1873 100644 --- a/drivers/iio/adc/sun4i-gpadc-iio.c +++ b/drivers/iio/adc/sun4i-gpadc-iio.c @@ -116,7 +116,7 @@ struct sun4i_gpadc_iio { static const struct iio_map sun4i_gpadc_hwmon_maps[] = { IIO_MAP("temp_adc", "iio_hwmon.0", NULL), - { /* sentinel */ }, + { } }; static const struct iio_chan_spec sun4i_gpadc_channels[] = { @@ -485,7 +485,7 @@ static const struct of_device_id sun4i_gpadc_of_id[] = { .compatible = "allwinner,sun8i-a33-ths", .data = &sun8i_a33_gpadc_data, }, - { /* sentinel */ } + { } }; static int sun4i_gpadc_probe_dt(struct platform_device *pdev, @@ -685,7 +685,7 @@ static const struct platform_device_id sun4i_gpadc_id[] = { { "sun4i-a10-gpadc-iio", (kernel_ulong_t)&sun4i_gpadc_data }, { "sun5i-a13-gpadc-iio", (kernel_ulong_t)&sun5i_gpadc_data }, { "sun6i-a31-gpadc-iio", (kernel_ulong_t)&sun6i_gpadc_data }, - { /* sentinel */ }, + { } }; MODULE_DEVICE_TABLE(platform, sun4i_gpadc_id); diff --git a/drivers/iio/adc/ti-adc081c.c b/drivers/iio/adc/ti-adc081c.c index 1af9be071d8d..4f514db5c26e 100644 --- a/drivers/iio/adc/ti-adc081c.c +++ b/drivers/iio/adc/ti-adc081c.c @@ -140,8 +140,8 @@ static irqreturn_t adc081c_trigger_handler(int irq, void *p) if (ret < 0) goto out; data->scan.channel = ret; - iio_push_to_buffers_with_timestamp(indio_dev, &data->scan, - iio_get_time_ns(indio_dev)); + iio_push_to_buffers_with_ts(indio_dev, &data->scan, sizeof(data->scan), + iio_get_time_ns(indio_dev)); out: iio_trigger_notify_done(indio_dev->trig); return IRQ_HANDLED; diff --git a/drivers/iio/adc/ti-adc0832.c b/drivers/iio/adc/ti-adc0832.c index e2dbd070c7c4..cfcdafbe284b 100644 --- a/drivers/iio/adc/ti-adc0832.c +++ b/drivers/iio/adc/ti-adc0832.c @@ -225,8 +225,8 @@ static irqreturn_t adc0832_trigger_handler(int irq, void *p) adc->data[i] = ret; i++; } - iio_push_to_buffers_with_timestamp(indio_dev, adc->data, - iio_get_time_ns(indio_dev)); + iio_push_to_buffers_with_ts(indio_dev, adc->data, sizeof(adc->data), + iio_get_time_ns(indio_dev)); out: mutex_unlock(&adc->lock); diff --git a/drivers/iio/adc/ti-adc084s021.c b/drivers/iio/adc/ti-adc084s021.c index 9c845ee01697..50a474f4d9f5 100644 --- a/drivers/iio/adc/ti-adc084s021.c +++ b/drivers/iio/adc/ti-adc084s021.c @@ -151,8 +151,8 @@ static irqreturn_t adc084s021_buffer_trigger_handler(int irq, void *pollfunc) if (adc084s021_adc_conversion(adc, adc->scan.channels) < 0) dev_err(&adc->spi->dev, "Failed to read data\n"); - iio_push_to_buffers_with_timestamp(indio_dev, &adc->scan, - iio_get_time_ns(indio_dev)); + iio_push_to_buffers_with_ts(indio_dev, &adc->scan, sizeof(adc->scan), + iio_get_time_ns(indio_dev)); mutex_unlock(&adc->lock); iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/adc/ti-adc12138.c b/drivers/iio/adc/ti-adc12138.c index 7f065f457b36..9dc465a10ffc 100644 --- a/drivers/iio/adc/ti-adc12138.c +++ b/drivers/iio/adc/ti-adc12138.c @@ -376,8 +376,8 @@ static irqreturn_t adc12138_trigger_handler(int irq, void *p) } } - iio_push_to_buffers_with_timestamp(indio_dev, adc->data, - iio_get_time_ns(indio_dev)); + iio_push_to_buffers_with_ts(indio_dev, adc->data, sizeof(adc->data), + iio_get_time_ns(indio_dev)); out: mutex_unlock(&adc->lock); diff --git a/drivers/iio/adc/ti-adc128s052.c b/drivers/iio/adc/ti-adc128s052.c index a456ea78462f..1b46a8155803 100644 --- a/drivers/iio/adc/ti-adc128s052.c +++ b/drivers/iio/adc/ti-adc128s052.c @@ -9,6 +9,7 @@ * https://www.ti.com/lit/ds/symlink/adc124s021.pdf */ +#include <linux/cleanup.h> #include <linux/err.h> #include <linux/iio/iio.h> #include <linux/mod_devicetable.h> @@ -20,40 +21,44 @@ struct adc128_configuration { const struct iio_chan_spec *channels; u8 num_channels; + const char *refname; + int num_other_regulators; + const char * const (*other_regulators)[]; }; struct adc128 { struct spi_device *spi; - struct regulator *reg; + /* + * Serialize the SPI 'write-channel + read data' accesses and protect + * the shared buffer. + */ struct mutex lock; - - u8 buffer[2] __aligned(IIO_DMA_MINALIGN); + int vref_mv; + union { + __be16 buffer16; + u8 buffer[2]; + } __aligned(IIO_DMA_MINALIGN); }; static int adc128_adc_conversion(struct adc128 *adc, u8 channel) { int ret; - mutex_lock(&adc->lock); + guard(mutex)(&adc->lock); adc->buffer[0] = channel << 3; adc->buffer[1] = 0; - ret = spi_write(adc->spi, &adc->buffer, 2); - if (ret < 0) { - mutex_unlock(&adc->lock); + ret = spi_write(adc->spi, &adc->buffer, sizeof(adc->buffer)); + if (ret < 0) return ret; - } - - ret = spi_read(adc->spi, &adc->buffer, 2); - - mutex_unlock(&adc->lock); + ret = spi_read(adc->spi, &adc->buffer16, sizeof(adc->buffer16)); if (ret < 0) return ret; - return ((adc->buffer[0] << 8 | adc->buffer[1]) & 0xFFF); + return be16_to_cpu(adc->buffer16) & 0xFFF; } static int adc128_read_raw(struct iio_dev *indio_dev, @@ -75,11 +80,7 @@ static int adc128_read_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_SCALE: - ret = regulator_get_voltage(adc->reg); - if (ret < 0) - return ret; - - *val = ret / 1000; + *val = adc->vref_mv; *val2 = 12; return IIO_VAL_FRACTIONAL_LOG2; @@ -121,21 +122,34 @@ static const struct iio_chan_spec adc124s021_channels[] = { ADC128_VOLTAGE_CHANNEL(3), }; +static const char * const bd79104_regulators[] = { "iovdd" }; + static const struct adc128_configuration adc128_config[] = { - { adc128s052_channels, ARRAY_SIZE(adc128s052_channels) }, - { adc122s021_channels, ARRAY_SIZE(adc122s021_channels) }, - { adc124s021_channels, ARRAY_SIZE(adc124s021_channels) }, + { + .channels = adc128s052_channels, + .num_channels = ARRAY_SIZE(adc128s052_channels), + .refname = "vref", + }, { + .channels = adc122s021_channels, + .num_channels = ARRAY_SIZE(adc122s021_channels), + .refname = "vref", + }, { + .channels = adc124s021_channels, + .num_channels = ARRAY_SIZE(adc124s021_channels), + .refname = "vref", + }, { + .channels = adc128s052_channels, + .num_channels = ARRAY_SIZE(adc128s052_channels), + .refname = "vdd", + .other_regulators = &bd79104_regulators, + .num_other_regulators = 1, + }, }; static const struct iio_info adc128_info = { .read_raw = adc128_read_raw, }; -static void adc128_disable_regulator(void *reg) -{ - regulator_disable(reg); -} - static int adc128_probe(struct spi_device *spi) { const struct adc128_configuration *config; @@ -159,20 +173,28 @@ static int adc128_probe(struct spi_device *spi) indio_dev->channels = config->channels; indio_dev->num_channels = config->num_channels; - adc->reg = devm_regulator_get(&spi->dev, "vref"); - if (IS_ERR(adc->reg)) - return PTR_ERR(adc->reg); - - ret = regulator_enable(adc->reg); + ret = devm_regulator_get_enable_read_voltage(&spi->dev, + config->refname); if (ret < 0) - return ret; - ret = devm_add_action_or_reset(&spi->dev, adc128_disable_regulator, - adc->reg); + return dev_err_probe(&spi->dev, ret, + "failed to read '%s' voltage", + config->refname); + + adc->vref_mv = ret / 1000; + + if (config->num_other_regulators) { + ret = devm_regulator_bulk_get_enable(&spi->dev, + config->num_other_regulators, + *config->other_regulators); + if (ret) + return dev_err_probe(&spi->dev, ret, + "Failed to enable regulators\n"); + } + + ret = devm_mutex_init(&spi->dev, &adc->lock); if (ret) return ret; - mutex_init(&adc->lock); - return devm_iio_device_register(&spi->dev, indio_dev); } @@ -184,7 +206,8 @@ static const struct of_device_id adc128_of_match[] = { { .compatible = "ti,adc124s021", .data = &adc128_config[2] }, { .compatible = "ti,adc124s051", .data = &adc128_config[2] }, { .compatible = "ti,adc124s101", .data = &adc128_config[2] }, - { /* sentinel */ }, + { .compatible = "rohm,bd79104", .data = &adc128_config[3] }, + { } }; MODULE_DEVICE_TABLE(of, adc128_of_match); @@ -196,6 +219,7 @@ static const struct spi_device_id adc128_id[] = { { "adc124s021", (kernel_ulong_t)&adc128_config[2] }, { "adc124s051", (kernel_ulong_t)&adc128_config[2] }, { "adc124s101", (kernel_ulong_t)&adc128_config[2] }, + { "bd79104", (kernel_ulong_t)&adc128_config[3] }, { } }; MODULE_DEVICE_TABLE(spi, adc128_id); diff --git a/drivers/iio/adc/ti-ads1015.c b/drivers/iio/adc/ti-ads1015.c index 4355726b373a..21181cc3bd85 100644 --- a/drivers/iio/adc/ti-ads1015.c +++ b/drivers/iio/adc/ti-ads1015.c @@ -12,6 +12,7 @@ */ #include <linux/module.h> +#include <linux/cleanup.h> #include <linux/init.h> #include <linux/irq.h> #include <linux/i2c.h> @@ -466,8 +467,8 @@ static irqreturn_t ads1015_trigger_handler(int irq, void *p) scan.chan = res; mutex_unlock(&data->lock); - iio_push_to_buffers_with_timestamp(indio_dev, &scan, - iio_get_time_ns(indio_dev)); + iio_push_to_buffers_with_ts(indio_dev, &scan, sizeof(scan), + iio_get_time_ns(indio_dev)); err: iio_trigger_notify_done(indio_dev->trig); @@ -533,6 +534,31 @@ static int ads1015_read_avail(struct iio_dev *indio_dev, } } +static int __ads1015_read_info_raw(struct ads1015_data *data, + struct iio_chan_spec const *chan, int *val) +{ + int ret; + + if (ads1015_event_channel_enabled(data) && + data->event_channel != chan->address) + return -EBUSY; + + ret = ads1015_set_power_state(data, true); + if (ret < 0) + return ret; + + ret = ads1015_get_adc_result(data, chan->address, val); + if (ret < 0) { + ads1015_set_power_state(data, false); + return ret; + } + + *val = sign_extend32(*val >> chan->scan_type.shift, + chan->scan_type.realbits - 1); + + return ads1015_set_power_state(data, false); +} + static int ads1015_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long mask) @@ -540,58 +566,29 @@ static int ads1015_read_raw(struct iio_dev *indio_dev, int ret, idx; struct ads1015_data *data = iio_priv(indio_dev); - mutex_lock(&data->lock); + guard(mutex)(&data->lock); switch (mask) { case IIO_CHAN_INFO_RAW: - ret = iio_device_claim_direct_mode(indio_dev); + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; + ret = __ads1015_read_info_raw(data, chan, val); + iio_device_release_direct(indio_dev); if (ret) - break; - - if (ads1015_event_channel_enabled(data) && - data->event_channel != chan->address) { - ret = -EBUSY; - goto release_direct; - } - - ret = ads1015_set_power_state(data, true); - if (ret < 0) - goto release_direct; - - ret = ads1015_get_adc_result(data, chan->address, val); - if (ret < 0) { - ads1015_set_power_state(data, false); - goto release_direct; - } - - *val = sign_extend32(*val >> chan->scan_type.shift, - chan->scan_type.realbits - 1); - - ret = ads1015_set_power_state(data, false); - if (ret < 0) - goto release_direct; + return ret; - ret = IIO_VAL_INT; -release_direct: - iio_device_release_direct_mode(indio_dev); - break; + return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: idx = data->channel_data[chan->address].pga; *val = ads1015_fullscale_range[idx]; *val2 = chan->scan_type.realbits - 1; - ret = IIO_VAL_FRACTIONAL_LOG2; - break; + return IIO_VAL_FRACTIONAL_LOG2; case IIO_CHAN_INFO_SAMP_FREQ: idx = data->channel_data[chan->address].data_rate; *val = data->chip->data_rate[idx]; - ret = IIO_VAL_INT; - break; + return IIO_VAL_INT; default: - ret = -EINVAL; - break; + return -EINVAL; } - mutex_unlock(&data->lock); - - return ret; } static int ads1015_write_raw(struct iio_dev *indio_dev, @@ -599,23 +596,16 @@ static int ads1015_write_raw(struct iio_dev *indio_dev, int val2, long mask) { struct ads1015_data *data = iio_priv(indio_dev); - int ret; - mutex_lock(&data->lock); + guard(mutex)(&data->lock); switch (mask) { case IIO_CHAN_INFO_SCALE: - ret = ads1015_set_scale(data, chan, val, val2); - break; + return ads1015_set_scale(data, chan, val, val2); case IIO_CHAN_INFO_SAMP_FREQ: - ret = ads1015_set_data_rate(data, chan->address, val); - break; + return ads1015_set_data_rate(data, chan->address, val); default: - ret = -EINVAL; - break; + return -EINVAL; } - mutex_unlock(&data->lock); - - return ret; } static int ads1015_read_event(struct iio_dev *indio_dev, @@ -624,20 +614,18 @@ static int ads1015_read_event(struct iio_dev *indio_dev, int *val2) { struct ads1015_data *data = iio_priv(indio_dev); - int ret; unsigned int comp_queue; int period; int dr; - mutex_lock(&data->lock); + guard(mutex)(&data->lock); switch (info) { case IIO_EV_INFO_VALUE: *val = (dir == IIO_EV_DIR_RISING) ? data->thresh_data[chan->address].high_thresh : data->thresh_data[chan->address].low_thresh; - ret = IIO_VAL_INT; - break; + return IIO_VAL_INT; case IIO_EV_INFO_PERIOD: dr = data->channel_data[chan->address].data_rate; comp_queue = data->thresh_data[chan->address].comp_queue; @@ -646,16 +634,10 @@ static int ads1015_read_event(struct iio_dev *indio_dev, *val = period / USEC_PER_SEC; *val2 = period % USEC_PER_SEC; - ret = IIO_VAL_INT_PLUS_MICRO; - break; + return IIO_VAL_INT_PLUS_MICRO; default: - ret = -EINVAL; - break; + return -EINVAL; } - - mutex_unlock(&data->lock); - - return ret; } static int ads1015_write_event(struct iio_dev *indio_dev, @@ -666,24 +648,22 @@ static int ads1015_write_event(struct iio_dev *indio_dev, struct ads1015_data *data = iio_priv(indio_dev); const int *data_rate = data->chip->data_rate; int realbits = chan->scan_type.realbits; - int ret = 0; long long period; int i; int dr; - mutex_lock(&data->lock); + guard(mutex)(&data->lock); switch (info) { case IIO_EV_INFO_VALUE: - if (val >= 1 << (realbits - 1) || val < -1 << (realbits - 1)) { - ret = -EINVAL; - break; - } + if (val >= 1 << (realbits - 1) || val < -1 << (realbits - 1)) + return -EINVAL; + if (dir == IIO_EV_DIR_RISING) data->thresh_data[chan->address].high_thresh = val; else data->thresh_data[chan->address].low_thresh = val; - break; + return 0; case IIO_EV_INFO_PERIOD: dr = data->channel_data[chan->address].data_rate; period = val * USEC_PER_SEC + val2; @@ -694,15 +674,10 @@ static int ads1015_write_event(struct iio_dev *indio_dev, break; } data->thresh_data[chan->address].comp_queue = i; - break; + return 0; default: - ret = -EINVAL; - break; + return -EINVAL; } - - mutex_unlock(&data->lock); - - return ret; } static int ads1015_read_event_config(struct iio_dev *indio_dev, @@ -710,25 +685,19 @@ static int ads1015_read_event_config(struct iio_dev *indio_dev, enum iio_event_direction dir) { struct ads1015_data *data = iio_priv(indio_dev); - int ret = 0; - mutex_lock(&data->lock); - if (data->event_channel == chan->address) { - switch (dir) { - case IIO_EV_DIR_RISING: - ret = 1; - break; - case IIO_EV_DIR_EITHER: - ret = (data->comp_mode == ADS1015_CFG_COMP_MODE_WINDOW); - break; - default: - ret = -EINVAL; - break; - } - } - mutex_unlock(&data->lock); + guard(mutex)(&data->lock); + if (data->event_channel != chan->address) + return 0; - return ret; + switch (dir) { + case IIO_EV_DIR_RISING: + return 1; + case IIO_EV_DIR_EITHER: + return (data->comp_mode == ADS1015_CFG_COMP_MODE_WINDOW); + default: + return -EINVAL; + } } static int ads1015_enable_event_config(struct ads1015_data *data, @@ -813,23 +782,18 @@ static int ads1015_write_event_config(struct iio_dev *indio_dev, int comp_mode = (dir == IIO_EV_DIR_EITHER) ? ADS1015_CFG_COMP_MODE_WINDOW : ADS1015_CFG_COMP_MODE_TRAD; - mutex_lock(&data->lock); + guard(mutex)(&data->lock); /* Prevent from enabling both buffer and event at a time */ - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) { - mutex_unlock(&data->lock); - return ret; - } + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; if (state) ret = ads1015_enable_event_config(data, chan, comp_mode); else ret = ads1015_disable_event_config(data, chan, comp_mode); - iio_device_release_direct_mode(indio_dev); - mutex_unlock(&data->lock); - + iio_device_release_direct(indio_dev); return ret; } diff --git a/drivers/iio/adc/ti-ads1100.c b/drivers/iio/adc/ti-ads1100.c index 1e46f07a9ca6..b0790e300b18 100644 --- a/drivers/iio/adc/ti-ads1100.c +++ b/drivers/iio/adc/ti-ads1100.c @@ -10,6 +10,7 @@ #include <linux/bitfield.h> #include <linux/bits.h> +#include <linux/cleanup.h> #include <linux/delay.h> #include <linux/module.h> #include <linux/init.h> @@ -219,36 +220,30 @@ static int ads1100_read_raw(struct iio_dev *indio_dev, int ret; struct ads1100_data *data = iio_priv(indio_dev); - mutex_lock(&data->lock); + guard(mutex)(&data->lock); switch (mask) { case IIO_CHAN_INFO_RAW: - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - break; + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; ret = ads1100_get_adc_result(data, chan->address, val); - if (ret >= 0) - ret = IIO_VAL_INT; - iio_device_release_direct_mode(indio_dev); - break; + iio_device_release_direct(indio_dev); + if (ret < 0) + return ret; + + return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: /* full-scale is the supply voltage in millivolts */ *val = ads1100_get_vdd_millivolts(data); *val2 = 15 + FIELD_GET(ADS1100_PGA_MASK, data->config); - ret = IIO_VAL_FRACTIONAL_LOG2; - break; + return IIO_VAL_FRACTIONAL_LOG2; case IIO_CHAN_INFO_SAMP_FREQ: *val = ads1100_data_rate[FIELD_GET(ADS1100_DR_MASK, data->config)]; - ret = IIO_VAL_INT; - break; + return IIO_VAL_INT; default: - ret = -EINVAL; - break; + return -EINVAL; } - mutex_unlock(&data->lock); - - return ret; } static int ads1100_write_raw(struct iio_dev *indio_dev, @@ -256,23 +251,16 @@ static int ads1100_write_raw(struct iio_dev *indio_dev, int val2, long mask) { struct ads1100_data *data = iio_priv(indio_dev); - int ret; - mutex_lock(&data->lock); + guard(mutex)(&data->lock); switch (mask) { case IIO_CHAN_INFO_SCALE: - ret = ads1100_set_scale(data, val, val2); - break; + return ads1100_set_scale(data, val, val2); case IIO_CHAN_INFO_SAMP_FREQ: - ret = ads1100_set_data_rate(data, chan->address, val); - break; + return ads1100_set_data_rate(data, chan->address, val); default: - ret = -EINVAL; - break; + return -EINVAL; } - mutex_unlock(&data->lock); - - return ret; } static const struct iio_info ads1100_info = { diff --git a/drivers/iio/adc/ti-ads1119.c b/drivers/iio/adc/ti-ads1119.c index f120e7e21cff..d280c949cf47 100644 --- a/drivers/iio/adc/ti-ads1119.c +++ b/drivers/iio/adc/ti-ads1119.c @@ -534,8 +534,8 @@ static irqreturn_t ads1119_trigger_handler(int irq, void *private) scan.sample = ret; - iio_push_to_buffers_with_timestamp(indio_dev, &scan, - iio_get_time_ns(indio_dev)); + iio_push_to_buffers_with_ts(indio_dev, &scan, sizeof(scan), + iio_get_time_ns(indio_dev)); done: iio_trigger_notify_done(indio_dev->trig); return IRQ_HANDLED; diff --git a/drivers/iio/adc/ti-ads124s08.c b/drivers/iio/adc/ti-ads124s08.c index 77c299bb4ebc..8ea1269f74db 100644 --- a/drivers/iio/adc/ti-ads124s08.c +++ b/drivers/iio/adc/ti-ads124s08.c @@ -297,8 +297,8 @@ static irqreturn_t ads124s_trigger_handler(int irq, void *p) j++; } - iio_push_to_buffers_with_timestamp(indio_dev, priv->buffer, - pf->timestamp); + iio_push_to_buffers_with_ts(indio_dev, priv->buffer, sizeof(priv->buffer), + pf->timestamp); iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/adc/ti-ads131e08.c b/drivers/iio/adc/ti-ads131e08.c index c6096b64664e..085f0d6fb39e 100644 --- a/drivers/iio/adc/ti-ads131e08.c +++ b/drivers/iio/adc/ti-ads131e08.c @@ -664,8 +664,8 @@ static irqreturn_t ads131e08_trigger_handler(int irq, void *private) i++; } - iio_push_to_buffers_with_timestamp(indio_dev, st->tmp_buf.data, - iio_get_time_ns(indio_dev)); + iio_push_to_buffers_with_ts(indio_dev, &st->tmp_buf, sizeof(st->tmp_buf), + iio_get_time_ns(indio_dev)); out: iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/adc/ti-ads7950.c b/drivers/iio/adc/ti-ads7950.c index af28672aa803..0356ccf23fea 100644 --- a/drivers/iio/adc/ti-ads7950.c +++ b/drivers/iio/adc/ti-ads7950.c @@ -403,10 +403,11 @@ static const struct iio_info ti_ads7950_info = { .update_scan_mode = ti_ads7950_update_scan_mode, }; -static void ti_ads7950_set(struct gpio_chip *chip, unsigned int offset, - int value) +static int ti_ads7950_set(struct gpio_chip *chip, unsigned int offset, + int value) { struct ti_ads7950_state *st = gpiochip_get_data(chip); + int ret; mutex_lock(&st->slock); @@ -416,9 +417,11 @@ static void ti_ads7950_set(struct gpio_chip *chip, unsigned int offset, st->cmd_settings_bitmask &= ~BIT(offset); st->single_tx = TI_ADS7950_MAN_CMD_SETTINGS(st); - spi_sync(st->spi, &st->scan_single_msg); + ret = spi_sync(st->spi, &st->scan_single_msg); mutex_unlock(&st->slock); + + return ret; } static int ti_ads7950_get(struct gpio_chip *chip, unsigned int offset) @@ -499,7 +502,11 @@ static int ti_ads7950_direction_input(struct gpio_chip *chip, static int ti_ads7950_direction_output(struct gpio_chip *chip, unsigned int offset, int value) { - ti_ads7950_set(chip, offset, value); + int ret; + + ret = ti_ads7950_set(chip, offset, value); + if (ret) + return ret; return _ti_ads7950_set_direction(chip, offset, 0); } @@ -641,7 +648,7 @@ static int ti_ads7950_probe(struct spi_device *spi) st->chip.direction_input = ti_ads7950_direction_input; st->chip.direction_output = ti_ads7950_direction_output; st->chip.get = ti_ads7950_get; - st->chip.set = ti_ads7950_set; + st->chip.set_rv = ti_ads7950_set; ret = gpiochip_add_data(&st->chip, st); if (ret) { diff --git a/drivers/iio/adc/ti-ads8688.c b/drivers/iio/adc/ti-ads8688.c index a31658b760a4..b0bf46cae0b6 100644 --- a/drivers/iio/adc/ti-ads8688.c +++ b/drivers/iio/adc/ti-ads8688.c @@ -389,8 +389,8 @@ static irqreturn_t ads8688_trigger_handler(int irq, void *p) j++; } - iio_push_to_buffers_with_timestamp(indio_dev, buffer, - iio_get_time_ns(indio_dev)); + iio_push_to_buffers_with_ts(indio_dev, buffer, sizeof(buffer), + iio_get_time_ns(indio_dev)); iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/adc/ti-lmp92064.c b/drivers/iio/adc/ti-lmp92064.c index 1e4a78677fe5..3f375c1f586c 100644 --- a/drivers/iio/adc/ti-lmp92064.c +++ b/drivers/iio/adc/ti-lmp92064.c @@ -209,8 +209,8 @@ static irqreturn_t lmp92064_trigger_handler(int irq, void *p) if (ret) goto err; - iio_push_to_buffers_with_timestamp(indio_dev, &data, - iio_get_time_ns(indio_dev)); + iio_push_to_buffers_with_ts(indio_dev, &data, sizeof(data), + iio_get_time_ns(indio_dev)); err: iio_trigger_notify_done(indio_dev->trig); @@ -366,7 +366,7 @@ MODULE_DEVICE_TABLE(spi, lmp92064_id_table); static const struct of_device_id lmp92064_of_table[] = { { .compatible = "ti,lmp92064" }, - {} + { } }; MODULE_DEVICE_TABLE(of, lmp92064_of_table); diff --git a/drivers/iio/adc/ti-tlc4541.c b/drivers/iio/adc/ti-tlc4541.c index 5a138be983ed..f67945c62c99 100644 --- a/drivers/iio/adc/ti-tlc4541.c +++ b/drivers/iio/adc/ti-tlc4541.c @@ -99,8 +99,8 @@ static irqreturn_t tlc4541_trigger_handler(int irq, void *p) if (ret < 0) goto done; - iio_push_to_buffers_with_timestamp(indio_dev, st->rx_buf, - iio_get_time_ns(indio_dev)); + iio_push_to_buffers_with_ts(indio_dev, st->rx_buf, sizeof(st->rx_buf), + iio_get_time_ns(indio_dev)); done: iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/adc/ti-tsc2046.c b/drivers/iio/adc/ti-tsc2046.c index 49560059f4b7..c2d2aada6772 100644 --- a/drivers/iio/adc/ti-tsc2046.c +++ b/drivers/iio/adc/ti-tsc2046.c @@ -418,8 +418,9 @@ static int tsc2046_adc_scan(struct iio_dev *indio_dev) for (group = 0; group < priv->groups; group++) priv->scan_buf.data[group] = tsc2046_adc_get_val(priv, group); - ret = iio_push_to_buffers_with_timestamp(indio_dev, &priv->scan_buf, - iio_get_time_ns(indio_dev)); + ret = iio_push_to_buffers_with_ts(indio_dev, &priv->scan_buf, + sizeof(priv->scan_buf), + iio_get_time_ns(indio_dev)); /* If the consumer is kfifo, we may get a EBUSY here - ignore it. */ if (ret < 0 && ret != -EBUSY) { dev_err_ratelimited(dev, "Failed to push scan buffer %pe\n", @@ -760,7 +761,6 @@ static int tsc2046_adc_probe(struct spi_device *spi) if (!dcfg) return -EINVAL; - spi->bits_per_word = 8; spi->mode &= ~SPI_MODE_X_MASK; spi->mode |= SPI_MODE_0; ret = spi_setup(spi); diff --git a/drivers/iio/adc/twl6030-gpadc.c b/drivers/iio/adc/twl6030-gpadc.c index ef7430e6877d..3ac774ebf678 100644 --- a/drivers/iio/adc/twl6030-gpadc.c +++ b/drivers/iio/adc/twl6030-gpadc.c @@ -871,7 +871,7 @@ static const struct of_device_id of_twl6030_match_tbl[] = { .compatible = "ti,twl6032-gpadc", .data = &twl6032_pdata, }, - { /* end */ } + { } }; MODULE_DEVICE_TABLE(of, of_twl6030_match_tbl); diff --git a/drivers/iio/adc/vf610_adc.c b/drivers/iio/adc/vf610_adc.c index 513365d42aa5..6404b015234a 100644 --- a/drivers/iio/adc/vf610_adc.c +++ b/drivers/iio/adc/vf610_adc.c @@ -11,6 +11,7 @@ #include <linux/property.h> #include <linux/platform_device.h> #include <linux/interrupt.h> +#include <linux/cleanup.h> #include <linux/delay.h> #include <linux/kernel.h> #include <linux/slab.h> @@ -504,7 +505,7 @@ static const struct iio_enum vf610_conversion_mode = { static const struct iio_chan_spec_ext_info vf610_ext_info[] = { IIO_ENUM("conversion_mode", IIO_SHARED_BY_DIR, &vf610_conversion_mode), - {}, + { } }; #define VF610_ADC_CHAN(_idx, _chan_type) { \ @@ -591,9 +592,9 @@ static irqreturn_t vf610_adc_isr(int irq, void *dev_id) info->value = vf610_adc_read_data(info); if (iio_buffer_enabled(indio_dev)) { info->scan.chan = info->value; - iio_push_to_buffers_with_timestamp(indio_dev, - &info->scan, - iio_get_time_ns(indio_dev)); + iio_push_to_buffers_with_ts(indio_dev, &info->scan, + sizeof(info->scan), + iio_get_time_ns(indio_dev)); iio_trigger_notify_done(indio_dev->trig); } else complete(&info->completion); @@ -630,36 +631,29 @@ static const struct attribute_group vf610_attribute_group = { .attrs = vf610_attributes, }; -static int vf610_read_sample(struct iio_dev *indio_dev, +static int vf610_read_sample(struct vf610_adc *info, struct iio_chan_spec const *chan, int *val) { - struct vf610_adc *info = iio_priv(indio_dev); unsigned int hc_cfg; int ret; - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; - - mutex_lock(&info->lock); + guard(mutex)(&info->lock); reinit_completion(&info->completion); hc_cfg = VF610_ADC_ADCHC(chan->channel); hc_cfg |= VF610_ADC_AIEN; writel(hc_cfg, info->regs + VF610_REG_ADC_HC0); ret = wait_for_completion_interruptible_timeout(&info->completion, VF610_ADC_TIMEOUT); - if (ret == 0) { - ret = -ETIMEDOUT; - goto out_unlock; - } + if (ret == 0) + return -ETIMEDOUT; if (ret < 0) - goto out_unlock; + return ret; switch (chan->type) { case IIO_VOLTAGE: *val = info->value; - break; + return 0; case IIO_TEMP: /* * Calculate in degree Celsius times 1000 @@ -669,17 +663,10 @@ static int vf610_read_sample(struct iio_dev *indio_dev, *val = 25000 - ((int)info->value - VF610_VTEMP25_3V3) * 1000000 / VF610_TEMP_SLOPE_COEFF; - break; + return 0; default: - ret = -EINVAL; - break; + return -EINVAL; } - -out_unlock: - mutex_unlock(&info->lock); - iio_device_release_direct_mode(indio_dev); - - return ret; } static int vf610_read_raw(struct iio_dev *indio_dev, @@ -694,7 +681,10 @@ static int vf610_read_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_RAW: case IIO_CHAN_INFO_PROCESSED: - ret = vf610_read_sample(indio_dev, chan, val); + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; + ret = vf610_read_sample(info, chan, val); + iio_device_release_direct(indio_dev); if (ret < 0) return ret; @@ -823,7 +813,7 @@ static const struct vf610_chip_info imx6sx_chip_info = { static const struct of_device_id vf610_adc_match[] = { { .compatible = "fsl,imx6sx-adc", .data = &imx6sx_chip_info}, { .compatible = "fsl,vf610-adc", .data = &vf610_chip_info}, - { /* sentinel */ } + { } }; MODULE_DEVICE_TABLE(of, vf610_adc_match); diff --git a/drivers/iio/adc/xilinx-xadc-core.c b/drivers/iio/adc/xilinx-xadc-core.c index e1f8740ae688..e257c1b94a5f 100644 --- a/drivers/iio/adc/xilinx-xadc-core.c +++ b/drivers/iio/adc/xilinx-xadc-core.c @@ -1186,7 +1186,7 @@ static const struct of_device_id xadc_of_match_table[] = { .compatible = "xlnx,system-management-wiz-1.3", .data = &xadc_us_axi_ops }, - { }, + { } }; MODULE_DEVICE_TABLE(of, xadc_of_match_table); diff --git a/drivers/iio/addac/ad74115.c b/drivers/iio/addac/ad74115.c index a7e480f2472d..4d8b64048e4f 100644 --- a/drivers/iio/addac/ad74115.c +++ b/drivers/iio/addac/ad74115.c @@ -542,18 +542,16 @@ static int ad74115_gpio_get(struct gpio_chip *gc, unsigned int offset) return FIELD_GET(AD74115_GPIO_CONFIG_GPI_DATA, val); } -static void ad74115_gpio_set(struct gpio_chip *gc, unsigned int offset, int value) +static int ad74115_gpio_set(struct gpio_chip *gc, unsigned int offset, + int value) { struct ad74115_state *st = gpiochip_get_data(gc); - struct device *dev = &st->spi->dev; - int ret; - ret = regmap_update_bits(st->regmap, AD74115_GPIO_CONFIG_X_REG(offset), - AD74115_GPIO_CONFIG_GPO_DATA, - FIELD_PREP(AD74115_GPIO_CONFIG_GPO_DATA, value)); - if (ret) - dev_err(dev, "Failed to set GPIO %u output value, err: %d\n", - offset, ret); + return regmap_update_bits(st->regmap, + AD74115_GPIO_CONFIG_X_REG(offset), + AD74115_GPIO_CONFIG_GPO_DATA, + FIELD_PREP(AD74115_GPIO_CONFIG_GPO_DATA, + value)); } static int ad74115_set_comp_debounce(struct ad74115_state *st, unsigned int val) @@ -866,15 +864,14 @@ static int ad74115_get_adc_code(struct iio_dev *indio_dev, struct ad74115_state *st = iio_priv(indio_dev); int ret; - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; mutex_lock(&st->lock); ret = _ad74115_get_adc_code(st, channel, val); mutex_unlock(&st->lock); - iio_device_release_direct_mode(indio_dev); + iio_device_release_direct(indio_dev); return ret; } @@ -1580,7 +1577,7 @@ static int ad74115_setup_gpio_chip(struct ad74115_state *st) .direction_input = ad74115_gpio_direction_input, .direction_output = ad74115_gpio_direction_output, .get = ad74115_gpio_get, - .set = ad74115_gpio_set, + .set_rv = ad74115_gpio_set, }; return devm_gpiochip_add_data(dev, &st->gc, st); diff --git a/drivers/iio/addac/ad74413r.c b/drivers/iio/addac/ad74413r.c index f14d12b03da6..a0bb1dbcb7ad 100644 --- a/drivers/iio/addac/ad74413r.c +++ b/drivers/iio/addac/ad74413r.c @@ -4,7 +4,6 @@ * Author: Cosmin Tanislav <cosmin.tanislav@analog.com> */ -#include <linux/unaligned.h> #include <linux/bitfield.h> #include <linux/cleanup.h> #include <linux/crc8.h> @@ -24,6 +23,8 @@ #include <linux/regmap.h> #include <linux/regulator/consumer.h> #include <linux/spi/spi.h> +#include <linux/types.h> +#include <linux/unaligned.h> #include <dt-bindings/iio/addac/adi,ad74413r.h> @@ -84,7 +85,7 @@ struct ad74413r_state { */ struct { u8 rx_buf[AD74413R_FRAME_SIZE * AD74413R_CHANNEL_MAX]; - s64 timestamp; + aligned_s64 timestamp; } adc_samples_buf __aligned(IIO_DMA_MINALIGN); u8 adc_samples_tx_buf[AD74413R_FRAME_SIZE * AD74413R_CHANNEL_MAX]; @@ -276,8 +277,8 @@ static int ad74413r_set_comp_drive_strength(struct ad74413r_state *st, } -static void ad74413r_gpio_set(struct gpio_chip *chip, - unsigned int offset, int val) +static int ad74413r_gpio_set(struct gpio_chip *chip, unsigned int offset, + int val) { struct ad74413r_state *st = gpiochip_get_data(chip); unsigned int real_offset = st->gpo_gpio_offsets[offset]; @@ -286,16 +287,16 @@ static void ad74413r_gpio_set(struct gpio_chip *chip, ret = ad74413r_set_gpo_config(st, real_offset, AD74413R_GPO_CONFIG_LOGIC); if (ret) - return; + return ret; - regmap_update_bits(st->regmap, AD74413R_REG_GPO_CONFIG_X(real_offset), - AD74413R_GPO_CONFIG_DATA_MASK, - val ? AD74413R_GPO_CONFIG_DATA_MASK : 0); + return regmap_update_bits(st->regmap, + AD74413R_REG_GPO_CONFIG_X(real_offset), + AD74413R_GPO_CONFIG_DATA_MASK, + val ? AD74413R_GPO_CONFIG_DATA_MASK : 0); } -static void ad74413r_gpio_set_multiple(struct gpio_chip *chip, - unsigned long *mask, - unsigned long *bits) +static int ad74413r_gpio_set_multiple(struct gpio_chip *chip, + unsigned long *mask, unsigned long *bits) { struct ad74413r_state *st = gpiochip_get_data(chip); unsigned long real_mask = 0; @@ -309,15 +310,15 @@ static void ad74413r_gpio_set_multiple(struct gpio_chip *chip, ret = ad74413r_set_gpo_config(st, real_offset, AD74413R_GPO_CONFIG_LOGIC_PARALLEL); if (ret) - return; + return ret; real_mask |= BIT(real_offset); if (*bits & offset) real_bits |= BIT(real_offset); } - regmap_update_bits(st->regmap, AD74413R_REG_GPO_PAR_DATA, - real_mask, real_bits); + return regmap_update_bits(st->regmap, AD74413R_REG_GPO_PAR_DATA, + real_mask, real_bits); } static int ad74413r_gpio_get(struct gpio_chip *chip, unsigned int offset) @@ -1424,8 +1425,8 @@ static int ad74413r_probe(struct spi_device *spi) st->gpo_gpiochip.ngpio = st->num_gpo_gpios; st->gpo_gpiochip.parent = st->dev; st->gpo_gpiochip.can_sleep = true; - st->gpo_gpiochip.set = ad74413r_gpio_set; - st->gpo_gpiochip.set_multiple = ad74413r_gpio_set_multiple; + st->gpo_gpiochip.set_rv = ad74413r_gpio_set; + st->gpo_gpiochip.set_multiple_rv = ad74413r_gpio_set_multiple; st->gpo_gpiochip.set_config = ad74413r_gpio_set_gpo_config; st->gpo_gpiochip.get_direction = ad74413r_gpio_get_gpo_direction; @@ -1505,14 +1506,14 @@ static const struct of_device_id ad74413r_dt_id[] = { .compatible = "adi,ad74413r", .data = &ad74413r_chip_info_data, }, - {}, + { } }; MODULE_DEVICE_TABLE(of, ad74413r_dt_id); static const struct spi_device_id ad74413r_spi_id[] = { { .name = "ad74412r", .driver_data = (kernel_ulong_t)&ad74412r_chip_info_data }, { .name = "ad74413r", .driver_data = (kernel_ulong_t)&ad74413r_chip_info_data }, - {} + { } }; MODULE_DEVICE_TABLE(spi, ad74413r_spi_id); diff --git a/drivers/iio/afe/iio-rescale.c b/drivers/iio/afe/iio-rescale.c index b6a46036d5ea..ecaf59278c6f 100644 --- a/drivers/iio/afe/iio-rescale.c +++ b/drivers/iio/afe/iio-rescale.c @@ -514,7 +514,7 @@ static const struct of_device_id rescale_match[] = { .data = &rescale_cfg[TEMP_SENSE_RTD], }, { .compatible = "temperature-transducer", .data = &rescale_cfg[TEMP_TRANSDUCER], }, - { /* sentinel */ } + { } }; MODULE_DEVICE_TABLE(of, rescale_match); diff --git a/drivers/iio/amplifiers/ad8366.c b/drivers/iio/amplifiers/ad8366.c index 31564afb13a2..e73c9b983395 100644 --- a/drivers/iio/amplifiers/ad8366.c +++ b/drivers/iio/amplifiers/ad8366.c @@ -330,7 +330,7 @@ static const struct spi_device_id ad8366_id[] = { {"adl5240", ID_ADL5240}, {"hmc792a", ID_HMC792}, {"hmc1119", ID_HMC1119}, - {} + { } }; MODULE_DEVICE_TABLE(spi, ad8366_id); diff --git a/drivers/iio/amplifiers/ada4250.c b/drivers/iio/amplifiers/ada4250.c index 566f0e1c98a5..74f8429d652b 100644 --- a/drivers/iio/amplifiers/ada4250.c +++ b/drivers/iio/amplifiers/ada4250.c @@ -378,13 +378,13 @@ static int ada4250_probe(struct spi_device *spi) static const struct spi_device_id ada4250_id[] = { { "ada4250", 0 }, - {} + { } }; MODULE_DEVICE_TABLE(spi, ada4250_id); static const struct of_device_id ada4250_of_match[] = { { .compatible = "adi,ada4250" }, - {}, + { } }; MODULE_DEVICE_TABLE(of, ada4250_of_match); diff --git a/drivers/iio/amplifiers/hmc425a.c b/drivers/iio/amplifiers/hmc425a.c index d9a359e1388a..4dbf894c7e3b 100644 --- a/drivers/iio/amplifiers/hmc425a.c +++ b/drivers/iio/amplifiers/hmc425a.c @@ -270,7 +270,7 @@ static const struct iio_chan_spec_ext_info ltc6373_ext_info[] = { .write = ltc6373_write_powerdown, .shared = IIO_SEPARATE, }, - {} + { } }; #define HMC425A_CHAN(_channel) \ @@ -398,7 +398,6 @@ static int hmc425a_probe(struct platform_device *pdev) return devm_iio_device_register(&pdev->dev, indio_dev); } -/* Match table for of_platform binding */ static const struct of_device_id hmc425a_of_match[] = { { .compatible = "adi,hmc425a", .data = &hmc425a_chip_info_tbl[ID_HMC425A]}, @@ -408,7 +407,7 @@ static const struct of_device_id hmc425a_of_match[] = { .data = &hmc425a_chip_info_tbl[ID_ADRF5740]}, { .compatible = "adi,ltc6373", .data = &hmc425a_chip_info_tbl[ID_LTC6373]}, - {} + { } }; MODULE_DEVICE_TABLE(of, hmc425a_of_match); diff --git a/drivers/iio/cdc/ad7150.c b/drivers/iio/cdc/ad7150.c index e64a41bae32c..427d32e398b3 100644 --- a/drivers/iio/cdc/ad7150.c +++ b/drivers/iio/cdc/ad7150.c @@ -631,7 +631,7 @@ static const struct i2c_device_id ad7150_id[] = { { "ad7150", AD7150 }, { "ad7151", AD7151 }, { "ad7156", AD7150 }, - {} + { } }; MODULE_DEVICE_TABLE(i2c, ad7150_id); @@ -640,7 +640,7 @@ static const struct of_device_id ad7150_of_match[] = { { "adi,ad7150" }, { "adi,ad7151" }, { "adi,ad7156" }, - {} + { } }; static struct i2c_driver ad7150_driver = { .driver = { diff --git a/drivers/iio/cdc/ad7746.c b/drivers/iio/cdc/ad7746.c index ba18dbbe0940..8a306d55c72a 100644 --- a/drivers/iio/cdc/ad7746.c +++ b/drivers/iio/cdc/ad7746.c @@ -792,7 +792,7 @@ static const struct i2c_device_id ad7746_id[] = { { "ad7745", 7745 }, { "ad7746", 7746 }, { "ad7747", 7747 }, - {} + { } }; MODULE_DEVICE_TABLE(i2c, ad7746_id); @@ -800,7 +800,7 @@ static const struct of_device_id ad7746_of_match[] = { { .compatible = "adi,ad7745" }, { .compatible = "adi,ad7746" }, { .compatible = "adi,ad7747" }, - { }, + { } }; MODULE_DEVICE_TABLE(of, ad7746_of_match); diff --git a/drivers/iio/chemical/Kconfig b/drivers/iio/chemical/Kconfig index 330fe0af946f..b22afa1f6d59 100644 --- a/drivers/iio/chemical/Kconfig +++ b/drivers/iio/chemical/Kconfig @@ -108,6 +108,16 @@ config IAQCORE iAQ-Core Continuous/Pulsed VOC (Volatile Organic Compounds) sensors +config MHZ19B + tristate "Winsen MHZ19B CO2 sensor" + depends on SERIAL_DEV_BUS + help + Say Y here to build Serdev interface support for the Winsen + MHZ19B CO2 sensor. + + To compile this driver as a module, choose M here: the module will + be called mhz19b. + config PMS7003 tristate "Plantower PMS7003 particulate matter sensor" depends on SERIAL_DEV_BUS @@ -166,6 +176,16 @@ config SCD4X To compile this driver as a module, choose M here: the module will be called scd4x. +config SEN0322 + tristate "SEN0322 oxygen sensor" + depends on I2C + select REGMAP_I2C + help + Say Y here to build support for the DFRobot SEN0322 oxygen sensor. + + To compile this driver as a module, choose M here: the module will + be called sen0322. + config SENSIRION_SGP30 tristate "Sensirion SGPxx gas sensors" depends on I2C diff --git a/drivers/iio/chemical/Makefile b/drivers/iio/chemical/Makefile index 4866db06bdc9..2287a00a6b75 100644 --- a/drivers/iio/chemical/Makefile +++ b/drivers/iio/chemical/Makefile @@ -15,11 +15,13 @@ obj-$(CONFIG_ENS160) += ens160_core.o obj-$(CONFIG_ENS160_I2C) += ens160_i2c.o obj-$(CONFIG_ENS160_SPI) += ens160_spi.o obj-$(CONFIG_IAQCORE) += ams-iaq-core.o +obj-$(CONFIG_MHZ19B) += mhz19b.o obj-$(CONFIG_PMS7003) += pms7003.o obj-$(CONFIG_SCD30_CORE) += scd30_core.o obj-$(CONFIG_SCD30_I2C) += scd30_i2c.o obj-$(CONFIG_SCD30_SERIAL) += scd30_serial.o obj-$(CONFIG_SCD4X) += scd4x.o +obj-$(CONFIG_SEN0322) += sen0322.o obj-$(CONFIG_SENSEAIR_SUNRISE_CO2) += sunrise_co2.o obj-$(CONFIG_SENSIRION_SGP30) += sgp30.o obj-$(CONFIG_SENSIRION_SGP40) += sgp40.o diff --git a/drivers/iio/chemical/ags02ma.c b/drivers/iio/chemical/ags02ma.c index 8fcd80946543..151178d4e8f4 100644 --- a/drivers/iio/chemical/ags02ma.c +++ b/drivers/iio/chemical/ags02ma.c @@ -140,13 +140,13 @@ static int ags02ma_probe(struct i2c_client *client) static const struct i2c_device_id ags02ma_id_table[] = { { "ags02ma" }, - { /* Sentinel */ } + { } }; MODULE_DEVICE_TABLE(i2c, ags02ma_id_table); static const struct of_device_id ags02ma_of_table[] = { { .compatible = "aosong,ags02ma" }, - { /* Sentinel */ } + { } }; MODULE_DEVICE_TABLE(of, ags02ma_of_table); diff --git a/drivers/iio/chemical/atlas-ezo-sensor.c b/drivers/iio/chemical/atlas-ezo-sensor.c index 761a853a4d17..de0b87edd188 100644 --- a/drivers/iio/chemical/atlas-ezo-sensor.c +++ b/drivers/iio/chemical/atlas-ezo-sensor.c @@ -189,7 +189,7 @@ static const struct i2c_device_id atlas_ezo_id[] = { { "atlas-co2-ezo", (kernel_ulong_t)&atlas_ezo_devices[ATLAS_CO2_EZO] }, { "atlas-o2-ezo", (kernel_ulong_t)&atlas_ezo_devices[ATLAS_O2_EZO] }, { "atlas-hum-ezo", (kernel_ulong_t)&atlas_ezo_devices[ATLAS_HUM_EZO] }, - {} + { } }; MODULE_DEVICE_TABLE(i2c, atlas_ezo_id); @@ -197,7 +197,7 @@ static const struct of_device_id atlas_ezo_dt_ids[] = { { .compatible = "atlas,co2-ezo", .data = &atlas_ezo_devices[ATLAS_CO2_EZO], }, { .compatible = "atlas,o2-ezo", .data = &atlas_ezo_devices[ATLAS_O2_EZO], }, { .compatible = "atlas,hum-ezo", .data = &atlas_ezo_devices[ATLAS_HUM_EZO], }, - {} + { } }; MODULE_DEVICE_TABLE(of, atlas_ezo_dt_ids); diff --git a/drivers/iio/chemical/atlas-sensor.c b/drivers/iio/chemical/atlas-sensor.c index baf93e5e3ca7..cb6662b92137 100644 --- a/drivers/iio/chemical/atlas-sensor.c +++ b/drivers/iio/chemical/atlas-sensor.c @@ -458,8 +458,9 @@ static irqreturn_t atlas_trigger_handler(int irq, void *private) &data->buffer, sizeof(__be32) * channels); if (!ret) - iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, - iio_get_time_ns(indio_dev)); + iio_push_to_buffers_with_ts(indio_dev, data->buffer, + sizeof(data->buffer), + iio_get_time_ns(indio_dev)); iio_trigger_notify_done(indio_dev->trig); @@ -518,13 +519,12 @@ static int atlas_read_raw(struct iio_dev *indio_dev, case IIO_CONCENTRATION: case IIO_ELECTRICALCONDUCTIVITY: case IIO_VOLTAGE: - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; ret = atlas_read_measurement(data, chan->address, ®); - iio_device_release_direct_mode(indio_dev); + iio_device_release_direct(indio_dev); break; default: ret = -EINVAL; @@ -594,7 +594,7 @@ static const struct i2c_device_id atlas_id[] = { { "atlas-orp-sm", (kernel_ulong_t)&atlas_devices[ATLAS_ORP_SM] }, { "atlas-do-sm", (kernel_ulong_t)&atlas_devices[ATLAS_DO_SM] }, { "atlas-rtd-sm", (kernel_ulong_t)&atlas_devices[ATLAS_RTD_SM] }, - {} + { } }; MODULE_DEVICE_TABLE(i2c, atlas_id); diff --git a/drivers/iio/chemical/bme680_core.c b/drivers/iio/chemical/bme680_core.c index 9d73fd2cf52c..3e850562ab00 100644 --- a/drivers/iio/chemical/bme680_core.c +++ b/drivers/iio/chemical/bme680_core.c @@ -1120,8 +1120,8 @@ static irqreturn_t bme680_trigger_handler(int irq, void *p) gas_range = FIELD_GET(BME680_GAS_RANGE_MASK, gas_regs_val); data->scan.chan[3] = bme680_compensate_gas(data, adc_gas_res, gas_range); - iio_push_to_buffers_with_timestamp(indio_dev, &data->scan, - iio_get_time_ns(indio_dev)); + iio_push_to_buffers_with_ts(indio_dev, &data->scan, sizeof(data->scan), + iio_get_time_ns(indio_dev)); out: iio_trigger_notify_done(indio_dev->trig); return IRQ_HANDLED; diff --git a/drivers/iio/chemical/bme680_i2c.c b/drivers/iio/chemical/bme680_i2c.c index ac7763f98a6a..5560ea708b36 100644 --- a/drivers/iio/chemical/bme680_i2c.c +++ b/drivers/iio/chemical/bme680_i2c.c @@ -37,13 +37,13 @@ static int bme680_i2c_probe(struct i2c_client *client) static const struct i2c_device_id bme680_i2c_id[] = { { "bme680" }, - {} + { } }; MODULE_DEVICE_TABLE(i2c, bme680_i2c_id); static const struct of_device_id bme680_of_i2c_match[] = { { .compatible = "bosch,bme680", }, - {}, + { } }; MODULE_DEVICE_TABLE(of, bme680_of_i2c_match); diff --git a/drivers/iio/chemical/bme680_spi.c b/drivers/iio/chemical/bme680_spi.c index ecb24ba0ebc9..aa97645ba539 100644 --- a/drivers/iio/chemical/bme680_spi.c +++ b/drivers/iio/chemical/bme680_spi.c @@ -112,14 +112,6 @@ static int bme680_spi_probe(struct spi_device *spi) const struct spi_device_id *id = spi_get_device_id(spi); struct bme680_spi_bus_context *bus_context; struct regmap *regmap; - int ret; - - spi->bits_per_word = 8; - ret = spi_setup(spi); - if (ret < 0) { - dev_err(&spi->dev, "spi_setup failed!\n"); - return ret; - } bus_context = devm_kzalloc(&spi->dev, sizeof(*bus_context), GFP_KERNEL); if (!bus_context) @@ -140,13 +132,13 @@ static int bme680_spi_probe(struct spi_device *spi) static const struct spi_device_id bme680_spi_id[] = { {"bme680", 0}, - {}, + { } }; MODULE_DEVICE_TABLE(spi, bme680_spi_id); static const struct of_device_id bme680_of_spi_match[] = { { .compatible = "bosch,bme680", }, - {}, + { } }; MODULE_DEVICE_TABLE(of, bme680_of_spi_match); diff --git a/drivers/iio/chemical/ccs811.c b/drivers/iio/chemical/ccs811.c index 451fb65dbe60..998c9239c4c7 100644 --- a/drivers/iio/chemical/ccs811.c +++ b/drivers/iio/chemical/ccs811.c @@ -15,6 +15,7 @@ * 4. Read error register and put the information in logs */ +#include <linux/cleanup.h> #include <linux/delay.h> #include <linux/gpio/consumer.h> #include <linux/i2c.h> @@ -214,6 +215,40 @@ static int ccs811_get_measurement(struct ccs811_data *data) return ret; } +static int ccs811_read_info_raw(struct ccs811_data *data, + struct iio_chan_spec const *chan, + int *val, int mask) +{ + int ret; + + guard(mutex)(&data->lock); + ret = ccs811_get_measurement(data); + if (ret < 0) + return ret; + + switch (chan->type) { + case IIO_VOLTAGE: + *val = be16_to_cpu(data->buffer.raw_data) & CCS811_VOLTAGE_MASK; + return IIO_VAL_INT; + case IIO_CURRENT: + *val = be16_to_cpu(data->buffer.raw_data) >> 10; + return IIO_VAL_INT; + case IIO_CONCENTRATION: + switch (chan->channel2) { + case IIO_MOD_CO2: + *val = be16_to_cpu(data->buffer.co2); + return IIO_VAL_INT; + case IIO_MOD_VOC: + *val = be16_to_cpu(data->buffer.voc); + return IIO_VAL_INT; + default: + return -EINVAL; + } + default: + return -EINVAL; + } +} + static int ccs811_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long mask) @@ -223,46 +258,12 @@ static int ccs811_read_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_RAW: - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; - mutex_lock(&data->lock); - ret = ccs811_get_measurement(data); - if (ret < 0) { - mutex_unlock(&data->lock); - iio_device_release_direct_mode(indio_dev); - return ret; - } + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; - switch (chan->type) { - case IIO_VOLTAGE: - *val = be16_to_cpu(data->buffer.raw_data) & - CCS811_VOLTAGE_MASK; - ret = IIO_VAL_INT; - break; - case IIO_CURRENT: - *val = be16_to_cpu(data->buffer.raw_data) >> 10; - ret = IIO_VAL_INT; - break; - case IIO_CONCENTRATION: - switch (chan->channel2) { - case IIO_MOD_CO2: - *val = be16_to_cpu(data->buffer.co2); - ret = IIO_VAL_INT; - break; - case IIO_MOD_VOC: - *val = be16_to_cpu(data->buffer.voc); - ret = IIO_VAL_INT; - break; - default: - ret = -EINVAL; - } - break; - default: - ret = -EINVAL; - } - mutex_unlock(&data->lock); - iio_device_release_direct_mode(indio_dev); + ret = ccs811_read_info_raw(data, chan, val, mask); + + iio_device_release_direct(indio_dev); return ret; @@ -342,8 +343,8 @@ static irqreturn_t ccs811_trigger_handler(int irq, void *p) goto err; } - iio_push_to_buffers_with_timestamp(indio_dev, &data->scan, - iio_get_time_ns(indio_dev)); + iio_push_to_buffers_with_ts(indio_dev, &data->scan, sizeof(data->scan), + iio_get_time_ns(indio_dev)); err: iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/chemical/ens160_core.c b/drivers/iio/chemical/ens160_core.c index 152f81ff57e3..6cec60074827 100644 --- a/drivers/iio/chemical/ens160_core.c +++ b/drivers/iio/chemical/ens160_core.c @@ -267,8 +267,8 @@ static irqreturn_t ens160_trigger_handler(int irq, void *p) if (ret) goto err; - iio_push_to_buffers_with_timestamp(indio_dev, &data->scan, - pf->timestamp); + iio_push_to_buffers_with_ts(indio_dev, &data->scan, sizeof(data->scan), + pf->timestamp); err: iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/chemical/mhz19b.c b/drivers/iio/chemical/mhz19b.c new file mode 100644 index 000000000000..3c64154918b1 --- /dev/null +++ b/drivers/iio/chemical/mhz19b.c @@ -0,0 +1,316 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * mh-z19b COâ‚‚ sensor driver + * + * Copyright (c) 2025 Gyeyoung Baek <gye976@gmail.com> + * + * Datasheet: + * https://www.winsen-sensor.com/d/files/infrared-gas-sensor/mh-z19b-co2-ver1_0.pdf + */ + +#include <linux/array_size.h> +#include <linux/completion.h> +#include <linux/device.h> +#include <linux/errno.h> +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> +#include <linux/jiffies.h> +#include <linux/kstrtox.h> +#include <linux/minmax.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/regulator/consumer.h> +#include <linux/serdev.h> +#include <linux/string.h> +#include <linux/types.h> +#include <linux/unaligned.h> + +/* + * Commands have following format: + * + * +------+------+-----+------+------+------+------+------+-------+ + * | 0xFF | 0x01 | cmd | arg0 | arg1 | 0x00 | 0x00 | 0x00 | cksum | + * +------+------+-----+------+------+------+------+------+-------+ + */ +#define MHZ19B_CMD_SIZE 9 + +/* ABC logic in MHZ19B means auto calibration. */ +#define MHZ19B_ABC_LOGIC_CMD 0x79 +#define MHZ19B_READ_CO2_CMD 0x86 +#define MHZ19B_SPAN_POINT_CMD 0x88 +#define MHZ19B_ZERO_POINT_CMD 0x87 + +#define MHZ19B_SPAN_POINT_PPM_MIN 1000 +#define MHZ19B_SPAN_POINT_PPM_MAX 5000 + +#define MHZ19B_SERDEV_TIMEOUT msecs_to_jiffies(100) + +struct mhz19b_state { + struct serdev_device *serdev; + + /* Must wait until the 'buf' is filled with 9 bytes.*/ + struct completion buf_ready; + + u8 buf_idx; + /* + * Serdev receive buffer. + * When data is received from the MH-Z19B, + * the 'mhz19b_receive_buf' callback function is called and fills this buffer. + */ + u8 buf[MHZ19B_CMD_SIZE] __aligned(IIO_DMA_MINALIGN); +}; + +static u8 mhz19b_get_checksum(u8 *cmd_buf) +{ + u8 i, checksum = 0; + +/* + * +------+------+-----+------+------+------+------+------+-------+ + * | 0xFF | 0x01 | cmd | arg0 | arg1 | 0x00 | 0x00 | 0x00 | cksum | + * +------+------+-----+------+------+------+------+------+-------+ + * i:1 2 3 4 5 6 7 + * + * Sum all cmd_buf elements from index 1 to 7. + */ + for (i = 1; i < 8; i++) + checksum += cmd_buf[i]; + + return -checksum; +} + +static int mhz19b_serdev_cmd(struct iio_dev *indio_dev, int cmd, u16 arg) +{ + struct mhz19b_state *st = iio_priv(indio_dev); + struct serdev_device *serdev = st->serdev; + struct device *dev = &indio_dev->dev; + int ret; + + /* + * cmd_buf[3,4] : arg0,1 + * cmd_buf[8] : checksum + */ + u8 cmd_buf[MHZ19B_CMD_SIZE] = { + 0xFF, 0x01, cmd, + }; + + switch (cmd) { + case MHZ19B_ABC_LOGIC_CMD: + cmd_buf[3] = arg ? 0xA0 : 0; + break; + case MHZ19B_SPAN_POINT_CMD: + put_unaligned_be16(arg, &cmd_buf[3]); + break; + default: + break; + } + cmd_buf[8] = mhz19b_get_checksum(cmd_buf); + + /* Write buf to uart ctrl synchronously */ + ret = serdev_device_write(serdev, cmd_buf, MHZ19B_CMD_SIZE, 0); + if (ret < 0) + return ret; + if (ret != MHZ19B_CMD_SIZE) + return -EIO; + + switch (cmd) { + case MHZ19B_READ_CO2_CMD: + ret = wait_for_completion_interruptible_timeout(&st->buf_ready, + MHZ19B_SERDEV_TIMEOUT); + if (ret < 0) + return ret; + if (!ret) + return -ETIMEDOUT; + + if (st->buf[8] != mhz19b_get_checksum(st->buf)) { + dev_err(dev, "checksum err"); + return -EINVAL; + } + + return get_unaligned_be16(&st->buf[2]); + default: + /* No response commands. */ + return 0; + } +} + +static int mhz19b_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + int ret; + + ret = mhz19b_serdev_cmd(indio_dev, MHZ19B_READ_CO2_CMD, 0); + if (ret < 0) + return ret; + + *val = ret; + return IIO_VAL_INT; +} + +/* + * echo 0 > calibration_auto_enable : ABC logic off + * echo 1 > calibration_auto_enable : ABC logic on + */ +static ssize_t calibration_auto_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + bool enable; + int ret; + + ret = kstrtobool(buf, &enable); + if (ret) + return ret; + + ret = mhz19b_serdev_cmd(indio_dev, MHZ19B_ABC_LOGIC_CMD, enable); + if (ret < 0) + return ret; + + return len; +} +static IIO_DEVICE_ATTR_WO(calibration_auto_enable, 0); + +/* + * echo 0 > calibration_forced_value : zero point calibration + * (make sure the sensor has been working under 400ppm for over 20 minutes.) + * echo [1000 1 5000] > calibration_forced_value : span point calibration + * (make sure the sensor has been working under a certain level COâ‚‚ for over 20 minutes.) + */ +static ssize_t calibration_forced_value_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + u16 ppm; + int cmd, ret; + + ret = kstrtou16(buf, 0, &ppm); + if (ret) + return ret; + + if (ppm) { + if (!in_range(ppm, MHZ19B_SPAN_POINT_PPM_MIN, + MHZ19B_SPAN_POINT_PPM_MAX - MHZ19B_SPAN_POINT_PPM_MIN + 1)) { + dev_dbg(&indio_dev->dev, + "span point ppm should be in a range [%d-%d]\n", + MHZ19B_SPAN_POINT_PPM_MIN, MHZ19B_SPAN_POINT_PPM_MAX); + return -EINVAL; + } + + cmd = MHZ19B_SPAN_POINT_CMD; + } else { + cmd = MHZ19B_ZERO_POINT_CMD; + } + + ret = mhz19b_serdev_cmd(indio_dev, cmd, ppm); + if (ret < 0) + return ret; + + return len; +} +static IIO_DEVICE_ATTR_WO(calibration_forced_value, 0); + +static struct attribute *mhz19b_attrs[] = { + &iio_dev_attr_calibration_auto_enable.dev_attr.attr, + &iio_dev_attr_calibration_forced_value.dev_attr.attr, + NULL +}; + +static const struct attribute_group mhz19b_attr_group = { + .attrs = mhz19b_attrs, +}; + +static const struct iio_info mhz19b_info = { + .attrs = &mhz19b_attr_group, + .read_raw = mhz19b_read_raw, +}; + +static const struct iio_chan_spec mhz19b_channels[] = { + { + .type = IIO_CONCENTRATION, + .channel2 = IIO_MOD_CO2, + .modified = 1, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + }, +}; + +static size_t mhz19b_receive_buf(struct serdev_device *serdev, + const u8 *data, size_t len) +{ + struct iio_dev *indio_dev = dev_get_drvdata(&serdev->dev); + struct mhz19b_state *st = iio_priv(indio_dev); + + memcpy(st->buf + st->buf_idx, data, len); + st->buf_idx += len; + + if (st->buf_idx == MHZ19B_CMD_SIZE) { + st->buf_idx = 0; + complete(&st->buf_ready); + } + + return len; +} + +static const struct serdev_device_ops mhz19b_ops = { + .receive_buf = mhz19b_receive_buf, + .write_wakeup = serdev_device_write_wakeup, +}; + +static int mhz19b_probe(struct serdev_device *serdev) +{ + int ret; + struct device *dev = &serdev->dev; + struct iio_dev *indio_dev; + struct mhz19b_state *st; + + serdev_device_set_client_ops(serdev, &mhz19b_ops); + ret = devm_serdev_device_open(dev, serdev); + if (ret) + return ret; + serdev_device_set_baudrate(serdev, 9600); + serdev_device_set_flow_control(serdev, false); + ret = serdev_device_set_parity(serdev, SERDEV_PARITY_NONE); + if (ret) + return ret; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; + serdev_device_set_drvdata(serdev, indio_dev); + + st = iio_priv(indio_dev); + st->serdev = serdev; + + init_completion(&st->buf_ready); + + ret = devm_regulator_get_enable(dev, "vin"); + if (ret) + return ret; + + indio_dev->name = "mh-z19b"; + indio_dev->channels = mhz19b_channels; + indio_dev->num_channels = ARRAY_SIZE(mhz19b_channels); + indio_dev->info = &mhz19b_info; + + return devm_iio_device_register(dev, indio_dev); +} + +static const struct of_device_id mhz19b_of_match[] = { + { .compatible = "winsen,mhz19b", }, + { } +}; +MODULE_DEVICE_TABLE(of, mhz19b_of_match); + +static struct serdev_device_driver mhz19b_driver = { + .driver = { + .name = "mhz19b", + .of_match_table = mhz19b_of_match, + }, + .probe = mhz19b_probe, +}; +module_serdev_device_driver(mhz19b_driver); + +MODULE_AUTHOR("Gyeyoung Baek"); +MODULE_DESCRIPTION("MH-Z19B CO2 sensor driver using serdev interface"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/chemical/pms7003.c b/drivers/iio/chemical/pms7003.c index e05ce1f12065..656d4a12c58f 100644 --- a/drivers/iio/chemical/pms7003.c +++ b/drivers/iio/chemical/pms7003.c @@ -127,8 +127,8 @@ static irqreturn_t pms7003_trigger_handler(int irq, void *p) pms7003_get_pm(frame->data + PMS7003_PM10_OFFSET); mutex_unlock(&state->lock); - iio_push_to_buffers_with_timestamp(indio_dev, &state->scan, - iio_get_time_ns(indio_dev)); + iio_push_to_buffers_with_ts(indio_dev, &state->scan, sizeof(state->scan), + iio_get_time_ns(indio_dev)); err: iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/chemical/scd30_core.c b/drivers/iio/chemical/scd30_core.c index 3fed6b63710f..8316720b1fa3 100644 --- a/drivers/iio/chemical/scd30_core.c +++ b/drivers/iio/chemical/scd30_core.c @@ -601,7 +601,8 @@ static irqreturn_t scd30_trigger_handler(int irq, void *p) if (ret) goto out; - iio_push_to_buffers_with_timestamp(indio_dev, &scan, iio_get_time_ns(indio_dev)); + iio_push_to_buffers_with_ts(indio_dev, &scan, sizeof(scan), + iio_get_time_ns(indio_dev)); out: iio_trigger_notify_done(indio_dev->trig); return IRQ_HANDLED; diff --git a/drivers/iio/chemical/scd4x.c b/drivers/iio/chemical/scd4x.c index 50e3ac44422b..2463149519b6 100644 --- a/drivers/iio/chemical/scd4x.c +++ b/drivers/iio/chemical/scd4x.c @@ -358,15 +358,14 @@ static int scd4x_read_raw(struct iio_dev *indio_dev, return IIO_VAL_INT; } - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; mutex_lock(&state->lock); ret = scd4x_read_channel(state, chan->address); mutex_unlock(&state->lock); - iio_device_release_direct_mode(indio_dev); + iio_device_release_direct(indio_dev); if (ret < 0) return ret; @@ -676,7 +675,8 @@ static irqreturn_t scd4x_trigger_handler(int irq, void *p) if (ret) goto out; - iio_push_to_buffers_with_timestamp(indio_dev, &scan, iio_get_time_ns(indio_dev)); + iio_push_to_buffers_with_ts(indio_dev, &scan, sizeof(scan), + iio_get_time_ns(indio_dev)); out: iio_trigger_notify_done(indio_dev->trig); return IRQ_HANDLED; diff --git a/drivers/iio/chemical/sen0322.c b/drivers/iio/chemical/sen0322.c new file mode 100644 index 000000000000..96c6fc1203ad --- /dev/null +++ b/drivers/iio/chemical/sen0322.c @@ -0,0 +1,161 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Driver for the DFRobot SEN0322 oxygen sensor. + * + * Datasheet: + * https://wiki.dfrobot.com/Gravity_I2C_Oxygen_Sensor_SKU_SEN0322 + * + * Possible I2C slave addresses: + * 0x70 + * 0x71 + * 0x72 + * 0x73 + * + * Copyright (C) 2025 Tóth János <gomba007@gmail.com> + */ + +#include <linux/i2c.h> +#include <linux/regmap.h> + +#include <linux/iio/iio.h> + +#define SEN0322_REG_DATA 0x03 +#define SEN0322_REG_COEFF 0x0A + +struct sen0322 { + struct regmap *regmap; +}; + +static int sen0322_read_data(struct sen0322 *sen0322) +{ + u8 data[3] = { }; + int ret; + + ret = regmap_bulk_read(sen0322->regmap, SEN0322_REG_DATA, data, + sizeof(data)); + if (ret < 0) + return ret; + + /* + * The actual value in the registers is: + * val = data[0] + data[1] / 10 + data[2] / 100 + * but it is multiplied by 100 here to avoid floating-point math + * and the scale is divided by 100 to compensate this. + */ + return data[0] * 100 + data[1] * 10 + data[2]; +} + +static int sen0322_read_scale(struct sen0322 *sen0322, int *num, int *den) +{ + u32 val; + int ret; + + ret = regmap_read(sen0322->regmap, SEN0322_REG_COEFF, &val); + if (ret < 0) + return ret; + + if (val) { + *num = val; + *den = 100000; /* Coeff is scaled by 1000 at calibration. */ + } else { /* The device is not calibrated, using the factory-defaults. */ + *num = 209; /* Oxygen content in the atmosphere is 20.9%. */ + *den = 120000; /* Output of the sensor at 20.9% is 120 uA. */ + } + + dev_dbg(regmap_get_device(sen0322->regmap), "scale: %d/%d\n", + *num, *den); + + return 0; +} + +static int sen0322_read_raw(struct iio_dev *iio_dev, + const struct iio_chan_spec *chan, + int *val, int *val2, long mask) +{ + struct sen0322 *sen0322 = iio_priv(iio_dev); + int ret; + + if (chan->type != IIO_CONCENTRATION) + return -EINVAL; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret = sen0322_read_data(sen0322); + if (ret < 0) + return ret; + + *val = ret; + return IIO_VAL_INT; + + case IIO_CHAN_INFO_SCALE: + ret = sen0322_read_scale(sen0322, val, val2); + if (ret < 0) + return ret; + + return IIO_VAL_FRACTIONAL; + + default: + return -EINVAL; + } +} + +static const struct iio_info sen0322_info = { + .read_raw = sen0322_read_raw, +}; + +static const struct regmap_config sen0322_regmap_conf = { + .reg_bits = 8, + .val_bits = 8, +}; + +static const struct iio_chan_spec sen0322_channel = { + .type = IIO_CONCENTRATION, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE), +}; + +static int sen0322_probe(struct i2c_client *client) +{ + struct sen0322 *sen0322; + struct iio_dev *iio_dev; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) + return -ENODEV; + + iio_dev = devm_iio_device_alloc(&client->dev, sizeof(*sen0322)); + if (!iio_dev) + return -ENOMEM; + + sen0322 = iio_priv(iio_dev); + + sen0322->regmap = devm_regmap_init_i2c(client, &sen0322_regmap_conf); + if (IS_ERR(sen0322->regmap)) + return PTR_ERR(sen0322->regmap); + + iio_dev->info = &sen0322_info; + iio_dev->name = "sen0322"; + iio_dev->channels = &sen0322_channel; + iio_dev->num_channels = 1; + iio_dev->modes = INDIO_DIRECT_MODE; + + return devm_iio_device_register(&client->dev, iio_dev); +} + +static const struct of_device_id sen0322_of_match[] = { + { .compatible = "dfrobot,sen0322" }, + { } +}; +MODULE_DEVICE_TABLE(of, sen0322_of_match); + +static struct i2c_driver sen0322_driver = { + .driver = { + .name = "sen0322", + .of_match_table = sen0322_of_match, + }, + .probe = sen0322_probe, +}; +module_i2c_driver(sen0322_driver); + +MODULE_AUTHOR("Tóth János <gomba007@gmail.com>"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("SEN0322 oxygen sensor driver"); diff --git a/drivers/iio/chemical/sps30.c b/drivers/iio/chemical/sps30.c index a7888146188d..a934bf0298dd 100644 --- a/drivers/iio/chemical/sps30.c +++ b/drivers/iio/chemical/sps30.c @@ -117,8 +117,8 @@ static irqreturn_t sps30_trigger_handler(int irq, void *p) if (ret) goto err; - iio_push_to_buffers_with_timestamp(indio_dev, &scan, - iio_get_time_ns(indio_dev)); + iio_push_to_buffers_with_ts(indio_dev, &scan, sizeof(scan), + iio_get_time_ns(indio_dev)); err: iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/chemical/sunrise_co2.c b/drivers/iio/chemical/sunrise_co2.c index cdb8696a4e81..af79efde37e8 100644 --- a/drivers/iio/chemical/sunrise_co2.c +++ b/drivers/iio/chemical/sunrise_co2.c @@ -373,7 +373,7 @@ static const struct iio_chan_spec_ext_info sunrise_concentration_ext_info[] = { .read = iio_enum_available_read, .private = (uintptr_t)&sunrise_error_statuses_enum, }, - {} + { } }; static const struct iio_chan_spec sunrise_channels[] = { @@ -519,7 +519,7 @@ static int sunrise_probe(struct i2c_client *client) static const struct of_device_id sunrise_of_match[] = { { .compatible = "senseair,sunrise-006-0-0007" }, - {} + { } }; MODULE_DEVICE_TABLE(of, sunrise_of_match); diff --git a/drivers/iio/common/cros_ec_sensors/cros_ec_lid_angle.c b/drivers/iio/common/cros_ec_sensors/cros_ec_lid_angle.c index 119acb078af3..2d3d148b4206 100644 --- a/drivers/iio/common/cros_ec_sensors/cros_ec_lid_angle.c +++ b/drivers/iio/common/cros_ec_sensors/cros_ec_lid_angle.c @@ -121,7 +121,7 @@ static const struct platform_device_id cros_ec_lid_angle_ids[] = { { .name = DRV_NAME, }, - { /* sentinel */ } + { } }; MODULE_DEVICE_TABLE(platform, cros_ec_lid_angle_ids); diff --git a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c index 66153b1850f1..82cef4a12442 100644 --- a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c +++ b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c @@ -311,7 +311,7 @@ static const struct platform_device_id cros_ec_sensors_ids[] = { { .name = "cros-ec-mag", }, - { /* sentinel */ } + { } }; MODULE_DEVICE_TABLE(platform, cros_ec_sensors_ids); diff --git a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c index 7751d6f69b12..700ebcd68ff4 100644 --- a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c +++ b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c @@ -34,25 +34,19 @@ static int cros_ec_get_host_cmd_version_mask(struct cros_ec_device *ec_dev, u16 cmd_offset, u16 cmd, u32 *mask) { + DEFINE_RAW_FLEX(struct cros_ec_command, buf, data, + MAX(sizeof(struct ec_response_get_cmd_versions), + sizeof(struct ec_params_get_cmd_versions))); int ret; - struct { - struct cros_ec_command msg; - union { - struct ec_params_get_cmd_versions params; - struct ec_response_get_cmd_versions resp; - }; - } __packed buf = { - .msg = { - .command = EC_CMD_GET_CMD_VERSIONS + cmd_offset, - .insize = sizeof(struct ec_response_get_cmd_versions), - .outsize = sizeof(struct ec_params_get_cmd_versions) - }, - .params = {.cmd = cmd} - }; - - ret = cros_ec_cmd_xfer_status(ec_dev, &buf.msg); + + buf->command = EC_CMD_GET_CMD_VERSIONS + cmd_offset; + buf->insize = sizeof(struct ec_response_get_cmd_versions); + buf->outsize = sizeof(struct ec_params_get_cmd_versions); + ((struct ec_params_get_cmd_versions *)buf->data)->cmd = cmd; + + ret = cros_ec_cmd_xfer_status(ec_dev, buf); if (ret >= 0) - *mask = buf.resp.version_mask; + *mask = ((struct ec_response_get_cmd_versions *)buf->data)->version_mask; return ret; } @@ -97,22 +91,6 @@ static void get_default_min_max_freq(enum motionsensor_type type, } } -static int cros_ec_sensor_set_ec_rate(struct cros_ec_sensors_core_state *st, - int rate) -{ - int ret; - - if (rate > U16_MAX) - rate = U16_MAX; - - mutex_lock(&st->cmd_lock); - st->param.cmd = MOTIONSENSE_CMD_EC_RATE; - st->param.ec_rate.data = rate; - ret = cros_ec_motion_send_host_cmd(st, 0); - mutex_unlock(&st->cmd_lock); - return ret; -} - static ssize_t cros_ec_sensor_set_report_latency(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) @@ -128,7 +106,25 @@ static ssize_t cros_ec_sensor_set_report_latency(struct device *dev, /* EC rate is in ms. */ latency = integer * 1000 + fract / 1000; - ret = cros_ec_sensor_set_ec_rate(st, latency); + + mutex_lock(&st->cmd_lock); + st->param.cmd = MOTIONSENSE_CMD_EC_RATE; + st->param.ec_rate.data = min(U16_MAX, latency); + ret = cros_ec_motion_send_host_cmd(st, 0); + if (ret < 0) { + mutex_unlock(&st->cmd_lock); + return ret; + } + + /* + * Flush samples currently in the FIFO, especially when the new latency + * is shorter than the old one: new timeout value is only considered when + * there is a new sample available. It can take a while for a slow + * sensor. + */ + st->param.cmd = MOTIONSENSE_CMD_FIFO_FLUSH; + ret = cros_ec_motion_send_host_cmd(st, 0); + mutex_unlock(&st->cmd_lock); if (ret < 0) return ret; @@ -486,7 +482,7 @@ const struct iio_chan_spec_ext_info cros_ec_sensors_ext_info[] = { .shared = IIO_SHARED_BY_ALL, .read = cros_ec_sensors_id }, - { }, + { } }; EXPORT_SYMBOL_GPL(cros_ec_sensors_ext_info); @@ -838,6 +834,18 @@ int cros_ec_sensors_core_write(struct cros_ec_sensors_core_state *st, st->param.sensor_odr.roundup = 1; ret = cros_ec_motion_send_host_cmd(st, 0); + if (ret) + break; + + /* Flush the FIFO when a sensor is stopped. + * If the FIFO has just been emptied, pending samples will be + * stuck until new samples are available. It will not happen + * when all the sensors are stopped. + */ + if (frequency == 0) { + st->param.cmd = MOTIONSENSE_CMD_FIFO_FLUSH; + ret = cros_ec_motion_send_host_cmd(st, 0); + } break; default: ret = -EINVAL; diff --git a/drivers/iio/common/scmi_sensors/scmi_iio.c b/drivers/iio/common/scmi_sensors/scmi_iio.c index ed15dcbf4cf6..da516c46e057 100644 --- a/drivers/iio/common/scmi_sensors/scmi_iio.c +++ b/drivers/iio/common/scmi_sensors/scmi_iio.c @@ -351,12 +351,11 @@ static int scmi_iio_read_raw(struct iio_dev *iio_dev, ret = scmi_iio_get_odr_val(iio_dev, val, val2); return ret ? ret : IIO_VAL_INT_PLUS_MICRO; case IIO_CHAN_INFO_RAW: - ret = iio_device_claim_direct_mode(iio_dev); - if (ret) - return ret; + if (!iio_device_claim_direct(iio_dev)) + return -EBUSY; ret = scmi_iio_read_channel_data(iio_dev, ch, val, val2); - iio_device_release_direct_mode(iio_dev); + iio_device_release_direct(iio_dev); return ret; default: return -EINVAL; @@ -418,7 +417,7 @@ static const struct iio_chan_spec_ext_info scmi_iio_ext_info[] = { .read = scmi_iio_get_raw_available, .shared = IIO_SHARED_BY_TYPE, }, - {}, + { } }; static void scmi_iio_set_timestamp_channel(struct iio_chan_spec *iio_chan, @@ -705,7 +704,7 @@ static int scmi_iio_dev_probe(struct scmi_device *sdev) static const struct scmi_device_id scmi_id_table[] = { { SCMI_PROTOCOL_SENSOR, "iiodev" }, - {}, + { } }; MODULE_DEVICE_TABLE(scmi, scmi_id_table); diff --git a/drivers/iio/common/ssp_sensors/ssp_dev.c b/drivers/iio/common/ssp_sensors/ssp_dev.c index 22ea10eb48ae..1e167dc673ca 100644 --- a/drivers/iio/common/ssp_sensors/ssp_dev.c +++ b/drivers/iio/common/ssp_sensors/ssp_dev.c @@ -167,7 +167,7 @@ static void ssp_wdt_work_func(struct work_struct *work) static void ssp_wdt_timer_func(struct timer_list *t) { - struct ssp_data *data = from_timer(data, t, wdt_timer); + struct ssp_data *data = timer_container_of(data, t, wdt_timer); switch (data->fw_dl_state) { case SSP_FW_DL_STATE_FAIL: @@ -434,7 +434,7 @@ static const struct of_device_id ssp_of_match[] = { .compatible = "samsung,sensorhub-thermostat", .data = &ssp_thermostat_info, }, - {}, + { } }; MODULE_DEVICE_TABLE(of, ssp_of_match); diff --git a/drivers/iio/common/ssp_sensors/ssp_spi.c b/drivers/iio/common/ssp_sensors/ssp_spi.c index f32b04b63ea1..b7f093d7345b 100644 --- a/drivers/iio/common/ssp_sensors/ssp_spi.c +++ b/drivers/iio/common/ssp_sensors/ssp_spi.c @@ -104,7 +104,7 @@ static struct ssp_msg *ssp_create_msg(u8 cmd, u16 len, u16 opt, u32 data) /* * It is a bit heavy to do it this way but often the function is used to compose * the message from smaller chunks which are placed on the stack. Often the - * chunks are small so memcpy should be optimalized. + * chunks are small so memcpy should be optimized. */ static inline void ssp_fill_buffer(struct ssp_msg *m, unsigned int offset, const void *src, unsigned int len) diff --git a/drivers/iio/common/st_sensors/st_sensors_core.c b/drivers/iio/common/st_sensors/st_sensors_core.c index e4f5a7ff7e74..8ce1dccfea4f 100644 --- a/drivers/iio/common/st_sensors/st_sensors_core.c +++ b/drivers/iio/common/st_sensors/st_sensors_core.c @@ -530,9 +530,8 @@ int st_sensors_read_info_raw(struct iio_dev *indio_dev, int err; struct st_sensor_data *sdata = iio_priv(indio_dev); - err = iio_device_claim_direct_mode(indio_dev); - if (err) - return err; + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; mutex_lock(&sdata->odr_lock); @@ -551,7 +550,7 @@ int st_sensors_read_info_raw(struct iio_dev *indio_dev, out: mutex_unlock(&sdata->odr_lock); - iio_device_release_direct_mode(indio_dev); + iio_device_release_direct(indio_dev); return err; } diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig index 4811ea973125..e0996dc014a3 100644 --- a/drivers/iio/dac/Kconfig +++ b/drivers/iio/dac/Kconfig @@ -6,6 +6,17 @@ menu "Digital to analog converters" +config AD3530R + tristate "Analog Devices AD3530R and Similar DACs driver" + depends on SPI + select REGMAP_SPI + help + Say yes here to build support for Analog Devices AD3530R, AD3531R + Digital to Analog Converter. + + To compile this driver as a module, choose M here: the + module will be called ad3530r. + config AD3552R_HS tristate "Analog Devices AD3552R DAC High Speed driver" select AD3552R_LIB diff --git a/drivers/iio/dac/Makefile b/drivers/iio/dac/Makefile index 8dd6cce81ed1..3684cd52b7fa 100644 --- a/drivers/iio/dac/Makefile +++ b/drivers/iio/dac/Makefile @@ -4,6 +4,7 @@ # # When adding new entries keep the list in alphabetical order +obj-$(CONFIG_AD3530R) += ad3530r.o obj-$(CONFIG_AD3552R_HS) += ad3552r-hs.o obj-$(CONFIG_AD3552R_LIB) += ad3552r-common.o obj-$(CONFIG_AD3552R) += ad3552r.o diff --git a/drivers/iio/dac/ad3530r.c b/drivers/iio/dac/ad3530r.c new file mode 100644 index 000000000000..f9752a571aa5 --- /dev/null +++ b/drivers/iio/dac/ad3530r.c @@ -0,0 +1,517 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * AD3530R/AD3530 8-channel, 16-bit Voltage Output DAC Driver + * AD3531R/AD3531 4-channel, 16-bit Voltage Output DAC Driver + * + * Copyright 2025 Analog Devices Inc. + */ + +#include <linux/array_size.h> +#include <linux/bitfield.h> +#include <linux/bits.h> +#include <linux/cleanup.h> +#include <linux/delay.h> +#include <linux/dev_printk.h> +#include <linux/err.h> +#include <linux/gpio/consumer.h> +#include <linux/iio/iio.h> +#include <linux/kstrtox.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/property.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> +#include <linux/spi/spi.h> +#include <linux/sysfs.h> +#include <linux/types.h> +#include <linux/units.h> + +#define AD3530R_INTERFACE_CONFIG_A 0x00 +#define AD3530R_OUTPUT_OPERATING_MODE_0 0x20 +#define AD3530R_OUTPUT_OPERATING_MODE_1 0x21 +#define AD3530R_OUTPUT_CONTROL_0 0x2A +#define AD3530R_REFERENCE_CONTROL_0 0x3C +#define AD3530R_SW_LDAC_TRIG_A 0xE5 +#define AD3530R_INPUT_CH 0xEB +#define AD3530R_MAX_REG_ADDR 0xF9 + +#define AD3531R_SW_LDAC_TRIG_A 0xDD +#define AD3531R_INPUT_CH 0xE3 + +#define AD3530R_SLD_TRIG_A BIT(7) +#define AD3530R_OUTPUT_CONTROL_RANGE BIT(2) +#define AD3530R_REFERENCE_CONTROL_SEL BIT(0) +#define AD3530R_REG_VAL_MASK GENMASK(15, 0) +#define AD3530R_OP_MODE_CHAN_MSK(chan) (GENMASK(1, 0) << 2 * (chan)) + +#define AD3530R_SW_RESET (BIT(7) | BIT(0)) +#define AD3530R_INTERNAL_VREF_mV 2500 +#define AD3530R_LDAC_PULSE_US 100 + +#define AD3530R_DAC_MAX_VAL GENMASK(15, 0) +#define AD3530R_MAX_CHANNELS 8 +#define AD3531R_MAX_CHANNELS 4 + +/* Non-constant mask variant of FIELD_PREP() */ +#define field_prep(_mask, _val) (((_val) << (ffs(_mask) - 1)) & (_mask)) + +enum ad3530r_mode { + AD3530R_NORMAL_OP, + AD3530R_POWERDOWN_1K, + AD3530R_POWERDOWN_7K7, + AD3530R_POWERDOWN_32K, +}; + +struct ad3530r_chan { + enum ad3530r_mode powerdown_mode; + bool powerdown; +}; + +struct ad3530r_chip_info { + const char *name; + const struct iio_chan_spec *channels; + int (*input_ch_reg)(unsigned int channel); + unsigned int num_channels; + unsigned int sw_ldac_trig_reg; + bool internal_ref_support; +}; + +struct ad3530r_state { + struct regmap *regmap; + /* lock to protect against multiple access to the device and shared data */ + struct mutex lock; + struct ad3530r_chan chan[AD3530R_MAX_CHANNELS]; + const struct ad3530r_chip_info *chip_info; + struct gpio_desc *ldac_gpio; + int vref_mV; + /* + * DMA (thus cache coherency maintenance) may require the transfer + * buffers to live in their own cache lines. + */ + __be16 buf __aligned(IIO_DMA_MINALIGN); +}; + +static int ad3530r_input_ch_reg(unsigned int channel) +{ + return 2 * channel + AD3530R_INPUT_CH; +} + +static int ad3531r_input_ch_reg(unsigned int channel) +{ + return 2 * channel + AD3531R_INPUT_CH; +} + +static const char * const ad3530r_powerdown_modes[] = { + "1kohm_to_gnd", + "7.7kohm_to_gnd", + "32kohm_to_gnd", +}; + +static int ad3530r_get_powerdown_mode(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan) +{ + struct ad3530r_state *st = iio_priv(indio_dev); + + guard(mutex)(&st->lock); + return st->chan[chan->channel].powerdown_mode - 1; +} + +static int ad3530r_set_powerdown_mode(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + unsigned int mode) +{ + struct ad3530r_state *st = iio_priv(indio_dev); + + guard(mutex)(&st->lock); + st->chan[chan->channel].powerdown_mode = mode + 1; + + return 0; +} + +static const struct iio_enum ad3530r_powerdown_mode_enum = { + .items = ad3530r_powerdown_modes, + .num_items = ARRAY_SIZE(ad3530r_powerdown_modes), + .get = ad3530r_get_powerdown_mode, + .set = ad3530r_set_powerdown_mode, +}; + +static ssize_t ad3530r_get_dac_powerdown(struct iio_dev *indio_dev, + uintptr_t private, + const struct iio_chan_spec *chan, + char *buf) +{ + struct ad3530r_state *st = iio_priv(indio_dev); + + guard(mutex)(&st->lock); + return sysfs_emit(buf, "%d\n", st->chan[chan->channel].powerdown); +} + +static ssize_t ad3530r_set_dac_powerdown(struct iio_dev *indio_dev, + uintptr_t private, + const struct iio_chan_spec *chan, + const char *buf, size_t len) +{ + struct ad3530r_state *st = iio_priv(indio_dev); + int ret; + unsigned int reg, pdmode, mask, val; + bool powerdown; + + ret = kstrtobool(buf, &powerdown); + if (ret) + return ret; + + guard(mutex)(&st->lock); + reg = chan->channel < AD3531R_MAX_CHANNELS ? + AD3530R_OUTPUT_OPERATING_MODE_0 : + AD3530R_OUTPUT_OPERATING_MODE_1; + pdmode = powerdown ? st->chan[chan->channel].powerdown_mode : 0; + mask = AD3530R_OP_MODE_CHAN_MSK(chan->channel); + val = field_prep(mask, pdmode); + + ret = regmap_update_bits(st->regmap, reg, mask, val); + if (ret) + return ret; + + st->chan[chan->channel].powerdown = powerdown; + + return len; +} + +static int ad3530r_trigger_hw_ldac(struct gpio_desc *ldac_gpio) +{ + gpiod_set_value_cansleep(ldac_gpio, 1); + fsleep(AD3530R_LDAC_PULSE_US); + gpiod_set_value_cansleep(ldac_gpio, 0); + + return 0; +} + +static int ad3530r_dac_write(struct ad3530r_state *st, unsigned int chan, + unsigned int val) +{ + int ret; + + guard(mutex)(&st->lock); + st->buf = cpu_to_be16(val); + + ret = regmap_bulk_write(st->regmap, st->chip_info->input_ch_reg(chan), + &st->buf, sizeof(st->buf)); + if (ret) + return ret; + + if (st->ldac_gpio) + return ad3530r_trigger_hw_ldac(st->ldac_gpio); + + return regmap_set_bits(st->regmap, st->chip_info->sw_ldac_trig_reg, + AD3530R_SLD_TRIG_A); +} + +static int ad3530r_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long info) +{ + struct ad3530r_state *st = iio_priv(indio_dev); + int ret; + + guard(mutex)(&st->lock); + switch (info) { + case IIO_CHAN_INFO_RAW: + ret = regmap_bulk_read(st->regmap, + st->chip_info->input_ch_reg(chan->channel), + &st->buf, sizeof(st->buf)); + if (ret) + return ret; + + *val = FIELD_GET(AD3530R_REG_VAL_MASK, be16_to_cpu(st->buf)); + + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + *val = st->vref_mV; + *val2 = 16; + + return IIO_VAL_FRACTIONAL_LOG2; + default: + return -EINVAL; + } +} + +static int ad3530r_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long info) +{ + struct ad3530r_state *st = iio_priv(indio_dev); + + switch (info) { + case IIO_CHAN_INFO_RAW: + if (val < 0 || val > AD3530R_DAC_MAX_VAL) + return -EINVAL; + + return ad3530r_dac_write(st, chan->channel, val); + default: + return -EINVAL; + } +} + +static int ad3530r_reg_access(struct iio_dev *indio_dev, unsigned int reg, + unsigned int writeval, unsigned int *readval) +{ + struct ad3530r_state *st = iio_priv(indio_dev); + + if (readval) + return regmap_read(st->regmap, reg, readval); + + return regmap_write(st->regmap, reg, writeval); +} + +static const struct iio_chan_spec_ext_info ad3530r_ext_info[] = { + { + .name = "powerdown", + .shared = IIO_SEPARATE, + .read = ad3530r_get_dac_powerdown, + .write = ad3530r_set_dac_powerdown, + }, + IIO_ENUM("powerdown_mode", IIO_SEPARATE, &ad3530r_powerdown_mode_enum), + IIO_ENUM_AVAILABLE("powerdown_mode", IIO_SHARED_BY_TYPE, + &ad3530r_powerdown_mode_enum), + { } +}; + +#define AD3530R_CHAN(_chan) \ +{ \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .channel = _chan, \ + .output = 1, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SCALE), \ + .ext_info = ad3530r_ext_info, \ +} + +static const struct iio_chan_spec ad3530r_channels[] = { + AD3530R_CHAN(0), + AD3530R_CHAN(1), + AD3530R_CHAN(2), + AD3530R_CHAN(3), + AD3530R_CHAN(4), + AD3530R_CHAN(5), + AD3530R_CHAN(6), + AD3530R_CHAN(7), +}; + +static const struct iio_chan_spec ad3531r_channels[] = { + AD3530R_CHAN(0), + AD3530R_CHAN(1), + AD3530R_CHAN(2), + AD3530R_CHAN(3), +}; + +static const struct ad3530r_chip_info ad3530_chip = { + .name = "ad3530", + .channels = ad3530r_channels, + .num_channels = ARRAY_SIZE(ad3530r_channels), + .sw_ldac_trig_reg = AD3530R_SW_LDAC_TRIG_A, + .input_ch_reg = ad3530r_input_ch_reg, + .internal_ref_support = false, +}; + +static const struct ad3530r_chip_info ad3530r_chip = { + .name = "ad3530r", + .channels = ad3530r_channels, + .num_channels = ARRAY_SIZE(ad3530r_channels), + .sw_ldac_trig_reg = AD3530R_SW_LDAC_TRIG_A, + .input_ch_reg = ad3530r_input_ch_reg, + .internal_ref_support = true, +}; + +static const struct ad3530r_chip_info ad3531_chip = { + .name = "ad3531", + .channels = ad3531r_channels, + .num_channels = ARRAY_SIZE(ad3531r_channels), + .sw_ldac_trig_reg = AD3531R_SW_LDAC_TRIG_A, + .input_ch_reg = ad3531r_input_ch_reg, + .internal_ref_support = false, +}; + +static const struct ad3530r_chip_info ad3531r_chip = { + .name = "ad3531r", + .channels = ad3531r_channels, + .num_channels = ARRAY_SIZE(ad3531r_channels), + .sw_ldac_trig_reg = AD3531R_SW_LDAC_TRIG_A, + .input_ch_reg = ad3531r_input_ch_reg, + .internal_ref_support = true, +}; + +static int ad3530r_setup(struct ad3530r_state *st, int external_vref_uV) +{ + struct device *dev = regmap_get_device(st->regmap); + struct gpio_desc *reset_gpio; + int i, ret; + u8 range_multiplier, val; + + reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(reset_gpio)) + return dev_err_probe(dev, PTR_ERR(reset_gpio), + "Failed to get reset GPIO\n"); + + if (reset_gpio) { + /* Perform hardware reset */ + fsleep(1 * USEC_PER_MSEC); + gpiod_set_value_cansleep(reset_gpio, 0); + } else { + /* Perform software reset */ + ret = regmap_update_bits(st->regmap, AD3530R_INTERFACE_CONFIG_A, + AD3530R_SW_RESET, AD3530R_SW_RESET); + if (ret) + return ret; + } + + fsleep(10 * USEC_PER_MSEC); + + range_multiplier = 1; + if (device_property_read_bool(dev, "adi,range-double")) { + ret = regmap_set_bits(st->regmap, AD3530R_OUTPUT_CONTROL_0, + AD3530R_OUTPUT_CONTROL_RANGE); + if (ret) + return ret; + + range_multiplier = 2; + } + + if (external_vref_uV) { + st->vref_mV = range_multiplier * external_vref_uV / MILLI; + } else { + ret = regmap_set_bits(st->regmap, AD3530R_REFERENCE_CONTROL_0, + AD3530R_REFERENCE_CONTROL_SEL); + if (ret) + return ret; + + st->vref_mV = range_multiplier * AD3530R_INTERNAL_VREF_mV; + } + + /* Set normal operating mode for all channels */ + val = FIELD_PREP(AD3530R_OP_MODE_CHAN_MSK(0), AD3530R_NORMAL_OP) | + FIELD_PREP(AD3530R_OP_MODE_CHAN_MSK(1), AD3530R_NORMAL_OP) | + FIELD_PREP(AD3530R_OP_MODE_CHAN_MSK(2), AD3530R_NORMAL_OP) | + FIELD_PREP(AD3530R_OP_MODE_CHAN_MSK(3), AD3530R_NORMAL_OP); + + ret = regmap_write(st->regmap, AD3530R_OUTPUT_OPERATING_MODE_0, val); + if (ret) + return ret; + + if (st->chip_info->num_channels > 4) { + ret = regmap_write(st->regmap, AD3530R_OUTPUT_OPERATING_MODE_1, + val); + if (ret) + return ret; + } + + for (i = 0; i < st->chip_info->num_channels; i++) + st->chan[i].powerdown_mode = AD3530R_POWERDOWN_32K; + + st->ldac_gpio = devm_gpiod_get_optional(dev, "ldac", GPIOD_OUT_LOW); + if (IS_ERR(st->ldac_gpio)) + return dev_err_probe(dev, PTR_ERR(st->ldac_gpio), + "Failed to get ldac GPIO\n"); + + return 0; +} + +static const struct regmap_config ad3530r_regmap_config = { + .reg_bits = 16, + .val_bits = 8, + .max_register = AD3530R_MAX_REG_ADDR, +}; + +static const struct iio_info ad3530r_info = { + .read_raw = ad3530r_read_raw, + .write_raw = ad3530r_write_raw, + .debugfs_reg_access = ad3530r_reg_access, +}; + +static int ad3530r_probe(struct spi_device *spi) +{ + static const char * const regulators[] = { "vdd", "iovdd" }; + struct device *dev = &spi->dev; + struct iio_dev *indio_dev; + struct ad3530r_state *st; + int ret, external_vref_uV; + + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; + + st = iio_priv(indio_dev); + + st->regmap = devm_regmap_init_spi(spi, &ad3530r_regmap_config); + if (IS_ERR(st->regmap)) + return dev_err_probe(dev, PTR_ERR(st->regmap), + "Failed to init regmap"); + + ret = devm_mutex_init(dev, &st->lock); + if (ret) + return ret; + + st->chip_info = spi_get_device_match_data(spi); + if (!st->chip_info) + return -ENODEV; + + ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(regulators), + regulators); + if (ret) + return dev_err_probe(dev, ret, "Failed to enable regulators\n"); + + external_vref_uV = devm_regulator_get_enable_read_voltage(dev, "ref"); + if (external_vref_uV < 0 && external_vref_uV != -ENODEV) + return external_vref_uV; + + if (external_vref_uV == -ENODEV) + external_vref_uV = 0; + + if (!st->chip_info->internal_ref_support && external_vref_uV == 0) + return -ENODEV; + + ret = ad3530r_setup(st, external_vref_uV); + if (ret) + return ret; + + indio_dev->name = st->chip_info->name; + indio_dev->info = &ad3530r_info; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = st->chip_info->channels; + indio_dev->num_channels = st->chip_info->num_channels; + + return devm_iio_device_register(&spi->dev, indio_dev); +} + +static const struct spi_device_id ad3530r_id[] = { + { "ad3530", (kernel_ulong_t)&ad3530_chip }, + { "ad3530r", (kernel_ulong_t)&ad3530r_chip }, + { "ad3531", (kernel_ulong_t)&ad3531_chip }, + { "ad3531r", (kernel_ulong_t)&ad3531r_chip }, + { } +}; +MODULE_DEVICE_TABLE(spi, ad3530r_id); + +static const struct of_device_id ad3530r_of_match[] = { + { .compatible = "adi,ad3530", .data = &ad3530_chip }, + { .compatible = "adi,ad3530r", .data = &ad3530r_chip }, + { .compatible = "adi,ad3531", .data = &ad3531_chip }, + { .compatible = "adi,ad3531r", .data = &ad3531r_chip }, + { } +}; +MODULE_DEVICE_TABLE(of, ad3530r_of_match); + +static struct spi_driver ad3530r_driver = { + .driver = { + .name = "ad3530r", + .of_match_table = ad3530r_of_match, + }, + .probe = ad3530r_probe, + .id_table = ad3530r_id, +}; +module_spi_driver(ad3530r_driver); + +MODULE_AUTHOR("Kim Seer Paller <kimseer.paller@analog.com>"); +MODULE_DESCRIPTION("Analog Devices AD3530R and Similar DACs Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/dac/ad3552r-common.c b/drivers/iio/dac/ad3552r-common.c index b8807e54fa05..38baaea0e6c8 100644 --- a/drivers/iio/dac/ad3552r-common.c +++ b/drivers/iio/dac/ad3552r-common.c @@ -43,6 +43,7 @@ const struct ad3552r_model_data ad3541r_model_data = { .num_ranges = ARRAY_SIZE(ad3542r_ch_ranges), .requires_output_range = true, .num_spi_data_lanes = 2, + .max_reg_addr = 0x46, }; EXPORT_SYMBOL_NS_GPL(ad3541r_model_data, "IIO_AD3552R"); @@ -54,6 +55,7 @@ const struct ad3552r_model_data ad3542r_model_data = { .num_ranges = ARRAY_SIZE(ad3542r_ch_ranges), .requires_output_range = true, .num_spi_data_lanes = 2, + .max_reg_addr = 0x49, }; EXPORT_SYMBOL_NS_GPL(ad3542r_model_data, "IIO_AD3552R"); @@ -65,6 +67,7 @@ const struct ad3552r_model_data ad3551r_model_data = { .num_ranges = ARRAY_SIZE(ad3552r_ch_ranges), .requires_output_range = false, .num_spi_data_lanes = 4, + .max_reg_addr = 0x46, }; EXPORT_SYMBOL_NS_GPL(ad3551r_model_data, "IIO_AD3552R"); @@ -76,6 +79,7 @@ const struct ad3552r_model_data ad3552r_model_data = { .num_ranges = ARRAY_SIZE(ad3552r_ch_ranges), .requires_output_range = false, .num_spi_data_lanes = 4, + .max_reg_addr = 0x49, }; EXPORT_SYMBOL_NS_GPL(ad3552r_model_data, "IIO_AD3552R"); diff --git a/drivers/iio/dac/ad3552r-hs.c b/drivers/iio/dac/ad3552r-hs.c index cd8dabb60c55..41b96b48ba98 100644 --- a/drivers/iio/dac/ad3552r-hs.c +++ b/drivers/iio/dac/ad3552r-hs.c @@ -7,6 +7,7 @@ */ #include <linux/bitfield.h> +#include <linux/debugfs.h> #include <linux/delay.h> #include <linux/gpio/consumer.h> #include <linux/iio/backend.h> @@ -54,6 +55,18 @@ struct ad3552r_hs_state { struct ad3552r_hs_platform_data *data; /* INTERFACE_CONFIG_D register cache, in DDR we cannot read values. */ u32 config_d; + /* Protects backend I/O operations from concurrent accesses. */ + struct mutex lock; +}; + +enum ad3552r_sources { + AD3552R_SRC_NORMAL, + AD3552R_SRC_RAMP_16BIT, +}; + +static const char * const dbgfs_attr_source[] = { + [AD3552R_SRC_NORMAL] = "normal", + [AD3552R_SRC_RAMP_16BIT] = "ramp-16bit", }; static int ad3552r_hs_reg_read(struct ad3552r_hs_state *st, u32 reg, u32 *val, @@ -65,6 +78,20 @@ static int ad3552r_hs_reg_read(struct ad3552r_hs_state *st, u32 reg, u32 *val, return st->data->bus_reg_read(st->back, reg, val, xfer_size); } +static int ad3552r_hs_set_data_source(struct ad3552r_hs_state *st, + enum iio_backend_data_source type) +{ + int i, ret; + + for (i = 0; i < st->model_data->num_hw_channels; ++i) { + ret = iio_backend_data_source_set(st->back, i, type); + if (ret) + return ret; + } + + return 0; +} + static int ad3552r_hs_update_reg_bits(struct ad3552r_hs_state *st, u32 reg, u32 mask, u32 val, size_t xfer_size) { @@ -464,6 +491,122 @@ static int ad3552r_hs_setup_custom_gain(struct ad3552r_hs_state *st, gain, 1); } +static int ad3552r_hs_reg_access(struct iio_dev *indio_dev, unsigned int reg, + unsigned int writeval, unsigned int *readval) +{ + struct ad3552r_hs_state *st = iio_priv(indio_dev); + + if (reg > st->model_data->max_reg_addr) + return -EINVAL; + + /* + * There are 8, 16 or 24 bit registers, but HDL supports only reading 8 + * or 16 bit data, not 24. So, also to avoid to check any proper read + * alignment, supporting only 8-bit readings here. + */ + if (readval) + return ad3552r_hs_reg_read(st, reg, readval, 1); + + return st->data->bus_reg_write(st->back, reg, writeval, 1); +} + +static ssize_t ad3552r_hs_show_data_source(struct file *f, char __user *userbuf, + size_t count, loff_t *ppos) +{ + struct ad3552r_hs_state *st = file_inode(f)->i_private; + enum iio_backend_data_source type; + int idx, ret; + + guard(mutex)(&st->lock); + + ret = iio_backend_data_source_get(st->back, 0, &type); + if (ret) + return ret; + + switch (type) { + case IIO_BACKEND_INTERNAL_RAMP_16BIT: + idx = AD3552R_SRC_RAMP_16BIT; + break; + case IIO_BACKEND_EXTERNAL: + idx = AD3552R_SRC_NORMAL; + break; + default: + return -EINVAL; + } + + return simple_read_from_buffer(userbuf, count, ppos, + dbgfs_attr_source[idx], + strlen(dbgfs_attr_source[idx])); +} + +static ssize_t ad3552r_hs_write_data_source(struct file *f, + const char __user *userbuf, + size_t count, loff_t *ppos) +{ + struct ad3552r_hs_state *st = file_inode(f)->i_private; + char buf[64]; + int ret, source; + + guard(mutex)(&st->lock); + + ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, userbuf, + count); + if (ret < 0) + return ret; + + buf[count] = '\0'; + + ret = match_string(dbgfs_attr_source, ARRAY_SIZE(dbgfs_attr_source), + buf); + if (ret < 0) + return ret; + + switch (ret) { + case AD3552R_SRC_RAMP_16BIT: + source = IIO_BACKEND_INTERNAL_RAMP_16BIT; + break; + case AD3552R_SRC_NORMAL: + source = IIO_BACKEND_EXTERNAL; + break; + default: + return -EINVAL; + } + + ret = ad3552r_hs_set_data_source(st, source); + if (ret) + return ret; + + return count; +} + +static ssize_t ad3552r_hs_show_data_source_avail(struct file *f, + char __user *userbuf, + size_t count, loff_t *ppos) +{ + ssize_t len = 0; + char buf[128]; + int i; + + for (i = 0; i < ARRAY_SIZE(dbgfs_attr_source); i++) { + len += scnprintf(buf + len, PAGE_SIZE - len, "%s ", + dbgfs_attr_source[i]); + } + buf[len - 1] = '\n'; + + return simple_read_from_buffer(userbuf, count, ppos, buf, len); +} + +static const struct file_operations ad3552r_hs_data_source_fops = { + .owner = THIS_MODULE, + .write = ad3552r_hs_write_data_source, + .read = ad3552r_hs_show_data_source, +}; + +static const struct file_operations ad3552r_hs_data_source_avail_fops = { + .owner = THIS_MODULE, + .read = ad3552r_hs_show_data_source_avail, +}; + static int ad3552r_hs_setup(struct ad3552r_hs_state *st) { u16 id; @@ -531,11 +674,7 @@ static int ad3552r_hs_setup(struct ad3552r_hs_state *st) if (ret) return ret; - ret = iio_backend_data_source_set(st->back, 0, IIO_BACKEND_EXTERNAL); - if (ret) - return ret; - - ret = iio_backend_data_source_set(st->back, 1, IIO_BACKEND_EXTERNAL); + ret = ad3552r_hs_set_data_source(st, IIO_BACKEND_EXTERNAL); if (ret) return ret; @@ -639,8 +778,29 @@ static const struct iio_chan_spec ad3552r_hs_channels[] = { static const struct iio_info ad3552r_hs_info = { .read_raw = &ad3552r_hs_read_raw, .write_raw = &ad3552r_hs_write_raw, + .debugfs_reg_access = &ad3552r_hs_reg_access, }; +static void ad3552r_hs_debugfs_init(struct iio_dev *indio_dev) +{ + struct ad3552r_hs_state *st = iio_priv(indio_dev); + struct dentry *d = iio_get_debugfs_dentry(indio_dev); + + if (!IS_ENABLED(CONFIG_DEBUG_FS)) + return; + + d = iio_get_debugfs_dentry(indio_dev); + if (!d) { + dev_warn(st->dev, "can't set debugfs in driver dir\n"); + return; + } + + debugfs_create_file("data_source", 0600, d, st, + &ad3552r_hs_data_source_fops); + debugfs_create_file("data_source_available", 0600, d, st, + &ad3552r_hs_data_source_avail_fops); +} + static int ad3552r_hs_probe(struct platform_device *pdev) { struct ad3552r_hs_state *st; @@ -685,7 +845,17 @@ static int ad3552r_hs_probe(struct platform_device *pdev) if (ret) return ret; - return devm_iio_device_register(&pdev->dev, indio_dev); + ret = devm_iio_device_register(&pdev->dev, indio_dev); + if (ret) + return ret; + + ret = devm_mutex_init(&pdev->dev, &st->lock); + if (ret) + return ret; + + ad3552r_hs_debugfs_init(indio_dev); + + return ret; } static const struct of_device_id ad3552r_hs_of_id[] = { diff --git a/drivers/iio/dac/ad3552r.h b/drivers/iio/dac/ad3552r.h index 768fa264d39e..9bb46a9e07a5 100644 --- a/drivers/iio/dac/ad3552r.h +++ b/drivers/iio/dac/ad3552r.h @@ -156,6 +156,7 @@ struct ad3552r_model_data { int num_ranges; bool requires_output_range; int num_spi_data_lanes; + int max_reg_addr; }; struct ad3552r_ch_data { diff --git a/drivers/iio/dac/ad5064.c b/drivers/iio/dac/ad5064.c index 905988724f27..84be5174babd 100644 --- a/drivers/iio/dac/ad5064.c +++ b/drivers/iio/dac/ad5064.c @@ -378,7 +378,7 @@ static const struct iio_chan_spec_ext_info ad5064_ext_info[] = { }, IIO_ENUM("powerdown_mode", IIO_SEPARATE, &ad5064_powerdown_mode_enum), IIO_ENUM_AVAILABLE("powerdown_mode", IIO_SHARED_BY_TYPE, &ad5064_powerdown_mode_enum), - { }, + { } }; static const struct iio_chan_spec_ext_info ltc2617_ext_info[] = { @@ -390,7 +390,7 @@ static const struct iio_chan_spec_ext_info ltc2617_ext_info[] = { }, IIO_ENUM("powerdown_mode", IIO_SEPARATE, <c2617_powerdown_mode_enum), IIO_ENUM_AVAILABLE("powerdown_mode", IIO_SHARED_BY_TYPE, <c2617_powerdown_mode_enum), - { }, + { } }; #define AD5064_CHANNEL(chan, addr, bits, _shift, _ext_info) { \ @@ -936,7 +936,7 @@ static const struct spi_device_id ad5064_spi_ids[] = { {"ad5668-1", ID_AD5668_1}, {"ad5668-2", ID_AD5668_2}, {"ad5668-3", ID_AD5668_2}, /* similar enough to ad5668-2 */ - {} + { } }; MODULE_DEVICE_TABLE(spi, ad5064_spi_ids); @@ -1048,7 +1048,7 @@ static const struct i2c_device_id ad5064_i2c_ids[] = { {"ltc2635-h10", ID_LTC2635_H10}, {"ltc2635-l8", ID_LTC2635_L8}, {"ltc2635-h8", ID_LTC2635_H8}, - {} + { } }; MODULE_DEVICE_TABLE(i2c, ad5064_i2c_ids); diff --git a/drivers/iio/dac/ad5360.c b/drivers/iio/dac/ad5360.c index e0b7f658d611..a57b0a093112 100644 --- a/drivers/iio/dac/ad5360.c +++ b/drivers/iio/dac/ad5360.c @@ -542,7 +542,7 @@ static const struct spi_device_id ad5360_ids[] = { { "ad5371", ID_AD5371 }, { "ad5372", ID_AD5372 }, { "ad5373", ID_AD5373 }, - {} + { } }; MODULE_DEVICE_TABLE(spi, ad5360_ids); diff --git a/drivers/iio/dac/ad5380.c b/drivers/iio/dac/ad5380.c index 392a1c7aee03..f63af704b77e 100644 --- a/drivers/iio/dac/ad5380.c +++ b/drivers/iio/dac/ad5380.c @@ -246,7 +246,7 @@ static const struct iio_chan_spec_ext_info ad5380_ext_info[] = { IIO_ENUM("powerdown_mode", IIO_SHARED_BY_TYPE, &ad5380_powerdown_mode_enum), IIO_ENUM_AVAILABLE("powerdown_mode", IIO_SHARED_BY_TYPE, &ad5380_powerdown_mode_enum), - { }, + { } }; #define AD5380_CHANNEL(_bits) { \ diff --git a/drivers/iio/dac/ad5446.c b/drivers/iio/dac/ad5446.c index 6ad99f97eed5..ad304b0fec08 100644 --- a/drivers/iio/dac/ad5446.c +++ b/drivers/iio/dac/ad5446.c @@ -141,7 +141,7 @@ static const struct iio_chan_spec_ext_info ad5446_ext_info_powerdown[] = { }, IIO_ENUM("powerdown_mode", IIO_SEPARATE, &ad5446_powerdown_mode_enum), IIO_ENUM_AVAILABLE("powerdown_mode", IIO_SHARED_BY_TYPE, &ad5446_powerdown_mode_enum), - { }, + { } }; #define _AD5446_CHANNEL(bits, storage, _shift, ext) { \ @@ -440,7 +440,7 @@ static const struct spi_device_id ad5446_spi_ids[] = { {"dac101s101", ID_AD5310}, {"dac121s101", ID_AD5320}, {"dac7512", ID_AD5320}, - {} + { } }; MODULE_DEVICE_TABLE(spi, ad5446_spi_ids); @@ -543,7 +543,7 @@ static const struct i2c_device_id ad5446_i2c_ids[] = { {"ad5602", ID_AD5602}, {"ad5612", ID_AD5612}, {"ad5622", ID_AD5622}, - {} + { } }; MODULE_DEVICE_TABLE(i2c, ad5446_i2c_ids); diff --git a/drivers/iio/dac/ad5449.c b/drivers/iio/dac/ad5449.c index 1c996016756a..d8c325260259 100644 --- a/drivers/iio/dac/ad5449.c +++ b/drivers/iio/dac/ad5449.c @@ -337,7 +337,7 @@ static const struct spi_device_id ad5449_spi_ids[] = { { "ad5439", ID_AD5439 }, { "ad5443", ID_AD5443 }, { "ad5449", ID_AD5449 }, - {} + { } }; MODULE_DEVICE_TABLE(spi, ad5449_spi_ids); diff --git a/drivers/iio/dac/ad5504.c b/drivers/iio/dac/ad5504.c index ff0765c8af47..355bcb6a8ba0 100644 --- a/drivers/iio/dac/ad5504.c +++ b/drivers/iio/dac/ad5504.c @@ -242,7 +242,7 @@ static const struct iio_chan_spec_ext_info ad5504_ext_info[] = { IIO_ENUM("powerdown_mode", IIO_SHARED_BY_TYPE, &ad5504_powerdown_mode_enum), IIO_ENUM_AVAILABLE("powerdown_mode", IIO_SHARED_BY_TYPE, &ad5504_powerdown_mode_enum), - { }, + { } }; #define AD5504_CHANNEL(_chan) { \ @@ -320,7 +320,7 @@ static int ad5504_probe(struct spi_device *spi) static const struct spi_device_id ad5504_id[] = { {"ad5504", ID_AD5504}, {"ad5501", ID_AD5501}, - {} + { } }; MODULE_DEVICE_TABLE(spi, ad5504_id); diff --git a/drivers/iio/dac/ad5592r-base.c b/drivers/iio/dac/ad5592r-base.c index 50d19304bacb..5f2cd51723f6 100644 --- a/drivers/iio/dac/ad5592r-base.c +++ b/drivers/iio/dac/ad5592r-base.c @@ -7,6 +7,7 @@ */ #include <linux/bitops.h> +#include <linux/cleanup.h> #include <linux/delay.h> #include <linux/iio/iio.h> #include <linux/module.h> @@ -24,16 +25,14 @@ static int ad5592r_gpio_get(struct gpio_chip *chip, unsigned offset) { struct ad5592r_state *st = gpiochip_get_data(chip); int ret = 0; - u8 val; + u8 val = 0; - mutex_lock(&st->gpio_lock); - - if (st->gpio_out & BIT(offset)) - val = st->gpio_val; - else - ret = st->ops->gpio_read(st, &val); - - mutex_unlock(&st->gpio_lock); + scoped_guard(mutex, &st->gpio_lock) { + if (st->gpio_out & BIT(offset)) + val = st->gpio_val; + else + ret = st->ops->gpio_read(st, &val); + } if (ret < 0) return ret; @@ -41,20 +40,19 @@ static int ad5592r_gpio_get(struct gpio_chip *chip, unsigned offset) return !!(val & BIT(offset)); } -static void ad5592r_gpio_set(struct gpio_chip *chip, unsigned offset, int value) +static int ad5592r_gpio_set(struct gpio_chip *chip, unsigned int offset, + int value) { struct ad5592r_state *st = gpiochip_get_data(chip); - mutex_lock(&st->gpio_lock); + guard(mutex)(&st->gpio_lock); if (value) st->gpio_val |= BIT(offset); else st->gpio_val &= ~BIT(offset); - st->ops->reg_write(st, AD5592R_REG_GPIO_SET, st->gpio_val); - - mutex_unlock(&st->gpio_lock); + return st->ops->reg_write(st, AD5592R_REG_GPIO_SET, st->gpio_val); } static int ad5592r_gpio_direction_input(struct gpio_chip *chip, unsigned offset) @@ -62,21 +60,16 @@ static int ad5592r_gpio_direction_input(struct gpio_chip *chip, unsigned offset) struct ad5592r_state *st = gpiochip_get_data(chip); int ret; - mutex_lock(&st->gpio_lock); + guard(mutex)(&st->gpio_lock); st->gpio_out &= ~BIT(offset); st->gpio_in |= BIT(offset); ret = st->ops->reg_write(st, AD5592R_REG_GPIO_OUT_EN, st->gpio_out); if (ret < 0) - goto err_unlock; - - ret = st->ops->reg_write(st, AD5592R_REG_GPIO_IN_EN, st->gpio_in); - -err_unlock: - mutex_unlock(&st->gpio_lock); + return ret; - return ret; + return st->ops->reg_write(st, AD5592R_REG_GPIO_IN_EN, st->gpio_in); } static int ad5592r_gpio_direction_output(struct gpio_chip *chip, @@ -85,7 +78,7 @@ static int ad5592r_gpio_direction_output(struct gpio_chip *chip, struct ad5592r_state *st = gpiochip_get_data(chip); int ret; - mutex_lock(&st->gpio_lock); + guard(mutex)(&st->gpio_lock); if (value) st->gpio_val |= BIT(offset); @@ -97,18 +90,13 @@ static int ad5592r_gpio_direction_output(struct gpio_chip *chip, ret = st->ops->reg_write(st, AD5592R_REG_GPIO_SET, st->gpio_val); if (ret < 0) - goto err_unlock; + return ret; ret = st->ops->reg_write(st, AD5592R_REG_GPIO_OUT_EN, st->gpio_out); if (ret < 0) - goto err_unlock; - - ret = st->ops->reg_write(st, AD5592R_REG_GPIO_IN_EN, st->gpio_in); - -err_unlock: - mutex_unlock(&st->gpio_lock); + return ret; - return ret; + return st->ops->reg_write(st, AD5592R_REG_GPIO_IN_EN, st->gpio_in); } static int ad5592r_gpio_request(struct gpio_chip *chip, unsigned offset) @@ -141,7 +129,7 @@ static int ad5592r_gpio_init(struct ad5592r_state *st) st->gpiochip.direction_input = ad5592r_gpio_direction_input; st->gpiochip.direction_output = ad5592r_gpio_direction_output; st->gpiochip.get = ad5592r_gpio_get; - st->gpiochip.set = ad5592r_gpio_set; + st->gpiochip.set_rv = ad5592r_gpio_set; st->gpiochip.request = ad5592r_gpio_request; st->gpiochip.owner = THIS_MODULE; st->gpiochip.names = ad5592r_gpio_names; @@ -155,6 +143,8 @@ static void ad5592r_gpio_cleanup(struct ad5592r_state *st) { if (st->gpio_map) gpiochip_remove(&st->gpiochip); + + mutex_destroy(&st->gpio_lock); } static int ad5592r_reset(struct ad5592r_state *st) @@ -169,10 +159,9 @@ static int ad5592r_reset(struct ad5592r_state *st) udelay(1); gpiod_set_value(gpio, 1); } else { - mutex_lock(&st->lock); - /* Writing this magic value resets the device */ - st->ops->reg_write(st, AD5592R_REG_RESET, 0xdac); - mutex_unlock(&st->lock); + scoped_guard(mutex, &st->lock) + /* Writing this magic value resets the device */ + st->ops->reg_write(st, AD5592R_REG_RESET, 0xdac); } udelay(250); @@ -247,46 +236,44 @@ static int ad5592r_set_channel_modes(struct ad5592r_state *st) } } - mutex_lock(&st->lock); + guard(mutex)(&st->lock); /* Pull down unused pins to GND */ ret = ops->reg_write(st, AD5592R_REG_PULLDOWN, pulldown); if (ret) - goto err_unlock; + return ret; ret = ops->reg_write(st, AD5592R_REG_TRISTATE, tristate); if (ret) - goto err_unlock; + return ret; /* Configure pins that we use */ ret = ops->reg_write(st, AD5592R_REG_DAC_EN, dac); if (ret) - goto err_unlock; + return ret; ret = ops->reg_write(st, AD5592R_REG_ADC_EN, adc); if (ret) - goto err_unlock; + return ret; ret = ops->reg_write(st, AD5592R_REG_GPIO_SET, st->gpio_val); if (ret) - goto err_unlock; + return ret; ret = ops->reg_write(st, AD5592R_REG_GPIO_OUT_EN, st->gpio_out); if (ret) - goto err_unlock; + return ret; ret = ops->reg_write(st, AD5592R_REG_GPIO_IN_EN, st->gpio_in); if (ret) - goto err_unlock; + return ret; /* Verify that we can read back at least one register */ ret = ops->reg_read(st, AD5592R_REG_ADC_EN, &read_back); if (!ret && (read_back & 0xff) != adc) - ret = -EIO; + return -EIO; -err_unlock: - mutex_unlock(&st->lock); - return ret; + return 0; } static int ad5592r_reset_channel_modes(struct ad5592r_state *st) @@ -303,7 +290,7 @@ static int ad5592r_write_raw(struct iio_dev *iio_dev, struct iio_chan_spec const *chan, int val, int val2, long mask) { struct ad5592r_state *st = iio_priv(iio_dev); - int ret; + int ret = 0; switch (mask) { case IIO_CHAN_INFO_RAW: @@ -314,11 +301,11 @@ static int ad5592r_write_raw(struct iio_dev *iio_dev, if (!chan->output) return -EINVAL; - mutex_lock(&st->lock); - ret = st->ops->write_dac(st, chan->channel, val); - if (!ret) - st->cached_dac[chan->channel] = val; - mutex_unlock(&st->lock); + scoped_guard(mutex, &st->lock) { + ret = st->ops->write_dac(st, chan->channel, val); + if (!ret) + st->cached_dac[chan->channel] = val; + } return ret; case IIO_CHAN_INFO_SCALE: if (chan->type == IIO_VOLTAGE) { @@ -333,14 +320,12 @@ static int ad5592r_write_raw(struct iio_dev *iio_dev, else return -EINVAL; - mutex_lock(&st->lock); + guard(mutex)(&st->lock); ret = st->ops->reg_read(st, AD5592R_REG_CTRL, &st->cached_gp_ctrl); - if (ret < 0) { - mutex_unlock(&st->lock); + if (ret < 0) return ret; - } if (chan->output) { if (gain) @@ -358,11 +343,8 @@ static int ad5592r_write_raw(struct iio_dev *iio_dev, ~AD5592R_REG_CTRL_ADC_RANGE; } - ret = st->ops->reg_write(st, AD5592R_REG_CTRL, - st->cached_gp_ctrl); - mutex_unlock(&st->lock); - - return ret; + return st->ops->reg_write(st, AD5592R_REG_CTRL, + st->cached_gp_ctrl); } break; default: @@ -377,15 +359,15 @@ static int ad5592r_read_raw(struct iio_dev *iio_dev, int *val, int *val2, long m) { struct ad5592r_state *st = iio_priv(iio_dev); - u16 read_val; - int ret, mult; + u16 read_val = 0; + int ret = 0, mult = 0; switch (m) { case IIO_CHAN_INFO_RAW: if (!chan->output) { - mutex_lock(&st->lock); - ret = st->ops->read_adc(st, chan->channel, &read_val); - mutex_unlock(&st->lock); + scoped_guard(mutex, &st->lock) + ret = st->ops->read_adc(st, chan->channel, + &read_val); if (ret) return ret; @@ -398,9 +380,8 @@ static int ad5592r_read_raw(struct iio_dev *iio_dev, read_val &= GENMASK(11, 0); } else { - mutex_lock(&st->lock); - read_val = st->cached_dac[chan->channel]; - mutex_unlock(&st->lock); + scoped_guard(mutex, &st->lock) + read_val = st->cached_dac[chan->channel]; } dev_dbg(st->dev, "Channel %u read: 0x%04hX\n", @@ -418,35 +399,32 @@ static int ad5592r_read_raw(struct iio_dev *iio_dev, return IIO_VAL_INT_PLUS_NANO; } - mutex_lock(&st->lock); - - if (chan->output) - mult = !!(st->cached_gp_ctrl & - AD5592R_REG_CTRL_DAC_RANGE); - else - mult = !!(st->cached_gp_ctrl & - AD5592R_REG_CTRL_ADC_RANGE); - - mutex_unlock(&st->lock); + scoped_guard(mutex, &st->lock) { + if (chan->output) + mult = !!(st->cached_gp_ctrl & + AD5592R_REG_CTRL_DAC_RANGE); + else + mult = !!(st->cached_gp_ctrl & + AD5592R_REG_CTRL_ADC_RANGE); + } *val *= ++mult; *val2 = chan->scan_type.realbits; return IIO_VAL_FRACTIONAL_LOG2; - case IIO_CHAN_INFO_OFFSET: + case IIO_CHAN_INFO_OFFSET: { ret = ad5592r_get_vref(st); - mutex_lock(&st->lock); + guard(mutex)(&st->lock); if (st->cached_gp_ctrl & AD5592R_REG_CTRL_ADC_RANGE) *val = (-34365 * 25) / ret; else *val = (-75365 * 25) / ret; - mutex_unlock(&st->lock); - return IIO_VAL_INT; + } default: return -EINVAL; } @@ -490,7 +468,7 @@ static const struct iio_chan_spec_ext_info ad5592r_ext_info[] = { .read = ad5592r_show_scale_available, .shared = IIO_SHARED_BY_TYPE, }, - {}, + { } }; static void ad5592r_setup_channel(struct iio_dev *iio_dev, @@ -606,6 +584,10 @@ int ad5592r_probe(struct device *dev, const char *name, st->num_channels = 8; dev_set_drvdata(dev, iio_dev); + ret = devm_mutex_init(dev, &st->lock); + if (ret) + return ret; + st->reg = devm_regulator_get_optional(dev, "vref"); if (IS_ERR(st->reg)) { if ((PTR_ERR(st->reg) != -ENODEV) && dev_fwnode(dev)) @@ -622,8 +604,6 @@ int ad5592r_probe(struct device *dev, const char *name, iio_dev->info = &ad5592r_info; iio_dev->modes = INDIO_DIRECT_MODE; - mutex_init(&st->lock); - ad5592r_init_scales(st, ad5592r_get_vref(st)); ret = ad5592r_reset(st); diff --git a/drivers/iio/dac/ad5592r.c b/drivers/iio/dac/ad5592r.c index fd82d8701322..92d1b629b85d 100644 --- a/drivers/iio/dac/ad5592r.c +++ b/drivers/iio/dac/ad5592r.c @@ -137,19 +137,19 @@ static void ad5592r_spi_remove(struct spi_device *spi) static const struct spi_device_id ad5592r_spi_ids[] = { { .name = "ad5592r", }, - {} + { } }; MODULE_DEVICE_TABLE(spi, ad5592r_spi_ids); static const struct of_device_id ad5592r_of_match[] = { { .compatible = "adi,ad5592r", }, - {}, + { } }; MODULE_DEVICE_TABLE(of, ad5592r_of_match); static const struct acpi_device_id ad5592r_acpi_match[] = { {"ADS5592", }, - { }, + { } }; MODULE_DEVICE_TABLE(acpi, ad5592r_acpi_match); diff --git a/drivers/iio/dac/ad5593r.c b/drivers/iio/dac/ad5593r.c index ddd13ad821a7..9a8525c61173 100644 --- a/drivers/iio/dac/ad5593r.c +++ b/drivers/iio/dac/ad5593r.c @@ -116,19 +116,19 @@ static void ad5593r_i2c_remove(struct i2c_client *i2c) static const struct i2c_device_id ad5593r_i2c_ids[] = { { .name = "ad5593r", }, - {}, + { } }; MODULE_DEVICE_TABLE(i2c, ad5593r_i2c_ids); static const struct of_device_id ad5593r_of_match[] = { { .compatible = "adi,ad5593r", }, - {}, + { } }; MODULE_DEVICE_TABLE(of, ad5593r_of_match); static const struct acpi_device_id ad5593r_acpi_match[] = { {"ADS5593", }, - { }, + { } }; MODULE_DEVICE_TABLE(acpi, ad5593r_acpi_match); diff --git a/drivers/iio/dac/ad5624r_spi.c b/drivers/iio/dac/ad5624r_spi.c index 2fd38ac8f698..13aefe769bad 100644 --- a/drivers/iio/dac/ad5624r_spi.c +++ b/drivers/iio/dac/ad5624r_spi.c @@ -160,7 +160,7 @@ static const struct iio_chan_spec_ext_info ad5624r_ext_info[] = { IIO_ENUM("powerdown_mode", IIO_SHARED_BY_TYPE, &ad5624r_powerdown_mode_enum), IIO_ENUM_AVAILABLE("powerdown_mode", IIO_SHARED_BY_TYPE, &ad5624r_powerdown_mode_enum), - { }, + { } }; #define AD5624R_CHANNEL(_chan, _bits) { \ @@ -266,7 +266,7 @@ static const struct spi_device_id ad5624r_id[] = { {"ad5624r5", ID_AD5624R5}, {"ad5644r5", ID_AD5644R5}, {"ad5664r5", ID_AD5664R5}, - {} + { } }; MODULE_DEVICE_TABLE(spi, ad5624r_id); diff --git a/drivers/iio/dac/ad5686-spi.c b/drivers/iio/dac/ad5686-spi.c index 9c727aa6ea18..df8619e0c092 100644 --- a/drivers/iio/dac/ad5686-spi.c +++ b/drivers/iio/dac/ad5686-spi.c @@ -112,7 +112,7 @@ static const struct spi_device_id ad5686_spi_id[] = { {"ad5685r", ID_AD5685R}, {"ad5686", ID_AD5686}, {"ad5686r", ID_AD5686R}, - {} + { } }; MODULE_DEVICE_TABLE(spi, ad5686_spi_id); diff --git a/drivers/iio/dac/ad5686.c b/drivers/iio/dac/ad5686.c index 763af690c444..d9cae9555e5d 100644 --- a/drivers/iio/dac/ad5686.c +++ b/drivers/iio/dac/ad5686.c @@ -185,7 +185,7 @@ static const struct iio_chan_spec_ext_info ad5686_ext_info[] = { }, IIO_ENUM("powerdown_mode", IIO_SEPARATE, &ad5686_powerdown_mode_enum), IIO_ENUM_AVAILABLE("powerdown_mode", IIO_SHARED_BY_TYPE, &ad5686_powerdown_mode_enum), - { }, + { } }; #define AD5868_CHANNEL(chan, addr, bits, _shift) { \ diff --git a/drivers/iio/dac/ad5696-i2c.c b/drivers/iio/dac/ad5696-i2c.c index 0156f32c12c8..d3327bca0e07 100644 --- a/drivers/iio/dac/ad5696-i2c.c +++ b/drivers/iio/dac/ad5696-i2c.c @@ -82,7 +82,7 @@ static const struct i2c_device_id ad5686_i2c_id[] = { {"ad5695r", ID_AD5695R}, {"ad5696", ID_AD5696}, {"ad5696r", ID_AD5696R}, - {} + { } }; MODULE_DEVICE_TABLE(i2c, ad5686_i2c_id); @@ -101,7 +101,7 @@ static const struct of_device_id ad5686_of_match[] = { { .compatible = "adi,ad5695r" }, { .compatible = "adi,ad5696" }, { .compatible = "adi,ad5696r" }, - {} + { } }; MODULE_DEVICE_TABLE(of, ad5686_of_match); diff --git a/drivers/iio/dac/ad5755.c b/drivers/iio/dac/ad5755.c index 05e80b6ae2cc..d0e5f35462b1 100644 --- a/drivers/iio/dac/ad5755.c +++ b/drivers/iio/dac/ad5755.c @@ -522,7 +522,7 @@ static const struct iio_chan_spec_ext_info ad5755_ext_info[] = { .write = ad5755_write_powerdown, .shared = IIO_SEPARATE, }, - { }, + { } }; #define AD5755_CHANNEL(_bits) { \ @@ -853,7 +853,7 @@ static const struct spi_device_id ad5755_id[] = { { "ad5757", (kernel_ulong_t)&ad5755_chip_info_tbl[ID_AD5757] }, { "ad5735", (kernel_ulong_t)&ad5755_chip_info_tbl[ID_AD5735] }, { "ad5737", (kernel_ulong_t)&ad5755_chip_info_tbl[ID_AD5737] }, - {} + { } }; MODULE_DEVICE_TABLE(spi, ad5755_id); diff --git a/drivers/iio/dac/ad5758.c b/drivers/iio/dac/ad5758.c index 98771e37a7b5..4ed4fda76ea9 100644 --- a/drivers/iio/dac/ad5758.c +++ b/drivers/iio/dac/ad5758.c @@ -878,7 +878,7 @@ static int ad5758_probe(struct spi_device *spi) static const struct spi_device_id ad5758_id[] = { { "ad5758", 0 }, - {} + { } }; MODULE_DEVICE_TABLE(spi, ad5758_id); diff --git a/drivers/iio/dac/ad5761.c b/drivers/iio/dac/ad5761.c index 0aa5ba7f4654..b5d20f04f070 100644 --- a/drivers/iio/dac/ad5761.c +++ b/drivers/iio/dac/ad5761.c @@ -137,13 +137,11 @@ static int _ad5761_spi_read(struct ad5761_state *st, u8 addr, u16 *val) struct spi_transfer xfers[] = { { .tx_buf = &st->data[0].d8[1], - .bits_per_word = 8, .len = 3, .cs_change = true, }, { .tx_buf = &st->data[1].d8[1], .rx_buf = &st->data[2].d8[1], - .bits_per_word = 8, .len = 3, }, }; @@ -348,7 +346,7 @@ static const struct spi_device_id ad5761_id[] = { {"ad5721r", ID_AD5721R}, {"ad5761", ID_AD5761}, {"ad5761r", ID_AD5761R}, - {} + { } }; MODULE_DEVICE_TABLE(spi, ad5761_id); diff --git a/drivers/iio/dac/ad5766.c b/drivers/iio/dac/ad5766.c index f658ac8086aa..f6a0a0d84fef 100644 --- a/drivers/iio/dac/ad5766.c +++ b/drivers/iio/dac/ad5766.c @@ -148,13 +148,11 @@ static int __ad5766_spi_read(struct ad5766_state *st, u8 dac, int *val) struct spi_transfer xfers[] = { { .tx_buf = &st->data[0].d32, - .bits_per_word = 8, .len = 3, .cs_change = 1, }, { .tx_buf = &st->data[1].d32, .rx_buf = &st->data[2].d32, - .bits_per_word = 8, .len = 3, }, }; @@ -437,7 +435,7 @@ static const struct iio_chan_spec_ext_info ad5766_ext_info[] = { IIO_ENUM("dither_scale", IIO_SEPARATE, &ad5766_dither_scale_enum), IIO_ENUM_AVAILABLE("dither_scale", IIO_SEPARATE, &ad5766_dither_scale_enum), - {} + { } }; #define AD576x_CHANNEL(_chan, _bits) { \ @@ -648,14 +646,14 @@ static int ad5766_probe(struct spi_device *spi) static const struct of_device_id ad5766_dt_match[] = { { .compatible = "adi,ad5766" }, { .compatible = "adi,ad5767" }, - {} + { } }; MODULE_DEVICE_TABLE(of, ad5766_dt_match); static const struct spi_device_id ad5766_spi_ids[] = { { "ad5766", ID_AD5766 }, { "ad5767", ID_AD5767 }, - {} + { } }; MODULE_DEVICE_TABLE(spi, ad5766_spi_ids); diff --git a/drivers/iio/dac/ad5770r.c b/drivers/iio/dac/ad5770r.c index 25cf11d0471b..6eb4027a44fb 100644 --- a/drivers/iio/dac/ad5770r.c +++ b/drivers/iio/dac/ad5770r.c @@ -637,13 +637,13 @@ static int ad5770r_probe(struct spi_device *spi) static const struct of_device_id ad5770r_of_id[] = { { .compatible = "adi,ad5770r", }, - {}, + { } }; MODULE_DEVICE_TABLE(of, ad5770r_of_id); static const struct spi_device_id ad5770r_id[] = { { "ad5770r", 0 }, - {}, + { } }; MODULE_DEVICE_TABLE(spi, ad5770r_id); diff --git a/drivers/iio/dac/ad5791.c b/drivers/iio/dac/ad5791.c index 07848be3f8d5..41582f2b90fb 100644 --- a/drivers/iio/dac/ad5791.c +++ b/drivers/iio/dac/ad5791.c @@ -138,13 +138,11 @@ static int ad5791_spi_read(struct ad5791_state *st, u8 addr, u32 *val) struct spi_transfer xfers[] = { { .tx_buf = &st->data[0].d8[1], - .bits_per_word = 8, .len = 3, .cs_change = 1, }, { .tx_buf = &st->data[1].d8[1], .rx_buf = &st->data[2].d8[1], - .bits_per_word = 8, .len = 3, }, }; @@ -312,7 +310,7 @@ static const struct iio_chan_spec_ext_info ad5791_ext_info[] = { IIO_ENUM("powerdown_mode", IIO_SHARED_BY_TYPE, &ad5791_powerdown_mode_enum), IIO_ENUM_AVAILABLE("powerdown_mode", IIO_SHARED_BY_TYPE, &ad5791_powerdown_mode_enum), - { }, + { } }; #define AD5791_DEFINE_CHIP_INFO(_name, bits, _shift, _lin_comp) \ diff --git a/drivers/iio/dac/ad7293.c b/drivers/iio/dac/ad7293.c index d3f49b5337d2..c3797e40cdd9 100644 --- a/drivers/iio/dac/ad7293.c +++ b/drivers/iio/dac/ad7293.c @@ -114,6 +114,7 @@ #define AD7293_REG_DATA_RAW_MSK GENMASK(15, 4) #define AD7293_REG_VINX_RANGE_GET_CH_MSK(x, ch) (((x) >> (ch)) & 0x1) #define AD7293_REG_VINX_RANGE_SET_CH_MSK(x, ch) (((x) & 0x1) << (ch)) +#define AD7293_GENERAL_ADC_REF_MSK BIT(7) #define AD7293_CHIP_ID 0x18 enum ad7293_ch_type { @@ -141,6 +142,7 @@ struct ad7293_state { /* Protect against concurrent accesses to the device, page selection and data content */ struct mutex lock; struct gpio_desc *gpio_reset; + bool vrefin_en; u8 page_select; u8 data[3] __aligned(IIO_DMA_MINALIGN); }; @@ -785,6 +787,12 @@ static int ad7293_properties_parse(struct ad7293_state *st) if (ret) return dev_err_probe(&spi->dev, ret, "failed to enable VDRIVE\n"); + ret = devm_regulator_get_enable_optional(&spi->dev, "vrefin"); + if (ret < 0 && ret != -ENODEV) + return dev_err_probe(&spi->dev, ret, "failed to enable VREFIN\n"); + + st->vrefin_en = ret != -ENODEV; + st->gpio_reset = devm_gpiod_get_optional(&st->spi->dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR(st->gpio_reset)) @@ -818,6 +826,11 @@ static int ad7293_init(struct ad7293_state *st) return -EINVAL; } + if (!st->vrefin_en) + return __ad7293_spi_update_bits(st, AD7293_REG_GENERAL, + AD7293_GENERAL_ADC_REF_MSK, + AD7293_GENERAL_ADC_REF_MSK); + return 0; } @@ -859,13 +872,13 @@ static int ad7293_probe(struct spi_device *spi) static const struct spi_device_id ad7293_id[] = { { "ad7293", 0 }, - {} + { } }; MODULE_DEVICE_TABLE(spi, ad7293_id); static const struct of_device_id ad7293_of_match[] = { { .compatible = "adi,ad7293" }, - {} + { } }; MODULE_DEVICE_TABLE(of, ad7293_of_match); diff --git a/drivers/iio/dac/ad7303.c b/drivers/iio/dac/ad7303.c index bff6bf697d9c..a88cc639047d 100644 --- a/drivers/iio/dac/ad7303.c +++ b/drivers/iio/dac/ad7303.c @@ -173,7 +173,7 @@ static const struct iio_chan_spec_ext_info ad7303_ext_info[] = { .write = ad7303_write_dac_powerdown, .shared = IIO_SEPARATE, }, - { }, + { } }; #define AD7303_CHANNEL(chan) { \ @@ -264,13 +264,13 @@ static int ad7303_probe(struct spi_device *spi) static const struct of_device_id ad7303_spi_of_match[] = { { .compatible = "adi,ad7303", }, - { /* sentinel */ }, + { } }; MODULE_DEVICE_TABLE(of, ad7303_spi_of_match); static const struct spi_device_id ad7303_spi_ids[] = { { "ad7303", 0 }, - {} + { } }; MODULE_DEVICE_TABLE(spi, ad7303_spi_ids); diff --git a/drivers/iio/dac/ad8801.c b/drivers/iio/dac/ad8801.c index 8a362fae2eca..60e663af1cc1 100644 --- a/drivers/iio/dac/ad8801.c +++ b/drivers/iio/dac/ad8801.c @@ -153,7 +153,7 @@ static int ad8801_probe(struct spi_device *spi) static const struct spi_device_id ad8801_ids[] = { {"ad8801", ID_AD8801}, {"ad8803", ID_AD8803}, - {} + { } }; MODULE_DEVICE_TABLE(spi, ad8801_ids); diff --git a/drivers/iio/dac/ad9739a.c b/drivers/iio/dac/ad9739a.c index b6a65359b0b4..d77b46d83bd4 100644 --- a/drivers/iio/dac/ad9739a.c +++ b/drivers/iio/dac/ad9739a.c @@ -442,13 +442,13 @@ static int ad9739a_probe(struct spi_device *spi) static const struct of_device_id ad9739a_of_match[] = { { .compatible = "adi,ad9739a" }, - {} + { } }; MODULE_DEVICE_TABLE(of, ad9739a_of_match); static const struct spi_device_id ad9739a_id[] = { {"ad9739a"}, - {} + { } }; MODULE_DEVICE_TABLE(spi, ad9739a_id); diff --git a/drivers/iio/dac/adi-axi-dac.c b/drivers/iio/dac/adi-axi-dac.c index 892d770aec69..33faba4b02c2 100644 --- a/drivers/iio/dac/adi-axi-dac.c +++ b/drivers/iio/dac/adi-axi-dac.c @@ -84,6 +84,7 @@ #define AXI_DAC_CHAN_CNTRL_7_REG(c) (0x0418 + (c) * 0x40) #define AXI_DAC_CHAN_CNTRL_7_DATA_SEL GENMASK(3, 0) +#define AXI_DAC_CHAN_CNTRL_MAX 15 #define AXI_DAC_RD_ADDR(x) (BIT(7) | (x)) /* 360 degrees in rad */ @@ -186,6 +187,9 @@ static int __axi_dac_frequency_get(struct axi_dac_state *st, unsigned int chan, u32 reg, raw; int ret; + if (chan > AXI_DAC_CHAN_CNTRL_MAX) + return -EINVAL; + if (!st->dac_clk) { dev_err(st->dev, "Sampling rate is 0...\n"); return -EINVAL; @@ -230,6 +234,9 @@ static int axi_dac_scale_get(struct axi_dac_state *st, int ret, vals[2]; u32 reg, raw; + if (chan->channel > AXI_DAC_CHAN_CNTRL_MAX) + return -EINVAL; + if (tone_2) reg = AXI_DAC_CHAN_CNTRL_3_REG(chan->channel); else @@ -264,6 +271,9 @@ static int axi_dac_phase_get(struct axi_dac_state *st, u32 reg, raw, phase; int ret, vals[2]; + if (chan->channel > AXI_DAC_CHAN_CNTRL_MAX) + return -EINVAL; + if (tone_2) reg = AXI_DAC_CHAN_CNTRL_4_REG(chan->channel); else @@ -291,6 +301,9 @@ static int __axi_dac_frequency_set(struct axi_dac_state *st, unsigned int chan, u16 raw; int ret; + if (chan > AXI_DAC_CHAN_CNTRL_MAX) + return -EINVAL; + if (!sample_rate || freq > sample_rate / 2) { dev_err(st->dev, "Invalid frequency(%u) dac_clk(%llu)\n", freq, sample_rate); @@ -342,6 +355,9 @@ static int axi_dac_scale_set(struct axi_dac_state *st, u32 raw = 0, reg; int ret; + if (chan->channel > AXI_DAC_CHAN_CNTRL_MAX) + return -EINVAL; + ret = iio_str_to_fixpoint(buf, 100000, &integer, &frac); if (ret) return ret; @@ -385,6 +401,9 @@ static int axi_dac_phase_set(struct axi_dac_state *st, u32 raw, reg; int ret; + if (chan->channel > AXI_DAC_CHAN_CNTRL_MAX) + return -EINVAL; + ret = iio_str_to_fixpoint(buf, 100000, &integer, &frac); if (ret) return ret; @@ -469,7 +488,7 @@ static const struct iio_chan_spec_ext_info axi_dac_ext_info[] = { IIO_BACKEND_EX_INFO("scale1", IIO_SEPARATE, AXI_DAC_SCALE_TONE_2), IIO_BACKEND_EX_INFO("phase0", IIO_SEPARATE, AXI_DAC_PHASE_TONE_1), IIO_BACKEND_EX_INFO("phase1", IIO_SEPARATE, AXI_DAC_PHASE_TONE_2), - {} + { } }; static int axi_dac_extend_chan(struct iio_backend *back, @@ -493,6 +512,9 @@ static int axi_dac_data_source_set(struct iio_backend *back, unsigned int chan, { struct axi_dac_state *st = iio_backend_get_priv(back); + if (chan > AXI_DAC_CHAN_CNTRL_MAX) + return -EINVAL; + switch (data) { case IIO_BACKEND_INTERNAL_CONTINUOUS_WAVE: return regmap_update_bits(st->regmap, @@ -514,6 +536,35 @@ static int axi_dac_data_source_set(struct iio_backend *back, unsigned int chan, } } +static int axi_dac_data_source_get(struct iio_backend *back, unsigned int chan, + enum iio_backend_data_source *data) +{ + struct axi_dac_state *st = iio_backend_get_priv(back); + int ret; + u32 val; + + if (chan > AXI_DAC_CHAN_CNTRL_MAX) + return -EINVAL; + + ret = regmap_read(st->regmap, AXI_DAC_CHAN_CNTRL_7_REG(chan), &val); + if (ret) + return ret; + + switch (val) { + case AXI_DAC_DATA_INTERNAL_TONE: + *data = IIO_BACKEND_INTERNAL_CONTINUOUS_WAVE; + return 0; + case AXI_DAC_DATA_DMA: + *data = IIO_BACKEND_EXTERNAL; + return 0; + case AXI_DAC_DATA_INTERNAL_RAMP_16BIT: + *data = IIO_BACKEND_INTERNAL_RAMP_16BIT; + return 0; + default: + return -EIO; + } +} + static int axi_dac_set_sample_rate(struct iio_backend *back, unsigned int chan, u64 sample_rate) { @@ -521,6 +572,8 @@ static int axi_dac_set_sample_rate(struct iio_backend *back, unsigned int chan, unsigned int freq; int ret, tone; + if (chan > AXI_DAC_CHAN_CNTRL_MAX) + return -EINVAL; if (!sample_rate) return -EINVAL; if (st->reg_config & AXI_DAC_CONFIG_DDS_DISABLE) @@ -707,6 +760,7 @@ static int axi_dac_bus_reg_read(struct iio_backend *back, u32 reg, u32 *val, { struct axi_dac_state *st = iio_backend_get_priv(back); int ret; + u32 ival; guard(mutex)(&st->lock); @@ -719,6 +773,13 @@ static int axi_dac_bus_reg_read(struct iio_backend *back, u32 reg, u32 *val, if (ret) return ret; + ret = regmap_read_poll_timeout(st->regmap, + AXI_DAC_UI_STATUS_REG, ival, + FIELD_GET(AXI_DAC_UI_STATUS_IF_BUSY, ival) == 0, + 10, 100 * KILO); + if (ret) + return ret; + return regmap_read(st->regmap, AXI_DAC_CUSTOM_RD_REG, val); } @@ -794,6 +855,7 @@ static const struct iio_backend_ops axi_ad3552r_ops = { .request_buffer = axi_dac_request_buffer, .free_buffer = axi_dac_free_buffer, .data_source_set = axi_dac_data_source_set, + .data_source_get = axi_dac_data_source_get, .ddr_enable = axi_dac_ddr_enable, .ddr_disable = axi_dac_ddr_disable, .data_stream_enable = axi_dac_data_stream_enable, @@ -961,7 +1023,7 @@ static const struct axi_dac_info dac_ad3552r = { static const struct of_device_id axi_dac_of_match[] = { { .compatible = "adi,axi-dac-9.1.b", .data = &dac_generic }, { .compatible = "adi,axi-ad3552r", .data = &dac_ad3552r }, - {} + { } }; MODULE_DEVICE_TABLE(of, axi_dac_of_match); diff --git a/drivers/iio/dac/dpot-dac.c b/drivers/iio/dac/dpot-dac.c index f36f10bfb6be..d1b8441051ae 100644 --- a/drivers/iio/dac/dpot-dac.c +++ b/drivers/iio/dac/dpot-dac.c @@ -237,7 +237,7 @@ static void dpot_dac_remove(struct platform_device *pdev) static const struct of_device_id dpot_dac_match[] = { { .compatible = "dpot-dac" }, - { /* sentinel */ } + { } }; MODULE_DEVICE_TABLE(of, dpot_dac_match); diff --git a/drivers/iio/dac/ds4424.c b/drivers/iio/dac/ds4424.c index e89e4c054653..a26a99753418 100644 --- a/drivers/iio/dac/ds4424.c +++ b/drivers/iio/dac/ds4424.c @@ -301,7 +301,7 @@ MODULE_DEVICE_TABLE(i2c, ds4424_id); static const struct of_device_id ds4424_of_match[] = { { .compatible = "maxim,ds4422" }, { .compatible = "maxim,ds4424" }, - { }, + { } }; MODULE_DEVICE_TABLE(of, ds4424_of_match); diff --git a/drivers/iio/dac/lpc18xx_dac.c b/drivers/iio/dac/lpc18xx_dac.c index 2332b0c22691..aa1c73f8429d 100644 --- a/drivers/iio/dac/lpc18xx_dac.c +++ b/drivers/iio/dac/lpc18xx_dac.c @@ -179,7 +179,7 @@ static void lpc18xx_dac_remove(struct platform_device *pdev) static const struct of_device_id lpc18xx_dac_match[] = { { .compatible = "nxp,lpc1850-dac" }, - { /* sentinel */ } + { } }; MODULE_DEVICE_TABLE(of, lpc18xx_dac_match); diff --git a/drivers/iio/dac/ltc1660.c b/drivers/iio/dac/ltc1660.c index 2758fc8a5ad5..6e80b49f4665 100644 --- a/drivers/iio/dac/ltc1660.c +++ b/drivers/iio/dac/ltc1660.c @@ -219,14 +219,14 @@ static void ltc1660_remove(struct spi_device *spi) static const struct of_device_id ltc1660_dt_ids[] = { { .compatible = "lltc,ltc1660", .data = (void *)ID_LTC1660 }, { .compatible = "lltc,ltc1665", .data = (void *)ID_LTC1665 }, - { /* sentinel */ } + { } }; MODULE_DEVICE_TABLE(of, ltc1660_dt_ids); static const struct spi_device_id ltc1660_id[] = { {"ltc1660", ID_LTC1660}, {"ltc1665", ID_LTC1665}, - { /* sentinel */ } + { } }; MODULE_DEVICE_TABLE(spi, ltc1660_id); diff --git a/drivers/iio/dac/ltc2632.c b/drivers/iio/dac/ltc2632.c index 999348836d87..105f939f7e54 100644 --- a/drivers/iio/dac/ltc2632.c +++ b/drivers/iio/dac/ltc2632.c @@ -176,7 +176,7 @@ static const struct iio_chan_spec_ext_info ltc2632_ext_info[] = { .write = ltc2632_write_dac_powerdown, .shared = IIO_SEPARATE, }, - { }, + { } }; #define LTC2632_CHANNEL(_chan, _bits) { \ @@ -372,7 +372,7 @@ static const struct spi_device_id ltc2632_id[] = { { "ltc2636-h12", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2636H12] }, { "ltc2636-h10", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2636H10] }, { "ltc2636-h8", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2636H8] }, - {} + { } }; MODULE_DEVICE_TABLE(spi, ltc2632_id); @@ -432,7 +432,7 @@ static const struct of_device_id ltc2632_of_match[] = { .compatible = "lltc,ltc2636-h8", .data = <c2632_chip_info_tbl[ID_LTC2636H8] }, - {} + { } }; MODULE_DEVICE_TABLE(of, ltc2632_of_match); diff --git a/drivers/iio/dac/ltc2688.c b/drivers/iio/dac/ltc2688.c index bdc857c7fa6d..1f24f07d1ad2 100644 --- a/drivers/iio/dac/ltc2688.c +++ b/drivers/iio/dac/ltc2688.c @@ -104,13 +104,11 @@ static int ltc2688_spi_read(void *context, const void *reg, size_t reg_size, struct spi_transfer xfers[] = { { .tx_buf = st->tx_data, - .bits_per_word = 8, .len = reg_size + val_size, .cs_change = 1, }, { .tx_buf = st->tx_data + 3, .rx_buf = st->rx_data, - .bits_per_word = 8, .len = reg_size + val_size, }, }; @@ -608,7 +606,7 @@ static const struct iio_chan_spec_ext_info ltc2688_toggle_sym_ext_info[] = { ltc2688_reg_bool_get, ltc2688_reg_bool_set), LTC2688_CHAN_EXT_INFO("symbol", LTC2688_CMD_SW_TOGGLE, IIO_SEPARATE, ltc2688_reg_bool_get, ltc2688_reg_bool_set), - {} + { } }; static const struct iio_chan_spec_ext_info ltc2688_toggle_ext_info[] = { @@ -621,7 +619,7 @@ static const struct iio_chan_spec_ext_info ltc2688_toggle_ext_info[] = { ltc2688_dither_toggle_set), LTC2688_CHAN_EXT_INFO("powerdown", LTC2688_CMD_POWERDOWN, IIO_SEPARATE, ltc2688_reg_bool_get, ltc2688_reg_bool_set), - {} + { } }; static struct iio_chan_spec_ext_info ltc2688_dither_ext_info[] = { @@ -649,13 +647,13 @@ static struct iio_chan_spec_ext_info ltc2688_dither_ext_info[] = { ltc2688_dither_toggle_set), LTC2688_CHAN_EXT_INFO("powerdown", LTC2688_CMD_POWERDOWN, IIO_SEPARATE, ltc2688_reg_bool_get, ltc2688_reg_bool_set), - {} + { } }; static const struct iio_chan_spec_ext_info ltc2688_ext_info[] = { LTC2688_CHAN_EXT_INFO("powerdown", LTC2688_CMD_POWERDOWN, IIO_SEPARATE, ltc2688_reg_bool_get, ltc2688_reg_bool_set), - {} + { } }; #define LTC2688_CHANNEL(_chan) { \ @@ -991,13 +989,13 @@ static int ltc2688_probe(struct spi_device *spi) static const struct of_device_id ltc2688_of_id[] = { { .compatible = "adi,ltc2688" }, - {} + { } }; MODULE_DEVICE_TABLE(of, ltc2688_of_id); static const struct spi_device_id ltc2688_id[] = { { "ltc2688" }, - {} + { } }; MODULE_DEVICE_TABLE(spi, ltc2688_id); diff --git a/drivers/iio/dac/max5522.c b/drivers/iio/dac/max5522.c index 9f72155dcbc7..1b8fe6b8d26e 100644 --- a/drivers/iio/dac/max5522.c +++ b/drivers/iio/dac/max5522.c @@ -174,7 +174,7 @@ static int max5522_spi_probe(struct spi_device *spi) static const struct spi_device_id max5522_ids[] = { { "max5522", (kernel_ulong_t)&max5522_chip_info_tbl[ID_MAX5522] }, - {} + { } }; MODULE_DEVICE_TABLE(spi, max5522_ids); @@ -183,7 +183,7 @@ static const struct of_device_id max5522_of_match[] = { .compatible = "maxim,max5522", .data = &max5522_chip_info_tbl[ID_MAX5522], }, - {} + { } }; MODULE_DEVICE_TABLE(of, max5522_of_match); diff --git a/drivers/iio/dac/max5821.c b/drivers/iio/dac/max5821.c index b062a18be5e7..e7e29359f8fe 100644 --- a/drivers/iio/dac/max5821.c +++ b/drivers/iio/dac/max5821.c @@ -137,7 +137,7 @@ static const struct iio_chan_spec_ext_info max5821_ext_info[] = { }, IIO_ENUM("powerdown_mode", IIO_SEPARATE, &max5821_powerdown_mode_enum), IIO_ENUM_AVAILABLE("powerdown_mode", IIO_SHARED_BY_TYPE, &max5821_powerdown_mode_enum), - { }, + { } }; #define MAX5821_CHANNEL(chan) { \ diff --git a/drivers/iio/dac/mcp4725.c b/drivers/iio/dac/mcp4725.c index 1337fb02ccf5..62972494a229 100644 --- a/drivers/iio/dac/mcp4725.c +++ b/drivers/iio/dac/mcp4725.c @@ -241,7 +241,7 @@ static const struct iio_chan_spec_ext_info mcp4725_ext_info[] = { &mcp472x_powerdown_mode_enum[MCP4725]), IIO_ENUM_AVAILABLE("powerdown_mode", IIO_SHARED_BY_TYPE, &mcp472x_powerdown_mode_enum[MCP4725]), - { }, + { } }; static const struct iio_chan_spec_ext_info mcp4726_ext_info[] = { @@ -255,7 +255,7 @@ static const struct iio_chan_spec_ext_info mcp4726_ext_info[] = { &mcp472x_powerdown_mode_enum[MCP4726]), IIO_ENUM_AVAILABLE("powerdown_mode", IIO_SHARED_BY_TYPE, &mcp472x_powerdown_mode_enum[MCP4726]), - { }, + { } }; static const struct iio_chan_spec mcp472x_channel[] = { diff --git a/drivers/iio/dac/mcp4728.c b/drivers/iio/dac/mcp4728.c index 192175dc6419..4f30b99110b7 100644 --- a/drivers/iio/dac/mcp4728.c +++ b/drivers/iio/dac/mcp4728.c @@ -286,7 +286,7 @@ static const struct iio_chan_spec_ext_info mcp4728_ext_info[] = { IIO_ENUM("powerdown_mode", IIO_SEPARATE, &mcp4728_powerdown_mode_enum), IIO_ENUM_AVAILABLE("powerdown_mode", IIO_SHARED_BY_TYPE, &mcp4728_powerdown_mode_enum), - {}, + { } }; static const struct iio_chan_spec mcp4728_channels[MCP4728_N_CHANNELS] = { @@ -573,13 +573,13 @@ static int mcp4728_probe(struct i2c_client *client) static const struct i2c_device_id mcp4728_id[] = { { "mcp4728" }, - {} + { } }; MODULE_DEVICE_TABLE(i2c, mcp4728_id); static const struct of_device_id mcp4728_of_match[] = { { .compatible = "microchip,mcp4728" }, - {} + { } }; MODULE_DEVICE_TABLE(of, mcp4728_of_match); diff --git a/drivers/iio/dac/mcp4821.c b/drivers/iio/dac/mcp4821.c index c1a59bbbba3c..748bdca9a964 100644 --- a/drivers/iio/dac/mcp4821.c +++ b/drivers/iio/dac/mcp4821.c @@ -206,7 +206,7 @@ static const struct of_device_id mcp4821_of_table[] = { MCP4821_COMPATIBLE("microchip,mcp4812", ID_MCP4812), MCP4821_COMPATIBLE("microchip,mcp4821", ID_MCP4821), MCP4821_COMPATIBLE("microchip,mcp4822", ID_MCP4822), - { /* Sentinel */ } + { } }; MODULE_DEVICE_TABLE(of, mcp4821_of_table); @@ -217,7 +217,7 @@ static const struct spi_device_id mcp4821_id_table[] = { { "mcp4812", (kernel_ulong_t)&mcp4821_chip_info_table[ID_MCP4812]}, { "mcp4821", (kernel_ulong_t)&mcp4821_chip_info_table[ID_MCP4821]}, { "mcp4822", (kernel_ulong_t)&mcp4821_chip_info_table[ID_MCP4822]}, - { /* Sentinel */ } + { } }; MODULE_DEVICE_TABLE(spi, mcp4821_id_table); diff --git a/drivers/iio/dac/mcp4922.c b/drivers/iio/dac/mcp4922.c index 26aa99059813..74f338afcab9 100644 --- a/drivers/iio/dac/mcp4922.c +++ b/drivers/iio/dac/mcp4922.c @@ -161,7 +161,7 @@ static const struct spi_device_id mcp4922_id[] = { {"mcp4912", ID_MCP4912}, {"mcp4921", ID_MCP4921}, {"mcp4922", ID_MCP4922}, - {} + { } }; MODULE_DEVICE_TABLE(spi, mcp4922_id); diff --git a/drivers/iio/dac/rohm-bd79703.c b/drivers/iio/dac/rohm-bd79703.c index e998ab51052e..a35c37d2261d 100644 --- a/drivers/iio/dac/rohm-bd79703.c +++ b/drivers/iio/dac/rohm-bd79703.c @@ -38,11 +38,20 @@ static const struct regmap_config bd79703_regmap_config = { .cache_type = REGCACHE_RBTREE, }; +/* Dynamic driver private data */ struct bd79703_data { struct regmap *regmap; int vfs; }; +/* Static, IC type specific data for different variants */ +struct bd7970x_chip_data { + const char *name; + const struct iio_chan_spec *channels; + int num_channels; + bool has_vfs; +}; + static int bd79703_read_raw(struct iio_dev *idev, struct iio_chan_spec const *chan, int *val, int *val2, long mask) @@ -67,7 +76,7 @@ static int bd79703_write_raw(struct iio_dev *idev, if (val < 0 || val >= 1 << BD79703_DAC_BITS) return -EINVAL; - return regmap_write(data->regmap, chan->channel + 1, val); + return regmap_write(data->regmap, chan->address, val); }; static const struct iio_info bd79703_info = { @@ -75,16 +84,42 @@ static const struct iio_info bd79703_info = { .write_raw = bd79703_write_raw, }; -#define BD79703_CHAN(_chan) { \ +#define BD79703_CHAN_ADDR(_chan, _addr) { \ .type = IIO_VOLTAGE, \ .indexed = 1, \ .output = 1, \ .channel = (_chan), \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ - .address = (_chan), \ + .address = (_addr), \ } +#define BD79703_CHAN(_chan) BD79703_CHAN_ADDR((_chan), (_chan) + 1) + +static const struct iio_chan_spec bd79700_channels[] = { + BD79703_CHAN(0), + BD79703_CHAN(1), +}; + +static const struct iio_chan_spec bd79701_channels[] = { + BD79703_CHAN(0), + BD79703_CHAN(1), + BD79703_CHAN(2), +}; + +/* + * The BD79702 has 4 channels. They aren't mapped to BD79703 channels 0, 1, 2 + * and 3, but to the channels 0, 1, 4, 5. So the addressing used with SPI + * accesses is 1, 2, 5 and 6 for them. Thus, they're not constant offset to + * the channel number as with other IC variants. + */ +static const struct iio_chan_spec bd79702_channels[] = { + BD79703_CHAN_ADDR(0, 1), + BD79703_CHAN_ADDR(1, 2), + BD79703_CHAN_ADDR(2, 5), + BD79703_CHAN_ADDR(3, 6), +}; + static const struct iio_chan_spec bd79703_channels[] = { BD79703_CHAN(0), BD79703_CHAN(1), @@ -94,13 +129,46 @@ static const struct iio_chan_spec bd79703_channels[] = { BD79703_CHAN(5), }; +static const struct bd7970x_chip_data bd79700_chip_data = { + .name = "bd79700", + .channels = bd79700_channels, + .num_channels = ARRAY_SIZE(bd79700_channels), + .has_vfs = false, +}; + +static const struct bd7970x_chip_data bd79701_chip_data = { + .name = "bd79701", + .channels = bd79701_channels, + .num_channels = ARRAY_SIZE(bd79701_channels), + .has_vfs = false, +}; + +static const struct bd7970x_chip_data bd79702_chip_data = { + .name = "bd79702", + .channels = bd79702_channels, + .num_channels = ARRAY_SIZE(bd79702_channels), + .has_vfs = true, +}; + +static const struct bd7970x_chip_data bd79703_chip_data = { + .name = "bd79703", + .channels = bd79703_channels, + .num_channels = ARRAY_SIZE(bd79703_channels), + .has_vfs = true, +}; + static int bd79703_probe(struct spi_device *spi) { + const struct bd7970x_chip_data *cd; struct device *dev = &spi->dev; struct bd79703_data *data; struct iio_dev *idev; int ret; + cd = spi_get_device_match_data(spi); + if (!cd) + return -ENODEV; + idev = devm_iio_device_alloc(dev, sizeof(*data)); if (!idev) return -ENOMEM; @@ -112,20 +180,30 @@ static int bd79703_probe(struct spi_device *spi) return dev_err_probe(dev, PTR_ERR(data->regmap), "Failed to initialize Regmap\n"); - ret = devm_regulator_get_enable(dev, "vcc"); - if (ret) - return dev_err_probe(dev, ret, "Failed to enable VCC\n"); - - ret = devm_regulator_get_enable_read_voltage(dev, "vfs"); - if (ret < 0) - return dev_err_probe(dev, ret, "Failed to get Vfs\n"); - + /* + * BD79703 has a separate VFS pin, whereas the BD79700 and BD79701 use + * VCC for their full-scale output voltage. + */ + if (cd->has_vfs) { + ret = devm_regulator_get_enable(dev, "vcc"); + if (ret) + return dev_err_probe(dev, ret, "Failed to enable VCC\n"); + + ret = devm_regulator_get_enable_read_voltage(dev, "vfs"); + if (ret < 0) + return dev_err_probe(dev, ret, "Failed to get Vfs\n"); + } else { + ret = devm_regulator_get_enable_read_voltage(dev, "vcc"); + if (ret < 0) + return dev_err_probe(dev, ret, "Failed to get VCC\n"); + } data->vfs = ret; - idev->channels = bd79703_channels; - idev->num_channels = ARRAY_SIZE(bd79703_channels); + + idev->channels = cd->channels; + idev->num_channels = cd->num_channels; idev->modes = INDIO_DIRECT_MODE; idev->info = &bd79703_info; - idev->name = "bd79703"; + idev->name = cd->name; /* Initialize all to output zero */ ret = regmap_write(data->regmap, BD79703_REG_OUT_ALL, 0); @@ -136,13 +214,19 @@ static int bd79703_probe(struct spi_device *spi) } static const struct spi_device_id bd79703_id[] = { - { "bd79703", }, + { "bd79700", (kernel_ulong_t)&bd79700_chip_data }, + { "bd79701", (kernel_ulong_t)&bd79701_chip_data }, + { "bd79702", (kernel_ulong_t)&bd79702_chip_data }, + { "bd79703", (kernel_ulong_t)&bd79703_chip_data }, { } }; MODULE_DEVICE_TABLE(spi, bd79703_id); static const struct of_device_id bd79703_of_match[] = { - { .compatible = "rohm,bd79703", }, + { .compatible = "rohm,bd79700", .data = &bd79700_chip_data }, + { .compatible = "rohm,bd79701", .data = &bd79701_chip_data }, + { .compatible = "rohm,bd79702", .data = &bd79702_chip_data }, + { .compatible = "rohm,bd79703", .data = &bd79703_chip_data }, { } }; MODULE_DEVICE_TABLE(of, bd79703_of_match); diff --git a/drivers/iio/dac/stm32-dac-core.c b/drivers/iio/dac/stm32-dac-core.c index 95ed5197d16f..8ef702917060 100644 --- a/drivers/iio/dac/stm32-dac-core.c +++ b/drivers/iio/dac/stm32-dac-core.c @@ -239,7 +239,7 @@ static const struct of_device_id stm32_dac_of_match[] = { .compatible = "st,stm32h7-dac-core", .data = (void *)&stm32h7_dac_cfg, }, - {}, + { } }; MODULE_DEVICE_TABLE(of, stm32_dac_of_match); diff --git a/drivers/iio/dac/stm32-dac.c b/drivers/iio/dac/stm32-dac.c index 3bfb368b3a23..344388338d9b 100644 --- a/drivers/iio/dac/stm32-dac.c +++ b/drivers/iio/dac/stm32-dac.c @@ -250,7 +250,7 @@ static const struct iio_chan_spec_ext_info stm32_dac_ext_info[] = { }, IIO_ENUM("powerdown_mode", IIO_SEPARATE, &stm32_dac_powerdown_mode_en), IIO_ENUM_AVAILABLE("powerdown_mode", IIO_SHARED_BY_TYPE, &stm32_dac_powerdown_mode_en), - {}, + { } }; #define STM32_DAC_CHANNEL(chan, name) { \ @@ -392,7 +392,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(stm32_dac_pm_ops, stm32_dac_suspend, static const struct of_device_id stm32_dac_of_match[] = { { .compatible = "st,stm32-dac", }, - {}, + { } }; MODULE_DEVICE_TABLE(of, stm32_dac_of_match); diff --git a/drivers/iio/dac/ti-dac082s085.c b/drivers/iio/dac/ti-dac082s085.c index 8e1590e3cc8b..715870c8a9c4 100644 --- a/drivers/iio/dac/ti-dac082s085.c +++ b/drivers/iio/dac/ti-dac082s085.c @@ -161,7 +161,7 @@ static const struct iio_chan_spec_ext_info ti_dac_ext_info[] = { }, IIO_ENUM("powerdown_mode", IIO_SHARED_BY_TYPE, &ti_dac_powerdown_mode), IIO_ENUM_AVAILABLE("powerdown_mode", IIO_SHARED_BY_TYPE, &ti_dac_powerdown_mode), - { }, + { } }; #define TI_DAC_CHANNEL(chan) { \ diff --git a/drivers/iio/dac/ti-dac5571.c b/drivers/iio/dac/ti-dac5571.c index c5162b72951a..bdc3f94aef98 100644 --- a/drivers/iio/dac/ti-dac5571.c +++ b/drivers/iio/dac/ti-dac5571.c @@ -216,7 +216,7 @@ static const struct iio_chan_spec_ext_info dac5571_ext_info[] = { }, IIO_ENUM("powerdown_mode", IIO_SEPARATE, &dac5571_powerdown_mode), IIO_ENUM_AVAILABLE("powerdown_mode", IIO_SHARED_BY_TYPE, &dac5571_powerdown_mode), - {}, + { } }; #define dac5571_CHANNEL(chan, name) { \ @@ -398,7 +398,7 @@ static const struct of_device_id dac5571_of_id[] = { {.compatible = "ti,dac5573", .data = &dac5571_spec[quad_8bit] }, {.compatible = "ti,dac6573", .data = &dac5571_spec[quad_10bit] }, {.compatible = "ti,dac7573", .data = &dac5571_spec[quad_12bit] }, - {} + { } }; MODULE_DEVICE_TABLE(of, dac5571_of_id); @@ -414,7 +414,7 @@ static const struct i2c_device_id dac5571_id[] = { {"dac5573", (kernel_ulong_t)&dac5571_spec[quad_8bit] }, {"dac6573", (kernel_ulong_t)&dac5571_spec[quad_10bit] }, {"dac7573", (kernel_ulong_t)&dac5571_spec[quad_12bit] }, - {} + { } }; MODULE_DEVICE_TABLE(i2c, dac5571_id); diff --git a/drivers/iio/dac/ti-dac7311.c b/drivers/iio/dac/ti-dac7311.c index 6f4aa4794a0c..3d2ce61f0db6 100644 --- a/drivers/iio/dac/ti-dac7311.c +++ b/drivers/iio/dac/ti-dac7311.c @@ -147,7 +147,7 @@ static const struct iio_chan_spec_ext_info ti_dac_ext_info[] = { }, IIO_ENUM("powerdown_mode", IIO_SHARED_BY_TYPE, &ti_dac_powerdown_mode), IIO_ENUM_AVAILABLE("powerdown_mode", IIO_SHARED_BY_TYPE, &ti_dac_powerdown_mode), - { }, + { } }; #define TI_DAC_CHANNEL(chan) { \ diff --git a/drivers/iio/dac/ti-dac7612.c b/drivers/iio/dac/ti-dac7612.c index 8195815de26f..c308eca02b88 100644 --- a/drivers/iio/dac/ti-dac7612.c +++ b/drivers/iio/dac/ti-dac7612.c @@ -166,7 +166,7 @@ static int dac7612_probe(struct spi_device *spi) static const struct spi_device_id dac7612_id[] = { {"ti-dac7612"}, - {} + { } }; MODULE_DEVICE_TABLE(spi, dac7612_id); @@ -174,7 +174,7 @@ static const struct of_device_id dac7612_of_match[] = { { .compatible = "ti,dac7612" }, { .compatible = "ti,dac7612u" }, { .compatible = "ti,dac7612ub" }, - { }, + { } }; MODULE_DEVICE_TABLE(of, dac7612_of_match); diff --git a/drivers/iio/dac/vf610_dac.c b/drivers/iio/dac/vf610_dac.c index 82a078fa98ad..b30ff7bb4400 100644 --- a/drivers/iio/dac/vf610_dac.c +++ b/drivers/iio/dac/vf610_dac.c @@ -99,7 +99,7 @@ static const struct iio_enum vf610_conversion_mode = { static const struct iio_chan_spec_ext_info vf610_ext_info[] = { IIO_ENUM("conversion_mode", IIO_SHARED_BY_DIR, &vf610_conversion_mode), - {}, + { } }; #define VF610_DAC_CHAN(_chan_type) { \ @@ -166,7 +166,7 @@ static const struct iio_info vf610_dac_iio_info = { static const struct of_device_id vf610_dac_match[] = { { .compatible = "fsl,vf610-dac", }, - { /* sentinel */ } + { } }; MODULE_DEVICE_TABLE(of, vf610_dac_match); diff --git a/drivers/iio/dummy/iio_simple_dummy_buffer.c b/drivers/iio/dummy/iio_simple_dummy_buffer.c index 288880346707..e35e0596cbfb 100644 --- a/drivers/iio/dummy/iio_simple_dummy_buffer.c +++ b/drivers/iio/dummy/iio_simple_dummy_buffer.c @@ -31,6 +31,11 @@ static const s16 fakedata[] = { [DUMMY_INDEX_ACCELX] = 344, }; +struct dummy_scan { + s16 data[ARRAY_SIZE(fakedata)]; + aligned_s64 timestamp; +}; + /** * iio_simple_dummy_trigger_h() - the trigger handler function * @irq: the interrupt number @@ -45,11 +50,18 @@ static irqreturn_t iio_simple_dummy_trigger_h(int irq, void *p) { struct iio_poll_func *pf = p; struct iio_dev *indio_dev = pf->indio_dev; + struct dummy_scan *scan; int i = 0, j; - u16 *data; - data = kzalloc(indio_dev->scan_bytes, GFP_KERNEL); - if (!data) + /* + * Note that some buses such as SPI require DMA safe buffers which + * cannot be on the stack. Two easy ways to do this: + * - Local kzalloc (as done here) + * - A buffer at the end of the structure accessed via iio_priv() + * that is marked __aligned(IIO_DMA_MINALIGN). + */ + scan = kzalloc(sizeof(*scan), GFP_KERNEL); + if (!scan) goto done; /* @@ -69,13 +81,12 @@ static irqreturn_t iio_simple_dummy_trigger_h(int irq, void *p) * constant table fakedata. */ iio_for_each_active_channel(indio_dev, j) - data[i++] = fakedata[j]; - - iio_push_to_buffers_with_timestamp(indio_dev, data, - iio_get_time_ns(indio_dev)); + scan->data[i++] = fakedata[j]; - kfree(data); + iio_push_to_buffers_with_ts(indio_dev, scan, sizeof(*scan), + iio_get_time_ns(indio_dev)); + kfree(scan); done: /* * Tell the core we are done with this trigger and ready for the diff --git a/drivers/iio/filter/admv8818.c b/drivers/iio/filter/admv8818.c index d85b7d3de866..19f823446cda 100644 --- a/drivers/iio/filter/admv8818.c +++ b/drivers/iio/filter/admv8818.c @@ -14,6 +14,7 @@ #include <linux/mod_devicetable.h> #include <linux/mutex.h> #include <linux/notifier.h> +#include <linux/property.h> #include <linux/regmap.h> #include <linux/spi/spi.h> #include <linux/units.h> @@ -70,6 +71,16 @@ #define ADMV8818_HPF_WR0_MSK GENMASK(7, 4) #define ADMV8818_LPF_WR0_MSK GENMASK(3, 0) +#define ADMV8818_BAND_BYPASS 0 +#define ADMV8818_BAND_MIN 1 +#define ADMV8818_BAND_MAX 4 +#define ADMV8818_BAND_CORNER_LOW 0 +#define ADMV8818_BAND_CORNER_HIGH 1 + +#define ADMV8818_STATE_MIN 0 +#define ADMV8818_STATE_MAX 15 +#define ADMV8818_NUM_STATES 16 + enum { ADMV8818_BW_FREQ, ADMV8818_CENTER_FREQ @@ -90,20 +101,24 @@ struct admv8818_state { struct mutex lock; unsigned int filter_mode; u64 cf_hz; + u64 lpf_margin_hz; + u64 hpf_margin_hz; }; -static const unsigned long long freq_range_hpf[4][2] = { +static const unsigned long long freq_range_hpf[5][2] = { + {0ULL, 0ULL}, /* bypass */ {1750000000ULL, 3550000000ULL}, {3400000000ULL, 7250000000ULL}, {6600000000, 12000000000}, {12500000000, 19900000000} }; -static const unsigned long long freq_range_lpf[4][2] = { +static const unsigned long long freq_range_lpf[5][2] = { + {U64_MAX, U64_MAX}, /* bypass */ {2050000000ULL, 3850000000ULL}, {3350000000ULL, 7250000000ULL}, {7000000000, 13000000000}, - {12550000000, 18500000000} + {12550000000, 18850000000} }; static const struct regmap_config admv8818_regmap_config = { @@ -121,44 +136,59 @@ static const char * const admv8818_modes[] = { static int __admv8818_hpf_select(struct admv8818_state *st, u64 freq) { - unsigned int hpf_step = 0, hpf_band = 0, i, j; - u64 freq_step; - int ret; + int band, state, ret; + unsigned int hpf_state = ADMV8818_STATE_MIN, hpf_band = ADMV8818_BAND_BYPASS; + u64 freq_error, min_freq_error, freq_corner, freq_step; - if (freq < freq_range_hpf[0][0]) + if (freq < freq_range_hpf[ADMV8818_BAND_MIN][ADMV8818_BAND_CORNER_LOW]) goto hpf_write; - if (freq > freq_range_hpf[3][1]) { - hpf_step = 15; - hpf_band = 4; - + if (freq >= freq_range_hpf[ADMV8818_BAND_MAX][ADMV8818_BAND_CORNER_HIGH]) { + hpf_state = ADMV8818_STATE_MAX; + hpf_band = ADMV8818_BAND_MAX; goto hpf_write; } - for (i = 0; i < 4; i++) { - freq_step = div_u64((freq_range_hpf[i][1] - - freq_range_hpf[i][0]), 15); + /* Close HPF frequency gap between 12 and 12.5 GHz */ + if (freq >= 12000ULL * HZ_PER_MHZ && freq < 12500ULL * HZ_PER_MHZ) { + hpf_state = ADMV8818_STATE_MAX; + hpf_band = 3; + goto hpf_write; + } - if (freq > freq_range_hpf[i][0] && - (freq < freq_range_hpf[i][1] + freq_step)) { - hpf_band = i + 1; + min_freq_error = U64_MAX; + for (band = ADMV8818_BAND_MIN; band <= ADMV8818_BAND_MAX; band++) { + /* + * This (and therefore all other ranges) have a corner + * frequency higher than the target frequency. + */ + if (freq_range_hpf[band][ADMV8818_BAND_CORNER_LOW] > freq) + break; - for (j = 1; j <= 16; j++) { - if (freq < (freq_range_hpf[i][0] + (freq_step * j))) { - hpf_step = j - 1; - break; - } + freq_step = freq_range_hpf[band][ADMV8818_BAND_CORNER_HIGH] - + freq_range_hpf[band][ADMV8818_BAND_CORNER_LOW]; + freq_step = div_u64(freq_step, ADMV8818_NUM_STATES - 1); + + for (state = ADMV8818_STATE_MIN; state <= ADMV8818_STATE_MAX; state++) { + freq_corner = freq_range_hpf[band][ADMV8818_BAND_CORNER_LOW] + + freq_step * state; + + /* + * This (and therefore all other states) have a corner + * frequency higher than the target frequency. + */ + if (freq_corner > freq) + break; + + freq_error = freq - freq_corner; + if (freq_error < min_freq_error) { + min_freq_error = freq_error; + hpf_state = state; + hpf_band = band; } - break; } } - /* Close HPF frequency gap between 12 and 12.5 GHz */ - if (freq >= 12000 * HZ_PER_MHZ && freq <= 12500 * HZ_PER_MHZ) { - hpf_band = 3; - hpf_step = 15; - } - hpf_write: ret = regmap_update_bits(st->regmap, ADMV8818_REG_WR0_SW, ADMV8818_SW_IN_SET_WR0_MSK | @@ -170,7 +200,7 @@ hpf_write: return regmap_update_bits(st->regmap, ADMV8818_REG_WR0_FILTER, ADMV8818_HPF_WR0_MSK, - FIELD_PREP(ADMV8818_HPF_WR0_MSK, hpf_step)); + FIELD_PREP(ADMV8818_HPF_WR0_MSK, hpf_state)); } static int admv8818_hpf_select(struct admv8818_state *st, u64 freq) @@ -186,31 +216,52 @@ static int admv8818_hpf_select(struct admv8818_state *st, u64 freq) static int __admv8818_lpf_select(struct admv8818_state *st, u64 freq) { - unsigned int lpf_step = 0, lpf_band = 0, i, j; - u64 freq_step; - int ret; + int band, state, ret; + unsigned int lpf_state = ADMV8818_STATE_MIN, lpf_band = ADMV8818_BAND_BYPASS; + u64 freq_error, min_freq_error, freq_corner, freq_step; - if (freq > freq_range_lpf[3][1]) + if (freq > freq_range_lpf[ADMV8818_BAND_MAX][ADMV8818_BAND_CORNER_HIGH]) goto lpf_write; - if (freq < freq_range_lpf[0][0]) { - lpf_band = 1; - + if (freq < freq_range_lpf[ADMV8818_BAND_MIN][ADMV8818_BAND_CORNER_LOW]) { + lpf_state = ADMV8818_STATE_MIN; + lpf_band = ADMV8818_BAND_MIN; goto lpf_write; } - for (i = 0; i < 4; i++) { - if (freq > freq_range_lpf[i][0] && freq < freq_range_lpf[i][1]) { - lpf_band = i + 1; - freq_step = div_u64((freq_range_lpf[i][1] - freq_range_lpf[i][0]), 15); + min_freq_error = U64_MAX; + for (band = ADMV8818_BAND_MAX; band >= ADMV8818_BAND_MIN; --band) { + /* + * At this point the highest corner frequency of + * all remaining ranges is below the target. + * LPF corner should be >= the target. + */ + if (freq > freq_range_lpf[band][ADMV8818_BAND_CORNER_HIGH]) + break; + + freq_step = freq_range_lpf[band][ADMV8818_BAND_CORNER_HIGH] - + freq_range_lpf[band][ADMV8818_BAND_CORNER_LOW]; + freq_step = div_u64(freq_step, ADMV8818_NUM_STATES - 1); + + for (state = ADMV8818_STATE_MAX; state >= ADMV8818_STATE_MIN; --state) { + + freq_corner = freq_range_lpf[band][ADMV8818_BAND_CORNER_LOW] + + state * freq_step; - for (j = 0; j <= 15; j++) { - if (freq < (freq_range_lpf[i][0] + (freq_step * j))) { - lpf_step = j; - break; - } + /* + * At this point all other states in range will + * place the corner frequency below the target + * LPF corner should >= the target. + */ + if (freq > freq_corner) + break; + + freq_error = freq_corner - freq; + if (freq_error < min_freq_error) { + min_freq_error = freq_error; + lpf_state = state; + lpf_band = band; } - break; } } @@ -225,7 +276,7 @@ lpf_write: return regmap_update_bits(st->regmap, ADMV8818_REG_WR0_FILTER, ADMV8818_LPF_WR0_MSK, - FIELD_PREP(ADMV8818_LPF_WR0_MSK, lpf_step)); + FIELD_PREP(ADMV8818_LPF_WR0_MSK, lpf_state)); } static int admv8818_lpf_select(struct admv8818_state *st, u64 freq) @@ -242,16 +293,28 @@ static int admv8818_lpf_select(struct admv8818_state *st, u64 freq) static int admv8818_rfin_band_select(struct admv8818_state *st) { int ret; + u64 hpf_corner_target, lpf_corner_target; st->cf_hz = clk_get_rate(st->clkin); + /* Check for underflow */ + if (st->cf_hz > st->hpf_margin_hz) + hpf_corner_target = st->cf_hz - st->hpf_margin_hz; + else + hpf_corner_target = 0; + + /* Check for overflow */ + lpf_corner_target = st->cf_hz + st->lpf_margin_hz; + if (lpf_corner_target < st->cf_hz) + lpf_corner_target = U64_MAX; + mutex_lock(&st->lock); - ret = __admv8818_hpf_select(st, st->cf_hz); + ret = __admv8818_hpf_select(st, hpf_corner_target); if (ret) goto exit; - ret = __admv8818_lpf_select(st, st->cf_hz); + ret = __admv8818_lpf_select(st, lpf_corner_target); exit: mutex_unlock(&st->lock); return ret; @@ -278,8 +341,11 @@ static int __admv8818_read_hpf_freq(struct admv8818_state *st, u64 *hpf_freq) hpf_state = FIELD_GET(ADMV8818_HPF_WR0_MSK, data); - *hpf_freq = div_u64(freq_range_hpf[hpf_band - 1][1] - freq_range_hpf[hpf_band - 1][0], 15); - *hpf_freq = freq_range_hpf[hpf_band - 1][0] + (*hpf_freq * hpf_state); + *hpf_freq = freq_range_hpf[hpf_band][ADMV8818_BAND_CORNER_HIGH] - + freq_range_hpf[hpf_band][ADMV8818_BAND_CORNER_LOW]; + *hpf_freq = div_u64(*hpf_freq, ADMV8818_NUM_STATES - 1); + *hpf_freq = freq_range_hpf[hpf_band][ADMV8818_BAND_CORNER_LOW] + + (*hpf_freq * hpf_state); return ret; } @@ -316,8 +382,11 @@ static int __admv8818_read_lpf_freq(struct admv8818_state *st, u64 *lpf_freq) lpf_state = FIELD_GET(ADMV8818_LPF_WR0_MSK, data); - *lpf_freq = div_u64(freq_range_lpf[lpf_band - 1][1] - freq_range_lpf[lpf_band - 1][0], 15); - *lpf_freq = freq_range_lpf[lpf_band - 1][0] + (*lpf_freq * lpf_state); + *lpf_freq = freq_range_lpf[lpf_band][ADMV8818_BAND_CORNER_HIGH] - + freq_range_lpf[lpf_band][ADMV8818_BAND_CORNER_LOW]; + *lpf_freq = div_u64(*lpf_freq, ADMV8818_NUM_STATES - 1); + *lpf_freq = freq_range_lpf[lpf_band][ADMV8818_BAND_CORNER_LOW] + + (*lpf_freq * lpf_state); return ret; } @@ -333,6 +402,19 @@ static int admv8818_read_lpf_freq(struct admv8818_state *st, u64 *lpf_freq) return ret; } +static int admv8818_write_raw_get_fmt(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + long mask) +{ + switch (mask) { + case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: + case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY: + return IIO_VAL_INT_64; + default: + return -EINVAL; + } +} + static int admv8818_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, int val2, long info) @@ -341,6 +423,9 @@ static int admv8818_write_raw(struct iio_dev *indio_dev, u64 freq = ((u64)val2 << 32 | (u32)val); + if ((s64)freq < 0) + return -EINVAL; + switch (info) { case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: return admv8818_lpf_select(st, freq); @@ -502,6 +587,7 @@ set_mode: static const struct iio_info admv8818_info = { .write_raw = admv8818_write_raw, + .write_raw_get_fmt = admv8818_write_raw_get_fmt, .read_raw = admv8818_read_raw, .debugfs_reg_access = &admv8818_reg_access, }; @@ -516,7 +602,7 @@ static const struct iio_enum admv8818_mode_enum = { static const struct iio_chan_spec_ext_info admv8818_ext_info[] = { IIO_ENUM("filter_mode", IIO_SHARED_BY_ALL, &admv8818_mode_enum), IIO_ENUM_AVAILABLE("filter_mode", IIO_SHARED_BY_ALL, &admv8818_mode_enum), - { }, + { } }; #define ADMV8818_CHAN(_channel) { \ @@ -641,6 +727,32 @@ static int admv8818_clk_setup(struct admv8818_state *st) return devm_add_action_or_reset(&spi->dev, admv8818_clk_notifier_unreg, st); } +static int admv8818_read_properties(struct admv8818_state *st) +{ + struct spi_device *spi = st->spi; + u32 mhz; + int ret; + + ret = device_property_read_u32(&spi->dev, "adi,lpf-margin-mhz", &mhz); + if (ret == 0) + st->lpf_margin_hz = (u64)mhz * HZ_PER_MHZ; + else if (ret == -EINVAL) + st->lpf_margin_hz = 0; + else + return ret; + + + ret = device_property_read_u32(&spi->dev, "adi,hpf-margin-mhz", &mhz); + if (ret == 0) + st->hpf_margin_hz = (u64)mhz * HZ_PER_MHZ; + else if (ret == -EINVAL) + st->hpf_margin_hz = 0; + else if (ret < 0) + return ret; + + return 0; +} + static int admv8818_probe(struct spi_device *spi) { struct iio_dev *indio_dev; @@ -672,6 +784,10 @@ static int admv8818_probe(struct spi_device *spi) mutex_init(&st->lock); + ret = admv8818_read_properties(st); + if (ret) + return ret; + ret = admv8818_init(st); if (ret) return ret; @@ -681,13 +797,13 @@ static int admv8818_probe(struct spi_device *spi) static const struct spi_device_id admv8818_id[] = { { "admv8818", 0 }, - {} + { } }; MODULE_DEVICE_TABLE(spi, admv8818_id); static const struct of_device_id admv8818_of_match[] = { { .compatible = "adi,admv8818" }, - {} + { } }; MODULE_DEVICE_TABLE(of, admv8818_of_match); diff --git a/drivers/iio/frequency/ad9523.c b/drivers/iio/frequency/ad9523.c index b1554ced7a26..63c485e9e44c 100644 --- a/drivers/iio/frequency/ad9523.c +++ b/drivers/iio/frequency/ad9523.c @@ -1032,7 +1032,7 @@ static int ad9523_probe(struct spi_device *spi) static const struct spi_device_id ad9523_id[] = { {"ad9523-1", 9523}, - {} + { } }; MODULE_DEVICE_TABLE(spi, ad9523_id); diff --git a/drivers/iio/frequency/adf4350.c b/drivers/iio/frequency/adf4350.c index 61828e61e275..47f1c7e9efa9 100644 --- a/drivers/iio/frequency/adf4350.c +++ b/drivers/iio/frequency/adf4350.c @@ -373,7 +373,7 @@ static const struct iio_chan_spec_ext_info adf4350_ext_info[] = { _ADF4350_EXT_INFO("frequency_resolution", ADF4350_FREQ_RESOLUTION), _ADF4350_EXT_INFO("refin_frequency", ADF4350_FREQ_REFIN), _ADF4350_EXT_INFO("powerdown", ADF4350_PWRDOWN), - { }, + { } }; static const struct iio_chan_spec adf4350_chan = { @@ -682,14 +682,14 @@ static int adf4350_probe(struct spi_device *spi) static const struct of_device_id adf4350_of_match[] = { { .compatible = "adi,adf4350", }, { .compatible = "adi,adf4351", }, - { /* sentinel */ }, + { } }; MODULE_DEVICE_TABLE(of, adf4350_of_match); static const struct spi_device_id adf4350_id[] = { {"adf4350", 4350}, {"adf4351", 4351}, - {} + { } }; MODULE_DEVICE_TABLE(spi, adf4350_id); diff --git a/drivers/iio/frequency/adf4371.c b/drivers/iio/frequency/adf4371.c index 9a84e81787b1..d6dc7827fb41 100644 --- a/drivers/iio/frequency/adf4371.c +++ b/drivers/iio/frequency/adf4371.c @@ -438,7 +438,7 @@ static const struct iio_chan_spec_ext_info adf4371_ext_info[] = { _ADF4371_EXT_INFO("frequency", ADF4371_FREQ), _ADF4371_EXT_INFO("powerdown", ADF4371_POWER_DOWN), _ADF4371_EXT_INFO("name", ADF4371_CHANNEL_NAME), - { }, + { } }; #define ADF4371_CHANNEL(index) { \ @@ -626,14 +626,14 @@ static int adf4371_probe(struct spi_device *spi) static const struct spi_device_id adf4371_id_table[] = { { "adf4371", (kernel_ulong_t)&adf4371_chip_info }, { "adf4372", (kernel_ulong_t)&adf4372_chip_info }, - {} + { } }; MODULE_DEVICE_TABLE(spi, adf4371_id_table); static const struct of_device_id adf4371_of_match[] = { { .compatible = "adi,adf4371", .data = &adf4371_chip_info }, { .compatible = "adi,adf4372", .data = &adf4372_chip_info}, - { }, + { } }; MODULE_DEVICE_TABLE(of, adf4371_of_match); diff --git a/drivers/iio/frequency/adf4377.c b/drivers/iio/frequency/adf4377.c index 45ceeb828d6b..08833b7035e4 100644 --- a/drivers/iio/frequency/adf4377.c +++ b/drivers/iio/frequency/adf4377.c @@ -985,14 +985,14 @@ static int adf4377_probe(struct spi_device *spi) static const struct spi_device_id adf4377_id[] = { { "adf4377", (kernel_ulong_t)&adf4377_chip_info }, { "adf4378", (kernel_ulong_t)&adf4378_chip_info }, - {} + { } }; MODULE_DEVICE_TABLE(spi, adf4377_id); static const struct of_device_id adf4377_of_match[] = { { .compatible = "adi,adf4377", .data = &adf4377_chip_info }, { .compatible = "adi,adf4378", .data = &adf4378_chip_info }, - {} + { } }; MODULE_DEVICE_TABLE(of, adf4377_of_match); diff --git a/drivers/iio/frequency/admv1013.c b/drivers/iio/frequency/admv1013.c index 8ef583680ad0..d8e8d541990f 100644 --- a/drivers/iio/frequency/admv1013.c +++ b/drivers/iio/frequency/admv1013.c @@ -319,7 +319,7 @@ static ssize_t admv1013_write(struct iio_dev *indio_dev, return -EINVAL; } - return ret ? ret : len; + return len; } static int admv1013_update_quad_filters(struct admv1013_state *st) @@ -407,7 +407,7 @@ static int admv1013_freq_change(struct notifier_block *nb, unsigned long action, static const struct iio_chan_spec_ext_info admv1013_ext_info[] = { _ADMV1013_EXT_INFO("i_calibphase", IIO_SEPARATE, ADMV1013_RFMOD_I_CALIBPHASE), _ADMV1013_EXT_INFO("q_calibphase", IIO_SEPARATE, ADMV1013_RFMOD_Q_CALIBPHASE), - { }, + { } }; #define ADMV1013_CHAN_PHASE(_channel, _channel2, _admv1013_ext_info) { \ @@ -615,13 +615,13 @@ static int admv1013_probe(struct spi_device *spi) static const struct spi_device_id admv1013_id[] = { { "admv1013", 0 }, - {} + { } }; MODULE_DEVICE_TABLE(spi, admv1013_id); static const struct of_device_id admv1013_of_match[] = { { .compatible = "adi,admv1013" }, - {}, + { } }; MODULE_DEVICE_TABLE(of, admv1013_of_match); diff --git a/drivers/iio/frequency/admv1014.c b/drivers/iio/frequency/admv1014.c index 986b87a72577..7a8f92ec80a2 100644 --- a/drivers/iio/frequency/admv1014.c +++ b/drivers/iio/frequency/admv1014.c @@ -792,13 +792,13 @@ static int admv1014_probe(struct spi_device *spi) static const struct spi_device_id admv1014_id[] = { { "admv1014", 0 }, - {} + { } }; MODULE_DEVICE_TABLE(spi, admv1014_id); static const struct of_device_id admv1014_of_match[] = { { .compatible = "adi,admv1014" }, - {} + { } }; MODULE_DEVICE_TABLE(of, admv1014_of_match); diff --git a/drivers/iio/frequency/adrf6780.c b/drivers/iio/frequency/adrf6780.c index 57ee908fc747..a7a21f929970 100644 --- a/drivers/iio/frequency/adrf6780.c +++ b/drivers/iio/frequency/adrf6780.c @@ -487,13 +487,13 @@ static int adrf6780_probe(struct spi_device *spi) static const struct spi_device_id adrf6780_id[] = { { "adrf6780", 0 }, - {} + { } }; MODULE_DEVICE_TABLE(spi, adrf6780_id); static const struct of_device_id adrf6780_of_match[] = { { .compatible = "adi,adrf6780" }, - {} + { } }; MODULE_DEVICE_TABLE(of, adrf6780_of_match); diff --git a/drivers/iio/gyro/adis16080.c b/drivers/iio/gyro/adis16080.c index 14b3abf6dce9..178bba95a709 100644 --- a/drivers/iio/gyro/adis16080.c +++ b/drivers/iio/gyro/adis16080.c @@ -214,7 +214,7 @@ static int adis16080_probe(struct spi_device *spi) static const struct spi_device_id adis16080_ids[] = { { "adis16080", ID_ADIS16080 }, { "adis16100", ID_ADIS16100 }, - {}, + { } }; MODULE_DEVICE_TABLE(spi, adis16080_ids); diff --git a/drivers/iio/gyro/adis16260.c b/drivers/iio/gyro/adis16260.c index c151fbb59ffe..586e6cfa14a9 100644 --- a/drivers/iio/gyro/adis16260.c +++ b/drivers/iio/gyro/adis16260.c @@ -414,7 +414,7 @@ static const struct spi_device_id adis16260_id[] = { {"adis16250", ADIS16260}, {"adis16255", ADIS16260}, {"adis16251", ADIS16251}, - {} + { } }; MODULE_DEVICE_TABLE(spi, adis16260_id); diff --git a/drivers/iio/gyro/adxrs290.c b/drivers/iio/gyro/adxrs290.c index 223fc181109c..8fcb41f45baa 100644 --- a/drivers/iio/gyro/adxrs290.c +++ b/drivers/iio/gyro/adxrs290.c @@ -290,9 +290,8 @@ static int adxrs290_read_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_RAW: - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; switch (chan->type) { case IIO_ANGL_VEL: @@ -316,7 +315,7 @@ static int adxrs290_read_raw(struct iio_dev *indio_dev, break; } - iio_device_release_direct_mode(indio_dev); + iio_device_release_direct(indio_dev); return ret; case IIO_CHAN_INFO_SCALE: switch (chan->type) { @@ -366,9 +365,8 @@ static int adxrs290_write_raw(struct iio_dev *indio_dev, struct adxrs290_state *st = iio_priv(indio_dev); int ret, lpf_idx, hpf_idx; - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; switch (mask) { case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: @@ -408,7 +406,7 @@ static int adxrs290_write_raw(struct iio_dev *indio_dev, break; } - iio_device_release_direct_mode(indio_dev); + iio_device_release_direct(indio_dev); return ret; } diff --git a/drivers/iio/gyro/adxrs450.c b/drivers/iio/gyro/adxrs450.c index f84438e0c42c..a1d8d3cb301b 100644 --- a/drivers/iio/gyro/adxrs450.c +++ b/drivers/iio/gyro/adxrs450.c @@ -95,12 +95,10 @@ static int adxrs450_spi_read_reg_16(struct iio_dev *indio_dev, struct spi_transfer xfers[] = { { .tx_buf = &st->tx, - .bits_per_word = 8, .len = sizeof(st->tx), .cs_change = 1, }, { .rx_buf = &st->rx, - .bits_per_word = 8, .len = sizeof(st->rx), }, }; @@ -169,12 +167,10 @@ static int adxrs450_spi_sensor_data(struct iio_dev *indio_dev, s16 *val) struct spi_transfer xfers[] = { { .tx_buf = &st->tx, - .bits_per_word = 8, .len = sizeof(st->tx), .cs_change = 1, }, { .rx_buf = &st->rx, - .bits_per_word = 8, .len = sizeof(st->rx), }, }; @@ -209,7 +205,6 @@ static int adxrs450_spi_initial(struct adxrs450_state *st, struct spi_transfer xfers = { .tx_buf = &st->tx, .rx_buf = &st->rx, - .bits_per_word = 8, .len = sizeof(st->tx), }; @@ -446,7 +441,7 @@ static int adxrs450_probe(struct spi_device *spi) static const struct spi_device_id adxrs450_id[] = { {"adxrs450", ID_ADXRS450}, {"adxrs453", ID_ADXRS453}, - {} + { } }; MODULE_DEVICE_TABLE(spi, adxrs450_id); diff --git a/drivers/iio/gyro/bmg160_i2c.c b/drivers/iio/gyro/bmg160_i2c.c index e6caab49f98a..1fb8a7969c25 100644 --- a/drivers/iio/gyro/bmg160_i2c.c +++ b/drivers/iio/gyro/bmg160_i2c.c @@ -41,7 +41,7 @@ static void bmg160_i2c_remove(struct i2c_client *client) static const struct acpi_device_id bmg160_acpi_match[] = { {"BMG0160", 0}, - {}, + { } }; MODULE_DEVICE_TABLE(acpi, bmg160_acpi_match); @@ -50,7 +50,7 @@ static const struct i2c_device_id bmg160_i2c_id[] = { { "bmg160" }, { "bmi055_gyro" }, { "bmi088_gyro" }, - {} + { } }; MODULE_DEVICE_TABLE(i2c, bmg160_i2c_id); diff --git a/drivers/iio/gyro/bmg160_spi.c b/drivers/iio/gyro/bmg160_spi.c index ac04b3b1b554..6aecc5eb8347 100644 --- a/drivers/iio/gyro/bmg160_spi.c +++ b/drivers/iio/gyro/bmg160_spi.c @@ -36,7 +36,7 @@ static const struct spi_device_id bmg160_spi_id[] = { {"bmg160", 0}, {"bmi055_gyro", 0}, {"bmi088_gyro", 0}, - {} + { } }; MODULE_DEVICE_TABLE(spi, bmg160_spi_id); diff --git a/drivers/iio/gyro/hid-sensor-gyro-3d.c b/drivers/iio/gyro/hid-sensor-gyro-3d.c index 54b6f6fbdcaa..c43990c518f7 100644 --- a/drivers/iio/gyro/hid-sensor-gyro-3d.c +++ b/drivers/iio/gyro/hid-sensor-gyro-3d.c @@ -375,7 +375,7 @@ static const struct platform_device_id hid_gyro_3d_ids[] = { /* Format: HID-SENSOR-usage_id_in_hex_lowercase */ .name = "HID-SENSOR-200076", }, - { /* sentinel */ } + { } }; MODULE_DEVICE_TABLE(platform, hid_gyro_3d_ids); diff --git a/drivers/iio/gyro/mpu3050-core.c b/drivers/iio/gyro/mpu3050-core.c index d66224bed8e3..16553948c5c3 100644 --- a/drivers/iio/gyro/mpu3050-core.c +++ b/drivers/iio/gyro/mpu3050-core.c @@ -684,7 +684,7 @@ mpu3050_get_mount_matrix(const struct iio_dev *indio_dev, static const struct iio_chan_spec_ext_info mpu3050_ext_info[] = { IIO_MOUNT_MATRIX(IIO_SHARED_BY_TYPE, mpu3050_get_mount_matrix), - { }, + { } }; #define MPU3050_AXIS_CHANNEL(axis, index) \ diff --git a/drivers/iio/gyro/mpu3050-i2c.c b/drivers/iio/gyro/mpu3050-i2c.c index 29ecfa6fd633..8e284f47242c 100644 --- a/drivers/iio/gyro/mpu3050-i2c.c +++ b/drivers/iio/gyro/mpu3050-i2c.c @@ -95,7 +95,7 @@ static void mpu3050_i2c_remove(struct i2c_client *client) */ static const struct i2c_device_id mpu3050_i2c_id[] = { { "mpu3050" }, - {} + { } }; MODULE_DEVICE_TABLE(i2c, mpu3050_i2c_id); @@ -103,7 +103,7 @@ static const struct of_device_id mpu3050_i2c_of_match[] = { { .compatible = "invensense,mpu3050", .data = "mpu3050" }, /* Deprecated vendor ID from the Input driver */ { .compatible = "invn,mpu3050", .data = "mpu3050" }, - { }, + { } }; MODULE_DEVICE_TABLE(of, mpu3050_i2c_of_match); diff --git a/drivers/iio/gyro/st_gyro_i2c.c b/drivers/iio/gyro/st_gyro_i2c.c index d4b11bdba666..aef5ec8f9dee 100644 --- a/drivers/iio/gyro/st_gyro_i2c.c +++ b/drivers/iio/gyro/st_gyro_i2c.c @@ -54,7 +54,7 @@ static const struct of_device_id st_gyro_of_match[] = { .compatible = "st,lsm9ds0-gyro", .data = LSM9DS0_GYRO_DEV_NAME, }, - {}, + { } }; MODULE_DEVICE_TABLE(of, st_gyro_of_match); @@ -102,7 +102,7 @@ static const struct i2c_device_id st_gyro_id_table[] = { { L3G4IS_GYRO_DEV_NAME }, { LSM330_GYRO_DEV_NAME }, { LSM9DS0_GYRO_DEV_NAME }, - {}, + { } }; MODULE_DEVICE_TABLE(i2c, st_gyro_id_table); diff --git a/drivers/iio/gyro/st_gyro_spi.c b/drivers/iio/gyro/st_gyro_spi.c index 811f712711f5..f645da157372 100644 --- a/drivers/iio/gyro/st_gyro_spi.c +++ b/drivers/iio/gyro/st_gyro_spi.c @@ -59,7 +59,7 @@ static const struct of_device_id st_gyro_of_match[] = { .compatible = "st,lsm9ds0-gyro", .data = LSM9DS0_GYRO_DEV_NAME, }, - {}, + { } }; MODULE_DEVICE_TABLE(of, st_gyro_of_match); @@ -107,7 +107,7 @@ static const struct spi_device_id st_gyro_id_table[] = { { L3G4IS_GYRO_DEV_NAME }, { LSM330_GYRO_DEV_NAME }, { LSM9DS0_GYRO_DEV_NAME }, - {}, + { } }; MODULE_DEVICE_TABLE(spi, st_gyro_id_table); diff --git a/drivers/iio/health/afe4403.c b/drivers/iio/health/afe4403.c index 13e1dd4dd62c..1582cfc03579 100644 --- a/drivers/iio/health/afe4403.c +++ b/drivers/iio/health/afe4403.c @@ -411,7 +411,7 @@ static const struct regmap_config afe4403_regmap_config = { static const struct of_device_id afe4403_of_match[] = { { .compatible = "ti,afe4403", }, - { /* sentinel */ } + { } }; MODULE_DEVICE_TABLE(of, afe4403_of_match); @@ -574,7 +574,7 @@ static int afe4403_probe(struct spi_device *spi) static const struct spi_device_id afe4403_ids[] = { { "afe4403", 0 }, - { /* sentinel */ } + { } }; MODULE_DEVICE_TABLE(spi, afe4403_ids); diff --git a/drivers/iio/health/afe4404.c b/drivers/iio/health/afe4404.c index d49e1572a439..99ff68aed27c 100644 --- a/drivers/iio/health/afe4404.c +++ b/drivers/iio/health/afe4404.c @@ -419,7 +419,7 @@ static const struct regmap_config afe4404_regmap_config = { static const struct of_device_id afe4404_of_match[] = { { .compatible = "ti,afe4404", }, - { /* sentinel */ } + { } }; MODULE_DEVICE_TABLE(of, afe4404_of_match); @@ -581,7 +581,7 @@ static int afe4404_probe(struct i2c_client *client) static const struct i2c_device_id afe4404_ids[] = { { "afe4404" }, - { /* sentinel */ } + { } }; MODULE_DEVICE_TABLE(i2c, afe4404_ids); diff --git a/drivers/iio/health/max30100.c b/drivers/iio/health/max30100.c index e08d143a707c..846664a4ee90 100644 --- a/drivers/iio/health/max30100.c +++ b/drivers/iio/health/max30100.c @@ -483,7 +483,7 @@ static void max30100_remove(struct i2c_client *client) static const struct i2c_device_id max30100_id[] = { { "max30100" }, - {} + { } }; MODULE_DEVICE_TABLE(i2c, max30100_id); diff --git a/drivers/iio/health/max30102.c b/drivers/iio/health/max30102.c index 1d074eb6a8c5..f5f29d2fec57 100644 --- a/drivers/iio/health/max30102.c +++ b/drivers/iio/health/max30102.c @@ -484,11 +484,11 @@ any_mode_retry: * things cannot concurrently change. And we just keep * trying until we get one of the modes... */ - if (iio_device_claim_direct_mode(indio_dev)) + if (!iio_device_claim_direct(indio_dev)) goto any_mode_retry; ret = max30102_get_temp(data, val, true); - iio_device_release_direct_mode(indio_dev); + iio_device_release_direct(indio_dev); } else { ret = max30102_get_temp(data, val, false); iio_device_release_buffer_mode(indio_dev); @@ -615,7 +615,7 @@ static const struct i2c_device_id max30102_id[] = { { "max30101", max30105 }, { "max30102", max30102 }, { "max30105", max30105 }, - {} + { } }; MODULE_DEVICE_TABLE(i2c, max30102_id); diff --git a/drivers/iio/humidity/am2315.c b/drivers/iio/humidity/am2315.c index 2323974b805c..f021c3e6d886 100644 --- a/drivers/iio/humidity/am2315.c +++ b/drivers/iio/humidity/am2315.c @@ -253,7 +253,7 @@ static int am2315_probe(struct i2c_client *client) static const struct i2c_device_id am2315_i2c_id[] = { { "am2315" }, - {} + { } }; MODULE_DEVICE_TABLE(i2c, am2315_i2c_id); diff --git a/drivers/iio/humidity/hdc100x.c b/drivers/iio/humidity/hdc100x.c index a303f704b7ed..c2b36e682e06 100644 --- a/drivers/iio/humidity/hdc100x.c +++ b/drivers/iio/humidity/hdc100x.c @@ -13,6 +13,7 @@ * https://www.ti.com/product/HDC1080/datasheet */ +#include <linux/cleanup.h> #include <linux/delay.h> #include <linux/module.h> #include <linux/mod_devicetable.h> @@ -206,26 +207,20 @@ static int hdc100x_read_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_RAW: { int ret; - mutex_lock(&data->lock); + guard(mutex)(&data->lock); if (chan->type == IIO_CURRENT) { *val = hdc100x_get_heater_status(data); - ret = IIO_VAL_INT; - } else { - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) { - mutex_unlock(&data->lock); - return ret; - } - - ret = hdc100x_get_measurement(data, chan); - iio_device_release_direct_mode(indio_dev); - if (ret >= 0) { - *val = ret; - ret = IIO_VAL_INT; - } + return IIO_VAL_INT; } - mutex_unlock(&data->lock); - return ret; + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; + + ret = hdc100x_get_measurement(data, chan); + iio_device_release_direct(indio_dev); + if (ret < 0) + return ret; + *val = ret; + return IIO_VAL_INT; } case IIO_CHAN_INFO_INT_TIME: *val = 0; @@ -256,26 +251,23 @@ static int hdc100x_write_raw(struct iio_dev *indio_dev, int val, int val2, long mask) { struct hdc100x_data *data = iio_priv(indio_dev); - int ret = -EINVAL; switch (mask) { - case IIO_CHAN_INFO_INT_TIME: + case IIO_CHAN_INFO_INT_TIME: { if (val != 0) return -EINVAL; - mutex_lock(&data->lock); - ret = hdc100x_set_it_time(data, chan->address, val2); - mutex_unlock(&data->lock); - return ret; - case IIO_CHAN_INFO_RAW: + guard(mutex)(&data->lock); + return hdc100x_set_it_time(data, chan->address, val2); + } + case IIO_CHAN_INFO_RAW: { if (chan->type != IIO_CURRENT || val2 != 0) return -EINVAL; - mutex_lock(&data->lock); - ret = hdc100x_update_config(data, HDC100X_REG_CONFIG_HEATER_EN, - val ? HDC100X_REG_CONFIG_HEATER_EN : 0); - mutex_unlock(&data->lock); - return ret; + guard(mutex)(&data->lock); + return hdc100x_update_config(data, HDC100X_REG_CONFIG_HEATER_EN, + val ? HDC100X_REG_CONFIG_HEATER_EN : 0); + } default: return -EINVAL; } @@ -284,27 +276,19 @@ static int hdc100x_write_raw(struct iio_dev *indio_dev, static int hdc100x_buffer_postenable(struct iio_dev *indio_dev) { struct hdc100x_data *data = iio_priv(indio_dev); - int ret; /* Buffer is enabled. First set ACQ Mode, then attach poll func */ - mutex_lock(&data->lock); - ret = hdc100x_update_config(data, HDC100X_REG_CONFIG_ACQ_MODE, - HDC100X_REG_CONFIG_ACQ_MODE); - mutex_unlock(&data->lock); - - return ret; + guard(mutex)(&data->lock); + return hdc100x_update_config(data, HDC100X_REG_CONFIG_ACQ_MODE, + HDC100X_REG_CONFIG_ACQ_MODE); } static int hdc100x_buffer_predisable(struct iio_dev *indio_dev) { struct hdc100x_data *data = iio_priv(indio_dev); - int ret; - mutex_lock(&data->lock); - ret = hdc100x_update_config(data, HDC100X_REG_CONFIG_ACQ_MODE, 0); - mutex_unlock(&data->lock); - - return ret; + guard(mutex)(&data->lock); + return hdc100x_update_config(data, HDC100X_REG_CONFIG_ACQ_MODE, 0); } static const struct iio_buffer_setup_ops hdc_buffer_setup_ops = { diff --git a/drivers/iio/humidity/hdc2010.c b/drivers/iio/humidity/hdc2010.c index f5867659e00f..894a8b4ab193 100644 --- a/drivers/iio/humidity/hdc2010.c +++ b/drivers/iio/humidity/hdc2010.c @@ -169,13 +169,12 @@ static int hdc2010_read_raw(struct iio_dev *indio_dev, *val = hdc2010_get_heater_status(data); return IIO_VAL_INT; } - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; mutex_lock(&data->lock); ret = hdc2010_get_prim_measurement_word(data, chan); mutex_unlock(&data->lock); - iio_device_release_direct_mode(indio_dev); + iio_device_release_direct(indio_dev); if (ret < 0) return ret; *val = ret; @@ -184,13 +183,12 @@ static int hdc2010_read_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_PEAK: { int ret; - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; mutex_lock(&data->lock); ret = hdc2010_get_peak_measurement_byte(data, chan); mutex_unlock(&data->lock); - iio_device_release_direct_mode(indio_dev); + iio_device_release_direct(indio_dev); if (ret < 0) return ret; /* Scaling up the value so we can use same offset as RAW */ diff --git a/drivers/iio/humidity/hid-sensor-humidity.c b/drivers/iio/humidity/hid-sensor-humidity.c index a40e1eb6e98c..be2338d5f407 100644 --- a/drivers/iio/humidity/hid-sensor-humidity.c +++ b/drivers/iio/humidity/hid-sensor-humidity.c @@ -276,7 +276,7 @@ static const struct platform_device_id hid_humidity_ids[] = { /* Format: HID-SENSOR-usage_id_in_hex_lowercase */ .name = "HID-SENSOR-200032", }, - { /* sentinel */ } + { } }; MODULE_DEVICE_TABLE(platform, hid_humidity_ids); diff --git a/drivers/iio/humidity/hts221_core.c b/drivers/iio/humidity/hts221_core.c index 0be11470730c..bfeb0a60d3af 100644 --- a/drivers/iio/humidity/hts221_core.c +++ b/drivers/iio/humidity/hts221_core.c @@ -418,31 +418,22 @@ static int hts221_read_oneshot(struct hts221_hw *hw, u8 addr, int *val) return IIO_VAL_INT; } -static int hts221_read_raw(struct iio_dev *iio_dev, - struct iio_chan_spec const *ch, - int *val, int *val2, long mask) +static int __hts221_read_raw(struct iio_dev *iio_dev, + struct iio_chan_spec const *ch, + int *val, int *val2, long mask) { struct hts221_hw *hw = iio_priv(iio_dev); - int ret; - - ret = iio_device_claim_direct_mode(iio_dev); - if (ret) - return ret; switch (mask) { case IIO_CHAN_INFO_RAW: - ret = hts221_read_oneshot(hw, ch->address, val); - break; + return hts221_read_oneshot(hw, ch->address, val); case IIO_CHAN_INFO_SCALE: - ret = hts221_get_sensor_scale(hw, ch->type, val, val2); - break; + return hts221_get_sensor_scale(hw, ch->type, val, val2); case IIO_CHAN_INFO_OFFSET: - ret = hts221_get_sensor_offset(hw, ch->type, val, val2); - break; + return hts221_get_sensor_offset(hw, ch->type, val, val2); case IIO_CHAN_INFO_SAMP_FREQ: *val = hw->odr; - ret = IIO_VAL_INT; - break; + return IIO_VAL_INT; case IIO_CHAN_INFO_OVERSAMPLING_RATIO: { u8 idx; const struct hts221_avg *avg; @@ -452,64 +443,72 @@ static int hts221_read_raw(struct iio_dev *iio_dev, avg = &hts221_avg_list[HTS221_SENSOR_H]; idx = hw->sensors[HTS221_SENSOR_H].cur_avg_idx; *val = avg->avg_avl[idx]; - ret = IIO_VAL_INT; - break; + return IIO_VAL_INT; case IIO_TEMP: avg = &hts221_avg_list[HTS221_SENSOR_T]; idx = hw->sensors[HTS221_SENSOR_T].cur_avg_idx; *val = avg->avg_avl[idx]; - ret = IIO_VAL_INT; - break; + return IIO_VAL_INT; default: - ret = -EINVAL; - break; + return -EINVAL; } - break; } default: - ret = -EINVAL; - break; + return -EINVAL; } +} + +static int hts221_read_raw(struct iio_dev *iio_dev, + struct iio_chan_spec const *ch, + int *val, int *val2, long mask) +{ + int ret; + + if (!iio_device_claim_direct(iio_dev)) + return -EBUSY; - iio_device_release_direct_mode(iio_dev); + ret = __hts221_read_raw(iio_dev, ch, val, val2, mask); + + iio_device_release_direct(iio_dev); return ret; } -static int hts221_write_raw(struct iio_dev *iio_dev, - struct iio_chan_spec const *chan, - int val, int val2, long mask) +static int __hts221_write_raw(struct iio_dev *iio_dev, + struct iio_chan_spec const *chan, + int val, long mask) { struct hts221_hw *hw = iio_priv(iio_dev); - int ret; - - ret = iio_device_claim_direct_mode(iio_dev); - if (ret) - return ret; switch (mask) { case IIO_CHAN_INFO_SAMP_FREQ: - ret = hts221_update_odr(hw, val); - break; + return hts221_update_odr(hw, val); case IIO_CHAN_INFO_OVERSAMPLING_RATIO: switch (chan->type) { case IIO_HUMIDITYRELATIVE: - ret = hts221_update_avg(hw, HTS221_SENSOR_H, val); - break; + return hts221_update_avg(hw, HTS221_SENSOR_H, val); case IIO_TEMP: - ret = hts221_update_avg(hw, HTS221_SENSOR_T, val); - break; + return hts221_update_avg(hw, HTS221_SENSOR_T, val); default: - ret = -EINVAL; - break; + return -EINVAL; } - break; default: - ret = -EINVAL; - break; + return -EINVAL; } +} + +static int hts221_write_raw(struct iio_dev *iio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + int ret; + + if (!iio_device_claim_direct(iio_dev)) + return -EBUSY; + + ret = __hts221_write_raw(iio_dev, chan, val, mask); - iio_device_release_direct_mode(iio_dev); + iio_device_release_direct(iio_dev); return ret; } diff --git a/drivers/iio/humidity/hts221_i2c.c b/drivers/iio/humidity/hts221_i2c.c index 87a8e3c8d277..cbaa7d1af6c4 100644 --- a/drivers/iio/humidity/hts221_i2c.c +++ b/drivers/iio/humidity/hts221_i2c.c @@ -42,19 +42,19 @@ static int hts221_i2c_probe(struct i2c_client *client) static const struct acpi_device_id hts221_acpi_match[] = { {"SMO9100", 0}, - { }, + { } }; MODULE_DEVICE_TABLE(acpi, hts221_acpi_match); static const struct of_device_id hts221_i2c_of_match[] = { { .compatible = "st,hts221", }, - {}, + { } }; MODULE_DEVICE_TABLE(of, hts221_i2c_of_match); static const struct i2c_device_id hts221_i2c_id_table[] = { { HTS221_DEV_NAME }, - {}, + { } }; MODULE_DEVICE_TABLE(i2c, hts221_i2c_id_table); diff --git a/drivers/iio/humidity/hts221_spi.c b/drivers/iio/humidity/hts221_spi.c index 00154b9d66b5..e6fef2acd523 100644 --- a/drivers/iio/humidity/hts221_spi.c +++ b/drivers/iio/humidity/hts221_spi.c @@ -42,13 +42,13 @@ static int hts221_spi_probe(struct spi_device *spi) static const struct of_device_id hts221_spi_of_match[] = { { .compatible = "st,hts221", }, - {}, + { } }; MODULE_DEVICE_TABLE(of, hts221_spi_of_match); static const struct spi_device_id hts221_spi_id_table[] = { { HTS221_DEV_NAME }, - {}, + { } }; MODULE_DEVICE_TABLE(spi, hts221_spi_id_table); diff --git a/drivers/iio/humidity/htu21.c b/drivers/iio/humidity/htu21.c index 6402e393edb8..7f1775bd26fd 100644 --- a/drivers/iio/humidity/htu21.c +++ b/drivers/iio/humidity/htu21.c @@ -232,14 +232,14 @@ static int htu21_probe(struct i2c_client *client) static const struct i2c_device_id htu21_id[] = { {"htu21", HTU21}, {"ms8607-humidity", MS8607}, - {} + { } }; MODULE_DEVICE_TABLE(i2c, htu21_id); static const struct of_device_id htu21_of_match[] = { { .compatible = "meas,htu21", }, { .compatible = "meas,ms8607-humidity", }, - { }, + { } }; MODULE_DEVICE_TABLE(of, htu21_of_match); diff --git a/drivers/iio/imu/adis.c b/drivers/iio/imu/adis.c index 0ea072a4c966..d160147cce0b 100644 --- a/drivers/iio/imu/adis.c +++ b/drivers/iio/imu/adis.c @@ -39,34 +39,29 @@ int __adis_write_reg(struct adis *adis, unsigned int reg, unsigned int value, struct spi_transfer xfers[] = { { .tx_buf = adis->tx, - .bits_per_word = 8, .len = 2, .cs_change = 1, .delay.value = adis->data->write_delay, .delay.unit = SPI_DELAY_UNIT_USECS, }, { .tx_buf = adis->tx + 2, - .bits_per_word = 8, .len = 2, .cs_change = 1, .delay.value = adis->data->write_delay, .delay.unit = SPI_DELAY_UNIT_USECS, }, { .tx_buf = adis->tx + 4, - .bits_per_word = 8, .len = 2, .cs_change = 1, .delay.value = adis->data->write_delay, .delay.unit = SPI_DELAY_UNIT_USECS, }, { .tx_buf = adis->tx + 6, - .bits_per_word = 8, .len = 2, .delay.value = adis->data->write_delay, .delay.unit = SPI_DELAY_UNIT_USECS, }, { .tx_buf = adis->tx + 8, - .bits_per_word = 8, .len = 2, .delay.value = adis->data->write_delay, .delay.unit = SPI_DELAY_UNIT_USECS, @@ -133,14 +128,12 @@ int __adis_read_reg(struct adis *adis, unsigned int reg, unsigned int *val, struct spi_transfer xfers[] = { { .tx_buf = adis->tx, - .bits_per_word = 8, .len = 2, .cs_change = 1, .delay.value = adis->data->write_delay, .delay.unit = SPI_DELAY_UNIT_USECS, }, { .tx_buf = adis->tx + 2, - .bits_per_word = 8, .len = 2, .cs_change = 1, .delay.value = adis->data->read_delay, @@ -148,14 +141,12 @@ int __adis_read_reg(struct adis *adis, unsigned int reg, unsigned int *val, }, { .tx_buf = adis->tx + 4, .rx_buf = adis->rx, - .bits_per_word = 8, .len = 2, .cs_change = 1, .delay.value = adis->data->read_delay, .delay.unit = SPI_DELAY_UNIT_USECS, }, { .rx_buf = adis->rx + 2, - .bits_per_word = 8, .len = 2, .delay.value = adis->data->read_delay, .delay.unit = SPI_DELAY_UNIT_USECS, diff --git a/drivers/iio/imu/adis16400.c b/drivers/iio/imu/adis16400.c index 3086dd536203..90ed3f9bb39c 100644 --- a/drivers/iio/imu/adis16400.c +++ b/drivers/iio/imu/adis16400.c @@ -1212,7 +1212,7 @@ static const struct spi_device_id adis16400_id[] = { {"adis16405", ADIS16400}, {"adis16445", ADIS16445}, {"adis16448", ADIS16448}, - {} + { } }; MODULE_DEVICE_TABLE(spi, adis16400_id); diff --git a/drivers/iio/imu/adis16460.c b/drivers/iio/imu/adis16460.c index ecf74046fde1..ba1887d36577 100644 --- a/drivers/iio/imu/adis16460.c +++ b/drivers/iio/imu/adis16460.c @@ -395,13 +395,13 @@ static int adis16460_probe(struct spi_device *spi) static const struct spi_device_id adis16460_ids[] = { { "adis16460", 0 }, - {} + { } }; MODULE_DEVICE_TABLE(spi, adis16460_ids); static const struct of_device_id adis16460_of_match[] = { { .compatible = "adi,adis16460" }, - {} + { } }; MODULE_DEVICE_TABLE(of, adis16460_of_match); diff --git a/drivers/iio/imu/adis16475.c b/drivers/iio/imu/adis16475.c index df8c6cd91169..924395b7e3b4 100644 --- a/drivers/iio/imu/adis16475.c +++ b/drivers/iio/imu/adis16475.c @@ -2058,7 +2058,7 @@ static const struct of_device_id adis16475_of_match[] = { .data = &adis16475_chip_info[ADIS16577_2] }, { .compatible = "adi,adis16577-3", .data = &adis16475_chip_info[ADIS16577_3] }, - { }, + { } }; MODULE_DEVICE_TABLE(of, adis16475_of_match); diff --git a/drivers/iio/imu/adis16480.c b/drivers/iio/imu/adis16480.c index 727e0a11eac1..543d5c4bfb11 100644 --- a/drivers/iio/imu/adis16480.c +++ b/drivers/iio/imu/adis16480.c @@ -1852,7 +1852,7 @@ static const struct of_device_id adis16480_of_match[] = { { .compatible = "adi,adis16547-1" }, { .compatible = "adi,adis16547-2" }, { .compatible = "adi,adis16547-3" }, - { }, + { } }; MODULE_DEVICE_TABLE(of, adis16480_of_match); diff --git a/drivers/iio/imu/adis_buffer.c b/drivers/iio/imu/adis_buffer.c index fdfc0538734c..cd3db2388164 100644 --- a/drivers/iio/imu/adis_buffer.c +++ b/drivers/iio/imu/adis_buffer.c @@ -49,12 +49,10 @@ static int adis_update_scan_mode_burst(struct iio_dev *indio_dev, tx[1] = 0; adis->xfer[0].tx_buf = tx; - adis->xfer[0].bits_per_word = 8; adis->xfer[0].len = 2; if (adis->data->burst_max_speed_hz) adis->xfer[0].speed_hz = adis->data->burst_max_speed_hz; adis->xfer[1].rx_buf = adis->buffer; - adis->xfer[1].bits_per_word = 8; adis->xfer[1].len = burst_length; if (adis->data->burst_max_speed_hz) adis->xfer[1].speed_hz = adis->data->burst_max_speed_hz; @@ -100,7 +98,6 @@ int adis_update_scan_mode(struct iio_dev *indio_dev, spi_message_init(&adis->msg); for (j = 0; j <= scan_count; j++) { - adis->xfer[j].bits_per_word = 8; if (j != scan_count) adis->xfer[j].cs_change = 1; adis->xfer[j].len = 2; diff --git a/drivers/iio/imu/bmi160/bmi160_i2c.c b/drivers/iio/imu/bmi160/bmi160_i2c.c index 214503fa4af5..9fa3a19a8977 100644 --- a/drivers/iio/imu/bmi160/bmi160_i2c.c +++ b/drivers/iio/imu/bmi160/bmi160_i2c.c @@ -39,7 +39,7 @@ static int bmi160_i2c_probe(struct i2c_client *client) static const struct i2c_device_id bmi160_i2c_id[] = { { "bmi120" }, { "bmi160" }, - {} + { } }; MODULE_DEVICE_TABLE(i2c, bmi160_i2c_id); @@ -55,14 +55,14 @@ static const struct acpi_device_id bmi160_acpi_match[] = { {"10EC5280", 0}, {"BMI0120", 0}, {"BMI0160", 0}, - { }, + { } }; MODULE_DEVICE_TABLE(acpi, bmi160_acpi_match); static const struct of_device_id bmi160_of_match[] = { { .compatible = "bosch,bmi120" }, { .compatible = "bosch,bmi160" }, - { }, + { } }; MODULE_DEVICE_TABLE(of, bmi160_of_match); diff --git a/drivers/iio/imu/bmi160/bmi160_spi.c b/drivers/iio/imu/bmi160/bmi160_spi.c index 8fbaab22db81..ebb586904215 100644 --- a/drivers/iio/imu/bmi160/bmi160_spi.c +++ b/drivers/iio/imu/bmi160/bmi160_spi.c @@ -36,21 +36,21 @@ static int bmi160_spi_probe(struct spi_device *spi) static const struct spi_device_id bmi160_spi_id[] = { {"bmi120", 0}, {"bmi160", 0}, - {} + { } }; MODULE_DEVICE_TABLE(spi, bmi160_spi_id); static const struct acpi_device_id bmi160_acpi_match[] = { {"BMI0120", 0}, {"BMI0160", 0}, - { }, + { } }; MODULE_DEVICE_TABLE(acpi, bmi160_acpi_match); static const struct of_device_id bmi160_of_match[] = { { .compatible = "bosch,bmi120" }, { .compatible = "bosch,bmi160" }, - { }, + { } }; MODULE_DEVICE_TABLE(of, bmi160_of_match); diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600.h b/drivers/iio/imu/inv_icm42600/inv_icm42600.h index 18787a43477b..f893dbe69965 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600.h +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600.h @@ -426,7 +426,7 @@ int inv_icm42600_set_temp_conf(struct inv_icm42600_state *st, bool enable, int inv_icm42600_debugfs_reg(struct iio_dev *indio_dev, unsigned int reg, unsigned int writeval, unsigned int *readval); -int inv_icm42600_core_probe(struct regmap *regmap, int chip, int irq, +int inv_icm42600_core_probe(struct regmap *regmap, int chip, inv_icm42600_bus_setup bus_setup); struct iio_dev *inv_icm42600_gyro_init(struct inv_icm42600_state *st); diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c index 388520ec60b5..e6cd9dcb0687 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c @@ -157,7 +157,7 @@ static const struct iio_chan_spec_ext_info inv_icm42600_accel_ext_infos[] = { &inv_icm42600_accel_power_mode_enum), IIO_ENUM("power_mode", IIO_SHARED_BY_TYPE, &inv_icm42600_accel_power_mode_enum), - {}, + { } }; static const struct iio_chan_spec inv_icm42600_accel_channels[] = { @@ -685,11 +685,10 @@ static int inv_icm42600_accel_read_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_RAW: - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; ret = inv_icm42600_accel_read_sensor(indio_dev, chan, &data); - iio_device_release_direct_mode(indio_dev); + iio_device_release_direct(indio_dev); if (ret) return ret; *val = data; @@ -747,20 +746,18 @@ static int inv_icm42600_accel_write_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_SCALE: - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; ret = inv_icm42600_accel_write_scale(indio_dev, val, val2); - iio_device_release_direct_mode(indio_dev); + iio_device_release_direct(indio_dev); return ret; case IIO_CHAN_INFO_SAMP_FREQ: return inv_icm42600_accel_write_odr(indio_dev, val, val2); case IIO_CHAN_INFO_CALIBBIAS: - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; ret = inv_icm42600_accel_write_offset(st, chan, val, val2); - iio_device_release_direct_mode(indio_dev); + iio_device_release_direct(indio_dev); return ret; default: return -EINVAL; diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c index ef9875d3b79d..63d46619ebfa 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c @@ -683,12 +683,13 @@ static void inv_icm42600_disable_pm(void *_data) pm_runtime_disable(dev); } -int inv_icm42600_core_probe(struct regmap *regmap, int chip, int irq, +int inv_icm42600_core_probe(struct regmap *regmap, int chip, inv_icm42600_bus_setup bus_setup) { struct device *dev = regmap_get_device(regmap); + struct fwnode_handle *fwnode = dev_fwnode(dev); struct inv_icm42600_state *st; - int irq_type; + int irq, irq_type; bool open_drain; int ret; @@ -697,6 +698,15 @@ int inv_icm42600_core_probe(struct regmap *regmap, int chip, int irq, return -ENODEV; } + /* get INT1 only supported interrupt or fallback to first interrupt */ + irq = fwnode_irq_get_byname(fwnode, "INT1"); + if (irq < 0 && irq != -EPROBE_DEFER) { + dev_info(dev, "no INT1 interrupt defined, fallback to first interrupt\n"); + irq = fwnode_irq_get(fwnode, 0); + } + if (irq < 0) + return dev_err_probe(dev, irq, "error missing INT1 interrupt\n"); + irq_type = irq_get_trigger_type(irq); if (!irq_type) irq_type = IRQF_TRIGGER_FALLING; diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c index 591ed78a55bb..b4d7ce1432a4 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c @@ -57,7 +57,7 @@ enum inv_icm42600_gyro_scan { static const struct iio_chan_spec_ext_info inv_icm42600_gyro_ext_infos[] = { IIO_MOUNT_MATRIX(IIO_SHARED_BY_ALL, inv_icm42600_get_mount_matrix), - {}, + { } }; static const struct iio_chan_spec inv_icm42600_gyro_channels[] = { @@ -591,11 +591,10 @@ static int inv_icm42600_gyro_read_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_RAW: - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; ret = inv_icm42600_gyro_read_sensor(st, chan, &data); - iio_device_release_direct_mode(indio_dev); + iio_device_release_direct(indio_dev); if (ret) return ret; *val = data; @@ -653,20 +652,18 @@ static int inv_icm42600_gyro_write_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_SCALE: - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; ret = inv_icm42600_gyro_write_scale(indio_dev, val, val2); - iio_device_release_direct_mode(indio_dev); + iio_device_release_direct(indio_dev); return ret; case IIO_CHAN_INFO_SAMP_FREQ: return inv_icm42600_gyro_write_odr(indio_dev, val, val2); case IIO_CHAN_INFO_CALIBBIAS: - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; ret = inv_icm42600_gyro_write_offset(st, chan, val, val2); - iio_device_release_direct_mode(indio_dev); + iio_device_release_direct(indio_dev); return ret; default: return -EINVAL; diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c index 04e440fe023a..7e4d3ea68721 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c @@ -67,8 +67,7 @@ static int inv_icm42600_probe(struct i2c_client *client) if (IS_ERR(regmap)) return PTR_ERR(regmap); - return inv_icm42600_core_probe(regmap, chip, client->irq, - inv_icm42600_i2c_bus_setup); + return inv_icm42600_core_probe(regmap, chip, inv_icm42600_i2c_bus_setup); } /* @@ -110,7 +109,7 @@ static const struct of_device_id inv_icm42600_of_matches[] = { .compatible = "invensense,icm42631", .data = (void *)INV_CHIP_ICM42631, }, - {} + { } }; MODULE_DEVICE_TABLE(of, inv_icm42600_of_matches); diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c index 2bd2c4c8e50c..13e2e7d38638 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c @@ -64,8 +64,7 @@ static int inv_icm42600_probe(struct spi_device *spi) if (IS_ERR(regmap)) return PTR_ERR(regmap); - return inv_icm42600_core_probe(regmap, chip, spi->irq, - inv_icm42600_spi_bus_setup); + return inv_icm42600_core_probe(regmap, chip, inv_icm42600_spi_bus_setup); } /* @@ -107,7 +106,7 @@ static const struct of_device_id inv_icm42600_of_matches[] = { .compatible = "invensense,icm42631", .data = (void *)INV_CHIP_ICM42631, }, - {} + { } }; MODULE_DEVICE_TABLE(of, inv_icm42600_of_matches); diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_temp.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_temp.c index 213cce1c3111..988f227f6563 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_temp.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_temp.c @@ -56,27 +56,28 @@ int inv_icm42600_temp_read_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_RAW: - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; ret = inv_icm42600_temp_read(st, &temp); - iio_device_release_direct_mode(indio_dev); + iio_device_release_direct(indio_dev); if (ret) return ret; *val = temp; return IIO_VAL_INT; /* * T°C = (temp / 132.48) + 25 - * Tm°C = 1000 * ((temp * 100 / 13248) + 25) + * Tm°C = 1000 * ((temp / 132.48) + 25) + * Tm°C = 7.548309 * temp + 25000 + * Tm°C = (temp + 3312) * 7.548309 * scale: 100000 / 13248 ~= 7.548309 - * offset: 25000 + * offset: 3312 */ case IIO_CHAN_INFO_SCALE: *val = 7; *val2 = 548309; return IIO_VAL_INT_PLUS_MICRO; case IIO_CHAN_INFO_OFFSET: - *val = 25000; + *val = 3312; return IIO_VAL_INT; default: return -EINVAL; diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c index 373e59f6d91a..a9bcf02e5b43 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c @@ -39,7 +39,7 @@ static const struct dmi_system_id inv_mpu_dev_list[] = { }, }, /* Add more matching tables here..*/ - {} + { } }; static int asus_acpi_get_sensor_info(struct acpi_device *adev, diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c index 5bcd5e797046..b8656c02354a 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c @@ -755,13 +755,12 @@ inv_mpu6050_read_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_RAW: - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; mutex_lock(&st->lock); ret = inv_mpu6050_read_channel_data(indio_dev, chan, val); mutex_unlock(&st->lock); - iio_device_release_direct_mode(indio_dev); + iio_device_release_direct(indio_dev); return ret; case IIO_CHAN_INFO_SCALE: switch (chan->type) { @@ -895,9 +894,8 @@ static int inv_mpu6050_write_raw(struct iio_dev *indio_dev, * we should only update scale when the chip is disabled, i.e. * not running */ - result = iio_device_claim_direct_mode(indio_dev); - if (result) - return result; + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; mutex_lock(&st->lock); result = pm_runtime_resume_and_get(pdev); @@ -944,7 +942,7 @@ static int inv_mpu6050_write_raw(struct iio_dev *indio_dev, pm_runtime_put_autosuspend(pdev); error_write_raw_unlock: mutex_unlock(&st->lock); - iio_device_release_direct_mode(indio_dev); + iio_device_release_direct(indio_dev); return result; } diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c index 91d77f94d204..8dc61812a8fc 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c @@ -192,7 +192,7 @@ static const struct i2c_device_id inv_mpu_id[] = { {"iam20680", INV_IAM20680}, {"iam20680hp", INV_IAM20680HP}, {"iam20680ht", INV_IAM20680HT}, - {} + { } }; MODULE_DEVICE_TABLE(i2c, inv_mpu_id); @@ -276,7 +276,7 @@ MODULE_DEVICE_TABLE(of, inv_of_match); static const struct acpi_device_id inv_acpi_match[] = { {"INVN6500", INV_MPU6500}, - { }, + { } }; MODULE_DEVICE_TABLE(acpi, inv_acpi_match); diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c index 20de6eb5cd35..1f4c62142b60 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c @@ -83,7 +83,7 @@ static const struct spi_device_id inv_mpu_id[] = { {"iam20680", INV_IAM20680}, {"iam20680hp", INV_IAM20680HP}, {"iam20680ht", INV_IAM20680HT}, - {} + { } }; MODULE_DEVICE_TABLE(spi, inv_mpu_id); @@ -163,7 +163,7 @@ MODULE_DEVICE_TABLE(of, inv_of_match); static const struct acpi_device_id inv_acpi_match[] = { {"INVN6000", INV_MPU6000}, - { }, + { } }; MODULE_DEVICE_TABLE(acpi, inv_acpi_match); diff --git a/drivers/iio/imu/kmx61.c b/drivers/iio/imu/kmx61.c index e19c5d3137c6..2bdfb2619137 100644 --- a/drivers/iio/imu/kmx61.c +++ b/drivers/iio/imu/kmx61.c @@ -1487,7 +1487,7 @@ static const struct dev_pm_ops kmx61_pm_ops = { static const struct i2c_device_id kmx61_id[] = { { "kmx611021" }, - {} + { } }; MODULE_DEVICE_TABLE(i2c, kmx61_id); diff --git a/drivers/iio/imu/smi240.c b/drivers/iio/imu/smi240.c index 4492c4d013bd..d159ee59acdd 100644 --- a/drivers/iio/imu/smi240.c +++ b/drivers/iio/imu/smi240.c @@ -414,11 +414,10 @@ static int smi240_read_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_RAW: - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; ret = smi240_get_data(data, chan->type, chan->channel2, val); - iio_device_release_direct_mode(indio_dev); + iio_device_release_direct(indio_dev); if (ret) return ret; return IIO_VAL_INT; diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c index 96c6106b95ee..c65ad49829e7 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c @@ -1804,12 +1804,11 @@ static int st_lsm6dsx_read_raw(struct iio_dev *iio_dev, switch (mask) { case IIO_CHAN_INFO_RAW: - ret = iio_device_claim_direct_mode(iio_dev); - if (ret) - break; + if (!iio_device_claim_direct(iio_dev)) + return -EBUSY; ret = st_lsm6dsx_read_oneshot(sensor, ch->address, val); - iio_device_release_direct_mode(iio_dev); + iio_device_release_direct(iio_dev); break; case IIO_CHAN_INFO_SAMP_FREQ: *val = sensor->odr / 1000; @@ -1834,11 +1833,10 @@ static int st_lsm6dsx_write_raw(struct iio_dev *iio_dev, int val, int val2, long mask) { struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev); - int err; + int err = 0; - err = iio_device_claim_direct_mode(iio_dev); - if (err) - return err; + if (!iio_device_claim_direct(iio_dev)) + return -EBUSY; switch (mask) { case IIO_CHAN_INFO_SCALE: @@ -1860,7 +1858,7 @@ static int st_lsm6dsx_write_raw(struct iio_dev *iio_dev, break; } - iio_device_release_direct_mode(iio_dev); + iio_device_release_direct(iio_dev); return err; } diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c index 25e1de89b6e4..7c933218036b 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c @@ -138,13 +138,13 @@ static const struct of_device_id st_lsm6dsx_i2c_of_match[] = { .compatible = "st,asm330lhhxg1", .data = (void *)ST_ASM330LHHXG1_ID, }, - {}, + { } }; MODULE_DEVICE_TABLE(of, st_lsm6dsx_i2c_of_match); static const struct acpi_device_id st_lsm6dsx_i2c_acpi_match[] = { { "SMO8B30", ST_LSM6DS3TRC_ID, }, - {} + { } }; MODULE_DEVICE_TABLE(acpi, st_lsm6dsx_i2c_acpi_match); @@ -173,7 +173,7 @@ static const struct i2c_device_id st_lsm6dsx_i2c_id_table[] = { { ST_ISM330IS_DEV_NAME, ST_ISM330IS_ID }, { ST_ASM330LHB_DEV_NAME, ST_ASM330LHB_ID }, { ST_ASM330LHHXG1_DEV_NAME, ST_ASM330LHHXG1_ID }, - {}, + { } }; MODULE_DEVICE_TABLE(i2c, st_lsm6dsx_i2c_id_table); diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c index f968f32890d1..cb5c5d7e1f3d 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c @@ -17,7 +17,7 @@ static const struct i3c_device_id st_lsm6dsx_i3c_ids[] = { I3C_DEVICE(0x0104, 0x006C, (void *)ST_LSM6DSO_ID), I3C_DEVICE(0x0104, 0x006B, (void *)ST_LSM6DSR_ID), - { /* sentinel */ }, + { } }; MODULE_DEVICE_TABLE(i3c, st_lsm6dsx_i3c_ids); diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c index c1b444520d2a..3c5e65dc0f97 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c @@ -558,12 +558,11 @@ st_lsm6dsx_shub_read_raw(struct iio_dev *iio_dev, switch (mask) { case IIO_CHAN_INFO_RAW: - ret = iio_device_claim_direct_mode(iio_dev); - if (ret) - break; + if (!iio_device_claim_direct(iio_dev)) + return -EBUSY; ret = st_lsm6dsx_shub_read_oneshot(sensor, ch, val); - iio_device_release_direct_mode(iio_dev); + iio_device_release_direct(iio_dev); break; case IIO_CHAN_INFO_SAMP_FREQ: *val = sensor->ext_info.slv_odr / 1000; @@ -614,53 +613,57 @@ st_lsm6dsx_shub_set_full_scale(struct st_lsm6dsx_sensor *sensor, } static int -st_lsm6dsx_shub_write_raw(struct iio_dev *iio_dev, - struct iio_chan_spec const *chan, - int val, int val2, long mask) +__st_lsm6dsx_shub_write_raw(struct iio_dev *iio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) { struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev); int err; - err = iio_device_claim_direct_mode(iio_dev); - if (err) - return err; - switch (mask) { case IIO_CHAN_INFO_SAMP_FREQ: { + struct st_lsm6dsx_hw *hw = sensor->hw; + struct st_lsm6dsx_sensor *ref_sensor; + u8 odr_val; u16 data; + int odr; val = val * 1000 + val2 / 1000; err = st_lsm6dsx_shub_get_odr_val(sensor, val, &data); - if (!err) { - struct st_lsm6dsx_hw *hw = sensor->hw; - struct st_lsm6dsx_sensor *ref_sensor; - u8 odr_val; - int odr; - - ref_sensor = iio_priv(hw->iio_devs[ST_LSM6DSX_ID_ACC]); - odr = st_lsm6dsx_check_odr(ref_sensor, val, &odr_val); - if (odr < 0) { - err = odr; - goto release; - } - - sensor->ext_info.slv_odr = val; - sensor->odr = odr; - } - break; + if (err) + return err; + + ref_sensor = iio_priv(hw->iio_devs[ST_LSM6DSX_ID_ACC]); + odr = st_lsm6dsx_check_odr(ref_sensor, val, &odr_val); + if (odr < 0) + return odr; + + sensor->ext_info.slv_odr = val; + sensor->odr = odr; + return 0; } case IIO_CHAN_INFO_SCALE: - err = st_lsm6dsx_shub_set_full_scale(sensor, val2); - break; + return st_lsm6dsx_shub_set_full_scale(sensor, val2); default: - err = -EINVAL; - break; + return -EINVAL; } +} + +static int +st_lsm6dsx_shub_write_raw(struct iio_dev *iio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + int ret; -release: - iio_device_release_direct_mode(iio_dev); + if (!iio_device_claim_direct(iio_dev)) + return -EBUSY; - return err; + ret = __st_lsm6dsx_shub_write_raw(iio_dev, chan, val, val2, mask); + + iio_device_release_direct(iio_dev); + + return ret; } static ssize_t diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c index 4b4b6d45524f..3389b15df0bc 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c @@ -133,7 +133,7 @@ static const struct of_device_id st_lsm6dsx_spi_of_match[] = { .compatible = "st,asm330lhhxg1", .data = (void *)ST_ASM330LHHXG1_ID, }, - {}, + { } }; MODULE_DEVICE_TABLE(of, st_lsm6dsx_spi_of_match); @@ -162,7 +162,7 @@ static const struct spi_device_id st_lsm6dsx_spi_id_table[] = { { ST_ISM330IS_DEV_NAME, ST_ISM330IS_ID }, { ST_ASM330LHB_DEV_NAME, ST_ASM330LHB_ID }, { ST_ASM330LHHXG1_DEV_NAME, ST_ASM330LHHXG1_ID }, - {}, + { } }; MODULE_DEVICE_TABLE(spi, st_lsm6dsx_spi_id_table); diff --git a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c index 8cc071463249..4232a9d800fc 100644 --- a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c +++ b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c @@ -28,20 +28,20 @@ static const struct of_device_id st_lsm9ds0_of_match[] = { .compatible = "st,lsm9ds0-imu", .data = LSM9DS0_IMU_DEV_NAME, }, - {} + { } }; MODULE_DEVICE_TABLE(of, st_lsm9ds0_of_match); static const struct i2c_device_id st_lsm9ds0_id_table[] = { { LSM303D_IMU_DEV_NAME }, { LSM9DS0_IMU_DEV_NAME }, - {} + { } }; MODULE_DEVICE_TABLE(i2c, st_lsm9ds0_id_table); static const struct acpi_device_id st_lsm9ds0_acpi_match[] = { {"ACCL0001", (kernel_ulong_t)LSM303D_IMU_DEV_NAME}, - {} + { } }; MODULE_DEVICE_TABLE(acpi, st_lsm9ds0_acpi_match); diff --git a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c index 806e55f75f65..acea8a0757d7 100644 --- a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c +++ b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c @@ -28,14 +28,14 @@ static const struct of_device_id st_lsm9ds0_of_match[] = { .compatible = "st,lsm9ds0-imu", .data = LSM9DS0_IMU_DEV_NAME, }, - {} + { } }; MODULE_DEVICE_TABLE(of, st_lsm9ds0_of_match); static const struct spi_device_id st_lsm9ds0_id_table[] = { { LSM303D_IMU_DEV_NAME }, { LSM9DS0_IMU_DEV_NAME }, - {} + { } }; MODULE_DEVICE_TABLE(spi, st_lsm9ds0_id_table); diff --git a/drivers/iio/industrialio-backend.c b/drivers/iio/industrialio-backend.c index a43c8d1bb3d0..c1eb9ef9db08 100644 --- a/drivers/iio/industrialio-backend.c +++ b/drivers/iio/industrialio-backend.c @@ -381,6 +381,34 @@ int iio_backend_data_source_set(struct iio_backend *back, unsigned int chan, EXPORT_SYMBOL_NS_GPL(iio_backend_data_source_set, "IIO_BACKEND"); /** + * iio_backend_data_source_get - Get current data source + * @back: Backend device + * @chan: Channel number + * @data: Pointer to receive the current source value + * + * A given backend may have different sources to stream/sync data. This allows + * to know what source is in use. + * + * RETURNS: + * 0 on success, negative error number on failure. + */ +int iio_backend_data_source_get(struct iio_backend *back, unsigned int chan, + enum iio_backend_data_source *data) +{ + int ret; + + ret = iio_backend_op_call(back, data_source_get, chan, data); + if (ret) + return ret; + + if (*data >= IIO_BACKEND_DATA_SOURCE_MAX) + return -EINVAL; + + return 0; +} +EXPORT_SYMBOL_NS_GPL(iio_backend_data_source_get, "IIO_BACKEND"); + +/** * iio_backend_set_sampling_freq - Set channel sampling rate * @back: Backend device * @chan: Channel number diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index b9f4113ae5fc..178e99b111de 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -26,6 +26,7 @@ #include <linux/sched.h> #include <linux/slab.h> #include <linux/wait.h> +#include <linux/wordpart.h> #include <linux/iio/buffer.h> #include <linux/iio/buffer_impl.h> @@ -966,8 +967,10 @@ static ssize_t iio_write_channel_info(struct device *dev, struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); int ret, fract_mult = 100000; int integer, fract = 0; + long long integer64; bool is_char = false; bool scale_db = false; + bool is_64bit = false; /* Assumes decimal - precision based on number of digits */ if (!indio_dev->info->write_raw) @@ -991,6 +994,9 @@ static ssize_t iio_write_channel_info(struct device *dev, case IIO_VAL_CHAR: is_char = true; break; + case IIO_VAL_INT_64: + is_64bit = true; + break; default: return -EINVAL; } @@ -1001,6 +1007,13 @@ static ssize_t iio_write_channel_info(struct device *dev, if (sscanf(buf, "%c", &ch) != 1) return -EINVAL; integer = ch; + } else if (is_64bit) { + ret = kstrtoll(buf, 0, &integer64); + if (ret) + return ret; + + fract = upper_32_bits(integer64); + integer = lower_32_bits(integer64); } else { ret = __iio_str_to_fixpoint(buf, fract_mult, &integer, &fract, scale_db); @@ -2144,17 +2157,19 @@ int __devm_iio_device_register(struct device *dev, struct iio_dev *indio_dev, EXPORT_SYMBOL_GPL(__devm_iio_device_register); /** - * iio_device_claim_direct_mode - Keep device in direct mode + * __iio_device_claim_direct - Keep device in direct mode * @indio_dev: the iio_dev associated with the device * * If the device is in direct mode it is guaranteed to stay - * that way until iio_device_release_direct_mode() is called. + * that way until __iio_device_release_direct() is called. * - * Use with iio_device_release_direct_mode() + * Use with __iio_device_release_direct(). * - * Returns: 0 on success, -EBUSY on failure. + * Drivers should only call iio_device_claim_direct(). + * + * Returns: true on success, false on failure. */ -int iio_device_claim_direct_mode(struct iio_dev *indio_dev) +bool __iio_device_claim_direct(struct iio_dev *indio_dev) { struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); @@ -2162,26 +2177,28 @@ int iio_device_claim_direct_mode(struct iio_dev *indio_dev) if (iio_buffer_enabled(indio_dev)) { mutex_unlock(&iio_dev_opaque->mlock); - return -EBUSY; + return false; } - return 0; + return true; } -EXPORT_SYMBOL_GPL(iio_device_claim_direct_mode); +EXPORT_SYMBOL_GPL(__iio_device_claim_direct); /** - * iio_device_release_direct_mode - releases claim on direct mode + * __iio_device_release_direct - releases claim on direct mode * @indio_dev: the iio_dev associated with the device * * Release the claim. Device is no longer guaranteed to stay * in direct mode. * - * Use with iio_device_claim_direct_mode() + * Drivers should only call iio_device_release_direct(). + * + * Use with __iio_device_claim_direct() */ -void iio_device_release_direct_mode(struct iio_dev *indio_dev) +void __iio_device_release_direct(struct iio_dev *indio_dev) { mutex_unlock(&to_iio_dev_opaque(indio_dev)->mlock); } -EXPORT_SYMBOL_GPL(iio_device_release_direct_mode); +EXPORT_SYMBOL_GPL(__iio_device_release_direct); /** * iio_device_claim_buffer_mode - Keep device in buffer mode diff --git a/drivers/iio/light/acpi-als.c b/drivers/iio/light/acpi-als.c index 2d91caf24dd0..032e6cae8b80 100644 --- a/drivers/iio/light/acpi-als.c +++ b/drivers/iio/light/acpi-als.c @@ -230,7 +230,7 @@ static int acpi_als_add(struct acpi_device *device) static const struct acpi_device_id acpi_als_device_ids[] = { {"ACPI0008", 0}, - {}, + { } }; MODULE_DEVICE_TABLE(acpi, acpi_als_device_ids); diff --git a/drivers/iio/light/adux1020.c b/drivers/iio/light/adux1020.c index 9240983a6cc4..e321f89c5340 100644 --- a/drivers/iio/light/adux1020.c +++ b/drivers/iio/light/adux1020.c @@ -820,7 +820,7 @@ static int adux1020_probe(struct i2c_client *client) static const struct i2c_device_id adux1020_id[] = { { "adux1020" }, - {} + { } }; MODULE_DEVICE_TABLE(i2c, adux1020_id); diff --git a/drivers/iio/light/al3000a.c b/drivers/iio/light/al3000a.c index e2fbb1270040..6f301c067045 100644 --- a/drivers/iio/light/al3000a.c +++ b/drivers/iio/light/al3000a.c @@ -85,12 +85,17 @@ static void al3000a_set_pwr_off(void *_data) static int al3000a_init(struct al3000a_data *data) { + struct device *dev = regmap_get_device(data->regmap); int ret; ret = al3000a_set_pwr_on(data); if (ret) return ret; + ret = devm_add_action_or_reset(dev, al3000a_set_pwr_off, data); + if (ret) + return dev_err_probe(dev, ret, "failed to add action\n"); + ret = regmap_write(data->regmap, AL3000A_REG_SYSTEM, AL3000A_CONFIG_RESET); if (ret) return ret; @@ -157,10 +162,6 @@ static int al3000a_probe(struct i2c_client *client) if (ret) return dev_err_probe(dev, ret, "failed to init ALS\n"); - ret = devm_add_action_or_reset(dev, al3000a_set_pwr_off, data); - if (ret) - return dev_err_probe(dev, ret, "failed to add action\n"); - return devm_iio_device_register(dev, indio_dev); } @@ -189,7 +190,7 @@ MODULE_DEVICE_TABLE(i2c, al3000a_id); static const struct of_device_id al3000a_of_match[] = { { .compatible = "dynaimage,al3000a" }, - { /* sentinel */ } + { } }; MODULE_DEVICE_TABLE(of, al3000a_of_match); diff --git a/drivers/iio/light/al3010.c b/drivers/iio/light/al3010.c index 7cbb8b203300..0932fa2b49fa 100644 --- a/drivers/iio/light/al3010.c +++ b/drivers/iio/light/al3010.c @@ -17,13 +17,12 @@ #include <linux/bitfield.h> #include <linux/i2c.h> #include <linux/module.h> +#include <linux/regmap.h> #include <linux/mod_devicetable.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> -#define AL3010_DRV_NAME "al3010" - #define AL3010_REG_SYSTEM 0x00 #define AL3010_REG_DATA_LOW 0x0c #define AL3010_REG_CONFIG 0x10 @@ -46,8 +45,14 @@ static const int al3010_scales[][2] = { {0, 1187200}, {0, 296800}, {0, 74200}, {0, 18600} }; +static const struct regmap_config al3010_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = AL3010_REG_CONFIG, +}; + struct al3010_data { - struct i2c_client *client; + struct regmap *regmap; }; static const struct iio_chan_spec al3010_channels[] = { @@ -69,40 +74,36 @@ static const struct attribute_group al3010_attribute_group = { .attrs = al3010_attributes, }; -static int al3010_set_pwr(struct i2c_client *client, bool pwr) +static int al3010_set_pwr_on(struct al3010_data *data) { - u8 val = pwr ? AL3010_CONFIG_ENABLE : AL3010_CONFIG_DISABLE; - return i2c_smbus_write_byte_data(client, AL3010_REG_SYSTEM, val); + return regmap_write(data->regmap, AL3010_REG_SYSTEM, AL3010_CONFIG_ENABLE); } static void al3010_set_pwr_off(void *_data) { struct al3010_data *data = _data; + struct device *dev = regmap_get_device(data->regmap); + int ret; - al3010_set_pwr(data->client, false); + ret = regmap_write(data->regmap, AL3010_REG_SYSTEM, AL3010_CONFIG_DISABLE); + if (ret) + dev_err(dev, "failed to write system register\n"); } static int al3010_init(struct al3010_data *data) { + struct device *dev = regmap_get_device(data->regmap); int ret; - ret = al3010_set_pwr(data->client, true); - if (ret < 0) + ret = al3010_set_pwr_on(data); + if (ret) return ret; - ret = devm_add_action_or_reset(&data->client->dev, - al3010_set_pwr_off, - data); - if (ret < 0) + ret = devm_add_action_or_reset(dev, al3010_set_pwr_off, data); + if (ret) return ret; - - ret = i2c_smbus_write_byte_data(data->client, AL3010_REG_CONFIG, - FIELD_PREP(AL3010_GAIN_MASK, - AL3XXX_RANGE_3)); - if (ret < 0) - return ret; - - return 0; + return regmap_write(data->regmap, AL3010_REG_CONFIG, + FIELD_PREP(AL3010_GAIN_MASK, AL3XXX_RANGE_3)); } static int al3010_read_raw(struct iio_dev *indio_dev, @@ -110,7 +111,7 @@ static int al3010_read_raw(struct iio_dev *indio_dev, int *val2, long mask) { struct al3010_data *data = iio_priv(indio_dev); - int ret; + int ret, gain, raw; switch (mask) { case IIO_CHAN_INFO_RAW: @@ -119,21 +120,21 @@ static int al3010_read_raw(struct iio_dev *indio_dev, * - low byte of output is stored at AL3010_REG_DATA_LOW * - high byte of output is stored at AL3010_REG_DATA_LOW + 1 */ - ret = i2c_smbus_read_word_data(data->client, - AL3010_REG_DATA_LOW); - if (ret < 0) + ret = regmap_read(data->regmap, AL3010_REG_DATA_LOW, &raw); + if (ret) return ret; - *val = ret; + + *val = raw; + return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: - ret = i2c_smbus_read_byte_data(data->client, - AL3010_REG_CONFIG); - if (ret < 0) + ret = regmap_read(data->regmap, AL3010_REG_CONFIG, &gain); + if (ret) return ret; - ret = FIELD_GET(AL3010_GAIN_MASK, ret); - *val = al3010_scales[ret][0]; - *val2 = al3010_scales[ret][1]; + gain = FIELD_GET(AL3010_GAIN_MASK, gain); + *val = al3010_scales[gain][0]; + *val2 = al3010_scales[gain][1]; return IIO_VAL_INT_PLUS_MICRO; } @@ -145,7 +146,7 @@ static int al3010_write_raw(struct iio_dev *indio_dev, int val2, long mask) { struct al3010_data *data = iio_priv(indio_dev); - int i; + unsigned int i; switch (mask) { case IIO_CHAN_INFO_SCALE: @@ -154,9 +155,8 @@ static int al3010_write_raw(struct iio_dev *indio_dev, val2 != al3010_scales[i][1]) continue; - return i2c_smbus_write_byte_data(data->client, - AL3010_REG_CONFIG, - FIELD_PREP(AL3010_GAIN_MASK, i)); + return regmap_write(data->regmap, AL3010_REG_CONFIG, + FIELD_PREP(AL3010_GAIN_MASK, i)); } break; } @@ -172,59 +172,66 @@ static const struct iio_info al3010_info = { static int al3010_probe(struct i2c_client *client) { struct al3010_data *data; + struct device *dev = &client->dev; struct iio_dev *indio_dev; int ret; - indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); + indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); if (!indio_dev) return -ENOMEM; data = iio_priv(indio_dev); i2c_set_clientdata(client, indio_dev); - data->client = client; + data->regmap = devm_regmap_init_i2c(client, &al3010_regmap_config); + if (IS_ERR(data->regmap)) + return dev_err_probe(dev, PTR_ERR(data->regmap), + "cannot allocate regmap\n"); indio_dev->info = &al3010_info; - indio_dev->name = AL3010_DRV_NAME; + indio_dev->name = "al3010"; indio_dev->channels = al3010_channels; indio_dev->num_channels = ARRAY_SIZE(al3010_channels); indio_dev->modes = INDIO_DIRECT_MODE; ret = al3010_init(data); - if (ret < 0) { - dev_err(&client->dev, "al3010 chip init failed\n"); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "failed to init ALS\n"); - return devm_iio_device_register(&client->dev, indio_dev); + return devm_iio_device_register(dev, indio_dev); } static int al3010_suspend(struct device *dev) { - return al3010_set_pwr(to_i2c_client(dev), false); + struct al3010_data *data = iio_priv(dev_get_drvdata(dev)); + + al3010_set_pwr_off(data); + return 0; } static int al3010_resume(struct device *dev) { - return al3010_set_pwr(to_i2c_client(dev), true); + struct al3010_data *data = iio_priv(dev_get_drvdata(dev)); + + return al3010_set_pwr_on(data); } static DEFINE_SIMPLE_DEV_PM_OPS(al3010_pm_ops, al3010_suspend, al3010_resume); static const struct i2c_device_id al3010_id[] = { {"al3010", }, - {} + { } }; MODULE_DEVICE_TABLE(i2c, al3010_id); static const struct of_device_id al3010_of_match[] = { { .compatible = "dynaimage,al3010", }, - {}, + { } }; MODULE_DEVICE_TABLE(of, al3010_of_match); static struct i2c_driver al3010_driver = { .driver = { - .name = AL3010_DRV_NAME, + .name = "al3010", .of_match_table = al3010_of_match, .pm = pm_sleep_ptr(&al3010_pm_ops), }, diff --git a/drivers/iio/light/al3320a.c b/drivers/iio/light/al3320a.c index 497ea3fe3377..63f5a85912fc 100644 --- a/drivers/iio/light/al3320a.c +++ b/drivers/iio/light/al3320a.c @@ -15,13 +15,12 @@ #include <linux/bitfield.h> #include <linux/i2c.h> #include <linux/module.h> +#include <linux/regmap.h> #include <linux/mod_devicetable.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> -#define AL3320A_DRV_NAME "al3320a" - #define AL3320A_REG_CONFIG 0x00 #define AL3320A_REG_STATUS 0x01 #define AL3320A_REG_INT 0x02 @@ -59,8 +58,14 @@ static const int al3320a_scales[][2] = { {0, 512000}, {0, 128000}, {0, 32000}, {0, 10000} }; +static const struct regmap_config al3320a_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = AL3320A_REG_HIGH_THRESH_HIGH, +}; + struct al3320a_data { - struct i2c_client *client; + struct regmap *regmap; }; static const struct iio_chan_spec al3320a_channels[] = { @@ -82,45 +87,47 @@ static const struct attribute_group al3320a_attribute_group = { .attrs = al3320a_attributes, }; -static int al3320a_set_pwr(struct i2c_client *client, bool pwr) +static int al3320a_set_pwr_on(struct al3320a_data *data) { - u8 val = pwr ? AL3320A_CONFIG_ENABLE : AL3320A_CONFIG_DISABLE; - return i2c_smbus_write_byte_data(client, AL3320A_REG_CONFIG, val); + return regmap_write(data->regmap, AL3320A_REG_CONFIG, AL3320A_CONFIG_ENABLE); } static void al3320a_set_pwr_off(void *_data) { struct al3320a_data *data = _data; + struct device *dev = regmap_get_device(data->regmap); + int ret; - al3320a_set_pwr(data->client, false); + ret = regmap_write(data->regmap, AL3320A_REG_CONFIG, AL3320A_CONFIG_DISABLE); + if (ret) + dev_err(dev, "failed to write system register\n"); } static int al3320a_init(struct al3320a_data *data) { + struct device *dev = regmap_get_device(data->regmap); int ret; - ret = al3320a_set_pwr(data->client, true); - - if (ret < 0) + ret = al3320a_set_pwr_on(data); + if (ret) return ret; - ret = i2c_smbus_write_byte_data(data->client, AL3320A_REG_CONFIG_RANGE, - FIELD_PREP(AL3320A_GAIN_MASK, - AL3320A_RANGE_3)); - if (ret < 0) + ret = devm_add_action_or_reset(dev, al3320a_set_pwr_off, data); + if (ret) return ret; - ret = i2c_smbus_write_byte_data(data->client, AL3320A_REG_MEAN_TIME, - AL3320A_DEFAULT_MEAN_TIME); - if (ret < 0) + ret = regmap_write(data->regmap, AL3320A_REG_CONFIG_RANGE, + FIELD_PREP(AL3320A_GAIN_MASK, AL3320A_RANGE_3)); + if (ret) return ret; - ret = i2c_smbus_write_byte_data(data->client, AL3320A_REG_WAIT, - AL3320A_DEFAULT_WAIT_TIME); - if (ret < 0) + ret = regmap_write(data->regmap, AL3320A_REG_MEAN_TIME, + AL3320A_DEFAULT_MEAN_TIME); + if (ret) return ret; - return 0; + return regmap_write(data->regmap, AL3320A_REG_WAIT, + AL3320A_DEFAULT_WAIT_TIME); } static int al3320a_read_raw(struct iio_dev *indio_dev, @@ -128,7 +135,7 @@ static int al3320a_read_raw(struct iio_dev *indio_dev, int *val2, long mask) { struct al3320a_data *data = iio_priv(indio_dev); - int ret; + int ret, gain, raw; switch (mask) { case IIO_CHAN_INFO_RAW: @@ -137,21 +144,21 @@ static int al3320a_read_raw(struct iio_dev *indio_dev, * - low byte of output is stored at AL3320A_REG_DATA_LOW * - high byte of output is stored at AL3320A_REG_DATA_LOW + 1 */ - ret = i2c_smbus_read_word_data(data->client, - AL3320A_REG_DATA_LOW); - if (ret < 0) + ret = regmap_read(data->regmap, AL3320A_REG_DATA_LOW, &raw); + if (ret) return ret; - *val = ret; + + *val = raw; + return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: - ret = i2c_smbus_read_byte_data(data->client, - AL3320A_REG_CONFIG_RANGE); - if (ret < 0) + ret = regmap_read(data->regmap, AL3320A_REG_CONFIG_RANGE, &gain); + if (ret) return ret; - ret = FIELD_GET(AL3320A_GAIN_MASK, ret); - *val = al3320a_scales[ret][0]; - *val2 = al3320a_scales[ret][1]; + gain = FIELD_GET(AL3320A_GAIN_MASK, gain); + *val = al3320a_scales[gain][0]; + *val2 = al3320a_scales[gain][1]; return IIO_VAL_INT_PLUS_MICRO; } @@ -163,7 +170,7 @@ static int al3320a_write_raw(struct iio_dev *indio_dev, int val2, long mask) { struct al3320a_data *data = iio_priv(indio_dev); - int i; + unsigned int i; switch (mask) { case IIO_CHAN_INFO_SCALE: @@ -172,9 +179,8 @@ static int al3320a_write_raw(struct iio_dev *indio_dev, val2 != al3320a_scales[i][1]) continue; - return i2c_smbus_write_byte_data(data->client, - AL3320A_REG_CONFIG_RANGE, - FIELD_PREP(AL3320A_GAIN_MASK, i)); + return regmap_write(data->regmap, AL3320A_REG_CONFIG_RANGE, + FIELD_PREP(AL3320A_GAIN_MASK, i)); } break; } @@ -190,46 +196,50 @@ static const struct iio_info al3320a_info = { static int al3320a_probe(struct i2c_client *client) { struct al3320a_data *data; + struct device *dev = &client->dev; struct iio_dev *indio_dev; int ret; - indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); + indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); if (!indio_dev) return -ENOMEM; data = iio_priv(indio_dev); i2c_set_clientdata(client, indio_dev); - data->client = client; + + data->regmap = devm_regmap_init_i2c(client, &al3320a_regmap_config); + if (IS_ERR(data->regmap)) + return dev_err_probe(dev, PTR_ERR(data->regmap), + "cannot allocate regmap\n"); indio_dev->info = &al3320a_info; - indio_dev->name = AL3320A_DRV_NAME; + indio_dev->name = "al3320a"; indio_dev->channels = al3320a_channels; indio_dev->num_channels = ARRAY_SIZE(al3320a_channels); indio_dev->modes = INDIO_DIRECT_MODE; ret = al3320a_init(data); if (ret < 0) { - dev_err(&client->dev, "al3320a chip init failed\n"); + dev_err(dev, "al3320a chip init failed\n"); return ret; } - ret = devm_add_action_or_reset(&client->dev, - al3320a_set_pwr_off, - data); - if (ret < 0) - return ret; - - return devm_iio_device_register(&client->dev, indio_dev); + return devm_iio_device_register(dev, indio_dev); } static int al3320a_suspend(struct device *dev) { - return al3320a_set_pwr(to_i2c_client(dev), false); + struct al3320a_data *data = iio_priv(dev_get_drvdata(dev)); + + al3320a_set_pwr_off(data); + return 0; } static int al3320a_resume(struct device *dev) { - return al3320a_set_pwr(to_i2c_client(dev), true); + struct al3320a_data *data = iio_priv(dev_get_drvdata(dev)); + + return al3320a_set_pwr_on(data); } static DEFINE_SIMPLE_DEV_PM_OPS(al3320a_pm_ops, al3320a_suspend, @@ -237,25 +247,25 @@ static DEFINE_SIMPLE_DEV_PM_OPS(al3320a_pm_ops, al3320a_suspend, static const struct i2c_device_id al3320a_id[] = { { "al3320a" }, - {} + { } }; MODULE_DEVICE_TABLE(i2c, al3320a_id); static const struct of_device_id al3320a_of_match[] = { { .compatible = "dynaimage,al3320a", }, - {}, + { } }; MODULE_DEVICE_TABLE(of, al3320a_of_match); static const struct acpi_device_id al3320a_acpi_match[] = { {"CALS0001"}, - { }, + { } }; MODULE_DEVICE_TABLE(acpi, al3320a_acpi_match); static struct i2c_driver al3320a_driver = { .driver = { - .name = AL3320A_DRV_NAME, + .name = "al3320a", .of_match_table = al3320a_of_match, .pm = pm_sleep_ptr(&al3320a_pm_ops), .acpi_match_table = al3320a_acpi_match, diff --git a/drivers/iio/light/apds9306.c b/drivers/iio/light/apds9306.c index 5ed7e17f49e7..e9b237de180a 100644 --- a/drivers/iio/light/apds9306.c +++ b/drivers/iio/light/apds9306.c @@ -831,11 +831,10 @@ static int apds9306_read_raw(struct iio_dev *indio_dev, * Changing device parameters during adc operation, resets * the ADC which has to avoided. */ - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; ret = apds9306_read_data(data, val, reg); - iio_device_release_direct_mode(indio_dev); + iio_device_release_direct(indio_dev); if (ret) return ret; diff --git a/drivers/iio/light/apds9960.c b/drivers/iio/light/apds9960.c index d30441d33703..0003a29bf264 100644 --- a/drivers/iio/light/apds9960.c +++ b/drivers/iio/light/apds9960.c @@ -1157,7 +1157,7 @@ static const struct dev_pm_ops apds9960_pm_ops = { static const struct i2c_device_id apds9960_id[] = { { "apds9960" }, - {} + { } }; MODULE_DEVICE_TABLE(i2c, apds9960_id); diff --git a/drivers/iio/light/as73211.c b/drivers/iio/light/as73211.c index 37fffce35dd1..68f60dc3c79d 100644 --- a/drivers/iio/light/as73211.c +++ b/drivers/iio/light/as73211.c @@ -16,6 +16,7 @@ */ #include <linux/bitfield.h> +#include <linux/cleanup.h> #include <linux/completion.h> #include <linux/delay.h> #include <linux/i2c.h> @@ -418,18 +419,17 @@ static int as73211_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec cons case IIO_CHAN_INFO_RAW: { int ret; - ret = iio_device_claim_direct_mode(indio_dev); - if (ret < 0) - return ret; + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; ret = as73211_req_data(data); if (ret < 0) { - iio_device_release_direct_mode(indio_dev); + iio_device_release_direct(indio_dev); return ret; } ret = i2c_smbus_read_word_data(data->client, chan->address); - iio_device_release_direct_mode(indio_dev); + iio_device_release_direct(indio_dev); if (ret < 0) return ret; @@ -517,6 +517,16 @@ static int _as73211_write_raw(struct iio_dev *indio_dev, struct as73211_data *data = iio_priv(indio_dev); int ret; + /* Need to switch to config mode ... */ + if ((data->osr & AS73211_OSR_DOS_MASK) != AS73211_OSR_DOS_CONFIG) { + data->osr &= ~AS73211_OSR_DOS_MASK; + data->osr |= AS73211_OSR_DOS_CONFIG; + + ret = i2c_smbus_write_byte_data(data->client, AS73211_REG_OSR, data->osr); + if (ret < 0) + return ret; + } + switch (mask) { case IIO_CHAN_INFO_SAMP_FREQ: { int reg_bits, freq_kHz = val / HZ_PER_KHZ; /* 1024, 2048, ... */ @@ -601,28 +611,14 @@ static int as73211_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec con struct as73211_data *data = iio_priv(indio_dev); int ret; - mutex_lock(&data->mutex); - - ret = iio_device_claim_direct_mode(indio_dev); - if (ret < 0) - goto error_unlock; - - /* Need to switch to config mode ... */ - if ((data->osr & AS73211_OSR_DOS_MASK) != AS73211_OSR_DOS_CONFIG) { - data->osr &= ~AS73211_OSR_DOS_MASK; - data->osr |= AS73211_OSR_DOS_CONFIG; + guard(mutex)(&data->mutex); - ret = i2c_smbus_write_byte_data(data->client, AS73211_REG_OSR, data->osr); - if (ret < 0) - goto error_release; - } + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; ret = _as73211_write_raw(indio_dev, chan, val, val2, mask); + iio_device_release_direct(indio_dev); -error_release: - iio_device_release_direct_mode(indio_dev); -error_unlock: - mutex_unlock(&data->mutex); return ret; } diff --git a/drivers/iio/light/bh1750.c b/drivers/iio/light/bh1750.c index 4b869fa9e5b1..764f88826fcb 100644 --- a/drivers/iio/light/bh1750.c +++ b/drivers/iio/light/bh1750.c @@ -22,12 +22,16 @@ #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> #include <linux/module.h> +#include <linux/gpio/consumer.h> #define BH1750_POWER_DOWN 0x00 #define BH1750_ONE_TIME_H_RES_MODE 0x20 /* auto-mode for BH1721 */ #define BH1750_CHANGE_INT_TIME_H_BIT 0x40 #define BH1750_CHANGE_INT_TIME_L_BIT 0x60 +/* Define the reset delay time in microseconds */ +#define BH1750_RESET_DELAY_US 10000 /* 10ms */ + enum { BH1710, BH1721, @@ -40,6 +44,7 @@ struct bh1750_data { struct mutex lock; const struct bh1750_chip_info *chip_info; u16 mtreg; + struct gpio_desc *reset_gpio; }; struct bh1750_chip_info { @@ -248,6 +253,25 @@ static int bh1750_probe(struct i2c_client *client) data->client = client; data->chip_info = &bh1750_chip_info_tbl[id->driver_data]; + /* Get reset GPIO from device tree */ + data->reset_gpio = devm_gpiod_get_optional(&client->dev, + "reset", GPIOD_OUT_HIGH); + + if (IS_ERR(data->reset_gpio)) + return dev_err_probe(&client->dev, PTR_ERR(data->reset_gpio), + "Failed to get reset GPIO\n"); + + /* Perform hardware reset if GPIO is provided */ + if (data->reset_gpio) { + /* Perform reset sequence: low-high */ + gpiod_set_value_cansleep(data->reset_gpio, 1); + fsleep(BH1750_RESET_DELAY_US); + gpiod_set_value_cansleep(data->reset_gpio, 0); + fsleep(BH1750_RESET_DELAY_US); + + dev_dbg(&client->dev, "BH1750 reset completed via GPIO\n"); + } + usec = data->chip_info->mtreg_to_usec * data->chip_info->mtreg_default; ret = bh1750_change_int_time(data, usec); if (ret < 0) diff --git a/drivers/iio/light/bh1780.c b/drivers/iio/light/bh1780.c index 475f44954f61..c7c877d2fe67 100644 --- a/drivers/iio/light/bh1780.c +++ b/drivers/iio/light/bh1780.c @@ -264,7 +264,7 @@ MODULE_DEVICE_TABLE(i2c, bh1780_id); static const struct of_device_id of_bh1780_match[] = { { .compatible = "rohm,bh1780gli", }, - {}, + { } }; MODULE_DEVICE_TABLE(of, of_bh1780_match); diff --git a/drivers/iio/light/cm3232.c b/drivers/iio/light/cm3232.c index 5b00ad2a014e..e864d2ef036e 100644 --- a/drivers/iio/light/cm3232.c +++ b/drivers/iio/light/cm3232.c @@ -369,7 +369,7 @@ static void cm3232_remove(struct i2c_client *client) static const struct i2c_device_id cm3232_id[] = { { "cm3232" }, - {} + { } }; static int cm3232_suspend(struct device *dev) @@ -406,7 +406,7 @@ MODULE_DEVICE_TABLE(i2c, cm3232_id); static const struct of_device_id cm3232_of_match[] = { {.compatible = "capella,cm3232"}, - {} + { } }; MODULE_DEVICE_TABLE(of, cm3232_of_match); diff --git a/drivers/iio/light/cm3323.c b/drivers/iio/light/cm3323.c index 79a64e2ff812..79ad6e2209ca 100644 --- a/drivers/iio/light/cm3323.c +++ b/drivers/iio/light/cm3323.c @@ -251,13 +251,13 @@ static int cm3323_probe(struct i2c_client *client) static const struct i2c_device_id cm3323_id[] = { { "cm3323" }, - {} + { } }; MODULE_DEVICE_TABLE(i2c, cm3323_id); static const struct of_device_id cm3323_of_match[] = { { .compatible = "capella,cm3323", }, - { /* sentinel */ } + { } }; MODULE_DEVICE_TABLE(of, cm3323_of_match); diff --git a/drivers/iio/light/cm3605.c b/drivers/iio/light/cm3605.c index 675c0fd44db4..0c17378e27d1 100644 --- a/drivers/iio/light/cm3605.c +++ b/drivers/iio/light/cm3605.c @@ -307,7 +307,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(cm3605_dev_pm_ops, cm3605_pm_suspend, static const struct of_device_id cm3605_of_match[] = { {.compatible = "capella,cm3605"}, - { }, + { } }; MODULE_DEVICE_TABLE(of, cm3605_of_match); diff --git a/drivers/iio/light/cros_ec_light_prox.c b/drivers/iio/light/cros_ec_light_prox.c index 19e529c84e95..815806ceb5c8 100644 --- a/drivers/iio/light/cros_ec_light_prox.c +++ b/drivers/iio/light/cros_ec_light_prox.c @@ -249,7 +249,7 @@ static const struct platform_device_id cros_ec_light_prox_ids[] = { { .name = "cros-ec-light", }, - { /* sentinel */ } + { } }; MODULE_DEVICE_TABLE(platform, cros_ec_light_prox_ids); diff --git a/drivers/iio/light/gp2ap002.c b/drivers/iio/light/gp2ap002.c index d56ee217fe53..42859e5b1089 100644 --- a/drivers/iio/light/gp2ap002.c +++ b/drivers/iio/light/gp2ap002.c @@ -700,7 +700,7 @@ MODULE_DEVICE_TABLE(i2c, gp2ap002_id_table); static const struct of_device_id gp2ap002_of_match[] = { { .compatible = "sharp,gp2ap002a00f" }, { .compatible = "sharp,gp2ap002s00f" }, - { }, + { } }; MODULE_DEVICE_TABLE(of, gp2ap002_of_match); diff --git a/drivers/iio/light/gp2ap020a00f.c b/drivers/iio/light/gp2ap020a00f.c index 1a352c88598e..c7df4b258e2c 100644 --- a/drivers/iio/light/gp2ap020a00f.c +++ b/drivers/iio/light/gp2ap020a00f.c @@ -1283,12 +1283,11 @@ static int gp2ap020a00f_read_raw(struct iio_dev *indio_dev, int err = -EINVAL; if (mask == IIO_CHAN_INFO_RAW) { - err = iio_device_claim_direct_mode(indio_dev); - if (err) - return err; + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; err = gp2ap020a00f_read_channel(data, chan, val); - iio_device_release_direct_mode(indio_dev); + iio_device_release_direct(indio_dev); } return err < 0 ? err : IIO_VAL_INT; } diff --git a/drivers/iio/light/hid-sensor-als.c b/drivers/iio/light/hid-sensor-als.c index aa4c72d4849e..830e5ae7f34a 100644 --- a/drivers/iio/light/hid-sensor-als.c +++ b/drivers/iio/light/hid-sensor-als.c @@ -456,7 +456,7 @@ static const struct platform_device_id hid_als_ids[] = { /* Format: HID-SENSOR-custom_sensor_tag-usage_id_in_hex_lowercase */ .name = "HID-SENSOR-LISS-0041", }, - { /* sentinel */ } + { } }; MODULE_DEVICE_TABLE(platform, hid_als_ids); diff --git a/drivers/iio/light/hid-sensor-prox.c b/drivers/iio/light/hid-sensor-prox.c index 4c65b32d34ce..efa904a70d0e 100644 --- a/drivers/iio/light/hid-sensor-prox.c +++ b/drivers/iio/light/hid-sensor-prox.c @@ -215,6 +215,9 @@ static int prox_capture_sample(struct hid_sensor_hub_device *hsdev, case 1: prox_state->human_presence[chan] = *(u8 *)raw_data * multiplier; return 0; + case 2: + prox_state->human_presence[chan] = *(u16 *)raw_data * multiplier; + return 0; case 4: prox_state->human_presence[chan] = *(u32 *)raw_data * multiplier; return 0; @@ -362,7 +365,7 @@ static const struct platform_device_id hid_prox_ids[] = { /* Format: HID-SENSOR-tag-usage_id_in_hex_lowercase */ .name = "HID-SENSOR-LISS-0226", }, - { /* sentinel */ } + { } }; MODULE_DEVICE_TABLE(platform, hid_prox_ids); diff --git a/drivers/iio/light/isl29018.c b/drivers/iio/light/isl29018.c index 201eae1c4589..1b4c18423048 100644 --- a/drivers/iio/light/isl29018.c +++ b/drivers/iio/light/isl29018.c @@ -824,7 +824,7 @@ static const struct acpi_device_id isl29018_acpi_match[] = { {"ISL29018", isl29018}, {"ISL29023", isl29023}, {"ISL29035", isl29035}, - {} + { } }; MODULE_DEVICE_TABLE(acpi, isl29018_acpi_match); @@ -832,7 +832,7 @@ static const struct i2c_device_id isl29018_id[] = { {"isl29018", isl29018}, {"isl29023", isl29023}, {"isl29035", isl29035}, - {} + { } }; MODULE_DEVICE_TABLE(i2c, isl29018_id); diff --git a/drivers/iio/light/isl29028.c b/drivers/iio/light/isl29028.c index 95bfb3ffa519..609ebf0f7313 100644 --- a/drivers/iio/light/isl29028.c +++ b/drivers/iio/light/isl29028.c @@ -680,7 +680,7 @@ static DEFINE_RUNTIME_DEV_PM_OPS(isl29028_pm_ops, isl29028_suspend, static const struct i2c_device_id isl29028_id[] = { { "isl29028" }, { "isl29030" }, - {} + { } }; MODULE_DEVICE_TABLE(i2c, isl29028_id); @@ -688,7 +688,7 @@ static const struct of_device_id isl29028_of_match[] = { { .compatible = "isl,isl29028", }, /* for backward compat., don't use */ { .compatible = "isil,isl29028", }, { .compatible = "isil,isl29030", }, - { }, + { } }; MODULE_DEVICE_TABLE(of, isl29028_of_match); diff --git a/drivers/iio/light/isl29125.c b/drivers/iio/light/isl29125.c index 326dc39e7929..6bc23b164cc5 100644 --- a/drivers/iio/light/isl29125.c +++ b/drivers/iio/light/isl29125.c @@ -131,11 +131,10 @@ static int isl29125_read_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_RAW: - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; ret = isl29125_read_data(data, chan->scan_index); - iio_device_release_direct_mode(indio_dev); + iio_device_release_direct(indio_dev); if (ret < 0) return ret; *val = ret; diff --git a/drivers/iio/light/jsa1212.c b/drivers/iio/light/jsa1212.c index e7ba934c8e69..fa4677c28931 100644 --- a/drivers/iio/light/jsa1212.c +++ b/drivers/iio/light/jsa1212.c @@ -424,7 +424,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(jsa1212_pm_ops, jsa1212_suspend, static const struct acpi_device_id jsa1212_acpi_match[] = { {"JSA1212", 0}, - { }, + { } }; MODULE_DEVICE_TABLE(acpi, jsa1212_acpi_match); diff --git a/drivers/iio/light/ltr390.c b/drivers/iio/light/ltr390.c index df664f360903..ee59bbb8aa09 100644 --- a/drivers/iio/light/ltr390.c +++ b/drivers/iio/light/ltr390.c @@ -717,13 +717,13 @@ static DEFINE_SIMPLE_DEV_PM_OPS(ltr390_pm_ops, ltr390_suspend, ltr390_resume); static const struct i2c_device_id ltr390_id[] = { { "ltr390" }, - { /* Sentinel */ } + { } }; MODULE_DEVICE_TABLE(i2c, ltr390_id); static const struct of_device_id ltr390_of_table[] = { { .compatible = "liteon,ltr390" }, - { /* Sentinel */ } + { } }; MODULE_DEVICE_TABLE(of, ltr390_of_table); diff --git a/drivers/iio/light/ltr501.c b/drivers/iio/light/ltr501.c index 669da0840eba..8d8051cf6927 100644 --- a/drivers/iio/light/ltr501.c +++ b/drivers/iio/light/ltr501.c @@ -541,7 +541,7 @@ static const struct iio_chan_spec_ext_info ltr501_ext_info[] = { .shared = IIO_SEPARATE, .read = ltr501_read_near_level, }, - { /* sentinel */ } + { } }; static const struct iio_event_spec ltr501_als_event_spec[] = { @@ -646,6 +646,36 @@ static const struct iio_chan_spec ltr301_channels[] = { IIO_CHAN_SOFT_TIMESTAMP(2), }; +static int ltr501_read_info_raw(struct ltr501_data *data, + struct iio_chan_spec const *chan, + int *val) +{ + __le16 buf[2]; + int ret; + + switch (chan->type) { + case IIO_INTENSITY: + mutex_lock(&data->lock_als); + ret = ltr501_read_als(data, buf); + mutex_unlock(&data->lock_als); + if (ret < 0) + return ret; + *val = le16_to_cpu(chan->address == LTR501_ALS_DATA1 ? + buf[0] : buf[1]); + return IIO_VAL_INT; + case IIO_PROXIMITY: + mutex_lock(&data->lock_ps); + ret = ltr501_read_ps(data); + mutex_unlock(&data->lock_ps); + if (ret < 0) + return ret; + *val = ret & LTR501_PS_DATA_MASK; + return IIO_VAL_INT; + default: + return -EINVAL; + } +} + static int ltr501_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long mask) @@ -658,14 +688,13 @@ static int ltr501_read_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_PROCESSED: switch (chan->type) { case IIO_LIGHT: - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; mutex_lock(&data->lock_als); ret = ltr501_read_als(data, buf); mutex_unlock(&data->lock_als); - iio_device_release_direct_mode(indio_dev); + iio_device_release_direct(indio_dev); if (ret < 0) return ret; *val = ltr501_calculate_lux(le16_to_cpu(buf[1]), @@ -675,36 +704,12 @@ static int ltr501_read_raw(struct iio_dev *indio_dev, return -EINVAL; } case IIO_CHAN_INFO_RAW: - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; - switch (chan->type) { - case IIO_INTENSITY: - mutex_lock(&data->lock_als); - ret = ltr501_read_als(data, buf); - mutex_unlock(&data->lock_als); - if (ret < 0) - break; - *val = le16_to_cpu(chan->address == LTR501_ALS_DATA1 ? - buf[0] : buf[1]); - ret = IIO_VAL_INT; - break; - case IIO_PROXIMITY: - mutex_lock(&data->lock_ps); - ret = ltr501_read_ps(data); - mutex_unlock(&data->lock_ps); - if (ret < 0) - break; - *val = ret & LTR501_PS_DATA_MASK; - ret = IIO_VAL_INT; - break; - default: - ret = -EINVAL; - break; - } + ret = ltr501_read_info_raw(data, chan, val); - iio_device_release_direct_mode(indio_dev); + iio_device_release_direct(indio_dev); return ret; case IIO_CHAN_INFO_SCALE: @@ -756,18 +761,14 @@ static int ltr501_get_gain_index(const struct ltr501_gain *gain, int size, return -1; } -static int ltr501_write_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int val, int val2, long mask) +static int __ltr501_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) { struct ltr501_data *data = iio_priv(indio_dev); int i, ret, freq_val, freq_val2; const struct ltr501_chip_info *info = data->chip_info; - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; - switch (mask) { case IIO_CHAN_INFO_SCALE: switch (chan->type) { @@ -775,53 +776,43 @@ static int ltr501_write_raw(struct iio_dev *indio_dev, i = ltr501_get_gain_index(info->als_gain, info->als_gain_tbl_size, val, val2); - if (i < 0) { - ret = -EINVAL; - break; - } + if (i < 0) + return -EINVAL; data->als_contr &= ~info->als_gain_mask; data->als_contr |= i << info->als_gain_shift; - ret = regmap_write(data->regmap, LTR501_ALS_CONTR, - data->als_contr); - break; + return regmap_write(data->regmap, LTR501_ALS_CONTR, + data->als_contr); case IIO_PROXIMITY: i = ltr501_get_gain_index(info->ps_gain, info->ps_gain_tbl_size, val, val2); - if (i < 0) { - ret = -EINVAL; - break; - } + if (i < 0) + return -EINVAL; + data->ps_contr &= ~LTR501_CONTR_PS_GAIN_MASK; data->ps_contr |= i << LTR501_CONTR_PS_GAIN_SHIFT; - ret = regmap_write(data->regmap, LTR501_PS_CONTR, - data->ps_contr); - break; + return regmap_write(data->regmap, LTR501_PS_CONTR, + data->ps_contr); default: - ret = -EINVAL; - break; + return -EINVAL; } - break; case IIO_CHAN_INFO_INT_TIME: switch (chan->type) { case IIO_INTENSITY: - if (val != 0) { - ret = -EINVAL; - break; - } + if (val != 0) + return -EINVAL; + mutex_lock(&data->lock_als); ret = ltr501_set_it_time(data, val2); mutex_unlock(&data->lock_als); - break; + return ret; default: - ret = -EINVAL; - break; + return -EINVAL; } - break; case IIO_CHAN_INFO_SAMP_FREQ: switch (chan->type) { @@ -829,50 +820,61 @@ static int ltr501_write_raw(struct iio_dev *indio_dev, ret = ltr501_als_read_samp_freq(data, &freq_val, &freq_val2); if (ret < 0) - break; + return ret; ret = ltr501_als_write_samp_freq(data, val, val2); if (ret < 0) - break; + return ret; /* update persistence count when changing frequency */ ret = ltr501_write_intr_prst(data, chan->type, 0, data->als_period); if (ret < 0) - ret = ltr501_als_write_samp_freq(data, freq_val, - freq_val2); - break; + /* Do not ovewrite error */ + ltr501_als_write_samp_freq(data, freq_val, + freq_val2); + return ret; case IIO_PROXIMITY: ret = ltr501_ps_read_samp_freq(data, &freq_val, &freq_val2); if (ret < 0) - break; + return ret; ret = ltr501_ps_write_samp_freq(data, val, val2); if (ret < 0) - break; + return ret; /* update persistence count when changing frequency */ ret = ltr501_write_intr_prst(data, chan->type, 0, data->ps_period); if (ret < 0) - ret = ltr501_ps_write_samp_freq(data, freq_val, - freq_val2); - break; + /* Do not overwrite error */ + ltr501_ps_write_samp_freq(data, freq_val, + freq_val2); + return ret; default: - ret = -EINVAL; - break; + return -EINVAL; } - break; - default: - ret = -EINVAL; - break; + return -EINVAL; } +} + +static int ltr501_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + int ret; + + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; + + ret = __ltr501_write_raw(indio_dev, chan, val, val2, mask); + + iio_device_release_direct(indio_dev); - iio_device_release_direct_mode(indio_dev); return ret; } @@ -1600,7 +1602,7 @@ static const struct acpi_device_id ltr_acpi_match[] = { { "LTER0301", ltr301 }, /* https://www.catalog.update.microsoft.com/Search.aspx?q=lter0303 */ { "LTER0303", ltr303 }, - { }, + { } }; MODULE_DEVICE_TABLE(acpi, ltr_acpi_match); @@ -1618,7 +1620,7 @@ static const struct of_device_id ltr501_of_match[] = { { .compatible = "liteon,ltr559", }, { .compatible = "liteon,ltr301", }, { .compatible = "liteon,ltr303", }, - {} + { } }; MODULE_DEVICE_TABLE(of, ltr501_of_match); diff --git a/drivers/iio/light/ltrf216a.c b/drivers/iio/light/ltrf216a.c index dbec1e7cfeb8..61f57a82b872 100644 --- a/drivers/iio/light/ltrf216a.c +++ b/drivers/iio/light/ltrf216a.c @@ -554,7 +554,7 @@ static const struct ltr_chip_info ltrf216a_chip_info = { static const struct i2c_device_id ltrf216a_id[] = { { "ltr308", .driver_data = (kernel_ulong_t)<r308_chip_info }, { "ltrf216a", .driver_data = (kernel_ulong_t)<rf216a_chip_info }, - {} + { } }; MODULE_DEVICE_TABLE(i2c, ltrf216a_id); @@ -563,7 +563,7 @@ static const struct of_device_id ltrf216a_of_match[] = { { .compatible = "liteon,ltrf216a", .data = <rf216a_chip_info }, /* For Valve's Steamdeck device, an ACPI platform using PRP0001 */ { .compatible = "ltr,ltrf216a", .data = <rf216a_chip_info }, - {} + { } }; MODULE_DEVICE_TABLE(of, ltrf216a_of_match); diff --git a/drivers/iio/light/opt4001.c b/drivers/iio/light/opt4001.c index 6cf60151b3d8..ba4eb82d9bc2 100644 --- a/drivers/iio/light/opt4001.c +++ b/drivers/iio/light/opt4001.c @@ -448,7 +448,7 @@ MODULE_DEVICE_TABLE(i2c, opt4001_id); static const struct of_device_id opt4001_of_match[] = { { .compatible = "ti,opt4001-sot-5x3", .data = &opt4001_sot_5x3_info}, { .compatible = "ti,opt4001-picostar", .data = &opt4001_picostar_info}, - {} + { } }; MODULE_DEVICE_TABLE(of, opt4001_of_match); diff --git a/drivers/iio/light/opt4060.c b/drivers/iio/light/opt4060.c index ab55f8d2ea0c..f4085020e03e 100644 --- a/drivers/iio/light/opt4060.c +++ b/drivers/iio/light/opt4060.c @@ -311,7 +311,7 @@ any_mode_retry: * concurrently change. And we just keep trying until we get one * of the modes... */ - if (iio_device_claim_direct_mode(indio_dev)) + if (!iio_device_claim_direct(indio_dev)) goto any_mode_retry; /* * This path means that we managed to claim direct mode. In @@ -320,7 +320,8 @@ any_mode_retry: */ ret = opt4060_set_state_common(chip, continuous_sampling, continuous_irq); - iio_device_release_direct_mode(indio_dev); + iio_device_release_direct(indio_dev); + return ret; } else { /* * This path means that we managed to claim buffer mode. In diff --git a/drivers/iio/light/pa12203001.c b/drivers/iio/light/pa12203001.c index b920bf82c102..8885852bef22 100644 --- a/drivers/iio/light/pa12203001.c +++ b/drivers/iio/light/pa12203001.c @@ -456,14 +456,14 @@ static const struct dev_pm_ops pa12203001_pm_ops = { static const struct acpi_device_id pa12203001_acpi_match[] = { { "TXCPA122", 0 }, - {} + { } }; MODULE_DEVICE_TABLE(acpi, pa12203001_acpi_match); static const struct i2c_device_id pa12203001_id[] = { { "txcpa122" }, - {} + { } }; MODULE_DEVICE_TABLE(i2c, pa12203001_id); diff --git a/drivers/iio/light/rohm-bu27034.c b/drivers/iio/light/rohm-bu27034.c index cc25596cb248..7cec5e943373 100644 --- a/drivers/iio/light/rohm-bu27034.c +++ b/drivers/iio/light/rohm-bu27034.c @@ -998,9 +998,8 @@ static int bu27034_read_raw(struct iio_dev *idev, return -EINVAL; /* Don't mess with measurement enabling while buffering */ - ret = iio_device_claim_direct_mode(idev); - if (ret) - return ret; + if (!iio_device_claim_direct(idev)) + return -EBUSY; mutex_lock(&data->mutex); /* @@ -1011,7 +1010,7 @@ static int bu27034_read_raw(struct iio_dev *idev, ret = result_get(data, chan->channel, val); mutex_unlock(&data->mutex); - iio_device_release_direct_mode(idev); + iio_device_release_direct(idev); if (ret) return ret; @@ -1050,9 +1049,8 @@ static int bu27034_write_raw(struct iio_dev *idev, struct bu27034_data *data = iio_priv(idev); int ret; - ret = iio_device_claim_direct_mode(idev); - if (ret) - return ret; + if (!iio_device_claim_direct(idev)) + return -EBUSY; switch (mask) { case IIO_CHAN_INFO_SCALE: @@ -1069,7 +1067,7 @@ static int bu27034_write_raw(struct iio_dev *idev, break; } - iio_device_release_direct_mode(idev); + iio_device_release_direct(idev); return ret; } diff --git a/drivers/iio/light/rpr0521.c b/drivers/iio/light/rpr0521.c index 2ba917c5c138..92e7552f3e39 100644 --- a/drivers/iio/light/rpr0521.c +++ b/drivers/iio/light/rpr0521.c @@ -11,6 +11,7 @@ #include <linux/module.h> #include <linux/mod_devicetable.h> +#include <linux/cleanup.h> #include <linux/init.h> #include <linux/i2c.h> #include <linux/regmap.h> @@ -704,50 +705,58 @@ static int rpr0521_write_ps_offset(struct rpr0521_data *data, int offset) return ret; } +static int rpr0521_read_info_raw(struct rpr0521_data *data, + struct iio_chan_spec const *chan, + int *val) +{ + u8 device_mask; + __le16 raw_data; + int ret; + + device_mask = rpr0521_data_reg[chan->address].device_mask; + + guard(mutex)(&data->lock); + ret = rpr0521_set_power_state(data, true, device_mask); + if (ret < 0) + return ret; + + ret = regmap_bulk_read(data->regmap, + rpr0521_data_reg[chan->address].address, + &raw_data, sizeof(raw_data)); + if (ret < 0) { + rpr0521_set_power_state(data, false, device_mask); + return ret; + } + + ret = rpr0521_set_power_state(data, false, device_mask); + if (ret < 0) + return ret; + + *val = le16_to_cpu(raw_data); + + return 0; +} + static int rpr0521_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long mask) { struct rpr0521_data *data = iio_priv(indio_dev); int ret; - int busy; - u8 device_mask; - __le16 raw_data; switch (mask) { case IIO_CHAN_INFO_RAW: if (chan->type != IIO_INTENSITY && chan->type != IIO_PROXIMITY) return -EINVAL; - busy = iio_device_claim_direct_mode(indio_dev); - if (busy) + if (!iio_device_claim_direct(indio_dev)) return -EBUSY; - device_mask = rpr0521_data_reg[chan->address].device_mask; - - mutex_lock(&data->lock); - ret = rpr0521_set_power_state(data, true, device_mask); - if (ret < 0) - goto rpr0521_read_raw_out; - - ret = regmap_bulk_read(data->regmap, - rpr0521_data_reg[chan->address].address, - &raw_data, sizeof(raw_data)); - if (ret < 0) { - rpr0521_set_power_state(data, false, device_mask); - goto rpr0521_read_raw_out; - } - - ret = rpr0521_set_power_state(data, false, device_mask); - -rpr0521_read_raw_out: - mutex_unlock(&data->lock); - iio_device_release_direct_mode(indio_dev); + ret = rpr0521_read_info_raw(data, chan, val); + iio_device_release_direct(indio_dev); if (ret < 0) return ret; - *val = le16_to_cpu(raw_data); - return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: diff --git a/drivers/iio/light/si1145.c b/drivers/iio/light/si1145.c index 66abda021696..4aa02afd853e 100644 --- a/drivers/iio/light/si1145.c +++ b/drivers/iio/light/si1145.c @@ -633,11 +633,10 @@ static int si1145_read_raw(struct iio_dev *indio_dev, case IIO_VOLTAGE: case IIO_TEMP: case IIO_UVINDEX: - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; ret = si1145_measure(indio_dev, chan); - iio_device_release_direct_mode(indio_dev); + iio_device_release_direct(indio_dev); if (ret < 0) return ret; @@ -750,18 +749,17 @@ static int si1145_write_raw(struct iio_dev *indio_dev, return -EINVAL; } - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; ret = si1145_param_set(data, reg1, val); if (ret < 0) { - iio_device_release_direct_mode(indio_dev); + iio_device_release_direct(indio_dev); return ret; } /* Set recovery period to one's complement of gain */ ret = si1145_param_set(data, reg2, (~val & 0x07) << 4); - iio_device_release_direct_mode(indio_dev); + iio_device_release_direct(indio_dev); return ret; case IIO_CHAN_INFO_RAW: if (chan->type != IIO_CURRENT) @@ -773,19 +771,18 @@ static int si1145_write_raw(struct iio_dev *indio_dev, reg1 = SI1145_PS_LED_REG(chan->channel); shift = SI1145_PS_LED_SHIFT(chan->channel); - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; ret = i2c_smbus_read_byte_data(data->client, reg1); if (ret < 0) { - iio_device_release_direct_mode(indio_dev); + iio_device_release_direct(indio_dev); return ret; } ret = i2c_smbus_write_byte_data(data->client, reg1, (ret & ~(0x0f << shift)) | ((val & 0x0f) << shift)); - iio_device_release_direct_mode(indio_dev); + iio_device_release_direct(indio_dev); return ret; case IIO_CHAN_INFO_SAMP_FREQ: return si1145_store_samp_freq(data, val); diff --git a/drivers/iio/light/st_uvis25_core.c b/drivers/iio/light/st_uvis25_core.c index 40a810000df0..124a8f9204a9 100644 --- a/drivers/iio/light/st_uvis25_core.c +++ b/drivers/iio/light/st_uvis25_core.c @@ -117,9 +117,8 @@ static int st_uvis25_read_raw(struct iio_dev *iio_dev, { int ret; - ret = iio_device_claim_direct_mode(iio_dev); - if (ret) - return ret; + if (!iio_device_claim_direct(iio_dev)) + return -EBUSY; switch (mask) { case IIO_CHAN_INFO_PROCESSED: { @@ -144,7 +143,7 @@ static int st_uvis25_read_raw(struct iio_dev *iio_dev, break; } - iio_device_release_direct_mode(iio_dev); + iio_device_release_direct(iio_dev); return ret; } diff --git a/drivers/iio/light/st_uvis25_i2c.c b/drivers/iio/light/st_uvis25_i2c.c index f54282476d11..5d9bb4d9be63 100644 --- a/drivers/iio/light/st_uvis25_i2c.c +++ b/drivers/iio/light/st_uvis25_i2c.c @@ -41,13 +41,13 @@ static int st_uvis25_i2c_probe(struct i2c_client *client) static const struct of_device_id st_uvis25_i2c_of_match[] = { { .compatible = "st,uvis25", }, - {}, + { } }; MODULE_DEVICE_TABLE(of, st_uvis25_i2c_of_match); static const struct i2c_device_id st_uvis25_i2c_id_table[] = { { ST_UVIS25_DEV_NAME }, - {}, + { } }; MODULE_DEVICE_TABLE(i2c, st_uvis25_i2c_id_table); diff --git a/drivers/iio/light/st_uvis25_spi.c b/drivers/iio/light/st_uvis25_spi.c index 18edc6a5a4a4..a5aad74ce73e 100644 --- a/drivers/iio/light/st_uvis25_spi.c +++ b/drivers/iio/light/st_uvis25_spi.c @@ -42,13 +42,13 @@ static int st_uvis25_spi_probe(struct spi_device *spi) static const struct of_device_id st_uvis25_spi_of_match[] = { { .compatible = "st,uvis25", }, - {}, + { } }; MODULE_DEVICE_TABLE(of, st_uvis25_spi_of_match); static const struct spi_device_id st_uvis25_spi_id_table[] = { { ST_UVIS25_DEV_NAME }, - {}, + { } }; MODULE_DEVICE_TABLE(spi, st_uvis25_spi_id_table); diff --git a/drivers/iio/light/stk3310.c b/drivers/iio/light/stk3310.c index b81cc44db43c..deada9ba4748 100644 --- a/drivers/iio/light/stk3310.c +++ b/drivers/iio/light/stk3310.c @@ -165,7 +165,7 @@ static const struct iio_chan_spec_ext_info stk3310_ext_info[] = { .shared = IIO_SEPARATE, .read = stk3310_read_near_level, }, - { /* sentinel */ } + { } }; static const struct iio_chan_spec stk3310_channels[] = { @@ -703,7 +703,7 @@ static const struct i2c_device_id stk3310_i2c_id[] = { { "STK3310" }, { "STK3311" }, { "STK3335" }, - {} + { } }; MODULE_DEVICE_TABLE(i2c, stk3310_i2c_id); @@ -711,7 +711,7 @@ static const struct acpi_device_id stk3310_acpi_id[] = { {"STK3013", 0}, {"STK3310", 0}, {"STK3311", 0}, - {} + { } }; MODULE_DEVICE_TABLE(acpi, stk3310_acpi_id); @@ -721,7 +721,7 @@ static const struct of_device_id stk3310_of_match[] = { { .compatible = "sensortek,stk3310", }, { .compatible = "sensortek,stk3311", }, { .compatible = "sensortek,stk3335", }, - {} + { } }; MODULE_DEVICE_TABLE(of, stk3310_of_match); diff --git a/drivers/iio/light/tcs3414.c b/drivers/iio/light/tcs3414.c index 884e43e4cda4..39268f855c77 100644 --- a/drivers/iio/light/tcs3414.c +++ b/drivers/iio/light/tcs3414.c @@ -134,16 +134,15 @@ static int tcs3414_read_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_RAW: - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; ret = tcs3414_req_data(data); if (ret < 0) { - iio_device_release_direct_mode(indio_dev); + iio_device_release_direct(indio_dev); return ret; } ret = i2c_smbus_read_word_data(data->client, chan->address); - iio_device_release_direct_mode(indio_dev); + iio_device_release_direct(indio_dev); if (ret < 0) return ret; *val = ret; diff --git a/drivers/iio/light/tcs3472.c b/drivers/iio/light/tcs3472.c index 2bd36a344ea5..0f8bf8503edd 100644 --- a/drivers/iio/light/tcs3472.c +++ b/drivers/iio/light/tcs3472.c @@ -148,16 +148,15 @@ static int tcs3472_read_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_RAW: - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; ret = tcs3472_req_data(data); if (ret < 0) { - iio_device_release_direct_mode(indio_dev); + iio_device_release_direct(indio_dev); return ret; } ret = i2c_smbus_read_word_data(data->client, chan->address); - iio_device_release_direct_mode(indio_dev); + iio_device_release_direct(indio_dev); if (ret < 0) return ret; *val = ret; diff --git a/drivers/iio/light/tsl2563.c b/drivers/iio/light/tsl2563.c index f1fe7640fce6..f2af1cd7c2d1 100644 --- a/drivers/iio/light/tsl2563.c +++ b/drivers/iio/light/tsl2563.c @@ -843,7 +843,7 @@ static const struct i2c_device_id tsl2563_id[] = { { "tsl2561", 1 }, { "tsl2562", 2 }, { "tsl2563", 3 }, - {} + { } }; MODULE_DEVICE_TABLE(i2c, tsl2563_id); @@ -852,7 +852,7 @@ static const struct of_device_id tsl2563_of_match[] = { { .compatible = "amstaos,tsl2561" }, { .compatible = "amstaos,tsl2562" }, { .compatible = "amstaos,tsl2563" }, - {} + { } }; MODULE_DEVICE_TABLE(of, tsl2563_of_match); diff --git a/drivers/iio/light/tsl2583.c b/drivers/iio/light/tsl2583.c index 02ad11611b9c..fc3b0c4226be 100644 --- a/drivers/iio/light/tsl2583.c +++ b/drivers/iio/light/tsl2583.c @@ -922,7 +922,7 @@ static const struct i2c_device_id tsl2583_idtable[] = { { "tsl2580", 0 }, { "tsl2581", 1 }, { "tsl2583", 2 }, - {} + { } }; MODULE_DEVICE_TABLE(i2c, tsl2583_idtable); @@ -930,7 +930,7 @@ static const struct of_device_id tsl2583_of_match[] = { { .compatible = "amstaos,tsl2580", }, { .compatible = "amstaos,tsl2581", }, { .compatible = "amstaos,tsl2583", }, - { }, + { } }; MODULE_DEVICE_TABLE(of, tsl2583_of_match); diff --git a/drivers/iio/light/tsl2591.c b/drivers/iio/light/tsl2591.c index b81ca6f73f92..08476f193a44 100644 --- a/drivers/iio/light/tsl2591.c +++ b/drivers/iio/light/tsl2591.c @@ -1204,7 +1204,7 @@ static int tsl2591_probe(struct i2c_client *client) static const struct of_device_id tsl2591_of_match[] = { { .compatible = "amstaos,tsl2591"}, - {} + { } }; MODULE_DEVICE_TABLE(of, tsl2591_of_match); diff --git a/drivers/iio/light/tsl2772.c b/drivers/iio/light/tsl2772.c index 349afdcbe30d..0b171106441a 100644 --- a/drivers/iio/light/tsl2772.c +++ b/drivers/iio/light/tsl2772.c @@ -1899,7 +1899,7 @@ static const struct i2c_device_id tsl2772_idtable[] = { { "tsl2772", tsl2772 }, { "tmd2772", tmd2772 }, { "apds9930", apds9930 }, - {} + { } }; MODULE_DEVICE_TABLE(i2c, tsl2772_idtable); @@ -1916,7 +1916,7 @@ static const struct of_device_id tsl2772_of_match[] = { { .compatible = "amstaos,tsl2772" }, { .compatible = "amstaos,tmd2772" }, { .compatible = "avago,apds9930" }, - {} + { } }; MODULE_DEVICE_TABLE(of, tsl2772_of_match); diff --git a/drivers/iio/light/us5182d.c b/drivers/iio/light/us5182d.c index c83114aed6b2..61a0957317a1 100644 --- a/drivers/iio/light/us5182d.c +++ b/drivers/iio/light/us5182d.c @@ -949,21 +949,21 @@ static const struct dev_pm_ops us5182d_pm_ops = { static const struct acpi_device_id us5182d_acpi_match[] = { { "USD5182", 0 }, - {} + { } }; MODULE_DEVICE_TABLE(acpi, us5182d_acpi_match); static const struct i2c_device_id us5182d_id[] = { { "usd5182" }, - {} + { } }; MODULE_DEVICE_TABLE(i2c, us5182d_id); static const struct of_device_id us5182d_of_match[] = { { .compatible = "upisemi,usd5182" }, - {} + { } }; MODULE_DEVICE_TABLE(of, us5182d_of_match); diff --git a/drivers/iio/light/vcnl4000.c b/drivers/iio/light/vcnl4000.c index e19199b17f2e..90e7d4421abf 100644 --- a/drivers/iio/light/vcnl4000.c +++ b/drivers/iio/light/vcnl4000.c @@ -1084,9 +1084,8 @@ static int vcnl4010_read_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_RAW: case IIO_CHAN_INFO_SCALE: - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; /* Protect against event capture. */ if (vcnl4010_is_in_periodic_mode(data)) { @@ -1096,7 +1095,7 @@ static int vcnl4010_read_raw(struct iio_dev *indio_dev, mask); } - iio_device_release_direct_mode(indio_dev); + iio_device_release_direct(indio_dev); return ret; case IIO_CHAN_INFO_SAMP_FREQ: switch (chan->type) { @@ -1157,9 +1156,8 @@ static int vcnl4010_write_raw(struct iio_dev *indio_dev, int ret; struct vcnl4000_data *data = iio_priv(indio_dev); - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; /* Protect against event capture. */ if (vcnl4010_is_in_periodic_mode(data)) { @@ -1183,7 +1181,7 @@ static int vcnl4010_write_raw(struct iio_dev *indio_dev, } end: - iio_device_release_direct_mode(indio_dev); + iio_device_release_direct(indio_dev); return ret; } @@ -1410,46 +1408,52 @@ static int vcnl4010_read_event_config(struct iio_dev *indio_dev, } } -static int vcnl4010_config_threshold(struct iio_dev *indio_dev, bool state) +static int vcnl4010_config_threshold_enable(struct vcnl4000_data *data) { - struct vcnl4000_data *data = iio_priv(indio_dev); int ret; - int icr; - int command; - if (state) { - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; + /* Enable periodic measurement of proximity data. */ + ret = i2c_smbus_write_byte_data(data->client, VCNL4000_COMMAND, + VCNL4000_SELF_TIMED_EN | VCNL4000_PROX_EN); + if (ret < 0) + return ret; - /* Enable periodic measurement of proximity data. */ - command = VCNL4000_SELF_TIMED_EN | VCNL4000_PROX_EN; + /* + * Enable interrupts on threshold, for proximity data by + * default. + */ + return i2c_smbus_write_byte_data(data->client, VCNL4010_INT_CTRL, + VCNL4010_INT_THR_EN); +} - /* - * Enable interrupts on threshold, for proximity data by - * default. - */ - icr = VCNL4010_INT_THR_EN; - } else { - if (!vcnl4010_is_thr_enabled(data)) - return 0; +static int vcnl4010_config_threshold_disable(struct vcnl4000_data *data) +{ + int ret; - command = 0; - icr = 0; - } + if (!vcnl4010_is_thr_enabled(data)) + return 0; - ret = i2c_smbus_write_byte_data(data->client, VCNL4000_COMMAND, - command); + ret = i2c_smbus_write_byte_data(data->client, VCNL4000_COMMAND, 0); if (ret < 0) - goto end; + return ret; - ret = i2c_smbus_write_byte_data(data->client, VCNL4010_INT_CTRL, icr); + return i2c_smbus_write_byte_data(data->client, VCNL4010_INT_CTRL, 0); +} -end: - if (state) - iio_device_release_direct_mode(indio_dev); +static int vcnl4010_config_threshold(struct iio_dev *indio_dev, bool state) +{ + struct vcnl4000_data *data = iio_priv(indio_dev); + int ret; - return ret; + if (state) { + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; + ret = vcnl4010_config_threshold_enable(data); + iio_device_release_direct(indio_dev); + return ret; + } else { + return vcnl4010_config_threshold_disable(data); + } } static int vcnl4010_write_event_config(struct iio_dev *indio_dev, @@ -1741,7 +1745,7 @@ static const struct iio_chan_spec_ext_info vcnl4000_ext_info[] = { .shared = IIO_SEPARATE, .read = vcnl4000_read_near_level, }, - { /* sentinel */ } + { } }; static const struct iio_event_spec vcnl4000_event_spec[] = { @@ -2064,7 +2068,7 @@ static const struct of_device_id vcnl_4000_of_match[] = { .compatible = "vishay,vcnl4200", .data = (void *)VCNL4200, }, - {}, + { } }; MODULE_DEVICE_TABLE(of, vcnl_4000_of_match); diff --git a/drivers/iio/light/vcnl4035.c b/drivers/iio/light/vcnl4035.c index 67c94be02018..b2bede9d3daa 100644 --- a/drivers/iio/light/vcnl4035.c +++ b/drivers/iio/light/vcnl4035.c @@ -156,6 +156,31 @@ static int vcnl4035_set_pm_runtime_state(struct vcnl4035_data *data, bool on) return ret; } +static int vcnl4035_read_info_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val) +{ + struct vcnl4035_data *data = iio_priv(indio_dev); + int ret; + int raw_data; + unsigned int reg; + + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; + + if (chan->channel) + reg = VCNL4035_ALS_DATA; + else + reg = VCNL4035_WHITE_DATA; + ret = regmap_read(data->regmap, reg, &raw_data); + iio_device_release_direct(indio_dev); + if (ret) + return ret; + + *val = raw_data; + + return IIO_VAL_INT; +} + /* * Device IT INT Time (ms) Scale (lux/step) * 000 50 0.064 @@ -175,28 +200,13 @@ static int vcnl4035_read_raw(struct iio_dev *indio_dev, { struct vcnl4035_data *data = iio_priv(indio_dev); int ret; - int raw_data; - unsigned int reg; switch (mask) { case IIO_CHAN_INFO_RAW: ret = vcnl4035_set_pm_runtime_state(data, true); if (ret < 0) return ret; - - ret = iio_device_claim_direct_mode(indio_dev); - if (!ret) { - if (chan->channel) - reg = VCNL4035_ALS_DATA; - else - reg = VCNL4035_WHITE_DATA; - ret = regmap_read(data->regmap, reg, &raw_data); - iio_device_release_direct_mode(indio_dev); - if (!ret) { - *val = raw_data; - ret = IIO_VAL_INT; - } - } + ret = vcnl4035_read_info_raw(indio_dev, chan, val); vcnl4035_set_pm_runtime_state(data, false); return ret; case IIO_CHAN_INFO_INT_TIME: diff --git a/drivers/iio/light/veml6040.c b/drivers/iio/light/veml6040.c index 216e271001a8..71a594b2ec85 100644 --- a/drivers/iio/light/veml6040.c +++ b/drivers/iio/light/veml6040.c @@ -256,13 +256,13 @@ static int veml6040_probe(struct i2c_client *client) static const struct i2c_device_id veml6040_id_table[] = { {"veml6040"}, - {} + { } }; MODULE_DEVICE_TABLE(i2c, veml6040_id_table); static const struct of_device_id veml6040_of_match[] = { {.compatible = "vishay,veml6040"}, - {} + { } }; MODULE_DEVICE_TABLE(of, veml6040_of_match); diff --git a/drivers/iio/light/veml6075.c b/drivers/iio/light/veml6075.c index 859891e8f115..edbb43407054 100644 --- a/drivers/iio/light/veml6075.c +++ b/drivers/iio/light/veml6075.c @@ -458,7 +458,7 @@ MODULE_DEVICE_TABLE(i2c, veml6075_id); static const struct of_device_id veml6075_of_match[] = { { .compatible = "vishay,veml6075" }, - {} + { } }; MODULE_DEVICE_TABLE(of, veml6075_of_match); diff --git a/drivers/iio/light/vl6180.c b/drivers/iio/light/vl6180.c index 6e2183a4243e..cc4f2e5404aa 100644 --- a/drivers/iio/light/vl6180.c +++ b/drivers/iio/light/vl6180.c @@ -745,7 +745,7 @@ static int vl6180_probe(struct i2c_client *client) static const struct of_device_id vl6180_of_match[] = { { .compatible = "st,vl6180", }, - { }, + { } }; MODULE_DEVICE_TABLE(of, vl6180_of_match); diff --git a/drivers/iio/light/zopt2201.c b/drivers/iio/light/zopt2201.c index 604be60e92ac..1e5e9bf2935f 100644 --- a/drivers/iio/light/zopt2201.c +++ b/drivers/iio/light/zopt2201.c @@ -113,11 +113,13 @@ static const struct { { 13, 3125 }, }; -static const struct { +struct zopt2201_scale { unsigned int scale, uscale; /* scale factor as integer + micro */ u8 gain; /* gain register value */ u8 res; /* resolution register value */ -} zopt2201_scale_als[] = { +}; + +static struct zopt2201_scale zopt2201_scale_als[] = { { 19, 200000, 0, 5 }, { 6, 400000, 1, 5 }, { 3, 200000, 2, 5 }, @@ -142,11 +144,7 @@ static const struct { { 0, 8333, 4, 0 }, }; -static const struct { - unsigned int scale, uscale; /* scale factor as integer + micro */ - u8 gain; /* gain register value */ - u8 res; /* resolution register value */ -} zopt2201_scale_uvb[] = { +static struct zopt2201_scale zopt2201_scale_uvb[] = { { 0, 460800, 0, 5 }, { 0, 153600, 1, 5 }, { 0, 76800, 2, 5 }, @@ -348,16 +346,17 @@ static int zopt2201_set_gain(struct zopt2201_data *data, u8 gain) return 0; } -static int zopt2201_write_scale_als_by_idx(struct zopt2201_data *data, int idx) +static int zopt2201_write_scale_by_idx(struct zopt2201_data *data, int idx, + struct zopt2201_scale *zopt2201_scale_array) { int ret; mutex_lock(&data->lock); - ret = zopt2201_set_resolution(data, zopt2201_scale_als[idx].res); + ret = zopt2201_set_resolution(data, zopt2201_scale_array[idx].res); if (ret < 0) goto unlock; - ret = zopt2201_set_gain(data, zopt2201_scale_als[idx].gain); + ret = zopt2201_set_gain(data, zopt2201_scale_array[idx].gain); unlock: mutex_unlock(&data->lock); @@ -371,29 +370,12 @@ static int zopt2201_write_scale_als(struct zopt2201_data *data, for (i = 0; i < ARRAY_SIZE(zopt2201_scale_als); i++) if (val == zopt2201_scale_als[i].scale && - val2 == zopt2201_scale_als[i].uscale) { - return zopt2201_write_scale_als_by_idx(data, i); - } + val2 == zopt2201_scale_als[i].uscale) + return zopt2201_write_scale_by_idx(data, i, zopt2201_scale_als); return -EINVAL; } -static int zopt2201_write_scale_uvb_by_idx(struct zopt2201_data *data, int idx) -{ - int ret; - - mutex_lock(&data->lock); - ret = zopt2201_set_resolution(data, zopt2201_scale_als[idx].res); - if (ret < 0) - goto unlock; - - ret = zopt2201_set_gain(data, zopt2201_scale_als[idx].gain); - -unlock: - mutex_unlock(&data->lock); - return ret; -} - static int zopt2201_write_scale_uvb(struct zopt2201_data *data, int val, int val2) { @@ -402,7 +384,7 @@ static int zopt2201_write_scale_uvb(struct zopt2201_data *data, for (i = 0; i < ARRAY_SIZE(zopt2201_scale_uvb); i++) if (val == zopt2201_scale_uvb[i].scale && val2 == zopt2201_scale_uvb[i].uscale) - return zopt2201_write_scale_uvb_by_idx(data, i); + return zopt2201_write_scale_by_idx(data, i, zopt2201_scale_uvb); return -EINVAL; } diff --git a/drivers/iio/magnetometer/af8133j.c b/drivers/iio/magnetometer/af8133j.c index c1fc339e85b4..192ba2da94e2 100644 --- a/drivers/iio/magnetometer/af8133j.c +++ b/drivers/iio/magnetometer/af8133j.c @@ -370,7 +370,8 @@ static irqreturn_t af8133j_trigger_handler(int irq, void *p) if (ret) goto out_done; - iio_push_to_buffers_with_timestamp(indio_dev, &sample, timestamp); + iio_push_to_buffers_with_ts(indio_dev, &sample, sizeof(sample), + timestamp); out_done: iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/magnetometer/ak8974.c b/drivers/iio/magnetometer/ak8974.c index 7bc341c69697..947fe8a475f2 100644 --- a/drivers/iio/magnetometer/ak8974.c +++ b/drivers/iio/magnetometer/ak8974.c @@ -673,8 +673,8 @@ static void ak8974_fill_buffer(struct iio_dev *indio_dev) goto out_unlock; } - iio_push_to_buffers_with_timestamp(indio_dev, &ak8974->scan, - iio_get_time_ns(indio_dev)); + iio_push_to_buffers_with_ts(indio_dev, &ak8974->scan, sizeof(ak8974->scan), + iio_get_time_ns(indio_dev)); out_unlock: mutex_unlock(&ak8974->lock); @@ -704,7 +704,7 @@ ak8974_get_mount_matrix(const struct iio_dev *indio_dev, static const struct iio_chan_spec_ext_info ak8974_ext_info[] = { IIO_MOUNT_MATRIX(IIO_SHARED_BY_DIR, ak8974_get_mount_matrix), - { }, + { } }; #define AK8974_AXIS_CHANNEL(axis, index, bits) \ @@ -1023,14 +1023,14 @@ static const struct i2c_device_id ak8974_id[] = { { "ami306" }, { "ak8974" }, { "hscdtd008a" }, - {} + { } }; MODULE_DEVICE_TABLE(i2c, ak8974_id); static const struct of_device_id ak8974_of_match[] = { { .compatible = "asahi-kasei,ak8974", }, { .compatible = "alps,hscdtd008a", }, - {} + { } }; MODULE_DEVICE_TABLE(of, ak8974_of_match); diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c index ef1363126cc2..a1e92b2abffd 100644 --- a/drivers/iio/magnetometer/ak8975.c +++ b/drivers/iio/magnetometer/ak8975.c @@ -882,8 +882,8 @@ static void ak8975_fill_buffer(struct iio_dev *indio_dev) data->scan.channels[1] = clamp_t(s16, le16_to_cpu(fval[1]), -def->range, def->range); data->scan.channels[2] = clamp_t(s16, le16_to_cpu(fval[2]), -def->range, def->range); - iio_push_to_buffers_with_timestamp(indio_dev, &data->scan, - iio_get_time_ns(indio_dev)); + iio_push_to_buffers_with_ts(indio_dev, &data->scan, sizeof(data->scan), + iio_get_time_ns(indio_dev)); return; @@ -1107,7 +1107,7 @@ static const struct i2c_device_id ak8975_id[] = { {"ak09912", (kernel_ulong_t)&ak_def_array[AK09912] }, {"ak09916", (kernel_ulong_t)&ak_def_array[AK09916] }, {"ak09918", (kernel_ulong_t)&ak_def_array[AK09918] }, - {} + { } }; MODULE_DEVICE_TABLE(i2c, ak8975_id); @@ -1122,7 +1122,7 @@ static const struct of_device_id ak8975_of_match[] = { { .compatible = "ak09912", .data = &ak_def_array[AK09912] }, { .compatible = "asahi-kasei,ak09916", .data = &ak_def_array[AK09916] }, { .compatible = "asahi-kasei,ak09918", .data = &ak_def_array[AK09918] }, - {} + { } }; MODULE_DEVICE_TABLE(of, ak8975_of_match); diff --git a/drivers/iio/magnetometer/als31300.c b/drivers/iio/magnetometer/als31300.c index 87b60c4e81fa..f72af829715f 100644 --- a/drivers/iio/magnetometer/als31300.c +++ b/drivers/iio/magnetometer/als31300.c @@ -245,8 +245,7 @@ static irqreturn_t als31300_trigger_handler(int irq, void *p) scan.channels[0] = x; scan.channels[1] = y; scan.channels[2] = z; - iio_push_to_buffers_with_timestamp(indio_dev, &scan, - pf->timestamp); + iio_push_to_buffers_with_ts(indio_dev, &scan, sizeof(scan), pf->timestamp); trigger_out: iio_trigger_notify_done(indio_dev->trig); @@ -457,7 +456,7 @@ static const struct i2c_device_id als31300_id[] = { .name = "als31300-2000", .driver_data = (kernel_ulong_t)&al31300_variant_2000, }, - { /* sentinel */ } + { } }; MODULE_DEVICE_TABLE(i2c, als31300_id); @@ -474,7 +473,7 @@ static const struct of_device_id als31300_of_match[] = { .compatible = "allegromicro,als31300-2000", .data = &al31300_variant_2000, }, - { /* sentinel */ } + { } }; MODULE_DEVICE_TABLE(of, als31300_of_match); diff --git a/drivers/iio/magnetometer/bmc150_magn.c b/drivers/iio/magnetometer/bmc150_magn.c index 88bb673e40d8..f9c51ceae011 100644 --- a/drivers/iio/magnetometer/bmc150_magn.c +++ b/drivers/iio/magnetometer/bmc150_magn.c @@ -678,8 +678,8 @@ static irqreturn_t bmc150_magn_trigger_handler(int irq, void *p) if (ret < 0) goto err; - iio_push_to_buffers_with_timestamp(indio_dev, &data->scan, - pf->timestamp); + iio_push_to_buffers_with_ts(indio_dev, &data->scan, sizeof(data->scan), + pf->timestamp); err: mutex_unlock(&data->mutex); diff --git a/drivers/iio/magnetometer/bmc150_magn_i2c.c b/drivers/iio/magnetometer/bmc150_magn_i2c.c index 8cbeda924bda..b110791f688a 100644 --- a/drivers/iio/magnetometer/bmc150_magn_i2c.c +++ b/drivers/iio/magnetometer/bmc150_magn_i2c.c @@ -42,7 +42,7 @@ static const struct i2c_device_id bmc150_magn_i2c_id[] = { { "bmc150_magn" }, { "bmc156_magn" }, { "bmm150_magn" }, - {} + { } }; MODULE_DEVICE_TABLE(i2c, bmc150_magn_i2c_id); diff --git a/drivers/iio/magnetometer/bmc150_magn_spi.c b/drivers/iio/magnetometer/bmc150_magn_spi.c index 2d4b8cba32f1..896b1d280731 100644 --- a/drivers/iio/magnetometer/bmc150_magn_spi.c +++ b/drivers/iio/magnetometer/bmc150_magn_spi.c @@ -37,7 +37,7 @@ static const struct spi_device_id bmc150_magn_spi_id[] = { {"bmc150_magn", 0}, {"bmc156_magn", 0}, {"bmm150_magn", 0}, - {} + { } }; MODULE_DEVICE_TABLE(spi, bmc150_magn_spi_id); diff --git a/drivers/iio/magnetometer/hid-sensor-magn-3d.c b/drivers/iio/magnetometer/hid-sensor-magn-3d.c index 97ddaa2a03f6..c673f9323e47 100644 --- a/drivers/iio/magnetometer/hid-sensor-magn-3d.c +++ b/drivers/iio/magnetometer/hid-sensor-magn-3d.c @@ -563,7 +563,7 @@ static const struct platform_device_id hid_magn_3d_ids[] = { /* Format: HID-SENSOR-usage_id_in_hex_lowercase */ .name = "HID-SENSOR-200083", }, - { /* sentinel */ } + { } }; MODULE_DEVICE_TABLE(platform, hid_magn_3d_ids); diff --git a/drivers/iio/magnetometer/hmc5843.h b/drivers/iio/magnetometer/hmc5843.h index ffd669b1ee7c..7a3faf7ffed4 100644 --- a/drivers/iio/magnetometer/hmc5843.h +++ b/drivers/iio/magnetometer/hmc5843.h @@ -34,7 +34,7 @@ enum hmc5843_ids { * @regmap: hardware access register maps * @variant: describe chip variants * @scan: buffer to pack data for passing to - * iio_push_to_buffers_with_timestamp() + * iio_push_to_buffers_with_ts() */ struct hmc5843_data { struct device *dev; diff --git a/drivers/iio/magnetometer/hmc5843_core.c b/drivers/iio/magnetometer/hmc5843_core.c index 2fc84310e2cc..fc16ebd314f7 100644 --- a/drivers/iio/magnetometer/hmc5843_core.c +++ b/drivers/iio/magnetometer/hmc5843_core.c @@ -452,8 +452,8 @@ static irqreturn_t hmc5843_trigger_handler(int irq, void *p) if (ret < 0) goto done; - iio_push_to_buffers_with_timestamp(indio_dev, &data->scan, - iio_get_time_ns(indio_dev)); + iio_push_to_buffers_with_ts(indio_dev, &data->scan, sizeof(data->scan), + iio_get_time_ns(indio_dev)); done: iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/magnetometer/hmc5843_i2c.c b/drivers/iio/magnetometer/hmc5843_i2c.c index 657a309e2bd5..b41709959e2b 100644 --- a/drivers/iio/magnetometer/hmc5843_i2c.c +++ b/drivers/iio/magnetometer/hmc5843_i2c.c @@ -84,7 +84,7 @@ static const struct of_device_id hmc5843_of_match[] = { { .compatible = "honeywell,hmc5883", .data = (void *)HMC5883_ID }, { .compatible = "honeywell,hmc5883l", .data = (void *)HMC5883L_ID }, { .compatible = "honeywell,hmc5983", .data = (void *)HMC5983_ID }, - {} + { } }; MODULE_DEVICE_TABLE(of, hmc5843_of_match); diff --git a/drivers/iio/magnetometer/hmc5843_spi.c b/drivers/iio/magnetometer/hmc5843_spi.c index b7fde331069d..6a55c1559b0d 100644 --- a/drivers/iio/magnetometer/hmc5843_spi.c +++ b/drivers/iio/magnetometer/hmc5843_spi.c @@ -60,7 +60,6 @@ static int hmc5843_spi_probe(struct spi_device *spi) spi->mode = SPI_MODE_3; spi->max_speed_hz = 8000000; - spi->bits_per_word = 8; ret = spi_setup(spi); if (ret) return ret; diff --git a/drivers/iio/magnetometer/mag3110.c b/drivers/iio/magnetometer/mag3110.c index 2fe8e97f2cf8..ff09250a06e7 100644 --- a/drivers/iio/magnetometer/mag3110.c +++ b/drivers/iio/magnetometer/mag3110.c @@ -9,6 +9,7 @@ * TODO: irq, user offset, oversampling, continuous mode */ +#include <linux/cleanup.h> #include <linux/module.h> #include <linux/i2c.h> #include <linux/iio/iio.h> @@ -102,17 +103,12 @@ static int mag3110_read(struct mag3110_data *data, __be16 buf[3]) { int ret; - mutex_lock(&data->lock); + guard(mutex)(&data->lock); ret = mag3110_request(data); - if (ret < 0) { - mutex_unlock(&data->lock); + if (ret < 0) return ret; - } - ret = i2c_smbus_read_i2c_block_data(data->client, - MAG3110_OUT_X, 3 * sizeof(__be16), (u8 *) buf); - mutex_unlock(&data->lock); - - return ret; + return i2c_smbus_read_i2c_block_data(data->client, MAG3110_OUT_X, + 3 * sizeof(__be16), (u8 *) buf); } static ssize_t mag3110_show_int_plus_micros(char *buf, @@ -231,19 +227,17 @@ static int mag3110_change_config(struct mag3110_data *data, u8 reg, u8 val) int ret; int is_active; - mutex_lock(&data->lock); + guard(mutex)(&data->lock); is_active = mag3110_is_active(data); - if (is_active < 0) { - ret = is_active; - goto fail; - } + if (is_active < 0) + return is_active; /* config can only be changed when in standby */ if (is_active > 0) { ret = mag3110_standby(data); if (ret < 0) - goto fail; + return ret; } /* @@ -252,23 +246,52 @@ static int mag3110_change_config(struct mag3110_data *data, u8 reg, u8 val) */ ret = mag3110_wait_standby(data); if (ret < 0) - goto fail; + return ret; ret = i2c_smbus_write_byte_data(data->client, reg, val); if (ret < 0) - goto fail; + return ret; if (is_active > 0) { ret = mag3110_active(data); if (ret < 0) - goto fail; + return ret; } - ret = 0; -fail: - mutex_unlock(&data->lock); + return 0; +} - return ret; +static int __mag3110_read_info_raw(struct mag3110_data *data, + struct iio_chan_spec const *chan, + int *val) +{ + __be16 buffer[3]; + int ret; + + switch (chan->type) { + case IIO_MAGN: /* in 0.1 uT / LSB */ + ret = mag3110_read(data, buffer); + if (ret < 0) + return ret; + *val = sign_extend32(be16_to_cpu(buffer[chan->scan_index]), + chan->scan_type.realbits - 1); + return IIO_VAL_INT; + + case IIO_TEMP: { /* in 1 C / LSB */ + guard(mutex)(&data->lock); + ret = mag3110_request(data); + if (ret < 0) + return ret; + ret = i2c_smbus_read_byte_data(data->client, + MAG3110_DIE_TEMP); + if (ret < 0) + return ret; + *val = sign_extend32(ret, chan->scan_type.realbits - 1); + return IIO_VAL_INT; + } + default: + return -EINVAL; + } } static int mag3110_read_raw(struct iio_dev *indio_dev, @@ -276,46 +299,14 @@ static int mag3110_read_raw(struct iio_dev *indio_dev, int *val, int *val2, long mask) { struct mag3110_data *data = iio_priv(indio_dev); - __be16 buffer[3]; int i, ret; switch (mask) { case IIO_CHAN_INFO_RAW: - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; - - switch (chan->type) { - case IIO_MAGN: /* in 0.1 uT / LSB */ - ret = mag3110_read(data, buffer); - if (ret < 0) - goto release; - *val = sign_extend32( - be16_to_cpu(buffer[chan->scan_index]), - chan->scan_type.realbits - 1); - ret = IIO_VAL_INT; - break; - case IIO_TEMP: /* in 1 C / LSB */ - mutex_lock(&data->lock); - ret = mag3110_request(data); - if (ret < 0) { - mutex_unlock(&data->lock); - goto release; - } - ret = i2c_smbus_read_byte_data(data->client, - MAG3110_DIE_TEMP); - mutex_unlock(&data->lock); - if (ret < 0) - goto release; - *val = sign_extend32(ret, - chan->scan_type.realbits - 1); - ret = IIO_VAL_INT; - break; - default: - ret = -EINVAL; - } -release: - iio_device_release_direct_mode(indio_dev); + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; + ret = __mag3110_read_info_raw(data, chan, val); + iio_device_release_direct(indio_dev); return ret; case IIO_CHAN_INFO_SCALE: @@ -346,24 +337,18 @@ release: return -EINVAL; } -static int mag3110_write_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int val, int val2, long mask) +static int __mag3110_write_raw(struct mag3110_data *data, + struct iio_chan_spec const *chan, + int val, int val2, long mask) { - struct mag3110_data *data = iio_priv(indio_dev); - int rate, ret; - - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; + int rate; switch (mask) { case IIO_CHAN_INFO_SAMP_FREQ: rate = mag3110_get_samp_freq_index(data, val, val2); - if (rate < 0) { - ret = -EINVAL; - break; - } + if (rate < 0) + return -EINVAL; + data->ctrl_reg1 &= 0xff & ~MAG3110_CTRL_DR_MASK & ~MAG3110_CTRL_AC; data->ctrl_reg1 |= rate << MAG3110_CTRL_DR_SHIFT; @@ -371,22 +356,32 @@ static int mag3110_write_raw(struct iio_dev *indio_dev, if (data->sleep_val < 40) data->ctrl_reg1 |= MAG3110_CTRL_AC; - ret = mag3110_change_config(data, MAG3110_CTRL_REG1, - data->ctrl_reg1); - break; + return mag3110_change_config(data, MAG3110_CTRL_REG1, + data->ctrl_reg1); + case IIO_CHAN_INFO_CALIBBIAS: - if (val < -10000 || val > 10000) { - ret = -EINVAL; - break; - } - ret = i2c_smbus_write_word_swapped(data->client, + if (val < -10000 || val > 10000) + return -EINVAL; + + return i2c_smbus_write_word_swapped(data->client, MAG3110_OFF_X + 2 * chan->scan_index, val << 1); - break; default: - ret = -EINVAL; - break; + return -EINVAL; } - iio_device_release_direct_mode(indio_dev); +} + +static int mag3110_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct mag3110_data *data = iio_priv(indio_dev); + int ret; + + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; + ret = __mag3110_write_raw(data, chan, val, val2, mask); + iio_device_release_direct(indio_dev); + return ret; } @@ -409,8 +404,8 @@ static irqreturn_t mag3110_trigger_handler(int irq, void *p) data->scan.temperature = ret; } - iio_push_to_buffers_with_timestamp(indio_dev, &data->scan, - iio_get_time_ns(indio_dev)); + iio_push_to_buffers_with_ts(indio_dev, &data->scan, sizeof(data->scan), + iio_get_time_ns(indio_dev)); done: iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/magnetometer/mmc35240.c b/drivers/iio/magnetometer/mmc35240.c index dd480a4a5f98..e08a57cd6de2 100644 --- a/drivers/iio/magnetometer/mmc35240.c +++ b/drivers/iio/magnetometer/mmc35240.c @@ -556,13 +556,13 @@ MODULE_DEVICE_TABLE(of, mmc35240_of_match); static const struct acpi_device_id mmc35240_acpi_match[] = { {"MMC35240", 0}, - { }, + { } }; MODULE_DEVICE_TABLE(acpi, mmc35240_acpi_match); static const struct i2c_device_id mmc35240_id[] = { { "mmc35240" }, - {} + { } }; MODULE_DEVICE_TABLE(i2c, mmc35240_id); diff --git a/drivers/iio/magnetometer/rm3100-core.c b/drivers/iio/magnetometer/rm3100-core.c index c99694a77a14..2b2884425746 100644 --- a/drivers/iio/magnetometer/rm3100-core.c +++ b/drivers/iio/magnetometer/rm3100-core.c @@ -399,12 +399,11 @@ static int rm3100_read_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_RAW: - ret = iio_device_claim_direct_mode(indio_dev); - if (ret < 0) - return ret; + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; ret = rm3100_read_mag(data, chan->scan_index, val); - iio_device_release_direct_mode(indio_dev); + iio_device_release_direct(indio_dev); return ret; case IIO_CHAN_INFO_SCALE: @@ -516,8 +515,8 @@ static irqreturn_t rm3100_trigger_handler(int irq, void *p) * Always using the same buffer so that we wouldn't need to set the * paddings to 0 in case of leaking any data. */ - iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, - pf->timestamp); + iio_push_to_buffers_with_ts(indio_dev, data->buffer, sizeof(data->buffer), + pf->timestamp); done: iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/magnetometer/rm3100-spi.c b/drivers/iio/magnetometer/rm3100-spi.c index dd6d48043740..2f60a41c07f7 100644 --- a/drivers/iio/magnetometer/rm3100-spi.c +++ b/drivers/iio/magnetometer/rm3100-spi.c @@ -32,7 +32,6 @@ static int rm3100_probe(struct spi_device *spi) spi->mode = SPI_MODE_0; /* Data rates cannot exceed 1Mbits. */ spi->max_speed_hz = 1000000; - spi->bits_per_word = 8; ret = spi_setup(spi); if (ret) return ret; diff --git a/drivers/iio/magnetometer/st_magn_i2c.c b/drivers/iio/magnetometer/st_magn_i2c.c index 1672b274768d..ed70e782af5e 100644 --- a/drivers/iio/magnetometer/st_magn_i2c.c +++ b/drivers/iio/magnetometer/st_magn_i2c.c @@ -54,7 +54,7 @@ static const struct of_device_id st_magn_of_match[] = { .compatible = "st,lsm303c-magn", .data = LSM303C_MAGN_DEV_NAME, }, - {}, + { } }; MODULE_DEVICE_TABLE(of, st_magn_of_match); @@ -102,7 +102,7 @@ static const struct i2c_device_id st_magn_id_table[] = { { LSM9DS1_MAGN_DEV_NAME }, { IIS2MDC_MAGN_DEV_NAME }, { LSM303C_MAGN_DEV_NAME }, - {}, + { } }; MODULE_DEVICE_TABLE(i2c, st_magn_id_table); diff --git a/drivers/iio/magnetometer/st_magn_spi.c b/drivers/iio/magnetometer/st_magn_spi.c index fe4d0e63133c..68816362bb95 100644 --- a/drivers/iio/magnetometer/st_magn_spi.c +++ b/drivers/iio/magnetometer/st_magn_spi.c @@ -49,7 +49,7 @@ static const struct of_device_id st_magn_of_match[] = { .compatible = "st,lsm303c-magn", .data = LSM303C_MAGN_DEV_NAME, }, - {} + { } }; MODULE_DEVICE_TABLE(of, st_magn_of_match); @@ -94,7 +94,7 @@ static const struct spi_device_id st_magn_id_table[] = { { LSM9DS1_MAGN_DEV_NAME }, { IIS2MDC_MAGN_DEV_NAME }, { LSM303C_MAGN_DEV_NAME }, - {}, + { } }; MODULE_DEVICE_TABLE(spi, st_magn_id_table); diff --git a/drivers/iio/magnetometer/tmag5273.c b/drivers/iio/magnetometer/tmag5273.c index 4187abe12784..2ca5c26f0091 100644 --- a/drivers/iio/magnetometer/tmag5273.c +++ b/drivers/iio/magnetometer/tmag5273.c @@ -712,13 +712,13 @@ static DEFINE_RUNTIME_DEV_PM_OPS(tmag5273_pm_ops, static const struct i2c_device_id tmag5273_id[] = { { "tmag5273" }, - { /* sentinel */ } + { } }; MODULE_DEVICE_TABLE(i2c, tmag5273_id); static const struct of_device_id tmag5273_of_match[] = { { .compatible = "ti,tmag5273" }, - { /* sentinel */ } + { } }; MODULE_DEVICE_TABLE(of, tmag5273_of_match); diff --git a/drivers/iio/magnetometer/yamaha-yas530.c b/drivers/iio/magnetometer/yamaha-yas530.c index 28012b20c64f..340607111d9a 100644 --- a/drivers/iio/magnetometer/yamaha-yas530.c +++ b/drivers/iio/magnetometer/yamaha-yas530.c @@ -674,8 +674,8 @@ static void yas5xx_fill_buffer(struct iio_dev *indio_dev) yas5xx->scan.channels[1] = x; yas5xx->scan.channels[2] = y; yas5xx->scan.channels[3] = z; - iio_push_to_buffers_with_timestamp(indio_dev, &yas5xx->scan, - iio_get_time_ns(indio_dev)); + iio_push_to_buffers_with_ts(indio_dev, &yas5xx->scan, sizeof(yas5xx->scan), + iio_get_time_ns(indio_dev)); } static irqreturn_t yas5xx_handle_trigger(int irq, void *p) @@ -1585,7 +1585,7 @@ static const struct i2c_device_id yas5xx_id[] = { {"yas532", (kernel_ulong_t)&yas5xx_chip_info_tbl[yas532] }, {"yas533", (kernel_ulong_t)&yas5xx_chip_info_tbl[yas533] }, {"yas537", (kernel_ulong_t)&yas5xx_chip_info_tbl[yas537] }, - {} + { } }; MODULE_DEVICE_TABLE(i2c, yas5xx_id); @@ -1594,7 +1594,7 @@ static const struct of_device_id yas5xx_of_match[] = { { .compatible = "yamaha,yas532", &yas5xx_chip_info_tbl[yas532] }, { .compatible = "yamaha,yas533", &yas5xx_chip_info_tbl[yas533] }, { .compatible = "yamaha,yas537", &yas5xx_chip_info_tbl[yas537] }, - {} + { } }; MODULE_DEVICE_TABLE(of, yas5xx_of_match); diff --git a/drivers/iio/multiplexer/iio-mux.c b/drivers/iio/multiplexer/iio-mux.c index c309d991490c..b742ca9a99d1 100644 --- a/drivers/iio/multiplexer/iio-mux.c +++ b/drivers/iio/multiplexer/iio-mux.c @@ -448,7 +448,7 @@ static int mux_probe(struct platform_device *pdev) static const struct of_device_id mux_match[] = { { .compatible = "io-channel-mux" }, - { /* sentinel */ } + { } }; MODULE_DEVICE_TABLE(of, mux_match); diff --git a/drivers/iio/orientation/hid-sensor-incl-3d.c b/drivers/iio/orientation/hid-sensor-incl-3d.c index 429035b65c65..4e23a598a3fb 100644 --- a/drivers/iio/orientation/hid-sensor-incl-3d.c +++ b/drivers/iio/orientation/hid-sensor-incl-3d.c @@ -399,7 +399,7 @@ static const struct platform_device_id hid_incl_3d_ids[] = { /* Format: HID-SENSOR-usage_id_in_hex_lowercase */ .name = "HID-SENSOR-200086", }, - { /* sentinel */ } + { } }; MODULE_DEVICE_TABLE(platform, hid_incl_3d_ids); diff --git a/drivers/iio/orientation/hid-sensor-rotation.c b/drivers/iio/orientation/hid-sensor-rotation.c index 96f03988640c..e759f91a710a 100644 --- a/drivers/iio/orientation/hid-sensor-rotation.c +++ b/drivers/iio/orientation/hid-sensor-rotation.c @@ -19,7 +19,7 @@ struct dev_rot_state { struct hid_sensor_common common_attributes; struct hid_sensor_hub_attribute_info quaternion; struct { - s32 sampled_vals[4] __aligned(16); + s32 sampled_vals[4]; aligned_s64 timestamp; } scan; int scale_pre_decml; @@ -351,7 +351,7 @@ static const struct platform_device_id hid_dev_rot_ids[] = { /* Geomagnetic orientation(AM) sensor */ .name = "HID-SENSOR-2000c1", }, - { /* sentinel */ } + { } }; MODULE_DEVICE_TABLE(platform, hid_dev_rot_ids); diff --git a/drivers/iio/position/hid-sensor-custom-intel-hinge.c b/drivers/iio/position/hid-sensor-custom-intel-hinge.c index 423bbb8a3b38..bff7039690ac 100644 --- a/drivers/iio/position/hid-sensor-custom-intel-hinge.c +++ b/drivers/iio/position/hid-sensor-custom-intel-hinge.c @@ -358,7 +358,7 @@ static const struct platform_device_id hid_hinge_ids[] = { /* Format: HID-SENSOR-INT-usage_id_in_hex_lowercase */ .name = "HID-SENSOR-INT-020b", }, - { /* sentinel */ } + { } }; MODULE_DEVICE_TABLE(platform, hid_hinge_ids); diff --git a/drivers/iio/potentiometer/ad5272.c b/drivers/iio/potentiometer/ad5272.c index b17941e4c2f7..672b1ca3a920 100644 --- a/drivers/iio/potentiometer/ad5272.c +++ b/drivers/iio/potentiometer/ad5272.c @@ -199,7 +199,7 @@ static const struct of_device_id ad5272_dt_ids[] = { { .compatible = "adi,ad5272-100", .data = (void *)AD5272_100 }, { .compatible = "adi,ad5274-020", .data = (void *)AD5274_020 }, { .compatible = "adi,ad5274-100", .data = (void *)AD5274_100 }, - {} + { } }; MODULE_DEVICE_TABLE(of, ad5272_dt_ids); @@ -209,7 +209,7 @@ static const struct i2c_device_id ad5272_id[] = { { "ad5272-100", AD5272_100 }, { "ad5274-020", AD5274_020 }, { "ad5274-100", AD5274_100 }, - {} + { } }; MODULE_DEVICE_TABLE(i2c, ad5272_id); diff --git a/drivers/iio/potentiometer/ds1803.c b/drivers/iio/potentiometer/ds1803.c index e0526dd0e3cb..5761f69c538a 100644 --- a/drivers/iio/potentiometer/ds1803.c +++ b/drivers/iio/potentiometer/ds1803.c @@ -231,7 +231,7 @@ static const struct of_device_id ds1803_dt_ids[] = { { .compatible = "maxim,ds1803-050", .data = &ds1803_cfg[DS1803_050] }, { .compatible = "maxim,ds1803-100", .data = &ds1803_cfg[DS1803_100] }, { .compatible = "maxim,ds3502", .data = &ds1803_cfg[DS3502] }, - {} + { } }; MODULE_DEVICE_TABLE(of, ds1803_dt_ids); @@ -240,7 +240,7 @@ static const struct i2c_device_id ds1803_id[] = { { "ds1803-050", (kernel_ulong_t)&ds1803_cfg[DS1803_050] }, { "ds1803-100", (kernel_ulong_t)&ds1803_cfg[DS1803_100] }, { "ds3502", (kernel_ulong_t)&ds1803_cfg[DS3502] }, - {} + { } }; MODULE_DEVICE_TABLE(i2c, ds1803_id); diff --git a/drivers/iio/potentiometer/max5432.c b/drivers/iio/potentiometer/max5432.c index c8e2481dadb5..26390be79d02 100644 --- a/drivers/iio/potentiometer/max5432.c +++ b/drivers/iio/potentiometer/max5432.c @@ -114,7 +114,7 @@ static const struct of_device_id max5432_dt_ids[] = { { .compatible = "maxim,max5433", .data = (void *)MAX5432_OHM_100K }, { .compatible = "maxim,max5434", .data = (void *)MAX5432_OHM_50K }, { .compatible = "maxim,max5435", .data = (void *)MAX5432_OHM_100K }, - { /* sentinel */ } + { } }; MODULE_DEVICE_TABLE(of, max5432_dt_ids); diff --git a/drivers/iio/potentiometer/max5487.c b/drivers/iio/potentiometer/max5487.c index 4838d2e72f53..3b11b991940b 100644 --- a/drivers/iio/potentiometer/max5487.c +++ b/drivers/iio/potentiometer/max5487.c @@ -137,7 +137,7 @@ static const struct acpi_device_id max5487_acpi_match[] = { { "MAX5487", 10 }, { "MAX5488", 50 }, { "MAX5489", 100 }, - { }, + { } }; MODULE_DEVICE_TABLE(acpi, max5487_acpi_match); diff --git a/drivers/iio/potentiometer/mcp4018.c b/drivers/iio/potentiometer/mcp4018.c index 44678d372126..a88bb2231850 100644 --- a/drivers/iio/potentiometer/mcp4018.c +++ b/drivers/iio/potentiometer/mcp4018.c @@ -117,7 +117,7 @@ static const struct i2c_device_id mcp4018_id[] = { MCP4018_ID_TABLE("mcp4019-103", MCP4018_103), MCP4018_ID_TABLE("mcp4019-503", MCP4018_503), MCP4018_ID_TABLE("mcp4019-104", MCP4018_104), - { /* sentinel */ } + { } }; MODULE_DEVICE_TABLE(i2c, mcp4018_id); @@ -139,7 +139,7 @@ static const struct of_device_id mcp4018_of_match[] = { MCP4018_COMPATIBLE("microchip,mcp4019-103", MCP4018_103), MCP4018_COMPATIBLE("microchip,mcp4019-503", MCP4018_503), MCP4018_COMPATIBLE("microchip,mcp4019-104", MCP4018_104), - { /* sentinel */ } + { } }; MODULE_DEVICE_TABLE(of, mcp4018_of_match); diff --git a/drivers/iio/potentiometer/mcp41010.c b/drivers/iio/potentiometer/mcp41010.c index 2b73c7540209..f35fc4a6c55b 100644 --- a/drivers/iio/potentiometer/mcp41010.c +++ b/drivers/iio/potentiometer/mcp41010.c @@ -171,7 +171,7 @@ static const struct of_device_id mcp41010_match[] = { { .compatible = "microchip,mcp42010", .data = &mcp41010_cfg[MCP42010] }, { .compatible = "microchip,mcp42050", .data = &mcp41010_cfg[MCP42050] }, { .compatible = "microchip,mcp42100", .data = &mcp41010_cfg[MCP42100] }, - {} + { } }; MODULE_DEVICE_TABLE(of, mcp41010_match); @@ -182,7 +182,7 @@ static const struct spi_device_id mcp41010_id[] = { { "mcp42010", MCP42010 }, { "mcp42050", MCP42050 }, { "mcp42100", MCP42100 }, - {} + { } }; MODULE_DEVICE_TABLE(spi, mcp41010_id); diff --git a/drivers/iio/potentiometer/mcp4131.c b/drivers/iio/potentiometer/mcp4131.c index 7890c0993ec4..9082b559d029 100644 --- a/drivers/iio/potentiometer/mcp4131.c +++ b/drivers/iio/potentiometer/mcp4131.c @@ -403,7 +403,7 @@ static const struct of_device_id mcp4131_dt_ids[] = { .data = &mcp4131_cfg[MCP426x_503] }, { .compatible = "microchip,mcp4262-104", .data = &mcp4131_cfg[MCP426x_104] }, - {} + { } }; MODULE_DEVICE_TABLE(of, mcp4131_dt_ids); @@ -472,7 +472,7 @@ static const struct spi_device_id mcp4131_id[] = { { "mcp4262-103", MCP426x_103 }, { "mcp4262-503", MCP426x_503 }, { "mcp4262-104", MCP426x_104 }, - {} + { } }; MODULE_DEVICE_TABLE(spi, mcp4131_id); diff --git a/drivers/iio/potentiometer/mcp4531.c b/drivers/iio/potentiometer/mcp4531.c index f28880ebd758..9912e91ff7b4 100644 --- a/drivers/iio/potentiometer/mcp4531.c +++ b/drivers/iio/potentiometer/mcp4531.c @@ -276,7 +276,7 @@ static const struct i2c_device_id mcp4531_id[] = { MCP4531_ID_TABLE("mcp4662-103", MCP466x_103), MCP4531_ID_TABLE("mcp4662-503", MCP466x_503), MCP4531_ID_TABLE("mcp4662-104", MCP466x_104), - { /* sentinel */ } + { } }; MODULE_DEVICE_TABLE(i2c, mcp4531_id); @@ -350,7 +350,7 @@ static const struct of_device_id mcp4531_of_match[] = { MCP4531_COMPATIBLE("microchip,mcp4662-103", MCP466x_103), MCP4531_COMPATIBLE("microchip,mcp4662-503", MCP466x_503), MCP4531_COMPATIBLE("microchip,mcp4662-104", MCP466x_104), - { /* sentinel */ } + { } }; MODULE_DEVICE_TABLE(of, mcp4531_of_match); diff --git a/drivers/iio/potentiometer/tpl0102.c b/drivers/iio/potentiometer/tpl0102.c index 8923ccb0fc4f..a42b57733363 100644 --- a/drivers/iio/potentiometer/tpl0102.c +++ b/drivers/iio/potentiometer/tpl0102.c @@ -153,7 +153,7 @@ static const struct i2c_device_id tpl0102_id[] = { { "cat5140-104", CAT5140_104 }, { "tpl0102-104", TPL0102_104 }, { "tpl0401-103", TPL0401_103 }, - {} + { } }; MODULE_DEVICE_TABLE(i2c, tpl0102_id); diff --git a/drivers/iio/potentiostat/lmp91000.c b/drivers/iio/potentiostat/lmp91000.c index c2c6b2b29867..030498d0b763 100644 --- a/drivers/iio/potentiostat/lmp91000.c +++ b/drivers/iio/potentiostat/lmp91000.c @@ -400,14 +400,14 @@ static void lmp91000_remove(struct i2c_client *client) static const struct of_device_id lmp91000_of_match[] = { { .compatible = "ti,lmp91000", }, { .compatible = "ti,lmp91002", }, - { }, + { } }; MODULE_DEVICE_TABLE(of, lmp91000_of_match); static const struct i2c_device_id lmp91000_id[] = { { "lmp91000" }, { "lmp91002" }, - {} + { } }; MODULE_DEVICE_TABLE(i2c, lmp91000_id); diff --git a/drivers/iio/pressure/abp060mg.c b/drivers/iio/pressure/abp060mg.c index 752a63c06b44..a0d956c3e254 100644 --- a/drivers/iio/pressure/abp060mg.c +++ b/drivers/iio/pressure/abp060mg.c @@ -247,7 +247,7 @@ static const struct i2c_device_id abp060mg_id_table[] = { { "abp015pd", ABP015PD }, { "abp030pd", ABP030PD }, { "abp060pd", ABP060PD }, - { /* empty */ }, + { } }; MODULE_DEVICE_TABLE(i2c, abp060mg_id_table); diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c index d44ab65c94cb..f37f20776c89 100644 --- a/drivers/iio/pressure/bmp280-core.c +++ b/drivers/iio/pressure/bmp280-core.c @@ -46,6 +46,7 @@ #include <linux/random.h> #include <linux/regmap.h> #include <linux/regulator/consumer.h> +#include <linux/types.h> #include <linux/iio/buffer.h> #include <linux/iio/iio.h> @@ -1105,9 +1106,13 @@ static irqreturn_t bmp280_trigger_handler(int irq, void *p) struct iio_poll_func *pf = p; struct iio_dev *indio_dev = pf->indio_dev; struct bmp280_data *data = iio_priv(indio_dev); - u32 adc_temp, adc_press, comp_press; - s32 t_fine, comp_temp; - s32 *chans = (s32 *)data->sensor_data; + u32 adc_temp, adc_press; + s32 t_fine; + struct { + u32 comp_press; + s32 comp_temp; + aligned_s64 timestamp; + } buffer; int ret; guard(mutex)(&data->lock); @@ -1127,7 +1132,7 @@ static irqreturn_t bmp280_trigger_handler(int irq, void *p) goto out; } - comp_temp = bmp280_compensate_temp(data, adc_temp); + buffer.comp_temp = bmp280_compensate_temp(data, adc_temp); /* Pressure calculations */ adc_press = FIELD_GET(BMP280_MEAS_TRIM_MASK, get_unaligned_be24(&data->buf[0])); @@ -1137,13 +1142,10 @@ static irqreturn_t bmp280_trigger_handler(int irq, void *p) } t_fine = bmp280_calc_t_fine(data, adc_temp); - comp_press = bmp280_compensate_press(data, adc_press, t_fine); - - chans[0] = comp_press; - chans[1] = comp_temp; + buffer.comp_press = bmp280_compensate_press(data, adc_press, t_fine); - iio_push_to_buffers_with_timestamp(indio_dev, data->sensor_data, - iio_get_time_ns(indio_dev)); + iio_push_to_buffers_with_ts(indio_dev, &buffer, sizeof(buffer), + iio_get_time_ns(indio_dev)); out: iio_trigger_notify_done(indio_dev->trig); @@ -1225,11 +1227,19 @@ static irqreturn_t bme280_trigger_handler(int irq, void *p) struct iio_poll_func *pf = p; struct iio_dev *indio_dev = pf->indio_dev; struct bmp280_data *data = iio_priv(indio_dev); - u32 adc_temp, adc_press, adc_humidity, comp_press, comp_humidity; - s32 t_fine, comp_temp; - s32 *chans = (s32 *)data->sensor_data; + u32 adc_temp, adc_press, adc_humidity; + s32 t_fine; + struct { + u32 comp_press; + s32 comp_temp; + u32 comp_humidity; + aligned_s64 timestamp; + } buffer; int ret; + /* Don't leak uninitialized stack to userspace. */ + memset(&buffer, 0, sizeof(buffer)); + guard(mutex)(&data->lock); /* Burst read data registers */ @@ -1247,7 +1257,7 @@ static irqreturn_t bme280_trigger_handler(int irq, void *p) goto out; } - comp_temp = bmp280_compensate_temp(data, adc_temp); + buffer.comp_temp = bmp280_compensate_temp(data, adc_temp); /* Pressure calculations */ adc_press = FIELD_GET(BMP280_MEAS_TRIM_MASK, get_unaligned_be24(&data->buf[0])); @@ -1257,7 +1267,7 @@ static irqreturn_t bme280_trigger_handler(int irq, void *p) } t_fine = bmp280_calc_t_fine(data, adc_temp); - comp_press = bmp280_compensate_press(data, adc_press, t_fine); + buffer.comp_press = bmp280_compensate_press(data, adc_press, t_fine); /* Humidity calculations */ adc_humidity = get_unaligned_be16(&data->buf[6]); @@ -1267,14 +1277,11 @@ static irqreturn_t bme280_trigger_handler(int irq, void *p) goto out; } - comp_humidity = bme280_compensate_humidity(data, adc_humidity, t_fine); - - chans[0] = comp_press; - chans[1] = comp_temp; - chans[2] = comp_humidity; + buffer.comp_humidity = bme280_compensate_humidity(data, adc_humidity, + t_fine); - iio_push_to_buffers_with_timestamp(indio_dev, data->sensor_data, - iio_get_time_ns(indio_dev)); + iio_push_to_buffers_with_ts(indio_dev, &buffer, sizeof(buffer), + iio_get_time_ns(indio_dev)); out: iio_trigger_notify_done(indio_dev->trig); @@ -1899,9 +1906,13 @@ static irqreturn_t bmp380_trigger_handler(int irq, void *p) struct iio_poll_func *pf = p; struct iio_dev *indio_dev = pf->indio_dev; struct bmp280_data *data = iio_priv(indio_dev); - u32 adc_temp, adc_press, comp_press; - s32 t_fine, comp_temp; - s32 *chans = (s32 *)data->sensor_data; + u32 adc_temp, adc_press; + s32 t_fine; + struct { + u32 comp_press; + s32 comp_temp; + aligned_s64 timestamp; + } buffer; int ret; guard(mutex)(&data->lock); @@ -1921,7 +1932,7 @@ static irqreturn_t bmp380_trigger_handler(int irq, void *p) goto out; } - comp_temp = bmp380_compensate_temp(data, adc_temp); + buffer.comp_temp = bmp380_compensate_temp(data, adc_temp); /* Pressure calculations */ adc_press = get_unaligned_le24(&data->buf[0]); @@ -1931,13 +1942,10 @@ static irqreturn_t bmp380_trigger_handler(int irq, void *p) } t_fine = bmp380_calc_t_fine(data, adc_temp); - comp_press = bmp380_compensate_press(data, adc_press, t_fine); + buffer.comp_press = bmp380_compensate_press(data, adc_press, t_fine); - chans[0] = comp_press; - chans[1] = comp_temp; - - iio_push_to_buffers_with_timestamp(indio_dev, data->sensor_data, - iio_get_time_ns(indio_dev)); + iio_push_to_buffers_with_ts(indio_dev, &buffer, sizeof(buffer), + iio_get_time_ns(indio_dev)); out: iio_trigger_notify_done(indio_dev->trig); @@ -2608,7 +2616,12 @@ static irqreturn_t bmp580_trigger_handler(int irq, void *p) struct iio_poll_func *pf = p; struct iio_dev *indio_dev = pf->indio_dev; struct bmp280_data *data = iio_priv(indio_dev); - int ret, offset; + struct { + __le32 comp_temp; + __le32 comp_press; + aligned_s64 timestamp; + } buffer; + int ret; guard(mutex)(&data->lock); @@ -2620,18 +2633,14 @@ static irqreturn_t bmp580_trigger_handler(int irq, void *p) goto out; } - offset = 0; - /* Pressure calculations */ - memcpy(&data->sensor_data[offset], &data->buf[3], 3); - - offset += sizeof(s32); + memcpy(&buffer.comp_press, &data->buf[3], 3); /* Temperature calculations */ - memcpy(&data->sensor_data[offset], &data->buf[0], 3); + memcpy(&buffer.comp_temp, &data->buf[0], 3); - iio_push_to_buffers_with_timestamp(indio_dev, data->sensor_data, - iio_get_time_ns(indio_dev)); + iio_push_to_buffers_with_ts(indio_dev, &buffer, sizeof(buffer), + iio_get_time_ns(indio_dev)); out: iio_trigger_notify_done(indio_dev->trig); @@ -2952,25 +2961,26 @@ static irqreturn_t bmp180_trigger_handler(int irq, void *p) struct iio_poll_func *pf = p; struct iio_dev *indio_dev = pf->indio_dev; struct bmp280_data *data = iio_priv(indio_dev); - int ret, comp_temp, comp_press; - s32 *chans = (s32 *)data->sensor_data; + struct { + u32 comp_press; + s32 comp_temp; + aligned_s64 timestamp; + } buffer; + int ret; guard(mutex)(&data->lock); - ret = bmp180_read_temp(data, &comp_temp); + ret = bmp180_read_temp(data, &buffer.comp_temp); if (ret) goto out; - ret = bmp180_read_press(data, &comp_press); + ret = bmp180_read_press(data, &buffer.comp_press); if (ret) goto out; - chans[0] = comp_press; - chans[1] = comp_temp; - - iio_push_to_buffers_with_timestamp(indio_dev, data->sensor_data, - iio_get_time_ns(indio_dev)); + iio_push_to_buffers_with_ts(indio_dev, &buffer, sizeof(buffer), + iio_get_time_ns(indio_dev)); out: iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/pressure/bmp280-i2c.c b/drivers/iio/pressure/bmp280-i2c.c index 868e1b2ec711..8e459b6c97ff 100644 --- a/drivers/iio/pressure/bmp280-i2c.c +++ b/drivers/iio/pressure/bmp280-i2c.c @@ -33,7 +33,7 @@ static const struct of_device_id bmp280_of_i2c_match[] = { { .compatible = "bosch,bme280", .data = &bme280_chip_info }, { .compatible = "bosch,bmp380", .data = &bmp380_chip_info }, { .compatible = "bosch,bmp580", .data = &bmp580_chip_info }, - { }, + { } }; MODULE_DEVICE_TABLE(of, bmp280_of_i2c_match); @@ -44,7 +44,7 @@ static const struct i2c_device_id bmp280_i2c_id[] = { {"bme280", (kernel_ulong_t)&bme280_chip_info }, {"bmp380", (kernel_ulong_t)&bmp380_chip_info }, {"bmp580", (kernel_ulong_t)&bmp580_chip_info }, - { }, + { } }; MODULE_DEVICE_TABLE(i2c, bmp280_i2c_id); diff --git a/drivers/iio/pressure/bmp280-spi.c b/drivers/iio/pressure/bmp280-spi.c index 0e6e27892f99..3b90384f17d7 100644 --- a/drivers/iio/pressure/bmp280-spi.c +++ b/drivers/iio/pressure/bmp280-spi.c @@ -81,14 +81,6 @@ static int bmp280_spi_probe(struct spi_device *spi) const struct bmp280_chip_info *chip_info; struct regmap_bus const *bmp_regmap_bus; struct regmap *regmap; - int ret; - - spi->bits_per_word = 8; - ret = spi_setup(spi); - if (ret < 0) { - dev_err(&spi->dev, "spi_setup failed!\n"); - return ret; - } chip_info = spi_get_device_match_data(spi); @@ -121,7 +113,7 @@ static const struct of_device_id bmp280_of_spi_match[] = { { .compatible = "bosch,bme280", .data = &bme280_chip_info }, { .compatible = "bosch,bmp380", .data = &bmp380_chip_info }, { .compatible = "bosch,bmp580", .data = &bmp580_chip_info }, - { }, + { } }; MODULE_DEVICE_TABLE(of, bmp280_of_spi_match); diff --git a/drivers/iio/pressure/bmp280.h b/drivers/iio/pressure/bmp280.h index 5b2ee1d0ee46..25bb9c743a05 100644 --- a/drivers/iio/pressure/bmp280.h +++ b/drivers/iio/pressure/bmp280.h @@ -349,7 +349,6 @@ BMP280_NUM_TEMP_BYTES + \ BME280_NUM_HUMIDITY_BYTES) -#define BME280_NUM_MAX_CHANNELS 3 /* Core exported structs */ static const char *const bmp280_supply_names[] = { @@ -452,13 +451,6 @@ struct bmp280_data { */ int sampling_freq; - /* - * Data to push to userspace triggered buffer. Up to 3 channels and - * s64 timestamp, aligned. - */ - u8 sensor_data[ALIGN(sizeof(s32) * BME280_NUM_MAX_CHANNELS, sizeof(s64)) - + sizeof(s64)] __aligned(sizeof(s64)); - /* Value to hold the current operation mode of the device */ enum bmp280_op_mode op_mode; diff --git a/drivers/iio/pressure/cros_ec_baro.c b/drivers/iio/pressure/cros_ec_baro.c index 2649c2f89e89..c6b950c596c1 100644 --- a/drivers/iio/pressure/cros_ec_baro.c +++ b/drivers/iio/pressure/cros_ec_baro.c @@ -192,7 +192,7 @@ static const struct platform_device_id cros_ec_baro_ids[] = { { .name = "cros-ec-baro", }, - { /* sentinel */ } + { } }; MODULE_DEVICE_TABLE(platform, cros_ec_baro_ids); diff --git a/drivers/iio/pressure/dlhl60d.c b/drivers/iio/pressure/dlhl60d.c index e99e97ea6300..48afe5c94000 100644 --- a/drivers/iio/pressure/dlhl60d.c +++ b/drivers/iio/pressure/dlhl60d.c @@ -147,12 +147,11 @@ static int dlh_read_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_RAW: - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; ret = dlh_read_direct(st, &pressure, &temperature); - iio_device_release_direct_mode(indio_dev); + iio_device_release_direct(indio_dev); if (ret) return ret; @@ -344,14 +343,14 @@ static int dlh_probe(struct i2c_client *client) static const struct of_device_id dlh_of_match[] = { { .compatible = "asc,dlhl60d" }, { .compatible = "asc,dlhl60g" }, - {} + { } }; MODULE_DEVICE_TABLE(of, dlh_of_match); static const struct i2c_device_id dlh_id[] = { { "dlhl60d", dlhl60d }, { "dlhl60g", dlhl60g }, - {} + { } }; MODULE_DEVICE_TABLE(i2c, dlh_id); diff --git a/drivers/iio/pressure/dps310.c b/drivers/iio/pressure/dps310.c index c6f44f0f4d2e..8edaa4d10a70 100644 --- a/drivers/iio/pressure/dps310.c +++ b/drivers/iio/pressure/dps310.c @@ -888,13 +888,13 @@ static int dps310_probe(struct i2c_client *client) static const struct i2c_device_id dps310_id[] = { { DPS310_DEV_NAME }, - {} + { } }; MODULE_DEVICE_TABLE(i2c, dps310_id); static const struct acpi_device_id dps310_acpi_match[] = { { "IFX3100" }, - {} + { } }; MODULE_DEVICE_TABLE(acpi, dps310_acpi_match); diff --git a/drivers/iio/pressure/hid-sensor-press.c b/drivers/iio/pressure/hid-sensor-press.c index f7273d30c5f0..5f1d6abda3e4 100644 --- a/drivers/iio/pressure/hid-sensor-press.c +++ b/drivers/iio/pressure/hid-sensor-press.c @@ -176,8 +176,9 @@ static int press_proc_event(struct hid_sensor_hub_device *hsdev, if (!press_state->timestamp) press_state->timestamp = iio_get_time_ns(indio_dev); - iio_push_to_buffers_with_timestamp( - indio_dev, &press_state->scan, press_state->timestamp); + iio_push_to_buffers_with_ts(indio_dev, &press_state->scan, + sizeof(press_state->scan), + press_state->timestamp); } return 0; @@ -339,7 +340,7 @@ static const struct platform_device_id hid_press_ids[] = { /* Format: HID-SENSOR-usage_id_in_hex_lowercase */ .name = "HID-SENSOR-200031", }, - { /* sentinel */ } + { } }; MODULE_DEVICE_TABLE(platform, hid_press_ids); diff --git a/drivers/iio/pressure/hp03.c b/drivers/iio/pressure/hp03.c index 6f7a16787143..cbb4aaf45e2c 100644 --- a/drivers/iio/pressure/hp03.c +++ b/drivers/iio/pressure/hp03.c @@ -273,7 +273,7 @@ MODULE_DEVICE_TABLE(i2c, hp03_id); static const struct of_device_id hp03_of_match[] = { { .compatible = "hoperf,hp03" }, - { }, + { } }; MODULE_DEVICE_TABLE(of, hp03_of_match); diff --git a/drivers/iio/pressure/hp206c.c b/drivers/iio/pressure/hp206c.c index 442740941933..abe10ccb6770 100644 --- a/drivers/iio/pressure/hp206c.c +++ b/drivers/iio/pressure/hp206c.c @@ -396,13 +396,13 @@ static int hp206c_probe(struct i2c_client *client) static const struct i2c_device_id hp206c_id[] = { {"hp206c"}, - {} + { } }; MODULE_DEVICE_TABLE(i2c, hp206c_id); static const struct acpi_device_id hp206c_acpi_match[] = { {"HOP206C", 0}, - { }, + { } }; MODULE_DEVICE_TABLE(acpi, hp206c_acpi_match); diff --git a/drivers/iio/pressure/hsc030pa.c b/drivers/iio/pressure/hsc030pa.c index 168245818cfe..2d00c0656259 100644 --- a/drivers/iio/pressure/hsc030pa.c +++ b/drivers/iio/pressure/hsc030pa.c @@ -314,8 +314,8 @@ static irqreturn_t hsc_trigger_handler(int irq, void *private) memcpy(&data->scan.chan[0], &data->buffer[0], 2); memcpy(&data->scan.chan[1], &data->buffer[2], 2); - iio_push_to_buffers_with_timestamp(indio_dev, &data->scan, - iio_get_time_ns(indio_dev)); + iio_push_to_buffers_with_ts(indio_dev, &data->scan, sizeof(data->scan), + iio_get_time_ns(indio_dev)); error: iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/pressure/hsc030pa_i2c.c b/drivers/iio/pressure/hsc030pa_i2c.c index 7f2398aa8155..a34ef4653f34 100644 --- a/drivers/iio/pressure/hsc030pa_i2c.c +++ b/drivers/iio/pressure/hsc030pa_i2c.c @@ -48,13 +48,13 @@ static int hsc_i2c_probe(struct i2c_client *client) static const struct of_device_id hsc_i2c_match[] = { { .compatible = "honeywell,hsc030pa" }, - {} + { } }; MODULE_DEVICE_TABLE(of, hsc_i2c_match); static const struct i2c_device_id hsc_i2c_id[] = { { "hsc030pa" }, - {} + { } }; MODULE_DEVICE_TABLE(i2c, hsc_i2c_id); diff --git a/drivers/iio/pressure/hsc030pa_spi.c b/drivers/iio/pressure/hsc030pa_spi.c index 60768726e9ad..5d331b3b6da8 100644 --- a/drivers/iio/pressure/hsc030pa_spi.c +++ b/drivers/iio/pressure/hsc030pa_spi.c @@ -35,13 +35,13 @@ static int hsc_spi_probe(struct spi_device *spi) static const struct of_device_id hsc_spi_match[] = { { .compatible = "honeywell,hsc030pa" }, - {} + { } }; MODULE_DEVICE_TABLE(of, hsc_spi_match); static const struct spi_device_id hsc_spi_id[] = { { "hsc030pa" }, - {} + { } }; MODULE_DEVICE_TABLE(spi, hsc_spi_id); diff --git a/drivers/iio/pressure/icp10100.c b/drivers/iio/pressure/icp10100.c index 3e0bf5d31ad7..1951c1cc84cf 100644 --- a/drivers/iio/pressure/icp10100.c +++ b/drivers/iio/pressure/icp10100.c @@ -343,9 +343,8 @@ static int icp10100_read_raw_measures(struct iio_dev *indio_dev, uint32_t pressure_mPa; int ret; - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; ret = icp10100_get_measures(st, &raw_pressure, &raw_temp); if (ret) @@ -370,7 +369,7 @@ static int icp10100_read_raw_measures(struct iio_dev *indio_dev, } error_release: - iio_device_release_direct_mode(indio_dev); + iio_device_release_direct(indio_dev); return ret; } @@ -439,7 +438,6 @@ static int icp10100_write_raw(struct iio_dev *indio_dev, { struct icp10100_state *st = iio_priv(indio_dev); unsigned int mode; - int ret; switch (mask) { case IIO_CHAN_INFO_OVERSAMPLING_RATIO: @@ -449,13 +447,12 @@ static int icp10100_write_raw(struct iio_dev *indio_dev, mode = ilog2(val); if (mode >= ICP10100_MODE_NB) return -EINVAL; - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; mutex_lock(&st->lock); st->mode = mode; mutex_unlock(&st->lock); - iio_device_release_direct_mode(indio_dev); + iio_device_release_direct(indio_dev); return 0; default: return -EINVAL; diff --git a/drivers/iio/pressure/mpl115_spi.c b/drivers/iio/pressure/mpl115_spi.c index 888cfa666238..4e1d24beff94 100644 --- a/drivers/iio/pressure/mpl115_spi.c +++ b/drivers/iio/pressure/mpl115_spi.c @@ -85,7 +85,7 @@ static int mpl115_spi_probe(struct spi_device *spi) static const struct spi_device_id mpl115_spi_ids[] = { { "mpl115", 0 }, - {} + { } }; MODULE_DEVICE_TABLE(spi, mpl115_spi_ids); diff --git a/drivers/iio/pressure/mpl3115.c b/drivers/iio/pressure/mpl3115.c index 71ded2eee060..d6715997f137 100644 --- a/drivers/iio/pressure/mpl3115.c +++ b/drivers/iio/pressure/mpl3115.c @@ -69,6 +69,52 @@ static int mpl3115_request(struct mpl3115_data *data) return 0; } +static int mpl3115_read_info_raw(struct mpl3115_data *data, + struct iio_chan_spec const *chan, int *val) +{ + int ret; + + switch (chan->type) { + case IIO_PRESSURE: { /* in 0.25 pascal / LSB */ + __be32 tmp = 0; + + guard(mutex)(&data->lock); + ret = mpl3115_request(data); + if (ret < 0) + return ret; + + ret = i2c_smbus_read_i2c_block_data(data->client, + MPL3115_OUT_PRESS, + 3, (u8 *) &tmp); + if (ret < 0) + return ret; + + *val = be32_to_cpu(tmp) >> chan->scan_type.shift; + return IIO_VAL_INT; + } + case IIO_TEMP: { /* in 0.0625 celsius / LSB */ + __be16 tmp; + + guard(mutex)(&data->lock); + ret = mpl3115_request(data); + if (ret < 0) + return ret; + + ret = i2c_smbus_read_i2c_block_data(data->client, + MPL3115_OUT_TEMP, + 2, (u8 *) &tmp); + if (ret < 0) + return ret; + + *val = sign_extend32(be16_to_cpu(tmp) >> chan->scan_type.shift, + chan->scan_type.realbits - 1); + return IIO_VAL_INT; + } + default: + return -EINVAL; + } +} + static int mpl3115_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long mask) @@ -78,54 +124,11 @@ static int mpl3115_read_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_RAW: - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; - - switch (chan->type) { - case IIO_PRESSURE: { /* in 0.25 pascal / LSB */ - __be32 tmp = 0; - - mutex_lock(&data->lock); - ret = mpl3115_request(data); - if (ret < 0) { - mutex_unlock(&data->lock); - break; - } - ret = i2c_smbus_read_i2c_block_data(data->client, - MPL3115_OUT_PRESS, 3, (u8 *) &tmp); - mutex_unlock(&data->lock); - if (ret < 0) - break; - *val = be32_to_cpu(tmp) >> chan->scan_type.shift; - ret = IIO_VAL_INT; - break; - } - case IIO_TEMP: { /* in 0.0625 celsius / LSB */ - __be16 tmp; - - mutex_lock(&data->lock); - ret = mpl3115_request(data); - if (ret < 0) { - mutex_unlock(&data->lock); - break; - } - ret = i2c_smbus_read_i2c_block_data(data->client, - MPL3115_OUT_TEMP, 2, (u8 *) &tmp); - mutex_unlock(&data->lock); - if (ret < 0) - break; - *val = sign_extend32(be16_to_cpu(tmp) >> chan->scan_type.shift, - chan->scan_type.realbits - 1); - ret = IIO_VAL_INT; - break; - } - default: - ret = -EINVAL; - break; - } + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; - iio_device_release_direct_mode(indio_dev); + ret = mpl3115_read_info_raw(data, chan, val); + iio_device_release_direct(indio_dev); return ret; case IIO_CHAN_INFO_SCALE: @@ -188,8 +191,8 @@ static irqreturn_t mpl3115_trigger_handler(int irq, void *p) } mutex_unlock(&data->lock); - iio_push_to_buffers_with_timestamp(indio_dev, buffer, - iio_get_time_ns(indio_dev)); + iio_push_to_buffers_with_ts(indio_dev, buffer, sizeof(buffer), + iio_get_time_ns(indio_dev)); done: iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/pressure/mprls0025pa_i2c.c b/drivers/iio/pressure/mprls0025pa_i2c.c index 48b23a4256ce..1a48f8d43d71 100644 --- a/drivers/iio/pressure/mprls0025pa_i2c.c +++ b/drivers/iio/pressure/mprls0025pa_i2c.c @@ -74,13 +74,13 @@ static int mpr_i2c_probe(struct i2c_client *client) static const struct of_device_id mpr_i2c_match[] = { { .compatible = "honeywell,mprls0025pa" }, - {} + { } }; MODULE_DEVICE_TABLE(of, mpr_i2c_match); static const struct i2c_device_id mpr_i2c_id[] = { { "mprls0025pa" }, - {} + { } }; MODULE_DEVICE_TABLE(i2c, mpr_i2c_id); diff --git a/drivers/iio/pressure/mprls0025pa_spi.c b/drivers/iio/pressure/mprls0025pa_spi.c index 09f724c76d70..d04102f8a4a0 100644 --- a/drivers/iio/pressure/mprls0025pa_spi.c +++ b/drivers/iio/pressure/mprls0025pa_spi.c @@ -66,13 +66,13 @@ static int mpr_spi_probe(struct spi_device *spi) static const struct of_device_id mpr_spi_match[] = { { .compatible = "honeywell,mprls0025pa" }, - {} + { } }; MODULE_DEVICE_TABLE(of, mpr_spi_match); static const struct spi_device_id mpr_spi_id[] = { { "mprls0025pa" }, - {} + { } }; MODULE_DEVICE_TABLE(spi, mpr_spi_id); diff --git a/drivers/iio/pressure/ms5611_core.c b/drivers/iio/pressure/ms5611_core.c index 00c077b2a2a4..bdac27bd5a5d 100644 --- a/drivers/iio/pressure/ms5611_core.c +++ b/drivers/iio/pressure/ms5611_core.c @@ -308,7 +308,6 @@ static int ms5611_write_raw(struct iio_dev *indio_dev, { struct ms5611_state *st = iio_priv(indio_dev); const struct ms5611_osr *osr = NULL; - int ret; if (mask != IIO_CHAN_INFO_OVERSAMPLING_RATIO) return -EINVAL; @@ -322,9 +321,8 @@ static int ms5611_write_raw(struct iio_dev *indio_dev, if (!osr) return -EINVAL; - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; mutex_lock(&st->lock); @@ -334,7 +332,7 @@ static int ms5611_write_raw(struct iio_dev *indio_dev, st->pressure_osr = osr; mutex_unlock(&st->lock); - iio_device_release_direct_mode(indio_dev); + iio_device_release_direct(indio_dev); return 0; } diff --git a/drivers/iio/pressure/ms5611_spi.c b/drivers/iio/pressure/ms5611_spi.c index b5a91e885793..25c7bd2d8fdf 100644 --- a/drivers/iio/pressure/ms5611_spi.c +++ b/drivers/iio/pressure/ms5611_spi.c @@ -92,7 +92,6 @@ static int ms5611_spi_probe(struct spi_device *spi) spi->mode = SPI_MODE_0; spi->max_speed_hz = min(spi->max_speed_hz, 20000000U); - spi->bits_per_word = 8; ret = spi_setup(spi); if (ret < 0) return ret; diff --git a/drivers/iio/pressure/ms5637.c b/drivers/iio/pressure/ms5637.c index a1767a17fdce..59705a666979 100644 --- a/drivers/iio/pressure/ms5637.c +++ b/drivers/iio/pressure/ms5637.c @@ -219,7 +219,7 @@ static const struct i2c_device_id ms5637_id[] = { {"ms5805", (kernel_ulong_t)&ms5805_data }, {"ms5837", (kernel_ulong_t)&ms5837_data }, {"ms8607-temppressure", (kernel_ulong_t)&ms8607_data }, - {} + { } }; MODULE_DEVICE_TABLE(i2c, ms5637_id); @@ -229,7 +229,7 @@ static const struct of_device_id ms5637_of_match[] = { { .compatible = "meas,ms5805", .data = &ms5805_data }, { .compatible = "meas,ms5837", .data = &ms5837_data }, { .compatible = "meas,ms8607-temppressure", .data = &ms8607_data }, - { }, + { } }; MODULE_DEVICE_TABLE(of, ms5637_of_match); diff --git a/drivers/iio/pressure/rohm-bm1390.c b/drivers/iio/pressure/rohm-bm1390.c index 9c1197f0e742..dac27fd359ad 100644 --- a/drivers/iio/pressure/rohm-bm1390.c +++ b/drivers/iio/pressure/rohm-bm1390.c @@ -319,12 +319,11 @@ static int bm1390_read_raw(struct iio_dev *idev, return -EINVAL; case IIO_CHAN_INFO_RAW: - ret = iio_device_claim_direct_mode(idev); - if (ret) - return ret; + if (!iio_device_claim_direct(idev)) + return -EBUSY; ret = bm1390_read_data(data, chan, val, val2); - iio_device_release_direct_mode(idev); + iio_device_release_direct(idev); if (ret) return ret; @@ -653,7 +652,8 @@ static irqreturn_t bm1390_trigger_handler(int irq, void *p) } } - iio_push_to_buffers_with_timestamp(idev, &data->buf, data->timestamp); + iio_push_to_buffers_with_ts(idev, &data->buf, sizeof(data->buf), + data->timestamp); iio_trigger_notify_done(idev->trig); return IRQ_HANDLED; @@ -883,13 +883,13 @@ static int bm1390_probe(struct i2c_client *i2c) static const struct of_device_id bm1390_of_match[] = { { .compatible = "rohm,bm1390glv-z" }, - {} + { } }; MODULE_DEVICE_TABLE(of, bm1390_of_match); static const struct i2c_device_id bm1390_id[] = { { "bm1390glv-z", }, - {} + { } }; MODULE_DEVICE_TABLE(i2c, bm1390_id); diff --git a/drivers/iio/pressure/st_pressure_i2c.c b/drivers/iio/pressure/st_pressure_i2c.c index b7b66ddc3a73..0f50bac1fb4d 100644 --- a/drivers/iio/pressure/st_pressure_i2c.c +++ b/drivers/iio/pressure/st_pressure_i2c.c @@ -50,13 +50,13 @@ static const struct of_device_id st_press_of_match[] = { .compatible = "st,lps22df", .data = LPS22DF_PRESS_DEV_NAME, }, - {}, + { } }; MODULE_DEVICE_TABLE(of, st_press_of_match); static const struct acpi_device_id st_press_acpi_match[] = { {"SNO9210", LPS22HB}, - { }, + { } }; MODULE_DEVICE_TABLE(acpi, st_press_acpi_match); @@ -69,7 +69,7 @@ static const struct i2c_device_id st_press_id_table[] = { { LPS35HW_PRESS_DEV_NAME, LPS35HW }, { LPS22HH_PRESS_DEV_NAME, LPS22HH }, { LPS22DF_PRESS_DEV_NAME, LPS22DF }, - {}, + { } }; MODULE_DEVICE_TABLE(i2c, st_press_id_table); diff --git a/drivers/iio/pressure/st_pressure_spi.c b/drivers/iio/pressure/st_pressure_spi.c index 1a4bd1a0f787..39827e6841ca 100644 --- a/drivers/iio/pressure/st_pressure_spi.c +++ b/drivers/iio/pressure/st_pressure_spi.c @@ -55,7 +55,7 @@ static const struct of_device_id st_press_of_match[] = { .compatible = "st,lps22df", .data = LPS22DF_PRESS_DEV_NAME, }, - {}, + { } }; MODULE_DEVICE_TABLE(of, st_press_of_match); @@ -106,7 +106,7 @@ static const struct spi_device_id st_press_id_table[] = { { "lps25h-press", }, { "lps331ap-press" }, { "lps22hb-press" }, - {}, + { } }; MODULE_DEVICE_TABLE(spi, st_press_id_table); diff --git a/drivers/iio/pressure/zpa2326.c b/drivers/iio/pressure/zpa2326.c index 9db1c94dfc18..1640aa3717ed 100644 --- a/drivers/iio/pressure/zpa2326.c +++ b/drivers/iio/pressure/zpa2326.c @@ -582,7 +582,7 @@ static int zpa2326_fill_sample_buffer(struct iio_dev *indio_dev, struct { u32 pressure; u16 temperature; - u64 timestamp; + aligned_s64 timestamp; } sample; int err; @@ -618,8 +618,8 @@ static int zpa2326_fill_sample_buffer(struct iio_dev *indio_dev, */ zpa2326_dbg(indio_dev, "filling raw samples buffer"); - iio_push_to_buffers_with_timestamp(indio_dev, &sample, - private->timestamp); + iio_push_to_buffers_with_ts(indio_dev, &sample, sizeof(sample), + private->timestamp); return 0; } @@ -1062,9 +1062,8 @@ static int zpa2326_sample_oneshot(struct iio_dev *indio_dev, int ret; struct zpa2326_private *priv; - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; ret = zpa2326_resume(indio_dev); if (ret < 0) @@ -1120,7 +1119,7 @@ static int zpa2326_sample_oneshot(struct iio_dev *indio_dev, suspend: zpa2326_suspend(indio_dev); release: - iio_device_release_direct_mode(indio_dev); + iio_device_release_direct(indio_dev); return ret; } @@ -1438,7 +1437,6 @@ static int zpa2326_set_frequency(struct iio_dev *indio_dev, int hz) { struct zpa2326_private *priv = iio_priv(indio_dev); int freq; - int err; /* Check if requested frequency is supported. */ for (freq = 0; freq < ARRAY_SIZE(zpa2326_sampling_frequencies); freq++) @@ -1448,13 +1446,12 @@ static int zpa2326_set_frequency(struct iio_dev *indio_dev, int hz) return -EINVAL; /* Don't allow changing frequency if buffered sampling is ongoing. */ - err = iio_device_claim_direct_mode(indio_dev); - if (err) - return err; + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; priv->frequency = &zpa2326_sampling_frequencies[freq]; - iio_device_release_direct_mode(indio_dev); + iio_device_release_direct(indio_dev); return 0; } diff --git a/drivers/iio/pressure/zpa2326_spi.c b/drivers/iio/pressure/zpa2326_spi.c index c678f5b96266..af756e2b0f31 100644 --- a/drivers/iio/pressure/zpa2326_spi.c +++ b/drivers/iio/pressure/zpa2326_spi.c @@ -47,7 +47,6 @@ static int zpa2326_probe_spi(struct spi_device *spi) */ spi->mode = SPI_MODE_3; spi->max_speed_hz = min(spi->max_speed_hz, 1000000U); - spi->bits_per_word = 8; err = spi_setup(spi); if (err < 0) return err; @@ -63,7 +62,7 @@ static void zpa2326_remove_spi(struct spi_device *spi) static const struct spi_device_id zpa2326_spi_ids[] = { { "zpa2326", 0 }, - { }, + { } }; MODULE_DEVICE_TABLE(spi, zpa2326_spi_ids); diff --git a/drivers/iio/proximity/as3935.c b/drivers/iio/proximity/as3935.c index 9d3caf2bef18..f1018b14aecf 100644 --- a/drivers/iio/proximity/as3935.c +++ b/drivers/iio/proximity/as3935.c @@ -231,8 +231,8 @@ static irqreturn_t as3935_trigger_handler(int irq, void *private) goto err_read; st->scan.chan = val & AS3935_DATA_MASK; - iio_push_to_buffers_with_timestamp(indio_dev, &st->scan, - iio_get_time_ns(indio_dev)); + iio_push_to_buffers_with_ts(indio_dev, &st->scan, sizeof(st->scan), + iio_get_time_ns(indio_dev)); err_read: iio_trigger_notify_done(indio_dev->trig); @@ -444,13 +444,13 @@ static int as3935_probe(struct spi_device *spi) static const struct of_device_id as3935_of_match[] = { { .compatible = "ams,as3935", }, - { /* sentinel */ }, + { } }; MODULE_DEVICE_TABLE(of, as3935_of_match); static const struct spi_device_id as3935_id[] = { {"as3935", 0}, - {}, + { } }; MODULE_DEVICE_TABLE(spi, as3935_id); diff --git a/drivers/iio/proximity/cros_ec_mkbp_proximity.c b/drivers/iio/proximity/cros_ec_mkbp_proximity.c index 667369be0555..1f9de7066ebf 100644 --- a/drivers/iio/proximity/cros_ec_mkbp_proximity.c +++ b/drivers/iio/proximity/cros_ec_mkbp_proximity.c @@ -59,16 +59,11 @@ static int cros_ec_mkbp_proximity_parse_state(const void *data) static int cros_ec_mkbp_proximity_query(struct cros_ec_device *ec_dev, int *state) { - struct { - struct cros_ec_command msg; - union { - struct ec_params_mkbp_info params; - u32 switches; - }; - } __packed buf = { }; - struct ec_params_mkbp_info *params = &buf.params; - struct cros_ec_command *msg = &buf.msg; - u32 *switches = &buf.switches; + DEFINE_RAW_FLEX(struct cros_ec_command, buf, data, + MAX(sizeof(u32), sizeof(struct ec_params_mkbp_info))); + struct ec_params_mkbp_info *params = (struct ec_params_mkbp_info *)buf->data; + struct cros_ec_command *msg = buf; + u32 *switches = (u32 *)buf->data; size_t insize = sizeof(*switches); int ret; @@ -250,7 +245,7 @@ static void cros_ec_mkbp_proximity_remove(struct platform_device *pdev) static const struct of_device_id cros_ec_mkbp_proximity_of_match[] = { { .compatible = "google,cros-ec-mkbp-proximity" }, - {} + { } }; MODULE_DEVICE_TABLE(of, cros_ec_mkbp_proximity_of_match); diff --git a/drivers/iio/proximity/hx9023s.c b/drivers/iio/proximity/hx9023s.c index 5aa8e5a22f32..33781c314728 100644 --- a/drivers/iio/proximity/hx9023s.c +++ b/drivers/iio/proximity/hx9023s.c @@ -701,12 +701,11 @@ static int hx9023s_read_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_RAW: - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; ret = hx9023s_get_proximity(data, chan, val); - iio_device_release_direct_mode(indio_dev); + iio_device_release_direct(indio_dev); return ret; case IIO_CHAN_INFO_SAMP_FREQ: return hx9023s_get_samp_freq(data, val, val2); @@ -954,8 +953,8 @@ static irqreturn_t hx9023s_trigger_handler(int irq, void *private) data->buffer.channels[i++] = cpu_to_le16(data->ch_data[index].diff); } - iio_push_to_buffers_with_timestamp(indio_dev, &data->buffer, - pf->timestamp); + iio_push_to_buffers_with_ts(indio_dev, &data->buffer, + sizeof(data->buffer), pf->timestamp); out: iio_trigger_notify_done(indio_dev->trig); @@ -1191,13 +1190,13 @@ static DEFINE_SIMPLE_DEV_PM_OPS(hx9023s_pm_ops, hx9023s_suspend, static const struct of_device_id hx9023s_of_match[] = { { .compatible = "tyhx,hx9023s" }, - {} + { } }; MODULE_DEVICE_TABLE(of, hx9023s_of_match); static const struct i2c_device_id hx9023s_id[] = { { "hx9023s" }, - {} + { } }; MODULE_DEVICE_TABLE(i2c, hx9023s_id); diff --git a/drivers/iio/proximity/irsd200.c b/drivers/iio/proximity/irsd200.c index b0ffd3574013..0d30b91dbcbc 100644 --- a/drivers/iio/proximity/irsd200.c +++ b/drivers/iio/proximity/irsd200.c @@ -760,15 +760,19 @@ static irqreturn_t irsd200_trigger_handler(int irq, void *pollf) { struct iio_dev *indio_dev = ((struct iio_poll_func *)pollf)->indio_dev; struct irsd200_data *data = iio_priv(indio_dev); - s64 buf[2] = {}; + struct { + s16 channel; + aligned_s64 ts; + } scan; int ret; - ret = irsd200_read_data(data, (s16 *)buf); + memset(&scan, 0, sizeof(scan)); + ret = irsd200_read_data(data, &scan.channel); if (ret) goto end; - iio_push_to_buffers_with_timestamp(indio_dev, buf, - iio_get_time_ns(indio_dev)); + iio_push_to_buffers_with_ts(indio_dev, &scan, sizeof(scan), + iio_get_time_ns(indio_dev)); end: iio_trigger_notify_done(indio_dev->trig); @@ -941,7 +945,7 @@ static const struct of_device_id irsd200_of_match[] = { { .compatible = "murata,irsd200", }, - {} + { } }; MODULE_DEVICE_TABLE(of, irsd200_of_match); diff --git a/drivers/iio/proximity/isl29501.c b/drivers/iio/proximity/isl29501.c index dc66ca9bba6b..d1510fe24050 100644 --- a/drivers/iio/proximity/isl29501.c +++ b/drivers/iio/proximity/isl29501.c @@ -481,7 +481,7 @@ static const struct iio_chan_spec_ext_info isl29501_ext_info[] = { _ISL29501_EXT_INFO("calib_phase_temp_b", REG_CALIB_PHASE_TEMP_B), _ISL29501_EXT_INFO("calib_phase_light_a", REG_CALIB_PHASE_LIGHT_A), _ISL29501_EXT_INFO("calib_phase_light_b", REG_CALIB_PHASE_LIGHT_B), - { }, + { } }; #define ISL29501_DISTANCE_SCAN_INDEX 0 @@ -990,7 +990,7 @@ static int isl29501_probe(struct i2c_client *client) static const struct i2c_device_id isl29501_id[] = { { "isl29501" }, - {} + { } }; MODULE_DEVICE_TABLE(i2c, isl29501_id); diff --git a/drivers/iio/proximity/mb1232.c b/drivers/iio/proximity/mb1232.c index cfc75d001f20..01783486bc7d 100644 --- a/drivers/iio/proximity/mb1232.c +++ b/drivers/iio/proximity/mb1232.c @@ -125,8 +125,8 @@ static irqreturn_t mb1232_trigger_handler(int irq, void *p) if (data->scan.distance < 0) goto err; - iio_push_to_buffers_with_timestamp(indio_dev, &data->scan, - pf->timestamp); + iio_push_to_buffers_with_ts(indio_dev, &data->scan, sizeof(data->scan), + pf->timestamp); err: iio_trigger_notify_done(indio_dev->trig); @@ -239,7 +239,7 @@ static const struct of_device_id of_mb1232_match[] = { { .compatible = "maxbotix,mb1242", }, { .compatible = "maxbotix,mb7040", }, { .compatible = "maxbotix,mb7137", }, - {}, + { } }; MODULE_DEVICE_TABLE(of, of_mb1232_match); diff --git a/drivers/iio/proximity/ping.c b/drivers/iio/proximity/ping.c index 2ad69b150902..c5b4e1378b7d 100644 --- a/drivers/iio/proximity/ping.c +++ b/drivers/iio/proximity/ping.c @@ -268,7 +268,7 @@ static const struct iio_chan_spec ping_chan_spec[] = { static const struct of_device_id of_ping_match[] = { { .compatible = "parallax,ping", .data = &pa_ping_cfg }, { .compatible = "parallax,laserping", .data = &pa_laser_ping_cfg }, - {}, + { } }; MODULE_DEVICE_TABLE(of, of_ping_match); diff --git a/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c b/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c index f3d054b06b4c..1deaf70e92ce 100644 --- a/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c +++ b/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c @@ -208,7 +208,7 @@ static int lidar_read_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_RAW: { u16 reg; - if (iio_device_claim_direct_mode(indio_dev)) + if (!iio_device_claim_direct(indio_dev)) return -EBUSY; ret = lidar_get_measurement(data, ®); @@ -216,7 +216,7 @@ static int lidar_read_raw(struct iio_dev *indio_dev, *val = reg; ret = IIO_VAL_INT; } - iio_device_release_direct_mode(indio_dev); + iio_device_release_direct(indio_dev); break; } case IIO_CHAN_INFO_SCALE: @@ -238,8 +238,9 @@ static irqreturn_t lidar_trigger_handler(int irq, void *private) ret = lidar_get_measurement(data, &data->scan.chan); if (!ret) { - iio_push_to_buffers_with_timestamp(indio_dev, &data->scan, - iio_get_time_ns(indio_dev)); + iio_push_to_buffers_with_ts(indio_dev, &data->scan, + sizeof(data->scan), + iio_get_time_ns(indio_dev)); } else if (ret != -EINVAL) { dev_err(&data->client->dev, "cannot read LIDAR measurement"); } diff --git a/drivers/iio/proximity/srf04.c b/drivers/iio/proximity/srf04.c index 71ad29e441b2..b059bac1078b 100644 --- a/drivers/iio/proximity/srf04.c +++ b/drivers/iio/proximity/srf04.c @@ -240,7 +240,7 @@ static const struct of_device_id of_srf04_match[] = { { .compatible = "maxbotix,mb1020", .data = &mb_lv_cfg }, { .compatible = "maxbotix,mb1030", .data = &mb_lv_cfg }, { .compatible = "maxbotix,mb1040", .data = &mb_lv_cfg }, - {}, + { } }; MODULE_DEVICE_TABLE(of, of_srf04_match); diff --git a/drivers/iio/proximity/srf08.c b/drivers/iio/proximity/srf08.c index 86cab113ef3d..6e32fdfd161b 100644 --- a/drivers/iio/proximity/srf08.c +++ b/drivers/iio/proximity/srf08.c @@ -191,8 +191,8 @@ static irqreturn_t srf08_trigger_handler(int irq, void *p) mutex_lock(&data->lock); data->scan.chan = sensor_data; - iio_push_to_buffers_with_timestamp(indio_dev, - &data->scan, pf->timestamp); + iio_push_to_buffers_with_ts(indio_dev, &data->scan, sizeof(data->scan), + pf->timestamp); mutex_unlock(&data->lock); err: @@ -531,7 +531,7 @@ static const struct of_device_id of_srf08_match[] = { { .compatible = "devantech,srf02", (void *)SRF02 }, { .compatible = "devantech,srf08", (void *)SRF08 }, { .compatible = "devantech,srf10", (void *)SRF10 }, - {}, + { } }; MODULE_DEVICE_TABLE(of, of_srf08_match); diff --git a/drivers/iio/proximity/sx9310.c b/drivers/iio/proximity/sx9310.c index b60707eba39d..fb02eac78ed4 100644 --- a/drivers/iio/proximity/sx9310.c +++ b/drivers/iio/proximity/sx9310.c @@ -995,21 +995,21 @@ static const struct sx931x_info sx9311_info = { static const struct acpi_device_id sx9310_acpi_match[] = { { "STH9310", (kernel_ulong_t)&sx9310_info }, { "STH9311", (kernel_ulong_t)&sx9311_info }, - {} + { } }; MODULE_DEVICE_TABLE(acpi, sx9310_acpi_match); static const struct of_device_id sx9310_of_match[] = { { .compatible = "semtech,sx9310", &sx9310_info }, { .compatible = "semtech,sx9311", &sx9311_info }, - {} + { } }; MODULE_DEVICE_TABLE(of, sx9310_of_match); static const struct i2c_device_id sx9310_id[] = { { "sx9310", (kernel_ulong_t)&sx9310_info }, { "sx9311", (kernel_ulong_t)&sx9311_info }, - {} + { } }; MODULE_DEVICE_TABLE(i2c, sx9310_id); diff --git a/drivers/iio/proximity/sx9324.c b/drivers/iio/proximity/sx9324.c index 73d972416c01..c7b2d03c23bc 100644 --- a/drivers/iio/proximity/sx9324.c +++ b/drivers/iio/proximity/sx9324.c @@ -202,7 +202,7 @@ static const struct iio_chan_spec_ext_info sx9324_channel_ext_info[] = { .shared = IIO_SEPARATE, .read = sx9324_phase_configuration_show, }, - {} + { } }; #define SX9324_CHANNEL(idx) \ diff --git a/drivers/iio/proximity/sx9500.c b/drivers/iio/proximity/sx9500.c index c4e94d0fb163..8913da59dc73 100644 --- a/drivers/iio/proximity/sx9500.c +++ b/drivers/iio/proximity/sx9500.c @@ -387,11 +387,10 @@ static int sx9500_read_raw(struct iio_dev *indio_dev, case IIO_PROXIMITY: switch (mask) { case IIO_CHAN_INFO_RAW: - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; ret = sx9500_read_proximity(data, chan, val); - iio_device_release_direct_mode(indio_dev); + iio_device_release_direct(indio_dev); return ret; case IIO_CHAN_INFO_SAMP_FREQ: return sx9500_read_samp_freq(data, val, val2); @@ -866,7 +865,7 @@ static const struct acpi_gpio_mapping acpi_sx9500_gpios[] = { * GPIO to be output only. Ask the GPIO core to ignore this limit. */ { "interrupt-gpios", &interrupt_gpios, 1, ACPI_GPIO_QUIRK_NO_IO_RESTRICTION }, - { }, + { } }; static void sx9500_gpio_probe(struct i2c_client *client, @@ -1031,7 +1030,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(sx9500_pm_ops, sx9500_suspend, sx9500_resume); static const struct acpi_device_id sx9500_acpi_match[] = { {"SSX9500", 0}, {"SASX9500", 0}, - { }, + { } }; MODULE_DEVICE_TABLE(acpi, sx9500_acpi_match); diff --git a/drivers/iio/proximity/sx_common.c b/drivers/iio/proximity/sx_common.c index f70198a1f0d1..59b35e40739b 100644 --- a/drivers/iio/proximity/sx_common.c +++ b/drivers/iio/proximity/sx_common.c @@ -379,8 +379,8 @@ static irqreturn_t sx_common_trigger_handler(int irq, void *private) data->buffer.channels[i++] = val; } - iio_push_to_buffers_with_timestamp(indio_dev, &data->buffer, - pf->timestamp); + iio_push_to_buffers_with_ts(indio_dev, &data->buffer, + sizeof(data->buffer), pf->timestamp); out: mutex_unlock(&data->mutex); diff --git a/drivers/iio/proximity/vcnl3020.c b/drivers/iio/proximity/vcnl3020.c index bb6c9cc88b35..31e77d9e0c90 100644 --- a/drivers/iio/proximity/vcnl3020.c +++ b/drivers/iio/proximity/vcnl3020.c @@ -653,7 +653,7 @@ static const struct of_device_id vcnl3020_of_match[] = { { .compatible = "vishay,vcnl3020", }, - {} + { } }; MODULE_DEVICE_TABLE(of, vcnl3020_of_match); diff --git a/drivers/iio/proximity/vl53l0x-i2c.c b/drivers/iio/proximity/vl53l0x-i2c.c index 87d10faaff9b..ef4aa7b2835e 100644 --- a/drivers/iio/proximity/vl53l0x-i2c.c +++ b/drivers/iio/proximity/vl53l0x-i2c.c @@ -94,8 +94,8 @@ static irqreturn_t vl53l0x_trigger_handler(int irq, void *priv) return -EREMOTEIO; data->scan.chan = get_unaligned_be16(&buffer[10]); - iio_push_to_buffers_with_timestamp(indio_dev, &data->scan, - iio_get_time_ns(indio_dev)); + iio_push_to_buffers_with_ts(indio_dev, &data->scan, sizeof(data->scan), + iio_get_time_ns(indio_dev)); iio_trigger_notify_done(indio_dev->trig); vl53l0x_clear_irq(data); diff --git a/drivers/iio/resolver/ad2s1200.c b/drivers/iio/resolver/ad2s1200.c index 9d95241bdf8f..0bc84f12cb34 100644 --- a/drivers/iio/resolver/ad2s1200.c +++ b/drivers/iio/resolver/ad2s1200.c @@ -186,7 +186,7 @@ MODULE_DEVICE_TABLE(of, ad2s1200_of_match); static const struct spi_device_id ad2s1200_id[] = { { "ad2s1200" }, { "ad2s1205" }, - {} + { } }; MODULE_DEVICE_TABLE(spi, ad2s1200_id); diff --git a/drivers/iio/resolver/ad2s1210.c b/drivers/iio/resolver/ad2s1210.c index ab860cedecd1..9b028c8bb1db 100644 --- a/drivers/iio/resolver/ad2s1210.c +++ b/drivers/iio/resolver/ad2s1210.c @@ -1340,7 +1340,8 @@ static irqreturn_t ad2s1210_trigger_handler(int irq, void *p) } ad2s1210_push_events(indio_dev, st->sample.fault, pf->timestamp); - iio_push_to_buffers_with_timestamp(indio_dev, &st->scan, pf->timestamp); + iio_push_to_buffers_with_ts(indio_dev, &st->scan, sizeof(st->scan), + pf->timestamp); error_ret: iio_trigger_notify_done(indio_dev->trig); @@ -1597,7 +1598,7 @@ MODULE_DEVICE_TABLE(of, ad2s1210_of_match); static const struct spi_device_id ad2s1210_id[] = { { "ad2s1210" }, - {} + { } }; MODULE_DEVICE_TABLE(spi, ad2s1210_id); diff --git a/drivers/iio/resolver/ad2s90.c b/drivers/iio/resolver/ad2s90.c index be6836e55376..18f1c905eeac 100644 --- a/drivers/iio/resolver/ad2s90.c +++ b/drivers/iio/resolver/ad2s90.c @@ -105,13 +105,13 @@ static int ad2s90_probe(struct spi_device *spi) static const struct of_device_id ad2s90_of_match[] = { { .compatible = "adi,ad2s90", }, - {} + { } }; MODULE_DEVICE_TABLE(of, ad2s90_of_match); static const struct spi_device_id ad2s90_id[] = { { "ad2s90" }, - {} + { } }; MODULE_DEVICE_TABLE(spi, ad2s90_id); diff --git a/drivers/iio/temperature/hid-sensor-temperature.c b/drivers/iio/temperature/hid-sensor-temperature.c index 692520e1c497..9f628a8e5cfb 100644 --- a/drivers/iio/temperature/hid-sensor-temperature.c +++ b/drivers/iio/temperature/hid-sensor-temperature.c @@ -131,8 +131,9 @@ static int temperature_proc_event(struct hid_sensor_hub_device *hsdev, struct temperature_state *temp_st = iio_priv(indio_dev); if (atomic_read(&temp_st->common_attributes.data_ready)) - iio_push_to_buffers_with_timestamp(indio_dev, &temp_st->scan, - iio_get_time_ns(indio_dev)); + iio_push_to_buffers_with_ts(indio_dev, &temp_st->scan, + sizeof(temp_st->scan), + iio_get_time_ns(indio_dev)); return 0; } @@ -272,7 +273,7 @@ static const struct platform_device_id hid_temperature_ids[] = { /* Format: HID-SENSOR-usage_id_in_hex_lowercase */ .name = "HID-SENSOR-200033", }, - { /* sentinel */ } + { } }; MODULE_DEVICE_TABLE(platform, hid_temperature_ids); diff --git a/drivers/iio/temperature/ltc2983.c b/drivers/iio/temperature/ltc2983.c index f8ea2219ab48..7dd40d69cce6 100644 --- a/drivers/iio/temperature/ltc2983.c +++ b/drivers/iio/temperature/ltc2983.c @@ -1664,7 +1664,7 @@ static const struct spi_device_id ltc2983_id_table[] = { { "ltc2984", (kernel_ulong_t)<c2984_chip_info_data }, { "ltc2986", (kernel_ulong_t)<c2986_chip_info_data }, { "ltm2985", (kernel_ulong_t)<m2985_chip_info_data }, - {}, + { } }; MODULE_DEVICE_TABLE(spi, ltc2983_id_table); @@ -1673,7 +1673,7 @@ static const struct of_device_id ltc2983_of_match[] = { { .compatible = "adi,ltc2984", .data = <c2984_chip_info_data }, { .compatible = "adi,ltc2986", .data = <c2986_chip_info_data }, { .compatible = "adi,ltm2985", .data = <m2985_chip_info_data }, - {}, + { } }; MODULE_DEVICE_TABLE(of, ltc2983_of_match); diff --git a/drivers/iio/temperature/maxim_thermocouple.c b/drivers/iio/temperature/maxim_thermocouple.c index 555a61e2f3fd..cae8e84821d7 100644 --- a/drivers/iio/temperature/maxim_thermocouple.c +++ b/drivers/iio/temperature/maxim_thermocouple.c @@ -9,7 +9,6 @@ #include <linux/init.h> #include <linux/mod_devicetable.h> #include <linux/module.h> -#include <linux/mutex.h> #include <linux/err.h> #include <linux/spi/spi.h> #include <linux/iio/iio.h> @@ -169,8 +168,9 @@ static irqreturn_t maxim_thermocouple_trigger_handler(int irq, void *private) ret = spi_read(data->spi, data->buffer, data->chip->read_size); if (!ret) { - iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, - iio_get_time_ns(indio_dev)); + iio_push_to_buffers_with_ts(indio_dev, data->buffer, + sizeof(data->buffer), + iio_get_time_ns(indio_dev)); } iio_trigger_notify_done(indio_dev->trig); @@ -183,40 +183,35 @@ static int maxim_thermocouple_read_raw(struct iio_dev *indio_dev, int *val, int *val2, long mask) { struct maxim_thermocouple_data *data = iio_priv(indio_dev); - int ret = -EINVAL; + int ret; switch (mask) { case IIO_CHAN_INFO_RAW: - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; ret = maxim_thermocouple_read(data, chan, val); - iio_device_release_direct_mode(indio_dev); - - if (!ret) - return IIO_VAL_INT; + iio_device_release_direct(indio_dev); + if (ret) + return ret; - break; + return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: switch (chan->channel2) { case IIO_MOD_TEMP_AMBIENT: *val = 62; *val2 = 500000; /* 1000 * 0.0625 */ - ret = IIO_VAL_INT_PLUS_MICRO; - break; + return IIO_VAL_INT_PLUS_MICRO; default: *val = 250; /* 1000 * 0.25 */ - ret = IIO_VAL_INT; + return IIO_VAL_INT; } - break; case IIO_CHAN_INFO_THERMOCOUPLE_TYPE: *val = data->tc_type; - ret = IIO_VAL_CHAR; - break; + return IIO_VAL_CHAR; + default: + return -EINVAL; } - - return ret; } static const struct iio_info maxim_thermocouple_info = { @@ -271,7 +266,7 @@ static const struct spi_device_id maxim_thermocouple_id[] = { {"max31855t", MAX31855T}, {"max31855e", MAX31855E}, {"max31855r", MAX31855R}, - {}, + { } }; MODULE_DEVICE_TABLE(spi, maxim_thermocouple_id); diff --git a/drivers/iio/temperature/mcp9600.c b/drivers/iio/temperature/mcp9600.c index c2447860adfd..6e9108d5cf75 100644 --- a/drivers/iio/temperature/mcp9600.c +++ b/drivers/iio/temperature/mcp9600.c @@ -449,13 +449,13 @@ static int mcp9600_probe(struct i2c_client *client) static const struct i2c_device_id mcp9600_id[] = { { "mcp9600" }, - {} + { } }; MODULE_DEVICE_TABLE(i2c, mcp9600_id); static const struct of_device_id mcp9600_of_match[] = { { .compatible = "microchip,mcp9600" }, - {} + { } }; MODULE_DEVICE_TABLE(of, mcp9600_of_match); diff --git a/drivers/iio/temperature/tmp006.c b/drivers/iio/temperature/tmp006.c index b5c94b7492f5..29bff9d8859d 100644 --- a/drivers/iio/temperature/tmp006.c +++ b/drivers/iio/temperature/tmp006.c @@ -269,8 +269,8 @@ static irqreturn_t tmp006_trigger_handler(int irq, void *p) goto err; scan.channels[1] = ret; - iio_push_to_buffers_with_timestamp(indio_dev, &scan, - iio_get_time_ns(indio_dev)); + iio_push_to_buffers_with_ts(indio_dev, &scan, sizeof(scan), + iio_get_time_ns(indio_dev)); err: iio_trigger_notify_done(indio_dev->trig); return IRQ_HANDLED; diff --git a/drivers/iio/temperature/tmp007.c b/drivers/iio/temperature/tmp007.c index fd4d389ce1df..043283b02c4d 100644 --- a/drivers/iio/temperature/tmp007.c +++ b/drivers/iio/temperature/tmp007.c @@ -558,7 +558,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(tmp007_pm_ops, tmp007_suspend, tmp007_resume); static const struct of_device_id tmp007_of_match[] = { { .compatible = "ti,tmp007", }, - { }, + { } }; MODULE_DEVICE_TABLE(of, tmp007_of_match); diff --git a/drivers/iio/temperature/tsys01.c b/drivers/iio/temperature/tsys01.c index cfaa16f46a3f..334bba6fdae6 100644 --- a/drivers/iio/temperature/tsys01.c +++ b/drivers/iio/temperature/tsys01.c @@ -207,13 +207,13 @@ static int tsys01_i2c_probe(struct i2c_client *client) static const struct i2c_device_id tsys01_id[] = { { "tsys01" }, - {} + { } }; MODULE_DEVICE_TABLE(i2c, tsys01_id); static const struct of_device_id tsys01_of_match[] = { { .compatible = "meas,tsys01", }, - { }, + { } }; MODULE_DEVICE_TABLE(of, tsys01_of_match); diff --git a/drivers/iio/temperature/tsys02d.c b/drivers/iio/temperature/tsys02d.c index ef34b3c58f26..0cad27205667 100644 --- a/drivers/iio/temperature/tsys02d.c +++ b/drivers/iio/temperature/tsys02d.c @@ -169,7 +169,7 @@ static int tsys02d_probe(struct i2c_client *client) static const struct i2c_device_id tsys02d_id[] = { { "tsys02d" }, - {} + { } }; MODULE_DEVICE_TABLE(i2c, tsys02d_id); diff --git a/drivers/iio/test/iio-test-format.c b/drivers/iio/test/iio-test-format.c index fc67e6b73df7..872dd8582003 100644 --- a/drivers/iio/test/iio-test-format.c +++ b/drivers/iio/test/iio-test-format.c @@ -257,7 +257,7 @@ static struct kunit_case iio_format_test_cases[] = { KUNIT_CASE(iio_test_iio_format_value_fractional_log2), KUNIT_CASE(iio_test_iio_format_value_multiple), KUNIT_CASE(iio_test_iio_format_value_integer_64), - {} + { } }; static struct kunit_suite iio_format_test_suite = { diff --git a/drivers/iio/test/iio-test-gts.c b/drivers/iio/test/iio-test-gts.c index 1eceec9d477f..11250bc905c9 100644 --- a/drivers/iio/test/iio-test-gts.c +++ b/drivers/iio/test/iio-test-gts.c @@ -499,7 +499,7 @@ static struct kunit_case iio_gts_test_cases[] = { KUNIT_CASE(test_iio_find_closest_gain_low), KUNIT_CASE(test_iio_gts_total_gain_to_scale), KUNIT_CASE(test_iio_gts_avail_test), - {} + { } }; static struct kunit_suite iio_gts_test_suite = { diff --git a/drivers/iio/test/iio-test-rescale.c b/drivers/iio/test/iio-test-rescale.c index bbc6a2e1c2c1..ac6942cf1e44 100644 --- a/drivers/iio/test/iio-test-rescale.c +++ b/drivers/iio/test/iio-test-rescale.c @@ -704,7 +704,7 @@ static void iio_rescale_test_offset(struct kunit *test) static struct kunit_case iio_rescale_test_cases[] = { KUNIT_CASE_PARAM(iio_rescale_test_scale, iio_rescale_scale_gen_params), KUNIT_CASE_PARAM(iio_rescale_test_offset, iio_rescale_offset_gen_params), - {} + { } }; static struct kunit_suite iio_rescale_test_suite = { diff --git a/drivers/iio/trigger/stm32-lptimer-trigger.c b/drivers/iio/trigger/stm32-lptimer-trigger.c index f1e18913236a..2505ace440b4 100644 --- a/drivers/iio/trigger/stm32-lptimer-trigger.c +++ b/drivers/iio/trigger/stm32-lptimer-trigger.c @@ -16,16 +16,43 @@ #include <linux/platform_device.h> #include <linux/property.h> -/* List Low-Power Timer triggers */ -static const char * const stm32_lptim_triggers[] = { - LPTIM1_OUT, - LPTIM2_OUT, - LPTIM3_OUT, +/* Maximum triggers + one trailing null entry to indicate the end of array */ +#define MAX_TRIGGERS 3 + +struct stm32_lptim_cfg { + const char * const (*triggers)[MAX_TRIGGERS]; + unsigned int nb_triggers; +}; + +/* List Low-Power Timer triggers for H7, MP13, MP15 */ +static const char * const stm32_lptim_triggers[][MAX_TRIGGERS] = { + { LPTIM1_OUT,}, + { LPTIM2_OUT,}, + { LPTIM3_OUT,}, +}; + +/* List Low-Power Timer triggers for STM32MP25 */ +static const char * const stm32mp25_lptim_triggers[][MAX_TRIGGERS] = { + { LPTIM1_CH1, LPTIM1_CH2, }, + { LPTIM2_CH1, LPTIM2_CH2, }, + { LPTIM3_CH1,}, + { LPTIM4_CH1,}, + { LPTIM5_OUT,}, +}; + +static const struct stm32_lptim_cfg stm32mp15_lptim_cfg = { + .triggers = stm32_lptim_triggers, + .nb_triggers = ARRAY_SIZE(stm32_lptim_triggers), +}; + +static const struct stm32_lptim_cfg stm32mp25_lptim_cfg = { + .triggers = stm32mp25_lptim_triggers, + .nb_triggers = ARRAY_SIZE(stm32mp25_lptim_triggers), }; struct stm32_lptim_trigger { struct device *dev; - const char *trg; + const char * const *triggers; }; static int stm32_lptim_validate_device(struct iio_trigger *trig, @@ -56,22 +83,33 @@ EXPORT_SYMBOL(is_stm32_lptim_trigger); static int stm32_lptim_setup_trig(struct stm32_lptim_trigger *priv) { - struct iio_trigger *trig; + const char * const *cur = priv->triggers; + int ret; - trig = devm_iio_trigger_alloc(priv->dev, "%s", priv->trg); - if (!trig) - return -ENOMEM; + while (cur && *cur) { + struct iio_trigger *trig; - trig->dev.parent = priv->dev->parent; - trig->ops = &stm32_lptim_trigger_ops; - iio_trigger_set_drvdata(trig, priv); + trig = devm_iio_trigger_alloc(priv->dev, "%s", *cur); + if (!trig) + return -ENOMEM; - return devm_iio_trigger_register(priv->dev, trig); + trig->dev.parent = priv->dev->parent; + trig->ops = &stm32_lptim_trigger_ops; + iio_trigger_set_drvdata(trig, priv); + + ret = devm_iio_trigger_register(priv->dev, trig); + if (ret) + return ret; + cur++; + } + + return 0; } static int stm32_lptim_trigger_probe(struct platform_device *pdev) { struct stm32_lptim_trigger *priv; + struct stm32_lptim_cfg const *lptim_cfg; u32 index; priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); @@ -81,18 +119,21 @@ static int stm32_lptim_trigger_probe(struct platform_device *pdev) if (device_property_read_u32(&pdev->dev, "reg", &index)) return -EINVAL; - if (index >= ARRAY_SIZE(stm32_lptim_triggers)) + lptim_cfg = device_get_match_data(&pdev->dev); + + if (index >= lptim_cfg->nb_triggers) return -EINVAL; priv->dev = &pdev->dev; - priv->trg = stm32_lptim_triggers[index]; + priv->triggers = lptim_cfg->triggers[index]; return stm32_lptim_setup_trig(priv); } static const struct of_device_id stm32_lptim_trig_of_match[] = { - { .compatible = "st,stm32-lptimer-trigger", }, - {}, + { .compatible = "st,stm32-lptimer-trigger", .data = &stm32mp15_lptim_cfg }, + { .compatible = "st,stm32mp25-lptimer-trigger", .data = &stm32mp25_lptim_cfg}, + { } }; MODULE_DEVICE_TABLE(of, stm32_lptim_trig_of_match); diff --git a/drivers/iio/trigger/stm32-timer-trigger.c b/drivers/iio/trigger/stm32-timer-trigger.c index e41cb741253b..925b864facca 100644 --- a/drivers/iio/trigger/stm32-timer-trigger.c +++ b/drivers/iio/trigger/stm32-timer-trigger.c @@ -711,7 +711,7 @@ static const struct iio_chan_spec_ext_info stm32_trigger_count_info[] = { IIO_ENUM_AVAILABLE("enable_mode", IIO_SHARED_BY_TYPE, &stm32_enable_mode_enum), IIO_ENUM("trigger_mode", IIO_SEPARATE, &stm32_trigger_mode_enum), IIO_ENUM_AVAILABLE("trigger_mode", IIO_SHARED_BY_TYPE, &stm32_trigger_mode_enum), - {} + { } }; static const struct iio_chan_spec stm32_trigger_channel = { @@ -921,7 +921,7 @@ static const struct of_device_id stm32_trig_of_match[] = { .compatible = "st,stm32mp25-timer-trigger", .data = (void *)&stm32mp25_timer_trg_cfg, }, - { /* end node */ }, + { } }; MODULE_DEVICE_TABLE(of, stm32_trig_of_match); diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c index e02721a9e288..b3b45c49077d 100644 --- a/drivers/infiniband/hw/cxgb4/cm.c +++ b/drivers/infiniband/hw/cxgb4/cm.c @@ -4327,7 +4327,7 @@ static DECLARE_WORK(skb_work, process_work); static void ep_timeout(struct timer_list *t) { - struct c4iw_ep *ep = from_timer(ep, t, timer); + struct c4iw_ep *ep = timer_container_of(ep, t, timer); int kickit = 0; spin_lock(&timeout_lock); diff --git a/drivers/infiniband/hw/hfi1/aspm.c b/drivers/infiniband/hw/hfi1/aspm.c index 9b508eaf441d..79990d09522b 100644 --- a/drivers/infiniband/hw/hfi1/aspm.c +++ b/drivers/infiniband/hw/hfi1/aspm.c @@ -169,7 +169,7 @@ unlock: /* Timer function for re-enabling ASPM in the absence of interrupt activity */ static void aspm_ctx_timer_function(struct timer_list *t) { - struct hfi1_ctxtdata *rcd = from_timer(rcd, t, aspm_timer); + struct hfi1_ctxtdata *rcd = timer_container_of(rcd, t, aspm_timer); unsigned long flags; spin_lock_irqsave(&rcd->aspm_lock, flags); diff --git a/drivers/infiniband/hw/hfi1/chip.c b/drivers/infiniband/hw/hfi1/chip.c index e908f529335d..0781ab756d44 100644 --- a/drivers/infiniband/hw/hfi1/chip.c +++ b/drivers/infiniband/hw/hfi1/chip.c @@ -5548,7 +5548,7 @@ static void handle_cce_err(struct hfi1_devdata *dd, u32 unused, u64 reg) #define RCVERR_CHECK_TIME 10 static void update_rcverr_timer(struct timer_list *t) { - struct hfi1_devdata *dd = from_timer(dd, t, rcverr_timer); + struct hfi1_devdata *dd = timer_container_of(dd, t, rcverr_timer); struct hfi1_pportdata *ppd = dd->pport; u32 cur_ovfl_cnt = read_dev_cntr(dd, C_RCV_OVF, CNTR_INVALID_VL); @@ -12587,7 +12587,7 @@ static void do_update_synth_timer(struct work_struct *work) static void update_synth_timer(struct timer_list *t) { - struct hfi1_devdata *dd = from_timer(dd, t, synth_stats_timer); + struct hfi1_devdata *dd = timer_container_of(dd, t, synth_stats_timer); queue_work(dd->update_cntr_wq, &dd->update_cntr_work); mod_timer(&dd->synth_stats_timer, jiffies + HZ * SYNTH_CNT_TIME); diff --git a/drivers/infiniband/hw/hfi1/driver.c b/drivers/infiniband/hw/hfi1/driver.c index 3da90f2eb8e7..06487e20f723 100644 --- a/drivers/infiniband/hw/hfi1/driver.c +++ b/drivers/infiniband/hw/hfi1/driver.c @@ -1315,7 +1315,8 @@ void shutdown_led_override(struct hfi1_pportdata *ppd) static void run_led_override(struct timer_list *t) { - struct hfi1_pportdata *ppd = from_timer(ppd, t, led_override_timer); + struct hfi1_pportdata *ppd = timer_container_of(ppd, t, + led_override_timer); struct hfi1_devdata *dd = ppd->dd; unsigned long timeout; int phase_idx; diff --git a/drivers/infiniband/hw/hfi1/mad.c b/drivers/infiniband/hw/hfi1/mad.c index b39f63ce6dfc..961fa07116f0 100644 --- a/drivers/infiniband/hw/hfi1/mad.c +++ b/drivers/infiniband/hw/hfi1/mad.c @@ -369,7 +369,7 @@ static void send_trap(struct hfi1_ibport *ibp, struct trap_node *trap) void hfi1_handle_trap_timer(struct timer_list *t) { - struct hfi1_ibport *ibp = from_timer(ibp, t, rvp.trap_timer); + struct hfi1_ibport *ibp = timer_container_of(ibp, t, rvp.trap_timer); struct trap_node *trap = NULL; unsigned long flags; int i; diff --git a/drivers/infiniband/hw/hfi1/sdma.c b/drivers/infiniband/hw/hfi1/sdma.c index 16a749d16ee9..719b7c34e238 100644 --- a/drivers/infiniband/hw/hfi1/sdma.c +++ b/drivers/infiniband/hw/hfi1/sdma.c @@ -467,7 +467,8 @@ static void sdma_err_progress_check_schedule(struct sdma_engine *sde) static void sdma_err_progress_check(struct timer_list *t) { unsigned index; - struct sdma_engine *sde = from_timer(sde, t, err_progress_check_timer); + struct sdma_engine *sde = timer_container_of(sde, t, + err_progress_check_timer); dd_dev_err(sde->dd, "SDE progress check event\n"); for (index = 0; index < sde->dd->num_sdma; index++) { diff --git a/drivers/infiniband/hw/hfi1/tid_rdma.c b/drivers/infiniband/hw/hfi1/tid_rdma.c index 78bf4a48c035..eafd2f157e32 100644 --- a/drivers/infiniband/hw/hfi1/tid_rdma.c +++ b/drivers/infiniband/hw/hfi1/tid_rdma.c @@ -3981,7 +3981,7 @@ void hfi1_del_tid_reap_timer(struct rvt_qp *qp) static void hfi1_tid_timeout(struct timer_list *t) { - struct hfi1_qp_priv *qpriv = from_timer(qpriv, t, s_tid_timer); + struct hfi1_qp_priv *qpriv = timer_container_of(qpriv, t, s_tid_timer); struct rvt_qp *qp = qpriv->owner; struct rvt_dev_info *rdi = ib_to_rvt(qp->ibqp.device); unsigned long flags; @@ -4797,7 +4797,8 @@ void hfi1_del_tid_retry_timer(struct rvt_qp *qp) static void hfi1_tid_retry_timeout(struct timer_list *t) { - struct hfi1_qp_priv *priv = from_timer(priv, t, s_tid_retry_timer); + struct hfi1_qp_priv *priv = timer_container_of(priv, t, + s_tid_retry_timer); struct rvt_qp *qp = priv->owner; struct rvt_swqe *wqe; unsigned long flags; diff --git a/drivers/infiniband/hw/hfi1/verbs.c b/drivers/infiniband/hw/hfi1/verbs.c index 49e0f79b950c..3cbbfccdd8cd 100644 --- a/drivers/infiniband/hw/hfi1/verbs.c +++ b/drivers/infiniband/hw/hfi1/verbs.c @@ -554,7 +554,7 @@ void hfi1_16B_rcv(struct hfi1_packet *packet) */ static void mem_timer(struct timer_list *t) { - struct hfi1_ibdev *dev = from_timer(dev, t, mem_timer); + struct hfi1_ibdev *dev = timer_container_of(dev, t, mem_timer); struct list_head *list = &dev->memwait; struct rvt_qp *qp = NULL; struct iowait *wait; diff --git a/drivers/infiniband/hw/irdma/cm.c b/drivers/infiniband/hw/irdma/cm.c index 23207f13ac1b..c6a0a661d6e7 100644 --- a/drivers/infiniband/hw/irdma/cm.c +++ b/drivers/infiniband/hw/irdma/cm.c @@ -1263,7 +1263,8 @@ static void irdma_cm_timer_tick(struct timer_list *t) struct irdma_timer_entry *send_entry, *close_entry; struct list_head *list_core_temp; struct list_head *list_node; - struct irdma_cm_core *cm_core = from_timer(cm_core, t, tcp_timer); + struct irdma_cm_core *cm_core = timer_container_of(cm_core, t, + tcp_timer); struct irdma_sc_vsi *vsi; u32 settimer = 0; unsigned long timetosend; diff --git a/drivers/infiniband/hw/irdma/utils.c b/drivers/infiniband/hw/irdma/utils.c index d66b4f7a84ec..b510ef747399 100644 --- a/drivers/infiniband/hw/irdma/utils.c +++ b/drivers/infiniband/hw/irdma/utils.c @@ -930,7 +930,7 @@ void irdma_terminate_done(struct irdma_sc_qp *qp, int timeout_occurred) static void irdma_terminate_timeout(struct timer_list *t) { - struct irdma_qp *iwqp = from_timer(iwqp, t, terminate_timer); + struct irdma_qp *iwqp = timer_container_of(iwqp, t, terminate_timer); struct irdma_sc_qp *qp = &iwqp->sc_qp; irdma_terminate_done(qp, 1); @@ -1537,7 +1537,7 @@ int irdma_puda_get_tcpip_info(struct irdma_puda_cmpl_info *info, static void irdma_hw_stats_timeout(struct timer_list *t) { struct irdma_vsi_pestat *pf_devstat = - from_timer(pf_devstat, t, stats_timer); + timer_container_of(pf_devstat, t, stats_timer); struct irdma_sc_vsi *sc_vsi = pf_devstat->vsi; if (sc_vsi->dev->hw_attrs.uk_attrs.hw_rev >= IRDMA_GEN_2) diff --git a/drivers/infiniband/hw/mlx5/mr.c b/drivers/infiniband/hw/mlx5/mr.c index 6dd813bac5b2..57f9bc2a4a3a 100644 --- a/drivers/infiniband/hw/mlx5/mr.c +++ b/drivers/infiniband/hw/mlx5/mr.c @@ -838,7 +838,7 @@ static void mlx5_mkey_cache_debugfs_init(struct mlx5_ib_dev *dev) static void delay_time_func(struct timer_list *t) { - struct mlx5_ib_dev *dev = from_timer(dev, t, delay_timer); + struct mlx5_ib_dev *dev = timer_container_of(dev, t, delay_timer); WRITE_ONCE(dev->fill_delay, 0); } diff --git a/drivers/infiniband/hw/mthca/mthca_catas.c b/drivers/infiniband/hw/mthca/mthca_catas.c index 6eabef9aa211..f1d79968c985 100644 --- a/drivers/infiniband/hw/mthca/mthca_catas.c +++ b/drivers/infiniband/hw/mthca/mthca_catas.c @@ -132,7 +132,7 @@ static void handle_catas(struct mthca_dev *dev) static void poll_catas(struct timer_list *t) { - struct mthca_dev *dev = from_timer(dev, t, catas_err.timer); + struct mthca_dev *dev = timer_container_of(dev, t, catas_err.timer); int i; for (i = 0; i < dev->catas_err.size; ++i) diff --git a/drivers/infiniband/hw/qib/qib_driver.c b/drivers/infiniband/hw/qib/qib_driver.c index bdd724add147..91fa5e160c0d 100644 --- a/drivers/infiniband/hw/qib/qib_driver.c +++ b/drivers/infiniband/hw/qib/qib_driver.c @@ -659,8 +659,8 @@ int qib_set_lid(struct qib_pportdata *ppd, u32 lid, u8 lmc) static void qib_run_led_override(struct timer_list *t) { - struct qib_pportdata *ppd = from_timer(ppd, t, - led_override_timer); + struct qib_pportdata *ppd = timer_container_of(ppd, t, + led_override_timer); struct qib_devdata *dd = ppd->dd; int timeoff; int ph_idx; diff --git a/drivers/infiniband/hw/qib/qib_iba6120.c b/drivers/infiniband/hw/qib/qib_iba6120.c index 277769fa9745..2640d283eee6 100644 --- a/drivers/infiniband/hw/qib/qib_iba6120.c +++ b/drivers/infiniband/hw/qib/qib_iba6120.c @@ -2615,7 +2615,7 @@ static void qib_chk_6120_errormask(struct qib_devdata *dd) */ static void qib_get_6120_faststats(struct timer_list *t) { - struct qib_devdata *dd = from_timer(dd, t, stats_timer); + struct qib_devdata *dd = timer_container_of(dd, t, stats_timer); struct qib_pportdata *ppd = dd->pport; unsigned long flags; u64 traffic_wds; @@ -2905,7 +2905,7 @@ static int qib_6120_set_loopback(struct qib_pportdata *ppd, const char *what) static void pma_6120_timer(struct timer_list *t) { - struct qib_chip_specific *cs = from_timer(cs, t, pma_timer); + struct qib_chip_specific *cs = timer_container_of(cs, t, pma_timer); struct qib_pportdata *ppd = cs->ppd; struct qib_ibport *ibp = &ppd->ibport_data; unsigned long flags; diff --git a/drivers/infiniband/hw/qib/qib_iba7220.c b/drivers/infiniband/hw/qib/qib_iba7220.c index 302c0d19f57d..0b347d1129fa 100644 --- a/drivers/infiniband/hw/qib/qib_iba7220.c +++ b/drivers/infiniband/hw/qib/qib_iba7220.c @@ -1044,8 +1044,8 @@ done: static void reenable_7220_chase(struct timer_list *t) { - struct qib_chippport_specific *cpspec = from_timer(cpspec, t, - chase_timer); + struct qib_chippport_specific *cpspec = timer_container_of(cpspec, t, + chase_timer); struct qib_pportdata *ppd = &cpspec->pportdata; ppd->cpspec->chase_timer.expires = 0; @@ -3240,7 +3240,7 @@ done: */ static void qib_get_7220_faststats(struct timer_list *t) { - struct qib_devdata *dd = from_timer(dd, t, stats_timer); + struct qib_devdata *dd = timer_container_of(dd, t, stats_timer); struct qib_pportdata *ppd = dd->pport; unsigned long flags; u64 traffic_wds; diff --git a/drivers/infiniband/hw/qib/qib_iba7322.c b/drivers/infiniband/hw/qib/qib_iba7322.c index 7b4bf06c3b38..781b6a4fb002 100644 --- a/drivers/infiniband/hw/qib/qib_iba7322.c +++ b/drivers/infiniband/hw/qib/qib_iba7322.c @@ -1721,7 +1721,8 @@ static void qib_error_tasklet(struct tasklet_struct *t) static void reenable_chase(struct timer_list *t) { - struct qib_chippport_specific *cp = from_timer(cp, t, chase_timer); + struct qib_chippport_specific *cp = timer_container_of(cp, t, + chase_timer); struct qib_pportdata *ppd = cp->ppd; ppd->cpspec->chase_timer.expires = 0; @@ -5084,7 +5085,7 @@ done: */ static void qib_get_7322_faststats(struct timer_list *t) { - struct qib_devdata *dd = from_timer(dd, t, stats_timer); + struct qib_devdata *dd = timer_container_of(dd, t, stats_timer); struct qib_pportdata *ppd; unsigned long flags; u64 traffic_wds; diff --git a/drivers/infiniband/hw/qib/qib_init.c b/drivers/infiniband/hw/qib/qib_init.c index 33c23adec101..1c45814f5646 100644 --- a/drivers/infiniband/hw/qib/qib_init.c +++ b/drivers/infiniband/hw/qib/qib_init.c @@ -493,7 +493,7 @@ static void enable_chip(struct qib_devdata *dd) static void verify_interrupt(struct timer_list *t) { - struct qib_devdata *dd = from_timer(dd, t, intrchk_timer); + struct qib_devdata *dd = timer_container_of(dd, t, intrchk_timer); u64 int_counter; if (!dd) diff --git a/drivers/infiniband/hw/qib/qib_intr.c b/drivers/infiniband/hw/qib/qib_intr.c index 85c3187d796d..93357823c6c0 100644 --- a/drivers/infiniband/hw/qib/qib_intr.c +++ b/drivers/infiniband/hw/qib/qib_intr.c @@ -172,7 +172,8 @@ skip_ibchange: void qib_clear_symerror_on_linkup(struct timer_list *t) { - struct qib_pportdata *ppd = from_timer(ppd, t, symerr_clear_timer); + struct qib_pportdata *ppd = timer_container_of(ppd, t, + symerr_clear_timer); if (ppd->lflags & QIBL_LINKACTIVE) return; diff --git a/drivers/infiniband/hw/qib/qib_mad.c b/drivers/infiniband/hw/qib/qib_mad.c index 568deb77ab4d..d99932b2ce21 100644 --- a/drivers/infiniband/hw/qib/qib_mad.c +++ b/drivers/infiniband/hw/qib/qib_mad.c @@ -2398,7 +2398,8 @@ bail: static void xmit_wait_timer_func(struct timer_list *t) { - struct qib_pportdata *ppd = from_timer(ppd, t, cong_stats.timer); + struct qib_pportdata *ppd = timer_container_of(ppd, t, + cong_stats.timer); struct qib_devdata *dd = dd_from_ppd(ppd); unsigned long flags; u8 status; diff --git a/drivers/infiniband/hw/qib/qib_sd7220.c b/drivers/infiniband/hw/qib/qib_sd7220.c index c4ee120ac7fb..40bc0a34273e 100644 --- a/drivers/infiniband/hw/qib/qib_sd7220.c +++ b/drivers/infiniband/hw/qib/qib_sd7220.c @@ -1385,7 +1385,7 @@ MODULE_PARM_DESC(relock_by_timer, "Allow relock attempt if link not up"); static void qib_run_relock(struct timer_list *t) { - struct qib_chip_specific *cs = from_timer(cs, t, relock_timer); + struct qib_chip_specific *cs = timer_container_of(cs, t, relock_timer); struct qib_devdata *dd = cs->dd; struct qib_pportdata *ppd = dd->pport; int timeoff; diff --git a/drivers/infiniband/hw/qib/qib_tx.c b/drivers/infiniband/hw/qib/qib_tx.c index 1325110237cd..397928c80f7c 100644 --- a/drivers/infiniband/hw/qib/qib_tx.c +++ b/drivers/infiniband/hw/qib/qib_tx.c @@ -548,7 +548,7 @@ void qib_hol_up(struct qib_pportdata *ppd) */ void qib_hol_event(struct timer_list *t) { - struct qib_pportdata *ppd = from_timer(ppd, t, hol_timer); + struct qib_pportdata *ppd = timer_container_of(ppd, t, hol_timer); /* If hardware error, etc, skip. */ if (!(ppd->dd->flags & QIB_INITTED)) diff --git a/drivers/infiniband/hw/qib/qib_verbs.c b/drivers/infiniband/hw/qib/qib_verbs.c index 9832567a8bb8..bab657f93084 100644 --- a/drivers/infiniband/hw/qib/qib_verbs.c +++ b/drivers/infiniband/hw/qib/qib_verbs.c @@ -361,7 +361,7 @@ drop: */ static void mem_timer(struct timer_list *t) { - struct qib_ibdev *dev = from_timer(dev, t, mem_timer); + struct qib_ibdev *dev = timer_container_of(dev, t, mem_timer); struct list_head *list = &dev->memwait; struct rvt_qp *qp = NULL; struct qib_qp_priv *priv = NULL; diff --git a/drivers/infiniband/sw/rdmavt/qp.c b/drivers/infiniband/sw/rdmavt/qp.c index 583debe4b9a2..e825e2ef7966 100644 --- a/drivers/infiniband/sw/rdmavt/qp.c +++ b/drivers/infiniband/sw/rdmavt/qp.c @@ -2585,7 +2585,7 @@ EXPORT_SYMBOL(rvt_del_timers_sync); */ static void rvt_rc_timeout(struct timer_list *t) { - struct rvt_qp *qp = from_timer(qp, t, s_timer); + struct rvt_qp *qp = timer_container_of(qp, t, s_timer); struct rvt_dev_info *rdi = ib_to_rvt(qp->ibqp.device); unsigned long flags; diff --git a/drivers/infiniband/sw/rxe/rxe_comp.c b/drivers/infiniband/sw/rxe/rxe_comp.c index d48af2180745..a5b2b62f596b 100644 --- a/drivers/infiniband/sw/rxe/rxe_comp.c +++ b/drivers/infiniband/sw/rxe/rxe_comp.c @@ -114,7 +114,7 @@ static enum ib_wc_opcode wr_to_wc_opcode(enum ib_wr_opcode opcode) void retransmit_timer(struct timer_list *t) { - struct rxe_qp *qp = from_timer(qp, t, retrans_timer); + struct rxe_qp *qp = timer_container_of(qp, t, retrans_timer); unsigned long flags; rxe_dbg_qp(qp, "retransmit timer fired\n"); diff --git a/drivers/infiniband/sw/rxe/rxe_req.c b/drivers/infiniband/sw/rxe/rxe_req.c index 9d0392df8a92..373b03f223be 100644 --- a/drivers/infiniband/sw/rxe/rxe_req.c +++ b/drivers/infiniband/sw/rxe/rxe_req.c @@ -97,7 +97,7 @@ static void req_retry(struct rxe_qp *qp) void rnr_nak_timer(struct timer_list *t) { - struct rxe_qp *qp = from_timer(qp, t, rnr_nak_timer); + struct rxe_qp *qp = timer_container_of(qp, t, rnr_nak_timer); unsigned long flags; rxe_dbg_qp(qp, "nak timer fired\n"); diff --git a/drivers/input/ff-memless.c b/drivers/input/ff-memless.c index 009822fa61b8..91636479ee3c 100644 --- a/drivers/input/ff-memless.c +++ b/drivers/input/ff-memless.c @@ -399,7 +399,7 @@ static void ml_play_effects(struct ml_device *ml) static void ml_effect_timer(struct timer_list *t) { - struct ml_device *ml = from_timer(ml, t, timer); + struct ml_device *ml = timer_container_of(ml, t, timer); struct input_dev *dev = ml->dev; pr_debug("timer: updating effects\n"); diff --git a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c index ae51f108bfae..a832bc46bc92 100644 --- a/drivers/input/gameport/gameport.c +++ b/drivers/input/gameport/gameport.c @@ -199,7 +199,8 @@ EXPORT_SYMBOL(gameport_stop_polling); static void gameport_run_poll_handler(struct timer_list *t) { - struct gameport *gameport = from_timer(gameport, t, poll_timer); + struct gameport *gameport = timer_container_of(gameport, t, + poll_timer); gameport->poll_handler(gameport); if (gameport->poll_cnt) diff --git a/drivers/input/input.c b/drivers/input/input.c index ec4346f20efd..44887e51e049 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -2249,7 +2249,7 @@ static void devm_input_device_unregister(struct device *dev, void *res) */ static void input_repeat_key(struct timer_list *t) { - struct input_dev *dev = from_timer(dev, t, timer); + struct input_dev *dev = timer_container_of(dev, t, timer); guard(spinlock_irqsave)(&dev->event_lock); diff --git a/drivers/input/joystick/db9.c b/drivers/input/joystick/db9.c index d7a253835889..d5c67a927404 100644 --- a/drivers/input/joystick/db9.c +++ b/drivers/input/joystick/db9.c @@ -351,7 +351,7 @@ static int db9_saturn(int mode, struct parport *port, struct input_dev *devs[]) static void db9_timer(struct timer_list *t) { - struct db9 *db9 = from_timer(db9, t, timer); + struct db9 *db9 = timer_container_of(db9, t, timer); struct parport *port = db9->pd->port; struct input_dev *dev = db9->dev[0]; struct input_dev *dev2 = db9->dev[1]; diff --git a/drivers/input/joystick/gamecon.c b/drivers/input/joystick/gamecon.c index 9fc629ad58b8..ae95cb3d0ae9 100644 --- a/drivers/input/joystick/gamecon.c +++ b/drivers/input/joystick/gamecon.c @@ -726,7 +726,7 @@ static void gc_psx_process_packet(struct gc *gc) static void gc_timer(struct timer_list *t) { - struct gc *gc = from_timer(gc, t, timer); + struct gc *gc = timer_container_of(gc, t, timer); /* * N64 pads - must be read first, any read confuses them for 200 us diff --git a/drivers/input/joystick/turbografx.c b/drivers/input/joystick/turbografx.c index aa3e7d471b96..5f69aef01791 100644 --- a/drivers/input/joystick/turbografx.c +++ b/drivers/input/joystick/turbografx.c @@ -72,7 +72,7 @@ static struct tgfx { static void tgfx_timer(struct timer_list *t) { - struct tgfx *tgfx = from_timer(tgfx, t, timer); + struct tgfx *tgfx = timer_container_of(tgfx, t, timer); struct input_dev *dev; int data1, data2, i; diff --git a/drivers/input/keyboard/imx_keypad.c b/drivers/input/keyboard/imx_keypad.c index 3cd47fa44efc..069c1d6376e1 100644 --- a/drivers/input/keyboard/imx_keypad.c +++ b/drivers/input/keyboard/imx_keypad.c @@ -183,7 +183,8 @@ static void imx_keypad_fire_events(struct imx_keypad *keypad, */ static void imx_keypad_check_for_events(struct timer_list *t) { - struct imx_keypad *keypad = from_timer(keypad, t, check_matrix_timer); + struct imx_keypad *keypad = timer_container_of(keypad, t, + check_matrix_timer); unsigned short matrix_volatile_state[MAX_MATRIX_KEY_COLS]; unsigned short reg_val; bool state_changed, is_zero_matrix; diff --git a/drivers/input/keyboard/locomokbd.c b/drivers/input/keyboard/locomokbd.c index c501a93a4417..58d4f2096cf9 100644 --- a/drivers/input/keyboard/locomokbd.c +++ b/drivers/input/keyboard/locomokbd.c @@ -194,7 +194,7 @@ static irqreturn_t locomokbd_interrupt(int irq, void *dev_id) */ static void locomokbd_timer_callback(struct timer_list *t) { - struct locomokbd *locomokbd = from_timer(locomokbd, t, timer); + struct locomokbd *locomokbd = timer_container_of(locomokbd, t, timer); locomokbd_scankeyboard(locomokbd); } diff --git a/drivers/input/keyboard/snvs_pwrkey.c b/drivers/input/keyboard/snvs_pwrkey.c index fe7398eeb828..954055aaf6e2 100644 --- a/drivers/input/keyboard/snvs_pwrkey.c +++ b/drivers/input/keyboard/snvs_pwrkey.c @@ -46,7 +46,8 @@ struct pwrkey_drv_data { static void imx_imx_snvs_check_for_events(struct timer_list *t) { - struct pwrkey_drv_data *pdata = from_timer(pdata, t, check_timer); + struct pwrkey_drv_data *pdata = timer_container_of(pdata, t, + check_timer); struct input_dev *input = pdata->input; u32 state; diff --git a/drivers/input/keyboard/tegra-kbc.c b/drivers/input/keyboard/tegra-kbc.c index 32a676f0de53..bc1c80a456f2 100644 --- a/drivers/input/keyboard/tegra-kbc.c +++ b/drivers/input/keyboard/tegra-kbc.c @@ -240,7 +240,7 @@ static void tegra_kbc_set_fifo_interrupt(struct tegra_kbc *kbc, bool enable) static void tegra_kbc_keypress_timer(struct timer_list *t) { - struct tegra_kbc *kbc = from_timer(kbc, t, timer); + struct tegra_kbc *kbc = timer_container_of(kbc, t, timer); u32 val; unsigned int i; diff --git a/drivers/input/misc/nxp-bbnsm-pwrkey.c b/drivers/input/misc/nxp-bbnsm-pwrkey.c index 7ba8d166d68c..0c7b8f8ef4a5 100644 --- a/drivers/input/misc/nxp-bbnsm-pwrkey.c +++ b/drivers/input/misc/nxp-bbnsm-pwrkey.c @@ -45,7 +45,7 @@ struct bbnsm_pwrkey { static void bbnsm_pwrkey_check_for_events(struct timer_list *t) { - struct bbnsm_pwrkey *bbnsm = from_timer(bbnsm, t, check_timer); + struct bbnsm_pwrkey *bbnsm = timer_container_of(bbnsm, t, check_timer); struct input_dev *input = bbnsm->input; u32 state; diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index 0bd7b09b0aa3..be734d65ea72 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -1582,7 +1582,7 @@ static psmouse_ret_t alps_handle_interleaved_ps2(struct psmouse *psmouse) static void alps_flush_packet(struct timer_list *t) { - struct alps_data *priv = from_timer(priv, t, timer); + struct alps_data *priv = timer_container_of(priv, t, timer); struct psmouse *psmouse = priv->psmouse; guard(serio_pause_rx)(psmouse->ps2dev.serio); diff --git a/drivers/input/mouse/byd.c b/drivers/input/mouse/byd.c index 4ee084e00a7c..71aa23dd7d8d 100644 --- a/drivers/input/mouse/byd.c +++ b/drivers/input/mouse/byd.c @@ -251,7 +251,7 @@ static void byd_report_input(struct psmouse *psmouse) static void byd_clear_touch(struct timer_list *t) { - struct byd_data *priv = from_timer(priv, t, timer); + struct byd_data *priv = timer_container_of(priv, t, timer); struct psmouse *psmouse = priv->psmouse; guard(serio_pause_rx)(psmouse->ps2dev.serio); diff --git a/drivers/input/touchscreen/ad7877.c b/drivers/input/touchscreen/ad7877.c index 8d8392ce7005..c9aa1847265a 100644 --- a/drivers/input/touchscreen/ad7877.c +++ b/drivers/input/touchscreen/ad7877.c @@ -375,7 +375,7 @@ static inline void ad7877_ts_event_release(struct ad7877 *ts) static void ad7877_timer(struct timer_list *t) { - struct ad7877 *ts = from_timer(ts, t, timer); + struct ad7877 *ts = timer_container_of(ts, t, timer); unsigned long flags; spin_lock_irqsave(&ts->lock, flags); diff --git a/drivers/input/touchscreen/ad7879.c b/drivers/input/touchscreen/ad7879.c index f661e199b63c..f9db5cefb25b 100644 --- a/drivers/input/touchscreen/ad7879.c +++ b/drivers/input/touchscreen/ad7879.c @@ -237,7 +237,7 @@ static void ad7879_ts_event_release(struct ad7879 *ts) static void ad7879_timer(struct timer_list *t) { - struct ad7879 *ts = from_timer(ts, t, timer); + struct ad7879 *ts = timer_container_of(ts, t, timer); ad7879_ts_event_release(ts); } diff --git a/drivers/input/touchscreen/bu21029_ts.c b/drivers/input/touchscreen/bu21029_ts.c index 3c997fba7048..64f474e67312 100644 --- a/drivers/input/touchscreen/bu21029_ts.c +++ b/drivers/input/touchscreen/bu21029_ts.c @@ -209,7 +209,8 @@ static void bu21029_touch_report(struct bu21029_ts_data *bu21029, const u8 *buf) static void bu21029_touch_release(struct timer_list *t) { - struct bu21029_ts_data *bu21029 = from_timer(bu21029, t, timer); + struct bu21029_ts_data *bu21029 = timer_container_of(bu21029, t, + timer); input_report_abs(bu21029->in_dev, ABS_PRESSURE, 0); input_report_key(bu21029->in_dev, BTN_TOUCH, 0); diff --git a/drivers/input/touchscreen/exc3000.c b/drivers/input/touchscreen/exc3000.c index 9a5977d8cad2..28da7ba55a4b 100644 --- a/drivers/input/touchscreen/exc3000.c +++ b/drivers/input/touchscreen/exc3000.c @@ -105,7 +105,7 @@ static void exc3000_report_slots(struct input_dev *input, static void exc3000_timer(struct timer_list *t) { - struct exc3000_data *data = from_timer(data, t, timer); + struct exc3000_data *data = timer_container_of(data, t, timer); input_mt_sync_frame(data->input); input_sync(data->input); diff --git a/drivers/input/touchscreen/sx8654.c b/drivers/input/touchscreen/sx8654.c index e59b8d0ed19e..5fa47a1a6fdc 100644 --- a/drivers/input/touchscreen/sx8654.c +++ b/drivers/input/touchscreen/sx8654.c @@ -116,7 +116,7 @@ static inline void sx865x_penrelease(struct sx8654 *ts) static void sx865x_penrelease_timer_handler(struct timer_list *t) { - struct sx8654 *ts = from_timer(ts, t, timer); + struct sx8654 *ts = timer_container_of(ts, t, timer); unsigned long flags; spin_lock_irqsave(&ts->lock, flags); diff --git a/drivers/input/touchscreen/tsc200x-core.c b/drivers/input/touchscreen/tsc200x-core.c index 252a93753ee5..82d7d1cf5010 100644 --- a/drivers/input/touchscreen/tsc200x-core.c +++ b/drivers/input/touchscreen/tsc200x-core.c @@ -194,7 +194,7 @@ out: static void tsc200x_penup_timer(struct timer_list *t) { - struct tsc200x *ts = from_timer(ts, t, penup_timer); + struct tsc200x *ts = timer_container_of(ts, t, penup_timer); guard(spinlock_irqsave)(&ts->lock); tsc200x_update_pen_state(ts, 0, 0, 0); diff --git a/drivers/interconnect/core.c b/drivers/interconnect/core.c index 9d5404a07e8a..1a41e59c77f8 100644 --- a/drivers/interconnect/core.c +++ b/drivers/interconnect/core.c @@ -20,6 +20,8 @@ #include "internal.h" +#define ICC_DYN_ID_START 10000 + #define CREATE_TRACE_POINTS #include "trace.h" @@ -826,7 +828,12 @@ static struct icc_node *icc_node_create_nolock(int id) if (!node) return ERR_PTR(-ENOMEM); - id = idr_alloc(&icc_idr, node, id, id + 1, GFP_KERNEL); + /* dynamic id allocation */ + if (id == ICC_ALLOC_DYN_ID) + id = idr_alloc(&icc_idr, node, ICC_DYN_ID_START, 0, GFP_KERNEL); + else + id = idr_alloc(&icc_idr, node, id, id + 1, GFP_KERNEL); + if (id < 0) { WARN(1, "%s: couldn't get idr\n", __func__); kfree(node); @@ -839,6 +846,25 @@ static struct icc_node *icc_node_create_nolock(int id) } /** + * icc_node_create_dyn() - create a node with dynamic id + * + * Return: icc_node pointer on success, or ERR_PTR() on error + */ +struct icc_node *icc_node_create_dyn(void) +{ + struct icc_node *node; + + mutex_lock(&icc_lock); + + node = icc_node_create_nolock(ICC_ALLOC_DYN_ID); + + mutex_unlock(&icc_lock); + + return node; +} +EXPORT_SYMBOL_GPL(icc_node_create_dyn); + +/** * icc_node_create() - create a node * @id: node id * @@ -885,6 +911,56 @@ void icc_node_destroy(int id) EXPORT_SYMBOL_GPL(icc_node_destroy); /** + * icc_link_nodes() - create link between two nodes + * @src_node: source node + * @dst_node: destination node + * + * Create a link between two nodes. The nodes might belong to different + * interconnect providers and the @dst_node might not exist (if the + * provider driver has not probed yet). So just create the @dst_node + * and when the actual provider driver is probed, the rest of the node + * data is filled. + * + * Return: 0 on success, or an error code otherwise + */ +int icc_link_nodes(struct icc_node *src_node, struct icc_node **dst_node) +{ + struct icc_node **new; + int ret = 0; + + if (!src_node->provider) + return -EINVAL; + + mutex_lock(&icc_lock); + + if (!*dst_node) { + *dst_node = icc_node_create_nolock(ICC_ALLOC_DYN_ID); + + if (IS_ERR(*dst_node)) { + ret = PTR_ERR(*dst_node); + goto out; + } + } + + new = krealloc(src_node->links, + (src_node->num_links + 1) * sizeof(*src_node->links), + GFP_KERNEL); + if (!new) { + ret = -ENOMEM; + goto out; + } + + src_node->links = new; + src_node->links[src_node->num_links++] = *dst_node; + +out: + mutex_unlock(&icc_lock); + + return ret; +} +EXPORT_SYMBOL_GPL(icc_link_nodes); + +/** * icc_link_create() - create a link between two nodes * @node: source node id * @dst_id: destination node id @@ -962,6 +1038,10 @@ void icc_node_add(struct icc_node *node, struct icc_provider *provider) node->avg_bw = node->init_avg; node->peak_bw = node->init_peak; + if (node->id >= ICC_DYN_ID_START) + node->name = devm_kasprintf(provider->dev, GFP_KERNEL, "%s@%s", + node->name, dev_name(provider->dev)); + if (node->avg_bw || node->peak_bw) { if (provider->pre_aggregate) provider->pre_aggregate(node); diff --git a/drivers/interconnect/qcom/icc-rpmh.c b/drivers/interconnect/qcom/icc-rpmh.c index f2d63745be54..41bfc6e7ee1d 100644 --- a/drivers/interconnect/qcom/icc-rpmh.c +++ b/drivers/interconnect/qcom/icc-rpmh.c @@ -280,7 +280,14 @@ int qcom_icc_rpmh_probe(struct platform_device *pdev) if (!qn) continue; - node = icc_node_create(qn->id); + if (desc->alloc_dyn_id) { + if (!qn->node) + qn->node = icc_node_create_dyn(); + node = qn->node; + } else { + node = icc_node_create(qn->id); + } + if (IS_ERR(node)) { ret = PTR_ERR(node); goto err_remove_nodes; @@ -290,8 +297,12 @@ int qcom_icc_rpmh_probe(struct platform_device *pdev) node->data = qn; icc_node_add(node, provider); - for (j = 0; j < qn->num_links; j++) - icc_link_create(node, qn->links[j]); + for (j = 0; j < qn->num_links; j++) { + if (desc->alloc_dyn_id) + icc_link_nodes(node, &qn->link_nodes[j]->node); + else + icc_link_create(node, qn->links[j]); + } data->nodes[i] = node; } diff --git a/drivers/interconnect/qcom/icc-rpmh.h b/drivers/interconnect/qcom/icc-rpmh.h index 82344c734091..bd8d730249b1 100644 --- a/drivers/interconnect/qcom/icc-rpmh.h +++ b/drivers/interconnect/qcom/icc-rpmh.h @@ -83,6 +83,8 @@ struct qcom_icc_qosbox { * @name: the node name used in debugfs * @links: an array of nodes where we can go next while traversing * @id: a unique node identifier + * @link_nodes: links associated with this node + * @node: icc_node associated with this node * @num_links: the total number of @links * @channels: num of channels at this node * @buswidth: width of the interconnect between a node and the bus @@ -96,6 +98,8 @@ struct qcom_icc_node { const char *name; u16 links[MAX_LINKS]; u16 id; + struct qcom_icc_node **link_nodes; + struct icc_node *node; u16 num_links; u16 channels; u16 buswidth; @@ -154,6 +158,7 @@ struct qcom_icc_desc { struct qcom_icc_bcm * const *bcms; size_t num_bcms; bool qos_requires_clocks; + bool alloc_dyn_id; }; int qcom_icc_aggregate(struct icc_node *node, u32 tag, u32 avg_bw, diff --git a/drivers/interconnect/qcom/osm-l3.c b/drivers/interconnect/qcom/osm-l3.c index 6a656ed44d49..baecbf2533f7 100644 --- a/drivers/interconnect/qcom/osm-l3.c +++ b/drivers/interconnect/qcom/osm-l3.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved. */ #include <linux/args.h> @@ -32,8 +33,6 @@ #define EPSS_REG_FREQ_LUT 0x100 #define EPSS_REG_PERF_STATE 0x320 -#define OSM_L3_MAX_LINKS 1 - #define to_osm_l3_provider(_provider) \ container_of(_provider, struct qcom_osm_l3_icc_provider, provider) @@ -48,16 +47,10 @@ struct qcom_osm_l3_icc_provider { /** * struct qcom_osm_l3_node - Qualcomm specific interconnect nodes * @name: the node name used in debugfs - * @links: an array of nodes where we can go next while traversing - * @id: a unique node identifier - * @num_links: the total number of @links * @buswidth: width of the interconnect between a node and the bus */ struct qcom_osm_l3_node { const char *name; - u16 links[OSM_L3_MAX_LINKS]; - u16 id; - u16 num_links; u16 buswidth; }; @@ -69,30 +62,22 @@ struct qcom_osm_l3_desc { unsigned int reg_perf_state; }; -enum { - OSM_L3_MASTER_NODE = 10000, - OSM_L3_SLAVE_NODE, -}; - -#define DEFINE_QNODE(_name, _id, _buswidth, ...) \ +#define DEFINE_QNODE(_name, _buswidth) \ static const struct qcom_osm_l3_node _name = { \ .name = #_name, \ - .id = _id, \ .buswidth = _buswidth, \ - .num_links = COUNT_ARGS(__VA_ARGS__), \ - .links = { __VA_ARGS__ }, \ } -DEFINE_QNODE(osm_l3_master, OSM_L3_MASTER_NODE, 16, OSM_L3_SLAVE_NODE); -DEFINE_QNODE(osm_l3_slave, OSM_L3_SLAVE_NODE, 16); +DEFINE_QNODE(osm_l3_slave, 16); +DEFINE_QNODE(osm_l3_master, 16); static const struct qcom_osm_l3_node * const osm_l3_nodes[] = { [MASTER_OSM_L3_APPS] = &osm_l3_master, [SLAVE_OSM_L3] = &osm_l3_slave, }; -DEFINE_QNODE(epss_l3_master, OSM_L3_MASTER_NODE, 32, OSM_L3_SLAVE_NODE); -DEFINE_QNODE(epss_l3_slave, OSM_L3_SLAVE_NODE, 32); +DEFINE_QNODE(epss_l3_slave, 32); +DEFINE_QNODE(epss_l3_master, 32); static const struct qcom_osm_l3_node * const epss_l3_nodes[] = { [MASTER_EPSS_L3_APPS] = &epss_l3_master, @@ -242,10 +227,10 @@ static int qcom_osm_l3_probe(struct platform_device *pdev) icc_provider_init(provider); + /* Create nodes */ for (i = 0; i < num_nodes; i++) { - size_t j; + node = icc_node_create_dyn(); - node = icc_node_create(qnodes[i]->id); if (IS_ERR(node)) { ret = PTR_ERR(node); goto err; @@ -256,12 +241,12 @@ static int qcom_osm_l3_probe(struct platform_device *pdev) node->data = (void *)qnodes[i]; icc_node_add(node, provider); - for (j = 0; j < qnodes[i]->num_links; j++) - icc_link_create(node, qnodes[i]->links[j]); - data->nodes[i] = node; } + /* Create link */ + icc_link_nodes(data->nodes[MASTER_OSM_L3_APPS], &data->nodes[SLAVE_OSM_L3]); + ret = icc_provider_register(provider); if (ret) goto err; @@ -278,6 +263,7 @@ err: static const struct of_device_id osm_l3_of_match[] = { { .compatible = "qcom,epss-l3", .data = &epss_l3_l3_vote }, { .compatible = "qcom,osm-l3", .data = &osm_l3 }, + { .compatible = "qcom,sa8775p-epss-l3", .data = &epss_l3_perf_state }, { .compatible = "qcom,sc7180-osm-l3", .data = &osm_l3 }, { .compatible = "qcom,sc7280-epss-l3", .data = &epss_l3_perf_state }, { .compatible = "qcom,sdm845-osm-l3", .data = &osm_l3 }, diff --git a/drivers/interconnect/qcom/sa8775p.c b/drivers/interconnect/qcom/sa8775p.c index e2826af3ea2e..04b4abbf4487 100644 --- a/drivers/interconnect/qcom/sa8775p.c +++ b/drivers/interconnect/qcom/sa8775p.c @@ -15,1859 +15,1587 @@ #include "bcm-voter.h" #include "icc-rpmh.h" -#define SA8775P_MASTER_GPU_TCU 0 -#define SA8775P_MASTER_PCIE_TCU 1 -#define SA8775P_MASTER_SYS_TCU 2 -#define SA8775P_MASTER_APPSS_PROC 3 -#define SA8775P_MASTER_LLCC 4 -#define SA8775P_MASTER_CNOC_LPASS_AG_NOC 5 -#define SA8775P_MASTER_GIC_AHB 6 -#define SA8775P_MASTER_CDSP_NOC_CFG 7 -#define SA8775P_MASTER_CDSPB_NOC_CFG 8 -#define SA8775P_MASTER_QDSS_BAM 9 -#define SA8775P_MASTER_QUP_0 10 -#define SA8775P_MASTER_QUP_1 11 -#define SA8775P_MASTER_QUP_2 12 -#define SA8775P_MASTER_A1NOC_SNOC 13 -#define SA8775P_MASTER_A2NOC_SNOC 14 -#define SA8775P_MASTER_CAMNOC_HF 15 -#define SA8775P_MASTER_CAMNOC_ICP 16 -#define SA8775P_MASTER_CAMNOC_SF 17 -#define SA8775P_MASTER_COMPUTE_NOC 18 -#define SA8775P_MASTER_COMPUTE_NOC_1 19 -#define SA8775P_MASTER_CNOC_A2NOC 20 -#define SA8775P_MASTER_CNOC_DC_NOC 21 -#define SA8775P_MASTER_GEM_NOC_CFG 22 -#define SA8775P_MASTER_GEM_NOC_CNOC 23 -#define SA8775P_MASTER_GEM_NOC_PCIE_SNOC 24 -#define SA8775P_MASTER_GPDSP_SAIL 25 -#define SA8775P_MASTER_GFX3D 26 -#define SA8775P_MASTER_LPASS_ANOC 27 -#define SA8775P_MASTER_MDP0 28 -#define SA8775P_MASTER_MDP1 29 -#define SA8775P_MASTER_MDP_CORE1_0 30 -#define SA8775P_MASTER_MDP_CORE1_1 31 -#define SA8775P_MASTER_MNOC_HF_MEM_NOC 32 -#define SA8775P_MASTER_CNOC_MNOC_HF_CFG 33 -#define SA8775P_MASTER_MNOC_SF_MEM_NOC 34 -#define SA8775P_MASTER_CNOC_MNOC_SF_CFG 35 -#define SA8775P_MASTER_ANOC_PCIE_GEM_NOC 36 -#define SA8775P_MASTER_SNOC_CFG 37 -#define SA8775P_MASTER_SNOC_GC_MEM_NOC 38 -#define SA8775P_MASTER_SNOC_SF_MEM_NOC 39 -#define SA8775P_MASTER_VIDEO_P0 40 -#define SA8775P_MASTER_VIDEO_P1 41 -#define SA8775P_MASTER_VIDEO_PROC 42 -#define SA8775P_MASTER_VIDEO_V_PROC 43 -#define SA8775P_MASTER_QUP_CORE_0 44 -#define SA8775P_MASTER_QUP_CORE_1 45 -#define SA8775P_MASTER_QUP_CORE_2 46 -#define SA8775P_MASTER_QUP_CORE_3 47 -#define SA8775P_MASTER_CRYPTO_CORE0 48 -#define SA8775P_MASTER_CRYPTO_CORE1 49 -#define SA8775P_MASTER_DSP0 50 -#define SA8775P_MASTER_DSP1 51 -#define SA8775P_MASTER_IPA 52 -#define SA8775P_MASTER_LPASS_PROC 53 -#define SA8775P_MASTER_CDSP_PROC 54 -#define SA8775P_MASTER_CDSP_PROC_B 55 -#define SA8775P_MASTER_PIMEM 56 -#define SA8775P_MASTER_QUP_3 57 -#define SA8775P_MASTER_EMAC 58 -#define SA8775P_MASTER_EMAC_1 59 -#define SA8775P_MASTER_GIC 60 -#define SA8775P_MASTER_PCIE_0 61 -#define SA8775P_MASTER_PCIE_1 62 -#define SA8775P_MASTER_QDSS_ETR_0 63 -#define SA8775P_MASTER_QDSS_ETR_1 64 -#define SA8775P_MASTER_SDC 65 -#define SA8775P_MASTER_UFS_CARD 66 -#define SA8775P_MASTER_UFS_MEM 67 -#define SA8775P_MASTER_USB2 68 -#define SA8775P_MASTER_USB3_0 69 -#define SA8775P_MASTER_USB3_1 70 -#define SA8775P_SLAVE_EBI1 512 -#define SA8775P_SLAVE_AHB2PHY_0 513 -#define SA8775P_SLAVE_AHB2PHY_1 514 -#define SA8775P_SLAVE_AHB2PHY_2 515 -#define SA8775P_SLAVE_AHB2PHY_3 516 -#define SA8775P_SLAVE_ANOC_THROTTLE_CFG 517 -#define SA8775P_SLAVE_AOSS 518 -#define SA8775P_SLAVE_APPSS 519 -#define SA8775P_SLAVE_BOOT_ROM 520 -#define SA8775P_SLAVE_CAMERA_CFG 521 -#define SA8775P_SLAVE_CAMERA_NRT_THROTTLE_CFG 522 -#define SA8775P_SLAVE_CAMERA_RT_THROTTLE_CFG 523 -#define SA8775P_SLAVE_CLK_CTL 524 -#define SA8775P_SLAVE_CDSP_CFG 525 -#define SA8775P_SLAVE_CDSP1_CFG 526 -#define SA8775P_SLAVE_RBCPR_CX_CFG 527 -#define SA8775P_SLAVE_RBCPR_MMCX_CFG 528 -#define SA8775P_SLAVE_RBCPR_MX_CFG 529 -#define SA8775P_SLAVE_CPR_NSPCX 530 -#define SA8775P_SLAVE_CRYPTO_0_CFG 531 -#define SA8775P_SLAVE_CX_RDPM 532 -#define SA8775P_SLAVE_DISPLAY_CFG 533 -#define SA8775P_SLAVE_DISPLAY_RT_THROTTLE_CFG 534 -#define SA8775P_SLAVE_DISPLAY1_CFG 535 -#define SA8775P_SLAVE_DISPLAY1_RT_THROTTLE_CFG 536 -#define SA8775P_SLAVE_EMAC_CFG 537 -#define SA8775P_SLAVE_EMAC1_CFG 538 -#define SA8775P_SLAVE_GP_DSP0_CFG 539 -#define SA8775P_SLAVE_GP_DSP1_CFG 540 -#define SA8775P_SLAVE_GPDSP0_THROTTLE_CFG 541 -#define SA8775P_SLAVE_GPDSP1_THROTTLE_CFG 542 -#define SA8775P_SLAVE_GPU_TCU_THROTTLE_CFG 543 -#define SA8775P_SLAVE_GFX3D_CFG 544 -#define SA8775P_SLAVE_HWKM 545 -#define SA8775P_SLAVE_IMEM_CFG 546 -#define SA8775P_SLAVE_IPA_CFG 547 -#define SA8775P_SLAVE_IPC_ROUTER_CFG 548 -#define SA8775P_SLAVE_LLCC_CFG 549 -#define SA8775P_SLAVE_LPASS 550 -#define SA8775P_SLAVE_LPASS_CORE_CFG 551 -#define SA8775P_SLAVE_LPASS_LPI_CFG 552 -#define SA8775P_SLAVE_LPASS_MPU_CFG 553 -#define SA8775P_SLAVE_LPASS_THROTTLE_CFG 554 -#define SA8775P_SLAVE_LPASS_TOP_CFG 555 -#define SA8775P_SLAVE_MX_RDPM 556 -#define SA8775P_SLAVE_MXC_RDPM 557 -#define SA8775P_SLAVE_PCIE_0_CFG 558 -#define SA8775P_SLAVE_PCIE_1_CFG 559 -#define SA8775P_SLAVE_PCIE_RSC_CFG 560 -#define SA8775P_SLAVE_PCIE_TCU_THROTTLE_CFG 561 -#define SA8775P_SLAVE_PCIE_THROTTLE_CFG 562 -#define SA8775P_SLAVE_PDM 563 -#define SA8775P_SLAVE_PIMEM_CFG 564 -#define SA8775P_SLAVE_PKA_WRAPPER_CFG 565 -#define SA8775P_SLAVE_QDSS_CFG 566 -#define SA8775P_SLAVE_QM_CFG 567 -#define SA8775P_SLAVE_QM_MPU_CFG 568 -#define SA8775P_SLAVE_QUP_0 569 -#define SA8775P_SLAVE_QUP_1 570 -#define SA8775P_SLAVE_QUP_2 571 -#define SA8775P_SLAVE_QUP_3 572 -#define SA8775P_SLAVE_SAIL_THROTTLE_CFG 573 -#define SA8775P_SLAVE_SDC1 574 -#define SA8775P_SLAVE_SECURITY 575 -#define SA8775P_SLAVE_SNOC_THROTTLE_CFG 576 -#define SA8775P_SLAVE_TCSR 577 -#define SA8775P_SLAVE_TLMM 578 -#define SA8775P_SLAVE_TSC_CFG 579 -#define SA8775P_SLAVE_UFS_CARD_CFG 580 -#define SA8775P_SLAVE_UFS_MEM_CFG 581 -#define SA8775P_SLAVE_USB2 582 -#define SA8775P_SLAVE_USB3_0 583 -#define SA8775P_SLAVE_USB3_1 584 -#define SA8775P_SLAVE_VENUS_CFG 585 -#define SA8775P_SLAVE_VENUS_CVP_THROTTLE_CFG 586 -#define SA8775P_SLAVE_VENUS_V_CPU_THROTTLE_CFG 587 -#define SA8775P_SLAVE_VENUS_VCODEC_THROTTLE_CFG 588 -#define SA8775P_SLAVE_A1NOC_SNOC 589 -#define SA8775P_SLAVE_A2NOC_SNOC 590 -#define SA8775P_SLAVE_DDRSS_CFG 591 -#define SA8775P_SLAVE_GEM_NOC_CNOC 592 -#define SA8775P_SLAVE_GEM_NOC_CFG 593 -#define SA8775P_SLAVE_SNOC_GEM_NOC_GC 594 -#define SA8775P_SLAVE_SNOC_GEM_NOC_SF 595 -#define SA8775P_SLAVE_GP_DSP_SAIL_NOC 596 -#define SA8775P_SLAVE_GPDSP_NOC_CFG 597 -#define SA8775P_SLAVE_HCP_A 598 -#define SA8775P_SLAVE_LLCC 599 -#define SA8775P_SLAVE_MNOC_HF_MEM_NOC 600 -#define SA8775P_SLAVE_MNOC_SF_MEM_NOC 601 -#define SA8775P_SLAVE_CNOC_MNOC_HF_CFG 602 -#define SA8775P_SLAVE_CNOC_MNOC_SF_CFG 603 -#define SA8775P_SLAVE_CDSP_MEM_NOC 604 -#define SA8775P_SLAVE_CDSPB_MEM_NOC 605 -#define SA8775P_SLAVE_HCP_B 606 -#define SA8775P_SLAVE_GEM_NOC_PCIE_CNOC 607 -#define SA8775P_SLAVE_PCIE_ANOC_CFG 608 -#define SA8775P_SLAVE_ANOC_PCIE_GEM_NOC 609 -#define SA8775P_SLAVE_SNOC_CFG 610 -#define SA8775P_SLAVE_LPASS_SNOC 611 -#define SA8775P_SLAVE_QUP_CORE_0 612 -#define SA8775P_SLAVE_QUP_CORE_1 613 -#define SA8775P_SLAVE_QUP_CORE_2 614 -#define SA8775P_SLAVE_QUP_CORE_3 615 -#define SA8775P_SLAVE_BOOT_IMEM 616 -#define SA8775P_SLAVE_IMEM 617 -#define SA8775P_SLAVE_PIMEM 618 -#define SA8775P_SLAVE_SERVICE_NSP_NOC 619 -#define SA8775P_SLAVE_SERVICE_NSPB_NOC 620 -#define SA8775P_SLAVE_SERVICE_GEM_NOC_1 621 -#define SA8775P_SLAVE_SERVICE_MNOC_HF 622 -#define SA8775P_SLAVE_SERVICE_MNOC_SF 623 -#define SA8775P_SLAVE_SERVICES_LPASS_AML_NOC 624 -#define SA8775P_SLAVE_SERVICE_LPASS_AG_NOC 625 -#define SA8775P_SLAVE_SERVICE_GEM_NOC_2 626 -#define SA8775P_SLAVE_SERVICE_SNOC 627 -#define SA8775P_SLAVE_SERVICE_GEM_NOC 628 -#define SA8775P_SLAVE_SERVICE_GEM_NOC2 629 -#define SA8775P_SLAVE_PCIE_0 630 -#define SA8775P_SLAVE_PCIE_1 631 -#define SA8775P_SLAVE_QDSS_STM 632 -#define SA8775P_SLAVE_TCU 633 +static struct qcom_icc_node qxm_qup3; +static struct qcom_icc_node xm_emac_0; +static struct qcom_icc_node xm_emac_1; +static struct qcom_icc_node xm_sdc1; +static struct qcom_icc_node xm_ufs_mem; +static struct qcom_icc_node xm_usb2_2; +static struct qcom_icc_node xm_usb3_0; +static struct qcom_icc_node xm_usb3_1; +static struct qcom_icc_node qns_a1noc_snoc; +static struct qcom_icc_node qhm_qdss_bam; +static struct qcom_icc_node qhm_qup0; +static struct qcom_icc_node qhm_qup1; +static struct qcom_icc_node qhm_qup2; +static struct qcom_icc_node qnm_cnoc_datapath; +static struct qcom_icc_node qxm_crypto_0; +static struct qcom_icc_node qxm_crypto_1; +static struct qcom_icc_node qxm_ipa; +static struct qcom_icc_node xm_qdss_etr_0; +static struct qcom_icc_node xm_qdss_etr_1; +static struct qcom_icc_node xm_ufs_card; +static struct qcom_icc_node qns_a2noc_snoc; +static struct qcom_icc_node qup0_core_master; +static struct qcom_icc_node qup1_core_master; +static struct qcom_icc_node qup2_core_master; +static struct qcom_icc_node qup3_core_master; +static struct qcom_icc_node qup0_core_slave; +static struct qcom_icc_node qup1_core_slave; +static struct qcom_icc_node qup2_core_slave; +static struct qcom_icc_node qup3_core_slave; +static struct qcom_icc_node qnm_gemnoc_cnoc; +static struct qcom_icc_node qnm_gemnoc_pcie; +static struct qcom_icc_node qhs_ahb2phy0; +static struct qcom_icc_node qhs_ahb2phy1; +static struct qcom_icc_node qhs_ahb2phy2; +static struct qcom_icc_node qhs_ahb2phy3; +static struct qcom_icc_node qhs_anoc_throttle_cfg; +static struct qcom_icc_node qhs_aoss; +static struct qcom_icc_node qhs_apss; +static struct qcom_icc_node qhs_boot_rom; +static struct qcom_icc_node qhs_camera_cfg; +static struct qcom_icc_node qhs_camera_nrt_throttle_cfg; +static struct qcom_icc_node qhs_camera_rt_throttle_cfg; +static struct qcom_icc_node qhs_clk_ctl; +static struct qcom_icc_node qhs_compute0_cfg; +static struct qcom_icc_node qhs_compute1_cfg; +static struct qcom_icc_node qhs_cpr_cx; +static struct qcom_icc_node qhs_cpr_mmcx; +static struct qcom_icc_node qhs_cpr_mx; +static struct qcom_icc_node qhs_cpr_nspcx; +static struct qcom_icc_node qhs_crypto0_cfg; +static struct qcom_icc_node qhs_cx_rdpm; +static struct qcom_icc_node qhs_display0_cfg; +static struct qcom_icc_node qhs_display0_rt_throttle_cfg; +static struct qcom_icc_node qhs_display1_cfg; +static struct qcom_icc_node qhs_display1_rt_throttle_cfg; +static struct qcom_icc_node qhs_emac0_cfg; +static struct qcom_icc_node qhs_emac1_cfg; +static struct qcom_icc_node qhs_gp_dsp0_cfg; +static struct qcom_icc_node qhs_gp_dsp1_cfg; +static struct qcom_icc_node qhs_gpdsp0_throttle_cfg; +static struct qcom_icc_node qhs_gpdsp1_throttle_cfg; +static struct qcom_icc_node qhs_gpu_tcu_throttle_cfg; +static struct qcom_icc_node qhs_gpuss_cfg; +static struct qcom_icc_node qhs_hwkm; +static struct qcom_icc_node qhs_imem_cfg; +static struct qcom_icc_node qhs_ipa; +static struct qcom_icc_node qhs_ipc_router; +static struct qcom_icc_node qhs_lpass_cfg; +static struct qcom_icc_node qhs_lpass_throttle_cfg; +static struct qcom_icc_node qhs_mx_rdpm; +static struct qcom_icc_node qhs_mxc_rdpm; +static struct qcom_icc_node qhs_pcie0_cfg; +static struct qcom_icc_node qhs_pcie1_cfg; +static struct qcom_icc_node qhs_pcie_rsc_cfg; +static struct qcom_icc_node qhs_pcie_tcu_throttle_cfg; +static struct qcom_icc_node qhs_pcie_throttle_cfg; +static struct qcom_icc_node qhs_pdm; +static struct qcom_icc_node qhs_pimem_cfg; +static struct qcom_icc_node qhs_pke_wrapper_cfg; +static struct qcom_icc_node qhs_qdss_cfg; +static struct qcom_icc_node qhs_qm_cfg; +static struct qcom_icc_node qhs_qm_mpu_cfg; +static struct qcom_icc_node qhs_qup0; +static struct qcom_icc_node qhs_qup1; +static struct qcom_icc_node qhs_qup2; +static struct qcom_icc_node qhs_qup3; +static struct qcom_icc_node qhs_sail_throttle_cfg; +static struct qcom_icc_node qhs_sdc1; +static struct qcom_icc_node qhs_security; +static struct qcom_icc_node qhs_snoc_throttle_cfg; +static struct qcom_icc_node qhs_tcsr; +static struct qcom_icc_node qhs_tlmm; +static struct qcom_icc_node qhs_tsc_cfg; +static struct qcom_icc_node qhs_ufs_card_cfg; +static struct qcom_icc_node qhs_ufs_mem_cfg; +static struct qcom_icc_node qhs_usb2_0; +static struct qcom_icc_node qhs_usb3_0; +static struct qcom_icc_node qhs_usb3_1; +static struct qcom_icc_node qhs_venus_cfg; +static struct qcom_icc_node qhs_venus_cvp_throttle_cfg; +static struct qcom_icc_node qhs_venus_v_cpu_throttle_cfg; +static struct qcom_icc_node qhs_venus_vcodec_throttle_cfg; +static struct qcom_icc_node qns_ddrss_cfg; +static struct qcom_icc_node qns_gpdsp_noc_cfg; +static struct qcom_icc_node qns_mnoc_hf_cfg; +static struct qcom_icc_node qns_mnoc_sf_cfg; +static struct qcom_icc_node qns_pcie_anoc_cfg; +static struct qcom_icc_node qns_snoc_cfg; +static struct qcom_icc_node qxs_boot_imem; +static struct qcom_icc_node qxs_imem; +static struct qcom_icc_node qxs_pimem; +static struct qcom_icc_node xs_pcie_0; +static struct qcom_icc_node xs_pcie_1; +static struct qcom_icc_node xs_qdss_stm; +static struct qcom_icc_node xs_sys_tcu_cfg; +static struct qcom_icc_node qnm_cnoc_dc_noc; +static struct qcom_icc_node qhs_llcc; +static struct qcom_icc_node qns_gemnoc; +static struct qcom_icc_node alm_gpu_tcu; +static struct qcom_icc_node alm_pcie_tcu; +static struct qcom_icc_node alm_sys_tcu; +static struct qcom_icc_node chm_apps; +static struct qcom_icc_node qnm_cmpnoc0; +static struct qcom_icc_node qnm_cmpnoc1; +static struct qcom_icc_node qnm_gemnoc_cfg; +static struct qcom_icc_node qnm_gpdsp_sail; +static struct qcom_icc_node qnm_gpu; +static struct qcom_icc_node qnm_mnoc_hf; +static struct qcom_icc_node qnm_mnoc_sf; +static struct qcom_icc_node qnm_pcie; +static struct qcom_icc_node qnm_snoc_gc; +static struct qcom_icc_node qnm_snoc_sf; +static struct qcom_icc_node qns_gem_noc_cnoc; +static struct qcom_icc_node qns_llcc; +static struct qcom_icc_node qns_pcie; +static struct qcom_icc_node srvc_even_gemnoc; +static struct qcom_icc_node srvc_odd_gemnoc; +static struct qcom_icc_node srvc_sys_gemnoc; +static struct qcom_icc_node srvc_sys_gemnoc_2; +static struct qcom_icc_node qxm_dsp0; +static struct qcom_icc_node qxm_dsp1; +static struct qcom_icc_node qns_gp_dsp_sail_noc; +static struct qcom_icc_node qhm_config_noc; +static struct qcom_icc_node qxm_lpass_dsp; +static struct qcom_icc_node qhs_lpass_core; +static struct qcom_icc_node qhs_lpass_lpi; +static struct qcom_icc_node qhs_lpass_mpu; +static struct qcom_icc_node qhs_lpass_top; +static struct qcom_icc_node qns_sysnoc; +static struct qcom_icc_node srvc_niu_aml_noc; +static struct qcom_icc_node srvc_niu_lpass_agnoc; +static struct qcom_icc_node llcc_mc; +static struct qcom_icc_node ebi; +static struct qcom_icc_node qnm_camnoc_hf; +static struct qcom_icc_node qnm_camnoc_icp; +static struct qcom_icc_node qnm_camnoc_sf; +static struct qcom_icc_node qnm_mdp0_0; +static struct qcom_icc_node qnm_mdp0_1; +static struct qcom_icc_node qnm_mdp1_0; +static struct qcom_icc_node qnm_mdp1_1; +static struct qcom_icc_node qnm_mnoc_hf_cfg; +static struct qcom_icc_node qnm_mnoc_sf_cfg; +static struct qcom_icc_node qnm_video0; +static struct qcom_icc_node qnm_video1; +static struct qcom_icc_node qnm_video_cvp; +static struct qcom_icc_node qnm_video_v_cpu; +static struct qcom_icc_node qns_mem_noc_hf; +static struct qcom_icc_node qns_mem_noc_sf; +static struct qcom_icc_node srvc_mnoc_hf; +static struct qcom_icc_node srvc_mnoc_sf; +static struct qcom_icc_node qhm_nsp_noc_config; +static struct qcom_icc_node qxm_nsp; +static struct qcom_icc_node qns_hcp; +static struct qcom_icc_node qns_nsp_gemnoc; +static struct qcom_icc_node service_nsp_noc; +static struct qcom_icc_node qhm_nspb_noc_config; +static struct qcom_icc_node qxm_nspb; +static struct qcom_icc_node qns_nspb_gemnoc; +static struct qcom_icc_node qns_nspb_hcp; +static struct qcom_icc_node service_nspb_noc; +static struct qcom_icc_node xm_pcie3_0; +static struct qcom_icc_node xm_pcie3_1; +static struct qcom_icc_node qns_pcie_mem_noc; +static struct qcom_icc_node qhm_gic; +static struct qcom_icc_node qnm_aggre1_noc; +static struct qcom_icc_node qnm_aggre2_noc; +static struct qcom_icc_node qnm_lpass_noc; +static struct qcom_icc_node qnm_snoc_cfg; +static struct qcom_icc_node qxm_pimem; +static struct qcom_icc_node xm_gic; +static struct qcom_icc_node qns_gemnoc_gc; +static struct qcom_icc_node qns_gemnoc_sf; +static struct qcom_icc_node srvc_snoc; static struct qcom_icc_node qxm_qup3 = { .name = "qxm_qup3", - .id = SA8775P_MASTER_QUP_3, .channels = 1, .buswidth = 8, .num_links = 1, - .links = { SA8775P_SLAVE_A1NOC_SNOC }, + .link_nodes = (struct qcom_icc_node *[]) { &qns_a1noc_snoc }, }; static struct qcom_icc_node xm_emac_0 = { .name = "xm_emac_0", - .id = SA8775P_MASTER_EMAC, .channels = 1, .buswidth = 8, .num_links = 1, - .links = { SA8775P_SLAVE_A1NOC_SNOC }, + .link_nodes = (struct qcom_icc_node *[]) { &qns_a1noc_snoc }, }; static struct qcom_icc_node xm_emac_1 = { .name = "xm_emac_1", - .id = SA8775P_MASTER_EMAC_1, .channels = 1, .buswidth = 8, .num_links = 1, - .links = { SA8775P_SLAVE_A1NOC_SNOC }, + .link_nodes = (struct qcom_icc_node *[]) { &qns_a1noc_snoc }, }; static struct qcom_icc_node xm_sdc1 = { .name = "xm_sdc1", - .id = SA8775P_MASTER_SDC, .channels = 1, .buswidth = 8, .num_links = 1, - .links = { SA8775P_SLAVE_A1NOC_SNOC }, + .link_nodes = (struct qcom_icc_node *[]) { &qns_a1noc_snoc }, }; static struct qcom_icc_node xm_ufs_mem = { .name = "xm_ufs_mem", - .id = SA8775P_MASTER_UFS_MEM, .channels = 1, .buswidth = 8, .num_links = 1, - .links = { SA8775P_SLAVE_A1NOC_SNOC }, + .link_nodes = (struct qcom_icc_node *[]) { &qns_a1noc_snoc }, }; static struct qcom_icc_node xm_usb2_2 = { .name = "xm_usb2_2", - .id = SA8775P_MASTER_USB2, .channels = 1, .buswidth = 8, .num_links = 1, - .links = { SA8775P_SLAVE_A1NOC_SNOC }, + .link_nodes = (struct qcom_icc_node *[]) { &qns_a1noc_snoc }, }; static struct qcom_icc_node xm_usb3_0 = { .name = "xm_usb3_0", - .id = SA8775P_MASTER_USB3_0, .channels = 1, .buswidth = 8, .num_links = 1, - .links = { SA8775P_SLAVE_A1NOC_SNOC }, + .link_nodes = (struct qcom_icc_node *[]) { &qns_a1noc_snoc }, }; static struct qcom_icc_node xm_usb3_1 = { .name = "xm_usb3_1", - .id = SA8775P_MASTER_USB3_1, .channels = 1, .buswidth = 8, .num_links = 1, - .links = { SA8775P_SLAVE_A1NOC_SNOC }, + .link_nodes = (struct qcom_icc_node *[]) { &qns_a1noc_snoc }, }; static struct qcom_icc_node qhm_qdss_bam = { .name = "qhm_qdss_bam", - .id = SA8775P_MASTER_QDSS_BAM, .channels = 1, .buswidth = 4, .num_links = 1, - .links = { SA8775P_SLAVE_A2NOC_SNOC }, + .link_nodes = (struct qcom_icc_node *[]) { &qns_a2noc_snoc }, }; static struct qcom_icc_node qhm_qup0 = { .name = "qhm_qup0", - .id = SA8775P_MASTER_QUP_0, .channels = 1, .buswidth = 4, .num_links = 1, - .links = { SA8775P_SLAVE_A2NOC_SNOC }, + .link_nodes = (struct qcom_icc_node *[]) { &qns_a2noc_snoc }, }; static struct qcom_icc_node qhm_qup1 = { .name = "qhm_qup1", - .id = SA8775P_MASTER_QUP_1, .channels = 1, .buswidth = 4, .num_links = 1, - .links = { SA8775P_SLAVE_A2NOC_SNOC }, + .link_nodes = (struct qcom_icc_node *[]) { &qns_a2noc_snoc }, }; static struct qcom_icc_node qhm_qup2 = { .name = "qhm_qup2", - .id = SA8775P_MASTER_QUP_2, .channels = 1, .buswidth = 4, .num_links = 1, - .links = { SA8775P_SLAVE_A2NOC_SNOC }, + .link_nodes = (struct qcom_icc_node *[]) { &qns_a2noc_snoc }, }; static struct qcom_icc_node qnm_cnoc_datapath = { .name = "qnm_cnoc_datapath", - .id = SA8775P_MASTER_CNOC_A2NOC, .channels = 1, .buswidth = 8, .num_links = 1, - .links = { SA8775P_SLAVE_A2NOC_SNOC }, + .link_nodes = (struct qcom_icc_node *[]) { &qns_a2noc_snoc }, }; static struct qcom_icc_node qxm_crypto_0 = { .name = "qxm_crypto_0", - .id = SA8775P_MASTER_CRYPTO_CORE0, .channels = 1, .buswidth = 8, .num_links = 1, - .links = { SA8775P_SLAVE_A2NOC_SNOC }, + .link_nodes = (struct qcom_icc_node *[]) { &qns_a2noc_snoc }, }; static struct qcom_icc_node qxm_crypto_1 = { .name = "qxm_crypto_1", - .id = SA8775P_MASTER_CRYPTO_CORE1, .channels = 1, .buswidth = 8, .num_links = 1, - .links = { SA8775P_SLAVE_A2NOC_SNOC }, + .link_nodes = (struct qcom_icc_node *[]) { &qns_a2noc_snoc }, }; static struct qcom_icc_node qxm_ipa = { .name = "qxm_ipa", - .id = SA8775P_MASTER_IPA, .channels = 1, .buswidth = 8, .num_links = 1, - .links = { SA8775P_SLAVE_A2NOC_SNOC }, + .link_nodes = (struct qcom_icc_node *[]) { &qns_a2noc_snoc }, }; static struct qcom_icc_node xm_qdss_etr_0 = { .name = "xm_qdss_etr_0", - .id = SA8775P_MASTER_QDSS_ETR_0, .channels = 1, .buswidth = 8, .num_links = 1, - .links = { SA8775P_SLAVE_A2NOC_SNOC }, + .link_nodes = (struct qcom_icc_node *[]) { &qns_a2noc_snoc }, }; static struct qcom_icc_node xm_qdss_etr_1 = { .name = "xm_qdss_etr_1", - .id = SA8775P_MASTER_QDSS_ETR_1, .channels = 1, .buswidth = 8, .num_links = 1, - .links = { SA8775P_SLAVE_A2NOC_SNOC }, + .link_nodes = (struct qcom_icc_node *[]) { &qns_a2noc_snoc }, }; static struct qcom_icc_node xm_ufs_card = { .name = "xm_ufs_card", - .id = SA8775P_MASTER_UFS_CARD, .channels = 1, .buswidth = 8, .num_links = 1, - .links = { SA8775P_SLAVE_A2NOC_SNOC }, + .link_nodes = (struct qcom_icc_node *[]) { &qns_a2noc_snoc }, }; static struct qcom_icc_node qup0_core_master = { .name = "qup0_core_master", - .id = SA8775P_MASTER_QUP_CORE_0, .channels = 1, .buswidth = 4, .num_links = 1, - .links = { SA8775P_SLAVE_QUP_CORE_0 }, + .link_nodes = (struct qcom_icc_node *[]) { &qup0_core_slave }, }; static struct qcom_icc_node qup1_core_master = { .name = "qup1_core_master", - .id = SA8775P_MASTER_QUP_CORE_1, .channels = 1, .buswidth = 4, .num_links = 1, - .links = { SA8775P_SLAVE_QUP_CORE_1 }, + .link_nodes = (struct qcom_icc_node *[]) { &qup1_core_slave }, }; static struct qcom_icc_node qup2_core_master = { .name = "qup2_core_master", - .id = SA8775P_MASTER_QUP_CORE_2, .channels = 1, .buswidth = 4, .num_links = 1, - .links = { SA8775P_SLAVE_QUP_CORE_2 }, + .link_nodes = (struct qcom_icc_node *[]) { &qup2_core_slave }, }; static struct qcom_icc_node qup3_core_master = { .name = "qup3_core_master", - .id = SA8775P_MASTER_QUP_CORE_3, .channels = 1, .buswidth = 4, .num_links = 1, - .links = { SA8775P_SLAVE_QUP_CORE_3 }, + .link_nodes = (struct qcom_icc_node *[]) { &qup3_core_slave }, }; static struct qcom_icc_node qnm_gemnoc_cnoc = { .name = "qnm_gemnoc_cnoc", - .id = SA8775P_MASTER_GEM_NOC_CNOC, .channels = 1, .buswidth = 16, .num_links = 82, - .links = { SA8775P_SLAVE_AHB2PHY_0, - SA8775P_SLAVE_AHB2PHY_1, - SA8775P_SLAVE_AHB2PHY_2, - SA8775P_SLAVE_AHB2PHY_3, - SA8775P_SLAVE_ANOC_THROTTLE_CFG, - SA8775P_SLAVE_AOSS, - SA8775P_SLAVE_APPSS, - SA8775P_SLAVE_BOOT_ROM, - SA8775P_SLAVE_CAMERA_CFG, - SA8775P_SLAVE_CAMERA_NRT_THROTTLE_CFG, - SA8775P_SLAVE_CAMERA_RT_THROTTLE_CFG, - SA8775P_SLAVE_CLK_CTL, - SA8775P_SLAVE_CDSP_CFG, - SA8775P_SLAVE_CDSP1_CFG, - SA8775P_SLAVE_RBCPR_CX_CFG, - SA8775P_SLAVE_RBCPR_MMCX_CFG, - SA8775P_SLAVE_RBCPR_MX_CFG, - SA8775P_SLAVE_CPR_NSPCX, - SA8775P_SLAVE_CRYPTO_0_CFG, - SA8775P_SLAVE_CX_RDPM, - SA8775P_SLAVE_DISPLAY_CFG, - SA8775P_SLAVE_DISPLAY_RT_THROTTLE_CFG, - SA8775P_SLAVE_DISPLAY1_CFG, - SA8775P_SLAVE_DISPLAY1_RT_THROTTLE_CFG, - SA8775P_SLAVE_EMAC_CFG, - SA8775P_SLAVE_EMAC1_CFG, - SA8775P_SLAVE_GP_DSP0_CFG, - SA8775P_SLAVE_GP_DSP1_CFG, - SA8775P_SLAVE_GPDSP0_THROTTLE_CFG, - SA8775P_SLAVE_GPDSP1_THROTTLE_CFG, - SA8775P_SLAVE_GPU_TCU_THROTTLE_CFG, - SA8775P_SLAVE_GFX3D_CFG, - SA8775P_SLAVE_HWKM, - SA8775P_SLAVE_IMEM_CFG, - SA8775P_SLAVE_IPA_CFG, - SA8775P_SLAVE_IPC_ROUTER_CFG, - SA8775P_SLAVE_LPASS, - SA8775P_SLAVE_LPASS_THROTTLE_CFG, - SA8775P_SLAVE_MX_RDPM, - SA8775P_SLAVE_MXC_RDPM, - SA8775P_SLAVE_PCIE_0_CFG, - SA8775P_SLAVE_PCIE_1_CFG, - SA8775P_SLAVE_PCIE_RSC_CFG, - SA8775P_SLAVE_PCIE_TCU_THROTTLE_CFG, - SA8775P_SLAVE_PCIE_THROTTLE_CFG, - SA8775P_SLAVE_PDM, - SA8775P_SLAVE_PIMEM_CFG, - SA8775P_SLAVE_PKA_WRAPPER_CFG, - SA8775P_SLAVE_QDSS_CFG, - SA8775P_SLAVE_QM_CFG, - SA8775P_SLAVE_QM_MPU_CFG, - SA8775P_SLAVE_QUP_0, - SA8775P_SLAVE_QUP_1, - SA8775P_SLAVE_QUP_2, - SA8775P_SLAVE_QUP_3, - SA8775P_SLAVE_SAIL_THROTTLE_CFG, - SA8775P_SLAVE_SDC1, - SA8775P_SLAVE_SECURITY, - SA8775P_SLAVE_SNOC_THROTTLE_CFG, - SA8775P_SLAVE_TCSR, - SA8775P_SLAVE_TLMM, - SA8775P_SLAVE_TSC_CFG, - SA8775P_SLAVE_UFS_CARD_CFG, - SA8775P_SLAVE_UFS_MEM_CFG, - SA8775P_SLAVE_USB2, - SA8775P_SLAVE_USB3_0, - SA8775P_SLAVE_USB3_1, - SA8775P_SLAVE_VENUS_CFG, - SA8775P_SLAVE_VENUS_CVP_THROTTLE_CFG, - SA8775P_SLAVE_VENUS_V_CPU_THROTTLE_CFG, - SA8775P_SLAVE_VENUS_VCODEC_THROTTLE_CFG, - SA8775P_SLAVE_DDRSS_CFG, - SA8775P_SLAVE_GPDSP_NOC_CFG, - SA8775P_SLAVE_CNOC_MNOC_HF_CFG, - SA8775P_SLAVE_CNOC_MNOC_SF_CFG, - SA8775P_SLAVE_PCIE_ANOC_CFG, - SA8775P_SLAVE_SNOC_CFG, - SA8775P_SLAVE_BOOT_IMEM, - SA8775P_SLAVE_IMEM, - SA8775P_SLAVE_PIMEM, - SA8775P_SLAVE_QDSS_STM, - SA8775P_SLAVE_TCU - }, + .link_nodes = (struct qcom_icc_node *[]) { &qhs_ahb2phy0, &qhs_ahb2phy1, + &qhs_ahb2phy2, &qhs_ahb2phy3, + &qhs_anoc_throttle_cfg, &qhs_aoss, + &qhs_apss, &qhs_boot_rom, + &qhs_camera_cfg, &qhs_camera_nrt_throttle_cfg, + &qhs_camera_rt_throttle_cfg, &qhs_clk_ctl, + &qhs_compute0_cfg, &qhs_compute1_cfg, + &qhs_cpr_cx, &qhs_cpr_mmcx, + &qhs_cpr_mx, &qhs_cpr_nspcx, + &qhs_crypto0_cfg, &qhs_cx_rdpm, + &qhs_display0_cfg, &qhs_display0_rt_throttle_cfg, + &qhs_display1_cfg, &qhs_display1_rt_throttle_cfg, + &qhs_emac0_cfg, &qhs_emac1_cfg, + &qhs_gp_dsp0_cfg, &qhs_gp_dsp1_cfg, + &qhs_gpdsp0_throttle_cfg, &qhs_gpdsp1_throttle_cfg, + &qhs_gpu_tcu_throttle_cfg, &qhs_gpuss_cfg, + &qhs_hwkm, &qhs_imem_cfg, + &qhs_ipa, &qhs_ipc_router, + &qhs_lpass_cfg, &qhs_lpass_throttle_cfg, + &qhs_mx_rdpm, &qhs_mxc_rdpm, + &qhs_pcie0_cfg, &qhs_pcie1_cfg, + &qhs_pcie_rsc_cfg, &qhs_pcie_tcu_throttle_cfg, + &qhs_pcie_throttle_cfg, &qhs_pdm, + &qhs_pimem_cfg, &qhs_pke_wrapper_cfg, + &qhs_qdss_cfg, &qhs_qm_cfg, + &qhs_qm_mpu_cfg, &qhs_qup0, + &qhs_qup1, &qhs_qup2, + &qhs_qup3, &qhs_sail_throttle_cfg, + &qhs_sdc1, &qhs_security, + &qhs_snoc_throttle_cfg, &qhs_tcsr, + &qhs_tlmm, &qhs_tsc_cfg, + &qhs_ufs_card_cfg, &qhs_ufs_mem_cfg, + &qhs_usb2_0, &qhs_usb3_0, + &qhs_usb3_1, &qhs_venus_cfg, + &qhs_venus_cvp_throttle_cfg, &qhs_venus_v_cpu_throttle_cfg, + &qhs_venus_vcodec_throttle_cfg, &qns_ddrss_cfg, + &qns_gpdsp_noc_cfg, &qns_mnoc_hf_cfg, + &qns_mnoc_sf_cfg, &qns_pcie_anoc_cfg, + &qns_snoc_cfg, &qxs_boot_imem, + &qxs_imem, &qxs_pimem, + &xs_qdss_stm, &xs_sys_tcu_cfg }, }; static struct qcom_icc_node qnm_gemnoc_pcie = { .name = "qnm_gemnoc_pcie", - .id = SA8775P_MASTER_GEM_NOC_PCIE_SNOC, .channels = 1, .buswidth = 16, .num_links = 2, - .links = { SA8775P_SLAVE_PCIE_0, - SA8775P_SLAVE_PCIE_1 - }, + .link_nodes = (struct qcom_icc_node *[]) { &xs_pcie_0, &xs_pcie_1 }, }; static struct qcom_icc_node qnm_cnoc_dc_noc = { .name = "qnm_cnoc_dc_noc", - .id = SA8775P_MASTER_CNOC_DC_NOC, .channels = 1, .buswidth = 4, .num_links = 2, - .links = { SA8775P_SLAVE_LLCC_CFG, - SA8775P_SLAVE_GEM_NOC_CFG - }, + .link_nodes = (struct qcom_icc_node *[]) { &qhs_llcc, &qns_gemnoc }, }; static struct qcom_icc_node alm_gpu_tcu = { .name = "alm_gpu_tcu", - .id = SA8775P_MASTER_GPU_TCU, .channels = 1, .buswidth = 8, .num_links = 2, - .links = { SA8775P_SLAVE_GEM_NOC_CNOC, - SA8775P_SLAVE_LLCC - }, + .link_nodes = (struct qcom_icc_node *[]) { &qns_gem_noc_cnoc, &qns_llcc }, }; static struct qcom_icc_node alm_pcie_tcu = { .name = "alm_pcie_tcu", - .id = SA8775P_MASTER_PCIE_TCU, .channels = 1, .buswidth = 8, .num_links = 2, - .links = { SA8775P_SLAVE_GEM_NOC_CNOC, - SA8775P_SLAVE_LLCC - }, + .link_nodes = (struct qcom_icc_node *[]) { &qns_gem_noc_cnoc, &qns_llcc }, }; static struct qcom_icc_node alm_sys_tcu = { .name = "alm_sys_tcu", - .id = SA8775P_MASTER_SYS_TCU, .channels = 1, .buswidth = 8, .num_links = 2, - .links = { SA8775P_SLAVE_GEM_NOC_CNOC, - SA8775P_SLAVE_LLCC - }, + .link_nodes = (struct qcom_icc_node *[]) { &qns_gem_noc_cnoc, &qns_llcc }, }; static struct qcom_icc_node chm_apps = { .name = "chm_apps", - .id = SA8775P_MASTER_APPSS_PROC, .channels = 4, .buswidth = 32, .num_links = 3, - .links = { SA8775P_SLAVE_GEM_NOC_CNOC, - SA8775P_SLAVE_LLCC, - SA8775P_SLAVE_GEM_NOC_PCIE_CNOC - }, + .link_nodes = (struct qcom_icc_node *[]) { &qns_gem_noc_cnoc, &qns_llcc, + &qns_pcie }, }; static struct qcom_icc_node qnm_cmpnoc0 = { .name = "qnm_cmpnoc0", - .id = SA8775P_MASTER_COMPUTE_NOC, .channels = 2, .buswidth = 32, .num_links = 2, - .links = { SA8775P_SLAVE_GEM_NOC_CNOC, - SA8775P_SLAVE_LLCC - }, + .link_nodes = (struct qcom_icc_node *[]) { &qns_gem_noc_cnoc, &qns_llcc }, }; static struct qcom_icc_node qnm_cmpnoc1 = { .name = "qnm_cmpnoc1", - .id = SA8775P_MASTER_COMPUTE_NOC_1, .channels = 2, .buswidth = 32, .num_links = 2, - .links = { SA8775P_SLAVE_GEM_NOC_CNOC, - SA8775P_SLAVE_LLCC - }, + .link_nodes = (struct qcom_icc_node *[]) { &qns_gem_noc_cnoc, &qns_llcc }, }; static struct qcom_icc_node qnm_gemnoc_cfg = { .name = "qnm_gemnoc_cfg", - .id = SA8775P_MASTER_GEM_NOC_CFG, .channels = 1, .buswidth = 4, .num_links = 4, - .links = { SA8775P_SLAVE_SERVICE_GEM_NOC_1, - SA8775P_SLAVE_SERVICE_GEM_NOC_2, - SA8775P_SLAVE_SERVICE_GEM_NOC, - SA8775P_SLAVE_SERVICE_GEM_NOC2 - }, + .link_nodes = (struct qcom_icc_node *[]) { &srvc_even_gemnoc, &srvc_odd_gemnoc, + &srvc_sys_gemnoc, &srvc_sys_gemnoc_2 }, }; static struct qcom_icc_node qnm_gpdsp_sail = { .name = "qnm_gpdsp_sail", - .id = SA8775P_MASTER_GPDSP_SAIL, .channels = 1, .buswidth = 16, .num_links = 2, - .links = { SA8775P_SLAVE_GEM_NOC_CNOC, - SA8775P_SLAVE_LLCC - }, + .link_nodes = (struct qcom_icc_node *[]) { &qns_gem_noc_cnoc, &qns_llcc }, }; static struct qcom_icc_node qnm_gpu = { .name = "qnm_gpu", - .id = SA8775P_MASTER_GFX3D, .channels = 2, .buswidth = 32, .num_links = 2, - .links = { SA8775P_SLAVE_GEM_NOC_CNOC, - SA8775P_SLAVE_LLCC - }, + .link_nodes = (struct qcom_icc_node *[]) { &qns_gem_noc_cnoc, &qns_llcc }, }; static struct qcom_icc_node qnm_mnoc_hf = { .name = "qnm_mnoc_hf", - .id = SA8775P_MASTER_MNOC_HF_MEM_NOC, .channels = 2, .buswidth = 32, .num_links = 2, - .links = { SA8775P_SLAVE_LLCC, - SA8775P_SLAVE_GEM_NOC_PCIE_CNOC - }, + .link_nodes = (struct qcom_icc_node *[]) { &qns_llcc, &qns_pcie }, }; static struct qcom_icc_node qnm_mnoc_sf = { .name = "qnm_mnoc_sf", - .id = SA8775P_MASTER_MNOC_SF_MEM_NOC, .channels = 2, .buswidth = 32, .num_links = 3, - .links = { SA8775P_SLAVE_GEM_NOC_CNOC, - SA8775P_SLAVE_LLCC, - SA8775P_SLAVE_GEM_NOC_PCIE_CNOC - }, + .link_nodes = (struct qcom_icc_node *[]) { &qns_gem_noc_cnoc, &qns_llcc, + &qns_pcie }, }; static struct qcom_icc_node qnm_pcie = { .name = "qnm_pcie", - .id = SA8775P_MASTER_ANOC_PCIE_GEM_NOC, .channels = 1, .buswidth = 32, .num_links = 2, - .links = { SA8775P_SLAVE_GEM_NOC_CNOC, - SA8775P_SLAVE_LLCC - }, + .link_nodes = (struct qcom_icc_node *[]) { &qns_gem_noc_cnoc, &qns_llcc }, }; static struct qcom_icc_node qnm_snoc_gc = { .name = "qnm_snoc_gc", - .id = SA8775P_MASTER_SNOC_GC_MEM_NOC, .channels = 1, .buswidth = 8, .num_links = 1, - .links = { SA8775P_SLAVE_LLCC }, + .link_nodes = (struct qcom_icc_node *[]) { &qns_llcc }, }; static struct qcom_icc_node qnm_snoc_sf = { .name = "qnm_snoc_sf", - .id = SA8775P_MASTER_SNOC_SF_MEM_NOC, .channels = 1, .buswidth = 16, .num_links = 3, - .links = { SA8775P_SLAVE_GEM_NOC_CNOC, - SA8775P_SLAVE_LLCC, - SA8775P_SLAVE_GEM_NOC_PCIE_CNOC }, + .link_nodes = (struct qcom_icc_node *[]) { &qns_gem_noc_cnoc, &qns_llcc, + &qns_pcie }, }; static struct qcom_icc_node qxm_dsp0 = { .name = "qxm_dsp0", - .id = SA8775P_MASTER_DSP0, .channels = 1, .buswidth = 16, .num_links = 1, - .links = { SA8775P_SLAVE_GP_DSP_SAIL_NOC }, + .link_nodes = (struct qcom_icc_node *[]) { &qns_gp_dsp_sail_noc }, }; static struct qcom_icc_node qxm_dsp1 = { .name = "qxm_dsp1", - .id = SA8775P_MASTER_DSP1, .channels = 1, .buswidth = 16, .num_links = 1, - .links = { SA8775P_SLAVE_GP_DSP_SAIL_NOC }, + .link_nodes = (struct qcom_icc_node *[]) { &qns_gp_dsp_sail_noc }, }; static struct qcom_icc_node qhm_config_noc = { .name = "qhm_config_noc", - .id = SA8775P_MASTER_CNOC_LPASS_AG_NOC, .channels = 1, .buswidth = 4, .num_links = 6, - .links = { SA8775P_SLAVE_LPASS_CORE_CFG, - SA8775P_SLAVE_LPASS_LPI_CFG, - SA8775P_SLAVE_LPASS_MPU_CFG, - SA8775P_SLAVE_LPASS_TOP_CFG, - SA8775P_SLAVE_SERVICES_LPASS_AML_NOC, - SA8775P_SLAVE_SERVICE_LPASS_AG_NOC - }, + .link_nodes = (struct qcom_icc_node *[]) { &qhs_lpass_core, &qhs_lpass_lpi, + &qhs_lpass_mpu, &qhs_lpass_top, + &srvc_niu_aml_noc, &srvc_niu_lpass_agnoc }, }; static struct qcom_icc_node qxm_lpass_dsp = { .name = "qxm_lpass_dsp", - .id = SA8775P_MASTER_LPASS_PROC, .channels = 1, .buswidth = 8, .num_links = 4, - .links = { SA8775P_SLAVE_LPASS_TOP_CFG, - SA8775P_SLAVE_LPASS_SNOC, - SA8775P_SLAVE_SERVICES_LPASS_AML_NOC, - SA8775P_SLAVE_SERVICE_LPASS_AG_NOC - }, + .link_nodes = (struct qcom_icc_node *[]) { &qhs_lpass_top, &qns_sysnoc, + &srvc_niu_aml_noc, &srvc_niu_lpass_agnoc }, }; static struct qcom_icc_node llcc_mc = { .name = "llcc_mc", - .id = SA8775P_MASTER_LLCC, .channels = 8, .buswidth = 4, .num_links = 1, - .links = { SA8775P_SLAVE_EBI1 }, + .link_nodes = (struct qcom_icc_node *[]) { &ebi }, }; static struct qcom_icc_node qnm_camnoc_hf = { .name = "qnm_camnoc_hf", - .id = SA8775P_MASTER_CAMNOC_HF, .channels = 1, .buswidth = 32, .num_links = 1, - .links = { SA8775P_SLAVE_MNOC_HF_MEM_NOC }, + .link_nodes = (struct qcom_icc_node *[]) { &qns_mem_noc_hf }, }; static struct qcom_icc_node qnm_camnoc_icp = { .name = "qnm_camnoc_icp", - .id = SA8775P_MASTER_CAMNOC_ICP, .channels = 1, .buswidth = 8, .num_links = 1, - .links = { SA8775P_SLAVE_MNOC_SF_MEM_NOC }, + .link_nodes = (struct qcom_icc_node *[]) { &qns_mem_noc_sf }, }; static struct qcom_icc_node qnm_camnoc_sf = { .name = "qnm_camnoc_sf", - .id = SA8775P_MASTER_CAMNOC_SF, .channels = 1, .buswidth = 32, .num_links = 1, - .links = { SA8775P_SLAVE_MNOC_SF_MEM_NOC }, + .link_nodes = (struct qcom_icc_node *[]) { &qns_mem_noc_sf }, }; static struct qcom_icc_node qnm_mdp0_0 = { .name = "qnm_mdp0_0", - .id = SA8775P_MASTER_MDP0, .channels = 1, .buswidth = 32, .num_links = 1, - .links = { SA8775P_SLAVE_MNOC_HF_MEM_NOC }, + .link_nodes = (struct qcom_icc_node *[]) { &qns_mem_noc_hf }, }; static struct qcom_icc_node qnm_mdp0_1 = { .name = "qnm_mdp0_1", - .id = SA8775P_MASTER_MDP1, .channels = 1, .buswidth = 32, .num_links = 1, - .links = { SA8775P_SLAVE_MNOC_HF_MEM_NOC }, + .link_nodes = (struct qcom_icc_node *[]) { &qns_mem_noc_hf }, }; static struct qcom_icc_node qnm_mdp1_0 = { .name = "qnm_mdp1_0", - .id = SA8775P_MASTER_MDP_CORE1_0, .channels = 1, .buswidth = 32, .num_links = 1, - .links = { SA8775P_SLAVE_MNOC_HF_MEM_NOC }, + .link_nodes = (struct qcom_icc_node *[]) { &qns_mem_noc_hf }, }; static struct qcom_icc_node qnm_mdp1_1 = { .name = "qnm_mdp1_1", - .id = SA8775P_MASTER_MDP_CORE1_1, .channels = 1, .buswidth = 32, .num_links = 1, - .links = { SA8775P_SLAVE_MNOC_HF_MEM_NOC }, + .link_nodes = (struct qcom_icc_node *[]) { &qns_mem_noc_hf }, }; static struct qcom_icc_node qnm_mnoc_hf_cfg = { .name = "qnm_mnoc_hf_cfg", - .id = SA8775P_MASTER_CNOC_MNOC_HF_CFG, .channels = 1, .buswidth = 4, .num_links = 1, - .links = { SA8775P_SLAVE_SERVICE_MNOC_HF }, + .link_nodes = (struct qcom_icc_node *[]) { &srvc_mnoc_hf }, }; static struct qcom_icc_node qnm_mnoc_sf_cfg = { .name = "qnm_mnoc_sf_cfg", - .id = SA8775P_MASTER_CNOC_MNOC_SF_CFG, .channels = 1, .buswidth = 4, .num_links = 1, - .links = { SA8775P_SLAVE_SERVICE_MNOC_SF }, + .link_nodes = (struct qcom_icc_node *[]) { &srvc_mnoc_sf }, }; static struct qcom_icc_node qnm_video0 = { .name = "qnm_video0", - .id = SA8775P_MASTER_VIDEO_P0, .channels = 1, .buswidth = 32, .num_links = 1, - .links = { SA8775P_SLAVE_MNOC_SF_MEM_NOC }, + .link_nodes = (struct qcom_icc_node *[]) { &qns_mem_noc_sf }, }; static struct qcom_icc_node qnm_video1 = { .name = "qnm_video1", - .id = SA8775P_MASTER_VIDEO_P1, .channels = 1, .buswidth = 32, .num_links = 1, - .links = { SA8775P_SLAVE_MNOC_SF_MEM_NOC }, + .link_nodes = (struct qcom_icc_node *[]) { &qns_mem_noc_sf }, }; static struct qcom_icc_node qnm_video_cvp = { .name = "qnm_video_cvp", - .id = SA8775P_MASTER_VIDEO_PROC, .channels = 1, .buswidth = 32, .num_links = 1, - .links = { SA8775P_SLAVE_MNOC_SF_MEM_NOC }, + .link_nodes = (struct qcom_icc_node *[]) { &qns_mem_noc_sf }, }; static struct qcom_icc_node qnm_video_v_cpu = { .name = "qnm_video_v_cpu", - .id = SA8775P_MASTER_VIDEO_V_PROC, .channels = 1, .buswidth = 8, .num_links = 1, - .links = { SA8775P_SLAVE_MNOC_SF_MEM_NOC }, + .link_nodes = (struct qcom_icc_node *[]) { &qns_mem_noc_sf }, }; static struct qcom_icc_node qhm_nsp_noc_config = { .name = "qhm_nsp_noc_config", - .id = SA8775P_MASTER_CDSP_NOC_CFG, .channels = 1, .buswidth = 4, .num_links = 1, - .links = { SA8775P_SLAVE_SERVICE_NSP_NOC }, + .link_nodes = (struct qcom_icc_node *[]) { &service_nsp_noc }, }; static struct qcom_icc_node qxm_nsp = { .name = "qxm_nsp", - .id = SA8775P_MASTER_CDSP_PROC, .channels = 2, .buswidth = 32, .num_links = 2, - .links = { SA8775P_SLAVE_HCP_A, SLAVE_CDSP_MEM_NOC }, + .link_nodes = (struct qcom_icc_node *[]) { &qns_hcp, &qns_nsp_gemnoc }, }; static struct qcom_icc_node qhm_nspb_noc_config = { .name = "qhm_nspb_noc_config", - .id = SA8775P_MASTER_CDSPB_NOC_CFG, .channels = 1, .buswidth = 4, .num_links = 1, - .links = { SA8775P_SLAVE_SERVICE_NSPB_NOC }, + .link_nodes = (struct qcom_icc_node *[]) { &service_nspb_noc }, }; static struct qcom_icc_node qxm_nspb = { .name = "qxm_nspb", - .id = SA8775P_MASTER_CDSP_PROC_B, .channels = 2, .buswidth = 32, .num_links = 2, - .links = { SA8775P_SLAVE_HCP_B, SLAVE_CDSPB_MEM_NOC }, + .link_nodes = (struct qcom_icc_node *[]) { &qns_nspb_hcp, &qns_nspb_gemnoc }, }; static struct qcom_icc_node xm_pcie3_0 = { .name = "xm_pcie3_0", - .id = SA8775P_MASTER_PCIE_0, .channels = 1, .buswidth = 16, .num_links = 1, - .links = { SA8775P_SLAVE_ANOC_PCIE_GEM_NOC }, + .link_nodes = (struct qcom_icc_node *[]) { &qns_pcie_mem_noc }, }; static struct qcom_icc_node xm_pcie3_1 = { .name = "xm_pcie3_1", - .id = SA8775P_MASTER_PCIE_1, .channels = 1, .buswidth = 32, .num_links = 1, - .links = { SA8775P_SLAVE_ANOC_PCIE_GEM_NOC }, + .link_nodes = (struct qcom_icc_node *[]) { &qns_pcie_mem_noc }, }; static struct qcom_icc_node qhm_gic = { .name = "qhm_gic", - .id = SA8775P_MASTER_GIC_AHB, .channels = 1, .buswidth = 4, .num_links = 1, - .links = { SA8775P_SLAVE_SNOC_GEM_NOC_SF }, + .link_nodes = (struct qcom_icc_node *[]) { &qns_gemnoc_sf }, }; static struct qcom_icc_node qnm_aggre1_noc = { .name = "qnm_aggre1_noc", - .id = SA8775P_MASTER_A1NOC_SNOC, .channels = 1, .buswidth = 32, .num_links = 1, - .links = { SA8775P_SLAVE_SNOC_GEM_NOC_SF }, + .link_nodes = (struct qcom_icc_node *[]) { &qns_gemnoc_sf }, }; static struct qcom_icc_node qnm_aggre2_noc = { .name = "qnm_aggre2_noc", - .id = SA8775P_MASTER_A2NOC_SNOC, .channels = 1, .buswidth = 16, .num_links = 1, - .links = { SA8775P_SLAVE_SNOC_GEM_NOC_SF }, + .link_nodes = (struct qcom_icc_node *[]) { &qns_gemnoc_sf }, }; static struct qcom_icc_node qnm_lpass_noc = { .name = "qnm_lpass_noc", - .id = SA8775P_MASTER_LPASS_ANOC, .channels = 1, .buswidth = 16, .num_links = 1, - .links = { SA8775P_SLAVE_SNOC_GEM_NOC_SF }, + .link_nodes = (struct qcom_icc_node *[]) { &qns_gemnoc_sf }, }; static struct qcom_icc_node qnm_snoc_cfg = { .name = "qnm_snoc_cfg", - .id = SA8775P_MASTER_SNOC_CFG, .channels = 1, .buswidth = 4, .num_links = 1, - .links = { SA8775P_SLAVE_SERVICE_SNOC }, + .link_nodes = (struct qcom_icc_node *[]) { &srvc_snoc }, }; static struct qcom_icc_node qxm_pimem = { .name = "qxm_pimem", - .id = SA8775P_MASTER_PIMEM, .channels = 1, .buswidth = 8, .num_links = 1, - .links = { SA8775P_SLAVE_SNOC_GEM_NOC_GC }, + .link_nodes = (struct qcom_icc_node *[]) { &qns_gemnoc_gc }, }; static struct qcom_icc_node xm_gic = { .name = "xm_gic", - .id = SA8775P_MASTER_GIC, .channels = 1, .buswidth = 8, .num_links = 1, - .links = { SA8775P_SLAVE_SNOC_GEM_NOC_GC }, + .link_nodes = (struct qcom_icc_node *[]) { &qns_gemnoc_gc }, }; static struct qcom_icc_node qns_a1noc_snoc = { .name = "qns_a1noc_snoc", - .id = SA8775P_SLAVE_A1NOC_SNOC, .channels = 1, .buswidth = 32, .num_links = 1, - .links = { SA8775P_MASTER_A1NOC_SNOC }, + .link_nodes = (struct qcom_icc_node *[]) { &qnm_aggre1_noc }, }; static struct qcom_icc_node qns_a2noc_snoc = { .name = "qns_a2noc_snoc", - .id = SA8775P_SLAVE_A2NOC_SNOC, .channels = 1, .buswidth = 16, .num_links = 1, - .links = { SA8775P_MASTER_A2NOC_SNOC }, + .link_nodes = (struct qcom_icc_node *[]) { &qnm_aggre2_noc }, }; static struct qcom_icc_node qup0_core_slave = { .name = "qup0_core_slave", - .id = SA8775P_SLAVE_QUP_CORE_0, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qup1_core_slave = { .name = "qup1_core_slave", - .id = SA8775P_SLAVE_QUP_CORE_1, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qup2_core_slave = { .name = "qup2_core_slave", - .id = SA8775P_SLAVE_QUP_CORE_2, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qup3_core_slave = { .name = "qup3_core_slave", - .id = SA8775P_SLAVE_QUP_CORE_3, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qhs_ahb2phy0 = { .name = "qhs_ahb2phy0", - .id = SA8775P_SLAVE_AHB2PHY_0, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qhs_ahb2phy1 = { .name = "qhs_ahb2phy1", - .id = SA8775P_SLAVE_AHB2PHY_1, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qhs_ahb2phy2 = { .name = "qhs_ahb2phy2", - .id = SA8775P_SLAVE_AHB2PHY_2, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qhs_ahb2phy3 = { .name = "qhs_ahb2phy3", - .id = SA8775P_SLAVE_AHB2PHY_3, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qhs_anoc_throttle_cfg = { .name = "qhs_anoc_throttle_cfg", - .id = SA8775P_SLAVE_ANOC_THROTTLE_CFG, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qhs_aoss = { .name = "qhs_aoss", - .id = SA8775P_SLAVE_AOSS, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qhs_apss = { .name = "qhs_apss", - .id = SA8775P_SLAVE_APPSS, .channels = 1, .buswidth = 8, }; static struct qcom_icc_node qhs_boot_rom = { .name = "qhs_boot_rom", - .id = SA8775P_SLAVE_BOOT_ROM, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qhs_camera_cfg = { .name = "qhs_camera_cfg", - .id = SA8775P_SLAVE_CAMERA_CFG, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qhs_camera_nrt_throttle_cfg = { .name = "qhs_camera_nrt_throttle_cfg", - .id = SA8775P_SLAVE_CAMERA_NRT_THROTTLE_CFG, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qhs_camera_rt_throttle_cfg = { .name = "qhs_camera_rt_throttle_cfg", - .id = SA8775P_SLAVE_CAMERA_RT_THROTTLE_CFG, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qhs_clk_ctl = { .name = "qhs_clk_ctl", - .id = SA8775P_SLAVE_CLK_CTL, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qhs_compute0_cfg = { .name = "qhs_compute0_cfg", - .id = SA8775P_SLAVE_CDSP_CFG, .channels = 1, .buswidth = 4, .num_links = 1, - .links = { SA8775P_MASTER_CDSP_NOC_CFG }, + .link_nodes = (struct qcom_icc_node *[]) { &qhm_nsp_noc_config }, }; static struct qcom_icc_node qhs_compute1_cfg = { .name = "qhs_compute1_cfg", - .id = SA8775P_SLAVE_CDSP1_CFG, .channels = 1, .buswidth = 4, .num_links = 1, - .links = { SA8775P_MASTER_CDSPB_NOC_CFG }, + .link_nodes = (struct qcom_icc_node *[]) { &qhm_nspb_noc_config }, }; static struct qcom_icc_node qhs_cpr_cx = { .name = "qhs_cpr_cx", - .id = SA8775P_SLAVE_RBCPR_CX_CFG, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qhs_cpr_mmcx = { .name = "qhs_cpr_mmcx", - .id = SA8775P_SLAVE_RBCPR_MMCX_CFG, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qhs_cpr_mx = { .name = "qhs_cpr_mx", - .id = SA8775P_SLAVE_RBCPR_MX_CFG, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qhs_cpr_nspcx = { .name = "qhs_cpr_nspcx", - .id = SA8775P_SLAVE_CPR_NSPCX, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qhs_crypto0_cfg = { .name = "qhs_crypto0_cfg", - .id = SA8775P_SLAVE_CRYPTO_0_CFG, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qhs_cx_rdpm = { .name = "qhs_cx_rdpm", - .id = SA8775P_SLAVE_CX_RDPM, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qhs_display0_cfg = { .name = "qhs_display0_cfg", - .id = SA8775P_SLAVE_DISPLAY_CFG, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qhs_display0_rt_throttle_cfg = { .name = "qhs_display0_rt_throttle_cfg", - .id = SA8775P_SLAVE_DISPLAY_RT_THROTTLE_CFG, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qhs_display1_cfg = { .name = "qhs_display1_cfg", - .id = SA8775P_SLAVE_DISPLAY1_CFG, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qhs_display1_rt_throttle_cfg = { .name = "qhs_display1_rt_throttle_cfg", - .id = SA8775P_SLAVE_DISPLAY1_RT_THROTTLE_CFG, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qhs_emac0_cfg = { .name = "qhs_emac0_cfg", - .id = SA8775P_SLAVE_EMAC_CFG, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qhs_emac1_cfg = { .name = "qhs_emac1_cfg", - .id = SA8775P_SLAVE_EMAC1_CFG, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qhs_gp_dsp0_cfg = { .name = "qhs_gp_dsp0_cfg", - .id = SA8775P_SLAVE_GP_DSP0_CFG, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qhs_gp_dsp1_cfg = { .name = "qhs_gp_dsp1_cfg", - .id = SA8775P_SLAVE_GP_DSP1_CFG, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qhs_gpdsp0_throttle_cfg = { .name = "qhs_gpdsp0_throttle_cfg", - .id = SA8775P_SLAVE_GPDSP0_THROTTLE_CFG, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qhs_gpdsp1_throttle_cfg = { .name = "qhs_gpdsp1_throttle_cfg", - .id = SA8775P_SLAVE_GPDSP1_THROTTLE_CFG, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qhs_gpu_tcu_throttle_cfg = { .name = "qhs_gpu_tcu_throttle_cfg", - .id = SA8775P_SLAVE_GPU_TCU_THROTTLE_CFG, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qhs_gpuss_cfg = { .name = "qhs_gpuss_cfg", - .id = SA8775P_SLAVE_GFX3D_CFG, .channels = 1, .buswidth = 8, }; static struct qcom_icc_node qhs_hwkm = { .name = "qhs_hwkm", - .id = SA8775P_SLAVE_HWKM, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qhs_imem_cfg = { .name = "qhs_imem_cfg", - .id = SA8775P_SLAVE_IMEM_CFG, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qhs_ipa = { .name = "qhs_ipa", - .id = SA8775P_SLAVE_IPA_CFG, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qhs_ipc_router = { .name = "qhs_ipc_router", - .id = SA8775P_SLAVE_IPC_ROUTER_CFG, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qhs_lpass_cfg = { .name = "qhs_lpass_cfg", - .id = SA8775P_SLAVE_LPASS, .channels = 1, .buswidth = 4, .num_links = 1, - .links = { SA8775P_MASTER_CNOC_LPASS_AG_NOC }, + .link_nodes = (struct qcom_icc_node *[]) { &qhm_config_noc }, }; static struct qcom_icc_node qhs_lpass_throttle_cfg = { .name = "qhs_lpass_throttle_cfg", - .id = SA8775P_SLAVE_LPASS_THROTTLE_CFG, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qhs_mx_rdpm = { .name = "qhs_mx_rdpm", - .id = SA8775P_SLAVE_MX_RDPM, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qhs_mxc_rdpm = { .name = "qhs_mxc_rdpm", - .id = SA8775P_SLAVE_MXC_RDPM, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qhs_pcie0_cfg = { .name = "qhs_pcie0_cfg", - .id = SA8775P_SLAVE_PCIE_0_CFG, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qhs_pcie1_cfg = { .name = "qhs_pcie1_cfg", - .id = SA8775P_SLAVE_PCIE_1_CFG, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qhs_pcie_rsc_cfg = { .name = "qhs_pcie_rsc_cfg", - .id = SA8775P_SLAVE_PCIE_RSC_CFG, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qhs_pcie_tcu_throttle_cfg = { .name = "qhs_pcie_tcu_throttle_cfg", - .id = SA8775P_SLAVE_PCIE_TCU_THROTTLE_CFG, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qhs_pcie_throttle_cfg = { .name = "qhs_pcie_throttle_cfg", - .id = SA8775P_SLAVE_PCIE_THROTTLE_CFG, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qhs_pdm = { .name = "qhs_pdm", - .id = SA8775P_SLAVE_PDM, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qhs_pimem_cfg = { .name = "qhs_pimem_cfg", - .id = SA8775P_SLAVE_PIMEM_CFG, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qhs_pke_wrapper_cfg = { .name = "qhs_pke_wrapper_cfg", - .id = SA8775P_SLAVE_PKA_WRAPPER_CFG, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qhs_qdss_cfg = { .name = "qhs_qdss_cfg", - .id = SA8775P_SLAVE_QDSS_CFG, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qhs_qm_cfg = { .name = "qhs_qm_cfg", - .id = SA8775P_SLAVE_QM_CFG, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qhs_qm_mpu_cfg = { .name = "qhs_qm_mpu_cfg", - .id = SA8775P_SLAVE_QM_MPU_CFG, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qhs_qup0 = { .name = "qhs_qup0", - .id = SA8775P_SLAVE_QUP_0, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qhs_qup1 = { .name = "qhs_qup1", - .id = SA8775P_SLAVE_QUP_1, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qhs_qup2 = { .name = "qhs_qup2", - .id = SA8775P_SLAVE_QUP_2, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qhs_qup3 = { .name = "qhs_qup3", - .id = SA8775P_SLAVE_QUP_3, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qhs_sail_throttle_cfg = { .name = "qhs_sail_throttle_cfg", - .id = SA8775P_SLAVE_SAIL_THROTTLE_CFG, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qhs_sdc1 = { .name = "qhs_sdc1", - .id = SA8775P_SLAVE_SDC1, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qhs_security = { .name = "qhs_security", - .id = SA8775P_SLAVE_SECURITY, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qhs_snoc_throttle_cfg = { .name = "qhs_snoc_throttle_cfg", - .id = SA8775P_SLAVE_SNOC_THROTTLE_CFG, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qhs_tcsr = { .name = "qhs_tcsr", - .id = SA8775P_SLAVE_TCSR, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qhs_tlmm = { .name = "qhs_tlmm", - .id = SA8775P_SLAVE_TLMM, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qhs_tsc_cfg = { .name = "qhs_tsc_cfg", - .id = SA8775P_SLAVE_TSC_CFG, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qhs_ufs_card_cfg = { .name = "qhs_ufs_card_cfg", - .id = SA8775P_SLAVE_UFS_CARD_CFG, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qhs_ufs_mem_cfg = { .name = "qhs_ufs_mem_cfg", - .id = SA8775P_SLAVE_UFS_MEM_CFG, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qhs_usb2_0 = { .name = "qhs_usb2_0", - .id = SA8775P_SLAVE_USB2, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qhs_usb3_0 = { .name = "qhs_usb3_0", - .id = SA8775P_SLAVE_USB3_0, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qhs_usb3_1 = { .name = "qhs_usb3_1", - .id = SA8775P_SLAVE_USB3_1, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qhs_venus_cfg = { .name = "qhs_venus_cfg", - .id = SA8775P_SLAVE_VENUS_CFG, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qhs_venus_cvp_throttle_cfg = { .name = "qhs_venus_cvp_throttle_cfg", - .id = SA8775P_SLAVE_VENUS_CVP_THROTTLE_CFG, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qhs_venus_v_cpu_throttle_cfg = { .name = "qhs_venus_v_cpu_throttle_cfg", - .id = SA8775P_SLAVE_VENUS_V_CPU_THROTTLE_CFG, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qhs_venus_vcodec_throttle_cfg = { .name = "qhs_venus_vcodec_throttle_cfg", - .id = SA8775P_SLAVE_VENUS_VCODEC_THROTTLE_CFG, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qns_ddrss_cfg = { .name = "qns_ddrss_cfg", - .id = SA8775P_SLAVE_DDRSS_CFG, .channels = 1, .buswidth = 4, .num_links = 1, - .links = { SA8775P_MASTER_CNOC_DC_NOC }, + .link_nodes = (struct qcom_icc_node *[]) { &qnm_cnoc_dc_noc }, }; static struct qcom_icc_node qns_gpdsp_noc_cfg = { .name = "qns_gpdsp_noc_cfg", - .id = SA8775P_SLAVE_GPDSP_NOC_CFG, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qns_mnoc_hf_cfg = { .name = "qns_mnoc_hf_cfg", - .id = SA8775P_SLAVE_CNOC_MNOC_HF_CFG, .channels = 1, .buswidth = 4, .num_links = 1, - .links = { SA8775P_MASTER_CNOC_MNOC_HF_CFG }, + .link_nodes = (struct qcom_icc_node *[]) { &qnm_mnoc_hf_cfg }, }; static struct qcom_icc_node qns_mnoc_sf_cfg = { .name = "qns_mnoc_sf_cfg", - .id = SA8775P_SLAVE_CNOC_MNOC_SF_CFG, .channels = 1, .buswidth = 4, .num_links = 1, - .links = { SA8775P_MASTER_CNOC_MNOC_SF_CFG }, + .link_nodes = (struct qcom_icc_node *[]) { &qnm_mnoc_sf_cfg }, }; static struct qcom_icc_node qns_pcie_anoc_cfg = { .name = "qns_pcie_anoc_cfg", - .id = SA8775P_SLAVE_PCIE_ANOC_CFG, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qns_snoc_cfg = { .name = "qns_snoc_cfg", - .id = SA8775P_SLAVE_SNOC_CFG, .channels = 1, .buswidth = 4, .num_links = 1, - .links = { SA8775P_MASTER_SNOC_CFG }, + .link_nodes = (struct qcom_icc_node *[]) { &qnm_snoc_cfg }, }; static struct qcom_icc_node qxs_boot_imem = { .name = "qxs_boot_imem", - .id = SA8775P_SLAVE_BOOT_IMEM, .channels = 1, .buswidth = 16, }; static struct qcom_icc_node qxs_imem = { .name = "qxs_imem", - .id = SA8775P_SLAVE_IMEM, .channels = 1, .buswidth = 8, }; static struct qcom_icc_node qxs_pimem = { .name = "qxs_pimem", - .id = SA8775P_SLAVE_PIMEM, .channels = 1, .buswidth = 8, }; static struct qcom_icc_node xs_pcie_0 = { .name = "xs_pcie_0", - .id = SA8775P_SLAVE_PCIE_0, .channels = 1, .buswidth = 16, }; static struct qcom_icc_node xs_pcie_1 = { .name = "xs_pcie_1", - .id = SA8775P_SLAVE_PCIE_1, .channels = 1, .buswidth = 32, }; static struct qcom_icc_node xs_qdss_stm = { .name = "xs_qdss_stm", - .id = SA8775P_SLAVE_QDSS_STM, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node xs_sys_tcu_cfg = { .name = "xs_sys_tcu_cfg", - .id = SA8775P_SLAVE_TCU, .channels = 1, .buswidth = 8, }; static struct qcom_icc_node qhs_llcc = { .name = "qhs_llcc", - .id = SA8775P_SLAVE_LLCC_CFG, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qns_gemnoc = { .name = "qns_gemnoc", - .id = SA8775P_SLAVE_GEM_NOC_CFG, .channels = 1, .buswidth = 4, .num_links = 1, - .links = { SA8775P_MASTER_GEM_NOC_CFG }, + .link_nodes = (struct qcom_icc_node *[]) { &qnm_gemnoc_cfg }, }; static struct qcom_icc_node qns_gem_noc_cnoc = { .name = "qns_gem_noc_cnoc", - .id = SA8775P_SLAVE_GEM_NOC_CNOC, .channels = 1, .buswidth = 16, .num_links = 1, - .links = { SA8775P_MASTER_GEM_NOC_CNOC }, + .link_nodes = (struct qcom_icc_node *[]) { &qnm_gemnoc_cnoc }, }; static struct qcom_icc_node qns_llcc = { .name = "qns_llcc", - .id = SA8775P_SLAVE_LLCC, .channels = 6, .buswidth = 16, .num_links = 1, - .links = { SA8775P_MASTER_LLCC }, + .link_nodes = (struct qcom_icc_node *[]) { &llcc_mc }, }; static struct qcom_icc_node qns_pcie = { .name = "qns_pcie", - .id = SA8775P_SLAVE_GEM_NOC_PCIE_CNOC, .channels = 1, .buswidth = 16, .num_links = 1, - .links = { SA8775P_MASTER_GEM_NOC_PCIE_SNOC }, + .link_nodes = (struct qcom_icc_node *[]) { &qnm_gemnoc_pcie }, }; static struct qcom_icc_node srvc_even_gemnoc = { .name = "srvc_even_gemnoc", - .id = SA8775P_SLAVE_SERVICE_GEM_NOC_1, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node srvc_odd_gemnoc = { .name = "srvc_odd_gemnoc", - .id = SA8775P_SLAVE_SERVICE_GEM_NOC_2, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node srvc_sys_gemnoc = { .name = "srvc_sys_gemnoc", - .id = SA8775P_SLAVE_SERVICE_GEM_NOC, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node srvc_sys_gemnoc_2 = { .name = "srvc_sys_gemnoc_2", - .id = SA8775P_SLAVE_SERVICE_GEM_NOC2, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qns_gp_dsp_sail_noc = { .name = "qns_gp_dsp_sail_noc", - .id = SA8775P_SLAVE_GP_DSP_SAIL_NOC, .channels = 1, .buswidth = 16, .num_links = 1, - .links = { SA8775P_MASTER_GPDSP_SAIL }, + .link_nodes = (struct qcom_icc_node *[]) { &qnm_gpdsp_sail }, }; static struct qcom_icc_node qhs_lpass_core = { .name = "qhs_lpass_core", - .id = SA8775P_SLAVE_LPASS_CORE_CFG, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qhs_lpass_lpi = { .name = "qhs_lpass_lpi", - .id = SA8775P_SLAVE_LPASS_LPI_CFG, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qhs_lpass_mpu = { .name = "qhs_lpass_mpu", - .id = SA8775P_SLAVE_LPASS_MPU_CFG, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qhs_lpass_top = { .name = "qhs_lpass_top", - .id = SA8775P_SLAVE_LPASS_TOP_CFG, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qns_sysnoc = { .name = "qns_sysnoc", - .id = SA8775P_SLAVE_LPASS_SNOC, .channels = 1, .buswidth = 16, .num_links = 1, - .links = { SA8775P_MASTER_LPASS_ANOC }, + .link_nodes = (struct qcom_icc_node *[]) { &qnm_lpass_noc }, }; static struct qcom_icc_node srvc_niu_aml_noc = { .name = "srvc_niu_aml_noc", - .id = SA8775P_SLAVE_SERVICES_LPASS_AML_NOC, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node srvc_niu_lpass_agnoc = { .name = "srvc_niu_lpass_agnoc", - .id = SA8775P_SLAVE_SERVICE_LPASS_AG_NOC, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node ebi = { .name = "ebi", - .id = SA8775P_SLAVE_EBI1, .channels = 8, .buswidth = 4, }; static struct qcom_icc_node qns_mem_noc_hf = { .name = "qns_mem_noc_hf", - .id = SA8775P_SLAVE_MNOC_HF_MEM_NOC, .channels = 2, .buswidth = 32, .num_links = 1, - .links = { SA8775P_MASTER_MNOC_HF_MEM_NOC }, + .link_nodes = (struct qcom_icc_node *[]) { &qnm_mnoc_hf }, }; static struct qcom_icc_node qns_mem_noc_sf = { .name = "qns_mem_noc_sf", - .id = SA8775P_SLAVE_MNOC_SF_MEM_NOC, .channels = 2, .buswidth = 32, .num_links = 1, - .links = { SA8775P_MASTER_MNOC_SF_MEM_NOC }, + .link_nodes = (struct qcom_icc_node *[]) { &qnm_mnoc_sf }, }; static struct qcom_icc_node srvc_mnoc_hf = { .name = "srvc_mnoc_hf", - .id = SA8775P_SLAVE_SERVICE_MNOC_HF, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node srvc_mnoc_sf = { .name = "srvc_mnoc_sf", - .id = SA8775P_SLAVE_SERVICE_MNOC_SF, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qns_hcp = { .name = "qns_hcp", - .id = SA8775P_SLAVE_HCP_A, .channels = 2, .buswidth = 32, }; static struct qcom_icc_node qns_nsp_gemnoc = { .name = "qns_nsp_gemnoc", - .id = SA8775P_SLAVE_CDSP_MEM_NOC, .channels = 2, .buswidth = 32, .num_links = 1, - .links = { SA8775P_MASTER_COMPUTE_NOC }, + .link_nodes = (struct qcom_icc_node *[]) { &qnm_cmpnoc0 }, }; static struct qcom_icc_node service_nsp_noc = { .name = "service_nsp_noc", - .id = SA8775P_SLAVE_SERVICE_NSP_NOC, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qns_nspb_gemnoc = { .name = "qns_nspb_gemnoc", - .id = SA8775P_SLAVE_CDSPB_MEM_NOC, .channels = 2, .buswidth = 32, .num_links = 1, - .links = { SA8775P_MASTER_COMPUTE_NOC_1 }, + .link_nodes = (struct qcom_icc_node *[]) { &qnm_cmpnoc1 }, }; static struct qcom_icc_node qns_nspb_hcp = { .name = "qns_nspb_hcp", - .id = SA8775P_SLAVE_HCP_B, .channels = 2, .buswidth = 32, }; static struct qcom_icc_node service_nspb_noc = { .name = "service_nspb_noc", - .id = SA8775P_SLAVE_SERVICE_NSPB_NOC, .channels = 1, .buswidth = 4, }; static struct qcom_icc_node qns_pcie_mem_noc = { .name = "qns_pcie_mem_noc", - .id = SA8775P_SLAVE_ANOC_PCIE_GEM_NOC, .channels = 1, .buswidth = 32, .num_links = 1, - .links = { SA8775P_MASTER_ANOC_PCIE_GEM_NOC }, + .link_nodes = (struct qcom_icc_node *[]) { &qnm_pcie }, }; static struct qcom_icc_node qns_gemnoc_gc = { .name = "qns_gemnoc_gc", - .id = SA8775P_SLAVE_SNOC_GEM_NOC_GC, .channels = 1, .buswidth = 8, .num_links = 1, - .links = { SA8775P_MASTER_SNOC_GC_MEM_NOC }, + .link_nodes = (struct qcom_icc_node *[]) { &qnm_snoc_gc }, }; static struct qcom_icc_node qns_gemnoc_sf = { .name = "qns_gemnoc_sf", - .id = SA8775P_SLAVE_SNOC_GEM_NOC_SF, .channels = 1, .buswidth = 16, .num_links = 1, - .links = { SA8775P_MASTER_SNOC_SF_MEM_NOC }, + .link_nodes = (struct qcom_icc_node *[]) { &qnm_snoc_sf }, }; static struct qcom_icc_node srvc_snoc = { .name = "srvc_snoc", - .id = SA8775P_SLAVE_SERVICE_SNOC, .channels = 1, .buswidth = 4, }; @@ -2113,6 +1841,7 @@ static const struct qcom_icc_desc sa8775p_aggre1_noc = { .num_nodes = ARRAY_SIZE(aggre1_noc_nodes), .bcms = aggre1_noc_bcms, .num_bcms = ARRAY_SIZE(aggre1_noc_bcms), + .alloc_dyn_id = true, }; static struct qcom_icc_bcm * const aggre2_noc_bcms[] = { @@ -2140,6 +1869,7 @@ static const struct qcom_icc_desc sa8775p_aggre2_noc = { .num_nodes = ARRAY_SIZE(aggre2_noc_nodes), .bcms = aggre2_noc_bcms, .num_bcms = ARRAY_SIZE(aggre2_noc_bcms), + .alloc_dyn_id = true, }; static struct qcom_icc_bcm * const clk_virt_bcms[] = { @@ -2164,6 +1894,7 @@ static const struct qcom_icc_desc sa8775p_clk_virt = { .num_nodes = ARRAY_SIZE(clk_virt_nodes), .bcms = clk_virt_bcms, .num_bcms = ARRAY_SIZE(clk_virt_bcms), + .alloc_dyn_id = true, }; static struct qcom_icc_bcm * const config_noc_bcms[] = { @@ -2269,6 +2000,7 @@ static const struct qcom_icc_desc sa8775p_config_noc = { .num_nodes = ARRAY_SIZE(config_noc_nodes), .bcms = config_noc_bcms, .num_bcms = ARRAY_SIZE(config_noc_bcms), + .alloc_dyn_id = true, }; static struct qcom_icc_bcm * const dc_noc_bcms[] = { @@ -2285,6 +2017,7 @@ static const struct qcom_icc_desc sa8775p_dc_noc = { .num_nodes = ARRAY_SIZE(dc_noc_nodes), .bcms = dc_noc_bcms, .num_bcms = ARRAY_SIZE(dc_noc_bcms), + .alloc_dyn_id = true, }; static struct qcom_icc_bcm * const gem_noc_bcms[] = { @@ -2321,6 +2054,7 @@ static const struct qcom_icc_desc sa8775p_gem_noc = { .num_nodes = ARRAY_SIZE(gem_noc_nodes), .bcms = gem_noc_bcms, .num_bcms = ARRAY_SIZE(gem_noc_bcms), + .alloc_dyn_id = true, }; static struct qcom_icc_bcm * const gpdsp_anoc_bcms[] = { @@ -2339,6 +2073,7 @@ static const struct qcom_icc_desc sa8775p_gpdsp_anoc = { .num_nodes = ARRAY_SIZE(gpdsp_anoc_nodes), .bcms = gpdsp_anoc_bcms, .num_bcms = ARRAY_SIZE(gpdsp_anoc_bcms), + .alloc_dyn_id = true, }; static struct qcom_icc_bcm * const lpass_ag_noc_bcms[] = { @@ -2362,6 +2097,7 @@ static const struct qcom_icc_desc sa8775p_lpass_ag_noc = { .num_nodes = ARRAY_SIZE(lpass_ag_noc_nodes), .bcms = lpass_ag_noc_bcms, .num_bcms = ARRAY_SIZE(lpass_ag_noc_bcms), + .alloc_dyn_id = true, }; static struct qcom_icc_bcm * const mc_virt_bcms[] = { @@ -2379,6 +2115,7 @@ static const struct qcom_icc_desc sa8775p_mc_virt = { .num_nodes = ARRAY_SIZE(mc_virt_nodes), .bcms = mc_virt_bcms, .num_bcms = ARRAY_SIZE(mc_virt_bcms), + .alloc_dyn_id = true, }; static struct qcom_icc_bcm * const mmss_noc_bcms[] = { @@ -2411,6 +2148,7 @@ static const struct qcom_icc_desc sa8775p_mmss_noc = { .num_nodes = ARRAY_SIZE(mmss_noc_nodes), .bcms = mmss_noc_bcms, .num_bcms = ARRAY_SIZE(mmss_noc_bcms), + .alloc_dyn_id = true, }; static struct qcom_icc_bcm * const nspa_noc_bcms[] = { @@ -2431,6 +2169,7 @@ static const struct qcom_icc_desc sa8775p_nspa_noc = { .num_nodes = ARRAY_SIZE(nspa_noc_nodes), .bcms = nspa_noc_bcms, .num_bcms = ARRAY_SIZE(nspa_noc_bcms), + .alloc_dyn_id = true, }; static struct qcom_icc_bcm * const nspb_noc_bcms[] = { @@ -2451,6 +2190,7 @@ static const struct qcom_icc_desc sa8775p_nspb_noc = { .num_nodes = ARRAY_SIZE(nspb_noc_nodes), .bcms = nspb_noc_bcms, .num_bcms = ARRAY_SIZE(nspb_noc_bcms), + .alloc_dyn_id = true, }; static struct qcom_icc_bcm * const pcie_anoc_bcms[] = { @@ -2468,6 +2208,7 @@ static const struct qcom_icc_desc sa8775p_pcie_anoc = { .num_nodes = ARRAY_SIZE(pcie_anoc_nodes), .bcms = pcie_anoc_bcms, .num_bcms = ARRAY_SIZE(pcie_anoc_bcms), + .alloc_dyn_id = true, }; static struct qcom_icc_bcm * const system_noc_bcms[] = { @@ -2496,6 +2237,7 @@ static const struct qcom_icc_desc sa8775p_system_noc = { .num_nodes = ARRAY_SIZE(system_noc_nodes), .bcms = system_noc_bcms, .num_bcms = ARRAY_SIZE(system_noc_bcms), + .alloc_dyn_id = true, }; static const struct of_device_id qnoc_of_match[] = { diff --git a/drivers/interconnect/qcom/sm8650.c b/drivers/interconnect/qcom/sm8650.c index 20ac5bc5e1fb..b7c321f4e4b5 100644 --- a/drivers/interconnect/qcom/sm8650.c +++ b/drivers/interconnect/qcom/sm8650.c @@ -17,20 +17,45 @@ #include "icc-rpmh.h" #include "sm8650.h" +static const struct regmap_config icc_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .fast_io = true, +}; + +static struct qcom_icc_qosbox qhm_qspi_qos = { + .num_ports = 1, + .port_offsets = { 0xc000 }, + .prio = 2, + .urg_fwd = 0, + .prio_fwd_disable = 0, +}; + static struct qcom_icc_node qhm_qspi = { .name = "qhm_qspi", .id = SM8650_MASTER_QSPI_0, .channels = 1, .buswidth = 4, + .qosbox = &qhm_qspi_qos, .num_links = 1, .links = { SM8650_SLAVE_A1NOC_SNOC }, }; +static struct qcom_icc_qosbox qhm_qup1_qos = { + .num_ports = 1, + .port_offsets = { 0xd000 }, + .prio = 2, + .urg_fwd = 0, + .prio_fwd_disable = 0, +}; + static struct qcom_icc_node qhm_qup1 = { .name = "qhm_qup1", .id = SM8650_MASTER_QUP_1, .channels = 1, .buswidth = 4, + .qosbox = &qhm_qup1_qos, .num_links = 1, .links = { SM8650_SLAVE_A1NOC_SNOC }, }; @@ -44,65 +69,128 @@ static struct qcom_icc_node qxm_qup02 = { .links = { SM8650_SLAVE_A1NOC_SNOC }, }; +static struct qcom_icc_qosbox xm_sdc4_qos = { + .num_ports = 1, + .port_offsets = { 0xe000 }, + .prio = 2, + .urg_fwd = 0, + .prio_fwd_disable = 0, +}; + static struct qcom_icc_node xm_sdc4 = { .name = "xm_sdc4", .id = SM8650_MASTER_SDCC_4, .channels = 1, .buswidth = 8, + .qosbox = &xm_sdc4_qos, .num_links = 1, .links = { SM8650_SLAVE_A1NOC_SNOC }, }; +static struct qcom_icc_qosbox xm_ufs_mem_qos = { + .num_ports = 1, + .port_offsets = { 0xf000 }, + .prio = 2, + .urg_fwd = 0, + .prio_fwd_disable = 0, +}; + static struct qcom_icc_node xm_ufs_mem = { .name = "xm_ufs_mem", .id = SM8650_MASTER_UFS_MEM, .channels = 1, .buswidth = 16, + .qosbox = &xm_ufs_mem_qos, .num_links = 1, .links = { SM8650_SLAVE_A1NOC_SNOC }, }; +static struct qcom_icc_qosbox xm_usb3_0_qos = { + .num_ports = 1, + .port_offsets = { 0x10000 }, + .prio = 2, + .urg_fwd = 0, + .prio_fwd_disable = 0, +}; + static struct qcom_icc_node xm_usb3_0 = { .name = "xm_usb3_0", .id = SM8650_MASTER_USB3_0, .channels = 1, .buswidth = 8, + .qosbox = &xm_usb3_0_qos, .num_links = 1, .links = { SM8650_SLAVE_A1NOC_SNOC }, }; +static struct qcom_icc_qosbox qhm_qdss_bam_qos = { + .num_ports = 1, + .port_offsets = { 0x12000 }, + .prio = 2, + .urg_fwd = 0, + .prio_fwd_disable = 0, +}; + static struct qcom_icc_node qhm_qdss_bam = { .name = "qhm_qdss_bam", .id = SM8650_MASTER_QDSS_BAM, .channels = 1, .buswidth = 4, + .qosbox = &qhm_qdss_bam_qos, .num_links = 1, .links = { SM8650_SLAVE_A2NOC_SNOC }, }; +static struct qcom_icc_qosbox qhm_qup2_qos = { + .num_ports = 1, + .port_offsets = { 0x13000 }, + .prio = 2, + .urg_fwd = 0, + .prio_fwd_disable = 0, +}; + static struct qcom_icc_node qhm_qup2 = { .name = "qhm_qup2", .id = SM8650_MASTER_QUP_2, .channels = 1, .buswidth = 4, + .qosbox = &qhm_qup2_qos, .num_links = 1, .links = { SM8650_SLAVE_A2NOC_SNOC }, }; +static struct qcom_icc_qosbox qxm_crypto_qos = { + .num_ports = 1, + .port_offsets = { 0x15000 }, + .prio = 2, + .urg_fwd = 1, + .prio_fwd_disable = 0, +}; + static struct qcom_icc_node qxm_crypto = { .name = "qxm_crypto", .id = SM8650_MASTER_CRYPTO, .channels = 1, .buswidth = 8, + .qosbox = &qxm_crypto_qos, .num_links = 1, .links = { SM8650_SLAVE_A2NOC_SNOC }, }; +static struct qcom_icc_qosbox qxm_ipa_qos = { + .num_ports = 1, + .port_offsets = { 0x16000 }, + .prio = 2, + .urg_fwd = 1, + .prio_fwd_disable = 0, +}; + static struct qcom_icc_node qxm_ipa = { .name = "qxm_ipa", .id = SM8650_MASTER_IPA, .channels = 1, .buswidth = 8, + .qosbox = &qxm_ipa_qos, .num_links = 1, .links = { SM8650_SLAVE_A2NOC_SNOC }, }; @@ -116,29 +204,56 @@ static struct qcom_icc_node qxm_sp = { .links = { SM8650_SLAVE_A2NOC_SNOC }, }; +static struct qcom_icc_qosbox xm_qdss_etr_0_qos = { + .num_ports = 1, + .port_offsets = { 0x17000 }, + .prio = 2, + .urg_fwd = 0, + .prio_fwd_disable = 0, +}; + static struct qcom_icc_node xm_qdss_etr_0 = { .name = "xm_qdss_etr_0", .id = SM8650_MASTER_QDSS_ETR, .channels = 1, .buswidth = 8, + .qosbox = &xm_qdss_etr_0_qos, .num_links = 1, .links = { SM8650_SLAVE_A2NOC_SNOC }, }; +static struct qcom_icc_qosbox xm_qdss_etr_1_qos = { + .num_ports = 1, + .port_offsets = { 0x18000 }, + .prio = 2, + .urg_fwd = 0, + .prio_fwd_disable = 0, +}; + static struct qcom_icc_node xm_qdss_etr_1 = { .name = "xm_qdss_etr_1", .id = SM8650_MASTER_QDSS_ETR_1, .channels = 1, .buswidth = 8, + .qosbox = &xm_qdss_etr_1_qos, .num_links = 1, .links = { SM8650_SLAVE_A2NOC_SNOC }, }; +static struct qcom_icc_qosbox xm_sdc2_qos = { + .num_ports = 1, + .port_offsets = { 0x19000 }, + .prio = 2, + .urg_fwd = 0, + .prio_fwd_disable = 0, +}; + static struct qcom_icc_node xm_sdc2 = { .name = "xm_sdc2", .id = SM8650_MASTER_SDCC_2, .channels = 1, .buswidth = 8, + .qosbox = &xm_sdc2_qos, .num_links = 1, .links = { SM8650_SLAVE_A2NOC_SNOC }, }; @@ -223,29 +338,56 @@ static struct qcom_icc_node qnm_gemnoc_pcie = { .links = { SM8650_SLAVE_PCIE_0, SM8650_SLAVE_PCIE_1 }, }; +static struct qcom_icc_qosbox alm_gpu_tcu_qos = { + .num_ports = 1, + .port_offsets = { 0xbf000 }, + .prio = 1, + .urg_fwd = 0, + .prio_fwd_disable = 1, +}; + static struct qcom_icc_node alm_gpu_tcu = { .name = "alm_gpu_tcu", .id = SM8650_MASTER_GPU_TCU, .channels = 1, .buswidth = 8, + .qosbox = &alm_gpu_tcu_qos, .num_links = 2, .links = { SM8650_SLAVE_GEM_NOC_CNOC, SM8650_SLAVE_LLCC }, }; +static struct qcom_icc_qosbox alm_sys_tcu_qos = { + .num_ports = 1, + .port_offsets = { 0xc1000 }, + .prio = 6, + .urg_fwd = 0, + .prio_fwd_disable = 1, +}; + static struct qcom_icc_node alm_sys_tcu = { .name = "alm_sys_tcu", .id = SM8650_MASTER_SYS_TCU, .channels = 1, .buswidth = 8, + .qosbox = &alm_sys_tcu_qos, .num_links = 2, .links = { SM8650_SLAVE_GEM_NOC_CNOC, SM8650_SLAVE_LLCC }, }; +static struct qcom_icc_qosbox alm_ubwc_p_tcu_qos = { + .num_ports = 1, + .port_offsets = { 0xc5000 }, + .prio = 1, + .urg_fwd = 0, + .prio_fwd_disable = 1, +}; + static struct qcom_icc_node alm_ubwc_p_tcu = { .name = "alm_ubwc_p_tcu", .id = SM8650_MASTER_UBWC_P_TCU, .channels = 1, .buswidth = 8, + .qosbox = &alm_ubwc_p_tcu_qos, .num_links = 2, .links = { SM8650_SLAVE_GEM_NOC_CNOC, SM8650_SLAVE_LLCC }, }; @@ -260,20 +402,38 @@ static struct qcom_icc_node chm_apps = { SM8650_SLAVE_MEM_NOC_PCIE_SNOC }, }; +static struct qcom_icc_qosbox qnm_gpu_qos = { + .num_ports = 2, + .port_offsets = { 0x31000, 0x71000 }, + .prio = 0, + .urg_fwd = 1, + .prio_fwd_disable = 1, +}; + static struct qcom_icc_node qnm_gpu = { .name = "qnm_gpu", .id = SM8650_MASTER_GFX3D, .channels = 2, .buswidth = 32, + .qosbox = &qnm_gpu_qos, .num_links = 2, .links = { SM8650_SLAVE_GEM_NOC_CNOC, SM8650_SLAVE_LLCC }, }; +static struct qcom_icc_qosbox qnm_lpass_gemnoc_qos = { + .num_ports = 1, + .port_offsets = { 0xb5000 }, + .prio = 0, + .urg_fwd = 1, + .prio_fwd_disable = 0, +}; + static struct qcom_icc_node qnm_lpass_gemnoc = { .name = "qnm_lpass_gemnoc", .id = SM8650_MASTER_LPASS_GEM_NOC, .channels = 1, .buswidth = 16, + .qosbox = &qnm_lpass_gemnoc_qos, .num_links = 3, .links = { SM8650_SLAVE_GEM_NOC_CNOC, SM8650_SLAVE_LLCC, SM8650_SLAVE_MEM_NOC_PCIE_SNOC }, @@ -289,67 +449,130 @@ static struct qcom_icc_node qnm_mdsp = { SM8650_SLAVE_MEM_NOC_PCIE_SNOC }, }; +static struct qcom_icc_qosbox qnm_mnoc_hf_qos = { + .num_ports = 2, + .port_offsets = { 0x33000, 0x73000 }, + .prio = 0, + .urg_fwd = 1, + .prio_fwd_disable = 0, +}; + static struct qcom_icc_node qnm_mnoc_hf = { .name = "qnm_mnoc_hf", .id = SM8650_MASTER_MNOC_HF_MEM_NOC, .channels = 2, .buswidth = 32, + .qosbox = &qnm_mnoc_hf_qos, .num_links = 2, .links = { SM8650_SLAVE_GEM_NOC_CNOC, SM8650_SLAVE_LLCC }, }; +static struct qcom_icc_qosbox qnm_mnoc_sf_qos = { + .num_ports = 2, + .port_offsets = { 0x35000, 0x75000 }, + .prio = 0, + .urg_fwd = 0, + .prio_fwd_disable = 0, +}; + static struct qcom_icc_node qnm_mnoc_sf = { .name = "qnm_mnoc_sf", .id = SM8650_MASTER_MNOC_SF_MEM_NOC, .channels = 2, .buswidth = 32, + .qosbox = &qnm_mnoc_sf_qos, .num_links = 2, .links = { SM8650_SLAVE_GEM_NOC_CNOC, SM8650_SLAVE_LLCC }, }; +static struct qcom_icc_qosbox qnm_nsp_gemnoc_qos = { + .num_ports = 2, + .port_offsets = { 0x37000, 0x77000 }, + .prio = 0, + .urg_fwd = 1, + .prio_fwd_disable = 1, +}; + static struct qcom_icc_node qnm_nsp_gemnoc = { .name = "qnm_nsp_gemnoc", .id = SM8650_MASTER_COMPUTE_NOC, .channels = 2, .buswidth = 32, + .qosbox = &qnm_nsp_gemnoc_qos, .num_links = 3, .links = { SM8650_SLAVE_GEM_NOC_CNOC, SM8650_SLAVE_LLCC, SM8650_SLAVE_MEM_NOC_PCIE_SNOC }, }; +static struct qcom_icc_qosbox qnm_pcie_qos = { + .num_ports = 1, + .port_offsets = { 0xb7000 }, + .prio = 2, + .urg_fwd = 1, + .prio_fwd_disable = 0, +}; + static struct qcom_icc_node qnm_pcie = { .name = "qnm_pcie", .id = SM8650_MASTER_ANOC_PCIE_GEM_NOC, .channels = 1, .buswidth = 16, + .qosbox = &qnm_pcie_qos, .num_links = 2, .links = { SM8650_SLAVE_GEM_NOC_CNOC, SM8650_SLAVE_LLCC }, }; +static struct qcom_icc_qosbox qnm_snoc_sf_qos = { + .num_ports = 1, + .port_offsets = { 0xbb000 }, + .prio = 0, + .urg_fwd = 1, + .prio_fwd_disable = 0, +}; + static struct qcom_icc_node qnm_snoc_sf = { .name = "qnm_snoc_sf", .id = SM8650_MASTER_SNOC_SF_MEM_NOC, .channels = 1, .buswidth = 16, + .qosbox = &qnm_snoc_sf_qos, .num_links = 3, .links = { SM8650_SLAVE_GEM_NOC_CNOC, SM8650_SLAVE_LLCC, SM8650_SLAVE_MEM_NOC_PCIE_SNOC }, }; +static struct qcom_icc_qosbox qnm_ubwc_p_qos = { + .num_ports = 1, + .port_offsets = { 0xc3000 }, + .prio = 1, + .urg_fwd = 1, + .prio_fwd_disable = 1, +}; + static struct qcom_icc_node qnm_ubwc_p = { .name = "qnm_ubwc_p", .id = SM8650_MASTER_UBWC_P, .channels = 1, .buswidth = 32, + .qosbox = &qnm_ubwc_p_qos, .num_links = 1, .links = { SM8650_SLAVE_LLCC }, }; +static struct qcom_icc_qosbox xm_gic_qos = { + .num_ports = 1, + .port_offsets = { 0xb9000 }, + .prio = 4, + .urg_fwd = 0, + .prio_fwd_disable = 1, +}; + static struct qcom_icc_node xm_gic = { .name = "xm_gic", .id = SM8650_MASTER_GIC, .channels = 1, .buswidth = 8, + .qosbox = &xm_gic_qos, .num_links = 1, .links = { SM8650_SLAVE_LLCC }, }; @@ -390,38 +613,74 @@ static struct qcom_icc_node llcc_mc = { .links = { SM8650_SLAVE_EBI1 }, }; +static struct qcom_icc_qosbox qnm_camnoc_hf_qos = { + .num_ports = 2, + .port_offsets = { 0x28000, 0x29000 }, + .prio = 0, + .urg_fwd = 1, + .prio_fwd_disable = 0, +}; + static struct qcom_icc_node qnm_camnoc_hf = { .name = "qnm_camnoc_hf", .id = SM8650_MASTER_CAMNOC_HF, .channels = 2, .buswidth = 32, + .qosbox = &qnm_camnoc_hf_qos, .num_links = 1, .links = { SM8650_SLAVE_MNOC_HF_MEM_NOC }, }; +static struct qcom_icc_qosbox qnm_camnoc_icp_qos = { + .num_ports = 1, + .port_offsets = { 0x2a000 }, + .prio = 4, + .urg_fwd = 1, + .prio_fwd_disable = 0, +}; + static struct qcom_icc_node qnm_camnoc_icp = { .name = "qnm_camnoc_icp", .id = SM8650_MASTER_CAMNOC_ICP, .channels = 1, .buswidth = 8, + .qosbox = &qnm_camnoc_icp_qos, .num_links = 1, .links = { SM8650_SLAVE_MNOC_SF_MEM_NOC }, }; +static struct qcom_icc_qosbox qnm_camnoc_sf_qos = { + .num_ports = 2, + .port_offsets = { 0x2b000, 0x2c000 }, + .prio = 0, + .urg_fwd = 1, + .prio_fwd_disable = 0, +}; + static struct qcom_icc_node qnm_camnoc_sf = { .name = "qnm_camnoc_sf", .id = SM8650_MASTER_CAMNOC_SF, .channels = 2, .buswidth = 32, + .qosbox = &qnm_camnoc_sf_qos, .num_links = 1, .links = { SM8650_SLAVE_MNOC_SF_MEM_NOC }, }; +static struct qcom_icc_qosbox qnm_mdp_qos = { + .num_ports = 2, + .port_offsets = { 0x2d000, 0x2e000 }, + .prio = 0, + .urg_fwd = 1, + .prio_fwd_disable = 0, +}; + static struct qcom_icc_node qnm_mdp = { .name = "qnm_mdp", .id = SM8650_MASTER_MDP, .channels = 2, .buswidth = 32, + .qosbox = &qnm_mdp_qos, .num_links = 1, .links = { SM8650_SLAVE_MNOC_HF_MEM_NOC }, }; @@ -435,38 +694,74 @@ static struct qcom_icc_node qnm_vapss_hcp = { .links = { SM8650_SLAVE_MNOC_SF_MEM_NOC }, }; +static struct qcom_icc_qosbox qnm_video_qos = { + .num_ports = 2, + .port_offsets = { 0x30000, 0x31000 }, + .prio = 0, + .urg_fwd = 1, + .prio_fwd_disable = 0, +}; + static struct qcom_icc_node qnm_video = { .name = "qnm_video", .id = SM8650_MASTER_VIDEO, .channels = 2, .buswidth = 32, + .qosbox = &qnm_video_qos, .num_links = 1, .links = { SM8650_SLAVE_MNOC_SF_MEM_NOC }, }; +static struct qcom_icc_qosbox qnm_video_cv_cpu_qos = { + .num_ports = 1, + .port_offsets = { 0x32000 }, + .prio = 4, + .urg_fwd = 1, + .prio_fwd_disable = 0, +}; + static struct qcom_icc_node qnm_video_cv_cpu = { .name = "qnm_video_cv_cpu", .id = SM8650_MASTER_VIDEO_CV_PROC, .channels = 1, .buswidth = 8, + .qosbox = &qnm_video_cv_cpu_qos, .num_links = 1, .links = { SM8650_SLAVE_MNOC_SF_MEM_NOC }, }; +static struct qcom_icc_qosbox qnm_video_cvp_qos = { + .num_ports = 2, + .port_offsets = { 0x33000, 0x34000 }, + .prio = 0, + .urg_fwd = 1, + .prio_fwd_disable = 0, +}; + static struct qcom_icc_node qnm_video_cvp = { .name = "qnm_video_cvp", .id = SM8650_MASTER_VIDEO_PROC, .channels = 2, .buswidth = 32, + .qosbox = &qnm_video_cvp_qos, .num_links = 1, .links = { SM8650_SLAVE_MNOC_SF_MEM_NOC }, }; +static struct qcom_icc_qosbox qnm_video_v_cpu_qos = { + .num_ports = 1, + .port_offsets = { 0x35000 }, + .prio = 4, + .urg_fwd = 1, + .prio_fwd_disable = 0, +}; + static struct qcom_icc_node qnm_video_v_cpu = { .name = "qnm_video_v_cpu", .id = SM8650_MASTER_VIDEO_V_PROC, .channels = 1, .buswidth = 8, + .qosbox = &qnm_video_v_cpu_qos, .num_links = 1, .links = { SM8650_SLAVE_MNOC_SF_MEM_NOC }, }; @@ -498,20 +793,38 @@ static struct qcom_icc_node qsm_pcie_anoc_cfg = { .links = { SM8650_SLAVE_SERVICE_PCIE_ANOC }, }; +static struct qcom_icc_qosbox xm_pcie3_0_qos = { + .num_ports = 1, + .port_offsets = { 0xb000 }, + .prio = 3, + .urg_fwd = 0, + .prio_fwd_disable = 0, +}; + static struct qcom_icc_node xm_pcie3_0 = { .name = "xm_pcie3_0", .id = SM8650_MASTER_PCIE_0, .channels = 1, .buswidth = 8, + .qosbox = &xm_pcie3_0_qos, .num_links = 1, .links = { SM8650_SLAVE_ANOC_PCIE_GEM_NOC }, }; +static struct qcom_icc_qosbox xm_pcie3_1_qos = { + .num_ports = 1, + .port_offsets = { 0xc000 }, + .prio = 2, + .urg_fwd = 0, + .prio_fwd_disable = 0, +}; + static struct qcom_icc_node xm_pcie3_1 = { .name = "xm_pcie3_1", .id = SM8650_MASTER_PCIE_1, .channels = 1, .buswidth = 16, + .qosbox = &xm_pcie3_1_qos, .num_links = 1, .links = { SM8650_SLAVE_ANOC_PCIE_GEM_NOC }, }; @@ -534,6 +847,24 @@ static struct qcom_icc_node qnm_aggre2_noc = { .links = { SM8650_SLAVE_SNOC_GEM_NOC_SF }, }; +static struct qcom_icc_qosbox qnm_apss_noc_qos = { + .num_ports = 1, + .port_offsets = { 0x1c000 }, + .prio = 2, + .urg_fwd = 0, + .prio_fwd_disable = 1, +}; + +static struct qcom_icc_node qnm_apss_noc = { + .name = "qnm_apss_noc", + .id = SM8650_MASTER_APSS_NOC, + .channels = 1, + .buswidth = 4, + .qosbox = &qnm_apss_noc_qos, + .num_links = 1, + .links = { SM8650_SLAVE_SNOC_GEM_NOC_SF }, +}; + static struct qcom_icc_node qns_a1noc_snoc = { .name = "qns_a1noc_snoc", .id = SM8650_SLAVE_A1NOC_SNOC, @@ -1325,6 +1656,7 @@ static struct qcom_icc_node * const aggre1_noc_nodes[] = { }; static const struct qcom_icc_desc sm8650_aggre1_noc = { + .config = &icc_regmap_config, .nodes = aggre1_noc_nodes, .num_nodes = ARRAY_SIZE(aggre1_noc_nodes), }; @@ -1346,6 +1678,7 @@ static struct qcom_icc_node * const aggre2_noc_nodes[] = { }; static const struct qcom_icc_desc sm8650_aggre2_noc = { + .config = &icc_regmap_config, .nodes = aggre2_noc_nodes, .num_nodes = ARRAY_SIZE(aggre2_noc_nodes), .bcms = aggre2_noc_bcms, @@ -1429,6 +1762,7 @@ static struct qcom_icc_node * const config_noc_nodes[] = { }; static const struct qcom_icc_desc sm8650_config_noc = { + .config = &icc_regmap_config, .nodes = config_noc_nodes, .num_nodes = ARRAY_SIZE(config_noc_nodes), .bcms = config_noc_bcms, @@ -1456,6 +1790,7 @@ static struct qcom_icc_node * const cnoc_main_nodes[] = { }; static const struct qcom_icc_desc sm8650_cnoc_main = { + .config = &icc_regmap_config, .nodes = cnoc_main_nodes, .num_nodes = ARRAY_SIZE(cnoc_main_nodes), .bcms = cnoc_main_bcms, @@ -1488,6 +1823,7 @@ static struct qcom_icc_node * const gem_noc_nodes[] = { }; static const struct qcom_icc_desc sm8650_gem_noc = { + .config = &icc_regmap_config, .nodes = gem_noc_nodes, .num_nodes = ARRAY_SIZE(gem_noc_nodes), .bcms = gem_noc_bcms, @@ -1500,6 +1836,7 @@ static struct qcom_icc_node * const lpass_ag_noc_nodes[] = { }; static const struct qcom_icc_desc sm8650_lpass_ag_noc = { + .config = &icc_regmap_config, .nodes = lpass_ag_noc_nodes, .num_nodes = ARRAY_SIZE(lpass_ag_noc_nodes), }; @@ -1514,6 +1851,7 @@ static struct qcom_icc_node * const lpass_lpiaon_noc_nodes[] = { }; static const struct qcom_icc_desc sm8650_lpass_lpiaon_noc = { + .config = &icc_regmap_config, .nodes = lpass_lpiaon_noc_nodes, .num_nodes = ARRAY_SIZE(lpass_lpiaon_noc_nodes), .bcms = lpass_lpiaon_noc_bcms, @@ -1526,6 +1864,7 @@ static struct qcom_icc_node * const lpass_lpicx_noc_nodes[] = { }; static const struct qcom_icc_desc sm8650_lpass_lpicx_noc = { + .config = &icc_regmap_config, .nodes = lpass_lpicx_noc_nodes, .num_nodes = ARRAY_SIZE(lpass_lpicx_noc_nodes), }; @@ -1569,6 +1908,7 @@ static struct qcom_icc_node * const mmss_noc_nodes[] = { }; static const struct qcom_icc_desc sm8650_mmss_noc = { + .config = &icc_regmap_config, .nodes = mmss_noc_nodes, .num_nodes = ARRAY_SIZE(mmss_noc_nodes), .bcms = mmss_noc_bcms, @@ -1585,6 +1925,7 @@ static struct qcom_icc_node * const nsp_noc_nodes[] = { }; static const struct qcom_icc_desc sm8650_nsp_noc = { + .config = &icc_regmap_config, .nodes = nsp_noc_nodes, .num_nodes = ARRAY_SIZE(nsp_noc_nodes), .bcms = nsp_noc_bcms, @@ -1604,6 +1945,7 @@ static struct qcom_icc_node * const pcie_anoc_nodes[] = { }; static const struct qcom_icc_desc sm8650_pcie_anoc = { + .config = &icc_regmap_config, .nodes = pcie_anoc_nodes, .num_nodes = ARRAY_SIZE(pcie_anoc_nodes), .bcms = pcie_anoc_bcms, @@ -1620,9 +1962,11 @@ static struct qcom_icc_node * const system_noc_nodes[] = { [MASTER_A1NOC_SNOC] = &qnm_aggre1_noc, [MASTER_A2NOC_SNOC] = &qnm_aggre2_noc, [SLAVE_SNOC_GEM_NOC_SF] = &qns_gemnoc_sf, + [MASTER_APSS_NOC] = &qnm_apss_noc, }; static const struct qcom_icc_desc sm8650_system_noc = { + .config = &icc_regmap_config, .nodes = system_noc_nodes, .num_nodes = ARRAY_SIZE(system_noc_nodes), .bcms = system_noc_bcms, diff --git a/drivers/interconnect/qcom/sm8650.h b/drivers/interconnect/qcom/sm8650.h index de35c956fe49..b6610225b38a 100644 --- a/drivers/interconnect/qcom/sm8650.h +++ b/drivers/interconnect/qcom/sm8650.h @@ -139,5 +139,6 @@ #define SM8650_SLAVE_USB3_0 127 #define SM8650_SLAVE_VENUS_CFG 128 #define SM8650_SLAVE_VSENSE_CTRL_CFG 129 +#define SM8650_MASTER_APSS_NOC 130 #endif diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c index 6c708fec48d1..ea2ef53bd4fe 100644 --- a/drivers/iommu/dma-iommu.c +++ b/drivers/iommu/dma-iommu.c @@ -179,7 +179,8 @@ static void fq_flush_iotlb(struct iommu_dma_cookie *cookie) static void fq_flush_timeout(struct timer_list *t) { - struct iommu_dma_cookie *cookie = from_timer(cookie, t, fq_timer); + struct iommu_dma_cookie *cookie = timer_container_of(cookie, t, + fq_timer); int cpu; atomic_set(&cookie->fq_timer_on, 0); diff --git a/drivers/isdn/hardware/mISDN/hfcpci.c b/drivers/isdn/hardware/mISDN/hfcpci.c index e3870d942699..2b05722d4dbe 100644 --- a/drivers/isdn/hardware/mISDN/hfcpci.c +++ b/drivers/isdn/hardware/mISDN/hfcpci.c @@ -291,7 +291,7 @@ reset_hfcpci(struct hfc_pci *hc) static void hfcpci_Timer(struct timer_list *t) { - struct hfc_pci *hc = from_timer(hc, t, hw.timer); + struct hfc_pci *hc = timer_container_of(hc, t, hw.timer); hc->hw.timer.expires = jiffies + 75; /* WD RESET */ /* diff --git a/drivers/isdn/hardware/mISDN/mISDNipac.c b/drivers/isdn/hardware/mISDN/mISDNipac.c index 165a63994f04..a34ea6058960 100644 --- a/drivers/isdn/hardware/mISDN/mISDNipac.c +++ b/drivers/isdn/hardware/mISDN/mISDNipac.c @@ -713,7 +713,7 @@ isac_release(struct isac_hw *isac) static void dbusy_timer_handler(struct timer_list *t) { - struct isac_hw *isac = from_timer(isac, t, dch.timer); + struct isac_hw *isac = timer_container_of(isac, t, dch.timer); int rbch, star; u_long flags; diff --git a/drivers/isdn/hardware/mISDN/mISDNisar.c b/drivers/isdn/hardware/mISDN/mISDNisar.c index e48f89cbecf8..dace91ba412b 100644 --- a/drivers/isdn/hardware/mISDN/mISDNisar.c +++ b/drivers/isdn/hardware/mISDN/mISDNisar.c @@ -1135,7 +1135,7 @@ EXPORT_SYMBOL(mISDNisar_irq); static void ftimer_handler(struct timer_list *t) { - struct isar_ch *ch = from_timer(ch, t, ftimer); + struct isar_ch *ch = timer_container_of(ch, t, ftimer); pr_debug("%s: ftimer flags %lx\n", ch->is->name, ch->bch.Flags); test_and_clear_bit(FLG_FTI_RUN, &ch->bch.Flags); diff --git a/drivers/isdn/hardware/mISDN/w6692.c b/drivers/isdn/hardware/mISDN/w6692.c index da933f4bdf4e..168fc345dcdc 100644 --- a/drivers/isdn/hardware/mISDN/w6692.c +++ b/drivers/isdn/hardware/mISDN/w6692.c @@ -802,7 +802,7 @@ w6692_irq(int intno, void *dev_id) static void dbusy_timer_handler(struct timer_list *t) { - struct dchannel *dch = from_timer(dch, t, timer); + struct dchannel *dch = timer_container_of(dch, t, timer); struct w6692_hw *card = dch->hw; int rbch, star; u_long flags; diff --git a/drivers/isdn/mISDN/dsp_tones.c b/drivers/isdn/mISDN/dsp_tones.c index 456b313bfa76..fa7813ae8d97 100644 --- a/drivers/isdn/mISDN/dsp_tones.c +++ b/drivers/isdn/mISDN/dsp_tones.c @@ -459,7 +459,7 @@ dsp_tone_hw_message(struct dsp *dsp, u8 *sample, int len) void dsp_tone_timeout(struct timer_list *t) { - struct dsp *dsp = from_timer(dsp, t, tone.tl); + struct dsp *dsp = timer_container_of(dsp, t, tone.tl); struct dsp_tone *tone = &dsp->tone; struct pattern *pat = (struct pattern *)tone->pattern; int index = tone->index; diff --git a/drivers/isdn/mISDN/fsm.c b/drivers/isdn/mISDN/fsm.c index 5ed0a6110687..825b686496d2 100644 --- a/drivers/isdn/mISDN/fsm.c +++ b/drivers/isdn/mISDN/fsm.c @@ -95,7 +95,7 @@ EXPORT_SYMBOL(mISDN_FsmChangeState); static void FsmExpireTimer(struct timer_list *t) { - struct FsmTimer *ft = from_timer(ft, t, tl); + struct FsmTimer *ft = timer_container_of(ft, t, tl); #if FSM_TIMER_DEBUG if (ft->fi->debug) ft->fi->printdebug(ft->fi, "FsmExpireTimer %lx", (long) ft); diff --git a/drivers/isdn/mISDN/l1oip_core.c b/drivers/isdn/mISDN/l1oip_core.c index a5ad88a960d0..f732f6614d37 100644 --- a/drivers/isdn/mISDN/l1oip_core.c +++ b/drivers/isdn/mISDN/l1oip_core.c @@ -822,7 +822,7 @@ l1oip_send_bh(struct work_struct *work) static void l1oip_keepalive(struct timer_list *t) { - struct l1oip *hc = from_timer(hc, t, keep_tl); + struct l1oip *hc = timer_container_of(hc, t, keep_tl); schedule_work(&hc->workq); } @@ -830,8 +830,8 @@ l1oip_keepalive(struct timer_list *t) static void l1oip_timeout(struct timer_list *t) { - struct l1oip *hc = from_timer(hc, t, - timeout_tl); + struct l1oip *hc = timer_container_of(hc, t, + timeout_tl); struct dchannel *dch = hc->chan[hc->d_idx].dch; if (debug & DEBUG_L1OIP_MSG) diff --git a/drivers/isdn/mISDN/timerdev.c b/drivers/isdn/mISDN/timerdev.c index 7cfa8c61dba0..df98144a9539 100644 --- a/drivers/isdn/mISDN/timerdev.c +++ b/drivers/isdn/mISDN/timerdev.c @@ -155,7 +155,7 @@ mISDN_poll(struct file *filep, poll_table *wait) static void dev_expire_timer(struct timer_list *t) { - struct mISDNtimer *timer = from_timer(timer, t, tl); + struct mISDNtimer *timer = timer_container_of(timer, t, tl); u_long flags; spin_lock_irqsave(&timer->dev->lock, flags); diff --git a/drivers/leds/flash/leds-rt8515.c b/drivers/leds/flash/leds-rt8515.c index 32ba397a33d2..6af0d2c7fc56 100644 --- a/drivers/leds/flash/leds-rt8515.c +++ b/drivers/leds/flash/leds-rt8515.c @@ -165,7 +165,7 @@ static const struct led_flash_ops rt8515_flash_ops = { static void rt8515_powerdown_timer(struct timer_list *t) { - struct rt8515 *rt = from_timer(rt, t, powerdown_timer); + struct rt8515 *rt = timer_container_of(rt, t, powerdown_timer); /* Turn the LED off */ rt8515_gpio_led_off(rt); diff --git a/drivers/leds/flash/leds-sgm3140.c b/drivers/leds/flash/leds-sgm3140.c index 48fb8a9ec703..3e83200675f2 100644 --- a/drivers/leds/flash/leds-sgm3140.c +++ b/drivers/leds/flash/leds-sgm3140.c @@ -135,7 +135,7 @@ static int sgm3140_brightness_set(struct led_classdev *led_cdev, static void sgm3140_powerdown_timer(struct timer_list *t) { - struct sgm3140 *priv = from_timer(priv, t, powerdown_timer); + struct sgm3140 *priv = timer_container_of(priv, t, powerdown_timer); gpiod_set_value(priv->enable_gpio, 0); gpiod_set_value(priv->flash_gpio, 0); diff --git a/drivers/leds/led-core.c b/drivers/leds/led-core.c index 1a59a4f38479..59473f286b31 100644 --- a/drivers/leds/led-core.c +++ b/drivers/leds/led-core.c @@ -64,7 +64,8 @@ static int __led_set_brightness_blocking(struct led_classdev *led_cdev, unsigned static void led_timer_function(struct timer_list *t) { - struct led_classdev *led_cdev = from_timer(led_cdev, t, blink_timer); + struct led_classdev *led_cdev = timer_container_of(led_cdev, t, + blink_timer); unsigned long brightness; unsigned long delay; diff --git a/drivers/leds/trigger/ledtrig-activity.c b/drivers/leds/trigger/ledtrig-activity.c index b3ee33aed36e..c973246a57f9 100644 --- a/drivers/leds/trigger/ledtrig-activity.c +++ b/drivers/leds/trigger/ledtrig-activity.c @@ -32,8 +32,8 @@ struct activity_data { static void led_activity_function(struct timer_list *t) { - struct activity_data *activity_data = from_timer(activity_data, t, - timer); + struct activity_data *activity_data = timer_container_of(activity_data, + t, timer); struct led_classdev *led_cdev = activity_data->led_cdev; unsigned int target; unsigned int usage; diff --git a/drivers/leds/trigger/ledtrig-heartbeat.c b/drivers/leds/trigger/ledtrig-heartbeat.c index 393b3ae832f4..40eb61b6d54e 100644 --- a/drivers/leds/trigger/ledtrig-heartbeat.c +++ b/drivers/leds/trigger/ledtrig-heartbeat.c @@ -33,7 +33,7 @@ struct heartbeat_trig_data { static void led_heartbeat_function(struct timer_list *t) { struct heartbeat_trig_data *heartbeat_data = - from_timer(heartbeat_data, t, timer); + timer_container_of(heartbeat_data, t, timer); struct led_classdev *led_cdev; unsigned long brightness = LED_OFF; unsigned long delay = 0; diff --git a/drivers/leds/trigger/ledtrig-pattern.c b/drivers/leds/trigger/ledtrig-pattern.c index 06d052957d37..9af3c18f14f4 100644 --- a/drivers/leds/trigger/ledtrig-pattern.c +++ b/drivers/leds/trigger/ledtrig-pattern.c @@ -150,7 +150,7 @@ static void pattern_trig_timer_common_function(struct pattern_trig_data *data) static void pattern_trig_timer_function(struct timer_list *t) { - struct pattern_trig_data *data = from_timer(data, t, timer); + struct pattern_trig_data *data = timer_container_of(data, t, timer); return pattern_trig_timer_common_function(data); } diff --git a/drivers/leds/trigger/ledtrig-transient.c b/drivers/leds/trigger/ledtrig-transient.c index e103c7ed830b..20f1351464b1 100644 --- a/drivers/leds/trigger/ledtrig-transient.c +++ b/drivers/leds/trigger/ledtrig-transient.c @@ -32,7 +32,7 @@ struct transient_trig_data { static void transient_timer_function(struct timer_list *t) { struct transient_trig_data *transient_data = - from_timer(transient_data, t, timer); + timer_container_of(transient_data, t, timer); struct led_classdev *led_cdev = transient_data->led_cdev; transient_data->activate = 0; diff --git a/drivers/mailbox/mailbox-altera.c b/drivers/mailbox/mailbox-altera.c index 748128661892..17278c2571d3 100644 --- a/drivers/mailbox/mailbox-altera.c +++ b/drivers/mailbox/mailbox-altera.c @@ -130,7 +130,7 @@ static void altera_mbox_rx_data(struct mbox_chan *chan) static void altera_mbox_poll_rx(struct timer_list *t) { - struct altera_mbox *mbox = from_timer(mbox, t, rxpoll_timer); + struct altera_mbox *mbox = timer_container_of(mbox, t, rxpoll_timer); altera_mbox_rx_data(mbox->chan); diff --git a/drivers/md/bcache/btree.c b/drivers/md/bcache/btree.c index 2cc2eb24dc8a..1d0100677357 100644 --- a/drivers/md/bcache/btree.c +++ b/drivers/md/bcache/btree.c @@ -89,8 +89,6 @@ * Test module load/unload */ -#define MAX_NEED_GC 64 -#define MAX_SAVE_PRIO 72 #define MAX_GC_TIMES 100 #define MIN_GC_NODES 100 #define GC_SLEEP_MS 100 diff --git a/drivers/md/bcache/stats.c b/drivers/md/bcache/stats.c index d39dec34b7a3..0056106495a7 100644 --- a/drivers/md/bcache/stats.c +++ b/drivers/md/bcache/stats.c @@ -149,7 +149,7 @@ static void scale_stats(struct cache_stats *stats, unsigned long rescale_at) static void scale_accounting(struct timer_list *t) { - struct cache_accounting *acc = from_timer(acc, t, timer); + struct cache_accounting *acc = timer_container_of(acc, t, timer); #define move_stat(name) do { \ unsigned int t = atomic_xchg(&acc->collector.name, 0); \ diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c index 1a2ce1a4b456..1efb768b2890 100644 --- a/drivers/md/bcache/super.c +++ b/drivers/md/bcache/super.c @@ -1733,7 +1733,12 @@ static CLOSURE_CALLBACK(cache_set_flush) mutex_unlock(&b->write_lock); } - if (ca->alloc_thread) + /* + * If the register_cache_set() call to bch_cache_set_alloc() failed, + * ca has not been assigned a value and return error. + * So we need check ca is not NULL during bch_cache_set_unregister(). + */ + if (ca && ca->alloc_thread) kthread_stop(ca->alloc_thread); if (c->journal.cur) { @@ -2233,15 +2238,47 @@ static int cache_alloc(struct cache *ca) bio_init(&ca->journal.bio, NULL, ca->journal.bio.bi_inline_vecs, 8, 0); /* - * when ca->sb.njournal_buckets is not zero, journal exists, - * and in bch_journal_replay(), tree node may split, - * so bucket of RESERVE_BTREE type is needed, - * the worst situation is all journal buckets are valid journal, - * and all the keys need to replay, - * so the number of RESERVE_BTREE type buckets should be as much - * as journal buckets + * When the cache disk is first registered, ca->sb.njournal_buckets + * is zero, and it is assigned in run_cache_set(). + * + * When ca->sb.njournal_buckets is not zero, journal exists, + * and in bch_journal_replay(), tree node may split. + * The worst situation is all journal buckets are valid journal, + * and all the keys need to replay, so the number of RESERVE_BTREE + * type buckets should be as much as journal buckets. + * + * If the number of RESERVE_BTREE type buckets is too few, the + * bch_allocator_thread() may hang up and unable to allocate + * bucket. The situation is roughly as follows: + * + * 1. In bch_data_insert_keys(), if the operation is not op->replace, + * it will call the bch_journal(), which increments the journal_ref + * counter. This counter is only decremented after bch_btree_insert + * completes. + * + * 2. When calling bch_btree_insert, if the btree needs to split, + * it will call btree_split() and btree_check_reserve() to check + * whether there are enough reserved buckets in the RESERVE_BTREE + * slot. If not enough, bcache_btree_root() will repeatedly retry. + * + * 3. Normally, the bch_allocator_thread is responsible for filling + * the reservation slots from the free_inc bucket list. When the + * free_inc bucket list is exhausted, the bch_allocator_thread + * will call invalidate_buckets() until free_inc is refilled. + * Then bch_allocator_thread calls bch_prio_write() once. and + * bch_prio_write() will call bch_journal_meta() and waits for + * the journal write to complete. + * + * 4. During journal_write, journal_write_unlocked() is be called. + * If journal full occurs, journal_reclaim() and btree_flush_write() + * will be called sequentially, then retry journal_write. + * + * 5. When 2 and 4 occur together, IO will hung up and cannot recover. + * + * Therefore, reserve more RESERVE_BTREE type buckets. */ - btree_buckets = ca->sb.njournal_buckets ?: 8; + btree_buckets = clamp_t(size_t, ca->sb.nbuckets >> 7, + 32, SB_JOURNAL_BUCKETS); free = roundup_pow_of_two(ca->sb.nbuckets) >> 10; if (!free) { ret = -EPERM; diff --git a/drivers/md/dm-delay.c b/drivers/md/dm-delay.c index 16d3d454fb0a..4bb6553278c7 100644 --- a/drivers/md/dm-delay.c +++ b/drivers/md/dm-delay.c @@ -56,7 +56,7 @@ struct dm_delay_info { static void handle_delayed_timer(struct timer_list *t) { - struct delay_c *dc = from_timer(dc, t, delay_timer); + struct delay_c *dc = timer_container_of(dc, t, delay_timer); queue_work(dc->kdelayd_wq, &dc->flush_expired_bios); } diff --git a/drivers/md/dm-integrity.c b/drivers/md/dm-integrity.c index 1f626066e8cc..4395657fa583 100644 --- a/drivers/md/dm-integrity.c +++ b/drivers/md/dm-integrity.c @@ -1540,7 +1540,8 @@ static void sleep_on_endio_wait(struct dm_integrity_c *ic) static void autocommit_fn(struct timer_list *t) { - struct dm_integrity_c *ic = from_timer(ic, t, autocommit_timer); + struct dm_integrity_c *ic = timer_container_of(ic, t, + autocommit_timer); if (likely(!dm_integrity_failed(ic))) queue_work(ic->commit_wq, &ic->commit_work); diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c index 81fec2e1e0ef..aaf4a0a4b0eb 100644 --- a/drivers/md/dm-mpath.c +++ b/drivers/md/dm-mpath.c @@ -790,7 +790,7 @@ static int queue_if_no_path(struct multipath *m, bool f_queue_if_no_path, */ static void queue_if_no_path_timeout_work(struct timer_list *t) { - struct multipath *m = from_timer(m, t, nopath_timer); + struct multipath *m = timer_container_of(m, t, nopath_timer); DMWARN("queue_if_no_path timeout on %s, failing queued IO", dm_table_device_name(m->ti->table)); diff --git a/drivers/md/dm-raid.c b/drivers/md/dm-raid.c index 127138c61be5..d296770478b2 100644 --- a/drivers/md/dm-raid.c +++ b/drivers/md/dm-raid.c @@ -1356,11 +1356,7 @@ static int parse_raid_params(struct raid_set *rs, struct dm_arg_set *as, return -EINVAL; } - /* - * In device-mapper, we specify things in sectors, but - * MD records this value in kB - */ - if (value < 0 || value / 2 > COUNTER_MAX) { + if (value < 0) { rs->ti->error = "Max write-behind limit out of range"; return -EINVAL; } diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c index 785af4816584..268f734ca9c3 100644 --- a/drivers/md/dm-raid1.c +++ b/drivers/md/dm-raid1.c @@ -103,7 +103,7 @@ static void wakeup_mirrord(void *context) static void delayed_wake_fn(struct timer_list *t) { - struct mirror_set *ms = from_timer(ms, t, timer); + struct mirror_set *ms = timer_container_of(ms, t, timer); clear_bit(0, &ms->timer_pending); wakeup_mirrord(ms); diff --git a/drivers/md/dm-vdo/dedupe.c b/drivers/md/dm-vdo/dedupe.c index 3c58b941e067..4d983092a152 100644 --- a/drivers/md/dm-vdo/dedupe.c +++ b/drivers/md/dm-vdo/dedupe.c @@ -2337,7 +2337,7 @@ static void timeout_index_operations_callback(struct vdo_completion *completion) static void timeout_index_operations(struct timer_list *t) { - struct hash_zone *zone = from_timer(zone, t, timer); + struct hash_zone *zone = timer_container_of(zone, t, timer); if (change_timer_state(zone, DEDUPE_QUERY_TIMER_RUNNING, DEDUPE_QUERY_TIMER_FIRED)) diff --git a/drivers/md/dm-writecache.c b/drivers/md/dm-writecache.c index d6a04a57472d..a428e1cacf07 100644 --- a/drivers/md/dm-writecache.c +++ b/drivers/md/dm-writecache.c @@ -706,7 +706,7 @@ static inline void writecache_verify_watermark(struct dm_writecache *wc) static void writecache_max_age_timer(struct timer_list *t) { - struct dm_writecache *wc = from_timer(wc, t, max_age_timer); + struct dm_writecache *wc = timer_container_of(wc, t, max_age_timer); if (!dm_suspended(wc->ti) && !writecache_has_error(wc)) { queue_work(wc->writeback_wq, &wc->writeback_work); @@ -866,7 +866,7 @@ static void writecache_flush_work(struct work_struct *work) static void writecache_autocommit_timer(struct timer_list *t) { - struct dm_writecache *wc = from_timer(wc, t, autocommit_timer); + struct dm_writecache *wc = timer_container_of(wc, t, autocommit_timer); if (!writecache_has_error(wc)) queue_work(wc->writeback_wq, &wc->flush_work); diff --git a/drivers/md/md-bitmap.c b/drivers/md/md-bitmap.c index 37b08f26c62f..bd694910b01b 100644 --- a/drivers/md/md-bitmap.c +++ b/drivers/md/md-bitmap.c @@ -105,9 +105,19 @@ * */ +typedef __u16 bitmap_counter_t; + #define PAGE_BITS (PAGE_SIZE << 3) #define PAGE_BIT_SHIFT (PAGE_SHIFT + 3) +#define COUNTER_BITS 16 +#define COUNTER_BIT_SHIFT 4 +#define COUNTER_BYTE_SHIFT (COUNTER_BIT_SHIFT - 3) + +#define NEEDED_MASK ((bitmap_counter_t) (1 << (COUNTER_BITS - 1))) +#define RESYNC_MASK ((bitmap_counter_t) (1 << (COUNTER_BITS - 2))) +#define COUNTER_MAX ((bitmap_counter_t) RESYNC_MASK - 1) + #define NEEDED(x) (((bitmap_counter_t) x) & NEEDED_MASK) #define RESYNC(x) (((bitmap_counter_t) x) & RESYNC_MASK) #define COUNTER(x) (((bitmap_counter_t) x) & COUNTER_MAX) @@ -789,7 +799,7 @@ static int md_bitmap_new_disk_sb(struct bitmap *bitmap) * is a good choice? We choose COUNTER_MAX / 2 arbitrarily. */ write_behind = bitmap->mddev->bitmap_info.max_write_behind; - if (write_behind > COUNTER_MAX) + if (write_behind > COUNTER_MAX / 2) write_behind = COUNTER_MAX / 2; sb->write_behind = cpu_to_le32(write_behind); bitmap->mddev->bitmap_info.max_write_behind = write_behind; @@ -1672,13 +1682,13 @@ __acquires(bitmap->lock) &(bitmap->bp[page].map[pageoff]); } -static int bitmap_startwrite(struct mddev *mddev, sector_t offset, - unsigned long sectors) +static void bitmap_start_write(struct mddev *mddev, sector_t offset, + unsigned long sectors) { struct bitmap *bitmap = mddev->bitmap; if (!bitmap) - return 0; + return; while (sectors) { sector_t blocks; @@ -1688,7 +1698,7 @@ static int bitmap_startwrite(struct mddev *mddev, sector_t offset, bmc = md_bitmap_get_counter(&bitmap->counts, offset, &blocks, 1); if (!bmc) { spin_unlock_irq(&bitmap->counts.lock); - return 0; + return; } if (unlikely(COUNTER(*bmc) == COUNTER_MAX)) { @@ -1724,11 +1734,10 @@ static int bitmap_startwrite(struct mddev *mddev, sector_t offset, else sectors = 0; } - return 0; } -static void bitmap_endwrite(struct mddev *mddev, sector_t offset, - unsigned long sectors) +static void bitmap_end_write(struct mddev *mddev, sector_t offset, + unsigned long sectors) { struct bitmap *bitmap = mddev->bitmap; @@ -2205,9 +2214,9 @@ static struct bitmap *__bitmap_create(struct mddev *mddev, int slot) return ERR_PTR(err); } -static int bitmap_create(struct mddev *mddev, int slot) +static int bitmap_create(struct mddev *mddev) { - struct bitmap *bitmap = __bitmap_create(mddev, slot); + struct bitmap *bitmap = __bitmap_create(mddev, -1); if (IS_ERR(bitmap)) return PTR_ERR(bitmap); @@ -2670,7 +2679,7 @@ location_store(struct mddev *mddev, const char *buf, size_t len) } mddev->bitmap_info.offset = offset; - rv = bitmap_create(mddev, -1); + rv = bitmap_create(mddev); if (rv) goto out; @@ -3003,8 +3012,8 @@ static struct bitmap_operations bitmap_ops = { .end_behind_write = bitmap_end_behind_write, .wait_behind_writes = bitmap_wait_behind_writes, - .startwrite = bitmap_startwrite, - .endwrite = bitmap_endwrite, + .start_write = bitmap_start_write, + .end_write = bitmap_end_write, .start_sync = bitmap_start_sync, .end_sync = bitmap_end_sync, .cond_end_sync = bitmap_cond_end_sync, diff --git a/drivers/md/md-bitmap.h b/drivers/md/md-bitmap.h index 31c93019c76b..59e9dd45cfde 100644 --- a/drivers/md/md-bitmap.h +++ b/drivers/md/md-bitmap.h @@ -9,15 +9,6 @@ #define BITMAP_MAGIC 0x6d746962 -typedef __u16 bitmap_counter_t; -#define COUNTER_BITS 16 -#define COUNTER_BIT_SHIFT 4 -#define COUNTER_BYTE_SHIFT (COUNTER_BIT_SHIFT - 3) - -#define NEEDED_MASK ((bitmap_counter_t) (1 << (COUNTER_BITS - 1))) -#define RESYNC_MASK ((bitmap_counter_t) (1 << (COUNTER_BITS - 2))) -#define COUNTER_MAX ((bitmap_counter_t) RESYNC_MASK - 1) - /* use these for bitmap->flags and bitmap->sb->state bit-fields */ enum bitmap_state { BITMAP_STALE = 1, /* the bitmap file is out of date or had -EIO */ @@ -72,7 +63,7 @@ struct md_bitmap_stats { struct bitmap_operations { bool (*enabled)(struct mddev *mddev); - int (*create)(struct mddev *mddev, int slot); + int (*create)(struct mddev *mddev); int (*resize)(struct mddev *mddev, sector_t blocks, int chunksize, bool init); @@ -89,10 +80,10 @@ struct bitmap_operations { void (*end_behind_write)(struct mddev *mddev); void (*wait_behind_writes)(struct mddev *mddev); - int (*startwrite)(struct mddev *mddev, sector_t offset, + void (*start_write)(struct mddev *mddev, sector_t offset, + unsigned long sectors); + void (*end_write)(struct mddev *mddev, sector_t offset, unsigned long sectors); - void (*endwrite)(struct mddev *mddev, sector_t offset, - unsigned long sectors); bool (*start_sync)(struct mddev *mddev, sector_t offset, sector_t *blocks, bool degraded); void (*end_sync)(struct mddev *mddev, sector_t offset, sector_t *blocks); diff --git a/drivers/md/md.c b/drivers/md/md.c index 0fde115e921f..0f03b21e66e4 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -6048,7 +6048,7 @@ static int add_named_array(const char *val, const struct kernel_param *kp) static void md_safemode_timeout(struct timer_list *t) { - struct mddev *mddev = from_timer(mddev, t, safemode_timer); + struct mddev *mddev = timer_container_of(mddev, t, safemode_timer); mddev->safemode = 1; if (mddev->external) @@ -6225,7 +6225,7 @@ int md_run(struct mddev *mddev) } if (err == 0 && pers->sync_request && (mddev->bitmap_info.file || mddev->bitmap_info.offset)) { - err = mddev->bitmap_ops->create(mddev, -1); + err = mddev->bitmap_ops->create(mddev); if (err) pr_warn("%s: failed to create bitmap (%d)\n", mdname(mddev), err); @@ -7285,7 +7285,7 @@ static int set_bitmap_file(struct mddev *mddev, int fd) err = 0; if (mddev->pers) { if (fd >= 0) { - err = mddev->bitmap_ops->create(mddev, -1); + err = mddev->bitmap_ops->create(mddev); if (!err) err = mddev->bitmap_ops->load(mddev); @@ -7601,7 +7601,7 @@ static int update_array_info(struct mddev *mddev, mdu_array_info_t *info) mddev->bitmap_info.default_offset; mddev->bitmap_info.space = mddev->bitmap_info.default_space; - rv = mddev->bitmap_ops->create(mddev, -1); + rv = mddev->bitmap_ops->create(mddev); if (!rv) rv = mddev->bitmap_ops->load(mddev); @@ -8799,14 +8799,14 @@ static void md_bitmap_start(struct mddev *mddev, mddev->pers->bitmap_sector(mddev, &md_io_clone->offset, &md_io_clone->sectors); - mddev->bitmap_ops->startwrite(mddev, md_io_clone->offset, - md_io_clone->sectors); + mddev->bitmap_ops->start_write(mddev, md_io_clone->offset, + md_io_clone->sectors); } static void md_bitmap_end(struct mddev *mddev, struct md_io_clone *md_io_clone) { - mddev->bitmap_ops->endwrite(mddev, md_io_clone->offset, - md_io_clone->sectors); + mddev->bitmap_ops->end_write(mddev, md_io_clone->offset, + md_io_clone->sectors); } static void md_end_clone_io(struct bio *bio) diff --git a/drivers/md/raid1-10.c b/drivers/md/raid1-10.c index c7efd8aab675..b8b3a9069701 100644 --- a/drivers/md/raid1-10.c +++ b/drivers/md/raid1-10.c @@ -293,3 +293,13 @@ static inline bool raid1_should_read_first(struct mddev *mddev, return false; } + +/* + * bio with REQ_RAHEAD or REQ_NOWAIT can fail at anytime, before such IO is + * submitted to the underlying disks, hence don't record badblocks or retry + * in this case. + */ +static inline bool raid1_should_handle_error(struct bio *bio) +{ + return !(bio->bi_opf & (REQ_RAHEAD | REQ_NOWAIT)); +} diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 657d481525be..19c5a0ce5a40 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -373,14 +373,16 @@ static void raid1_end_read_request(struct bio *bio) */ update_head_pos(r1_bio->read_disk, r1_bio); - if (uptodate) + if (uptodate) { set_bit(R1BIO_Uptodate, &r1_bio->state); - else if (test_bit(FailFast, &rdev->flags) && - test_bit(R1BIO_FailFast, &r1_bio->state)) + } else if (test_bit(FailFast, &rdev->flags) && + test_bit(R1BIO_FailFast, &r1_bio->state)) { /* This was a fail-fast read so we definitely * want to retry */ ; - else { + } else if (!raid1_should_handle_error(bio)) { + uptodate = 1; + } else { /* If all other devices have failed, we want to return * the error upwards rather than fail the last device. * Here we redefine "uptodate" to mean "Don't want to retry" @@ -451,16 +453,15 @@ static void raid1_end_write_request(struct bio *bio) struct bio *to_put = NULL; int mirror = find_bio_disk(r1_bio, bio); struct md_rdev *rdev = conf->mirrors[mirror].rdev; - bool discard_error; sector_t lo = r1_bio->sector; sector_t hi = r1_bio->sector + r1_bio->sectors; - - discard_error = bio->bi_status && bio_op(bio) == REQ_OP_DISCARD; + bool ignore_error = !raid1_should_handle_error(bio) || + (bio->bi_status && bio_op(bio) == REQ_OP_DISCARD); /* * 'one mirror IO has finished' event handler: */ - if (bio->bi_status && !discard_error) { + if (bio->bi_status && !ignore_error) { set_bit(WriteErrorSeen, &rdev->flags); if (!test_and_set_bit(WantReplacement, &rdev->flags)) set_bit(MD_RECOVERY_NEEDED, & @@ -511,7 +512,7 @@ static void raid1_end_write_request(struct bio *bio) /* Maybe we can clear some bad blocks. */ if (rdev_has_badblock(rdev, r1_bio->sector, r1_bio->sectors) && - !discard_error) { + !ignore_error) { r1_bio->bios[mirror] = IO_MADE_GOOD; set_bit(R1BIO_MadeGood, &r1_bio->state); } diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index dce06bf65016..b74780af4c22 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -399,6 +399,8 @@ static void raid10_end_read_request(struct bio *bio) * wait for the 'master' bio. */ set_bit(R10BIO_Uptodate, &r10_bio->state); + } else if (!raid1_should_handle_error(bio)) { + uptodate = 1; } else { /* If all other devices that store this block have * failed, we want to return the error upwards rather @@ -456,9 +458,8 @@ static void raid10_end_write_request(struct bio *bio) int slot, repl; struct md_rdev *rdev = NULL; struct bio *to_put = NULL; - bool discard_error; - - discard_error = bio->bi_status && bio_op(bio) == REQ_OP_DISCARD; + bool ignore_error = !raid1_should_handle_error(bio) || + (bio->bi_status && bio_op(bio) == REQ_OP_DISCARD); dev = find_bio_disk(conf, r10_bio, bio, &slot, &repl); @@ -472,7 +473,7 @@ static void raid10_end_write_request(struct bio *bio) /* * this branch is our 'one mirror IO has finished' event handler: */ - if (bio->bi_status && !discard_error) { + if (bio->bi_status && !ignore_error) { if (repl) /* Never record new bad blocks to replacement, * just fail it. @@ -527,7 +528,7 @@ static void raid10_end_write_request(struct bio *bio) /* Maybe we can clear some bad blocks. */ if (rdev_has_badblock(rdev, r10_bio->devs[slot].addr, r10_bio->sectors) && - !discard_error) { + !ignore_error) { bio_put(bio); if (repl) r10_bio->devs[slot].repl_bio = IO_MADE_GOOD; diff --git a/drivers/media/common/saa7146/saa7146_fops.c b/drivers/media/common/saa7146/saa7146_fops.c index 2952678cce45..9d0362a75ecd 100644 --- a/drivers/media/common/saa7146/saa7146_fops.c +++ b/drivers/media/common/saa7146/saa7146_fops.c @@ -153,7 +153,7 @@ void saa7146_buffer_next(struct saa7146_dev *dev, void saa7146_buffer_timeout(struct timer_list *t) { - struct saa7146_dmaqueue *q = from_timer(q, t, timeout); + struct saa7146_dmaqueue *q = timer_container_of(q, t, timeout); struct saa7146_dev *dev = q->dev; unsigned long flags; diff --git a/drivers/media/common/saa7146/saa7146_vbi.c b/drivers/media/common/saa7146/saa7146_vbi.c index 6c324a683be9..1ffcc025d1a4 100644 --- a/drivers/media/common/saa7146/saa7146_vbi.c +++ b/drivers/media/common/saa7146/saa7146_vbi.c @@ -330,7 +330,7 @@ static void vbi_stop(struct saa7146_dev *dev) static void vbi_read_timeout(struct timer_list *t) { - struct saa7146_vv *vv = from_timer(vv, t, vbi_read_timeout); + struct saa7146_vv *vv = timer_container_of(vv, t, vbi_read_timeout); struct saa7146_dev *dev = vv->vbi_dmaq.dev; DEB_VBI("dev:%p\n", dev); diff --git a/drivers/media/dvb-core/dmxdev.c b/drivers/media/dvb-core/dmxdev.c index 1e985f943944..151177e5a06d 100644 --- a/drivers/media/dvb-core/dmxdev.c +++ b/drivers/media/dvb-core/dmxdev.c @@ -352,7 +352,8 @@ static int dvb_dmxdev_set_buffer_size(struct dmxdev_filter *dmxdevfilter, static void dvb_dmxdev_filter_timeout(struct timer_list *t) { - struct dmxdev_filter *dmxdevfilter = from_timer(dmxdevfilter, t, timer); + struct dmxdev_filter *dmxdevfilter = timer_container_of(dmxdevfilter, + t, timer); dmxdevfilter->buffer.error = -ETIMEDOUT; spin_lock_irq(&dmxdevfilter->dev->lock); diff --git a/drivers/media/i2c/tc358743.c b/drivers/media/i2c/tc358743.c index dcef93e1a3bc..3d6703b75bfa 100644 --- a/drivers/media/i2c/tc358743.c +++ b/drivers/media/i2c/tc358743.c @@ -1505,7 +1505,7 @@ static irqreturn_t tc358743_irq_handler(int irq, void *dev_id) static void tc358743_irq_poll_timer(struct timer_list *t) { - struct tc358743_state *state = from_timer(state, t, timer); + struct tc358743_state *state = timer_container_of(state, t, timer); unsigned int msecs; schedule_work(&state->work_i2c_poll); diff --git a/drivers/media/i2c/tvaudio.c b/drivers/media/i2c/tvaudio.c index 42115118a0bd..6267e9ad39c0 100644 --- a/drivers/media/i2c/tvaudio.c +++ b/drivers/media/i2c/tvaudio.c @@ -318,7 +318,7 @@ static int chip_cmd(struct CHIPSTATE *chip, char *name, audiocmd *cmd) static void chip_thread_wake(struct timer_list *t) { - struct CHIPSTATE *chip = from_timer(chip, t, wt); + struct CHIPSTATE *chip = timer_container_of(chip, t, wt); wake_up_process(chip->thread); } diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index 377a7e7f0499..9ce67f515843 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -2798,7 +2798,7 @@ bttv_irq_wakeup_vbi(struct bttv *btv, struct bttv_buffer *wakeup, static void bttv_irq_timeout(struct timer_list *t) { - struct bttv *btv = from_timer(btv, t, timeout); + struct bttv *btv = timer_container_of(btv, t, timeout); struct bttv_buffer_set old,new; struct bttv_buffer *ovbi; struct bttv_buffer *item; diff --git a/drivers/media/pci/bt8xx/bttv-input.c b/drivers/media/pci/bt8xx/bttv-input.c index 9eb7a5356b4c..84aa269248fd 100644 --- a/drivers/media/pci/bt8xx/bttv-input.c +++ b/drivers/media/pci/bt8xx/bttv-input.c @@ -126,7 +126,7 @@ void bttv_input_irq(struct bttv *btv) static void bttv_input_timer(struct timer_list *t) { - struct bttv_ir *ir = from_timer(ir, t, timer); + struct bttv_ir *ir = timer_container_of(ir, t, timer); struct bttv *btv = ir->btv; if (btv->c.type == BTTV_BOARD_ENLTV_FM_2) @@ -182,7 +182,7 @@ static u32 bttv_rc5_decode(unsigned int code) static void bttv_rc5_timer_end(struct timer_list *t) { - struct bttv_ir *ir = from_timer(ir, t, timer); + struct bttv_ir *ir = timer_container_of(ir, t, timer); ktime_t tv; u32 gap, rc5, scancode; u8 toggle, command, system; diff --git a/drivers/media/pci/cx18/cx18-fileops.c b/drivers/media/pci/cx18/cx18-fileops.c index 7e742733391b..315577d71d95 100644 --- a/drivers/media/pci/cx18/cx18-fileops.c +++ b/drivers/media/pci/cx18/cx18-fileops.c @@ -628,7 +628,7 @@ __poll_t cx18_v4l2_enc_poll(struct file *filp, poll_table *wait) void cx18_vb_timeout(struct timer_list *t) { - struct cx18_stream *s = from_timer(s, t, vb_timeout); + struct cx18_stream *s = timer_container_of(s, t, vb_timeout); /* * Return all of the buffers in error state, so the vbi/vid inode diff --git a/drivers/media/pci/ivtv/ivtv-irq.c b/drivers/media/pci/ivtv/ivtv-irq.c index b3b670b6ef70..748c14e87963 100644 --- a/drivers/media/pci/ivtv/ivtv-irq.c +++ b/drivers/media/pci/ivtv/ivtv-irq.c @@ -1064,7 +1064,7 @@ irqreturn_t ivtv_irq_handler(int irq, void *dev_id) void ivtv_unfinished_dma(struct timer_list *t) { - struct ivtv *itv = from_timer(itv, t, dma_timer); + struct ivtv *itv = timer_container_of(itv, t, dma_timer); if (!test_bit(IVTV_F_I_DMA, &itv->i_flags)) return; diff --git a/drivers/media/pci/netup_unidvb/netup_unidvb_core.c b/drivers/media/pci/netup_unidvb/netup_unidvb_core.c index 16338d13d9c8..9f2ac33cffa7 100644 --- a/drivers/media/pci/netup_unidvb/netup_unidvb_core.c +++ b/drivers/media/pci/netup_unidvb/netup_unidvb_core.c @@ -637,7 +637,7 @@ static void netup_unidvb_queue_cleanup(struct netup_dma *dma) static void netup_unidvb_dma_timeout(struct timer_list *t) { - struct netup_dma *dma = from_timer(dma, t, timeout); + struct netup_dma *dma = timer_container_of(dma, t, timeout); struct netup_unidvb_dev *ndev = dma->ndev; dev_dbg(&ndev->pci_dev->dev, "%s()\n", __func__); diff --git a/drivers/media/pci/saa7134/saa7134-core.c b/drivers/media/pci/saa7134/saa7134-core.c index 84295bdb8ce4..537aa65acdc8 100644 --- a/drivers/media/pci/saa7134/saa7134-core.c +++ b/drivers/media/pci/saa7134/saa7134-core.c @@ -328,7 +328,7 @@ void saa7134_buffer_next(struct saa7134_dev *dev, void saa7134_buffer_timeout(struct timer_list *t) { - struct saa7134_dmaqueue *q = from_timer(q, t, timeout); + struct saa7134_dmaqueue *q = timer_container_of(q, t, timeout); struct saa7134_dev *dev = q->dev; unsigned long flags; diff --git a/drivers/media/pci/saa7134/saa7134-input.c b/drivers/media/pci/saa7134/saa7134-input.c index d7d97c7d4a2b..468dbe8d552f 100644 --- a/drivers/media/pci/saa7134/saa7134-input.c +++ b/drivers/media/pci/saa7134/saa7134-input.c @@ -431,7 +431,7 @@ void saa7134_input_irq(struct saa7134_dev *dev) static void saa7134_input_timer(struct timer_list *t) { - struct saa7134_card_ir *ir = from_timer(ir, t, timer); + struct saa7134_card_ir *ir = timer_container_of(ir, t, timer); struct saa7134_dev *dev = ir->dev->priv; build_key(dev); diff --git a/drivers/media/pci/tw686x/tw686x-core.c b/drivers/media/pci/tw686x/tw686x-core.c index 80bd268926cc..f39e0e34deb6 100644 --- a/drivers/media/pci/tw686x/tw686x-core.c +++ b/drivers/media/pci/tw686x/tw686x-core.c @@ -125,7 +125,7 @@ void tw686x_enable_channel(struct tw686x_dev *dev, unsigned int channel) */ static void tw686x_dma_delay(struct timer_list *t) { - struct tw686x_dev *dev = from_timer(dev, t, dma_delay_timer); + struct tw686x_dev *dev = timer_container_of(dev, t, dma_delay_timer); unsigned long flags; spin_lock_irqsave(&dev->lock, flags); diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c index 9f89bd2620c7..73fdcd362265 100644 --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c @@ -143,7 +143,7 @@ void s5p_mfc_cleanup_queue(struct list_head *lh, struct vb2_queue *vq) static void s5p_mfc_watchdog(struct timer_list *t) { - struct s5p_mfc_dev *dev = from_timer(dev, t, watchdog_timer); + struct s5p_mfc_dev *dev = timer_container_of(dev, t, watchdog_timer); if (test_bit(0, &dev->hw_lock)) atomic_inc(&dev->watchdog_cnt); diff --git a/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c b/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c index 87a817dda4a9..602c37cbe177 100644 --- a/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c +++ b/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c @@ -62,7 +62,7 @@ static int load_c8sectpfe_fw(struct c8sectpfei *fei); static void c8sectpfe_timer_interrupt(struct timer_list *t) { - struct c8sectpfei *fei = from_timer(fei, t, timer); + struct c8sectpfei *fei = timer_container_of(fei, t, timer); struct channel_info *channel; int chan_num; diff --git a/drivers/media/radio/radio-cadet.c b/drivers/media/radio/radio-cadet.c index 2ddf1dfa0522..5110754e1a31 100644 --- a/drivers/media/radio/radio-cadet.c +++ b/drivers/media/radio/radio-cadet.c @@ -284,7 +284,7 @@ static bool cadet_has_rds_data(struct cadet *dev) static void cadet_handler(struct timer_list *t) { - struct cadet *dev = from_timer(dev, t, readtimer); + struct cadet *dev = timer_container_of(dev, t, readtimer); /* Service the RDS fifo */ if (mutex_trylock(&dev->lock)) { diff --git a/drivers/media/rc/ene_ir.c b/drivers/media/rc/ene_ir.c index 9435cba3f4d9..d6c54a3bccc2 100644 --- a/drivers/media/rc/ene_ir.c +++ b/drivers/media/rc/ene_ir.c @@ -659,7 +659,7 @@ exit: /* timer to simulate tx done interrupt */ static void ene_tx_irqsim(struct timer_list *t) { - struct ene_device *dev = from_timer(dev, t, tx_sim_timer); + struct ene_device *dev = timer_container_of(dev, t, tx_sim_timer); unsigned long flags; spin_lock_irqsave(&dev->hw_lock, flags); diff --git a/drivers/media/rc/igorplugusb.c b/drivers/media/rc/igorplugusb.c index bfe86588c69b..e034c93d57cf 100644 --- a/drivers/media/rc/igorplugusb.c +++ b/drivers/media/rc/igorplugusb.c @@ -131,7 +131,7 @@ static void igorplugusb_cmd(struct igorplugusb *ir, int cmd) static void igorplugusb_timer(struct timer_list *t) { - struct igorplugusb *ir = from_timer(ir, t, timer); + struct igorplugusb *ir = timer_container_of(ir, t, timer); igorplugusb_cmd(ir, GET_INFRACODE); } diff --git a/drivers/media/rc/img-ir/img-ir-hw.c b/drivers/media/rc/img-ir/img-ir-hw.c index da89ddf771c3..63f6f5b36838 100644 --- a/drivers/media/rc/img-ir/img-ir-hw.c +++ b/drivers/media/rc/img-ir/img-ir-hw.c @@ -865,7 +865,7 @@ static void img_ir_handle_data(struct img_ir_priv *priv, u32 len, u64 raw) /* timer function to end waiting for repeat. */ static void img_ir_end_timer(struct timer_list *t) { - struct img_ir_priv *priv = from_timer(priv, t, hw.end_timer); + struct img_ir_priv *priv = timer_container_of(priv, t, hw.end_timer); spin_lock_irq(&priv->lock); img_ir_end_repeat(priv); @@ -879,7 +879,8 @@ static void img_ir_end_timer(struct timer_list *t) */ static void img_ir_suspend_timer(struct timer_list *t) { - struct img_ir_priv *priv = from_timer(priv, t, hw.suspend_timer); + struct img_ir_priv *priv = timer_container_of(priv, t, + hw.suspend_timer); spin_lock_irq(&priv->lock); /* diff --git a/drivers/media/rc/img-ir/img-ir-raw.c b/drivers/media/rc/img-ir/img-ir-raw.c index 669f3309e237..92fb7b555a0f 100644 --- a/drivers/media/rc/img-ir/img-ir-raw.c +++ b/drivers/media/rc/img-ir/img-ir-raw.c @@ -65,7 +65,7 @@ void img_ir_isr_raw(struct img_ir_priv *priv, u32 irq_status) */ static void img_ir_echo_timer(struct timer_list *t) { - struct img_ir_priv *priv = from_timer(priv, t, raw.timer); + struct img_ir_priv *priv = timer_container_of(priv, t, raw.timer); spin_lock_irq(&priv->lock); diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c index cb6f36ebe5c8..f5221b018808 100644 --- a/drivers/media/rc/imon.c +++ b/drivers/media/rc/imon.c @@ -1091,7 +1091,7 @@ static void usb_tx_callback(struct urb *urb) */ static void imon_touch_display_timeout(struct timer_list *t) { - struct imon_context *ictx = from_timer(ictx, t, ttimer); + struct imon_context *ictx = timer_container_of(ictx, t, ttimer); if (ictx->display_type != IMON_DISPLAY_TYPE_VGA) return; diff --git a/drivers/media/rc/ir-mce_kbd-decoder.c b/drivers/media/rc/ir-mce_kbd-decoder.c index 817030fb50c9..bb2d7c37c263 100644 --- a/drivers/media/rc/ir-mce_kbd-decoder.c +++ b/drivers/media/rc/ir-mce_kbd-decoder.c @@ -109,7 +109,8 @@ static unsigned char kbd_keycodes[256] = { static void mce_kbd_rx_timeout(struct timer_list *t) { - struct ir_raw_event_ctrl *raw = from_timer(raw, t, mce_kbd.rx_timeout); + struct ir_raw_event_ctrl *raw = timer_container_of(raw, t, + mce_kbd.rx_timeout); unsigned char maskcode; unsigned long flags; int i; diff --git a/drivers/media/rc/rc-ir-raw.c b/drivers/media/rc/rc-ir-raw.c index aa4ac43c66fa..5dafe11f61c6 100644 --- a/drivers/media/rc/rc-ir-raw.c +++ b/drivers/media/rc/rc-ir-raw.c @@ -552,7 +552,8 @@ EXPORT_SYMBOL(ir_raw_encode_scancode); */ static void ir_raw_edge_handle(struct timer_list *t) { - struct ir_raw_event_ctrl *raw = from_timer(raw, t, edge_handle); + struct ir_raw_event_ctrl *raw = timer_container_of(raw, t, + edge_handle); struct rc_dev *dev = raw->dev; unsigned long flags; ktime_t interval; diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index e46358fb8ac0..b9bf5cdcde4a 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -674,7 +674,7 @@ EXPORT_SYMBOL_GPL(rc_keyup); */ static void ir_timer_keyup(struct timer_list *t) { - struct rc_dev *dev = from_timer(dev, t, timer_keyup); + struct rc_dev *dev = timer_container_of(dev, t, timer_keyup); unsigned long flags; /* @@ -703,7 +703,7 @@ static void ir_timer_keyup(struct timer_list *t) */ static void ir_timer_repeat(struct timer_list *t) { - struct rc_dev *dev = from_timer(dev, t, timer_repeat); + struct rc_dev *dev = timer_container_of(dev, t, timer_repeat); struct input_dev *input = dev->input_dev; unsigned long flags; diff --git a/drivers/media/usb/au0828/au0828-dvb.c b/drivers/media/usb/au0828/au0828-dvb.c index 3666f4452d11..5d0447ff7d06 100644 --- a/drivers/media/usb/au0828/au0828-dvb.c +++ b/drivers/media/usb/au0828/au0828-dvb.c @@ -97,7 +97,7 @@ static void au0828_restart_dvb_streaming(struct work_struct *work); static void au0828_bulk_timeout(struct timer_list *t) { - struct au0828_dev *dev = from_timer(dev, t, bulk_timeout); + struct au0828_dev *dev = timer_container_of(dev, t, bulk_timeout); dprintk(1, "%s called\n", __func__); dev->bulk_timeout_running = 0; diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c index 33d1fad0f7b8..e5dff969ed57 100644 --- a/drivers/media/usb/au0828/au0828-video.c +++ b/drivers/media/usb/au0828/au0828-video.c @@ -948,7 +948,7 @@ int au0828_analog_unregister(struct au0828_dev *dev) such as tvtime from hanging) */ static void au0828_vid_buffer_timeout(struct timer_list *t) { - struct au0828_dev *dev = from_timer(dev, t, vid_timeout); + struct au0828_dev *dev = timer_container_of(dev, t, vid_timeout); struct au0828_dmaqueue *dma_q = &dev->vidq; struct au0828_buffer *buf; unsigned char *vid_data; @@ -972,7 +972,7 @@ static void au0828_vid_buffer_timeout(struct timer_list *t) static void au0828_vbi_buffer_timeout(struct timer_list *t) { - struct au0828_dev *dev = from_timer(dev, t, vbi_timeout); + struct au0828_dev *dev = timer_container_of(dev, t, vbi_timeout); struct au0828_dmaqueue *dma_q = &dev->vbiq; struct au0828_buffer *buf; unsigned char *vbi_data; diff --git a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c index e23b0de1e0aa..f21c2806eb9f 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c @@ -3562,7 +3562,7 @@ struct hdw_timer { static void pvr2_ctl_timeout(struct timer_list *t) { - struct hdw_timer *timer = from_timer(timer, t, timer); + struct hdw_timer *timer = timer_container_of(timer, t, timer); struct pvr2_hdw *hdw = timer->hdw; if (hdw->ctl_write_pend_flag || hdw->ctl_read_pend_flag) { @@ -4421,7 +4421,7 @@ static int state_eval_encoder_run(struct pvr2_hdw *hdw) /* Timeout function for quiescent timer. */ static void pvr2_hdw_quiescent_timeout(struct timer_list *t) { - struct pvr2_hdw *hdw = from_timer(hdw, t, quiescent_timer); + struct pvr2_hdw *hdw = timer_container_of(hdw, t, quiescent_timer); hdw->state_decoder_quiescent = !0; trace_stbit("state_decoder_quiescent",hdw->state_decoder_quiescent); hdw->state_stale = !0; @@ -4432,7 +4432,8 @@ static void pvr2_hdw_quiescent_timeout(struct timer_list *t) /* Timeout function for decoder stabilization timer. */ static void pvr2_hdw_decoder_stabilization_timeout(struct timer_list *t) { - struct pvr2_hdw *hdw = from_timer(hdw, t, decoder_stabilization_timer); + struct pvr2_hdw *hdw = timer_container_of(hdw, t, + decoder_stabilization_timer); hdw->state_decoder_ready = !0; trace_stbit("state_decoder_ready", hdw->state_decoder_ready); hdw->state_stale = !0; @@ -4443,7 +4444,7 @@ static void pvr2_hdw_decoder_stabilization_timeout(struct timer_list *t) /* Timeout function for encoder wait timer. */ static void pvr2_hdw_encoder_wait_timeout(struct timer_list *t) { - struct pvr2_hdw *hdw = from_timer(hdw, t, encoder_wait_timer); + struct pvr2_hdw *hdw = timer_container_of(hdw, t, encoder_wait_timer); hdw->state_encoder_waitok = !0; trace_stbit("state_encoder_waitok",hdw->state_encoder_waitok); hdw->state_stale = !0; @@ -4454,7 +4455,7 @@ static void pvr2_hdw_encoder_wait_timeout(struct timer_list *t) /* Timeout function for encoder run timer. */ static void pvr2_hdw_encoder_run_timeout(struct timer_list *t) { - struct pvr2_hdw *hdw = from_timer(hdw, t, encoder_run_timer); + struct pvr2_hdw *hdw = timer_container_of(hdw, t, encoder_run_timer); if (!hdw->state_encoder_runok) { hdw->state_encoder_runok = !0; trace_stbit("state_encoder_runok",hdw->state_encoder_runok); diff --git a/drivers/media/usb/s2255/s2255drv.c b/drivers/media/usb/s2255/s2255drv.c index 899a7a67e2ba..8332f2c5aed7 100644 --- a/drivers/media/usb/s2255/s2255drv.c +++ b/drivers/media/usb/s2255/s2255drv.c @@ -471,7 +471,7 @@ static void s2255_reset_dsppower(struct s2255_dev *dev) */ static void s2255_timer(struct timer_list *t) { - struct s2255_dev *dev = from_timer(dev, t, timer); + struct s2255_dev *dev = timer_container_of(dev, t, timer); struct s2255_fw *data = dev->fw_data; if (usb_submit_urb(data->fw_urb, GFP_ATOMIC) < 0) { pr_err("s2255: can't submit urb\n"); diff --git a/drivers/memory/tegra/tegra210-emc-core.c b/drivers/memory/tegra/tegra210-emc-core.c index e63f62690571..e96ca4157d48 100644 --- a/drivers/memory/tegra/tegra210-emc-core.c +++ b/drivers/memory/tegra/tegra210-emc-core.c @@ -558,7 +558,7 @@ tegra210_emc_table_register_offsets = { static void tegra210_emc_train(struct timer_list *timer) { - struct tegra210_emc *emc = from_timer(emc, timer, training); + struct tegra210_emc *emc = timer_container_of(emc, timer, training); unsigned long flags; if (!emc->last) @@ -614,7 +614,8 @@ static unsigned int tegra210_emc_get_temperature(struct tegra210_emc *emc) static void tegra210_emc_poll_refresh(struct timer_list *timer) { - struct tegra210_emc *emc = from_timer(emc, timer, refresh_timer); + struct tegra210_emc *emc = timer_container_of(emc, timer, + refresh_timer); unsigned int temperature; if (!emc->debugfs.temperature) diff --git a/drivers/memstick/core/ms_block.c b/drivers/memstick/core/ms_block.c index 7dc2c9987982..d34892782f6e 100644 --- a/drivers/memstick/core/ms_block.c +++ b/drivers/memstick/core/ms_block.c @@ -1498,7 +1498,7 @@ static int msb_ftl_scan(struct msb_data *msb) static void msb_cache_flush_timer(struct timer_list *t) { - struct msb_data *msb = from_timer(msb, t, cache_flush_timer); + struct msb_data *msb = timer_container_of(msb, t, cache_flush_timer); msb->need_flush_cache = true; queue_work(msb->io_queue, &msb->io_work); diff --git a/drivers/memstick/host/jmb38x_ms.c b/drivers/memstick/host/jmb38x_ms.c index a5a9bb3f16be..cddddb3a5a27 100644 --- a/drivers/memstick/host/jmb38x_ms.c +++ b/drivers/memstick/host/jmb38x_ms.c @@ -590,7 +590,7 @@ static irqreturn_t jmb38x_ms_isr(int irq, void *dev_id) static void jmb38x_ms_abort(struct timer_list *t) { - struct jmb38x_ms_host *host = from_timer(host, t, timer); + struct jmb38x_ms_host *host = timer_container_of(host, t, timer); struct memstick_host *msh = host->msh; unsigned long flags; diff --git a/drivers/memstick/host/r592.c b/drivers/memstick/host/r592.c index 488ef8eecb26..605b2265536f 100644 --- a/drivers/memstick/host/r592.c +++ b/drivers/memstick/host/r592.c @@ -614,7 +614,7 @@ static void r592_update_card_detect(struct r592_device *dev) /* Timer routine that fires 1 second after last card detection event, */ static void r592_detect_timer(struct timer_list *t) { - struct r592_device *dev = from_timer(dev, t, detect_timer); + struct r592_device *dev = timer_container_of(dev, t, detect_timer); r592_update_card_detect(dev); memstick_detect_change(dev->host); } diff --git a/drivers/memstick/host/tifm_ms.c b/drivers/memstick/host/tifm_ms.c index 676348eee015..db7f3a088fb0 100644 --- a/drivers/memstick/host/tifm_ms.c +++ b/drivers/memstick/host/tifm_ms.c @@ -535,7 +535,7 @@ static int tifm_ms_set_param(struct memstick_host *msh, static void tifm_ms_abort(struct timer_list *t) { - struct tifm_ms *host = from_timer(host, t, timer); + struct tifm_ms *host = timer_container_of(host, t, timer); dev_dbg(&host->dev->dev, "status %x\n", readl(host->dev->addr + SOCK_MS_STATUS)); diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index c161546d728f..b9ca56930003 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -652,7 +652,6 @@ source "drivers/misc/altera-stapl/Kconfig" source "drivers/misc/mei/Kconfig" source "drivers/misc/vmw_vmci/Kconfig" source "drivers/misc/genwqe/Kconfig" -source "drivers/misc/echo/Kconfig" source "drivers/misc/ocxl/Kconfig" source "drivers/misc/bcm-vk/Kconfig" source "drivers/misc/cardreader/Kconfig" @@ -660,4 +659,5 @@ source "drivers/misc/uacce/Kconfig" source "drivers/misc/pvpanic/Kconfig" source "drivers/misc/mchp_pci1xxxx/Kconfig" source "drivers/misc/keba/Kconfig" +source "drivers/misc/amd-sbi/Kconfig" endmenu diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 054cee9b08a4..917b9a7183aa 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -50,7 +50,6 @@ obj-$(CONFIG_LATTICE_ECP3_CONFIG) += lattice-ecp3-config.o obj-$(CONFIG_SRAM) += sram.o obj-$(CONFIG_SRAM_EXEC) += sram-exec.o obj-$(CONFIG_GENWQE) += genwqe/ -obj-$(CONFIG_ECHO) += echo/ obj-$(CONFIG_DW_XDATA_PCIE) += dw-xdata-pcie.o obj-$(CONFIG_PCI_ENDPOINT_TEST) += pci_endpoint_test.o obj-$(CONFIG_OCXL) += ocxl/ @@ -75,3 +74,4 @@ lan966x-pci-objs := lan966x_pci.o lan966x-pci-objs += lan966x_pci.dtbo.o obj-$(CONFIG_MCHP_LAN966X_PCI) += lan966x-pci.o obj-y += keba/ +obj-y += amd-sbi/ diff --git a/drivers/misc/amd-sbi/Kconfig b/drivers/misc/amd-sbi/Kconfig new file mode 100644 index 000000000000..4840831c84ca --- /dev/null +++ b/drivers/misc/amd-sbi/Kconfig @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: GPL-2.0-only +config AMD_SBRMI_I2C + tristate "AMD side band RMI support" + depends on I2C + help + Side band RMI over I2C support for AMD out of band management. + + This driver can also be built as a module. If so, the module will + be called sbrmi-i2c. + +config AMD_SBRMI_HWMON + bool "SBRMI hardware monitoring" + depends on AMD_SBRMI_I2C && HWMON + depends on !(AMD_SBRMI_I2C=y && HWMON=m) + help + This provides support for RMI device hardware monitoring. If enabled, + a hardware monitoring device will be created for each socket in + the system. diff --git a/drivers/misc/amd-sbi/Makefile b/drivers/misc/amd-sbi/Makefile new file mode 100644 index 000000000000..38eaaa651fd9 --- /dev/null +++ b/drivers/misc/amd-sbi/Makefile @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only +sbrmi-i2c-objs += rmi-i2c.o rmi-core.o +sbrmi-i2c-$(CONFIG_AMD_SBRMI_HWMON) += rmi-hwmon.o +obj-$(CONFIG_AMD_SBRMI_I2C) += sbrmi-i2c.o diff --git a/drivers/misc/amd-sbi/rmi-core.c b/drivers/misc/amd-sbi/rmi-core.c new file mode 100644 index 000000000000..b653a21a909e --- /dev/null +++ b/drivers/misc/amd-sbi/rmi-core.c @@ -0,0 +1,474 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * sbrmi-core.c - file defining SB-RMI protocols compliant + * AMD SoC device. + * + * Copyright (C) 2025 Advanced Micro Devices, Inc. + */ +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/fs.h> +#include <linux/i2c.h> +#include <linux/miscdevice.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/regmap.h> +#include "rmi-core.h" + +/* Mask for Status Register bit[1] */ +#define SW_ALERT_MASK 0x2 +/* Mask to check H/W Alert status bit */ +#define HW_ALERT_MASK 0x80 + +/* Software Interrupt for triggering */ +#define START_CMD 0x80 +#define TRIGGER_MAILBOX 0x01 + +/* Default message lengths as per APML command protocol */ +/* CPUID */ +#define CPUID_RD_DATA_LEN 0x8 +#define CPUID_WR_DATA_LEN 0x8 +#define CPUID_RD_REG_LEN 0xa +#define CPUID_WR_REG_LEN 0x9 +/* MSR */ +#define MSR_RD_REG_LEN 0xa +#define MSR_WR_REG_LEN 0x8 +#define MSR_RD_DATA_LEN 0x8 +#define MSR_WR_DATA_LEN 0x7 + +/* CPUID MSR Command Ids */ +#define CPUID_MCA_CMD 0x73 +#define RD_CPUID_CMD 0x91 +#define RD_MCA_CMD 0x86 + +/* CPUID MCAMSR mask & index */ +#define CPUID_MCA_THRD_MASK GENMASK(15, 0) +#define CPUID_MCA_THRD_INDEX 32 +#define CPUID_MCA_FUNC_MASK GENMASK(31, 0) +#define CPUID_EXT_FUNC_INDEX 56 + +/* input for bulk write to CPUID protocol */ +struct cpu_msr_indata { + u8 wr_len; /* const value */ + u8 rd_len; /* const value */ + u8 proto_cmd; /* const value */ + u8 thread; /* thread number */ + union { + u8 reg_offset[4]; /* input value */ + u32 value; + } __packed; + u8 ext; /* extended function */ +}; + +/* output for bulk read from CPUID protocol */ +struct cpu_msr_outdata { + u8 num_bytes; /* number of bytes return */ + u8 status; /* Protocol status code */ + union { + u64 value; + u8 reg_data[8]; + } __packed; +}; + +static inline void prepare_cpuid_input_message(struct cpu_msr_indata *input, + u8 thread_id, u32 func, + u8 ext_func) +{ + input->rd_len = CPUID_RD_DATA_LEN; + input->wr_len = CPUID_WR_DATA_LEN; + input->proto_cmd = RD_CPUID_CMD; + input->thread = thread_id << 1; + input->value = func; + input->ext = ext_func; +} + +static inline void prepare_mca_msr_input_message(struct cpu_msr_indata *input, + u8 thread_id, u32 data_in) +{ + input->rd_len = MSR_RD_DATA_LEN; + input->wr_len = MSR_WR_DATA_LEN; + input->proto_cmd = RD_MCA_CMD; + input->thread = thread_id << 1; + input->value = data_in; +} + +static int sbrmi_get_rev(struct sbrmi_data *data) +{ + unsigned int rev; + u16 offset = SBRMI_REV; + int ret; + + ret = regmap_read(data->regmap, offset, &rev); + if (ret < 0) + return ret; + + data->rev = rev; + return 0; +} + +/* Read CPUID function protocol */ +static int rmi_cpuid_read(struct sbrmi_data *data, + struct apml_cpuid_msg *msg) +{ + struct cpu_msr_indata input = {0}; + struct cpu_msr_outdata output = {0}; + int val = 0; + int ret, hw_status; + u16 thread; + + mutex_lock(&data->lock); + /* cache the rev value to identify if protocol is supported or not */ + if (!data->rev) { + ret = sbrmi_get_rev(data); + if (ret < 0) + goto exit_unlock; + } + /* CPUID protocol for REV 0x10 is not supported*/ + if (data->rev == 0x10) { + ret = -EOPNOTSUPP; + goto exit_unlock; + } + + thread = msg->cpu_in_out << CPUID_MCA_THRD_INDEX & CPUID_MCA_THRD_MASK; + + /* Thread > 127, Thread128 CS register, 1'b1 needs to be set to 1 */ + if (thread > 127) { + thread -= 128; + val = 1; + } + ret = regmap_write(data->regmap, SBRMI_THREAD128CS, val); + if (ret < 0) + goto exit_unlock; + + prepare_cpuid_input_message(&input, thread, + msg->cpu_in_out & CPUID_MCA_FUNC_MASK, + msg->cpu_in_out >> CPUID_EXT_FUNC_INDEX); + + ret = regmap_bulk_write(data->regmap, CPUID_MCA_CMD, + &input, CPUID_WR_REG_LEN); + if (ret < 0) + goto exit_unlock; + + /* + * For RMI Rev 0x20, new h/w status bit is introduced. which is used + * by firmware to indicate completion of commands (0x71, 0x72, 0x73). + * wait for the status bit to be set by the hardware before + * reading the data out. + */ + ret = regmap_read_poll_timeout(data->regmap, SBRMI_STATUS, hw_status, + hw_status & HW_ALERT_MASK, 500, 2000000); + if (ret) + goto exit_unlock; + + ret = regmap_bulk_read(data->regmap, CPUID_MCA_CMD, + &output, CPUID_RD_REG_LEN); + if (ret < 0) + goto exit_unlock; + + ret = regmap_write(data->regmap, SBRMI_STATUS, + HW_ALERT_MASK); + if (ret < 0) + goto exit_unlock; + + if (output.num_bytes != CPUID_RD_REG_LEN - 1) { + ret = -EMSGSIZE; + goto exit_unlock; + } + if (output.status) { + ret = -EPROTOTYPE; + msg->fw_ret_code = output.status; + goto exit_unlock; + } + msg->cpu_in_out = output.value; +exit_unlock: + if (ret < 0) + msg->cpu_in_out = 0; + mutex_unlock(&data->lock); + return ret; +} + +/* MCA MSR protocol */ +static int rmi_mca_msr_read(struct sbrmi_data *data, + struct apml_mcamsr_msg *msg) +{ + struct cpu_msr_outdata output = {0}; + struct cpu_msr_indata input = {0}; + int ret, val = 0; + int hw_status; + u16 thread; + + mutex_lock(&data->lock); + /* cache the rev value to identify if protocol is supported or not */ + if (!data->rev) { + ret = sbrmi_get_rev(data); + if (ret < 0) + goto exit_unlock; + } + /* MCA MSR protocol for REV 0x10 is not supported*/ + if (data->rev == 0x10) { + ret = -EOPNOTSUPP; + goto exit_unlock; + } + + thread = msg->mcamsr_in_out << CPUID_MCA_THRD_INDEX & CPUID_MCA_THRD_MASK; + + /* Thread > 127, Thread128 CS register, 1'b1 needs to be set to 1 */ + if (thread > 127) { + thread -= 128; + val = 1; + } + ret = regmap_write(data->regmap, SBRMI_THREAD128CS, val); + if (ret < 0) + goto exit_unlock; + + prepare_mca_msr_input_message(&input, thread, + msg->mcamsr_in_out & CPUID_MCA_FUNC_MASK); + + ret = regmap_bulk_write(data->regmap, CPUID_MCA_CMD, + &input, MSR_WR_REG_LEN); + if (ret < 0) + goto exit_unlock; + + /* + * For RMI Rev 0x20, new h/w status bit is introduced. which is used + * by firmware to indicate completion of commands (0x71, 0x72, 0x73). + * wait for the status bit to be set by the hardware before + * reading the data out. + */ + ret = regmap_read_poll_timeout(data->regmap, SBRMI_STATUS, hw_status, + hw_status & HW_ALERT_MASK, 500, 2000000); + if (ret) + goto exit_unlock; + + ret = regmap_bulk_read(data->regmap, CPUID_MCA_CMD, + &output, MSR_RD_REG_LEN); + if (ret < 0) + goto exit_unlock; + + ret = regmap_write(data->regmap, SBRMI_STATUS, + HW_ALERT_MASK); + if (ret < 0) + goto exit_unlock; + + if (output.num_bytes != MSR_RD_REG_LEN - 1) { + ret = -EMSGSIZE; + goto exit_unlock; + } + if (output.status) { + ret = -EPROTOTYPE; + msg->fw_ret_code = output.status; + goto exit_unlock; + } + msg->mcamsr_in_out = output.value; + +exit_unlock: + mutex_unlock(&data->lock); + return ret; +} + +int rmi_mailbox_xfer(struct sbrmi_data *data, + struct apml_mbox_msg *msg) +{ + unsigned int bytes, ec; + int i, ret; + int sw_status; + u8 byte; + + mutex_lock(&data->lock); + + msg->fw_ret_code = 0; + + /* Indicate firmware a command is to be serviced */ + ret = regmap_write(data->regmap, SBRMI_INBNDMSG7, START_CMD); + if (ret < 0) + goto exit_unlock; + + /* Write the command to SBRMI::InBndMsg_inst0 */ + ret = regmap_write(data->regmap, SBRMI_INBNDMSG0, msg->cmd); + if (ret < 0) + goto exit_unlock; + + /* + * For both read and write the initiator (BMC) writes + * Command Data In[31:0] to SBRMI::InBndMsg_inst[4:1] + * SBRMI_x3C(MSB):SBRMI_x39(LSB) + */ + for (i = 0; i < AMD_SBI_MB_DATA_SIZE; i++) { + byte = (msg->mb_in_out >> i * 8) & 0xff; + ret = regmap_write(data->regmap, SBRMI_INBNDMSG1 + i, byte); + if (ret < 0) + goto exit_unlock; + } + + /* + * Write 0x01 to SBRMI::SoftwareInterrupt to notify firmware to + * perform the requested read or write command + */ + ret = regmap_write(data->regmap, SBRMI_SW_INTERRUPT, TRIGGER_MAILBOX); + if (ret < 0) + goto exit_unlock; + + /* + * Firmware will write SBRMI::Status[SwAlertSts]=1 to generate + * an ALERT (if enabled) to initiator (BMC) to indicate completion + * of the requested command + */ + ret = regmap_read_poll_timeout(data->regmap, SBRMI_STATUS, sw_status, + sw_status & SW_ALERT_MASK, 500, 2000000); + if (ret) + goto exit_unlock; + + ret = regmap_read(data->regmap, SBRMI_OUTBNDMSG7, &ec); + if (ret || ec) + goto exit_clear_alert; + /* + * For a read operation, the initiator (BMC) reads the firmware + * response Command Data Out[31:0] from SBRMI::OutBndMsg_inst[4:1] + * {SBRMI_x34(MSB):SBRMI_x31(LSB)}. + */ + for (i = 0; i < AMD_SBI_MB_DATA_SIZE; i++) { + ret = regmap_read(data->regmap, + SBRMI_OUTBNDMSG1 + i, &bytes); + if (ret < 0) + break; + msg->mb_in_out |= bytes << i * 8; + } + +exit_clear_alert: + /* + * BMC must write 1'b1 to SBRMI::Status[SwAlertSts] to clear the + * ALERT to initiator + */ + ret = regmap_write(data->regmap, SBRMI_STATUS, + sw_status | SW_ALERT_MASK); + if (ec) { + ret = -EPROTOTYPE; + msg->fw_ret_code = ec; + } +exit_unlock: + mutex_unlock(&data->lock); + return ret; +} + +static int apml_rmi_reg_xfer(struct sbrmi_data *data, + struct apml_reg_xfer_msg __user *arg) +{ + struct apml_reg_xfer_msg msg = { 0 }; + unsigned int data_read; + int ret; + + /* Copy the structure from user */ + if (copy_from_user(&msg, arg, sizeof(struct apml_reg_xfer_msg))) + return -EFAULT; + + mutex_lock(&data->lock); + if (msg.rflag) { + ret = regmap_read(data->regmap, msg.reg_addr, &data_read); + if (!ret) + msg.data_in_out = data_read; + } else { + ret = regmap_write(data->regmap, msg.reg_addr, msg.data_in_out); + } + + mutex_unlock(&data->lock); + + if (msg.rflag && !ret) + return copy_to_user(arg, &msg, sizeof(struct apml_reg_xfer_msg)); + return ret; +} + +static int apml_mailbox_xfer(struct sbrmi_data *data, struct apml_mbox_msg __user *arg) +{ + struct apml_mbox_msg msg = { 0 }; + int ret; + + /* Copy the structure from user */ + if (copy_from_user(&msg, arg, sizeof(struct apml_mbox_msg))) + return -EFAULT; + + /* Mailbox protocol */ + ret = rmi_mailbox_xfer(data, &msg); + if (ret && ret != -EPROTOTYPE) + return ret; + + return copy_to_user(arg, &msg, sizeof(struct apml_mbox_msg)); +} + +static int apml_cpuid_xfer(struct sbrmi_data *data, struct apml_cpuid_msg __user *arg) +{ + struct apml_cpuid_msg msg = { 0 }; + int ret; + + /* Copy the structure from user */ + if (copy_from_user(&msg, arg, sizeof(struct apml_cpuid_msg))) + return -EFAULT; + + /* CPUID Protocol */ + ret = rmi_cpuid_read(data, &msg); + if (ret && ret != -EPROTOTYPE) + return ret; + + return copy_to_user(arg, &msg, sizeof(struct apml_cpuid_msg)); +} + +static int apml_mcamsr_xfer(struct sbrmi_data *data, struct apml_mcamsr_msg __user *arg) +{ + struct apml_mcamsr_msg msg = { 0 }; + int ret; + + /* Copy the structure from user */ + if (copy_from_user(&msg, arg, sizeof(struct apml_mcamsr_msg))) + return -EFAULT; + + /* MCAMSR Protocol */ + ret = rmi_mca_msr_read(data, &msg); + if (ret && ret != -EPROTOTYPE) + return ret; + + return copy_to_user(arg, &msg, sizeof(struct apml_mcamsr_msg)); +} + +static long sbrmi_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) +{ + void __user *argp = (void __user *)arg; + struct sbrmi_data *data; + + data = container_of(fp->private_data, struct sbrmi_data, sbrmi_misc_dev); + switch (cmd) { + case SBRMI_IOCTL_MBOX_CMD: + return apml_mailbox_xfer(data, argp); + case SBRMI_IOCTL_CPUID_CMD: + return apml_cpuid_xfer(data, argp); + case SBRMI_IOCTL_MCAMSR_CMD: + return apml_mcamsr_xfer(data, argp); + case SBRMI_IOCTL_REG_XFER_CMD: + return apml_rmi_reg_xfer(data, argp); + default: + return -ENOTTY; + } +} + +static const struct file_operations sbrmi_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = sbrmi_ioctl, + .compat_ioctl = compat_ptr_ioctl, +}; + +int create_misc_rmi_device(struct sbrmi_data *data, + struct device *dev) +{ + data->sbrmi_misc_dev.name = devm_kasprintf(dev, + GFP_KERNEL, + "sbrmi-%x", + data->dev_static_addr); + data->sbrmi_misc_dev.minor = MISC_DYNAMIC_MINOR; + data->sbrmi_misc_dev.fops = &sbrmi_fops; + data->sbrmi_misc_dev.parent = dev; + data->sbrmi_misc_dev.nodename = devm_kasprintf(dev, + GFP_KERNEL, + "sbrmi-%x", + data->dev_static_addr); + data->sbrmi_misc_dev.mode = 0600; + + return misc_register(&data->sbrmi_misc_dev); +} diff --git a/drivers/misc/amd-sbi/rmi-core.h b/drivers/misc/amd-sbi/rmi-core.h new file mode 100644 index 000000000000..975ae858e9fd --- /dev/null +++ b/drivers/misc/amd-sbi/rmi-core.h @@ -0,0 +1,74 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2025 Advanced Micro Devices, Inc. + */ + +#ifndef _SBRMI_CORE_H_ +#define _SBRMI_CORE_H_ + +#include <linux/miscdevice.h> +#include <linux/mutex.h> +#include <linux/i2c.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <uapi/misc/amd-apml.h> + +/* SB-RMI registers */ +enum sbrmi_reg { + SBRMI_REV, + SBRMI_CTRL, + SBRMI_STATUS, + SBRMI_OUTBNDMSG0 = 0x30, + SBRMI_OUTBNDMSG1, + SBRMI_OUTBNDMSG2, + SBRMI_OUTBNDMSG3, + SBRMI_OUTBNDMSG4, + SBRMI_OUTBNDMSG5, + SBRMI_OUTBNDMSG6, + SBRMI_OUTBNDMSG7, + SBRMI_INBNDMSG0, + SBRMI_INBNDMSG1, + SBRMI_INBNDMSG2, + SBRMI_INBNDMSG3, + SBRMI_INBNDMSG4, + SBRMI_INBNDMSG5, + SBRMI_INBNDMSG6, + SBRMI_INBNDMSG7, + SBRMI_SW_INTERRUPT, + SBRMI_THREAD128CS = 0x4b, +}; + +/* + * SB-RMI supports soft mailbox service request to MP1 (power management + * firmware) through SBRMI inbound/outbound message registers. + * SB-RMI message IDs + */ +enum sbrmi_msg_id { + SBRMI_READ_PKG_PWR_CONSUMPTION = 0x1, + SBRMI_WRITE_PKG_PWR_LIMIT, + SBRMI_READ_PKG_PWR_LIMIT, + SBRMI_READ_PKG_MAX_PWR_LIMIT, +}; + +/* Each client has this additional data */ +struct sbrmi_data { + struct miscdevice sbrmi_misc_dev; + struct regmap *regmap; + /* Mutex locking */ + struct mutex lock; + u32 pwr_limit_max; + u8 dev_static_addr; + u8 rev; +}; + +int rmi_mailbox_xfer(struct sbrmi_data *data, struct apml_mbox_msg *msg); +#ifdef CONFIG_AMD_SBRMI_HWMON +int create_hwmon_sensor_device(struct device *dev, struct sbrmi_data *data); +#else +static inline int create_hwmon_sensor_device(struct device *dev, struct sbrmi_data *data) +{ + return 0; +} +#endif +int create_misc_rmi_device(struct sbrmi_data *data, struct device *dev); +#endif /*_SBRMI_CORE_H_*/ diff --git a/drivers/misc/amd-sbi/rmi-hwmon.c b/drivers/misc/amd-sbi/rmi-hwmon.c new file mode 100644 index 000000000000..f4f015605daa --- /dev/null +++ b/drivers/misc/amd-sbi/rmi-hwmon.c @@ -0,0 +1,120 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * rmi-hwmon.c - hwmon sensor support for side band RMI + * + * Copyright (C) 2025 Advanced Micro Devices, Inc. + */ +#include <linux/err.h> +#include <linux/hwmon.h> +#include <uapi/misc/amd-apml.h> +#include "rmi-core.h" + +/* Do not allow setting negative power limit */ +#define SBRMI_PWR_MIN 0 + +static int sbrmi_read(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long *val) +{ + struct sbrmi_data *data = dev_get_drvdata(dev); + struct apml_mbox_msg msg = { 0 }; + int ret; + + if (!data) + return -ENODEV; + + if (type != hwmon_power) + return -EINVAL; + + switch (attr) { + case hwmon_power_input: + msg.cmd = SBRMI_READ_PKG_PWR_CONSUMPTION; + ret = rmi_mailbox_xfer(data, &msg); + break; + case hwmon_power_cap: + msg.cmd = SBRMI_READ_PKG_PWR_LIMIT; + ret = rmi_mailbox_xfer(data, &msg); + break; + case hwmon_power_cap_max: + msg.mb_in_out = data->pwr_limit_max; + ret = 0; + break; + default: + return -EINVAL; + } + if (ret < 0) + return ret; + /* hwmon power attributes are in microWatt */ + *val = (long)msg.mb_in_out * 1000; + return ret; +} + +static int sbrmi_write(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long val) +{ + struct sbrmi_data *data = dev_get_drvdata(dev); + struct apml_mbox_msg msg = { 0 }; + + if (!data) + return -ENODEV; + + if (type != hwmon_power && attr != hwmon_power_cap) + return -EINVAL; + /* + * hwmon power attributes are in microWatt + * mailbox read/write is in mWatt + */ + val /= 1000; + + val = clamp_val(val, SBRMI_PWR_MIN, data->pwr_limit_max); + + msg.cmd = SBRMI_WRITE_PKG_PWR_LIMIT; + msg.mb_in_out = val; + + return rmi_mailbox_xfer(data, &msg); +} + +static umode_t sbrmi_is_visible(const void *data, + enum hwmon_sensor_types type, + u32 attr, int channel) +{ + switch (type) { + case hwmon_power: + switch (attr) { + case hwmon_power_input: + case hwmon_power_cap_max: + return 0444; + case hwmon_power_cap: + return 0644; + } + break; + default: + break; + } + return 0; +} + +static const struct hwmon_channel_info * const sbrmi_info[] = { + HWMON_CHANNEL_INFO(power, + HWMON_P_INPUT | HWMON_P_CAP | HWMON_P_CAP_MAX), + NULL +}; + +static const struct hwmon_ops sbrmi_hwmon_ops = { + .is_visible = sbrmi_is_visible, + .read = sbrmi_read, + .write = sbrmi_write, +}; + +static const struct hwmon_chip_info sbrmi_chip_info = { + .ops = &sbrmi_hwmon_ops, + .info = sbrmi_info, +}; + +int create_hwmon_sensor_device(struct device *dev, struct sbrmi_data *data) +{ + struct device *hwmon_dev; + + hwmon_dev = devm_hwmon_device_register_with_info(dev, "sbrmi", data, + &sbrmi_chip_info, NULL); + return PTR_ERR_OR_ZERO(hwmon_dev); +} diff --git a/drivers/misc/amd-sbi/rmi-i2c.c b/drivers/misc/amd-sbi/rmi-i2c.c new file mode 100644 index 000000000000..f891f5af4bc6 --- /dev/null +++ b/drivers/misc/amd-sbi/rmi-i2c.c @@ -0,0 +1,133 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * rmi-i2c.c - Side band RMI over I2C support for AMD out + * of band management + * + * Copyright (C) 2024 Advanced Micro Devices, Inc. + */ + +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/i2c.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/of.h> +#include <linux/regmap.h> +#include "rmi-core.h" + +static int sbrmi_enable_alert(struct sbrmi_data *data) +{ + int ctrl, ret; + + /* + * Enable the SB-RMI Software alert status + * by writing 0 to bit 4 of Control register(0x1) + */ + ret = regmap_read(data->regmap, SBRMI_CTRL, &ctrl); + if (ret < 0) + return ret; + + if (ctrl & 0x10) { + ctrl &= ~0x10; + return regmap_write(data->regmap, SBRMI_CTRL, ctrl); + } + + return 0; +} + +static int sbrmi_get_max_pwr_limit(struct sbrmi_data *data) +{ + struct apml_mbox_msg msg = { 0 }; + int ret; + + msg.cmd = SBRMI_READ_PKG_MAX_PWR_LIMIT; + ret = rmi_mailbox_xfer(data, &msg); + if (ret < 0) + return ret; + data->pwr_limit_max = msg.mb_in_out; + + return ret; +} + +static int sbrmi_i2c_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct sbrmi_data *data; + struct regmap_config sbrmi_i2c_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + }; + int ret; + + data = devm_kzalloc(dev, sizeof(struct sbrmi_data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + mutex_init(&data->lock); + + data->regmap = devm_regmap_init_i2c(client, &sbrmi_i2c_regmap_config); + if (IS_ERR(data->regmap)) + return PTR_ERR(data->regmap); + + /* Enable alert for SB-RMI sequence */ + ret = sbrmi_enable_alert(data); + if (ret < 0) + return ret; + + /* Cache maximum power limit */ + ret = sbrmi_get_max_pwr_limit(data); + if (ret < 0) + return ret; + + data->dev_static_addr = client->addr; + dev_set_drvdata(dev, data); + + ret = create_hwmon_sensor_device(dev, data); + if (ret < 0) + return ret; + return create_misc_rmi_device(data, dev); +} + +static void sbrmi_i2c_remove(struct i2c_client *client) +{ + struct sbrmi_data *data = dev_get_drvdata(&client->dev); + + misc_deregister(&data->sbrmi_misc_dev); + /* Assign fops and parent of misc dev to NULL */ + data->sbrmi_misc_dev.fops = NULL; + data->sbrmi_misc_dev.parent = NULL; + dev_info(&client->dev, "Removed sbrmi-i2c driver\n"); + return; +} + +static const struct i2c_device_id sbrmi_id[] = { + {"sbrmi-i2c"}, + {} +}; +MODULE_DEVICE_TABLE(i2c, sbrmi_id); + +static const struct of_device_id __maybe_unused sbrmi_of_match[] = { + { + .compatible = "amd,sbrmi", + }, + { }, +}; +MODULE_DEVICE_TABLE(of, sbrmi_of_match); + +static struct i2c_driver sbrmi_driver = { + .driver = { + .name = "sbrmi-i2c", + .of_match_table = of_match_ptr(sbrmi_of_match), + }, + .probe = sbrmi_i2c_probe, + .remove = sbrmi_i2c_remove, + .id_table = sbrmi_id, +}; + +module_i2c_driver(sbrmi_driver); + +MODULE_AUTHOR("Akshay Gupta <akshay.gupta@amd.com>"); +MODULE_AUTHOR("Naveen Krishna Chatradhi <naveenkrishna.chatradhi@amd.com>"); +MODULE_DESCRIPTION("Hwmon driver for AMD SB-RMI emulated sensor"); +MODULE_LICENSE("GPL"); diff --git a/drivers/misc/bcm-vk/bcm_vk.h b/drivers/misc/bcm-vk/bcm_vk.h index 386884c2a263..9344c2366a4b 100644 --- a/drivers/misc/bcm-vk/bcm_vk.h +++ b/drivers/misc/bcm-vk/bcm_vk.h @@ -311,7 +311,6 @@ struct bcm_vk_peer_log { u32 wr_idx; u32 buf_size; u32 mask; - char data[]; }; /* max buf size allowed */ diff --git a/drivers/misc/bcm-vk/bcm_vk_tty.c b/drivers/misc/bcm-vk/bcm_vk_tty.c index 44a2dd80054d..e6c42b772e96 100644 --- a/drivers/misc/bcm-vk/bcm_vk_tty.c +++ b/drivers/misc/bcm-vk/bcm_vk_tty.c @@ -43,7 +43,7 @@ struct bcm_vk_tty_chan { static void bcm_vk_tty_poll(struct timer_list *t) { - struct bcm_vk *vk = from_timer(vk, t, serial_timer); + struct bcm_vk *vk = timer_container_of(vk, t, serial_timer); queue_work(vk->tty_wq_thread, &vk->tty_wq_work); mod_timer(&vk->serial_timer, jiffies + SERIAL_TIMER_VALUE); diff --git a/drivers/misc/cardreader/alcor_pci.c b/drivers/misc/cardreader/alcor_pci.c index a5549eaf52d0..8e7ea2c9142d 100644 --- a/drivers/misc/cardreader/alcor_pci.c +++ b/drivers/misc/cardreader/alcor_pci.c @@ -121,23 +121,23 @@ static int alcor_pci_probe(struct pci_dev *pdev, priv->cfg = cfg; priv->irq = pdev->irq; - ret = pci_request_regions(pdev, DRV_NAME_ALCOR_PCI); + ret = pcim_request_all_regions(pdev, DRV_NAME_ALCOR_PCI); if (ret) { dev_err(&pdev->dev, "Cannot request region\n"); - ret = -ENOMEM; + ret = -EBUSY; goto error_free_ida; } if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM)) { dev_err(&pdev->dev, "BAR %d is not iomem. Aborting.\n", bar); ret = -ENODEV; - goto error_release_regions; + goto error_free_ida; } priv->iobase = pcim_iomap(pdev, bar, 0); if (!priv->iobase) { ret = -ENOMEM; - goto error_release_regions; + goto error_free_ida; } /* make sure irqs are disabled */ @@ -147,7 +147,7 @@ static int alcor_pci_probe(struct pci_dev *pdev, ret = dma_set_mask_and_coherent(priv->dev, AU6601_SDMA_MASK); if (ret) { dev_err(priv->dev, "Failed to set DMA mask\n"); - goto error_release_regions; + goto error_free_ida; } pci_set_master(pdev); @@ -169,8 +169,6 @@ static int alcor_pci_probe(struct pci_dev *pdev, error_clear_drvdata: pci_clear_master(pdev); pci_set_drvdata(pdev, NULL); -error_release_regions: - pci_release_regions(pdev); error_free_ida: ida_free(&alcor_pci_idr, priv->id); return ret; @@ -186,7 +184,6 @@ static void alcor_pci_remove(struct pci_dev *pdev) ida_free(&alcor_pci_idr, priv->id); - pci_release_regions(pdev); pci_clear_master(pdev); pci_set_drvdata(pdev, NULL); } diff --git a/drivers/misc/cardreader/rts5264.c b/drivers/misc/cardreader/rts5264.c index 8be4ed7d9d47..06d7a8a95fd6 100644 --- a/drivers/misc/cardreader/rts5264.c +++ b/drivers/misc/cardreader/rts5264.c @@ -605,6 +605,22 @@ static int rts5264_extra_init_hw(struct rtsx_pcr *pcr) return 0; } +static int rts5264_optimize_phy(struct rtsx_pcr *pcr) +{ + u16 subvendor, subdevice, val; + + subvendor = pcr->pci->subsystem_vendor; + subdevice = pcr->pci->subsystem_device; + + if ((subvendor == 0x1028) && (subdevice == 0x0CE1)) { + rtsx_pci_read_phy_register(pcr, _PHY_REV0, &val); + if ((val & 0xFE00) > 0x3800) + rtsx_pci_update_phy(pcr, _PHY_REV0, 0x1FF, 0x3800); + } + + return 0; +} + static void rts5264_enable_aspm(struct rtsx_pcr *pcr, bool enable) { u8 val = FORCE_ASPM_CTL0 | FORCE_ASPM_CTL1; @@ -682,6 +698,7 @@ static const struct pcr_ops rts5264_pcr_ops = { .turn_on_led = rts5264_turn_on_led, .turn_off_led = rts5264_turn_off_led, .extra_init_hw = rts5264_extra_init_hw, + .optimize_phy = rts5264_optimize_phy, .enable_auto_blink = rts5264_enable_auto_blink, .disable_auto_blink = rts5264_disable_auto_blink, .card_power_on = rts5264_card_power_on, diff --git a/drivers/misc/cardreader/rtsx_pcr.c b/drivers/misc/cardreader/rtsx_pcr.c index be3d4e0e50cc..a7b066c48740 100644 --- a/drivers/misc/cardreader/rtsx_pcr.c +++ b/drivers/misc/cardreader/rtsx_pcr.c @@ -420,25 +420,6 @@ static void rtsx_pci_add_sg_tbl(struct rtsx_pcr *pcr, pcr->sgi++; } -int rtsx_pci_transfer_data(struct rtsx_pcr *pcr, struct scatterlist *sglist, - int num_sg, bool read, int timeout) -{ - int err = 0, count; - - pcr_dbg(pcr, "--> %s: num_sg = %d\n", __func__, num_sg); - count = rtsx_pci_dma_map_sg(pcr, sglist, num_sg, read); - if (count < 1) - return -EINVAL; - pcr_dbg(pcr, "DMA mapping count: %d\n", count); - - err = rtsx_pci_dma_transfer(pcr, sglist, count, read, timeout); - - rtsx_pci_dma_unmap_sg(pcr, sglist, num_sg, read); - - return err; -} -EXPORT_SYMBOL_GPL(rtsx_pci_transfer_data); - int rtsx_pci_dma_map_sg(struct rtsx_pcr *pcr, struct scatterlist *sglist, int num_sg, bool read) { @@ -1197,33 +1178,6 @@ void rtsx_pci_disable_oobs_polling(struct rtsx_pcr *pcr) } -int rtsx_sd_power_off_card3v3(struct rtsx_pcr *pcr) -{ - rtsx_pci_write_register(pcr, CARD_CLK_EN, SD_CLK_EN | - MS_CLK_EN | SD40_CLK_EN, 0); - rtsx_pci_write_register(pcr, CARD_OE, SD_OUTPUT_EN, 0); - rtsx_pci_card_power_off(pcr, RTSX_SD_CARD); - - msleep(50); - - rtsx_pci_card_pull_ctl_disable(pcr, RTSX_SD_CARD); - - return 0; -} - -int rtsx_ms_power_off_card3v3(struct rtsx_pcr *pcr) -{ - rtsx_pci_write_register(pcr, CARD_CLK_EN, SD_CLK_EN | - MS_CLK_EN | SD40_CLK_EN, 0); - - rtsx_pci_card_pull_ctl_disable(pcr, RTSX_MS_CARD); - - rtsx_pci_write_register(pcr, CARD_OE, MS_OUTPUT_EN, 0); - rtsx_pci_card_power_off(pcr, RTSX_MS_CARD); - - return 0; -} - static int rtsx_pci_init_hw(struct rtsx_pcr *pcr) { struct pci_dev *pdev = pcr->pci; diff --git a/drivers/misc/cardreader/rtsx_pcr.h b/drivers/misc/cardreader/rtsx_pcr.h index 9215d66de00c..8e5951b61143 100644 --- a/drivers/misc/cardreader/rtsx_pcr.h +++ b/drivers/misc/cardreader/rtsx_pcr.h @@ -127,7 +127,5 @@ int rtsx_pci_get_ocpstat(struct rtsx_pcr *pcr, u8 *val); void rtsx_pci_clear_ocpstat(struct rtsx_pcr *pcr); void rtsx_pci_enable_oobs_polling(struct rtsx_pcr *pcr); void rtsx_pci_disable_oobs_polling(struct rtsx_pcr *pcr); -int rtsx_sd_power_off_card3v3(struct rtsx_pcr *pcr); -int rtsx_ms_power_off_card3v3(struct rtsx_pcr *pcr); #endif diff --git a/drivers/misc/cardreader/rtsx_usb.c b/drivers/misc/cardreader/rtsx_usb.c index 7314c8d9ae75..148107a4547c 100644 --- a/drivers/misc/cardreader/rtsx_usb.c +++ b/drivers/misc/cardreader/rtsx_usb.c @@ -31,7 +31,7 @@ static const struct mfd_cell rtsx_usb_cells[] = { static void rtsx_usb_sg_timed_out(struct timer_list *t) { - struct rtsx_ucr *ucr = from_timer(ucr, t, sg_timer); + struct rtsx_ucr *ucr = timer_container_of(ucr, t, sg_timer); dev_dbg(&ucr->pusb_intf->dev, "%s: sg transfer timed out", __func__); usb_sg_cancel(&ucr->current_sg); diff --git a/drivers/misc/echo/Kconfig b/drivers/misc/echo/Kconfig deleted file mode 100644 index ce0a37a47fc1..000000000000 --- a/drivers/misc/echo/Kconfig +++ /dev/null @@ -1,9 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -config ECHO - tristate "Line Echo Canceller support" - help - This driver provides line echo cancelling support for mISDN and - Zaptel drivers. - - To compile this driver as a module, choose M here. The module - will be called echo. diff --git a/drivers/misc/echo/Makefile b/drivers/misc/echo/Makefile deleted file mode 100644 index 5b97467ffb7d..000000000000 --- a/drivers/misc/echo/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -obj-$(CONFIG_ECHO) += echo.o diff --git a/drivers/misc/echo/echo.c b/drivers/misc/echo/echo.c deleted file mode 100644 index 3c4eaba86576..000000000000 --- a/drivers/misc/echo/echo.c +++ /dev/null @@ -1,589 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * SpanDSP - a series of DSP components for telephony - * - * echo.c - A line echo canceller. This code is being developed - * against and partially complies with G168. - * - * Written by Steve Underwood <steveu@coppice.org> - * and David Rowe <david_at_rowetel_dot_com> - * - * Copyright (C) 2001, 2003 Steve Underwood, 2007 David Rowe - * - * Based on a bit from here, a bit from there, eye of toad, ear of - * bat, 15 years of failed attempts by David and a few fried brain - * cells. - * - * All rights reserved. - */ - -/*! \file */ - -/* Implementation Notes - David Rowe - April 2007 - - This code started life as Steve's NLMS algorithm with a tap - rotation algorithm to handle divergence during double talk. I - added a Geigel Double Talk Detector (DTD) [2] and performed some - G168 tests. However I had trouble meeting the G168 requirements, - especially for double talk - there were always cases where my DTD - failed, for example where near end speech was under the 6dB - threshold required for declaring double talk. - - So I tried a two path algorithm [1], which has so far given better - results. The original tap rotation/Geigel algorithm is available - in SVN http://svn.rowetel.com/software/oslec/tags/before_16bit. - It's probably possible to make it work if some one wants to put some - serious work into it. - - At present no special treatment is provided for tones, which - generally cause NLMS algorithms to diverge. Initial runs of a - subset of the G168 tests for tones (e.g ./echo_test 6) show the - current algorithm is passing OK, which is kind of surprising. The - full set of tests needs to be performed to confirm this result. - - One other interesting change is that I have managed to get the NLMS - code to work with 16 bit coefficients, rather than the original 32 - bit coefficents. This reduces the MIPs and storage required. - I evaulated the 16 bit port using g168_tests.sh and listening tests - on 4 real-world samples. - - I also attempted the implementation of a block based NLMS update - [2] but although this passes g168_tests.sh it didn't converge well - on the real-world samples. I have no idea why, perhaps a scaling - problem. The block based code is also available in SVN - http://svn.rowetel.com/software/oslec/tags/before_16bit. If this - code can be debugged, it will lead to further reduction in MIPS, as - the block update code maps nicely onto DSP instruction sets (it's a - dot product) compared to the current sample-by-sample update. - - Steve also has some nice notes on echo cancellers in echo.h - - References: - - [1] Ochiai, Areseki, and Ogihara, "Echo Canceller with Two Echo - Path Models", IEEE Transactions on communications, COM-25, - No. 6, June - 1977. - https://www.rowetel.com/images/echo/dual_path_paper.pdf - - [2] The classic, very useful paper that tells you how to - actually build a real world echo canceller: - Messerschmitt, Hedberg, Cole, Haoui, Winship, "Digital Voice - Echo Canceller with a TMS320020, - https://www.rowetel.com/images/echo/spra129.pdf - - [3] I have written a series of blog posts on this work, here is - Part 1: http://www.rowetel.com/blog/?p=18 - - [4] The source code http://svn.rowetel.com/software/oslec/ - - [5] A nice reference on LMS filters: - https://en.wikipedia.org/wiki/Least_mean_squares_filter - - Credits: - - Thanks to Steve Underwood, Jean-Marc Valin, and Ramakrishnan - Muthukrishnan for their suggestions and email discussions. Thanks - also to those people who collected echo samples for me such as - Mark, Pawel, and Pavel. -*/ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/slab.h> - -#include "echo.h" - -#define MIN_TX_POWER_FOR_ADAPTION 64 -#define MIN_RX_POWER_FOR_ADAPTION 64 -#define DTD_HANGOVER 600 /* 600 samples, or 75ms */ -#define DC_LOG2BETA 3 /* log2() of DC filter Beta */ - -/* adapting coeffs using the traditional stochastic descent (N)LMS algorithm */ - -static inline void lms_adapt_bg(struct oslec_state *ec, int clean, int shift) -{ - int i; - - int offset1; - int offset2; - int factor; - int exp; - - if (shift > 0) - factor = clean << shift; - else - factor = clean >> -shift; - - /* Update the FIR taps */ - - offset2 = ec->curr_pos; - offset1 = ec->taps - offset2; - - for (i = ec->taps - 1; i >= offset1; i--) { - exp = (ec->fir_state_bg.history[i - offset1] * factor); - ec->fir_taps16[1][i] += (int16_t) ((exp + (1 << 14)) >> 15); - } - for (; i >= 0; i--) { - exp = (ec->fir_state_bg.history[i + offset2] * factor); - ec->fir_taps16[1][i] += (int16_t) ((exp + (1 << 14)) >> 15); - } -} - -static inline int top_bit(unsigned int bits) -{ - if (bits == 0) - return -1; - else - return (int)fls((int32_t) bits) - 1; -} - -struct oslec_state *oslec_create(int len, int adaption_mode) -{ - struct oslec_state *ec; - int i; - const int16_t *history; - - ec = kzalloc(sizeof(*ec), GFP_KERNEL); - if (!ec) - return NULL; - - ec->taps = len; - ec->log2taps = top_bit(len); - ec->curr_pos = ec->taps - 1; - - ec->fir_taps16[0] = - kcalloc(ec->taps, sizeof(int16_t), GFP_KERNEL); - if (!ec->fir_taps16[0]) - goto error_oom_0; - - ec->fir_taps16[1] = - kcalloc(ec->taps, sizeof(int16_t), GFP_KERNEL); - if (!ec->fir_taps16[1]) - goto error_oom_1; - - history = fir16_create(&ec->fir_state, ec->fir_taps16[0], ec->taps); - if (!history) - goto error_state; - history = fir16_create(&ec->fir_state_bg, ec->fir_taps16[1], ec->taps); - if (!history) - goto error_state_bg; - - for (i = 0; i < 5; i++) - ec->xvtx[i] = ec->yvtx[i] = ec->xvrx[i] = ec->yvrx[i] = 0; - - ec->cng_level = 1000; - oslec_adaption_mode(ec, adaption_mode); - - ec->snapshot = kcalloc(ec->taps, sizeof(int16_t), GFP_KERNEL); - if (!ec->snapshot) - goto error_snap; - - ec->cond_met = 0; - ec->pstates = 0; - ec->ltxacc = ec->lrxacc = ec->lcleanacc = ec->lclean_bgacc = 0; - ec->ltx = ec->lrx = ec->lclean = ec->lclean_bg = 0; - ec->tx_1 = ec->tx_2 = ec->rx_1 = ec->rx_2 = 0; - ec->lbgn = ec->lbgn_acc = 0; - ec->lbgn_upper = 200; - ec->lbgn_upper_acc = ec->lbgn_upper << 13; - - return ec; - -error_snap: - fir16_free(&ec->fir_state_bg); -error_state_bg: - fir16_free(&ec->fir_state); -error_state: - kfree(ec->fir_taps16[1]); -error_oom_1: - kfree(ec->fir_taps16[0]); -error_oom_0: - kfree(ec); - return NULL; -} -EXPORT_SYMBOL_GPL(oslec_create); - -void oslec_free(struct oslec_state *ec) -{ - int i; - - fir16_free(&ec->fir_state); - fir16_free(&ec->fir_state_bg); - for (i = 0; i < 2; i++) - kfree(ec->fir_taps16[i]); - kfree(ec->snapshot); - kfree(ec); -} -EXPORT_SYMBOL_GPL(oslec_free); - -void oslec_adaption_mode(struct oslec_state *ec, int adaption_mode) -{ - ec->adaption_mode = adaption_mode; -} -EXPORT_SYMBOL_GPL(oslec_adaption_mode); - -void oslec_flush(struct oslec_state *ec) -{ - int i; - - ec->ltxacc = ec->lrxacc = ec->lcleanacc = ec->lclean_bgacc = 0; - ec->ltx = ec->lrx = ec->lclean = ec->lclean_bg = 0; - ec->tx_1 = ec->tx_2 = ec->rx_1 = ec->rx_2 = 0; - - ec->lbgn = ec->lbgn_acc = 0; - ec->lbgn_upper = 200; - ec->lbgn_upper_acc = ec->lbgn_upper << 13; - - ec->nonupdate_dwell = 0; - - fir16_flush(&ec->fir_state); - fir16_flush(&ec->fir_state_bg); - ec->fir_state.curr_pos = ec->taps - 1; - ec->fir_state_bg.curr_pos = ec->taps - 1; - for (i = 0; i < 2; i++) - memset(ec->fir_taps16[i], 0, ec->taps * sizeof(int16_t)); - - ec->curr_pos = ec->taps - 1; - ec->pstates = 0; -} -EXPORT_SYMBOL_GPL(oslec_flush); - -void oslec_snapshot(struct oslec_state *ec) -{ - memcpy(ec->snapshot, ec->fir_taps16[0], ec->taps * sizeof(int16_t)); -} -EXPORT_SYMBOL_GPL(oslec_snapshot); - -/* Dual Path Echo Canceller */ - -int16_t oslec_update(struct oslec_state *ec, int16_t tx, int16_t rx) -{ - int32_t echo_value; - int clean_bg; - int tmp; - int tmp1; - - /* - * Input scaling was found be required to prevent problems when tx - * starts clipping. Another possible way to handle this would be the - * filter coefficent scaling. - */ - - ec->tx = tx; - ec->rx = rx; - tx >>= 1; - rx >>= 1; - - /* - * Filter DC, 3dB point is 160Hz (I think), note 32 bit precision - * required otherwise values do not track down to 0. Zero at DC, Pole - * at (1-Beta) on real axis. Some chip sets (like Si labs) don't - * need this, but something like a $10 X100P card does. Any DC really - * slows down convergence. - * - * Note: removes some low frequency from the signal, this reduces the - * speech quality when listening to samples through headphones but may - * not be obvious through a telephone handset. - * - * Note that the 3dB frequency in radians is approx Beta, e.g. for Beta - * = 2^(-3) = 0.125, 3dB freq is 0.125 rads = 159Hz. - */ - - if (ec->adaption_mode & ECHO_CAN_USE_RX_HPF) { - tmp = rx << 15; - - /* - * Make sure the gain of the HPF is 1.0. This can still - * saturate a little under impulse conditions, and it might - * roll to 32768 and need clipping on sustained peak level - * signals. However, the scale of such clipping is small, and - * the error due to any saturation should not markedly affect - * the downstream processing. - */ - tmp -= (tmp >> 4); - - ec->rx_1 += -(ec->rx_1 >> DC_LOG2BETA) + tmp - ec->rx_2; - - /* - * hard limit filter to prevent clipping. Note that at this - * stage rx should be limited to +/- 16383 due to right shift - * above - */ - tmp1 = ec->rx_1 >> 15; - if (tmp1 > 16383) - tmp1 = 16383; - if (tmp1 < -16383) - tmp1 = -16383; - rx = tmp1; - ec->rx_2 = tmp; - } - - /* Block average of power in the filter states. Used for - adaption power calculation. */ - - { - int new, old; - - /* efficient "out with the old and in with the new" algorithm so - we don't have to recalculate over the whole block of - samples. */ - new = (int)tx * (int)tx; - old = (int)ec->fir_state.history[ec->fir_state.curr_pos] * - (int)ec->fir_state.history[ec->fir_state.curr_pos]; - ec->pstates += - ((new - old) + (1 << (ec->log2taps - 1))) >> ec->log2taps; - if (ec->pstates < 0) - ec->pstates = 0; - } - - /* Calculate short term average levels using simple single pole IIRs */ - - ec->ltxacc += abs(tx) - ec->ltx; - ec->ltx = (ec->ltxacc + (1 << 4)) >> 5; - ec->lrxacc += abs(rx) - ec->lrx; - ec->lrx = (ec->lrxacc + (1 << 4)) >> 5; - - /* Foreground filter */ - - ec->fir_state.coeffs = ec->fir_taps16[0]; - echo_value = fir16(&ec->fir_state, tx); - ec->clean = rx - echo_value; - ec->lcleanacc += abs(ec->clean) - ec->lclean; - ec->lclean = (ec->lcleanacc + (1 << 4)) >> 5; - - /* Background filter */ - - echo_value = fir16(&ec->fir_state_bg, tx); - clean_bg = rx - echo_value; - ec->lclean_bgacc += abs(clean_bg) - ec->lclean_bg; - ec->lclean_bg = (ec->lclean_bgacc + (1 << 4)) >> 5; - - /* Background Filter adaption */ - - /* Almost always adap bg filter, just simple DT and energy - detection to minimise adaption in cases of strong double talk. - However this is not critical for the dual path algorithm. - */ - ec->factor = 0; - ec->shift = 0; - if (!ec->nonupdate_dwell) { - int p, logp, shift; - - /* Determine: - - f = Beta * clean_bg_rx/P ------ (1) - - where P is the total power in the filter states. - - The Boffins have shown that if we obey (1) we converge - quickly and avoid instability. - - The correct factor f must be in Q30, as this is the fixed - point format required by the lms_adapt_bg() function, - therefore the scaled version of (1) is: - - (2^30) * f = (2^30) * Beta * clean_bg_rx/P - factor = (2^30) * Beta * clean_bg_rx/P ----- (2) - - We have chosen Beta = 0.25 by experiment, so: - - factor = (2^30) * (2^-2) * clean_bg_rx/P - - (30 - 2 - log2(P)) - factor = clean_bg_rx 2 ----- (3) - - To avoid a divide we approximate log2(P) as top_bit(P), - which returns the position of the highest non-zero bit in - P. This approximation introduces an error as large as a - factor of 2, but the algorithm seems to handle it OK. - - Come to think of it a divide may not be a big deal on a - modern DSP, so its probably worth checking out the cycles - for a divide versus a top_bit() implementation. - */ - - p = MIN_TX_POWER_FOR_ADAPTION + ec->pstates; - logp = top_bit(p) + ec->log2taps; - shift = 30 - 2 - logp; - ec->shift = shift; - - lms_adapt_bg(ec, clean_bg, shift); - } - - /* very simple DTD to make sure we dont try and adapt with strong - near end speech */ - - ec->adapt = 0; - if ((ec->lrx > MIN_RX_POWER_FOR_ADAPTION) && (ec->lrx > ec->ltx)) - ec->nonupdate_dwell = DTD_HANGOVER; - if (ec->nonupdate_dwell) - ec->nonupdate_dwell--; - - /* Transfer logic */ - - /* These conditions are from the dual path paper [1], I messed with - them a bit to improve performance. */ - - if ((ec->adaption_mode & ECHO_CAN_USE_ADAPTION) && - (ec->nonupdate_dwell == 0) && - /* (ec->Lclean_bg < 0.875*ec->Lclean) */ - (8 * ec->lclean_bg < 7 * ec->lclean) && - /* (ec->Lclean_bg < 0.125*ec->Ltx) */ - (8 * ec->lclean_bg < ec->ltx)) { - if (ec->cond_met == 6) { - /* - * BG filter has had better results for 6 consecutive - * samples - */ - ec->adapt = 1; - memcpy(ec->fir_taps16[0], ec->fir_taps16[1], - ec->taps * sizeof(int16_t)); - } else - ec->cond_met++; - } else - ec->cond_met = 0; - - /* Non-Linear Processing */ - - ec->clean_nlp = ec->clean; - if (ec->adaption_mode & ECHO_CAN_USE_NLP) { - /* - * Non-linear processor - a fancy way to say "zap small - * signals, to avoid residual echo due to (uLaw/ALaw) - * non-linearity in the channel.". - */ - - if ((16 * ec->lclean < ec->ltx)) { - /* - * Our e/c has improved echo by at least 24 dB (each - * factor of 2 is 6dB, so 2*2*2*2=16 is the same as - * 6+6+6+6=24dB) - */ - if (ec->adaption_mode & ECHO_CAN_USE_CNG) { - ec->cng_level = ec->lbgn; - - /* - * Very elementary comfort noise generation. - * Just random numbers rolled off very vaguely - * Hoth-like. DR: This noise doesn't sound - * quite right to me - I suspect there are some - * overflow issues in the filtering as it's too - * "crackly". - * TODO: debug this, maybe just play noise at - * high level or look at spectrum. - */ - - ec->cng_rndnum = - 1664525U * ec->cng_rndnum + 1013904223U; - ec->cng_filter = - ((ec->cng_rndnum & 0xFFFF) - 32768 + - 5 * ec->cng_filter) >> 3; - ec->clean_nlp = - (ec->cng_filter * ec->cng_level * 8) >> 14; - - } else if (ec->adaption_mode & ECHO_CAN_USE_CLIP) { - /* This sounds much better than CNG */ - if (ec->clean_nlp > ec->lbgn) - ec->clean_nlp = ec->lbgn; - if (ec->clean_nlp < -ec->lbgn) - ec->clean_nlp = -ec->lbgn; - } else { - /* - * just mute the residual, doesn't sound very - * good, used mainly in G168 tests - */ - ec->clean_nlp = 0; - } - } else { - /* - * Background noise estimator. I tried a few - * algorithms here without much luck. This very simple - * one seems to work best, we just average the level - * using a slow (1 sec time const) filter if the - * current level is less than a (experimentally - * derived) constant. This means we dont include high - * level signals like near end speech. When combined - * with CNG or especially CLIP seems to work OK. - */ - if (ec->lclean < 40) { - ec->lbgn_acc += abs(ec->clean) - ec->lbgn; - ec->lbgn = (ec->lbgn_acc + (1 << 11)) >> 12; - } - } - } - - /* Roll around the taps buffer */ - if (ec->curr_pos <= 0) - ec->curr_pos = ec->taps; - ec->curr_pos--; - - if (ec->adaption_mode & ECHO_CAN_DISABLE) - ec->clean_nlp = rx; - - /* Output scaled back up again to match input scaling */ - - return (int16_t) ec->clean_nlp << 1; -} -EXPORT_SYMBOL_GPL(oslec_update); - -/* This function is separated from the echo canceller is it is usually called - as part of the tx process. See rx HP (DC blocking) filter above, it's - the same design. - - Some soft phones send speech signals with a lot of low frequency - energy, e.g. down to 20Hz. This can make the hybrid non-linear - which causes the echo canceller to fall over. This filter can help - by removing any low frequency before it gets to the tx port of the - hybrid. - - It can also help by removing and DC in the tx signal. DC is bad - for LMS algorithms. - - This is one of the classic DC removal filters, adjusted to provide - sufficient bass rolloff to meet the above requirement to protect hybrids - from things that upset them. The difference between successive samples - produces a lousy HPF, and then a suitably placed pole flattens things out. - The final result is a nicely rolled off bass end. The filtering is - implemented with extended fractional precision, which noise shapes things, - giving very clean DC removal. -*/ - -int16_t oslec_hpf_tx(struct oslec_state *ec, int16_t tx) -{ - int tmp; - int tmp1; - - if (ec->adaption_mode & ECHO_CAN_USE_TX_HPF) { - tmp = tx << 15; - - /* - * Make sure the gain of the HPF is 1.0. The first can still - * saturate a little under impulse conditions, and it might - * roll to 32768 and need clipping on sustained peak level - * signals. However, the scale of such clipping is small, and - * the error due to any saturation should not markedly affect - * the downstream processing. - */ - tmp -= (tmp >> 4); - - ec->tx_1 += -(ec->tx_1 >> DC_LOG2BETA) + tmp - ec->tx_2; - tmp1 = ec->tx_1 >> 15; - if (tmp1 > 32767) - tmp1 = 32767; - if (tmp1 < -32767) - tmp1 = -32767; - tx = tmp1; - ec->tx_2 = tmp; - } - - return tx; -} -EXPORT_SYMBOL_GPL(oslec_hpf_tx); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("David Rowe"); -MODULE_DESCRIPTION("Open Source Line Echo Canceller"); -MODULE_VERSION("0.3.0"); diff --git a/drivers/misc/echo/echo.h b/drivers/misc/echo/echo.h deleted file mode 100644 index 56b4b95fd020..000000000000 --- a/drivers/misc/echo/echo.h +++ /dev/null @@ -1,175 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * SpanDSP - a series of DSP components for telephony - * - * echo.c - A line echo canceller. This code is being developed - * against and partially complies with G168. - * - * Written by Steve Underwood <steveu@coppice.org> - * and David Rowe <david_at_rowetel_dot_com> - * - * Copyright (C) 2001 Steve Underwood and 2007 David Rowe - * - * All rights reserved. - */ - -#ifndef __ECHO_H -#define __ECHO_H - -/* -Line echo cancellation for voice - -What does it do? - -This module aims to provide G.168-2002 compliant echo cancellation, to remove -electrical echoes (e.g. from 2-4 wire hybrids) from voice calls. - -How does it work? - -The heart of the echo cancellor is FIR filter. This is adapted to match the -echo impulse response of the telephone line. It must be long enough to -adequately cover the duration of that impulse response. The signal transmitted -to the telephone line is passed through the FIR filter. Once the FIR is -properly adapted, the resulting output is an estimate of the echo signal -received from the line. This is subtracted from the received signal. The result -is an estimate of the signal which originated at the far end of the line, free -from echos of our own transmitted signal. - -The least mean squares (LMS) algorithm is attributed to Widrow and Hoff, and -was introduced in 1960. It is the commonest form of filter adaption used in -things like modem line equalisers and line echo cancellers. There it works very -well. However, it only works well for signals of constant amplitude. It works -very poorly for things like speech echo cancellation, where the signal level -varies widely. This is quite easy to fix. If the signal level is normalised - -similar to applying AGC - LMS can work as well for a signal of varying -amplitude as it does for a modem signal. This normalised least mean squares -(NLMS) algorithm is the commonest one used for speech echo cancellation. Many -other algorithms exist - e.g. RLS (essentially the same as Kalman filtering), -FAP, etc. Some perform significantly better than NLMS. However, factors such -as computational complexity and patents favour the use of NLMS. - -A simple refinement to NLMS can improve its performance with speech. NLMS tends -to adapt best to the strongest parts of a signal. If the signal is white noise, -the NLMS algorithm works very well. However, speech has more low frequency than -high frequency content. Pre-whitening (i.e. filtering the signal to flatten its -spectrum) the echo signal improves the adapt rate for speech, and ensures the -final residual signal is not heavily biased towards high frequencies. A very -low complexity filter is adequate for this, so pre-whitening adds little to the -compute requirements of the echo canceller. - -An FIR filter adapted using pre-whitened NLMS performs well, provided certain -conditions are met: - - - The transmitted signal has poor self-correlation. - - There is no signal being generated within the environment being - cancelled. - -The difficulty is that neither of these can be guaranteed. - -If the adaption is performed while transmitting noise (or something fairly -noise like, such as voice) the adaption works very well. If the adaption is -performed while transmitting something highly correlative (typically narrow -band energy such as signalling tones or DTMF), the adaption can go seriously -wrong. The reason is there is only one solution for the adaption on a near -random signal - the impulse response of the line. For a repetitive signal, -there are any number of solutions which converge the adaption, and nothing -guides the adaption to choose the generalised one. Allowing an untrained -canceller to converge on this kind of narrowband energy probably a good thing, -since at least it cancels the tones. Allowing a well converged canceller to -continue converging on such energy is just a way to ruin its generalised -adaption. A narrowband detector is needed, so adapation can be suspended at -appropriate times. - -The adaption process is based on trying to eliminate the received signal. When -there is any signal from within the environment being cancelled it may upset -the adaption process. Similarly, if the signal we are transmitting is small, -noise may dominate and disturb the adaption process. If we can ensure that the -adaption is only performed when we are transmitting a significant signal level, -and the environment is not, things will be OK. Clearly, it is easy to tell when -we are sending a significant signal. Telling, if the environment is generating -a significant signal, and doing it with sufficient speed that the adaption will -not have diverged too much more we stop it, is a little harder. - -The key problem in detecting when the environment is sourcing significant -energy is that we must do this very quickly. Given a reasonably long sample of -the received signal, there are a number of strategies which may be used to -assess whether that signal contains a strong far end component. However, by the -time that assessment is complete the far end signal will have already caused -major mis-convergence in the adaption process. An assessment algorithm is -needed which produces a fairly accurate result from a very short burst of far -end energy. - -How do I use it? - -The echo cancellor processes both the transmit and receive streams sample by -sample. The processing function is not declared inline. Unfortunately, -cancellation requires many operations per sample, so the call overhead is only -a minor burden. -*/ - -#include "fir.h" -#include "oslec.h" - -/* - G.168 echo canceller descriptor. This defines the working state for a line - echo canceller. -*/ -struct oslec_state { - int16_t tx; - int16_t rx; - int16_t clean; - int16_t clean_nlp; - - int nonupdate_dwell; - int curr_pos; - int taps; - int log2taps; - int adaption_mode; - - int cond_met; - int32_t pstates; - int16_t adapt; - int32_t factor; - int16_t shift; - - /* Average levels and averaging filter states */ - int ltxacc; - int lrxacc; - int lcleanacc; - int lclean_bgacc; - int ltx; - int lrx; - int lclean; - int lclean_bg; - int lbgn; - int lbgn_acc; - int lbgn_upper; - int lbgn_upper_acc; - - /* foreground and background filter states */ - struct fir16_state_t fir_state; - struct fir16_state_t fir_state_bg; - int16_t *fir_taps16[2]; - - /* DC blocking filter states */ - int tx_1; - int tx_2; - int rx_1; - int rx_2; - - /* optional High Pass Filter states */ - int32_t xvtx[5]; - int32_t yvtx[5]; - int32_t xvrx[5]; - int32_t yvrx[5]; - - /* Parameters for the optional Hoth noise generator */ - int cng_level; - int cng_rndnum; - int cng_filter; - - /* snapshot sample of coeffs used for development */ - int16_t *snapshot; -}; - -#endif /* __ECHO_H */ diff --git a/drivers/misc/echo/fir.h b/drivers/misc/echo/fir.h deleted file mode 100644 index 4d0821025223..000000000000 --- a/drivers/misc/echo/fir.h +++ /dev/null @@ -1,154 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * SpanDSP - a series of DSP components for telephony - * - * fir.h - General telephony FIR routines - * - * Written by Steve Underwood <steveu@coppice.org> - * - * Copyright (C) 2002 Steve Underwood - * - * All rights reserved. - */ - -#if !defined(_FIR_H_) -#define _FIR_H_ - -/* - Ideas for improvement: - - 1/ Rewrite filter for dual MAC inner loop. The issue here is handling - history sample offsets that are 16 bit aligned - the dual MAC needs - 32 bit aligmnent. There are some good examples in libbfdsp. - - 2/ Use the hardware circular buffer facility tohalve memory usage. - - 3/ Consider using internal memory. - - Using less memory might also improve speed as cache misses will be - reduced. A drop in MIPs and memory approaching 50% should be - possible. - - The foreground and background filters currenlty use a total of - about 10 MIPs/ch as measured with speedtest.c on a 256 TAP echo - can. -*/ - -/* - * 16 bit integer FIR descriptor. This defines the working state for a single - * instance of an FIR filter using 16 bit integer coefficients. - */ -struct fir16_state_t { - int taps; - int curr_pos; - const int16_t *coeffs; - int16_t *history; -}; - -/* - * 32 bit integer FIR descriptor. This defines the working state for a single - * instance of an FIR filter using 32 bit integer coefficients, and filtering - * 16 bit integer data. - */ -struct fir32_state_t { - int taps; - int curr_pos; - const int32_t *coeffs; - int16_t *history; -}; - -/* - * Floating point FIR descriptor. This defines the working state for a single - * instance of an FIR filter using floating point coefficients and data. - */ -struct fir_float_state_t { - int taps; - int curr_pos; - const float *coeffs; - float *history; -}; - -static inline const int16_t *fir16_create(struct fir16_state_t *fir, - const int16_t *coeffs, int taps) -{ - fir->taps = taps; - fir->curr_pos = taps - 1; - fir->coeffs = coeffs; - fir->history = kcalloc(taps, sizeof(int16_t), GFP_KERNEL); - return fir->history; -} - -static inline void fir16_flush(struct fir16_state_t *fir) -{ - memset(fir->history, 0, fir->taps * sizeof(int16_t)); -} - -static inline void fir16_free(struct fir16_state_t *fir) -{ - kfree(fir->history); -} - -static inline int16_t fir16(struct fir16_state_t *fir, int16_t sample) -{ - int32_t y; - int i; - int offset1; - int offset2; - - fir->history[fir->curr_pos] = sample; - - offset2 = fir->curr_pos; - offset1 = fir->taps - offset2; - y = 0; - for (i = fir->taps - 1; i >= offset1; i--) - y += fir->coeffs[i] * fir->history[i - offset1]; - for (; i >= 0; i--) - y += fir->coeffs[i] * fir->history[i + offset2]; - if (fir->curr_pos <= 0) - fir->curr_pos = fir->taps; - fir->curr_pos--; - return (int16_t) (y >> 15); -} - -static inline const int16_t *fir32_create(struct fir32_state_t *fir, - const int32_t *coeffs, int taps) -{ - fir->taps = taps; - fir->curr_pos = taps - 1; - fir->coeffs = coeffs; - fir->history = kcalloc(taps, sizeof(int16_t), GFP_KERNEL); - return fir->history; -} - -static inline void fir32_flush(struct fir32_state_t *fir) -{ - memset(fir->history, 0, fir->taps * sizeof(int16_t)); -} - -static inline void fir32_free(struct fir32_state_t *fir) -{ - kfree(fir->history); -} - -static inline int16_t fir32(struct fir32_state_t *fir, int16_t sample) -{ - int i; - int32_t y; - int offset1; - int offset2; - - fir->history[fir->curr_pos] = sample; - offset2 = fir->curr_pos; - offset1 = fir->taps - offset2; - y = 0; - for (i = fir->taps - 1; i >= offset1; i--) - y += fir->coeffs[i] * fir->history[i - offset1]; - for (; i >= 0; i--) - y += fir->coeffs[i] * fir->history[i + offset2]; - if (fir->curr_pos <= 0) - fir->curr_pos = fir->taps; - fir->curr_pos--; - return (int16_t) (y >> 15); -} - -#endif diff --git a/drivers/misc/echo/oslec.h b/drivers/misc/echo/oslec.h deleted file mode 100644 index f1adac143b90..000000000000 --- a/drivers/misc/echo/oslec.h +++ /dev/null @@ -1,81 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * OSLEC - A line echo canceller. This code is being developed - * against and partially complies with G168. Using code from SpanDSP - * - * Written by Steve Underwood <steveu@coppice.org> - * and David Rowe <david_at_rowetel_dot_com> - * - * Copyright (C) 2001 Steve Underwood and 2007-2008 David Rowe - * - * All rights reserved. - */ - -#ifndef __OSLEC_H -#define __OSLEC_H - -/* Mask bits for the adaption mode */ -#define ECHO_CAN_USE_ADAPTION 0x01 -#define ECHO_CAN_USE_NLP 0x02 -#define ECHO_CAN_USE_CNG 0x04 -#define ECHO_CAN_USE_CLIP 0x08 -#define ECHO_CAN_USE_TX_HPF 0x10 -#define ECHO_CAN_USE_RX_HPF 0x20 -#define ECHO_CAN_DISABLE 0x40 - -/** - * oslec_state: G.168 echo canceller descriptor. - * - * This defines the working state for a line echo canceller. - */ -struct oslec_state; - -/** - * oslec_create - Create a voice echo canceller context. - * @len: The length of the canceller, in samples. - * @return: The new canceller context, or NULL if the canceller could not be - * created. - */ -struct oslec_state *oslec_create(int len, int adaption_mode); - -/** - * oslec_free - Free a voice echo canceller context. - * @ec: The echo canceller context. - */ -void oslec_free(struct oslec_state *ec); - -/** - * oslec_flush - Flush (reinitialise) a voice echo canceller context. - * @ec: The echo canceller context. - */ -void oslec_flush(struct oslec_state *ec); - -/** - * oslec_adaption_mode - set the adaption mode of a voice echo canceller context. - * @ec The echo canceller context. - * @adaption_mode: The mode. - */ -void oslec_adaption_mode(struct oslec_state *ec, int adaption_mode); - -void oslec_snapshot(struct oslec_state *ec); - -/** - * oslec_update: Process a sample through a voice echo canceller. - * @ec: The echo canceller context. - * @tx: The transmitted audio sample. - * @rx: The received audio sample. - * - * The return value is the clean (echo cancelled) received sample. - */ -int16_t oslec_update(struct oslec_state *ec, int16_t tx, int16_t rx); - -/** - * oslec_hpf_tx: Process to high pass filter the tx signal. - * @ec: The echo canceller context. - * @tx: The transmitted auio sample. - * - * The return value is the HP filtered transmit sample, send this to your D/A. - */ -int16_t oslec_hpf_tx(struct oslec_state *ec, int16_t tx); - -#endif /* __OSLEC_H */ diff --git a/drivers/misc/eeprom/idt_89hpesx.c b/drivers/misc/eeprom/idt_89hpesx.c index 1fc632ebf22f..60c42170d147 100644 --- a/drivers/misc/eeprom/idt_89hpesx.c +++ b/drivers/misc/eeprom/idt_89hpesx.c @@ -61,11 +61,6 @@ MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("T-platforms"); /* - * csr_dbgdir - CSR read/write operations Debugfs directory - */ -static struct dentry *csr_dbgdir; - -/* * struct idt_89hpesx_dev - IDT 89HPESx device data structure * @eesize: Size of EEPROM in bytes (calculated from "idt,eecompatible") * @eero: EEPROM Read-only flag @@ -1325,35 +1320,6 @@ static void idt_remove_sysfs_files(struct idt_89hpesx_dev *pdev) } /* - * idt_create_dbgfs_files() - create debugfs files - * @pdev: Pointer to the driver data - */ -#define CSRNAME_LEN ((size_t)32) -static void idt_create_dbgfs_files(struct idt_89hpesx_dev *pdev) -{ - struct i2c_client *cli = pdev->client; - char fname[CSRNAME_LEN]; - - /* Create Debugfs directory for CSR file */ - snprintf(fname, CSRNAME_LEN, "%d-%04hx", cli->adapter->nr, cli->addr); - pdev->csr_dir = debugfs_create_dir(fname, csr_dbgdir); - - /* Create Debugfs file for CSR read/write operations */ - debugfs_create_file(cli->name, 0600, pdev->csr_dir, pdev, - &csr_dbgfs_ops); -} - -/* - * idt_remove_dbgfs_files() - remove debugfs files - * @pdev: Pointer to the driver data - */ -static void idt_remove_dbgfs_files(struct idt_89hpesx_dev *pdev) -{ - /* Remove CSR directory and it sysfs-node */ - debugfs_remove_recursive(pdev->csr_dir); -} - -/* * idt_probe() - IDT 89HPESx driver probe() callback method */ static int idt_probe(struct i2c_client *client) @@ -1382,7 +1348,7 @@ static int idt_probe(struct i2c_client *client) goto err_free_pdev; /* Create debugfs files */ - idt_create_dbgfs_files(pdev); + debugfs_create_file(pdev->client->name, 0600, client->debugfs, pdev, &csr_dbgfs_ops); return 0; @@ -1399,9 +1365,6 @@ static void idt_remove(struct i2c_client *client) { struct idt_89hpesx_dev *pdev = i2c_get_clientdata(client); - /* Remove debugfs files first */ - idt_remove_dbgfs_files(pdev); - /* Remove sysfs files */ idt_remove_sysfs_files(pdev); @@ -1550,38 +1513,4 @@ static struct i2c_driver idt_driver = { .remove = idt_remove, .id_table = idt_ids, }; - -/* - * idt_init() - IDT 89HPESx driver init() callback method - */ -static int __init idt_init(void) -{ - int ret; - - /* Create Debugfs directory first */ - if (debugfs_initialized()) - csr_dbgdir = debugfs_create_dir("idt_csr", NULL); - - /* Add new i2c-device driver */ - ret = i2c_add_driver(&idt_driver); - if (ret) { - debugfs_remove_recursive(csr_dbgdir); - return ret; - } - - return 0; -} -module_init(idt_init); - -/* - * idt_exit() - IDT 89HPESx driver exit() callback method - */ -static void __exit idt_exit(void) -{ - /* Discard debugfs directory and all files if any */ - debugfs_remove_recursive(csr_dbgdir); - - /* Unregister i2c-device driver */ - i2c_del_driver(&idt_driver); -} -module_exit(idt_exit); +module_i2c_driver(idt_driver); diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c index 7b7a22c91fe4..378923594f02 100644 --- a/drivers/misc/fastrpc.c +++ b/drivers/misc/fastrpc.c @@ -2313,7 +2313,7 @@ static int fastrpc_rpmsg_probe(struct rpmsg_device *rpdev) rmem = of_reserved_mem_lookup(rmem_node); if (!rmem) { err = -EINVAL; - goto fdev_error; + goto err_free_data; } src_perms = BIT(QCOM_SCM_VMID_HLOS); @@ -2334,7 +2334,7 @@ static int fastrpc_rpmsg_probe(struct rpmsg_device *rpdev) data->unsigned_support = false; err = fastrpc_device_register(rdev, data, secure_dsp, domains[domain_id]); if (err) - goto fdev_error; + goto err_free_data; break; case CDSP_DOMAIN_ID: case CDSP1_DOMAIN_ID: @@ -2342,15 +2342,15 @@ static int fastrpc_rpmsg_probe(struct rpmsg_device *rpdev) /* Create both device nodes so that we can allow both Signed and Unsigned PD */ err = fastrpc_device_register(rdev, data, true, domains[domain_id]); if (err) - goto fdev_error; + goto err_free_data; err = fastrpc_device_register(rdev, data, false, domains[domain_id]); if (err) - goto populate_error; + goto err_deregister_fdev; break; default: err = -EINVAL; - goto fdev_error; + goto err_free_data; } kref_init(&data->refcount); @@ -2367,17 +2367,17 @@ static int fastrpc_rpmsg_probe(struct rpmsg_device *rpdev) err = of_platform_populate(rdev->of_node, NULL, NULL, rdev); if (err) - goto populate_error; + goto err_deregister_fdev; return 0; -populate_error: +err_deregister_fdev: if (data->fdevice) misc_deregister(&data->fdevice->miscdev); if (data->secure_fdevice) misc_deregister(&data->secure_fdevice->miscdev); -fdev_error: +err_free_data: kfree(data); return err; } diff --git a/drivers/misc/lis3lv02d/Kconfig b/drivers/misc/lis3lv02d/Kconfig index bb2fec4b5880..56005243a230 100644 --- a/drivers/misc/lis3lv02d/Kconfig +++ b/drivers/misc/lis3lv02d/Kconfig @@ -10,7 +10,7 @@ config SENSORS_LIS3_SPI help This driver provides support for the LIS3LV02Dx accelerometer connected via SPI. The accelerometer data is readable via - /sys/devices/platform/lis3lv02d. + /sys/devices/faux/lis3lv02d. This driver also provides an absolute input class device, allowing the laptop to act as a pinball machine-esque joystick. @@ -26,7 +26,7 @@ config SENSORS_LIS3_I2C help This driver provides support for the LIS3LV02Dx accelerometer connected via I2C. The accelerometer data is readable via - /sys/devices/platform/lis3lv02d. + /sys/devices/faux/lis3lv02d. This driver also provides an absolute input class device, allowing the device to act as a pinball machine-esque joystick. diff --git a/drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gpio.c b/drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gpio.c index 98d3d123004c..ff8f4404d10f 100644 --- a/drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gpio.c +++ b/drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gpio.c @@ -7,12 +7,14 @@ #include <linux/gpio/driver.h> #include <linux/bio.h> #include <linux/mutex.h> +#include <linux/pci.h> #include <linux/kthread.h> #include <linux/interrupt.h> #include "mchp_pci1xxxx_gp.h" #define PCI1XXXX_NR_PINS 93 +#define PCI_DEV_REV_OFFSET 0x08 #define PERI_GEN_RESET 0 #define OUT_EN_OFFSET(x) ((((x) / 32) * 4) + 0x400) #define INP_EN_OFFSET(x) ((((x) / 32) * 4) + 0x400 + 0x10) @@ -40,9 +42,27 @@ struct pci1xxxx_gpio { raw_spinlock_t wa_lock; struct gpio_chip gpio; spinlock_t lock; + u32 gpio_wake_mask[3]; int irq_base; + u8 dev_rev; }; +static int pci1xxxx_gpio_get_device_revision(struct pci1xxxx_gpio *priv) +{ + struct device *parent = priv->aux_dev->dev.parent; + struct pci_dev *pcidev = to_pci_dev(parent); + int ret; + u32 val; + + ret = pci_read_config_dword(pcidev, PCI_DEV_REV_OFFSET, &val); + if (ret) + return ret; + + priv->dev_rev = val; + + return 0; +} + static int pci1xxxx_gpio_get_direction(struct gpio_chip *gpio, unsigned int nr) { struct pci1xxxx_gpio *priv = gpiochip_get_data(gpio); @@ -115,8 +135,7 @@ static int pci1xxxx_gpio_direction_output(struct gpio_chip *gpio, return 0; } -static void pci1xxxx_gpio_set(struct gpio_chip *gpio, - unsigned int nr, int val) +static int pci1xxxx_gpio_set(struct gpio_chip *gpio, unsigned int nr, int val) { struct pci1xxxx_gpio *priv = gpiochip_get_data(gpio); unsigned long flags; @@ -124,6 +143,8 @@ static void pci1xxxx_gpio_set(struct gpio_chip *gpio, spin_lock_irqsave(&priv->lock, flags); pci1xxx_assign_bit(priv->reg_base, OUT_OFFSET(nr), (nr % 32), val); spin_unlock_irqrestore(&priv->lock, flags); + + return 0; } static int pci1xxxx_gpio_set_config(struct gpio_chip *gpio, unsigned int offset, @@ -253,6 +274,22 @@ static int pci1xxxx_gpio_set_type(struct irq_data *data, unsigned int trigger_ty return true; } +static int pci1xxxx_gpio_set_wake(struct irq_data *data, unsigned int enable) +{ + struct gpio_chip *chip = irq_data_get_irq_chip_data(data); + struct pci1xxxx_gpio *priv = gpiochip_get_data(chip); + unsigned int gpio = irqd_to_hwirq(data); + unsigned int bitpos = gpio % 32; + unsigned int bank = gpio / 32; + + if (enable) + priv->gpio_wake_mask[bank] |= (1 << bitpos); + else + priv->gpio_wake_mask[bank] &= ~(1 << bitpos); + + return 0; +} + static irqreturn_t pci1xxxx_gpio_irq_handler(int irq, void *dev_id) { struct pci1xxxx_gpio *priv = dev_id; @@ -300,6 +337,7 @@ static const struct irq_chip pci1xxxx_gpio_irqchip = { .irq_mask = pci1xxxx_gpio_irq_mask, .irq_unmask = pci1xxxx_gpio_irq_unmask, .irq_set_type = pci1xxxx_gpio_set_type, + .irq_set_wake = pci1xxxx_gpio_set_wake, .flags = IRQCHIP_IMMUTABLE, GPIOCHIP_IRQ_RESOURCE_HELPERS, }; @@ -307,32 +345,83 @@ static const struct irq_chip pci1xxxx_gpio_irqchip = { static int pci1xxxx_gpio_suspend(struct device *dev) { struct pci1xxxx_gpio *priv = dev_get_drvdata(dev); + struct device *parent = priv->aux_dev->dev.parent; + struct pci_dev *pcidev = to_pci_dev(parent); + unsigned int gpio_bank_base; + unsigned int wake_mask; + unsigned int gpiobank; unsigned long flags; + for (gpiobank = 0; gpiobank < 3; gpiobank++) { + wake_mask = priv->gpio_wake_mask[gpiobank]; + + if (wake_mask) { + gpio_bank_base = gpiobank * 32; + + pci1xxx_assign_bit(priv->reg_base, + PIO_PCI_CTRL_REG_OFFSET, 0, true); + writel(~wake_mask, priv->reg_base + + WAKEMASK_OFFSET(gpio_bank_base)); + } + } + spin_lock_irqsave(&priv->lock, flags); pci1xxx_assign_bit(priv->reg_base, PIO_GLOBAL_CONFIG_OFFSET, 16, true); pci1xxx_assign_bit(priv->reg_base, PIO_GLOBAL_CONFIG_OFFSET, 17, false); pci1xxx_assign_bit(priv->reg_base, PERI_GEN_RESET, 16, true); + + if (priv->dev_rev >= 0xC0) + pci1xxx_assign_bit(priv->reg_base, PERI_GEN_RESET, 17, true); + spin_unlock_irqrestore(&priv->lock, flags); + device_set_wakeup_enable(&pcidev->dev, true); + pci_wake_from_d3(pcidev, true); + return 0; } static int pci1xxxx_gpio_resume(struct device *dev) { struct pci1xxxx_gpio *priv = dev_get_drvdata(dev); + struct device *parent = priv->aux_dev->dev.parent; + struct pci_dev *pcidev = to_pci_dev(parent); + unsigned int gpio_bank_base; + unsigned int wake_mask; + unsigned int gpiobank; unsigned long flags; + for (gpiobank = 0; gpiobank < 3; gpiobank++) { + wake_mask = priv->gpio_wake_mask[gpiobank]; + + if (wake_mask) { + gpio_bank_base = gpiobank * 32; + + writel(wake_mask, priv->reg_base + + INTR_STAT_OFFSET(gpio_bank_base)); + pci1xxx_assign_bit(priv->reg_base, + PIO_PCI_CTRL_REG_OFFSET, 0, false); + writel(0xffffffff, priv->reg_base + + WAKEMASK_OFFSET(gpio_bank_base)); + } + } + spin_lock_irqsave(&priv->lock, flags); pci1xxx_assign_bit(priv->reg_base, PIO_GLOBAL_CONFIG_OFFSET, 17, true); pci1xxx_assign_bit(priv->reg_base, PIO_GLOBAL_CONFIG_OFFSET, 16, false); pci1xxx_assign_bit(priv->reg_base, PERI_GEN_RESET, 16, false); + + if (priv->dev_rev >= 0xC0) + pci1xxx_assign_bit(priv->reg_base, PERI_GEN_RESET, 17, false); + spin_unlock_irqrestore(&priv->lock, flags); + pci_wake_from_d3(pcidev, false); + return 0; } @@ -349,7 +438,7 @@ static int pci1xxxx_gpio_setup(struct pci1xxxx_gpio *priv, int irq) gchip->direction_output = pci1xxxx_gpio_direction_output; gchip->get_direction = pci1xxxx_gpio_get_direction; gchip->get = pci1xxxx_gpio_get; - gchip->set = pci1xxxx_gpio_set; + gchip->set_rv = pci1xxxx_gpio_set; gchip->set_config = pci1xxxx_gpio_set_config; gchip->dbg_show = NULL; gchip->base = -1; @@ -412,6 +501,10 @@ static int pci1xxxx_gpio_probe(struct auxiliary_device *aux_dev, if (retval < 0) return retval; + retval = pci1xxxx_gpio_get_device_revision(priv); + if (retval) + return retval; + dev_set_drvdata(&aux_dev->dev, priv); return devm_gpiochip_add_data(&aux_dev->dev, &priv->gpio, priv); diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c index b09b79fedaba..c484f416fae4 100644 --- a/drivers/misc/mei/interrupt.c +++ b/drivers/misc/mei/interrupt.c @@ -133,7 +133,7 @@ static int mei_cl_irq_read_msg(struct mei_cl *cl, break; case MEI_EXT_HDR_GSC: gsc_f2h = (struct mei_ext_hdr_gsc_f2h *)ext; - cb->ext_hdr = kzalloc(sizeof(*gsc_f2h), GFP_KERNEL); + cb->ext_hdr = (struct mei_ext_hdr *)kzalloc(sizeof(*gsc_f2h), GFP_KERNEL); if (!cb->ext_hdr) { cb->status = -ENOMEM; goto discard; diff --git a/drivers/misc/mei/vsc-tp.c b/drivers/misc/mei/vsc-tp.c index da26a080916c..267d0de5fade 100644 --- a/drivers/misc/mei/vsc-tp.c +++ b/drivers/misc/mei/vsc-tp.c @@ -324,7 +324,7 @@ int vsc_tp_rom_xfer(struct vsc_tp *tp, const void *obuf, void *ibuf, size_t len) guard(mutex)(&tp->mutex); /* rom xfer is big endian */ - cpu_to_be32_array((u32 *)tp->tx_buf, obuf, words); + cpu_to_be32_array((__be32 *)tp->tx_buf, obuf, words); ret = read_poll_timeout(gpiod_get_value_cansleep, ret, !ret, VSC_TP_ROM_XFER_POLL_DELAY_US, @@ -340,7 +340,7 @@ int vsc_tp_rom_xfer(struct vsc_tp *tp, const void *obuf, void *ibuf, size_t len) return ret; if (ibuf) - be32_to_cpu_array(ibuf, (u32 *)tp->rx_buf, words); + be32_to_cpu_array(ibuf, (__be32 *)tp->rx_buf, words); return ret; } diff --git a/drivers/misc/sgi-xp/xpc_main.c b/drivers/misc/sgi-xp/xpc_main.c index 697a008c14d3..9fe816bf3957 100644 --- a/drivers/misc/sgi-xp/xpc_main.c +++ b/drivers/misc/sgi-xp/xpc_main.c @@ -164,7 +164,8 @@ struct xpc_arch_operations xpc_arch_ops; static void xpc_timeout_partition_disengage(struct timer_list *t) { - struct xpc_partition *part = from_timer(part, t, disengage_timer); + struct xpc_partition *part = timer_container_of(part, t, + disengage_timer); DBUG_ON(time_is_after_jiffies(part->disengage_timeout)); diff --git a/drivers/misc/tps6594-pfsm.c b/drivers/misc/tps6594-pfsm.c index 0a24ce44cc37..6db1c9d48f8f 100644 --- a/drivers/misc/tps6594-pfsm.c +++ b/drivers/misc/tps6594-pfsm.c @@ -281,6 +281,9 @@ static int tps6594_pfsm_probe(struct platform_device *pdev) pfsm->miscdev.minor = MISC_DYNAMIC_MINOR; pfsm->miscdev.name = devm_kasprintf(dev, GFP_KERNEL, "pfsm-%ld-0x%02x", tps->chip_id, tps->reg); + if (!pfsm->miscdev.name) + return -ENOMEM; + pfsm->miscdev.fops = &tps6594_pfsm_fops; pfsm->miscdev.parent = dev->parent; pfsm->chip_id = tps->chip_id; diff --git a/drivers/misc/vmw_vmci/vmci_host.c b/drivers/misc/vmw_vmci/vmci_host.c index abe79f6fd2a7..b64944367ac5 100644 --- a/drivers/misc/vmw_vmci/vmci_host.c +++ b/drivers/misc/vmw_vmci/vmci_host.c @@ -227,6 +227,7 @@ static int drv_cp_harray_to_user(void __user *user_buf_uva, static int vmci_host_setup_notify(struct vmci_ctx *context, unsigned long uva) { + struct page *page; int retval; if (context->notify_page) { @@ -243,13 +244,11 @@ static int vmci_host_setup_notify(struct vmci_ctx *context, /* * Lock physical page backing a given user VA. */ - retval = get_user_pages_fast(uva, 1, FOLL_WRITE, &context->notify_page); - if (retval != 1) { - context->notify_page = NULL; + retval = get_user_pages_fast(uva, 1, FOLL_WRITE, &page); + if (retval != 1) return VMCI_ERROR_GENERIC; - } - if (context->notify_page == NULL) - return VMCI_ERROR_UNAVAILABLE; + + context->notify_page = page; /* * Map the locked page and set up notify pointer. diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index dacb5bd9bb71..f14671ea5716 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -212,7 +212,7 @@ out: static void mmc_retune_timer(struct timer_list *t) { - struct mmc_host *host = from_timer(host, t, retune_timer); + struct mmc_host *host = timer_container_of(host, t, retune_timer); mmc_retune_needed(host); } diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index 14e981b834b6..0e0666c0bb6e 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -714,7 +714,7 @@ static inline unsigned int atmci_convert_chksize(struct atmel_mci *host, static void atmci_timeout_timer(struct timer_list *t) { - struct atmel_mci *host = from_timer(host, t, timer); + struct atmel_mci *host = timer_container_of(host, t, timer); struct device *dev = host->dev; dev_dbg(dev, "software timeout\n"); @@ -1652,7 +1652,8 @@ static void atmci_command_complete(struct atmel_mci *host, static void atmci_detect_change(struct timer_list *t) { - struct atmel_mci_slot *slot = from_timer(slot, t, detect_timer); + struct atmel_mci_slot *slot = timer_container_of(slot, t, + detect_timer); bool present; bool present_old; diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 2bfcc47dcf3e..988492237707 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -3179,7 +3179,7 @@ no_dma: static void dw_mci_cmd11_timer(struct timer_list *t) { - struct dw_mci *host = from_timer(host, t, cmd11_timer); + struct dw_mci *host = timer_container_of(host, t, cmd11_timer); if (host->state != STATE_SENDING_CMD11) { dev_warn(host->dev, "Unexpected CMD11 timeout\n"); @@ -3193,7 +3193,7 @@ static void dw_mci_cmd11_timer(struct timer_list *t) static void dw_mci_cto_timer(struct timer_list *t) { - struct dw_mci *host = from_timer(host, t, cto_timer); + struct dw_mci *host = timer_container_of(host, t, cto_timer); unsigned long irqflags; u32 pending; @@ -3248,7 +3248,7 @@ exit: static void dw_mci_dto_timer(struct timer_list *t) { - struct dw_mci *host = from_timer(host, t, dto_timer); + struct dw_mci *host = timer_container_of(host, t, dto_timer); unsigned long irqflags; u32 pending; diff --git a/drivers/mmc/host/jz4740_mmc.c b/drivers/mmc/host/jz4740_mmc.c index bd1662e275d4..0fbbf57db52e 100644 --- a/drivers/mmc/host/jz4740_mmc.c +++ b/drivers/mmc/host/jz4740_mmc.c @@ -641,7 +641,8 @@ poll_timeout: static void jz4740_mmc_timeout(struct timer_list *t) { - struct jz4740_mmc_host *host = from_timer(host, t, timeout_timer); + struct jz4740_mmc_host *host = timer_container_of(host, t, + timeout_timer); if (!test_and_clear_bit(0, &host->waiting)) return; diff --git a/drivers/mmc/host/meson-mx-sdio.c b/drivers/mmc/host/meson-mx-sdio.c index e0ae5a0c9670..8a49c32fd3f9 100644 --- a/drivers/mmc/host/meson-mx-sdio.c +++ b/drivers/mmc/host/meson-mx-sdio.c @@ -467,7 +467,8 @@ static irqreturn_t meson_mx_mmc_irq_thread(int irq, void *irq_data) static void meson_mx_mmc_timeout(struct timer_list *t) { - struct meson_mx_mmc_host *host = from_timer(host, t, cmd_timeout); + struct meson_mx_mmc_host *host = timer_container_of(host, t, + cmd_timeout); unsigned long irqflags; u32 irqc; diff --git a/drivers/mmc/host/mvsdio.c b/drivers/mmc/host/mvsdio.c index 912ffacbad88..101f36de7b63 100644 --- a/drivers/mmc/host/mvsdio.c +++ b/drivers/mmc/host/mvsdio.c @@ -509,7 +509,7 @@ static irqreturn_t mvsd_irq(int irq, void *dev) static void mvsd_timeout_timer(struct timer_list *t) { - struct mvsd_host *host = from_timer(host, t, timer); + struct mvsd_host *host = timer_container_of(host, t, timer); void __iomem *iobase = host->base; struct mmc_request *mrq; unsigned long flags; diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c index 95d8d40a06a8..e588e24256cc 100644 --- a/drivers/mmc/host/mxcmmc.c +++ b/drivers/mmc/host/mxcmmc.c @@ -955,7 +955,7 @@ static bool filter(struct dma_chan *chan, void *param) static void mxcmci_watchdog(struct timer_list *t) { - struct mxcmci_host *host = from_timer(host, t, watchdog); + struct mxcmci_host *host = timer_container_of(host, t, watchdog); struct mmc_request *req = host->req; unsigned int stat = mxcmci_readl(host, MMC_REG_STATUS); diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c index c50617d03709..c2be0f04439d 100644 --- a/drivers/mmc/host/omap.c +++ b/drivers/mmc/host/omap.c @@ -639,7 +639,8 @@ static void mmc_omap_abort_command(struct work_struct *work) static void mmc_omap_cmd_timer(struct timer_list *t) { - struct mmc_omap_host *host = from_timer(host, t, cmd_abort_timer); + struct mmc_omap_host *host = timer_container_of(host, t, + cmd_abort_timer); unsigned long flags; spin_lock_irqsave(&host->slot_lock, flags); @@ -655,7 +656,7 @@ mmc_omap_cmd_timer(struct timer_list *t) static void mmc_omap_clk_timer(struct timer_list *t) { - struct mmc_omap_host *host = from_timer(host, t, clk_timer); + struct mmc_omap_host *host = timer_container_of(host, t, clk_timer); mmc_omap_fclk_enable(host, 0); } @@ -879,7 +880,7 @@ void omap_mmc_notify_cover_event(struct device *dev, int num, int is_closed) static void mmc_omap_cover_timer(struct timer_list *t) { - struct mmc_omap_slot *slot = from_timer(slot, t, cover_timer); + struct mmc_omap_slot *slot = timer_container_of(slot, t, cover_timer); queue_work(system_bh_wq, &slot->cover_bh_work); } diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 32fa0b2bb912..f008167d1863 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -3245,7 +3245,7 @@ static void sdhci_timeout_timer(struct timer_list *t) struct sdhci_host *host; unsigned long flags; - host = from_timer(host, t, timer); + host = timer_container_of(host, t, timer); spin_lock_irqsave(&host->lock, flags); @@ -3267,7 +3267,7 @@ static void sdhci_timeout_data_timer(struct timer_list *t) struct sdhci_host *host; unsigned long flags; - host = from_timer(host, t, data_timer); + host = timer_container_of(host, t, data_timer); spin_lock_irqsave(&host->lock, flags); diff --git a/drivers/mmc/host/tifm_sd.c b/drivers/mmc/host/tifm_sd.c index 713223f2d377..5e5ec92f80e6 100644 --- a/drivers/mmc/host/tifm_sd.c +++ b/drivers/mmc/host/tifm_sd.c @@ -777,7 +777,7 @@ static void tifm_sd_end_cmd(struct work_struct *t) static void tifm_sd_abort(struct timer_list *t) { - struct tifm_sd *host = from_timer(host, t, timer); + struct tifm_sd *host = timer_container_of(host, t, timer); pr_err("%s : card failed to respond for a long period of time " "(%x, %x)\n", diff --git a/drivers/mmc/host/via-sdmmc.c b/drivers/mmc/host/via-sdmmc.c index 909d80a02824..9903966c2f54 100644 --- a/drivers/mmc/host/via-sdmmc.c +++ b/drivers/mmc/host/via-sdmmc.c @@ -937,7 +937,7 @@ static void via_sdc_timeout(struct timer_list *t) struct via_crdr_mmc_host *sdhost; unsigned long flags; - sdhost = from_timer(sdhost, t, timer); + sdhost = timer_container_of(sdhost, t, timer); spin_lock_irqsave(&sdhost->lock, flags); diff --git a/drivers/mmc/host/vub300.c b/drivers/mmc/host/vub300.c index dd71e5b8e1a5..f498fe11ecdf 100644 --- a/drivers/mmc/host/vub300.c +++ b/drivers/mmc/host/vub300.c @@ -740,8 +740,8 @@ static void vub300_deadwork_thread(struct work_struct *work) static void vub300_inactivity_timer_expired(struct timer_list *t) { /* softirq */ - struct vub300_mmc_host *vub300 = from_timer(vub300, t, - inactivity_timer); + struct vub300_mmc_host *vub300 = timer_container_of(vub300, t, + inactivity_timer); if (!vub300->interface) { kref_put(&vub300->kref, vub300_delete); } else if (vub300->cmd) { @@ -1180,8 +1180,8 @@ static void send_command(struct vub300_mmc_host *vub300) */ static void vub300_sg_timed_out(struct timer_list *t) { - struct vub300_mmc_host *vub300 = from_timer(vub300, t, - sg_transfer_timer); + struct vub300_mmc_host *vub300 = timer_container_of(vub300, t, + sg_transfer_timer); vub300->usb_timed_out = 1; usb_sg_cancel(&vub300->sg_request); usb_unlink_urb(vub300->command_out_urb); diff --git a/drivers/mmc/host/wbsd.c b/drivers/mmc/host/wbsd.c index d5974b355a5a..2ae787d966de 100644 --- a/drivers/mmc/host/wbsd.c +++ b/drivers/mmc/host/wbsd.c @@ -947,7 +947,7 @@ static const struct mmc_host_ops wbsd_ops = { static void wbsd_reset_ignore(struct timer_list *t) { - struct wbsd_host *host = from_timer(host, t, ignore_timer); + struct wbsd_host *host = timer_container_of(host, t, ignore_timer); BUG_ON(host == NULL); diff --git a/drivers/most/most_usb.c b/drivers/most/most_usb.c index 2199ba821922..cf5be9c449a5 100644 --- a/drivers/most/most_usb.c +++ b/drivers/most/most_usb.c @@ -667,7 +667,7 @@ static void hdm_request_netinfo(struct most_interface *iface, int channel, */ static void link_stat_timer_handler(struct timer_list *t) { - struct most_dev *mdev = from_timer(mdev, t, link_stat_timer); + struct most_dev *mdev = timer_container_of(mdev, t, link_stat_timer); schedule_work(&mdev->poll_work_obj); mdev->link_stat_timer.expires = jiffies + (2 * HZ); diff --git a/drivers/mtd/sm_ftl.c b/drivers/mtd/sm_ftl.c index d28d4f1790f5..abc7b186353f 100644 --- a/drivers/mtd/sm_ftl.c +++ b/drivers/mtd/sm_ftl.c @@ -993,7 +993,7 @@ restart: /* flush timer, runs a second after last write */ static void sm_cache_flush_timer(struct timer_list *t) { - struct sm_ftl *ftl = from_timer(ftl, t, timer); + struct sm_ftl *ftl = timer_container_of(ftl, t, timer); queue_work(cache_flush_workqueue, &ftl->flush_work); } diff --git a/drivers/mux/adg792a.c b/drivers/mux/adg792a.c index 4da5aecb9fc6..a5afe29e3cf1 100644 --- a/drivers/mux/adg792a.c +++ b/drivers/mux/adg792a.c @@ -141,7 +141,7 @@ MODULE_DEVICE_TABLE(of, adg792a_of_match); static struct i2c_driver adg792a_driver = { .driver = { .name = "adg792a", - .of_match_table = of_match_ptr(adg792a_of_match), + .of_match_table = adg792a_of_match, }, .probe = adg792a_probe, .id_table = adg792a_id, diff --git a/drivers/mux/adgs1408.c b/drivers/mux/adgs1408.c index 22ed051eb1a4..5eaf07d09ac9 100644 --- a/drivers/mux/adgs1408.c +++ b/drivers/mux/adgs1408.c @@ -59,9 +59,7 @@ static int adgs1408_probe(struct spi_device *spi) s32 idle_state; int ret; - chip_id = (enum adgs1408_chip_id)device_get_match_data(dev); - if (!chip_id) - chip_id = spi_get_device_id(spi)->driver_data; + chip_id = (kernel_ulong_t)spi_get_device_match_data(spi); mux_chip = devm_mux_chip_alloc(dev, 1, 0); if (IS_ERR(mux_chip)) diff --git a/drivers/mux/gpio.c b/drivers/mux/gpio.c index 5710879cd47f..4cc3202c58f3 100644 --- a/drivers/mux/gpio.c +++ b/drivers/mux/gpio.c @@ -15,6 +15,7 @@ #include <linux/mux/driver.h> #include <linux/platform_device.h> #include <linux/property.h> +#include <linux/regulator/consumer.h> struct mux_gpio { struct gpio_descs *gpios; @@ -80,6 +81,10 @@ static int mux_gpio_probe(struct platform_device *pdev) mux_chip->mux->idle_state = idle_state; } + ret = devm_regulator_get_enable_optional(dev, "mux"); + if (ret && ret != -ENODEV) + return dev_err_probe(dev, ret, "failed to get/enable mux supply\n"); + ret = devm_mux_chip_register(dev, mux_chip); if (ret < 0) return ret; diff --git a/drivers/mux/mmio.c b/drivers/mux/mmio.c index 30a952c34365..9993ce38a818 100644 --- a/drivers/mux/mmio.c +++ b/drivers/mux/mmio.c @@ -33,6 +33,12 @@ static const struct of_device_id mux_mmio_dt_ids[] = { }; MODULE_DEVICE_TABLE(of, mux_mmio_dt_ids); +static const struct regmap_config mux_mmio_regmap_cfg = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, +}; + static int mux_mmio_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -40,6 +46,7 @@ static int mux_mmio_probe(struct platform_device *pdev) struct regmap_field **fields; struct mux_chip *mux_chip; struct regmap *regmap; + void __iomem *base; int num_fields; int ret; int i; @@ -47,7 +54,11 @@ static int mux_mmio_probe(struct platform_device *pdev) if (of_device_is_compatible(np, "mmio-mux")) { regmap = syscon_node_to_regmap(np->parent); } else { - regmap = device_node_to_regmap(np); + base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(base)) + regmap = ERR_PTR(-ENODEV); + else + regmap = regmap_init_mmio(dev, base, &mux_mmio_regmap_cfg); /* Fallback to checking the parent node on "real" errors. */ if (IS_ERR(regmap) && regmap != ERR_PTR(-EPROBE_DEFER)) { regmap = dev_get_regmap(dev->parent, NULL); @@ -107,7 +118,7 @@ static int mux_mmio_probe(struct platform_device *pdev) fields[i] = devm_regmap_field_alloc(dev, regmap, field); if (IS_ERR(fields[i])) { ret = PTR_ERR(fields[i]); - dev_err(dev, "bitfield %d: failed allocate: %d\n", + dev_err(dev, "bitfield %d: failed to allocate: %d\n", i, ret); return ret; } diff --git a/drivers/net/arcnet/arcnet.c b/drivers/net/arcnet/arcnet.c index 602e6e1adf00..882972604c82 100644 --- a/drivers/net/arcnet/arcnet.c +++ b/drivers/net/arcnet/arcnet.c @@ -382,7 +382,7 @@ static void arcdev_setup(struct net_device *dev) static void arcnet_timer(struct timer_list *t) { - struct arcnet_local *lp = from_timer(lp, t, timer); + struct arcnet_local *lp = timer_container_of(lp, t, timer); struct net_device *dev = lp->dev; spin_lock_irq(&lp->lock); diff --git a/drivers/net/can/grcan.c b/drivers/net/can/grcan.c index adf3970f070f..c5784d9779ef 100644 --- a/drivers/net/can/grcan.c +++ b/drivers/net/can/grcan.c @@ -806,7 +806,7 @@ static irqreturn_t grcan_interrupt(int irq, void *dev_id) */ static void grcan_running_reset(struct timer_list *t) { - struct grcan_priv *priv = from_timer(priv, t, rr_timer); + struct grcan_priv *priv = timer_container_of(priv, t, rr_timer); struct net_device *dev = priv->dev; struct grcan_registers __iomem *regs = priv->regs; unsigned long flags; @@ -897,7 +897,7 @@ static inline void grcan_reset_timer(struct timer_list *timer, __u32 bitrate) /* Disable channels and schedule a running reset */ static void grcan_initiate_running_reset(struct timer_list *t) { - struct grcan_priv *priv = from_timer(priv, t, hang_timer); + struct grcan_priv *priv = timer_container_of(priv, t, hang_timer); struct net_device *dev = priv->dev; struct grcan_registers __iomem *regs = priv->regs; unsigned long flags; diff --git a/drivers/net/can/kvaser_pciefd.c b/drivers/net/can/kvaser_pciefd.c index 52301511ed1b..09510663988c 100644 --- a/drivers/net/can/kvaser_pciefd.c +++ b/drivers/net/can/kvaser_pciefd.c @@ -937,7 +937,8 @@ static int kvaser_pciefd_get_berr_counter(const struct net_device *ndev, static void kvaser_pciefd_bec_poll_timer(struct timer_list *data) { - struct kvaser_pciefd_can *can = from_timer(can, data, bec_poll_timer); + struct kvaser_pciefd_can *can = timer_container_of(can, data, + bec_poll_timer); kvaser_pciefd_enable_err_gen(can); kvaser_pciefd_request_status(can); diff --git a/drivers/net/can/sja1000/peak_pcmcia.c b/drivers/net/can/sja1000/peak_pcmcia.c index 6c7b1c58f85f..ce18e9e56059 100644 --- a/drivers/net/can/sja1000/peak_pcmcia.c +++ b/drivers/net/can/sja1000/peak_pcmcia.c @@ -374,7 +374,7 @@ static inline void pcan_set_can_power(struct pcan_pccard *card, int onoff) */ static void pcan_led_timer(struct timer_list *t) { - struct pcan_pccard *card = from_timer(card, t, led_timer); + struct pcan_pccard *card = timer_container_of(card, t, led_timer); struct net_device *netdev; int i, up_count = 0; u8 ccr; diff --git a/drivers/net/can/usb/peak_usb/pcan_usb.c b/drivers/net/can/usb/peak_usb/pcan_usb.c index c75df1755b3b..6b293a9056c2 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb.c @@ -319,7 +319,7 @@ static int pcan_usb_write_mode(struct peak_usb_device *dev, u8 onoff) */ static void pcan_usb_restart(struct timer_list *t) { - struct pcan_usb *pdev = from_timer(pdev, t, restart_timer); + struct pcan_usb *pdev = timer_container_of(pdev, t, restart_timer); struct peak_usb_device *dev = &pdev->dev; /* notify candev and netdev */ diff --git a/drivers/net/dsa/mv88e6xxx/phy.c b/drivers/net/dsa/mv88e6xxx/phy.c index b6d249eb64e7..4e7827ee684a 100644 --- a/drivers/net/dsa/mv88e6xxx/phy.c +++ b/drivers/net/dsa/mv88e6xxx/phy.c @@ -182,7 +182,7 @@ static void mv88e6xxx_phy_ppu_reenable_work(struct work_struct *ugly) static void mv88e6xxx_phy_ppu_reenable_timer(struct timer_list *t) { - struct mv88e6xxx_chip *chip = from_timer(chip, t, ppu_timer); + struct mv88e6xxx_chip *chip = timer_container_of(chip, t, ppu_timer); schedule_work(&chip->ppu_work); } diff --git a/drivers/net/eql.c b/drivers/net/eql.c index 5889759b8d83..9ba10efd3794 100644 --- a/drivers/net/eql.c +++ b/drivers/net/eql.c @@ -143,7 +143,7 @@ static void eql_kill_one_slave(slave_queue_t *queue, slave_t *slave); static void eql_timer(struct timer_list *t) { - equalizer_t *eql = from_timer(eql, t, timer); + equalizer_t *eql = timer_container_of(eql, t, timer); struct list_head *this, *tmp, *head; spin_lock(&eql->queue.lock); diff --git a/drivers/net/ethernet/3com/3c515.c b/drivers/net/ethernet/3com/3c515.c index 8ba2ed87fe7c..ecdea58e6a21 100644 --- a/drivers/net/ethernet/3com/3c515.c +++ b/drivers/net/ethernet/3com/3c515.c @@ -859,7 +859,7 @@ static int corkscrew_open(struct net_device *dev) static void corkscrew_timer(struct timer_list *t) { #ifdef AUTOMEDIA - struct corkscrew_private *vp = from_timer(vp, t, timer); + struct corkscrew_private *vp = timer_container_of(vp, t, timer); struct net_device *dev = vp->our_dev; int ioaddr = dev->base_addr; unsigned long flags; diff --git a/drivers/net/ethernet/3com/3c574_cs.c b/drivers/net/ethernet/3com/3c574_cs.c index b295d528a237..1f2070497a75 100644 --- a/drivers/net/ethernet/3com/3c574_cs.c +++ b/drivers/net/ethernet/3com/3c574_cs.c @@ -858,7 +858,7 @@ static irqreturn_t el3_interrupt(int irq, void *dev_id) */ static void media_check(struct timer_list *t) { - struct el3_private *lp = from_timer(lp, t, media); + struct el3_private *lp = timer_container_of(lp, t, media); struct net_device *dev = lp->p_dev->priv; unsigned int ioaddr = dev->base_addr; unsigned long flags; diff --git a/drivers/net/ethernet/3com/3c589_cs.c b/drivers/net/ethernet/3com/3c589_cs.c index ff331a3bde73..ea49be43b8c3 100644 --- a/drivers/net/ethernet/3com/3c589_cs.c +++ b/drivers/net/ethernet/3com/3c589_cs.c @@ -685,7 +685,7 @@ static irqreturn_t el3_interrupt(int irq, void *dev_id) static void media_check(struct timer_list *t) { - struct el3_private *lp = from_timer(lp, t, media); + struct el3_private *lp = timer_container_of(lp, t, media); struct net_device *dev = lp->p_dev->priv; unsigned int ioaddr = dev->base_addr; u16 media, errs; diff --git a/drivers/net/ethernet/3com/3c59x.c b/drivers/net/ethernet/3com/3c59x.c index 1a10f5dbc4d7..8c9cc97efd4e 100644 --- a/drivers/net/ethernet/3com/3c59x.c +++ b/drivers/net/ethernet/3com/3c59x.c @@ -1783,7 +1783,7 @@ out: static void vortex_timer(struct timer_list *t) { - struct vortex_private *vp = from_timer(vp, t, timer); + struct vortex_private *vp = timer_container_of(vp, t, timer); struct net_device *dev = vp->mii.dev; void __iomem *ioaddr = vp->ioaddr; int next_tick = 60*HZ; diff --git a/drivers/net/ethernet/8390/axnet_cs.c b/drivers/net/ethernet/8390/axnet_cs.c index e5be5044e1d4..7c8213011b5c 100644 --- a/drivers/net/ethernet/8390/axnet_cs.c +++ b/drivers/net/ethernet/8390/axnet_cs.c @@ -550,7 +550,7 @@ static irqreturn_t ei_irq_wrapper(int irq, void *dev_id) static void ei_watchdog(struct timer_list *t) { - struct axnet_dev *info = from_timer(info, t, watchdog); + struct axnet_dev *info = timer_container_of(info, t, watchdog); struct net_device *dev = info->p_dev->priv; unsigned int nic_base = dev->base_addr; unsigned int mii_addr = nic_base + AXNET_MII_EEP; diff --git a/drivers/net/ethernet/8390/pcnet_cs.c b/drivers/net/ethernet/8390/pcnet_cs.c index a326f25dda09..19f9c5db3f3b 100644 --- a/drivers/net/ethernet/8390/pcnet_cs.c +++ b/drivers/net/ethernet/8390/pcnet_cs.c @@ -1018,7 +1018,7 @@ static irqreturn_t ei_irq_wrapper(int irq, void *dev_id) static void ei_watchdog(struct timer_list *t) { - struct pcnet_dev *info = from_timer(info, t, watchdog); + struct pcnet_dev *info = timer_container_of(info, t, watchdog); struct net_device *dev = info->p_dev->priv; unsigned int nic_base = dev->base_addr; unsigned int mii_addr = nic_base + DLINK_GPIO; diff --git a/drivers/net/ethernet/agere/et131x.c b/drivers/net/ethernet/agere/et131x.c index b398adacda91..678eddb36172 100644 --- a/drivers/net/ethernet/agere/et131x.c +++ b/drivers/net/ethernet/agere/et131x.c @@ -3076,7 +3076,8 @@ err_out: */ static void et131x_error_timer_handler(struct timer_list *t) { - struct et131x_adapter *adapter = from_timer(adapter, t, error_timer); + struct et131x_adapter *adapter = timer_container_of(adapter, t, + error_timer); struct phy_device *phydev = adapter->netdev->phydev; if (et1310_in_phy_coma(adapter)) { diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c index 7d9ee9867a40..86fd08f375df 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.c +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c @@ -3667,7 +3667,8 @@ static void ena_update_host_info(struct ena_admin_host_info *host_info, static void ena_timer_service(struct timer_list *t) { - struct ena_adapter *adapter = from_timer(adapter, t, timer_service); + struct ena_adapter *adapter = timer_container_of(adapter, t, + timer_service); u8 *debug_area = adapter->ena_dev->host_attr.debug_area_virt_addr; struct ena_admin_host_info *host_info = adapter->ena_dev->host_attr.host_info; diff --git a/drivers/net/ethernet/amd/a2065.c b/drivers/net/ethernet/amd/a2065.c index b923ad9e1581..ce9445425045 100644 --- a/drivers/net/ethernet/amd/a2065.c +++ b/drivers/net/ethernet/amd/a2065.c @@ -636,7 +636,7 @@ static void lance_set_multicast(struct net_device *dev) static void lance_set_multicast_retry(struct timer_list *t) { - struct lance_private *lp = from_timer(lp, t, multicast_timer); + struct lance_private *lp = timer_container_of(lp, t, multicast_timer); lance_set_multicast(lp->dev); } diff --git a/drivers/net/ethernet/amd/amd8111e.c b/drivers/net/ethernet/amd/amd8111e.c index 86522e8574cb..76e8c13d5985 100644 --- a/drivers/net/ethernet/amd/amd8111e.c +++ b/drivers/net/ethernet/amd/amd8111e.c @@ -1641,7 +1641,8 @@ static int __maybe_unused amd8111e_resume(struct device *dev_d) static void amd8111e_config_ipg(struct timer_list *t) { - struct amd8111e_priv *lp = from_timer(lp, t, ipg_data.ipg_timer); + struct amd8111e_priv *lp = timer_container_of(lp, t, + ipg_data.ipg_timer); struct ipg_info *ipg_data = &lp->ipg_data; void __iomem *mmio = lp->mmio; unsigned int prev_col_cnt = ipg_data->col_cnt; diff --git a/drivers/net/ethernet/amd/declance.c b/drivers/net/ethernet/amd/declance.c index b072ca5930fc..8d05a0c5f2d5 100644 --- a/drivers/net/ethernet/amd/declance.c +++ b/drivers/net/ethernet/amd/declance.c @@ -1004,7 +1004,7 @@ static void lance_set_multicast(struct net_device *dev) static void lance_set_multicast_retry(struct timer_list *t) { - struct lance_private *lp = from_timer(lp, t, multicast_timer); + struct lance_private *lp = timer_container_of(lp, t, multicast_timer); struct net_device *dev = lp->dev; lance_set_multicast(dev); diff --git a/drivers/net/ethernet/amd/pcnet32.c b/drivers/net/ethernet/amd/pcnet32.c index e5adafecc686..9eaefa0f5e80 100644 --- a/drivers/net/ethernet/amd/pcnet32.c +++ b/drivers/net/ethernet/amd/pcnet32.c @@ -2905,7 +2905,7 @@ static void pcnet32_check_media(struct net_device *dev, int verbose) static void pcnet32_watchdog(struct timer_list *t) { - struct pcnet32_private *lp = from_timer(lp, t, watchdog_timer); + struct pcnet32_private *lp = timer_container_of(lp, t, watchdog_timer); struct net_device *dev = lp->dev; unsigned long flags; diff --git a/drivers/net/ethernet/amd/pds_core/main.c b/drivers/net/ethernet/amd/pds_core/main.c index 4843f9249a31..9b81e1c260c2 100644 --- a/drivers/net/ethernet/amd/pds_core/main.c +++ b/drivers/net/ethernet/amd/pds_core/main.c @@ -23,7 +23,7 @@ MODULE_DEVICE_TABLE(pci, pdsc_id_table); static void pdsc_wdtimer_cb(struct timer_list *t) { - struct pdsc *pdsc = from_timer(pdsc, t, wdtimer); + struct pdsc *pdsc = timer_container_of(pdsc, t, wdtimer); dev_dbg(pdsc->dev, "%s: jiffies %ld\n", __func__, jiffies); mod_timer(&pdsc->wdtimer, diff --git a/drivers/net/ethernet/amd/sunlance.c b/drivers/net/ethernet/amd/sunlance.c index 3cd31855a5f6..0b273327f5a6 100644 --- a/drivers/net/ethernet/amd/sunlance.c +++ b/drivers/net/ethernet/amd/sunlance.c @@ -1246,7 +1246,7 @@ static void lance_set_multicast(struct net_device *dev) static void lance_set_multicast_retry(struct timer_list *t) { - struct lance_private *lp = from_timer(lp, t, multicast_timer); + struct lance_private *lp = timer_container_of(lp, t, multicast_timer); struct net_device *dev = lp->dev; lance_set_multicast(dev); diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c index 76c328721fcd..65447f9a0a59 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c @@ -534,7 +534,8 @@ static irqreturn_t xgbe_dma_isr(int irq, void *data) static void xgbe_tx_timer(struct timer_list *t) { - struct xgbe_channel *channel = from_timer(channel, t, tx_timer); + struct xgbe_channel *channel = timer_container_of(channel, t, + tx_timer); struct xgbe_prv_data *pdata = channel->pdata; struct napi_struct *napi; @@ -572,7 +573,8 @@ static void xgbe_service(struct work_struct *work) static void xgbe_service_timer(struct timer_list *t) { - struct xgbe_prv_data *pdata = from_timer(pdata, t, service_timer); + struct xgbe_prv_data *pdata = timer_container_of(pdata, t, + service_timer); struct xgbe_channel *channel; unsigned int i; diff --git a/drivers/net/ethernet/apple/bmac.c b/drivers/net/ethernet/apple/bmac.c index b50052c25a91..b3bf8d6f88e8 100644 --- a/drivers/net/ethernet/apple/bmac.c +++ b/drivers/net/ethernet/apple/bmac.c @@ -1410,7 +1410,7 @@ bmac_output(struct sk_buff *skb, struct net_device *dev) static void bmac_tx_timeout(struct timer_list *t) { - struct bmac_data *bp = from_timer(bp, t, tx_timeout); + struct bmac_data *bp = timer_container_of(bp, t, tx_timeout); struct net_device *dev = macio_get_drvdata(bp->mdev); volatile struct dbdma_regs __iomem *td = bp->tx_dma; volatile struct dbdma_regs __iomem *rd = bp->rx_dma; diff --git a/drivers/net/ethernet/apple/mace.c b/drivers/net/ethernet/apple/mace.c index 1fed112f4e68..af26905e44e3 100644 --- a/drivers/net/ethernet/apple/mace.c +++ b/drivers/net/ethernet/apple/mace.c @@ -805,7 +805,7 @@ static irqreturn_t mace_interrupt(int irq, void *dev_id) static void mace_tx_timeout(struct timer_list *t) { - struct mace_data *mp = from_timer(mp, t, tx_timeout); + struct mace_data *mp = timer_container_of(mp, t, tx_timeout); struct net_device *dev = macio_get_drvdata(mp->mdev); volatile struct mace __iomem *mb = mp->mace; volatile struct dbdma_regs __iomem *td = mp->tx_dma; diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c index e71cd10e4e1f..b24eaa5283fa 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c @@ -254,7 +254,7 @@ static void aq_nic_service_task(struct work_struct *work) static void aq_nic_service_timer_cb(struct timer_list *t) { - struct aq_nic_s *self = from_timer(self, t, service_timer); + struct aq_nic_s *self = timer_container_of(self, t, service_timer); mod_timer(&self->service_timer, jiffies + AQ_CFG_SERVICE_TIMER_INTERVAL); @@ -264,7 +264,7 @@ static void aq_nic_service_timer_cb(struct timer_list *t) static void aq_nic_polling_timer_cb(struct timer_list *t) { - struct aq_nic_s *self = from_timer(self, t, polling_timer); + struct aq_nic_s *self = timer_container_of(self, t, polling_timer); unsigned int i = 0U; for (i = 0U; self->aq_vecs > i; ++i) diff --git a/drivers/net/ethernet/atheros/ag71xx.c b/drivers/net/ethernet/atheros/ag71xx.c index 67b654889cae..d8e6f23e1432 100644 --- a/drivers/net/ethernet/atheros/ag71xx.c +++ b/drivers/net/ethernet/atheros/ag71xx.c @@ -1563,7 +1563,7 @@ err_drop: static void ag71xx_oom_timer_handler(struct timer_list *t) { - struct ag71xx *ag = from_timer(ag, t, oom_timer); + struct ag71xx *ag = timer_container_of(ag, t, oom_timer); napi_schedule(&ag->napi); } diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c index 82137f9deae9..ef1a51347351 100644 --- a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c +++ b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c @@ -231,8 +231,8 @@ static u32 atl1c_wait_until_idle(struct atl1c_hw *hw, u32 modu_ctrl) */ static void atl1c_phy_config(struct timer_list *t) { - struct atl1c_adapter *adapter = from_timer(adapter, t, - phy_config_timer); + struct atl1c_adapter *adapter = timer_container_of(adapter, t, + phy_config_timer); struct atl1c_hw *hw = &adapter->hw; unsigned long flags; diff --git a/drivers/net/ethernet/atheros/atl1e/atl1e_main.c b/drivers/net/ethernet/atheros/atl1e/atl1e_main.c index f664a0edbc49..40290028580b 100644 --- a/drivers/net/ethernet/atheros/atl1e/atl1e_main.c +++ b/drivers/net/ethernet/atheros/atl1e/atl1e_main.c @@ -115,8 +115,8 @@ static inline void atl1e_irq_reset(struct atl1e_adapter *adapter) */ static void atl1e_phy_config(struct timer_list *t) { - struct atl1e_adapter *adapter = from_timer(adapter, t, - phy_config_timer); + struct atl1e_adapter *adapter = timer_container_of(adapter, t, + phy_config_timer); struct atl1e_hw *hw = &adapter->hw; unsigned long flags; diff --git a/drivers/net/ethernet/atheros/atlx/atl1.c b/drivers/net/ethernet/atheros/atlx/atl1.c index 38cd84b7677c..cfdb546a09e7 100644 --- a/drivers/net/ethernet/atheros/atlx/atl1.c +++ b/drivers/net/ethernet/atheros/atlx/atl1.c @@ -2556,8 +2556,8 @@ static irqreturn_t atl1_intr(int irq, void *data) */ static void atl1_phy_config(struct timer_list *t) { - struct atl1_adapter *adapter = from_timer(adapter, t, - phy_config_timer); + struct atl1_adapter *adapter = timer_container_of(adapter, t, + phy_config_timer); struct atl1_hw *hw = &adapter->hw; unsigned long flags; diff --git a/drivers/net/ethernet/atheros/atlx/atl2.c b/drivers/net/ethernet/atheros/atlx/atl2.c index 88f65f8cf4d3..280e2f5f4aa5 100644 --- a/drivers/net/ethernet/atheros/atlx/atl2.c +++ b/drivers/net/ethernet/atheros/atlx/atl2.c @@ -1010,7 +1010,8 @@ static void atl2_tx_timeout(struct net_device *netdev, unsigned int txqueue) */ static void atl2_watchdog(struct timer_list *t) { - struct atl2_adapter *adapter = from_timer(adapter, t, watchdog_timer); + struct atl2_adapter *adapter = timer_container_of(adapter, t, + watchdog_timer); if (!test_bit(__ATL2_DOWN, &adapter->flags)) { u32 drop_rxd, drop_rxs; @@ -1035,8 +1036,8 @@ static void atl2_watchdog(struct timer_list *t) */ static void atl2_phy_config(struct timer_list *t) { - struct atl2_adapter *adapter = from_timer(adapter, t, - phy_config_timer); + struct atl2_adapter *adapter = timer_container_of(adapter, t, + phy_config_timer); struct atl2_hw *hw = &adapter->hw; unsigned long flags; diff --git a/drivers/net/ethernet/broadcom/b44.c b/drivers/net/ethernet/broadcom/b44.c index c91884373429..8267417b3750 100644 --- a/drivers/net/ethernet/broadcom/b44.c +++ b/drivers/net/ethernet/broadcom/b44.c @@ -575,7 +575,7 @@ static void b44_check_phy(struct b44 *bp) static void b44_timer(struct timer_list *t) { - struct b44 *bp = from_timer(bp, t, timer); + struct b44 *bp = timer_container_of(bp, t, timer); spin_lock_irq(&bp->lock); diff --git a/drivers/net/ethernet/broadcom/bcm63xx_enet.c b/drivers/net/ethernet/broadcom/bcm63xx_enet.c index 19611bdd86e6..92204fea1f08 100644 --- a/drivers/net/ethernet/broadcom/bcm63xx_enet.c +++ b/drivers/net/ethernet/broadcom/bcm63xx_enet.c @@ -286,7 +286,7 @@ static int bcm_enet_refill_rx(struct net_device *dev, bool napi_mode) */ static void bcm_enet_refill_rx_timer(struct timer_list *t) { - struct bcm_enet_priv *priv = from_timer(priv, t, rx_timeout); + struct bcm_enet_priv *priv = timer_container_of(priv, t, rx_timeout); struct net_device *dev = priv->net_dev; spin_lock(&priv->rx_lock); @@ -2001,7 +2001,7 @@ static inline int bcm_enet_port_is_rgmii(int portid) */ static void swphy_poll_timer(struct timer_list *t) { - struct bcm_enet_priv *priv = from_timer(priv, t, swphy_poll); + struct bcm_enet_priv *priv = timer_container_of(priv, t, swphy_poll); unsigned int i; for (i = 0; i < priv->num_ports; i++) { diff --git a/drivers/net/ethernet/broadcom/bnx2.c b/drivers/net/ethernet/broadcom/bnx2.c index ec0c9584f3bb..cb1011f6fd30 100644 --- a/drivers/net/ethernet/broadcom/bnx2.c +++ b/drivers/net/ethernet/broadcom/bnx2.c @@ -6163,7 +6163,7 @@ bnx2_5708_serdes_timer(struct bnx2 *bp) static void bnx2_timer(struct timer_list *t) { - struct bnx2 *bp = from_timer(bp, t, timer); + struct bnx2 *bp = timer_container_of(bp, t, timer); if (!netif_running(bp->dev)) return; diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index f522ca8ff66b..c9a1a1d504c0 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -5783,7 +5783,7 @@ void bnx2x_drv_pulse(struct bnx2x *bp) static void bnx2x_timer(struct timer_list *t) { - struct bnx2x *bp = from_timer(bp, t, timer); + struct bnx2x *bp = timer_container_of(bp, t, timer); if (!netif_running(bp->dev)) return; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index d5495762c945..869580b6f70d 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -13995,7 +13995,7 @@ fw_reset: static void bnxt_timer(struct timer_list *t) { - struct bnxt *bp = from_timer(bp, t, timer); + struct bnxt *bp = timer_container_of(bp, t, timer); struct net_device *dev = bp->dev; if (!netif_running(dev) || !test_bit(BNXT_STATE_OPEN, &bp->state)) diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index ff47e96b9124..91104cc2c238 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -11062,7 +11062,7 @@ static void tg3_chk_missed_msi(struct tg3 *tp) static void tg3_timer(struct timer_list *t) { - struct tg3 *tp = from_timer(tp, t, timer); + struct tg3 *tp = timer_container_of(tp, t, timer); spin_lock(&tp->lock); diff --git a/drivers/net/ethernet/brocade/bna/bnad.c b/drivers/net/ethernet/brocade/bna/bnad.c index 50eb54ecf1ba..9bed33295839 100644 --- a/drivers/net/ethernet/brocade/bna/bnad.c +++ b/drivers/net/ethernet/brocade/bna/bnad.c @@ -1688,7 +1688,8 @@ err_return: static void bnad_ioc_timeout(struct timer_list *t) { - struct bnad *bnad = from_timer(bnad, t, bna.ioceth.ioc.ioc_timer); + struct bnad *bnad = timer_container_of(bnad, t, + bna.ioceth.ioc.ioc_timer); unsigned long flags; spin_lock_irqsave(&bnad->bna_lock, flags); @@ -1699,7 +1700,8 @@ bnad_ioc_timeout(struct timer_list *t) static void bnad_ioc_hb_check(struct timer_list *t) { - struct bnad *bnad = from_timer(bnad, t, bna.ioceth.ioc.hb_timer); + struct bnad *bnad = timer_container_of(bnad, t, + bna.ioceth.ioc.hb_timer); unsigned long flags; spin_lock_irqsave(&bnad->bna_lock, flags); @@ -1710,7 +1712,8 @@ bnad_ioc_hb_check(struct timer_list *t) static void bnad_iocpf_timeout(struct timer_list *t) { - struct bnad *bnad = from_timer(bnad, t, bna.ioceth.ioc.iocpf_timer); + struct bnad *bnad = timer_container_of(bnad, t, + bna.ioceth.ioc.iocpf_timer); unsigned long flags; spin_lock_irqsave(&bnad->bna_lock, flags); @@ -1721,7 +1724,8 @@ bnad_iocpf_timeout(struct timer_list *t) static void bnad_iocpf_sem_timeout(struct timer_list *t) { - struct bnad *bnad = from_timer(bnad, t, bna.ioceth.ioc.sem_timer); + struct bnad *bnad = timer_container_of(bnad, t, + bna.ioceth.ioc.sem_timer); unsigned long flags; spin_lock_irqsave(&bnad->bna_lock, flags); @@ -1743,7 +1747,7 @@ bnad_iocpf_sem_timeout(struct timer_list *t) static void bnad_dim_timeout(struct timer_list *t) { - struct bnad *bnad = from_timer(bnad, t, dim_timer); + struct bnad *bnad = timer_container_of(bnad, t, dim_timer); struct bnad_rx_info *rx_info; struct bnad_rx_ctrl *rx_ctrl; int i, j; @@ -1776,7 +1780,7 @@ bnad_dim_timeout(struct timer_list *t) static void bnad_stats_timeout(struct timer_list *t) { - struct bnad *bnad = from_timer(bnad, t, stats_timer); + struct bnad *bnad = timer_container_of(bnad, t, stats_timer); unsigned long flags; if (!netif_running(bnad->netdev) || diff --git a/drivers/net/ethernet/chelsio/cxgb/sge.c b/drivers/net/ethernet/chelsio/cxgb/sge.c index a10923c7e25c..5f354cf62cdd 100644 --- a/drivers/net/ethernet/chelsio/cxgb/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb/sge.c @@ -1922,7 +1922,7 @@ send: static void sge_tx_reclaim_cb(struct timer_list *t) { int i; - struct sge *sge = from_timer(sge, t, tx_reclaim_timer); + struct sge *sge = timer_container_of(sge, t, tx_reclaim_timer); for (i = 0; i < SGE_CMDQ_N; ++i) { struct cmdQ *q = &sge->cmdQ[i]; @@ -2017,7 +2017,7 @@ void t1_sge_start(struct sge *sge) */ static void espibug_workaround_t204(struct timer_list *t) { - struct sge *sge = from_timer(sge, t, espibug_timer); + struct sge *sge = timer_container_of(sge, t, espibug_timer); struct adapter *adapter = sge->adapter; unsigned int nports = adapter->params.nports; u32 seop[MAX_NPORTS]; @@ -2060,7 +2060,7 @@ static void espibug_workaround_t204(struct timer_list *t) static void espibug_workaround(struct timer_list *t) { - struct sge *sge = from_timer(sge, t, espibug_timer); + struct sge *sge = timer_container_of(sge, t, espibug_timer); struct adapter *adapter = sge->adapter; if (netif_running(adapter->port[0].dev)) { diff --git a/drivers/net/ethernet/chelsio/cxgb3/sge.c b/drivers/net/ethernet/chelsio/cxgb3/sge.c index bd5c3b3fa5e3..b59735d0e065 100644 --- a/drivers/net/ethernet/chelsio/cxgb3/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb3/sge.c @@ -2906,7 +2906,7 @@ void t3_sge_err_intr_handler(struct adapter *adapter) */ static void sge_timer_tx(struct timer_list *t) { - struct sge_qset *qs = from_timer(qs, t, tx_reclaim_timer); + struct sge_qset *qs = timer_container_of(qs, t, tx_reclaim_timer); struct port_info *pi = netdev_priv(qs->netdev); struct adapter *adap = pi->adapter; unsigned int tbd[SGE_TXQ_PER_SET] = {0, 0}; @@ -2947,7 +2947,7 @@ static void sge_timer_tx(struct timer_list *t) static void sge_timer_rx(struct timer_list *t) { spinlock_t *lock; - struct sge_qset *qs = from_timer(qs, t, rx_reclaim_timer); + struct sge_qset *qs = timer_container_of(qs, t, rx_reclaim_timer); struct port_info *pi = netdev_priv(qs->netdev); struct adapter *adap = pi->adapter; u32 status; diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c index 69d045d769c4..0765d000eaef 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c @@ -1051,7 +1051,7 @@ static void ch_flower_stats_handler(struct work_struct *work) static void ch_flower_stats_cb(struct timer_list *t) { - struct adapter *adap = from_timer(adap, t, flower_stats_timer); + struct adapter *adap = timer_container_of(adap, t, flower_stats_timer); schedule_work(&adap->flower_stats_work); } diff --git a/drivers/net/ethernet/chelsio/cxgb4/sge.c b/drivers/net/ethernet/chelsio/cxgb4/sge.c index f2d533acb056..64402e3646b3 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb4/sge.c @@ -4234,7 +4234,7 @@ static void sge_rx_timer_cb(struct timer_list *t) { unsigned long m; unsigned int i; - struct adapter *adap = from_timer(adap, t, sge.rx_timer); + struct adapter *adap = timer_container_of(adap, t, sge.rx_timer); struct sge *s = &adap->sge; for (i = 0; i < BITS_TO_LONGS(s->egr_sz); i++) @@ -4269,7 +4269,7 @@ done: static void sge_tx_timer_cb(struct timer_list *t) { - struct adapter *adap = from_timer(adap, t, sge.tx_timer); + struct adapter *adap = timer_container_of(adap, t, sge.tx_timer); struct sge *s = &adap->sge; unsigned long m, period; unsigned int i, budget; diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/sge.c b/drivers/net/ethernet/chelsio/cxgb4vf/sge.c index f42af01f4114..4e6ecb9c8dcc 100644 --- a/drivers/net/ethernet/chelsio/cxgb4vf/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb4vf/sge.c @@ -2062,7 +2062,7 @@ irq_handler_t t4vf_intr_handler(struct adapter *adapter) */ static void sge_rx_timer_cb(struct timer_list *t) { - struct adapter *adapter = from_timer(adapter, t, sge.rx_timer); + struct adapter *adapter = timer_container_of(adapter, t, sge.rx_timer); struct sge *s = &adapter->sge; unsigned int i; @@ -2121,7 +2121,7 @@ static void sge_rx_timer_cb(struct timer_list *t) */ static void sge_tx_timer_cb(struct timer_list *t) { - struct adapter *adapter = from_timer(adapter, t, sge.tx_timer); + struct adapter *adapter = timer_container_of(adapter, t, sge.tx_timer); struct sge *s = &adapter->sge; unsigned int i, budget; diff --git a/drivers/net/ethernet/cisco/enic/enic_clsf.c b/drivers/net/ethernet/cisco/enic/enic_clsf.c index 9900993b6aea..837f954873ee 100644 --- a/drivers/net/ethernet/cisco/enic/enic_clsf.c +++ b/drivers/net/ethernet/cisco/enic/enic_clsf.c @@ -125,7 +125,7 @@ struct enic_rfs_fltr_node *htbl_fltr_search(struct enic *enic, u16 fltr_id) #ifdef CONFIG_RFS_ACCEL void enic_flow_may_expire(struct timer_list *t) { - struct enic *enic = from_timer(enic, t, rfs_h.rfs_may_expire); + struct enic *enic = timer_container_of(enic, t, rfs_h.rfs_may_expire); bool res; int j; diff --git a/drivers/net/ethernet/cisco/enic/enic_main.c b/drivers/net/ethernet/cisco/enic/enic_main.c index 6ef8a0d90bce..773f5ad972a2 100644 --- a/drivers/net/ethernet/cisco/enic/enic_main.c +++ b/drivers/net/ethernet/cisco/enic/enic_main.c @@ -1510,7 +1510,7 @@ static int enic_poll_msix_rq(struct napi_struct *napi, int budget) static void enic_notify_timer(struct timer_list *t) { - struct enic *enic = from_timer(enic, t, notify_timer); + struct enic *enic = timer_container_of(enic, t, notify_timer); enic_notify_check(enic); diff --git a/drivers/net/ethernet/dec/tulip/de2104x.c b/drivers/net/ethernet/dec/tulip/de2104x.c index f9339d0772b5..f9504f340c4a 100644 --- a/drivers/net/ethernet/dec/tulip/de2104x.c +++ b/drivers/net/ethernet/dec/tulip/de2104x.c @@ -963,7 +963,7 @@ static void de_next_media (struct de_private *de, const u32 *media, static void de21040_media_timer (struct timer_list *t) { - struct de_private *de = from_timer(de, t, media_timer); + struct de_private *de = timer_container_of(de, t, media_timer); struct net_device *dev = de->dev; u32 status = dr32(SIAStatus); unsigned int carrier; @@ -1044,7 +1044,7 @@ static unsigned int de_ok_to_advertise (struct de_private *de, u32 new_media) static void de21041_media_timer (struct timer_list *t) { - struct de_private *de = from_timer(de, t, media_timer); + struct de_private *de = timer_container_of(de, t, media_timer); struct net_device *dev = de->dev; u32 status = dr32(SIAStatus); unsigned int carrier; diff --git a/drivers/net/ethernet/dec/tulip/dmfe.c b/drivers/net/ethernet/dec/tulip/dmfe.c index ae34b95ed676..2d3bd343b6e6 100644 --- a/drivers/net/ethernet/dec/tulip/dmfe.c +++ b/drivers/net/ethernet/dec/tulip/dmfe.c @@ -1115,7 +1115,7 @@ static const struct ethtool_ops netdev_ethtool_ops = { static void dmfe_timer(struct timer_list *t) { - struct dmfe_board_info *db = from_timer(db, t, timer); + struct dmfe_board_info *db = timer_container_of(db, t, timer); struct net_device *dev = pci_get_drvdata(db->pdev); void __iomem *ioaddr = db->ioaddr; u32 tmp_cr8; diff --git a/drivers/net/ethernet/dec/tulip/interrupt.c b/drivers/net/ethernet/dec/tulip/interrupt.c index 2d926a26fbb9..0a12cb9b3ba7 100644 --- a/drivers/net/ethernet/dec/tulip/interrupt.c +++ b/drivers/net/ethernet/dec/tulip/interrupt.c @@ -104,7 +104,7 @@ int tulip_refill_rx(struct net_device *dev) void oom_timer(struct timer_list *t) { - struct tulip_private *tp = from_timer(tp, t, oom_timer); + struct tulip_private *tp = timer_container_of(tp, t, oom_timer); napi_schedule(&tp->napi); } diff --git a/drivers/net/ethernet/dec/tulip/pnic.c b/drivers/net/ethernet/dec/tulip/pnic.c index 653bde48ef44..1de5ed967070 100644 --- a/drivers/net/ethernet/dec/tulip/pnic.c +++ b/drivers/net/ethernet/dec/tulip/pnic.c @@ -86,7 +86,7 @@ void pnic_lnk_change(struct net_device *dev, int csr5) void pnic_timer(struct timer_list *t) { - struct tulip_private *tp = from_timer(tp, t, timer); + struct tulip_private *tp = timer_container_of(tp, t, timer); struct net_device *dev = tp->dev; void __iomem *ioaddr = tp->base_addr; int next_tick = 60*HZ; diff --git a/drivers/net/ethernet/dec/tulip/pnic2.c b/drivers/net/ethernet/dec/tulip/pnic2.c index 2e3bdc0fcdc0..39c410bf224e 100644 --- a/drivers/net/ethernet/dec/tulip/pnic2.c +++ b/drivers/net/ethernet/dec/tulip/pnic2.c @@ -78,7 +78,7 @@ void pnic2_timer(struct timer_list *t) { - struct tulip_private *tp = from_timer(tp, t, timer); + struct tulip_private *tp = timer_container_of(tp, t, timer); struct net_device *dev = tp->dev; void __iomem *ioaddr = tp->base_addr; int next_tick = 60*HZ; diff --git a/drivers/net/ethernet/dec/tulip/timer.c b/drivers/net/ethernet/dec/tulip/timer.c index 642e9dfc5451..ca0c509b601c 100644 --- a/drivers/net/ethernet/dec/tulip/timer.c +++ b/drivers/net/ethernet/dec/tulip/timer.c @@ -139,7 +139,7 @@ void tulip_media_task(struct work_struct *work) void mxic_timer(struct timer_list *t) { - struct tulip_private *tp = from_timer(tp, t, timer); + struct tulip_private *tp = timer_container_of(tp, t, timer); struct net_device *dev = tp->dev; void __iomem *ioaddr = tp->base_addr; int next_tick = 60*HZ; @@ -156,7 +156,7 @@ void mxic_timer(struct timer_list *t) void comet_timer(struct timer_list *t) { - struct tulip_private *tp = from_timer(tp, t, timer); + struct tulip_private *tp = timer_container_of(tp, t, timer); struct net_device *dev = tp->dev; int next_tick = 2*HZ; diff --git a/drivers/net/ethernet/dec/tulip/tulip_core.c b/drivers/net/ethernet/dec/tulip/tulip_core.c index bec76e7bf5dd..5b7e6eb080f3 100644 --- a/drivers/net/ethernet/dec/tulip/tulip_core.c +++ b/drivers/net/ethernet/dec/tulip/tulip_core.c @@ -114,7 +114,7 @@ int tulip_debug = 1; static void tulip_timer(struct timer_list *t) { - struct tulip_private *tp = from_timer(tp, t, timer); + struct tulip_private *tp = timer_container_of(tp, t, timer); struct net_device *dev = tp->dev; if (netif_running(dev)) diff --git a/drivers/net/ethernet/dec/tulip/uli526x.c b/drivers/net/ethernet/dec/tulip/uli526x.c index 3f1bd670700b..6e4d8d31aba9 100644 --- a/drivers/net/ethernet/dec/tulip/uli526x.c +++ b/drivers/net/ethernet/dec/tulip/uli526x.c @@ -1014,7 +1014,7 @@ static const struct ethtool_ops netdev_ethtool_ops = { static void uli526x_timer(struct timer_list *t) { - struct uli526x_board_info *db = from_timer(db, t, timer); + struct uli526x_board_info *db = timer_container_of(db, t, timer); struct net_device *dev = pci_get_drvdata(db->pdev); struct uli_phy_ops *phy = &db->phy; void __iomem *ioaddr = db->ioaddr; diff --git a/drivers/net/ethernet/dec/tulip/winbond-840.c b/drivers/net/ethernet/dec/tulip/winbond-840.c index e593273b2867..a24a25a5f73d 100644 --- a/drivers/net/ethernet/dec/tulip/winbond-840.c +++ b/drivers/net/ethernet/dec/tulip/winbond-840.c @@ -763,7 +763,7 @@ static inline void update_csr6(struct net_device *dev, int new) static void netdev_timer(struct timer_list *t) { - struct netdev_private *np = from_timer(np, t, timer); + struct netdev_private *np = timer_container_of(np, t, timer); struct net_device *dev = pci_get_drvdata(np->pci_dev); void __iomem *ioaddr = np->base_addr; diff --git a/drivers/net/ethernet/dlink/dl2k.c b/drivers/net/ethernet/dlink/dl2k.c index 038a0400c1f9..da9b7715df05 100644 --- a/drivers/net/ethernet/dlink/dl2k.c +++ b/drivers/net/ethernet/dlink/dl2k.c @@ -650,7 +650,7 @@ static int rio_open(struct net_device *dev) static void rio_timer (struct timer_list *t) { - struct netdev_private *np = from_timer(np, t, timer); + struct netdev_private *np = timer_container_of(np, t, timer); struct net_device *dev = pci_get_drvdata(np->pdev); unsigned int entry; int next_tick = 1*HZ; diff --git a/drivers/net/ethernet/fealnx.c b/drivers/net/ethernet/fealnx.c index 670b68201376..6ac8547ef9b8 100644 --- a/drivers/net/ethernet/fealnx.c +++ b/drivers/net/ethernet/fealnx.c @@ -1074,7 +1074,7 @@ static void allocate_rx_buffers(struct net_device *dev) static void netdev_timer(struct timer_list *t) { - struct netdev_private *np = from_timer(np, t, timer); + struct netdev_private *np = timer_container_of(np, t, timer); struct net_device *dev = np->mii.dev; void __iomem *ioaddr = np->mem; int old_crvalue = np->crvalue; @@ -1163,7 +1163,7 @@ static void enable_rxtx(struct net_device *dev) static void reset_timer(struct timer_list *t) { - struct netdev_private *np = from_timer(np, t, reset_timer); + struct netdev_private *np = timer_container_of(np, t, reset_timer); struct net_device *dev = np->mii.dev; unsigned long flags; diff --git a/drivers/net/ethernet/google/gve/gve_main.c b/drivers/net/ethernet/google/gve/gve_main.c index 7cd1eda0b449..dc35a23ec47f 100644 --- a/drivers/net/ethernet/google/gve/gve_main.c +++ b/drivers/net/ethernet/google/gve/gve_main.c @@ -268,7 +268,8 @@ static void gve_stats_report_schedule(struct gve_priv *priv) static void gve_stats_report_timer(struct timer_list *t) { - struct gve_priv *priv = from_timer(priv, t, stats_report_timer); + struct gve_priv *priv = timer_container_of(priv, t, + stats_report_timer); mod_timer(&priv->stats_report_timer, round_jiffies(jiffies + diff --git a/drivers/net/ethernet/hisilicon/hns/hns_enet.c b/drivers/net/ethernet/hisilicon/hns/hns_enet.c index d98f8d3ce7c8..e905f10b894e 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_enet.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_enet.c @@ -2075,7 +2075,7 @@ static void hns_nic_task_schedule(struct hns_nic_priv *priv) static void hns_nic_service_timer(struct timer_list *t) { - struct hns_nic_priv *priv = from_timer(priv, t, service_timer); + struct hns_nic_priv *priv = timer_container_of(priv, t, service_timer); (void)mod_timer(&priv->service_timer, jiffies + SERVICE_TIMER_HZ); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index 3e28a08934ab..a7de67699a01 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -4503,7 +4503,7 @@ static void hclge_set_def_reset_request(struct hnae3_ae_dev *ae_dev, static void hclge_reset_timer(struct timer_list *t) { - struct hclge_dev *hdev = from_timer(hdev, t, reset_timer); + struct hclge_dev *hdev = timer_container_of(hdev, t, reset_timer); /* if default_reset_request has no value, it means that this reset * request has already be handled, so just return here diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c index dada42e7e0ec..c4f35e8e2177 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c @@ -2057,7 +2057,7 @@ static enum hclgevf_evt_cause hclgevf_check_evt_cause(struct hclgevf_dev *hdev, static void hclgevf_reset_timer(struct timer_list *t) { - struct hclgevf_dev *hdev = from_timer(hdev, t, reset_timer); + struct hclgevf_dev *hdev = timer_container_of(hdev, t, reset_timer); hclgevf_clear_event_cause(hdev, HCLGEVF_VECTOR0_EVENT_RST); hclgevf_reset_task_schedule(hdev); diff --git a/drivers/net/ethernet/intel/e100.c b/drivers/net/ethernet/intel/e100.c index c0ead54ea186..5c56c1edd492 100644 --- a/drivers/net/ethernet/intel/e100.c +++ b/drivers/net/ethernet/intel/e100.c @@ -1682,7 +1682,7 @@ static void e100_adjust_adaptive_ifs(struct nic *nic, int speed, int duplex) static void e100_watchdog(struct timer_list *t) { - struct nic *nic = from_timer(nic, t, watchdog); + struct nic *nic = timer_container_of(nic, t, watchdog); struct ethtool_cmd cmd = { .cmd = ETHTOOL_GSET }; u32 speed; diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index e0f492a6723f..a96f4cfa6e17 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -4853,7 +4853,8 @@ static void e1000e_update_phy_task(struct work_struct *work) **/ static void e1000_update_phy_info(struct timer_list *t) { - struct e1000_adapter *adapter = from_timer(adapter, t, phy_info_timer); + struct e1000_adapter *adapter = timer_container_of(adapter, t, + phy_info_timer); if (test_bit(__E1000_DOWN, &adapter->state)) return; @@ -5189,7 +5190,8 @@ static void e1000e_check_82574_phy_workaround(struct e1000_adapter *adapter) **/ static void e1000_watchdog(struct timer_list *t) { - struct e1000_adapter *adapter = from_timer(adapter, t, watchdog_timer); + struct e1000_adapter *adapter = timer_container_of(adapter, t, + watchdog_timer); /* Do the rest outside of interrupt context */ schedule_work(&adapter->watchdog_task); diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_pci.c b/drivers/net/ethernet/intel/fm10k/fm10k_pci.c index 21267ab603ef..ae5fe34659cf 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_pci.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_pci.c @@ -199,8 +199,8 @@ static void fm10k_start_service_event(struct fm10k_intfc *interface) **/ static void fm10k_service_timer(struct timer_list *t) { - struct fm10k_intfc *interface = from_timer(interface, t, - service_timer); + struct fm10k_intfc *interface = timer_container_of(interface, t, + service_timer); /* Reset the timer */ mod_timer(&interface->service_timer, (HZ * 2) + jiffies); diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 120d68654e3f..f1c9e575703e 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -11412,7 +11412,7 @@ static void i40e_service_task(struct work_struct *work) **/ static void i40e_service_timer(struct timer_list *t) { - struct i40e_pf *pf = from_timer(pf, t, service_timer); + struct i40e_pf *pf = timer_container_of(pf, t, service_timer); mod_timer(&pf->service_timer, round_jiffies(jiffies + pf->service_timer_period)); diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index d97d4b25b30d..0a11b4281092 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -1743,7 +1743,7 @@ static void ice_service_task_restart(struct ice_pf *pf) */ static void ice_service_timer(struct timer_list *t) { - struct ice_pf *pf = from_timer(pf, t, serv_tmr); + struct ice_pf *pf = timer_container_of(pf, t, serv_tmr); mod_timer(&pf->serv_tmr, round_jiffies(pf->serv_tmr_period + jiffies)); ice_service_task_schedule(pf); diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl_fdir.c b/drivers/net/ethernet/intel/ice/ice_virtchnl_fdir.c index 1cca9b2262e8..ae83c3914e29 100644 --- a/drivers/net/ethernet/intel/ice/ice_virtchnl_fdir.c +++ b/drivers/net/ethernet/intel/ice/ice_virtchnl_fdir.c @@ -1450,7 +1450,8 @@ err_free_pkt: */ static void ice_vf_fdir_timer(struct timer_list *t) { - struct ice_vf_fdir_ctx *ctx_irq = from_timer(ctx_irq, t, rx_tmr); + struct ice_vf_fdir_ctx *ctx_irq = timer_container_of(ctx_irq, t, + rx_tmr); struct ice_vf_fdir_ctx *ctx_done; struct ice_vf_fdir *fdir; unsigned long flags; diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index 9e9a5900e6e5..b76a154e635e 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -5465,7 +5465,8 @@ static void igb_spoof_check(struct igb_adapter *adapter) */ static void igb_update_phy_info(struct timer_list *t) { - struct igb_adapter *adapter = from_timer(adapter, t, phy_info_timer); + struct igb_adapter *adapter = timer_container_of(adapter, t, + phy_info_timer); igb_get_phy_info(&adapter->hw); } @@ -5555,7 +5556,8 @@ static void igb_check_lvmmc(struct igb_adapter *adapter) **/ static void igb_watchdog(struct timer_list *t) { - struct igb_adapter *adapter = from_timer(adapter, t, watchdog_timer); + struct igb_adapter *adapter = timer_container_of(adapter, t, + watchdog_timer); /* Do the rest outside of interrupt context */ schedule_work(&adapter->watchdog_task); } diff --git a/drivers/net/ethernet/intel/igbvf/netdev.c b/drivers/net/ethernet/intel/igbvf/netdev.c index beb01248600f..e55dd9345833 100644 --- a/drivers/net/ethernet/intel/igbvf/netdev.c +++ b/drivers/net/ethernet/intel/igbvf/netdev.c @@ -1900,7 +1900,8 @@ static bool igbvf_has_link(struct igbvf_adapter *adapter) **/ static void igbvf_watchdog(struct timer_list *t) { - struct igbvf_adapter *adapter = from_timer(adapter, t, watchdog_timer); + struct igbvf_adapter *adapter = timer_container_of(adapter, t, + watchdog_timer); /* Do the rest outside of interrupt context */ schedule_work(&adapter->watchdog_task); diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c index 27575a1e1777..686793c539f2 100644 --- a/drivers/net/ethernet/intel/igc/igc_main.c +++ b/drivers/net/ethernet/intel/igc/igc_main.c @@ -5749,7 +5749,8 @@ static void igc_clear_interrupt_scheme(struct igc_adapter *adapter) */ static void igc_update_phy_info(struct timer_list *t) { - struct igc_adapter *adapter = from_timer(adapter, t, phy_info_timer); + struct igc_adapter *adapter = timer_container_of(adapter, t, + phy_info_timer); igc_get_phy_info(&adapter->hw); } @@ -5791,7 +5792,8 @@ bool igc_has_link(struct igc_adapter *adapter) */ static void igc_watchdog(struct timer_list *t) { - struct igc_adapter *adapter = from_timer(adapter, t, watchdog_timer); + struct igc_adapter *adapter = timer_container_of(adapter, t, + watchdog_timer); /* Do the rest outside of interrupt context */ schedule_work(&adapter->watchdog_task); } diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 03d31e5b131d..cba860f0e1f1 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -8310,7 +8310,8 @@ static void ixgbe_sfp_link_config_subtask(struct ixgbe_adapter *adapter) **/ static void ixgbe_service_timer(struct timer_list *t) { - struct ixgbe_adapter *adapter = from_timer(adapter, t, service_timer); + struct ixgbe_adapter *adapter = timer_container_of(adapter, t, + service_timer); unsigned long next_event_offset; /* poll faster when waiting for link */ diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c index a217c5c04804..535d0f71f521 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c +++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c @@ -3176,8 +3176,8 @@ void ixgbevf_update_stats(struct ixgbevf_adapter *adapter) **/ static void ixgbevf_service_timer(struct timer_list *t) { - struct ixgbevf_adapter *adapter = from_timer(adapter, t, - service_timer); + struct ixgbevf_adapter *adapter = timer_container_of(adapter, t, + service_timer); /* Reset the timer */ mod_timer(&adapter->service_timer, (HZ * 2) + jiffies); diff --git a/drivers/net/ethernet/korina.c b/drivers/net/ethernet/korina.c index 1e2ac1a5f099..891a94d89f4b 100644 --- a/drivers/net/ethernet/korina.c +++ b/drivers/net/ethernet/korina.c @@ -900,7 +900,8 @@ static void korina_check_media(struct net_device *dev, unsigned int init_media) static void korina_poll_media(struct timer_list *t) { - struct korina_private *lp = from_timer(lp, t, media_check_timer); + struct korina_private *lp = timer_container_of(lp, t, + media_check_timer); struct net_device *dev = lp->dev; korina_check_media(dev, 0); diff --git a/drivers/net/ethernet/marvell/mv643xx_eth.c b/drivers/net/ethernet/marvell/mv643xx_eth.c index 8cc888bf6094..0ab52c57c648 100644 --- a/drivers/net/ethernet/marvell/mv643xx_eth.c +++ b/drivers/net/ethernet/marvell/mv643xx_eth.c @@ -1333,7 +1333,8 @@ static void mib_counters_update(struct mv643xx_eth_private *mp) static void mib_counters_timer_wrapper(struct timer_list *t) { - struct mv643xx_eth_private *mp = from_timer(mp, t, mib_counters_timer); + struct mv643xx_eth_private *mp = timer_container_of(mp, t, + mib_counters_timer); mib_counters_update(mp); mod_timer(&mp->mib_counters_timer, jiffies + 30 * HZ); } @@ -2306,7 +2307,7 @@ static int mv643xx_eth_poll(struct napi_struct *napi, int budget) static inline void oom_timer_wrapper(struct timer_list *t) { - struct mv643xx_eth_private *mp = from_timer(mp, t, rx_oom); + struct mv643xx_eth_private *mp = timer_container_of(mp, t, rx_oom); napi_schedule(&mp->napi); } diff --git a/drivers/net/ethernet/marvell/pxa168_eth.c b/drivers/net/ethernet/marvell/pxa168_eth.c index 72c1967768f4..e4cfdc8bc055 100644 --- a/drivers/net/ethernet/marvell/pxa168_eth.c +++ b/drivers/net/ethernet/marvell/pxa168_eth.c @@ -353,7 +353,7 @@ static void rxq_refill(struct net_device *dev) static inline void rxq_refill_timer_wrapper(struct timer_list *t) { - struct pxa168_eth_private *pep = from_timer(pep, t, timeout); + struct pxa168_eth_private *pep = timer_container_of(pep, t, timeout); napi_schedule(&pep->napi); } diff --git a/drivers/net/ethernet/marvell/skge.c b/drivers/net/ethernet/marvell/skge.c index b2081d6e34f0..05349a0b2db1 100644 --- a/drivers/net/ethernet/marvell/skge.c +++ b/drivers/net/ethernet/marvell/skge.c @@ -1494,7 +1494,7 @@ static int xm_check_link(struct net_device *dev) */ static void xm_link_timer(struct timer_list *t) { - struct skge_port *skge = from_timer(skge, t, link_timer); + struct skge_port *skge = timer_container_of(skge, t, link_timer); struct net_device *dev = skge->netdev; struct skge_hw *hw = skge->hw; int port = skge->port; diff --git a/drivers/net/ethernet/marvell/sky2.c b/drivers/net/ethernet/marvell/sky2.c index e2a9aae8bc9b..3831f533b9db 100644 --- a/drivers/net/ethernet/marvell/sky2.c +++ b/drivers/net/ethernet/marvell/sky2.c @@ -2961,7 +2961,7 @@ static int sky2_rx_hung(struct net_device *dev) static void sky2_watchdog(struct timer_list *t) { - struct sky2_hw *hw = from_timer(hw, t, watchdog_timer); + struct sky2_hw *hw = timer_container_of(hw, t, watchdog_timer); /* Check for lost IRQ once a second */ if (sky2_read32(hw, B0_ISRC)) { diff --git a/drivers/net/ethernet/mellanox/mlx4/catas.c b/drivers/net/ethernet/mellanox/mlx4/catas.c index 33ba0a5c38ac..edcc6f662618 100644 --- a/drivers/net/ethernet/mellanox/mlx4/catas.c +++ b/drivers/net/ethernet/mellanox/mlx4/catas.c @@ -236,7 +236,7 @@ static void dump_err_buf(struct mlx4_dev *dev) static void poll_catas(struct timer_list *t) { - struct mlx4_priv *priv = from_timer(priv, t, catas_err.timer); + struct mlx4_priv *priv = timer_container_of(priv, t, catas_err.timer); struct mlx4_dev *dev = &priv->dev; u32 slave_read; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c b/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c index 5442a02c4097..69933addd921 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c @@ -278,7 +278,8 @@ static void mlx5_sync_reset_reload_work(struct work_struct *work) #define MLX5_RESET_POLL_INTERVAL (HZ / 10) static void poll_sync_reset(struct timer_list *t) { - struct mlx5_fw_reset *fw_reset = from_timer(fw_reset, t, timer); + struct mlx5_fw_reset *fw_reset = timer_container_of(fw_reset, t, + timer); struct mlx5_core_dev *dev = fw_reset->dev; u32 fatal_error; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/health.c b/drivers/net/ethernet/mellanox/mlx5/core/health.c index 624452ddebc0..cf7a1edd0530 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/health.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/health.c @@ -779,7 +779,8 @@ static void mlx5_health_log_ts_update(struct work_struct *work) static void poll_health(struct timer_list *t) { - struct mlx5_core_dev *dev = from_timer(dev, t, priv.health.timer); + struct mlx5_core_dev *dev = timer_container_of(dev, t, + priv.health.timer); struct mlx5_core_health *health = &dev->priv.health; struct health_buffer __iomem *h = health->health; u32 fatal_error; diff --git a/drivers/net/ethernet/micrel/ksz884x.c b/drivers/net/ethernet/micrel/ksz884x.c index 1302aa8e0853..cdde19b8edc4 100644 --- a/drivers/net/ethernet/micrel/ksz884x.c +++ b/drivers/net/ethernet/micrel/ksz884x.c @@ -6304,7 +6304,8 @@ static void mib_read_work(struct work_struct *work) static void mib_monitor(struct timer_list *t) { - struct dev_info *hw_priv = from_timer(hw_priv, t, mib_timer_info.timer); + struct dev_info *hw_priv = timer_container_of(hw_priv, t, + mib_timer_info.timer); mib_read_work(&hw_priv->mib_read); @@ -6331,7 +6332,8 @@ static void mib_monitor(struct timer_list *t) */ static void dev_monitor(struct timer_list *t) { - struct dev_priv *priv = from_timer(priv, t, monitor_timer_info.timer); + struct dev_priv *priv = timer_container_of(priv, t, + monitor_timer_info.timer); struct net_device *dev = priv->mii_if.dev; struct dev_info *hw_priv = priv->adapter; struct ksz_hw *hw = &hw_priv->hw; diff --git a/drivers/net/ethernet/myricom/myri10ge/myri10ge.c b/drivers/net/ethernet/myricom/myri10ge/myri10ge.c index 7c501a758325..e611ff7fa3fa 100644 --- a/drivers/net/ethernet/myricom/myri10ge/myri10ge.c +++ b/drivers/net/ethernet/myricom/myri10ge/myri10ge.c @@ -3478,7 +3478,7 @@ static void myri10ge_watchdog_timer(struct timer_list *t) u32 rx_pause_cnt; u16 cmd; - mgp = from_timer(mgp, t, watchdog_timer); + mgp = timer_container_of(mgp, t, watchdog_timer); rx_pause_cnt = ntohl(mgp->ss[0].fw_stats->dropped_pause); busy_slice_cnt = 0; diff --git a/drivers/net/ethernet/natsemi/natsemi.c b/drivers/net/ethernet/natsemi/natsemi.c index dd279788cf9e..b253734dbc80 100644 --- a/drivers/net/ethernet/natsemi/natsemi.c +++ b/drivers/net/ethernet/natsemi/natsemi.c @@ -1786,7 +1786,7 @@ static void init_registers(struct net_device *dev) */ static void netdev_timer(struct timer_list *t) { - struct netdev_private *np = from_timer(np, t, timer); + struct netdev_private *np = timer_container_of(np, t, timer); struct net_device *dev = np->dev; void __iomem * ioaddr = ns_ioaddr(dev); int next_tick = NATSEMI_TIMER_FREQ; diff --git a/drivers/net/ethernet/natsemi/ns83820.c b/drivers/net/ethernet/natsemi/ns83820.c index bf0347715a05..56d5464222d9 100644 --- a/drivers/net/ethernet/natsemi/ns83820.c +++ b/drivers/net/ethernet/natsemi/ns83820.c @@ -1587,7 +1587,7 @@ static void ns83820_tx_timeout(struct net_device *ndev, unsigned int txqueue) static void ns83820_tx_watch(struct timer_list *t) { - struct ns83820 *dev = from_timer(dev, t, tx_watchdog); + struct ns83820 *dev = timer_container_of(dev, t, tx_watchdog); struct net_device *ndev = dev->ndev; #if defined(DEBUG) diff --git a/drivers/net/ethernet/neterion/s2io.c b/drivers/net/ethernet/neterion/s2io.c index 3e55e8dc664c..27443e346f9f 100644 --- a/drivers/net/ethernet/neterion/s2io.c +++ b/drivers/net/ethernet/neterion/s2io.c @@ -4195,7 +4195,7 @@ pci_map_failed: static void s2io_alarm_handle(struct timer_list *t) { - struct s2io_nic *sp = from_timer(sp, t, alarm_timer); + struct s2io_nic *sp = timer_container_of(sp, t, alarm_timer); struct net_device *dev = sp->dev; s2io_handle_errors(dev); diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c index 28997ddab966..932f59d70f41 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c @@ -159,7 +159,7 @@ static int nfp_net_reconfig_wait(struct nfp_net *nn, unsigned long deadline) static void nfp_net_reconfig_timer(struct timer_list *t) { - struct nfp_net *nn = from_timer(nn, t, reconfig_timer); + struct nfp_net *nn = timer_container_of(nn, t, reconfig_timer); spin_lock_bh(&nn->reconfig_lock); diff --git a/drivers/net/ethernet/nvidia/forcedeth.c b/drivers/net/ethernet/nvidia/forcedeth.c index 29cb74ccb25a..19aa1f1538aa 100644 --- a/drivers/net/ethernet/nvidia/forcedeth.c +++ b/drivers/net/ethernet/nvidia/forcedeth.c @@ -1891,7 +1891,7 @@ packet_dropped: /* If rx bufs are exhausted called after 50ms to attempt to refresh */ static void nv_do_rx_refill(struct timer_list *t) { - struct fe_priv *np = from_timer(np, t, oom_kick); + struct fe_priv *np = timer_container_of(np, t, oom_kick); /* Just reschedule NAPI rx processing */ napi_schedule(&np->napi); @@ -4140,7 +4140,7 @@ static void nv_free_irq(struct net_device *dev) static void nv_do_nic_poll(struct timer_list *t) { - struct fe_priv *np = from_timer(np, t, nic_poll); + struct fe_priv *np = timer_container_of(np, t, nic_poll); struct net_device *dev = np->dev; u8 __iomem *base = get_hwbase(dev); u32 mask = 0; @@ -4259,7 +4259,7 @@ static void nv_do_stats_poll(struct timer_list *t) __acquires(&netdev_priv(dev)->hwstats_lock) __releases(&netdev_priv(dev)->hwstats_lock) { - struct fe_priv *np = from_timer(np, t, stats_poll); + struct fe_priv *np = timer_container_of(np, t, stats_poll); struct net_device *dev = np->dev; /* If lock is currently taken, the stats are being refreshed diff --git a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c index 1651df8a7c21..e5a6f59af0b6 100644 --- a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c +++ b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c @@ -1014,8 +1014,8 @@ static void pch_gbe_set_mode(struct pch_gbe_adapter *adapter, u16 speed, */ static void pch_gbe_watchdog(struct timer_list *t) { - struct pch_gbe_adapter *adapter = from_timer(adapter, t, - watchdog_timer); + struct pch_gbe_adapter *adapter = timer_container_of(adapter, t, + watchdog_timer); struct net_device *netdev = adapter->netdev; struct pch_gbe_hw *hw = &adapter->hw; diff --git a/drivers/net/ethernet/packetengines/hamachi.c b/drivers/net/ethernet/packetengines/hamachi.c index 26bc8b3b1ec8..b0de7e9f12a5 100644 --- a/drivers/net/ethernet/packetengines/hamachi.c +++ b/drivers/net/ethernet/packetengines/hamachi.c @@ -1025,7 +1025,7 @@ static inline int hamachi_tx(struct net_device *dev) static void hamachi_timer(struct timer_list *t) { - struct hamachi_private *hmp = from_timer(hmp, t, timer); + struct hamachi_private *hmp = timer_container_of(hmp, t, timer); struct net_device *dev = hmp->mii_if.dev; void __iomem *ioaddr = hmp->base; int next_tick = 10*HZ; diff --git a/drivers/net/ethernet/packetengines/yellowfin.c b/drivers/net/ethernet/packetengines/yellowfin.c index 21b760e65d73..1e25ac13a7d8 100644 --- a/drivers/net/ethernet/packetengines/yellowfin.c +++ b/drivers/net/ethernet/packetengines/yellowfin.c @@ -652,7 +652,7 @@ err_free_irq: static void yellowfin_timer(struct timer_list *t) { - struct yellowfin_private *yp = from_timer(yp, t, timer); + struct yellowfin_private *yp = timer_container_of(yp, t, timer); struct net_device *dev = pci_get_drvdata(yp->pci_dev); void __iomem *ioaddr = yp->base; int next_tick = 60*HZ; diff --git a/drivers/net/ethernet/pasemi/pasemi_mac.c b/drivers/net/ethernet/pasemi/pasemi_mac.c index 801380729046..fe58024b5901 100644 --- a/drivers/net/ethernet/pasemi/pasemi_mac.c +++ b/drivers/net/ethernet/pasemi/pasemi_mac.c @@ -934,7 +934,8 @@ static irqreturn_t pasemi_mac_rx_intr(int irq, void *data) static void pasemi_mac_tx_timer(struct timer_list *t) { - struct pasemi_mac_txring *txring = from_timer(txring, t, clean_timer); + struct pasemi_mac_txring *txring = timer_container_of(txring, t, + clean_timer); struct pasemi_mac *mac = txring->mac; pasemi_mac_clean_tx(txring); diff --git a/drivers/net/ethernet/pensando/ionic/ionic_dev.c b/drivers/net/ethernet/pensando/ionic/ionic_dev.c index 57edcde9e6f8..18b9c8a810ae 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_dev.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_dev.c @@ -13,7 +13,7 @@ static void ionic_watchdog_cb(struct timer_list *t) { - struct ionic *ionic = from_timer(ionic, t, watchdog_timer); + struct ionic *ionic = timer_container_of(ionic, t, watchdog_timer); struct ionic_lif *lif = ionic->lif; struct ionic_deferred_work *work; int hb; diff --git a/drivers/net/ethernet/qlogic/qla3xxx.c b/drivers/net/ethernet/qlogic/qla3xxx.c index bf5bf8c95c85..aee4e63b4b82 100644 --- a/drivers/net/ethernet/qlogic/qla3xxx.c +++ b/drivers/net/ethernet/qlogic/qla3xxx.c @@ -3735,7 +3735,7 @@ static void ql_get_board_info(struct ql3_adapter *qdev) static void ql3xxx_timer(struct timer_list *t) { - struct ql3_adapter *qdev = from_timer(qdev, t, adapter_timer); + struct ql3_adapter *qdev = timer_container_of(qdev, t, adapter_timer); queue_delayed_work(qdev->workqueue, &qdev->link_state_work, 0); } diff --git a/drivers/net/ethernet/realtek/atp.c b/drivers/net/ethernet/realtek/atp.c index c73a57e4a144..0d65434982a2 100644 --- a/drivers/net/ethernet/realtek/atp.c +++ b/drivers/net/ethernet/realtek/atp.c @@ -717,7 +717,7 @@ static irqreturn_t atp_interrupt(int irq, void *dev_instance) problem where the adapter forgets its ethernet address. */ static void atp_timed_checker(struct timer_list *t) { - struct net_local *lp = from_timer(lp, t, timer); + struct net_local *lp = timer_container_of(lp, t, timer); struct net_device *dev = lp->dev; long ioaddr = dev->base_addr; int tickssofar = jiffies - lp->last_rx_time; diff --git a/drivers/net/ethernet/rocker/rocker_ofdpa.c b/drivers/net/ethernet/rocker/rocker_ofdpa.c index 19985d13e243..61e50517c05b 100644 --- a/drivers/net/ethernet/rocker/rocker_ofdpa.c +++ b/drivers/net/ethernet/rocker/rocker_ofdpa.c @@ -1982,7 +1982,7 @@ err_out: static void ofdpa_fdb_cleanup(struct timer_list *t) { - struct ofdpa *ofdpa = from_timer(ofdpa, t, fdb_cleanup_timer); + struct ofdpa *ofdpa = timer_container_of(ofdpa, t, fdb_cleanup_timer); struct ofdpa_port *ofdpa_port; struct ofdpa_fdb_tbl_entry *entry; struct hlist_node *tmp; diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c b/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c index 36b63bf343a9..75bad561b352 100644 --- a/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c +++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c @@ -104,7 +104,8 @@ void sxgbe_disable_eee_mode(struct sxgbe_priv_data * const priv) */ static void sxgbe_eee_ctrl_timer(struct timer_list *t) { - struct sxgbe_priv_data *priv = from_timer(priv, t, eee_ctrl_timer); + struct sxgbe_priv_data *priv = timer_container_of(priv, t, + eee_ctrl_timer); sxgbe_enable_eee_mode(priv); mod_timer(&priv->eee_ctrl_timer, SXGBE_LPI_TIMER(eee_timer)); @@ -1012,7 +1013,7 @@ static void sxgbe_disable_mtl_engine(struct sxgbe_priv_data *priv) */ static void sxgbe_tx_timer(struct timer_list *t) { - struct sxgbe_tx_queue *p = from_timer(p, t, txtimer); + struct sxgbe_tx_queue *p = timer_container_of(p, t, txtimer); sxgbe_tx_queue_clean(p); } diff --git a/drivers/net/ethernet/seeq/ether3.c b/drivers/net/ethernet/seeq/ether3.c index 1d65113fab76..20dad39b5ab9 100644 --- a/drivers/net/ethernet/seeq/ether3.c +++ b/drivers/net/ethernet/seeq/ether3.c @@ -170,7 +170,7 @@ ether3_setbuffer(struct net_device *dev, buffer_rw_t read, int start) */ static void ether3_ledoff(struct timer_list *t) { - struct dev_priv *private = from_timer(private, t, timer); + struct dev_priv *private = timer_container_of(private, t, timer); struct net_device *dev = private->dev; ether3_outw(priv(dev)->regs.config2 |= CFG2_CTRLO, REG_CONFIG2); diff --git a/drivers/net/ethernet/sfc/falcon/falcon.c b/drivers/net/ethernet/sfc/falcon/falcon.c index b865275beb66..c44df8e4dd30 100644 --- a/drivers/net/ethernet/sfc/falcon/falcon.c +++ b/drivers/net/ethernet/sfc/falcon/falcon.c @@ -1453,8 +1453,8 @@ static void falcon_stats_complete(struct ef4_nic *efx) static void falcon_stats_timer_func(struct timer_list *t) { - struct falcon_nic_data *nic_data = from_timer(nic_data, t, - stats_timer); + struct falcon_nic_data *nic_data = timer_container_of(nic_data, t, + stats_timer); struct ef4_nic *efx = nic_data->efx; spin_lock(&efx->stats_lock); diff --git a/drivers/net/ethernet/sfc/falcon/rx.c b/drivers/net/ethernet/sfc/falcon/rx.c index 38ad7ac07726..f69fcf6caca8 100644 --- a/drivers/net/ethernet/sfc/falcon/rx.c +++ b/drivers/net/ethernet/sfc/falcon/rx.c @@ -382,7 +382,8 @@ void ef4_fast_push_rx_descriptors(struct ef4_rx_queue *rx_queue, bool atomic) void ef4_rx_slow_fill(struct timer_list *t) { - struct ef4_rx_queue *rx_queue = from_timer(rx_queue, t, slow_fill); + struct ef4_rx_queue *rx_queue = timer_container_of(rx_queue, t, + slow_fill); /* Post an event to cause NAPI to run and refill the queue */ ef4_nic_generate_fill_event(rx_queue); diff --git a/drivers/net/ethernet/sfc/mcdi.c b/drivers/net/ethernet/sfc/mcdi.c index dcef0588be96..5e9b8def5e42 100644 --- a/drivers/net/ethernet/sfc/mcdi.c +++ b/drivers/net/ethernet/sfc/mcdi.c @@ -605,7 +605,7 @@ static void efx_mcdi_ev_cpl(struct efx_nic *efx, unsigned int seqno, static void efx_mcdi_timeout_async(struct timer_list *t) { - struct efx_mcdi_iface *mcdi = from_timer(mcdi, t, async_timer); + struct efx_mcdi_iface *mcdi = timer_container_of(mcdi, t, async_timer); efx_mcdi_complete_async(mcdi, true); } diff --git a/drivers/net/ethernet/sfc/rx_common.c b/drivers/net/ethernet/sfc/rx_common.c index 8eb272ba674b..f4f75299dfa9 100644 --- a/drivers/net/ethernet/sfc/rx_common.c +++ b/drivers/net/ethernet/sfc/rx_common.c @@ -352,7 +352,8 @@ void efx_free_rx_buffers(struct efx_rx_queue *rx_queue, void efx_rx_slow_fill(struct timer_list *t) { - struct efx_rx_queue *rx_queue = from_timer(rx_queue, t, slow_fill); + struct efx_rx_queue *rx_queue = timer_container_of(rx_queue, t, + slow_fill); /* Post an event to cause NAPI to run and refill the queue */ efx_nic_generate_fill_event(rx_queue); diff --git a/drivers/net/ethernet/sfc/siena/mcdi.c b/drivers/net/ethernet/sfc/siena/mcdi.c index 99ab5f294691..c8f0fb43e285 100644 --- a/drivers/net/ethernet/sfc/siena/mcdi.c +++ b/drivers/net/ethernet/sfc/siena/mcdi.c @@ -609,7 +609,7 @@ static void efx_mcdi_ev_cpl(struct efx_nic *efx, unsigned int seqno, static void efx_mcdi_timeout_async(struct timer_list *t) { - struct efx_mcdi_iface *mcdi = from_timer(mcdi, t, async_timer); + struct efx_mcdi_iface *mcdi = timer_container_of(mcdi, t, async_timer); efx_mcdi_complete_async(mcdi, true); } diff --git a/drivers/net/ethernet/sfc/siena/rx_common.c b/drivers/net/ethernet/sfc/siena/rx_common.c index ab493e529d5c..98d27174015d 100644 --- a/drivers/net/ethernet/sfc/siena/rx_common.c +++ b/drivers/net/ethernet/sfc/siena/rx_common.c @@ -349,7 +349,8 @@ void efx_siena_free_rx_buffers(struct efx_rx_queue *rx_queue, void efx_siena_rx_slow_fill(struct timer_list *t) { - struct efx_rx_queue *rx_queue = from_timer(rx_queue, t, slow_fill); + struct efx_rx_queue *rx_queue = timer_container_of(rx_queue, t, + slow_fill); /* Post an event to cause NAPI to run and refill the queue */ efx_nic_generate_fill_event(rx_queue); diff --git a/drivers/net/ethernet/sgi/ioc3-eth.c b/drivers/net/ethernet/sgi/ioc3-eth.c index 7196e1c607f3..39731069d99e 100644 --- a/drivers/net/ethernet/sgi/ioc3-eth.c +++ b/drivers/net/ethernet/sgi/ioc3-eth.c @@ -570,7 +570,7 @@ static inline void ioc3_setup_duplex(struct ioc3_private *ip) static void ioc3_timer(struct timer_list *t) { - struct ioc3_private *ip = from_timer(ip, t, ioc3_timer); + struct ioc3_private *ip = timer_container_of(ip, t, ioc3_timer); /* Print the link status if it has changed */ mii_check_media(&ip->mii, 1, 0); diff --git a/drivers/net/ethernet/sis/sis190.c b/drivers/net/ethernet/sis/sis190.c index d10b14787607..15e46e6ac262 100644 --- a/drivers/net/ethernet/sis/sis190.c +++ b/drivers/net/ethernet/sis/sis190.c @@ -1023,7 +1023,7 @@ out_unlock: static void sis190_phy_timer(struct timer_list *t) { - struct sis190_private *tp = from_timer(tp, t, timer); + struct sis190_private *tp = timer_container_of(tp, t, timer); struct net_device *dev = tp->dev; if (likely(netif_running(dev))) diff --git a/drivers/net/ethernet/sis/sis900.c b/drivers/net/ethernet/sis/sis900.c index df869f82cae8..b461918dc5f4 100644 --- a/drivers/net/ethernet/sis/sis900.c +++ b/drivers/net/ethernet/sis/sis900.c @@ -1314,7 +1314,8 @@ static void sis630_set_eq(struct net_device *net_dev, u8 revision) static void sis900_timer(struct timer_list *t) { - struct sis900_private *sis_priv = from_timer(sis_priv, t, timer); + struct sis900_private *sis_priv = timer_container_of(sis_priv, t, + timer); struct net_device *net_dev = sis_priv->mii_info.dev; struct mii_phy *mii_phy = sis_priv->mii; static const int next_tick = 5*HZ; diff --git a/drivers/net/ethernet/smsc/epic100.c b/drivers/net/ethernet/smsc/epic100.c index ca0ab3a35b73..45f703fe0e5a 100644 --- a/drivers/net/ethernet/smsc/epic100.c +++ b/drivers/net/ethernet/smsc/epic100.c @@ -850,7 +850,7 @@ static void check_media(struct net_device *dev) static void epic_timer(struct timer_list *t) { - struct epic_private *ep = from_timer(ep, t, timer); + struct epic_private *ep = timer_container_of(ep, t, timer); struct net_device *dev = ep->mii.dev; void __iomem *ioaddr = ep->ioaddr; int next_tick = 5*HZ; diff --git a/drivers/net/ethernet/smsc/smc91c92_cs.c b/drivers/net/ethernet/smsc/smc91c92_cs.c index 6fa957fb523b..cc0c75694351 100644 --- a/drivers/net/ethernet/smsc/smc91c92_cs.c +++ b/drivers/net/ethernet/smsc/smc91c92_cs.c @@ -1713,7 +1713,7 @@ static void smc_reset(struct net_device *dev) static void media_check(struct timer_list *t) { - struct smc_private *smc = from_timer(smc, t, media); + struct smc_private *smc = timer_container_of(smc, t, media); struct net_device *dev = smc->mii_if.dev; unsigned int ioaddr = dev->base_addr; u_short i, media, saved_bank; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 1369fa70bc58..b948df1bff9a 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -481,7 +481,7 @@ static void stmmac_stop_sw_lpi(struct stmmac_priv *priv) */ static void stmmac_eee_ctrl_timer(struct timer_list *t) { - struct stmmac_priv *priv = from_timer(priv, t, eee_ctrl_timer); + struct stmmac_priv *priv = timer_container_of(priv, t, eee_ctrl_timer); stmmac_try_to_start_sw_lpi(priv); } diff --git a/drivers/net/ethernet/sun/cassini.c b/drivers/net/ethernet/sun/cassini.c index b777e5a099eb..acfb523214b9 100644 --- a/drivers/net/ethernet/sun/cassini.c +++ b/drivers/net/ethernet/sun/cassini.c @@ -4021,7 +4021,7 @@ done: static void cas_link_timer(struct timer_list *t) { - struct cas *cp = from_timer(cp, t, link_timer); + struct cas *cp = timer_container_of(cp, t, link_timer); int mask, pending = 0, reset = 0; unsigned long flags; diff --git a/drivers/net/ethernet/sun/niu.c b/drivers/net/ethernet/sun/niu.c index 379b6e90121d..ddca8fc7883e 100644 --- a/drivers/net/ethernet/sun/niu.c +++ b/drivers/net/ethernet/sun/niu.c @@ -2225,7 +2225,7 @@ static int niu_link_status(struct niu *np, int *link_up_p) static void niu_timer(struct timer_list *t) { - struct niu *np = from_timer(np, t, timer); + struct niu *np = timer_container_of(np, t, timer); unsigned long off; int err, link_up; diff --git a/drivers/net/ethernet/sun/sunbmac.c b/drivers/net/ethernet/sun/sunbmac.c index d2c82102133c..edb2fd3a6551 100644 --- a/drivers/net/ethernet/sun/sunbmac.c +++ b/drivers/net/ethernet/sun/sunbmac.c @@ -526,7 +526,7 @@ static int try_next_permutation(struct bigmac *bp, void __iomem *tregs) static void bigmac_timer(struct timer_list *t) { - struct bigmac *bp = from_timer(bp, t, bigmac_timer); + struct bigmac *bp = timer_container_of(bp, t, bigmac_timer); void __iomem *tregs = bp->tregs; int restart_timer = 0; diff --git a/drivers/net/ethernet/sun/sungem.c b/drivers/net/ethernet/sun/sungem.c index 06579d7b5220..8e69d917d827 100644 --- a/drivers/net/ethernet/sun/sungem.c +++ b/drivers/net/ethernet/sun/sungem.c @@ -1481,7 +1481,7 @@ static int gem_mdio_link_not_up(struct gem *gp) static void gem_link_timer(struct timer_list *t) { - struct gem *gp = from_timer(gp, t, link_timer); + struct gem *gp = timer_container_of(gp, t, link_timer); struct net_device *dev = gp->dev; int restart_aneg = 0; diff --git a/drivers/net/ethernet/sun/sunhme.c b/drivers/net/ethernet/sun/sunhme.c index 9a7586623318..4bc0e114d5ee 100644 --- a/drivers/net/ethernet/sun/sunhme.c +++ b/drivers/net/ethernet/sun/sunhme.c @@ -721,7 +721,7 @@ force_link: static void happy_meal_timer(struct timer_list *t) { - struct happy_meal *hp = from_timer(hp, t, happy_timer); + struct happy_meal *hp = timer_container_of(hp, t, happy_timer); void __iomem *tregs = hp->tcvregs; int restart_timer = 0; diff --git a/drivers/net/ethernet/sun/sunvnet_common.c b/drivers/net/ethernet/sun/sunvnet_common.c index ddc6d46a7a86..0212853c9430 100644 --- a/drivers/net/ethernet/sun/sunvnet_common.c +++ b/drivers/net/ethernet/sun/sunvnet_common.c @@ -1044,7 +1044,7 @@ static inline void vnet_free_skbs(struct sk_buff *skb) void sunvnet_clean_timer_expire_common(struct timer_list *t) { - struct vnet_port *port = from_timer(port, t, clean_timer); + struct vnet_port *port = timer_container_of(port, t, clean_timer); struct sk_buff *freeskbs; unsigned pending; diff --git a/drivers/net/ethernet/synopsys/dwc-xlgmac-net.c b/drivers/net/ethernet/synopsys/dwc-xlgmac-net.c index 24e4b246f25f..37101dc50d04 100644 --- a/drivers/net/ethernet/synopsys/dwc-xlgmac-net.c +++ b/drivers/net/ethernet/synopsys/dwc-xlgmac-net.c @@ -360,7 +360,8 @@ static irqreturn_t xlgmac_dma_isr(int irq, void *data) static void xlgmac_tx_timer(struct timer_list *t) { - struct xlgmac_channel *channel = from_timer(channel, t, tx_timer); + struct xlgmac_channel *channel = timer_container_of(channel, t, + tx_timer); struct xlgmac_pdata *pdata = channel->pdata; struct napi_struct *napi; diff --git a/drivers/net/ethernet/ti/cpsw_ale.c b/drivers/net/ethernet/ti/cpsw_ale.c index 7f77694ecfba..fbe35af615a6 100644 --- a/drivers/net/ethernet/ti/cpsw_ale.c +++ b/drivers/net/ethernet/ti/cpsw_ale.c @@ -1231,7 +1231,7 @@ int cpsw_ale_rx_ratelimit_bc(struct cpsw_ale *ale, int port, unsigned int rateli static void cpsw_ale_timer(struct timer_list *t) { - struct cpsw_ale *ale = from_timer(ale, t, timer); + struct cpsw_ale *ale = timer_container_of(ale, t, timer); cpsw_ale_control_set(ale, 0, ALE_AGEOUT, 1); diff --git a/drivers/net/ethernet/ti/netcp_ethss.c b/drivers/net/ethernet/ti/netcp_ethss.c index fd2b74508980..55a1a96cd834 100644 --- a/drivers/net/ethernet/ti/netcp_ethss.c +++ b/drivers/net/ethernet/ti/netcp_ethss.c @@ -2833,7 +2833,7 @@ static int gbe_ioctl(void *intf_priv, struct ifreq *req, int cmd) static void netcp_ethss_timer(struct timer_list *t) { - struct gbe_priv *gbe_dev = from_timer(gbe_dev, t, timer); + struct gbe_priv *gbe_dev = timer_container_of(gbe_dev, t, timer); struct gbe_intf *gbe_intf; struct gbe_slave *slave; diff --git a/drivers/net/ethernet/ti/tlan.c b/drivers/net/ethernet/ti/tlan.c index d9240fb91747..a55b0f951181 100644 --- a/drivers/net/ethernet/ti/tlan.c +++ b/drivers/net/ethernet/ti/tlan.c @@ -1815,7 +1815,7 @@ ThunderLAN driver timer function static void tlan_timer(struct timer_list *t) { - struct tlan_priv *priv = from_timer(priv, t, timer); + struct tlan_priv *priv = timer_container_of(priv, t, timer); struct net_device *dev = priv->dev; u32 elapsed; unsigned long flags = 0; @@ -2746,7 +2746,7 @@ static void tlan_phy_finish_auto_neg(struct net_device *dev) static void tlan_phy_monitor(struct timer_list *t) { - struct tlan_priv *priv = from_timer(priv, t, media_timer); + struct tlan_priv *priv = timer_container_of(priv, t, media_timer); struct net_device *dev = priv->dev; u16 phy; u16 phy_status; diff --git a/drivers/net/ethernet/tundra/tsi108_eth.c b/drivers/net/ethernet/tundra/tsi108_eth.c index 7ec0e3c13d54..7e0b3d694ac0 100644 --- a/drivers/net/ethernet/tundra/tsi108_eth.c +++ b/drivers/net/ethernet/tundra/tsi108_eth.c @@ -1652,7 +1652,7 @@ regs_fail: static void tsi108_timed_checker(struct timer_list *t) { - struct tsi108_prv_data *data = from_timer(data, t, timer); + struct tsi108_prv_data *data = timer_container_of(data, t, timer); struct net_device *dev = data->dev; tsi108_check_phy(dev); diff --git a/drivers/net/ethernet/wangxun/libwx/wx_lib.c b/drivers/net/ethernet/wangxun/libwx/wx_lib.c index 5c747509d56b..7f2e6cddfeb1 100644 --- a/drivers/net/ethernet/wangxun/libwx/wx_lib.c +++ b/drivers/net/ethernet/wangxun/libwx/wx_lib.c @@ -3116,7 +3116,7 @@ EXPORT_SYMBOL(wx_service_event_complete); void wx_service_timer(struct timer_list *t) { - struct wx *wx = from_timer(wx, t, service_timer); + struct wx *wx = timer_container_of(wx, t, service_timer); unsigned long next_event_offset = HZ * 2; /* Reset the timer */ diff --git a/drivers/net/fddi/defza.c b/drivers/net/fddi/defza.c index 54b7f24f3810..2098c3068d34 100644 --- a/drivers/net/fddi/defza.c +++ b/drivers/net/fddi/defza.c @@ -1044,7 +1044,7 @@ static irqreturn_t fza_interrupt(int irq, void *dev_id) static void fza_reset_timer(struct timer_list *t) { - struct fza_private *fp = from_timer(fp, t, reset_timer); + struct fza_private *fp = timer_container_of(fp, t, reset_timer); if (!fp->timer_state) { pr_err("%s: RESET timed out!\n", fp->name); diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c index b33d84ed5bbf..c5e5423e1863 100644 --- a/drivers/net/hamradio/6pack.c +++ b/drivers/net/hamradio/6pack.c @@ -133,7 +133,7 @@ static int encode_sixpack(unsigned char *, unsigned char *, int, unsigned char); static void sp_xmit_on_air(struct timer_list *t) { - struct sixpack *sp = from_timer(sp, t, tx_t); + struct sixpack *sp = timer_container_of(sp, t, tx_t); int actual, when = sp->slottime; static unsigned char random; @@ -491,7 +491,7 @@ static inline void tnc_set_sync_state(struct sixpack *sp, int new_tnc_state) static void resync_tnc(struct timer_list *t) { - struct sixpack *sp = from_timer(sp, t, resync_t); + struct sixpack *sp = timer_container_of(sp, t, resync_t); static char resync_cmd = 0xe8; /* clear any data that might have been received */ diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c index f88721dec681..ae5048efde68 100644 --- a/drivers/net/hamradio/scc.c +++ b/drivers/net/hamradio/scc.c @@ -1127,7 +1127,7 @@ static inline int is_grouped(struct scc_channel *scc) static void t_dwait(struct timer_list *t) { - struct scc_channel *scc = from_timer(scc, t, tx_t); + struct scc_channel *scc = timer_container_of(scc, t, tx_t); if (scc->stat.tx_state == TXS_WAIT) /* maxkeyup or idle timeout */ { @@ -1169,7 +1169,7 @@ static void t_dwait(struct timer_list *t) static void t_txdelay(struct timer_list *t) { - struct scc_channel *scc = from_timer(scc, t, tx_t); + struct scc_channel *scc = timer_container_of(scc, t, tx_t); scc_start_maxkeyup(scc); @@ -1190,7 +1190,7 @@ static void t_txdelay(struct timer_list *t) static void t_tail(struct timer_list *t) { - struct scc_channel *scc = from_timer(scc, t, tx_t); + struct scc_channel *scc = timer_container_of(scc, t, tx_t); unsigned long flags; spin_lock_irqsave(&scc->lock, flags); @@ -1217,7 +1217,7 @@ static void t_tail(struct timer_list *t) static void t_busy(struct timer_list *t) { - struct scc_channel *scc = from_timer(scc, t, tx_wdog); + struct scc_channel *scc = timer_container_of(scc, t, tx_wdog); timer_delete(&scc->tx_t); netif_stop_queue(scc->dev); /* don't pile on the wabbit! */ @@ -1236,7 +1236,7 @@ static void t_busy(struct timer_list *t) static void t_maxkeyup(struct timer_list *t) { - struct scc_channel *scc = from_timer(scc, t, tx_wdog); + struct scc_channel *scc = timer_container_of(scc, t, tx_wdog); unsigned long flags; spin_lock_irqsave(&scc->lock, flags); @@ -1270,7 +1270,7 @@ static void t_maxkeyup(struct timer_list *t) static void t_idle(struct timer_list *t) { - struct scc_channel *scc = from_timer(scc, t, tx_t); + struct scc_channel *scc = timer_container_of(scc, t, tx_t); timer_delete(&scc->tx_wdog); @@ -1403,7 +1403,7 @@ static unsigned long scc_get_param(struct scc_channel *scc, unsigned int cmd) static void scc_stop_calibrate(struct timer_list *t) { - struct scc_channel *scc = from_timer(scc, t, tx_wdog); + struct scc_channel *scc = timer_container_of(scc, t, tx_wdog); unsigned long flags; spin_lock_irqsave(&scc->lock, flags); diff --git a/drivers/net/hippi/rrunner.c b/drivers/net/hippi/rrunner.c index 6342c319c0e4..7b7e7a47a75e 100644 --- a/drivers/net/hippi/rrunner.c +++ b/drivers/net/hippi/rrunner.c @@ -1154,7 +1154,7 @@ static inline void rr_raz_rx(struct rr_private *rrpriv, static void rr_timer(struct timer_list *t) { - struct rr_private *rrpriv = from_timer(rrpriv, t, timer); + struct rr_private *rrpriv = timer_container_of(rrpriv, t, timer); struct net_device *dev = pci_get_drvdata(rrpriv->pci_dev); struct rr_regs __iomem *regs = rrpriv->regs; unsigned long flags; diff --git a/drivers/net/ntb_netdev.c b/drivers/net/ntb_netdev.c index ef4204638392..fbeae05817e9 100644 --- a/drivers/net/ntb_netdev.c +++ b/drivers/net/ntb_netdev.c @@ -229,7 +229,7 @@ err: static void ntb_netdev_tx_timer(struct timer_list *t) { - struct ntb_netdev *dev = from_timer(dev, t, tx_timer); + struct ntb_netdev *dev = timer_container_of(dev, t, tx_timer); struct net_device *ndev = dev->ndev; if (ntb_transport_tx_free_entry(dev->qp) < tx_stop) { diff --git a/drivers/net/slip/slip.c b/drivers/net/slip/slip.c index 3cfa17cd5073..c889fb374703 100644 --- a/drivers/net/slip/slip.c +++ b/drivers/net/slip/slip.c @@ -1378,7 +1378,7 @@ module_exit(slip_exit); static void sl_outfill(struct timer_list *t) { - struct slip *sl = from_timer(sl, t, outfill_timer); + struct slip *sl = timer_container_of(sl, t, outfill_timer); spin_lock(&sl->lock); @@ -1409,7 +1409,7 @@ out: static void sl_keepalive(struct timer_list *t) { - struct slip *sl = from_timer(sl, t, keepalive_timer); + struct slip *sl = timer_container_of(sl, t, keepalive_timer); spin_lock(&sl->lock); diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 1207196cbbed..f8c5e2fd04df 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -377,7 +377,7 @@ static void tun_flow_delete_by_queue(struct tun_struct *tun, u16 queue_index) static void tun_flow_cleanup(struct timer_list *t) { - struct tun_struct *tun = from_timer(tun, t, flow_gc_timer); + struct tun_struct *tun = timer_container_of(tun, t, flow_gc_timer); unsigned long delay = tun->ageing_time; unsigned long next_timer = jiffies + delay; unsigned long count = 0; diff --git a/drivers/net/usb/catc.c b/drivers/net/usb/catc.c index fc5e441aa7c3..6759388692f8 100644 --- a/drivers/net/usb/catc.c +++ b/drivers/net/usb/catc.c @@ -602,7 +602,7 @@ static void catc_stats_done(struct catc *catc, struct ctrl_queue *q) static void catc_stats_timer(struct timer_list *t) { - struct catc *catc = from_timer(catc, t, timer); + struct catc *catc = timer_container_of(catc, t, timer); int i; for (i = 0; i < 8; i++) diff --git a/drivers/net/usb/lan78xx.c b/drivers/net/usb/lan78xx.c index 759dab980a09..f53e255116ea 100644 --- a/drivers/net/usb/lan78xx.c +++ b/drivers/net/usb/lan78xx.c @@ -4642,7 +4642,7 @@ static const struct net_device_ops lan78xx_netdev_ops = { static void lan78xx_stat_monitor(struct timer_list *t) { - struct lan78xx_net *dev = from_timer(dev, t, stat_monitor); + struct lan78xx_net *dev = timer_container_of(dev, t, stat_monitor); lan78xx_defer_kevent(dev, EVENT_STAT_UPDATE); } diff --git a/drivers/net/usb/sierra_net.c b/drivers/net/usb/sierra_net.c index dec6e82eb0e0..c30ca415d1d3 100644 --- a/drivers/net/usb/sierra_net.c +++ b/drivers/net/usb/sierra_net.c @@ -573,7 +573,7 @@ static void sierra_net_defer_kevent(struct usbnet *dev, int work) */ static void sierra_sync_timer(struct timer_list *t) { - struct sierra_net_data *priv = from_timer(priv, t, sync_timer); + struct sierra_net_data *priv = timer_container_of(priv, t, sync_timer); struct usbnet *dev = priv->usbnet; dev_dbg(&dev->udev->dev, "%s", __func__); diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index c39dfa17813a..c04e715a4c2a 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -1551,7 +1551,7 @@ static inline void usb_free_skb(struct sk_buff *skb) static void usbnet_bh (struct timer_list *t) { - struct usbnet *dev = from_timer(dev, t, delay); + struct usbnet *dev = timer_container_of(dev, t, delay); struct sk_buff *skb; struct skb_data *entry; diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c index a56d7239b127..97792de896b7 100644 --- a/drivers/net/vxlan/vxlan_core.c +++ b/drivers/net/vxlan/vxlan_core.c @@ -2809,7 +2809,7 @@ out: /* Walk the forwarding table and purge stale entries */ static void vxlan_cleanup(struct timer_list *t) { - struct vxlan_dev *vxlan = from_timer(vxlan, t, age_timer); + struct vxlan_dev *vxlan = timer_container_of(vxlan, t, age_timer); unsigned long next_timer = jiffies + FDB_AGE_INTERVAL; struct vxlan_fdb *f; diff --git a/drivers/net/wan/hdlc_cisco.c b/drivers/net/wan/hdlc_cisco.c index 7e653432c139..bfc978b15bc2 100644 --- a/drivers/net/wan/hdlc_cisco.c +++ b/drivers/net/wan/hdlc_cisco.c @@ -244,7 +244,7 @@ rx_error: static void cisco_timer(struct timer_list *t) { - struct cisco_state *st = from_timer(st, t, timer); + struct cisco_state *st = timer_container_of(st, t, timer); struct net_device *dev = st->dev; spin_lock(&st->lock); diff --git a/drivers/net/wan/hdlc_fr.c b/drivers/net/wan/hdlc_fr.c index 34014f427060..08a0ba5ca471 100644 --- a/drivers/net/wan/hdlc_fr.c +++ b/drivers/net/wan/hdlc_fr.c @@ -581,7 +581,7 @@ static void fr_set_link_state(int reliable, struct net_device *dev) static void fr_timer(struct timer_list *t) { - struct frad_state *st = from_timer(st, t, timer); + struct frad_state *st = timer_container_of(st, t, timer); struct net_device *dev = st->dev; hdlc_device *hdlc = dev_to_hdlc(dev); int i, cnt = 0, reliable; diff --git a/drivers/net/wan/hdlc_ppp.c b/drivers/net/wan/hdlc_ppp.c index 19921b02846d..7496a2e9a282 100644 --- a/drivers/net/wan/hdlc_ppp.c +++ b/drivers/net/wan/hdlc_ppp.c @@ -561,7 +561,7 @@ out: static void ppp_timer(struct timer_list *t) { - struct proto *proto = from_timer(proto, t, timer); + struct proto *proto = timer_container_of(proto, t, timer); struct ppp *ppp = get_ppp(proto->dev); unsigned long flags; diff --git a/drivers/net/wireguard/timers.c b/drivers/net/wireguard/timers.c index a9e0890c2f77..4016a3065602 100644 --- a/drivers/net/wireguard/timers.c +++ b/drivers/net/wireguard/timers.c @@ -40,8 +40,8 @@ static inline void mod_peer_timer(struct wg_peer *peer, static void wg_expired_retransmit_handshake(struct timer_list *timer) { - struct wg_peer *peer = from_timer(peer, timer, - timer_retransmit_handshake); + struct wg_peer *peer = timer_container_of(peer, timer, + timer_retransmit_handshake); if (peer->timer_handshake_attempts > MAX_TIMER_HANDSHAKES) { pr_debug("%s: Handshake for peer %llu (%pISpfsc) did not complete after %d attempts, giving up\n", @@ -78,7 +78,8 @@ static void wg_expired_retransmit_handshake(struct timer_list *timer) static void wg_expired_send_keepalive(struct timer_list *timer) { - struct wg_peer *peer = from_timer(peer, timer, timer_send_keepalive); + struct wg_peer *peer = timer_container_of(peer, timer, + timer_send_keepalive); wg_packet_send_keepalive(peer); if (peer->timer_need_another_keepalive) { @@ -90,7 +91,8 @@ static void wg_expired_send_keepalive(struct timer_list *timer) static void wg_expired_new_handshake(struct timer_list *timer) { - struct wg_peer *peer = from_timer(peer, timer, timer_new_handshake); + struct wg_peer *peer = timer_container_of(peer, timer, + timer_new_handshake); pr_debug("%s: Retrying handshake with peer %llu (%pISpfsc) because we stopped hearing back after %d seconds\n", peer->device->dev->name, peer->internal_id, @@ -104,7 +106,8 @@ static void wg_expired_new_handshake(struct timer_list *timer) static void wg_expired_zero_key_material(struct timer_list *timer) { - struct wg_peer *peer = from_timer(peer, timer, timer_zero_key_material); + struct wg_peer *peer = timer_container_of(peer, timer, + timer_zero_key_material); rcu_read_lock_bh(); if (!READ_ONCE(peer->is_dead)) { @@ -134,8 +137,8 @@ static void wg_queued_expired_zero_key_material(struct work_struct *work) static void wg_expired_send_persistent_keepalive(struct timer_list *timer) { - struct wg_peer *peer = from_timer(peer, timer, - timer_persistent_keepalive); + struct wg_peer *peer = timer_container_of(peer, timer, + timer_persistent_keepalive); if (likely(peer->persistent_keepalive_interval)) wg_packet_send_keepalive(peer); diff --git a/drivers/net/wireless/ath/ar5523/ar5523.c b/drivers/net/wireless/ath/ar5523/ar5523.c index 96dc2778022a..343c9de2749c 100644 --- a/drivers/net/wireless/ath/ar5523/ar5523.c +++ b/drivers/net/wireless/ath/ar5523/ar5523.c @@ -902,7 +902,7 @@ static void ar5523_tx_work(struct work_struct *work) static void ar5523_tx_wd_timer(struct timer_list *t) { - struct ar5523 *ar = from_timer(ar, t, tx_wd_timer); + struct ar5523 *ar = timer_container_of(ar, t, tx_wd_timer); ar5523_dbg(ar, "TX watchdog timer triggered\n"); ieee80211_queue_work(ar->hw, &ar->tx_wd_work); diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index 52981052e211..fb0d5d4cae3a 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -257,7 +257,8 @@ static void ath10k_htt_rx_msdu_buff_replenish(struct ath10k_htt *htt) static void ath10k_htt_rx_ring_refill_retry(struct timer_list *t) { - struct ath10k_htt *htt = from_timer(htt, t, rx_ring.refill_retry_timer); + struct ath10k_htt *htt = timer_container_of(htt, t, + rx_ring.refill_retry_timer); ath10k_htt_rx_msdu_buff_replenish(htt); } diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 20ec0a6d0f71..1e6d43285138 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -591,7 +591,7 @@ skip: static void ath10k_pci_ps_timer(struct timer_list *t) { - struct ath10k_pci *ar_pci = from_timer(ar_pci, t, ps_timer); + struct ath10k_pci *ar_pci = timer_container_of(ar_pci, t, ps_timer); struct ath10k *ar = ar_pci->ar; unsigned long flags; @@ -844,7 +844,8 @@ void ath10k_pci_rx_post(struct ath10k *ar) void ath10k_pci_rx_replenish_retry(struct timer_list *t) { - struct ath10k_pci *ar_pci = from_timer(ar_pci, t, rx_post_retry); + struct ath10k_pci *ar_pci = timer_container_of(ar_pci, t, + rx_post_retry); struct ath10k *ar = ar_pci->ar; ath10k_pci_rx_post(ar); diff --git a/drivers/net/wireless/ath/ath10k/sdio.c b/drivers/net/wireless/ath/ath10k/sdio.c index f3212eab56a1..c06d50db40b8 100644 --- a/drivers/net/wireless/ath/ath10k/sdio.c +++ b/drivers/net/wireless/ath/ath10k/sdio.c @@ -1447,7 +1447,8 @@ release: static void ath10k_sdio_sleep_timer_handler(struct timer_list *t) { - struct ath10k_sdio *ar_sdio = from_timer(ar_sdio, t, sleep_timer); + struct ath10k_sdio *ar_sdio = timer_container_of(ar_sdio, t, + sleep_timer); ar_sdio->mbox_state = SDIO_MBOX_REQUEST_TO_SLEEP_STATE; queue_work(ar_sdio->workqueue, &ar_sdio->wr_async_work); diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c index 866bad2db334..b2bf9d72b92f 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.c +++ b/drivers/net/wireless/ath/ath10k/snoc.c @@ -644,7 +644,8 @@ static void ath10k_snoc_htt_rx_cb(struct ath10k_ce_pipe *ce_state) static void ath10k_snoc_rx_replenish_retry(struct timer_list *t) { - struct ath10k_snoc *ar_snoc = from_timer(ar_snoc, t, rx_post_retry); + struct ath10k_snoc *ar_snoc = timer_container_of(ar_snoc, t, + rx_post_retry); struct ath10k *ar = ar_snoc->ar; ath10k_snoc_rx_post(ar); diff --git a/drivers/net/wireless/ath/ath11k/ce.c b/drivers/net/wireless/ath/ath11k/ce.c index 9d8efec46508..746038006eb4 100644 --- a/drivers/net/wireless/ath/ath11k/ce.c +++ b/drivers/net/wireless/ath/ath11k/ce.c @@ -907,7 +907,7 @@ EXPORT_SYMBOL(ath11k_ce_rx_post_buf); void ath11k_ce_rx_replenish_retry(struct timer_list *t) { - struct ath11k_base *ab = from_timer(ab, t, rx_replenish_retry); + struct ath11k_base *ab = timer_container_of(ab, t, rx_replenish_retry); ath11k_ce_rx_post_buf(ab); } diff --git a/drivers/net/wireless/ath/ath11k/dp.c b/drivers/net/wireless/ath/ath11k/dp.c index 3a544e5fefca..bf3928ada995 100644 --- a/drivers/net/wireless/ath/ath11k/dp.c +++ b/drivers/net/wireless/ath/ath11k/dp.c @@ -1117,8 +1117,9 @@ fail_link_desc_cleanup: static void ath11k_dp_shadow_timer_handler(struct timer_list *t) { - struct ath11k_hp_update_timer *update_timer = from_timer(update_timer, - t, timer); + struct ath11k_hp_update_timer *update_timer = timer_container_of(update_timer, + t, + timer); struct ath11k_base *ab = update_timer->ab; struct hal_srng *srng = &ab->hal.srng_list[update_timer->ring_id]; diff --git a/drivers/net/wireless/ath/ath11k/dp_rx.c b/drivers/net/wireless/ath/ath11k/dp_rx.c index ea2959305dec..9230a965f6f0 100644 --- a/drivers/net/wireless/ath/ath11k/dp_rx.c +++ b/drivers/net/wireless/ath/ath11k/dp_rx.c @@ -308,7 +308,7 @@ static u8 *ath11k_dp_rxdesc_mpdu_start_addr2(struct ath11k_base *ab, static void ath11k_dp_service_mon_ring(struct timer_list *t) { - struct ath11k_base *ab = from_timer(ab, t, mon_reap_timer); + struct ath11k_base *ab = timer_container_of(ab, t, mon_reap_timer); int i; for (i = 0; i < ab->hw_params.num_rxdma_per_pdev; i++) @@ -3174,7 +3174,8 @@ move_next: static void ath11k_dp_rx_frag_timer(struct timer_list *timer) { - struct dp_rx_tid *rx_tid = from_timer(rx_tid, timer, frag_timer); + struct dp_rx_tid *rx_tid = timer_container_of(rx_tid, timer, + frag_timer); spin_lock_bh(&rx_tid->ab->base_lock); if (rx_tid->last_frag_no && diff --git a/drivers/net/wireless/ath/ath12k/ce.c b/drivers/net/wireless/ath/ath12k/ce.c index 47821a3b060b..3f3439262cf4 100644 --- a/drivers/net/wireless/ath/ath12k/ce.c +++ b/drivers/net/wireless/ath/ath12k/ce.c @@ -868,7 +868,7 @@ void ath12k_ce_rx_post_buf(struct ath12k_base *ab) void ath12k_ce_rx_replenish_retry(struct timer_list *t) { - struct ath12k_base *ab = from_timer(ab, t, rx_replenish_retry); + struct ath12k_base *ab = timer_container_of(ab, t, rx_replenish_retry); ath12k_ce_rx_post_buf(ab); } diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c index 7e1a8f29c7b6..57648febc4a4 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.c +++ b/drivers/net/wireless/ath/ath12k/dp_rx.c @@ -2955,7 +2955,8 @@ exit: static void ath12k_dp_rx_frag_timer(struct timer_list *timer) { - struct ath12k_dp_rx_tid *rx_tid = from_timer(rx_tid, timer, frag_timer); + struct ath12k_dp_rx_tid *rx_tid = timer_container_of(rx_tid, timer, + frag_timer); spin_lock_bh(&rx_tid->ab->base_lock); if (rx_tid->last_frag_no && diff --git a/drivers/net/wireless/ath/ath6kl/main.c b/drivers/net/wireless/ath/ath6kl/main.c index 867089a3c096..d62b96459751 100644 --- a/drivers/net/wireless/ath/ath6kl/main.c +++ b/drivers/net/wireless/ath/ath6kl/main.c @@ -503,7 +503,7 @@ void ath6kl_connect_ap_mode_sta(struct ath6kl_vif *vif, u16 aid, u8 *mac_addr, void disconnect_timer_handler(struct timer_list *t) { - struct ath6kl_vif *vif = from_timer(vif, t, disconnect_timer); + struct ath6kl_vif *vif = timer_container_of(vif, t, disconnect_timer); ath6kl_init_profile_info(vif); ath6kl_disconnect(vif); diff --git a/drivers/net/wireless/ath/ath6kl/recovery.c b/drivers/net/wireless/ath/ath6kl/recovery.c index fd2dceb8b63d..43186c193df1 100644 --- a/drivers/net/wireless/ath/ath6kl/recovery.c +++ b/drivers/net/wireless/ath/ath6kl/recovery.c @@ -62,7 +62,7 @@ void ath6kl_recovery_hb_event(struct ath6kl *ar, u32 cookie) static void ath6kl_recovery_hb_timer(struct timer_list *t) { - struct ath6kl *ar = from_timer(ar, t, fw_recovery.hb_timer); + struct ath6kl *ar = timer_container_of(ar, t, fw_recovery.hb_timer); int err; if (test_bit(RECOVERY_CLEANUP, &ar->flag) || diff --git a/drivers/net/wireless/ath/ath6kl/txrx.c b/drivers/net/wireless/ath/ath6kl/txrx.c index 3a6f0b647e17..c3b06b515c4f 100644 --- a/drivers/net/wireless/ath/ath6kl/txrx.c +++ b/drivers/net/wireless/ath/ath6kl/txrx.c @@ -1623,7 +1623,8 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet) static void aggr_timeout(struct timer_list *t) { u8 i, j; - struct aggr_info_conn *aggr_conn = from_timer(aggr_conn, t, timer); + struct aggr_info_conn *aggr_conn = timer_container_of(aggr_conn, t, + timer); struct rxtid *rxtid; struct rxtid_stats *stats; diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index 3787b9fb0075..84317afe4651 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -1078,7 +1078,7 @@ static int ath6kl_wmi_tkip_micerr_event_rx(struct wmi *wmi, u8 *datap, int len, void ath6kl_wmi_sscan_timer(struct timer_list *t) { - struct ath6kl_vif *vif = from_timer(vif, t, sched_scan_timer); + struct ath6kl_vif *vif = timer_container_of(vif, t, sched_scan_timer); cfg80211_sched_scan_results(vif->ar->wiphy, 0); } diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index 799be0be24f4..121e51ce1bc0 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c @@ -1040,7 +1040,7 @@ static void ath_scan_channel_start(struct ath_softc *sc) static void ath_chanctx_timer(struct timer_list *t) { - struct ath_softc *sc = from_timer(sc, t, sched.timer); + struct ath_softc *sc = timer_container_of(sc, t, sched.timer); struct ath_common *common = ath9k_hw_common(sc->sc_ah); ath_dbg(common, CHAN_CTX, @@ -1051,7 +1051,7 @@ static void ath_chanctx_timer(struct timer_list *t) static void ath_offchannel_timer(struct timer_list *t) { - struct ath_softc *sc = from_timer(sc, t, offchannel.timer); + struct ath_softc *sc = timer_container_of(sc, t, offchannel.timer); struct ath_chanctx *ctx; struct ath_common *common = ath9k_hw_common(sc->sc_ah); diff --git a/drivers/net/wireless/ath/ath9k/gpio.c b/drivers/net/wireless/ath/ath9k/gpio.c index 5a26f1d05f04..2dbc7efdd637 100644 --- a/drivers/net/wireless/ath/ath9k/gpio.c +++ b/drivers/net/wireless/ath/ath9k/gpio.c @@ -193,7 +193,7 @@ static void ath_mci_ftp_adjust(struct ath_softc *sc) */ static void ath_btcoex_period_timer(struct timer_list *t) { - struct ath_softc *sc = from_timer(sc, t, btcoex.period_timer); + struct ath_softc *sc = timer_container_of(sc, t, btcoex.period_timer); struct ath_hw *ah = sc->sc_ah; struct ath_btcoex *btcoex = &sc->btcoex; enum ath_stomp_type stomp_type; @@ -254,7 +254,8 @@ skip_hw_wakeup: */ static void ath_btcoex_no_stomp_timer(struct timer_list *t) { - struct ath_softc *sc = from_timer(sc, t, btcoex.no_stomp_timer); + struct ath_softc *sc = timer_container_of(sc, t, + btcoex.no_stomp_timer); struct ath_hw *ah = sc->sc_ah; struct ath_btcoex *btcoex = &sc->btcoex; diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c index ce9c04e418b8..ee5945cfc10e 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c @@ -760,7 +760,8 @@ static void ath9k_htc_tx_cleanup_queue(struct ath9k_htc_priv *priv, void ath9k_htc_tx_cleanup_timer(struct timer_list *t) { - struct ath9k_htc_priv *priv = from_timer(priv, t, tx.cleanup_timer); + struct ath9k_htc_priv *priv = timer_container_of(priv, t, + tx.cleanup_timer); struct ath_common *common = ath9k_hw_common(priv->ah); struct ath9k_htc_tx_event *event, *tmp; struct sk_buff *skb; diff --git a/drivers/net/wireless/ath/ath9k/link.c b/drivers/net/wireless/ath/ath9k/link.c index 7f890997bb53..5d7e3ddb6dbc 100644 --- a/drivers/net/wireless/ath/ath9k/link.c +++ b/drivers/net/wireless/ath/ath9k/link.c @@ -332,7 +332,7 @@ fail_paprd: */ void ath_ani_calibrate(struct timer_list *t) { - struct ath_common *common = from_timer(common, t, ani.timer); + struct ath_common *common = timer_container_of(common, t, ani.timer); struct ath_softc *sc = common->priv; struct ath_hw *ah = sc->sc_ah; bool longcal = false; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 92fc5e3d756e..c56f4f3b8990 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -98,7 +98,7 @@ static bool ath9k_setpower(struct ath_softc *sc, enum ath9k_power_mode mode) void ath_ps_full_sleep(struct timer_list *t) { - struct ath_softc *sc = from_timer(sc, t, sleep_timer); + struct ath_softc *sc = timer_container_of(sc, t, sleep_timer); struct ath_common *common = ath9k_hw_common(sc->sc_ah); unsigned long flags; bool reset; diff --git a/drivers/net/wireless/ath/wcn36xx/dxe.c b/drivers/net/wireless/ath/wcn36xx/dxe.c index cc2a033e87f5..0f4df5585fd9 100644 --- a/drivers/net/wireless/ath/wcn36xx/dxe.c +++ b/drivers/net/wireless/ath/wcn36xx/dxe.c @@ -373,7 +373,7 @@ void wcn36xx_dxe_tx_ack_ind(struct wcn36xx *wcn, u32 status) static void wcn36xx_dxe_tx_timer(struct timer_list *t) { - struct wcn36xx *wcn = from_timer(wcn, t, tx_ack_timer); + struct wcn36xx *wcn = timer_container_of(wcn, t, tx_ack_timer); struct ieee80211_tx_info *info; unsigned long flags; struct sk_buff *skb; diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c index 59884e8e3765..55c267ab2893 100644 --- a/drivers/net/wireless/ath/wil6210/netdev.c +++ b/drivers/net/wireless/ath/wil6210/netdev.c @@ -227,7 +227,7 @@ static void wil_ndev_destructor(struct net_device *ndev) static void wil_connect_timer_fn(struct timer_list *t) { - struct wil6210_vif *vif = from_timer(vif, t, connect_timer); + struct wil6210_vif *vif = timer_container_of(vif, t, connect_timer); struct wil6210_priv *wil = vif_to_wil(vif); bool q; @@ -243,7 +243,7 @@ static void wil_connect_timer_fn(struct timer_list *t) static void wil_scan_timer_fn(struct timer_list *t) { - struct wil6210_vif *vif = from_timer(vif, t, scan_timer); + struct wil6210_vif *vif = timer_container_of(vif, t, scan_timer); struct wil6210_priv *wil = vif_to_wil(vif); clear_bit(wil_status_fwready, wil->status); @@ -253,7 +253,8 @@ static void wil_scan_timer_fn(struct timer_list *t) static void wil_p2p_discovery_timer_fn(struct timer_list *t) { - struct wil6210_vif *vif = from_timer(vif, t, p2p.discovery_timer); + struct wil6210_vif *vif = timer_container_of(vif, t, + p2p.discovery_timer); struct wil6210_priv *wil = vif_to_wil(vif); wil_dbg_misc(wil, "p2p_discovery_timer_fn\n"); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/btcoex.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/btcoex.c index e0de34a3e43a..69ef8cf203d2 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/btcoex.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/btcoex.c @@ -272,7 +272,8 @@ static void brcmf_btcoex_restore_part1(struct brcmf_btcoex_info *btci) */ static void brcmf_btcoex_timerfunc(struct timer_list *t) { - struct brcmf_btcoex_info *bt_local = from_timer(bt_local, t, timer); + struct brcmf_btcoex_info *bt_local = timer_container_of(bt_local, t, + timer); brcmf_dbg(TRACE, "enter\n"); bt_local->timer_on = false; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index dc2383faddd1..b94c3619526c 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -3557,7 +3557,7 @@ static void brcmf_cfg80211_escan_timeout_worker(struct work_struct *work) static void brcmf_escan_timeout(struct timer_list *t) { struct brcmf_cfg80211_info *cfg = - from_timer(cfg, t, escan_timeout); + timer_container_of(cfg, t, escan_timeout); struct brcmf_pub *drvr = cfg->pub; if (cfg->int_escan_map || cfg->scan_request) { diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c index 9f1854b3d1a5..8f97562811d7 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c @@ -2328,7 +2328,8 @@ brcmf_pcie_fwcon_timer(struct brcmf_pciedev_info *devinfo, bool active) static void brcmf_pcie_fwcon(struct timer_list *t) { - struct brcmf_pciedev_info *devinfo = from_timer(devinfo, t, timer); + struct brcmf_pciedev_info *devinfo = timer_container_of(devinfo, t, + timer); if (!devinfo->console_active) return; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c index 93727b9a5f0d..cf26ab15ee0c 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c @@ -4121,7 +4121,7 @@ brcmf_sdio_watchdog_thread(void *data) static void brcmf_sdio_watchdog(struct timer_list *t) { - struct brcmf_sdio *bus = from_timer(bus, t, timer); + struct brcmf_sdio *bus = timer_container_of(bus, t, timer); if (bus->watchdog_tsk) { complete(&bus->watchdog_wait); diff --git a/drivers/net/wireless/intel/ipw2x00/libipw_crypto.c b/drivers/net/wireless/intel/ipw2x00/libipw_crypto.c index dfcc12aa8620..243d0c5928a2 100644 --- a/drivers/net/wireless/intel/ipw2x00/libipw_crypto.c +++ b/drivers/net/wireless/intel/ipw2x00/libipw_crypto.c @@ -110,8 +110,8 @@ static void libipw_crypt_quiescing(struct libipw_crypt_info *info) static void libipw_crypt_deinit_handler(struct timer_list *t) { - struct libipw_crypt_info *info = from_timer(info, t, - crypt_deinit_timer); + struct libipw_crypt_info *info = timer_container_of(info, t, + crypt_deinit_timer); unsigned long flags; libipw_crypt_deinit_entries(info, 0); diff --git a/drivers/net/wireless/intel/iwlegacy/3945-rs.c b/drivers/net/wireless/intel/iwlegacy/3945-rs.c index df1b8ec86651..1826c37c090c 100644 --- a/drivers/net/wireless/intel/iwlegacy/3945-rs.c +++ b/drivers/net/wireless/intel/iwlegacy/3945-rs.c @@ -168,7 +168,8 @@ il3945_rate_scale_flush_wins(struct il3945_rs_sta *rs_sta) static void il3945_bg_rate_scale_flush(struct timer_list *t) { - struct il3945_rs_sta *rs_sta = from_timer(rs_sta, t, rate_scale_flush); + struct il3945_rs_sta *rs_sta = timer_container_of(rs_sta, t, + rate_scale_flush); struct il_priv *il __maybe_unused = rs_sta->il; int unflushed = 0; unsigned long flags; diff --git a/drivers/net/wireless/intel/iwlegacy/4965-mac.c b/drivers/net/wireless/intel/iwlegacy/4965-mac.c index dc8c408902e6..8e58e97a148f 100644 --- a/drivers/net/wireless/intel/iwlegacy/4965-mac.c +++ b/drivers/net/wireless/intel/iwlegacy/4965-mac.c @@ -4051,7 +4051,7 @@ il4965_hdl_alive(struct il_priv *il, struct il_rx_buf *rxb) static void il4965_bg_stats_periodic(struct timer_list *t) { - struct il_priv *il = from_timer(il, t, stats_periodic); + struct il_priv *il = timer_container_of(il, t, stats_periodic); if (test_bit(S_EXIT_PENDING, &il->status)) return; diff --git a/drivers/net/wireless/intel/iwlegacy/common.c b/drivers/net/wireless/intel/iwlegacy/common.c index 09fb4b758704..9a86688aea67 100644 --- a/drivers/net/wireless/intel/iwlegacy/common.c +++ b/drivers/net/wireless/intel/iwlegacy/common.c @@ -4804,7 +4804,7 @@ il_check_stuck_queue(struct il_priv *il, int cnt) void il_bg_watchdog(struct timer_list *t) { - struct il_priv *il = from_timer(il, t, watchdog); + struct il_priv *il = timer_container_of(il, t, watchdog); int cnt; unsigned long timeout; diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/main.c b/drivers/net/wireless/intel/iwlwifi/dvm/main.c index 1d619384c629..dbfd45948e8b 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/main.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/main.c @@ -381,7 +381,8 @@ int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags, bool clear) */ static void iwl_bg_statistics_periodic(struct timer_list *t) { - struct iwl_priv *priv = from_timer(priv, t, statistics_periodic); + struct iwl_priv *priv = timer_container_of(priv, t, + statistics_periodic); if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; @@ -537,7 +538,7 @@ static void iwl_continuous_event_trace(struct iwl_priv *priv) */ static void iwl_bg_ucode_trace(struct timer_list *t) { - struct iwl_priv *priv = from_timer(priv, t, ucode_trace); + struct iwl_priv *priv = timer_container_of(priv, t, ucode_trace); if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/tt.c b/drivers/net/wireless/intel/iwlwifi/dvm/tt.c index 98f0949b3683..96831ce8da6f 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/tt.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/tt.c @@ -137,8 +137,8 @@ enum iwl_antenna_ok iwl_tx_ant_restriction(struct iwl_priv *priv) */ static void iwl_tt_check_exit_ct_kill(struct timer_list *t) { - struct iwl_priv *priv = from_timer(priv, t, - thermal_throttle.ct_kill_exit_tm); + struct iwl_priv *priv = timer_container_of(priv, t, + thermal_throttle.ct_kill_exit_tm); struct iwl_tt_mgmt *tt = &priv->thermal_throttle; if (test_bit(STATUS_EXIT_PENDING, &priv->status)) @@ -187,8 +187,8 @@ static void iwl_perform_ct_kill_task(struct iwl_priv *priv, static void iwl_tt_ready_for_ct_kill(struct timer_list *t) { - struct iwl_priv *priv = from_timer(priv, t, - thermal_throttle.ct_kill_waiting_tm); + struct iwl_priv *priv = timer_container_of(priv, t, + thermal_throttle.ct_kill_waiting_tm); struct iwl_tt_mgmt *tt = &priv->thermal_throttle; if (test_bit(STATUS_EXIT_PENDING, &priv->status)) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c index 5c8f6dc9a3e0..5240dacf1360 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c @@ -949,7 +949,7 @@ static void iwl_dbg_tlv_apply_config(struct iwl_fw_runtime *fwrt, static void iwl_dbg_tlv_periodic_trig_handler(struct timer_list *t) { struct iwl_dbg_tlv_timer_node *timer_node = - from_timer(timer_node, t, timer); + timer_container_of(timer_node, t, timer); struct iwl_fwrt_dump_data dump_data = { .trig = (void *)timer_node->tlv->data, }; diff --git a/drivers/net/wireless/intel/iwlwifi/mld/agg.c b/drivers/net/wireless/intel/iwlwifi/mld/agg.c index bda488ae9eec..6b349270481d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/agg.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/agg.c @@ -317,7 +317,7 @@ EXPORT_SYMBOL_IF_IWLWIFI_KUNIT(iwl_mld_reorder); static void iwl_mld_rx_agg_session_expired(struct timer_list *t) { struct iwl_mld_baid_data *data = - from_timer(data, t, session_timer); + timer_container_of(data, t, session_timer); struct iwl_mld_baid_data __rcu **rcu_ptr = data->rcu_ptr; struct iwl_mld_baid_data *ba_data; struct ieee80211_link_sta *link_sta; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index 8ec4a007b4b0..5f6797598998 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -253,7 +253,7 @@ int iwl_mvm_sta_send_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta, static void iwl_mvm_rx_agg_session_expired(struct timer_list *t) { struct iwl_mvm_baid_data *data = - from_timer(data, t, session_timer); + timer_container_of(data, t, session_timer); struct iwl_mvm_baid_data __rcu **rcu_ptr = data->rcu_ptr; struct iwl_mvm_baid_data *ba_data; struct ieee80211_sta *sta; diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c index 7abd7c7daa89..bb467e2b1779 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c @@ -700,7 +700,7 @@ void iwl_txq_log_scd_error(struct iwl_trans *trans, struct iwl_txq *txq) static void iwl_txq_stuck_timer(struct timer_list *t) { - struct iwl_txq *txq = from_timer(txq, t, stuck_timer); + struct iwl_txq *txq = timer_container_of(txq, t, stuck_timer); struct iwl_trans *trans = txq->trans; spin_lock(&txq->lock); diff --git a/drivers/net/wireless/marvell/libertas/if_usb.c b/drivers/net/wireless/marvell/libertas/if_usb.c index ea3cc2eaec36..b3c4040257a6 100644 --- a/drivers/net/wireless/marvell/libertas/if_usb.c +++ b/drivers/net/wireless/marvell/libertas/if_usb.c @@ -165,7 +165,7 @@ static void if_usb_setup_firmware(struct lbs_private *priv) static void if_usb_fw_timeo(struct timer_list *t) { - struct if_usb_card *cardp = from_timer(cardp, t, fw_timeout); + struct if_usb_card *cardp = timer_container_of(cardp, t, fw_timeout); if (cardp->fwdnldover) { lbs_deb_usb("Download complete, no event. Assuming success\n"); diff --git a/drivers/net/wireless/marvell/libertas/main.c b/drivers/net/wireless/marvell/libertas/main.c index 26d13e9b3c95..d44e02c6fe38 100644 --- a/drivers/net/wireless/marvell/libertas/main.c +++ b/drivers/net/wireless/marvell/libertas/main.c @@ -693,7 +693,7 @@ EXPORT_SYMBOL_GPL(lbs_resume); */ static void lbs_cmd_timeout_handler(struct timer_list *t) { - struct lbs_private *priv = from_timer(priv, t, command_timer); + struct lbs_private *priv = timer_container_of(priv, t, command_timer); unsigned long flags; spin_lock_irqsave(&priv->driver_lock, flags); @@ -727,7 +727,8 @@ out: */ static void lbs_tx_lockup_handler(struct timer_list *t) { - struct lbs_private *priv = from_timer(priv, t, tx_lockup_timer); + struct lbs_private *priv = timer_container_of(priv, t, + tx_lockup_timer); unsigned long flags; spin_lock_irqsave(&priv->driver_lock, flags); diff --git a/drivers/net/wireless/marvell/libertas_tf/if_usb.c b/drivers/net/wireless/marvell/libertas_tf/if_usb.c index 7c413dc81f9a..5662a244f82a 100644 --- a/drivers/net/wireless/marvell/libertas_tf/if_usb.c +++ b/drivers/net/wireless/marvell/libertas_tf/if_usb.c @@ -113,7 +113,7 @@ static void if_usb_setup_firmware(struct lbtf_private *priv) static void if_usb_fw_timeo(struct timer_list *t) { - struct if_usb_card *cardp = from_timer(cardp, t, fw_timeout); + struct if_usb_card *cardp = timer_container_of(cardp, t, fw_timeout); lbtf_deb_enter(LBTF_DEB_USB); if (!cardp->fwdnldover) { diff --git a/drivers/net/wireless/marvell/libertas_tf/main.c b/drivers/net/wireless/marvell/libertas_tf/main.c index a57a11be57d8..50c0f6179e2d 100644 --- a/drivers/net/wireless/marvell/libertas_tf/main.c +++ b/drivers/net/wireless/marvell/libertas_tf/main.c @@ -126,7 +126,7 @@ static void lbtf_cmd_work(struct work_struct *work) */ static void command_timer_fn(struct timer_list *t) { - struct lbtf_private *priv = from_timer(priv, t, command_timer); + struct lbtf_private *priv = timer_container_of(priv, t, command_timer); unsigned long flags; lbtf_deb_enter(LBTF_DEB_CMD); diff --git a/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c b/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c index 8aff1df09b40..354c5ce66045 100644 --- a/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c +++ b/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c @@ -300,7 +300,7 @@ static void mwifiex_flush_data(struct timer_list *t) { struct reorder_tmr_cnxt *ctx = - from_timer(ctx, t, timer); + timer_container_of(ctx, t, timer); int start_win, seq_num; ctx->timer_is_set = false; diff --git a/drivers/net/wireless/marvell/mwifiex/cmdevt.c b/drivers/net/wireless/marvell/mwifiex/cmdevt.c index 3bf27efe4537..0f466c31337f 100644 --- a/drivers/net/wireless/marvell/mwifiex/cmdevt.c +++ b/drivers/net/wireless/marvell/mwifiex/cmdevt.c @@ -934,7 +934,8 @@ void mwifiex_process_assoc_resp(struct mwifiex_adapter *adapter) void mwifiex_cmd_timeout_func(struct timer_list *t) { - struct mwifiex_adapter *adapter = from_timer(adapter, t, cmd_timer); + struct mwifiex_adapter *adapter = timer_container_of(adapter, t, + cmd_timer); struct cmd_ctrl_node *cmd_node; set_bit(MWIFIEX_IS_CMD_TIMEDOUT, &adapter->work_flags); diff --git a/drivers/net/wireless/marvell/mwifiex/init.c b/drivers/net/wireless/marvell/mwifiex/init.c index 32c374e47794..4820010a86f6 100644 --- a/drivers/net/wireless/marvell/mwifiex/init.c +++ b/drivers/net/wireless/marvell/mwifiex/init.c @@ -41,7 +41,8 @@ static int mwifiex_add_bss_prio_tbl(struct mwifiex_private *priv) static void wakeup_timer_fn(struct timer_list *t) { - struct mwifiex_adapter *adapter = from_timer(adapter, t, wakeup_timer); + struct mwifiex_adapter *adapter = timer_container_of(adapter, t, + wakeup_timer); mwifiex_dbg(adapter, ERROR, "Firmware wakeup failed\n"); adapter->hw_status = MWIFIEX_HW_STATUS_RESET; diff --git a/drivers/net/wireless/marvell/mwifiex/tdls.c b/drivers/net/wireless/marvell/mwifiex/tdls.c index 18e8c04d14c4..77a9a6de636d 100644 --- a/drivers/net/wireless/marvell/mwifiex/tdls.c +++ b/drivers/net/wireless/marvell/mwifiex/tdls.c @@ -1415,7 +1415,8 @@ void mwifiex_auto_tdls_update_peer_signal(struct mwifiex_private *priv, void mwifiex_check_auto_tdls(struct timer_list *t) { - struct mwifiex_private *priv = from_timer(priv, t, auto_tdls_timer); + struct mwifiex_private *priv = timer_container_of(priv, t, + auto_tdls_timer); struct mwifiex_auto_tdls_peer *tdls_peer; u16 reason = WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED; diff --git a/drivers/net/wireless/marvell/mwifiex/usb.c b/drivers/net/wireless/marvell/mwifiex/usb.c index 2f565397cf36..947ecb0a7b40 100644 --- a/drivers/net/wireless/marvell/mwifiex/usb.c +++ b/drivers/net/wireless/marvell/mwifiex/usb.c @@ -1125,7 +1125,7 @@ static void mwifiex_usb_tx_aggr_tmo(struct timer_list *t) struct urb_context *urb_cnxt = NULL; struct sk_buff *skb_send = NULL; struct tx_aggr_tmr_cnxt *timer_context = - from_timer(timer_context, t, hold_timer); + timer_container_of(timer_context, t, hold_timer); struct mwifiex_adapter *adapter = timer_context->adapter; struct usb_tx_data_port *port = timer_context->port; int err = 0; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index c54005df08ca..8a37fb37f77d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -1043,7 +1043,7 @@ void mt7615_roc_work(struct work_struct *work) void mt7615_roc_timer(struct timer_list *timer) { - struct mt7615_phy *phy = from_timer(phy, timer, roc_timer); + struct mt7615_phy *phy = timer_container_of(phy, timer, roc_timer); ieee80211_queue_work(phy->mt76->hw, &phy->roc_work); } diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_core.c b/drivers/net/wireless/mediatek/mt76/mt792x_core.c index 38dd58f6e493..a50c1723ca29 100644 --- a/drivers/net/wireless/mediatek/mt76/mt792x_core.c +++ b/drivers/net/wireless/mediatek/mt76/mt792x_core.c @@ -283,7 +283,7 @@ EXPORT_SYMBOL_GPL(mt792x_tx_worker); void mt792x_roc_timer(struct timer_list *timer) { - struct mt792x_phy *phy = from_timer(phy, timer, roc_timer); + struct mt792x_phy *phy = timer_container_of(phy, timer, roc_timer); ieee80211_queue_work(phy->mt76->hw, &phy->roc_work); } @@ -291,7 +291,7 @@ EXPORT_SYMBOL_GPL(mt792x_roc_timer); void mt792x_csa_timer(struct timer_list *timer) { - struct mt792x_vif *mvif = from_timer(mvif, timer, csa_timer); + struct mt792x_vif *mvif = timer_container_of(mvif, timer, csa_timer); ieee80211_queue_work(mvif->phy->mt76->hw, &mvif->csa_work); } diff --git a/drivers/net/wireless/microchip/wilc1000/hif.c b/drivers/net/wireless/microchip/wilc1000/hif.c index cb46a39ef757..a229c6cab332 100644 --- a/drivers/net/wireless/microchip/wilc1000/hif.c +++ b/drivers/net/wireless/microchip/wilc1000/hif.c @@ -953,8 +953,8 @@ static void wilc_handle_listen_state_expired(struct work_struct *work) static void listen_timer_cb(struct timer_list *t) { - struct host_if_drv *hif_drv = from_timer(hif_drv, t, - remain_on_ch_timer); + struct host_if_drv *hif_drv = timer_container_of(hif_drv, t, + remain_on_ch_timer); struct wilc_vif *vif = hif_drv->remain_on_ch_timer_vif; int result; struct host_if_msg *msg; @@ -1075,7 +1075,8 @@ static void handle_scan_complete(struct work_struct *work) static void timer_scan_cb(struct timer_list *t) { - struct host_if_drv *hif_drv = from_timer(hif_drv, t, scan_timer); + struct host_if_drv *hif_drv = timer_container_of(hif_drv, t, + scan_timer); struct wilc_vif *vif = hif_drv->scan_timer_vif; struct host_if_msg *msg; int result; @@ -1091,8 +1092,8 @@ static void timer_scan_cb(struct timer_list *t) static void timer_connect_cb(struct timer_list *t) { - struct host_if_drv *hif_drv = from_timer(hif_drv, t, - connect_timer); + struct host_if_drv *hif_drv = timer_container_of(hif_drv, t, + connect_timer); struct wilc_vif *vif = hif_drv->connect_timer_vif; struct host_if_msg *msg; int result; @@ -1497,7 +1498,7 @@ int wilc_hif_set_cfg(struct wilc_vif *vif, struct cfg_param_attr *param) static void get_periodic_rssi(struct timer_list *t) { - struct wilc_vif *vif = from_timer(vif, t, periodic_rssi); + struct wilc_vif *vif = timer_container_of(vif, t, periodic_rssi); if (!vif->hif_drv) { netdev_err(vif->ndev, "%s: hif driver is NULL", __func__); diff --git a/drivers/net/wireless/purelifi/plfxlc/usb.c b/drivers/net/wireless/purelifi/plfxlc/usb.c index c2a1234b59db..d8b0b79dea1a 100644 --- a/drivers/net/wireless/purelifi/plfxlc/usb.c +++ b/drivers/net/wireless/purelifi/plfxlc/usb.c @@ -548,7 +548,7 @@ error: static void slif_data_plane_sap_timer_callb(struct timer_list *t) { - struct plfxlc_usb *usb = from_timer(usb, t, tx.tx_retry_timer); + struct plfxlc_usb *usb = timer_container_of(usb, t, tx.tx_retry_timer); plfxlc_send_packet_from_data_queue(usb); timer_setup(&usb->tx.tx_retry_timer, @@ -558,7 +558,7 @@ static void slif_data_plane_sap_timer_callb(struct timer_list *t) static void sta_queue_cleanup_timer_callb(struct timer_list *t) { - struct plfxlc_usb *usb = from_timer(usb, t, sta_queue_cleanup); + struct plfxlc_usb *usb = timer_container_of(usb, t, sta_queue_cleanup); struct plfxlc_usb_tx *tx = &usb->tx; int sidx; diff --git a/drivers/net/wireless/realtek/rtlwifi/base.c b/drivers/net/wireless/realtek/rtlwifi/base.c index 6189edc1d8d7..e26feb8de658 100644 --- a/drivers/net/wireless/realtek/rtlwifi/base.c +++ b/drivers/net/wireless/realtek/rtlwifi/base.c @@ -2220,7 +2220,8 @@ label_lps_done: void rtl_watch_dog_timer_callback(struct timer_list *t) { - struct rtl_priv *rtlpriv = from_timer(rtlpriv, t, works.watchdog_timer); + struct rtl_priv *rtlpriv = timer_container_of(rtlpriv, t, + works.watchdog_timer); queue_delayed_work(rtlpriv->works.rtl_wq, &rtlpriv->works.watchdog_wq, 0); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/dm.c b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/dm.c index 5a34894a533b..f749d19ec5f5 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/dm.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/dm.c @@ -1684,7 +1684,8 @@ static void rtl88e_dm_fast_ant_training(struct ieee80211_hw *hw) void rtl88e_dm_fast_antenna_training_callback(struct timer_list *t) { struct rtl_priv *rtlpriv = - from_timer(rtlpriv, t, works.fast_antenna_training_timer); + timer_container_of(rtlpriv, t, + works.fast_antenna_training_timer); struct ieee80211_hw *hw = rtlpriv->hw; rtl88e_dm_fast_ant_training(hw); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/hw.c index 27f6c35ba0f9..d122f1eb345e 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/hw.c @@ -237,8 +237,8 @@ static void _rtl88ee_set_fw_ps_rf_off_low_power(struct ieee80211_hw *hw) void rtl88ee_fw_clk_off_timer_callback(struct timer_list *t) { - struct rtl_priv *rtlpriv = from_timer(rtlpriv, t, - works.fw_clockoff_timer); + struct rtl_priv *rtlpriv = timer_container_of(rtlpriv, t, + works.fw_clockoff_timer); struct ieee80211_hw *hw = rtlpriv->hw; _rtl88ee_set_fw_ps_rf_off_low_power(hw); diff --git a/drivers/net/wireless/realtek/rtw88/tx.c b/drivers/net/wireless/realtek/rtw88/tx.c index 6ed470dd6f22..2ab440cb2d67 100644 --- a/drivers/net/wireless/realtek/rtw88/tx.c +++ b/drivers/net/wireless/realtek/rtw88/tx.c @@ -178,7 +178,8 @@ static void rtw_tx_report_enable(struct rtw_dev *rtwdev, void rtw_tx_report_purge_timer(struct timer_list *t) { - struct rtw_dev *rtwdev = from_timer(rtwdev, t, tx_report.purge_timer); + struct rtw_dev *rtwdev = timer_container_of(rtwdev, t, + tx_report.purge_timer); struct rtw_tx_report *tx_report = &rtwdev->tx_report; unsigned long flags; diff --git a/drivers/net/wireless/rsi/rsi_91x_hal.c b/drivers/net/wireless/rsi/rsi_91x_hal.c index 53827657abb2..7d26314a3e76 100644 --- a/drivers/net/wireless/rsi/rsi_91x_hal.c +++ b/drivers/net/wireless/rsi/rsi_91x_hal.c @@ -490,7 +490,7 @@ int rsi_prepare_beacon(struct rsi_common *common, struct sk_buff *skb) static void bl_cmd_timeout(struct timer_list *t) { - struct rsi_hw *adapter = from_timer(adapter, t, bl_cmd_timer); + struct rsi_hw *adapter = timer_container_of(adapter, t, bl_cmd_timer); adapter->blcmd_timer_expired = true; timer_delete(&adapter->bl_cmd_timer); diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c index 9db08200f4fa..0e115b428f96 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c +++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c @@ -1746,7 +1746,7 @@ static void rsi_resume_conn_channel(struct rsi_common *common) void rsi_roc_timeout(struct timer_list *t) { - struct rsi_common *common = from_timer(common, t, roc_timer); + struct rsi_common *common = timer_container_of(common, t, roc_timer); rsi_dbg(INFO_ZONE, "Remain on channel expired\n"); diff --git a/drivers/net/wireless/st/cw1200/queue.c b/drivers/net/wireless/st/cw1200/queue.c index 4fd76183c368..a933e2c7dc2c 100644 --- a/drivers/net/wireless/st/cw1200/queue.c +++ b/drivers/net/wireless/st/cw1200/queue.c @@ -133,7 +133,7 @@ static void cw1200_queue_gc(struct timer_list *t) { LIST_HEAD(list); struct cw1200_queue *queue = - from_timer(queue, t, gc); + timer_container_of(queue, t, gc); spin_lock_bh(&queue->lock); __cw1200_queue_gc(queue, &list, true); diff --git a/drivers/net/wireless/st/cw1200/sta.c b/drivers/net/wireless/st/cw1200/sta.c index 444272caf124..5dd7f6a38900 100644 --- a/drivers/net/wireless/st/cw1200/sta.c +++ b/drivers/net/wireless/st/cw1200/sta.c @@ -2112,7 +2112,8 @@ void cw1200_multicast_stop_work(struct work_struct *work) void cw1200_mcast_timeout(struct timer_list *t) { - struct cw1200_common *priv = from_timer(priv, t, mcast_timeout); + struct cw1200_common *priv = timer_container_of(priv, t, + mcast_timeout); wiphy_warn(priv->hw->wiphy, "Multicast delivery timeout.\n"); diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index ea9bc4717a85..f93c95edd991 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -189,7 +189,8 @@ out: static void wl1271_rx_streaming_timer(struct timer_list *t) { - struct wl12xx_vif *wlvif = from_timer(wlvif, t, rx_streaming_timer); + struct wl12xx_vif *wlvif = timer_container_of(wlvif, t, + rx_streaming_timer); struct wl1271 *wl = wlvif->wl; ieee80211_queue_work(wl->hw, &wlvif->rx_streaming_disable_work); } diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index 5836995d6774..c759ebc56457 100644 --- a/drivers/net/xen-netback/netback.c +++ b/drivers/net/xen-netback/netback.c @@ -198,7 +198,8 @@ static void tx_add_credit(struct xenvif_queue *queue) void xenvif_tx_credit_callback(struct timer_list *t) { - struct xenvif_queue *queue = from_timer(queue, t, credit_timeout); + struct xenvif_queue *queue = timer_container_of(queue, t, + credit_timeout); tx_add_credit(queue); xenvif_napi_schedule_or_enable_events(queue); } diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index 5091e1fa4a0d..9bac50963477 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -245,7 +245,8 @@ static bool xennet_can_sg(struct net_device *dev) static void rx_refill_timeout(struct timer_list *t) { - struct netfront_queue *queue = from_timer(queue, t, rx_refill_timer); + struct netfront_queue *queue = timer_container_of(queue, t, + rx_refill_timer); napi_schedule(&queue->napi); } diff --git a/drivers/nfc/nfcmrvl/fw_dnld.c b/drivers/nfc/nfcmrvl/fw_dnld.c index 43ce0c9b2355..a9b03dcc4100 100644 --- a/drivers/nfc/nfcmrvl/fw_dnld.c +++ b/drivers/nfc/nfcmrvl/fw_dnld.c @@ -119,7 +119,8 @@ static void fw_dnld_over(struct nfcmrvl_private *priv, u32 error) static void fw_dnld_timeout(struct timer_list *t) { - struct nfcmrvl_private *priv = from_timer(priv, t, fw_dnld.timer); + struct nfcmrvl_private *priv = timer_container_of(priv, t, + fw_dnld.timer); nfc_err(priv->dev, "FW loading timeout"); priv->fw_dnld.state = STATE_RESET; diff --git a/drivers/nfc/pn533/pn533.c b/drivers/nfc/pn533/pn533.c index 34c40d10e260..14661249c690 100644 --- a/drivers/nfc/pn533/pn533.c +++ b/drivers/nfc/pn533/pn533.c @@ -1233,7 +1233,7 @@ static int pn533_init_target_complete(struct pn533 *dev, struct sk_buff *resp) static void pn533_listen_mode_timer(struct timer_list *t) { - struct pn533 *dev = from_timer(dev, t, listen_timer); + struct pn533 *dev = timer_container_of(dev, t, listen_timer); dev->cancel_listen = 1; diff --git a/drivers/nfc/pn533/uart.c b/drivers/nfc/pn533/uart.c index 580c9193e4a7..a081bce61c29 100644 --- a/drivers/nfc/pn533/uart.c +++ b/drivers/nfc/pn533/uart.c @@ -133,7 +133,7 @@ static const struct pn533_phy_ops uart_phy_ops = { static void pn532_cmd_timeout(struct timer_list *t) { - struct pn532_uart_phy *dev = from_timer(dev, t, cmd_timeout); + struct pn532_uart_phy *dev = timer_container_of(dev, t, cmd_timeout); pn532_uart_send_frame(dev->priv, dev->cur_out_buf); } diff --git a/drivers/nfc/st-nci/ndlc.c b/drivers/nfc/st-nci/ndlc.c index 8feac119a4bc..be4808859cfa 100644 --- a/drivers/nfc/st-nci/ndlc.c +++ b/drivers/nfc/st-nci/ndlc.c @@ -237,14 +237,14 @@ EXPORT_SYMBOL(ndlc_recv); static void ndlc_t1_timeout(struct timer_list *t) { - struct llt_ndlc *ndlc = from_timer(ndlc, t, t1_timer); + struct llt_ndlc *ndlc = timer_container_of(ndlc, t, t1_timer); schedule_work(&ndlc->sm_work); } static void ndlc_t2_timeout(struct timer_list *t) { - struct llt_ndlc *ndlc = from_timer(ndlc, t, t2_timer); + struct llt_ndlc *ndlc = timer_container_of(ndlc, t, t2_timer); schedule_work(&ndlc->sm_work); } diff --git a/drivers/nfc/st-nci/se.c b/drivers/nfc/st-nci/se.c index 8cfe5405bae6..607ec768eb7b 100644 --- a/drivers/nfc/st-nci/se.c +++ b/drivers/nfc/st-nci/se.c @@ -696,7 +696,8 @@ static void st_nci_se_wt_timeout(struct timer_list *t) */ /* hardware reset managed through VCC_UICC_OUT power supply */ u8 param = 0x01; - struct st_nci_info *info = from_timer(info, t, se_info.bwi_timer); + struct st_nci_info *info = timer_container_of(info, t, + se_info.bwi_timer); info->se_info.bwi_active = false; @@ -714,8 +715,8 @@ static void st_nci_se_wt_timeout(struct timer_list *t) static void st_nci_se_activation_timeout(struct timer_list *t) { - struct st_nci_info *info = from_timer(info, t, - se_info.se_active_timer); + struct st_nci_info *info = timer_container_of(info, t, + se_info.se_active_timer); info->se_info.se_active = false; diff --git a/drivers/nfc/st21nfca/se.c b/drivers/nfc/st21nfca/se.c index 9a50f3c03bd4..7154bc1d644a 100644 --- a/drivers/nfc/st21nfca/se.c +++ b/drivers/nfc/st21nfca/se.c @@ -280,15 +280,16 @@ static void st21nfca_se_wt_work(struct work_struct *work) static void st21nfca_se_wt_timeout(struct timer_list *t) { - struct st21nfca_hci_info *info = from_timer(info, t, se_info.bwi_timer); + struct st21nfca_hci_info *info = timer_container_of(info, t, + se_info.bwi_timer); schedule_work(&info->se_info.timeout_work); } static void st21nfca_se_activation_timeout(struct timer_list *t) { - struct st21nfca_hci_info *info = from_timer(info, t, - se_info.se_active_timer); + struct st21nfca_hci_info *info = timer_container_of(info, t, + se_info.se_active_timer); info->se_info.se_active = false; diff --git a/drivers/nvme/common/auth.c b/drivers/nvme/common/auth.c index 3b6d759bcdf2..91e273b89fea 100644 --- a/drivers/nvme/common/auth.c +++ b/drivers/nvme/common/auth.c @@ -471,7 +471,7 @@ EXPORT_SYMBOL_GPL(nvme_auth_generate_key); * @c1: Value of challenge C1 * @c2: Value of challenge C2 * @hash_len: Hash length of the hash algorithm - * @ret_psk: Pointer too the resulting generated PSK + * @ret_psk: Pointer to the resulting generated PSK * @ret_len: length of @ret_psk * * Generate a PSK for TLS as specified in NVMe base specification, section @@ -759,8 +759,8 @@ int nvme_auth_derive_tls_psk(int hmac_id, u8 *psk, size_t psk_len, goto out_free_prk; /* - * 2 addtional bytes for the length field from HDKF-Expand-Label, - * 2 addtional bytes for the HMAC ID, and one byte for the space + * 2 additional bytes for the length field from HDKF-Expand-Label, + * 2 additional bytes for the HMAC ID, and one byte for the space * separator. */ info_len = strlen(psk_digest) + strlen(psk_prefix) + 5; diff --git a/drivers/nvme/host/Kconfig b/drivers/nvme/host/Kconfig index 7dca58f0a237..31974c7dd20c 100644 --- a/drivers/nvme/host/Kconfig +++ b/drivers/nvme/host/Kconfig @@ -106,7 +106,7 @@ config NVME_TCP_TLS help Enables TLS encryption for NVMe TCP using the netlink handshake API. - The TLS handshake daemon is availble at + The TLS handshake daemon is available at https://github.com/oracle/ktls-utils. If unsure, say N. diff --git a/drivers/nvme/host/constants.c b/drivers/nvme/host/constants.c index 2b9e6cfaf2a8..1a0058be5821 100644 --- a/drivers/nvme/host/constants.c +++ b/drivers/nvme/host/constants.c @@ -145,7 +145,7 @@ static const char * const nvme_statuses[] = { [NVME_SC_BAD_ATTRIBUTES] = "Conflicting Attributes", [NVME_SC_INVALID_PI] = "Invalid Protection Information", [NVME_SC_READ_ONLY] = "Attempted Write to Read Only Range", - [NVME_SC_ONCS_NOT_SUPPORTED] = "ONCS Not Supported", + [NVME_SC_CMD_SIZE_LIM_EXCEEDED ] = "Command Size Limits Exceeded", [NVME_SC_ZONE_BOUNDARY_ERROR] = "Zoned Boundary Error", [NVME_SC_ZONE_FULL] = "Zone Is Full", [NVME_SC_ZONE_READ_ONLY] = "Zone Is Read Only", diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index f69a232a000a..92697f98c601 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -290,7 +290,6 @@ static blk_status_t nvme_error_status(u16 status) case NVME_SC_NS_NOT_READY: return BLK_STS_TARGET; case NVME_SC_BAD_ATTRIBUTES: - case NVME_SC_ONCS_NOT_SUPPORTED: case NVME_SC_INVALID_OPCODE: case NVME_SC_INVALID_FIELD: case NVME_SC_INVALID_NS: @@ -1027,7 +1026,7 @@ static inline blk_status_t nvme_setup_rw(struct nvme_ns *ns, if (ns->head->ms) { /* - * If formated with metadata, the block layer always provides a + * If formatted with metadata, the block layer always provides a * metadata buffer if CONFIG_BLK_DEV_INTEGRITY is enabled. Else * we enable the PRACT bit for protection information or set the * namespace capacity to zero to prevent any I/O. diff --git a/drivers/nvme/host/fabrics.c b/drivers/nvme/host/fabrics.c index 93e9041b9657..2e58a7ce1090 100644 --- a/drivers/nvme/host/fabrics.c +++ b/drivers/nvme/host/fabrics.c @@ -582,7 +582,7 @@ EXPORT_SYMBOL_GPL(nvmf_connect_io_queue); * Do not retry when: * * - the DNR bit is set and the specification states no further connect - * attempts with the same set of paramenters should be attempted. + * attempts with the same set of parameters should be attempted. * * - when the authentication attempt fails, because the key was invalid. * This error code is set on the host side. diff --git a/drivers/nvme/host/fabrics.h b/drivers/nvme/host/fabrics.h index 9cf5b020adba..1b58ee7d0dce 100644 --- a/drivers/nvme/host/fabrics.h +++ b/drivers/nvme/host/fabrics.h @@ -80,7 +80,7 @@ enum { * @transport: Holds the fabric transport "technology name" (for a lack of * better description) that will be used by an NVMe controller * being added. - * @subsysnqn: Hold the fully qualified NQN subystem name (format defined + * @subsysnqn: Hold the fully qualified NQN subsystem name (format defined * in the NVMe specification, "NVMe Qualified Names"). * @traddr: The transport-specific TRADDR field for a port on the * subsystem which is adding a controller. @@ -156,7 +156,7 @@ struct nvmf_ctrl_options { * @create_ctrl(): function pointer that points to a non-NVMe * implementation-specific fabric technology * that would go into starting up that fabric - * for the purpose of conneciton to an NVMe controller + * for the purpose of connection to an NVMe controller * using that fabric technology. * * Notes: @@ -165,7 +165,7 @@ struct nvmf_ctrl_options { * 2. create_ctrl() must be defined (even if it does nothing) * 3. struct nvmf_transport_ops must be statically allocated in the * modules .bss section so that a pure module_get on @module - * prevents the memory from beeing freed. + * prevents the memory from being freed. */ struct nvmf_transport_ops { struct list_head entry; diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c index fdafa3e9e66f..014b387f1e8b 100644 --- a/drivers/nvme/host/fc.c +++ b/drivers/nvme/host/fc.c @@ -1955,7 +1955,7 @@ nvme_fc_fcpio_done(struct nvmefc_fcp_req *req) } /* - * For the linux implementation, if we have an unsuccesful + * For the linux implementation, if we have an unsucceesful * status, they blk-mq layer can typically be called with the * non-zero status and the content of the cqe isn't important. */ @@ -2479,7 +2479,7 @@ __nvme_fc_abort_outstanding_ios(struct nvme_fc_ctrl *ctrl, bool start_queues) * writing the registers for shutdown and polling (call * nvme_disable_ctrl()). Given a bunch of i/o was potentially * just aborted and we will wait on those contexts, and given - * there was no indication of how live the controlelr is on the + * there was no indication of how live the controller is on the * link, don't send more io to create more contexts for the * shutdown. Let the controller fail via keepalive failure if * its still present. diff --git a/drivers/nvme/host/ioctl.c b/drivers/nvme/host/ioctl.c index ca86d3bf7ea4..0b50da2f1175 100644 --- a/drivers/nvme/host/ioctl.c +++ b/drivers/nvme/host/ioctl.c @@ -493,13 +493,15 @@ static int nvme_uring_cmd_io(struct nvme_ctrl *ctrl, struct nvme_ns *ns, d.timeout_ms = READ_ONCE(cmd->timeout_ms); if (d.data_len && (ioucmd->flags & IORING_URING_CMD_FIXED)) { - /* fixedbufs is only for non-vectored io */ - if (vec) - return -EINVAL; + int ddir = nvme_is_write(&c) ? WRITE : READ; - ret = io_uring_cmd_import_fixed(d.addr, d.data_len, - nvme_is_write(&c) ? WRITE : READ, &iter, ioucmd, - issue_flags); + if (vec) + ret = io_uring_cmd_import_fixed_vec(ioucmd, + u64_to_user_ptr(d.addr), d.data_len, + ddir, &iter, issue_flags); + else + ret = io_uring_cmd_import_fixed(d.addr, d.data_len, + ddir, &iter, ioucmd, issue_flags); if (ret < 0) return ret; @@ -521,7 +523,7 @@ static int nvme_uring_cmd_io(struct nvme_ctrl *ctrl, struct nvme_ns *ns, if (d.data_len) { ret = nvme_map_user_request(req, d.addr, d.data_len, nvme_to_user_ptr(d.metadata), d.metadata_len, - map_iter, vec); + map_iter, vec ? NVME_IOCTL_VEC : 0); if (ret) goto out_free_req; } @@ -727,7 +729,7 @@ int nvme_ns_head_ioctl(struct block_device *bdev, blk_mode_t mode, /* * Handle ioctls that apply to the controller instead of the namespace - * seperately and drop the ns SRCU reference early. This avoids a + * separately and drop the ns SRCU reference early. This avoids a * deadlock when deleting namespaces using the passthrough interface. */ if (is_ctrl_ioctl(cmd)) diff --git a/drivers/nvme/host/multipath.c b/drivers/nvme/host/multipath.c index 878ea8b1a0ac..e040e467f9fa 100644 --- a/drivers/nvme/host/multipath.c +++ b/drivers/nvme/host/multipath.c @@ -760,7 +760,7 @@ int nvme_mpath_alloc_disk(struct nvme_ctrl *ctrl, struct nvme_ns_head *head) * controller's scan_work context. If a path error occurs here, the IO * will wait until a path becomes available or all paths are torn down, * but that action also occurs within scan_work, so it would deadlock. - * Defer the partion scan to a different context that does not block + * Defer the partition scan to a different context that does not block * scan_work. */ set_bit(GD_SUPPRESS_PART_SCAN, &head->disk->state); @@ -998,7 +998,7 @@ void nvme_mpath_update(struct nvme_ctrl *ctrl) static void nvme_anatt_timeout(struct timer_list *t) { - struct nvme_ctrl *ctrl = from_timer(ctrl, t, anatt_timer); + struct nvme_ctrl *ctrl = timer_container_of(ctrl, t, anatt_timer); dev_info(ctrl->device, "ANATT timeout, resetting controller.\n"); nvme_reset_ctrl(ctrl); diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h index ad0c1f834f09..a468cdc5b5cb 100644 --- a/drivers/nvme/host/nvme.h +++ b/drivers/nvme/host/nvme.h @@ -523,7 +523,7 @@ static inline bool nvme_ns_head_multipath(struct nvme_ns_head *head) enum nvme_ns_features { NVME_NS_EXT_LBAS = 1 << 0, /* support extended LBA format */ NVME_NS_METADATA_SUPPORTED = 1 << 1, /* support getting generated md */ - NVME_NS_DEAC = 1 << 2, /* DEAC bit in Write Zeores supported */ + NVME_NS_DEAC = 1 << 2, /* DEAC bit in Write Zeroes supported */ }; struct nvme_ns { diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index e0bfe04a2bc2..8ff12e415cb5 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -3015,7 +3015,7 @@ static void nvme_reset_work(struct work_struct *work) goto out; /* - * Freeze and update the number of I/O queues as thos might have + * Freeze and update the number of I/O queues as those might have * changed. If there are no I/O queues left after this reset, keep the * controller around but remove all namespaces. */ @@ -3186,7 +3186,7 @@ static unsigned long check_vendor_combination_bug(struct pci_dev *pdev) /* * Exclude some Kingston NV1 and A2000 devices from * NVME_QUIRK_SIMPLE_SUSPEND. Do a full suspend to save a - * lot fo energy with s2idle sleep on some TUXEDO platforms. + * lot of energy with s2idle sleep on some TUXEDO platforms. */ if (dmi_match(DMI_BOARD_NAME, "NS5X_NS7XAU") || dmi_match(DMI_BOARD_NAME, "NS5x_7xAU") || diff --git a/drivers/nvme/host/pr.c b/drivers/nvme/host/pr.c index cf2d2c5039dd..ca6a74607b13 100644 --- a/drivers/nvme/host/pr.c +++ b/drivers/nvme/host/pr.c @@ -82,8 +82,6 @@ static int nvme_status_to_pr_err(int status) return PR_STS_SUCCESS; case NVME_SC_RESERVATION_CONFLICT: return PR_STS_RESERVATION_CONFLICT; - case NVME_SC_ONCS_NOT_SUPPORTED: - return -EOPNOTSUPP; case NVME_SC_BAD_ATTRIBUTES: case NVME_SC_INVALID_OPCODE: case NVME_SC_INVALID_FIELD: diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c index b5a0295b5bf4..9bd3646568d0 100644 --- a/drivers/nvme/host/rdma.c +++ b/drivers/nvme/host/rdma.c @@ -221,7 +221,7 @@ static struct nvme_rdma_qe *nvme_rdma_alloc_ring(struct ib_device *ibdev, /* * Bind the CQEs (post recv buffers) DMA mapping to the RDMA queue - * lifetime. It's safe, since any chage in the underlying RDMA device + * lifetime. It's safe, since any change in the underlying RDMA device * will issue error recovery and queue re-creation. */ for (i = 0; i < ib_queue_size; i++) { @@ -800,7 +800,7 @@ static int nvme_rdma_configure_admin_queue(struct nvme_rdma_ctrl *ctrl, /* * Bind the async event SQE DMA mapping to the admin queue lifetime. - * It's safe, since any chage in the underlying RDMA device will issue + * It's safe, since any change in the underlying RDMA device will issue * error recovery and queue re-creation. */ error = nvme_rdma_alloc_qe(ctrl->device->dev, &ctrl->async_event_sqe, diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c index f6379aa33d77..d924008c3949 100644 --- a/drivers/nvme/host/tcp.c +++ b/drivers/nvme/host/tcp.c @@ -452,7 +452,8 @@ nvme_tcp_fetch_request(struct nvme_tcp_queue *queue) return NULL; } - list_del(&req->entry); + list_del_init(&req->entry); + init_llist_node(&req->lentry); return req; } @@ -565,6 +566,8 @@ static int nvme_tcp_init_request(struct blk_mq_tag_set *set, req->queue = queue; nvme_req(rq)->ctrl = &ctrl->ctrl; nvme_req(rq)->cmd = &pdu->cmd; + init_llist_node(&req->lentry); + INIT_LIST_HEAD(&req->entry); return 0; } @@ -769,6 +772,14 @@ static int nvme_tcp_handle_r2t(struct nvme_tcp_queue *queue, return -EPROTO; } + if (llist_on_list(&req->lentry) || + !list_empty(&req->entry)) { + dev_err(queue->ctrl->ctrl.device, + "req %d unexpected r2t while processing request\n", + rq->tag); + return -EPROTO; + } + req->pdu_len = 0; req->h2cdata_left = r2t_length; req->h2cdata_offset = r2t_offset; @@ -1355,7 +1366,7 @@ static int nvme_tcp_try_recv(struct nvme_tcp_queue *queue) queue->nr_cqe = 0; consumed = sock->ops->read_sock(sk, &rd_desc, nvme_tcp_recv_skb); release_sock(sk); - return consumed; + return consumed == -EAGAIN ? 0 : consumed; } static void nvme_tcp_io_work(struct work_struct *w) @@ -1383,6 +1394,11 @@ static void nvme_tcp_io_work(struct work_struct *w) else if (unlikely(result < 0)) return; + /* did we get some space after spending time in recv? */ + if (nvme_tcp_queue_has_pending(queue) && + sk_stream_is_writeable(queue->sock->sk)) + pending = true; + if (!pending || !queue->rd_enabled) return; @@ -2350,7 +2366,7 @@ static int nvme_tcp_setup_ctrl(struct nvme_ctrl *ctrl, bool new) nvme_tcp_teardown_admin_queue(ctrl, false); ret = nvme_tcp_configure_admin_queue(ctrl, false); if (ret) - return ret; + goto destroy_admin; } if (ctrl->icdoff) { @@ -2594,6 +2610,8 @@ static void nvme_tcp_submit_async_event(struct nvme_ctrl *arg) ctrl->async_req.offset = 0; ctrl->async_req.curr_bio = NULL; ctrl->async_req.data_len = 0; + init_llist_node(&ctrl->async_req.lentry); + INIT_LIST_HEAD(&ctrl->async_req.entry); nvme_tcp_queue_request(&ctrl->async_req, true); } diff --git a/drivers/nvme/target/admin-cmd.c b/drivers/nvme/target/admin-cmd.c index c7317299078d..3e378153a781 100644 --- a/drivers/nvme/target/admin-cmd.c +++ b/drivers/nvme/target/admin-cmd.c @@ -1165,7 +1165,7 @@ static void nvmet_execute_identify(struct nvmet_req *req) * A "minimum viable" abort implementation: the command is mandatory in the * spec, but we are not required to do any useful work. We couldn't really * do a useful abort, so don't bother even with waiting for the command - * to be exectuted and return immediately telling the command to abort + * to be executed and return immediately telling the command to abort * wasn't found. */ static void nvmet_execute_abort(struct nvmet_req *req) diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c index db7b17d1094e..175c5b6d4dd5 100644 --- a/drivers/nvme/target/core.c +++ b/drivers/nvme/target/core.c @@ -62,14 +62,7 @@ inline u16 errno_to_nvme_status(struct nvmet_req *req, int errno) return NVME_SC_LBA_RANGE | NVME_STATUS_DNR; case -EOPNOTSUPP: req->error_loc = offsetof(struct nvme_common_command, opcode); - switch (req->cmd->common.opcode) { - case nvme_cmd_dsm: - case nvme_cmd_write_zeroes: - return NVME_SC_ONCS_NOT_SUPPORTED | NVME_STATUS_DNR; - default: - return NVME_SC_INVALID_OPCODE | NVME_STATUS_DNR; - } - break; + return NVME_SC_INVALID_OPCODE | NVME_STATUS_DNR; case -ENODATA: req->error_loc = offsetof(struct nvme_rw_command, nsid); return NVME_SC_ACCESS_DENIED; @@ -651,7 +644,7 @@ void nvmet_ns_disable(struct nvmet_ns *ns) * Now that we removed the namespaces from the lookup list, we * can kill the per_cpu ref and wait for any remaining references * to be dropped, as well as a RCU grace period for anyone only - * using the namepace under rcu_read_lock(). Note that we can't + * using the namespace under rcu_read_lock(). Note that we can't * use call_rcu here as we need to ensure the namespaces have * been fully destroyed before unloading the module. */ diff --git a/drivers/nvme/target/fc.c b/drivers/nvme/target/fc.c index 254537b93e63..25598a46bf0d 100644 --- a/drivers/nvme/target/fc.c +++ b/drivers/nvme/target/fc.c @@ -1339,7 +1339,7 @@ nvmet_fc_portentry_rebind_tgt(struct nvmet_fc_tgtport *tgtport) /** * nvmet_fc_register_targetport - transport entry point called by an * LLDD to register the existence of a local - * NVME subystem FC port. + * NVME subsystem FC port. * @pinfo: pointer to information about the port to be registered * @template: LLDD entrypoints and operational parameters for the port * @dev: physical hardware device node port corresponds to. Will be diff --git a/drivers/nvme/target/io-cmd-bdev.c b/drivers/nvme/target/io-cmd-bdev.c index 83be0657e6df..eba42df2f821 100644 --- a/drivers/nvme/target/io-cmd-bdev.c +++ b/drivers/nvme/target/io-cmd-bdev.c @@ -133,7 +133,7 @@ u16 blk_to_nvme_status(struct nvmet_req *req, blk_status_t blk_sts) * Right now there exists M : 1 mapping between block layer error * to the NVMe status code (see nvme_error_status()). For consistency, * when we reverse map we use most appropriate NVMe Status code from - * the group of the NVMe staus codes used in the nvme_error_status(). + * the group of the NVMe status codes used in the nvme_error_status(). */ switch (blk_sts) { case BLK_STS_NOSPC: @@ -145,15 +145,8 @@ u16 blk_to_nvme_status(struct nvmet_req *req, blk_status_t blk_sts) req->error_loc = offsetof(struct nvme_rw_command, slba); break; case BLK_STS_NOTSUPP: + status = NVME_SC_INVALID_OPCODE | NVME_STATUS_DNR; req->error_loc = offsetof(struct nvme_common_command, opcode); - switch (req->cmd->common.opcode) { - case nvme_cmd_dsm: - case nvme_cmd_write_zeroes: - status = NVME_SC_ONCS_NOT_SUPPORTED | NVME_STATUS_DNR; - break; - default: - status = NVME_SC_INVALID_OPCODE | NVME_STATUS_DNR; - } break; case BLK_STS_MEDIUM: status = NVME_SC_ACCESS_DENIED; diff --git a/drivers/nvme/target/passthru.c b/drivers/nvme/target/passthru.c index 26e2907ce8bb..b7515c53829b 100644 --- a/drivers/nvme/target/passthru.c +++ b/drivers/nvme/target/passthru.c @@ -99,7 +99,7 @@ static u16 nvmet_passthru_override_id_ctrl(struct nvmet_req *req) /* * The passthru NVMe driver may have a limit on the number of segments - * which depends on the host's memory fragementation. To solve this, + * which depends on the host's memory fragmentation. To solve this, * ensure mdts is limited to the pages equal to the number of segments. */ max_hw_sectors = min_not_zero(pctrl->max_segments << PAGE_SECTORS_SHIFT, diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig index 3de07ef52490..d370b2ad11e7 100644 --- a/drivers/nvmem/Kconfig +++ b/drivers/nvmem/Kconfig @@ -40,6 +40,19 @@ config NVMEM_APPLE_EFUSES This driver can also be built as a module. If so, the module will be called nvmem-apple-efuses. +config NVMEM_APPLE_SPMI + tristate "Apple SPMI NVMEM" + depends on ARCH_APPLE || COMPILE_TEST + depends on SPMI + select REGMAP_SPMI + help + Say y here to build a driver to expose NVMEM cells for a set of power + and RTC-related settings on a SPMI-attached PMIC present on Apple + devices, such as Apple Silicon Macs. + + This driver can also be built as a module. If so, the module + will be called apple-nvmem-spmi. + config NVMEM_BCM_OCOTP tristate "Broadcom On-Chip OTP Controller support" depends on ARCH_BCM_IPROC || COMPILE_TEST @@ -272,6 +285,7 @@ config NVMEM_RCAR_EFUSE config NVMEM_RMEM tristate "Reserved Memory Based Driver Support" depends on HAS_IOMEM + select CRC32 help This driver maps reserved memory into an nvmem device. It might be useful to expose information left by firmware in memory. diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile index a9d03cfbbd27..2021d59688db 100644 --- a/drivers/nvmem/Makefile +++ b/drivers/nvmem/Makefile @@ -12,6 +12,8 @@ obj-y += layouts/ # Devices obj-$(CONFIG_NVMEM_APPLE_EFUSES) += nvmem-apple-efuses.o nvmem-apple-efuses-y := apple-efuses.o +obj-$(CONFIG_NVMEM_APPLE_SPMI) += apple_nvmem_spmi.o +apple_nvmem_spmi-y := apple-spmi-nvmem.o obj-$(CONFIG_NVMEM_BCM_OCOTP) += nvmem-bcm-ocotp.o nvmem-bcm-ocotp-y := bcm-ocotp.o obj-$(CONFIG_NVMEM_BRCM_NVRAM) += nvmem_brcm_nvram.o diff --git a/drivers/nvmem/apple-spmi-nvmem.c b/drivers/nvmem/apple-spmi-nvmem.c new file mode 100644 index 000000000000..88614005d5ce --- /dev/null +++ b/drivers/nvmem/apple-spmi-nvmem.c @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* + * Apple SPMI NVMEM driver + * + * Copyright The Asahi Linux Contributors + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/nvmem-provider.h> +#include <linux/of.h> +#include <linux/spmi.h> +#include <linux/regmap.h> + +static const struct regmap_config apple_spmi_regmap_config = { + .reg_bits = 16, + .val_bits = 8, + .max_register = 0xffff, +}; + +static int apple_spmi_nvmem_probe(struct spmi_device *sdev) +{ + struct regmap *regmap; + struct nvmem_config nvmem_cfg = { + .dev = &sdev->dev, + .name = "spmi_nvmem", + .id = NVMEM_DEVID_AUTO, + .word_size = 1, + .stride = 1, + .size = 0xffff, + .reg_read = (void *)regmap_bulk_read, + .reg_write = (void *)regmap_bulk_write, + }; + + regmap = devm_regmap_init_spmi_ext(sdev, &apple_spmi_regmap_config); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + nvmem_cfg.priv = regmap; + + return PTR_ERR_OR_ZERO(devm_nvmem_register(&sdev->dev, &nvmem_cfg)); +} + +static const struct of_device_id apple_spmi_nvmem_id_table[] = { + { .compatible = "apple,spmi-nvmem" }, + { }, +}; +MODULE_DEVICE_TABLE(of, apple_spmi_nvmem_id_table); + +static struct spmi_driver apple_spmi_nvmem_driver = { + .probe = apple_spmi_nvmem_probe, + .driver = { + .name = "apple-spmi-nvmem", + .of_match_table = apple_spmi_nvmem_id_table, + }, +}; + +module_spmi_driver(apple_spmi_nvmem_driver); + +MODULE_LICENSE("Dual MIT/GPL"); +MODULE_AUTHOR("Hector Martin <marcan@marcan.st>"); +MODULE_DESCRIPTION("Apple SPMI NVMEM driver"); diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index e206efc29a00..fd2a9698d1c9 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -47,9 +47,6 @@ struct nvmem_cell { static DEFINE_MUTEX(nvmem_mutex); static DEFINE_IDA(nvmem_ida); -static DEFINE_MUTEX(nvmem_cell_mutex); -static LIST_HEAD(nvmem_cell_tables); - static DEFINE_MUTEX(nvmem_lookup_mutex); static LIST_HEAD(nvmem_lookup_list); @@ -719,41 +716,6 @@ int nvmem_unregister_notifier(struct notifier_block *nb) } EXPORT_SYMBOL_GPL(nvmem_unregister_notifier); -static int nvmem_add_cells_from_table(struct nvmem_device *nvmem) -{ - const struct nvmem_cell_info *info; - struct nvmem_cell_table *table; - struct nvmem_cell_entry *cell; - int rval = 0, i; - - mutex_lock(&nvmem_cell_mutex); - list_for_each_entry(table, &nvmem_cell_tables, node) { - if (strcmp(nvmem_dev_name(nvmem), table->nvmem_name) == 0) { - for (i = 0; i < table->ncells; i++) { - info = &table->cells[i]; - - cell = kzalloc(sizeof(*cell), GFP_KERNEL); - if (!cell) { - rval = -ENOMEM; - goto out; - } - - rval = nvmem_cell_info_to_nvmem_cell_entry(nvmem, info, cell); - if (rval) { - kfree(cell); - goto out; - } - - nvmem_cell_entry_add(cell); - } - } - } - -out: - mutex_unlock(&nvmem_cell_mutex); - return rval; -} - static struct nvmem_cell_entry * nvmem_find_cell_entry_by_name(struct nvmem_device *nvmem, const char *cell_id) { @@ -1040,10 +1002,6 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config) goto err_remove_cells; } - rval = nvmem_add_cells_from_table(nvmem); - if (rval) - goto err_remove_cells; - if (config->add_legacy_fixed_of_cells) { rval = nvmem_add_cells_from_legacy_of(nvmem); if (rval) @@ -2152,32 +2110,6 @@ int nvmem_device_write(struct nvmem_device *nvmem, EXPORT_SYMBOL_GPL(nvmem_device_write); /** - * nvmem_add_cell_table() - register a table of cell info entries - * - * @table: table of cell info entries - */ -void nvmem_add_cell_table(struct nvmem_cell_table *table) -{ - mutex_lock(&nvmem_cell_mutex); - list_add_tail(&table->node, &nvmem_cell_tables); - mutex_unlock(&nvmem_cell_mutex); -} -EXPORT_SYMBOL_GPL(nvmem_add_cell_table); - -/** - * nvmem_del_cell_table() - remove a previously registered cell info table - * - * @table: table of cell info entries - */ -void nvmem_del_cell_table(struct nvmem_cell_table *table) -{ - mutex_lock(&nvmem_cell_mutex); - list_del(&table->node); - mutex_unlock(&nvmem_cell_mutex); -} -EXPORT_SYMBOL_GPL(nvmem_del_cell_table); - -/** * nvmem_add_cell_lookups() - register a list of cell lookup entries * * @entries: array of cell lookup entries diff --git a/drivers/nvmem/zynqmp_nvmem.c b/drivers/nvmem/zynqmp_nvmem.c index 8682adaacd69..7da717d6c7fa 100644 --- a/drivers/nvmem/zynqmp_nvmem.c +++ b/drivers/nvmem/zynqmp_nvmem.c @@ -213,6 +213,7 @@ static int zynqmp_nvmem_probe(struct platform_device *pdev) econfig.word_size = 1; econfig.size = ZYNQMP_NVMEM_SIZE; econfig.dev = dev; + econfig.priv = dev; econfig.add_legacy_fixed_of_cells = true; econfig.reg_read = zynqmp_nvmem_read; econfig.reg_write = zynqmp_nvmem_write; diff --git a/drivers/parport/ieee1284.c b/drivers/parport/ieee1284.c index 474515d27e9c..4035010249cd 100644 --- a/drivers/parport/ieee1284.c +++ b/drivers/parport/ieee1284.c @@ -40,7 +40,7 @@ static void parport_ieee1284_wakeup (struct parport *port) static void timeout_waiting_on_port (struct timer_list *t) { - struct parport *port = from_timer(port, t, timer); + struct parport *port = timer_container_of(port, t, timer); parport_ieee1284_wakeup (port); } diff --git a/drivers/pci/hotplug/cpqphp_ctrl.c b/drivers/pci/hotplug/cpqphp_ctrl.c index 20529d1a3c44..760a5dec0431 100644 --- a/drivers/pci/hotplug/cpqphp_ctrl.c +++ b/drivers/pci/hotplug/cpqphp_ctrl.c @@ -1883,7 +1883,7 @@ void cpqhp_pushbutton_thread(struct timer_list *t) { u8 hp_slot; struct pci_func *func; - struct slot *p_slot = from_timer(p_slot, t, task_event); + struct slot *p_slot = timer_container_of(p_slot, t, task_event); struct controller *ctrl = (struct controller *) p_slot->ctrl; pushbutton_pending = NULL; diff --git a/drivers/pci/hotplug/shpchp_hpc.c b/drivers/pci/hotplug/shpchp_hpc.c index 387b85585263..183bf43510a1 100644 --- a/drivers/pci/hotplug/shpchp_hpc.c +++ b/drivers/pci/hotplug/shpchp_hpc.c @@ -211,7 +211,7 @@ static inline int shpc_indirect_read(struct controller *ctrl, int index, */ static void int_poll_timeout(struct timer_list *t) { - struct controller *ctrl = from_timer(ctrl, t, poll_timer); + struct controller *ctrl = timer_container_of(ctrl, t, poll_timer); /* Poll for interrupt events. regs == NULL => polling */ shpc_isr(0, ctrl); diff --git a/drivers/pci/msi/irqdomain.c b/drivers/pci/msi/irqdomain.c index d7ba8795d60f..c05152733993 100644 --- a/drivers/pci/msi/irqdomain.c +++ b/drivers/pci/msi/irqdomain.c @@ -271,6 +271,7 @@ static bool pci_create_device_domain(struct pci_dev *pdev, const struct msi_doma /** * pci_setup_msi_device_domain - Setup a device MSI interrupt domain * @pdev: The PCI device to create the domain on + * @hwsize: The maximum number of MSI vectors * * Return: * True when: @@ -287,7 +288,7 @@ static bool pci_create_device_domain(struct pci_dev *pdev, const struct msi_doma * - The device is removed * - MSI is disabled and a MSI-X domain is created */ -bool pci_setup_msi_device_domain(struct pci_dev *pdev) +bool pci_setup_msi_device_domain(struct pci_dev *pdev, unsigned int hwsize) { if (WARN_ON_ONCE(pdev->msix_enabled)) return false; @@ -297,7 +298,7 @@ bool pci_setup_msi_device_domain(struct pci_dev *pdev) if (pci_match_device_domain(pdev, DOMAIN_BUS_PCI_DEVICE_MSIX)) msi_remove_device_irq_domain(&pdev->dev, MSI_DEFAULT_DOMAIN); - return pci_create_device_domain(pdev, &pci_msi_template, 1); + return pci_create_device_domain(pdev, &pci_msi_template, hwsize); } /** diff --git a/drivers/pci/msi/msi.c b/drivers/pci/msi/msi.c index d6ce04054702..6ede55a7c5e6 100644 --- a/drivers/pci/msi/msi.c +++ b/drivers/pci/msi/msi.c @@ -439,16 +439,16 @@ int __pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec, if (nvec < minvec) return -ENOSPC; - if (nvec > maxvec) - nvec = maxvec; - rc = pci_setup_msi_context(dev); if (rc) return rc; - if (!pci_setup_msi_device_domain(dev)) + if (!pci_setup_msi_device_domain(dev, nvec)) return -ENODEV; + if (nvec > maxvec) + nvec = maxvec; + for (;;) { if (affd) { nvec = irq_calc_affinity_vectors(minvec, nvec, affd); diff --git a/drivers/pci/msi/msi.h b/drivers/pci/msi/msi.h index fc70b601e942..0b420b319f50 100644 --- a/drivers/pci/msi/msi.h +++ b/drivers/pci/msi/msi.h @@ -107,7 +107,7 @@ enum support_mode { }; bool pci_msi_domain_supports(struct pci_dev *dev, unsigned int feature_mask, enum support_mode mode); -bool pci_setup_msi_device_domain(struct pci_dev *pdev); +bool pci_setup_msi_device_domain(struct pci_dev *pdev, unsigned int hwsize); bool pci_setup_msix_device_domain(struct pci_dev *pdev, unsigned int hwsize); /* Legacy (!IRQDOMAIN) fallbacks */ diff --git a/drivers/pcmcia/bcm63xx_pcmcia.c b/drivers/pcmcia/bcm63xx_pcmcia.c index 85874b7a9f36..d3baed444646 100644 --- a/drivers/pcmcia/bcm63xx_pcmcia.c +++ b/drivers/pcmcia/bcm63xx_pcmcia.c @@ -268,7 +268,7 @@ static void bcm63xx_pcmcia_poll(struct timer_list *t) struct bcm63xx_pcmcia_socket *skt; unsigned int stat, events; - skt = from_timer(skt, t, timer); + skt = timer_container_of(skt, t, timer); spin_lock_bh(&skt->lock); diff --git a/drivers/pcmcia/electra_cf.c b/drivers/pcmcia/electra_cf.c index 3bdd939dd2f4..2530079d38f4 100644 --- a/drivers/pcmcia/electra_cf.c +++ b/drivers/pcmcia/electra_cf.c @@ -68,7 +68,7 @@ static int electra_cf_ss_init(struct pcmcia_socket *s) /* the timer is primarily to kick this socket's pccardd */ static void electra_cf_timer(struct timer_list *t) { - struct electra_cf_socket *cf = from_timer(cf, t, timer); + struct electra_cf_socket *cf = timer_container_of(cf, t, timer); int present = electra_cf_present(cf); if (present != cf->present) { diff --git a/drivers/pcmcia/omap_cf.c b/drivers/pcmcia/omap_cf.c index f0ccf479f36e..1b1dff56ec7b 100644 --- a/drivers/pcmcia/omap_cf.c +++ b/drivers/pcmcia/omap_cf.c @@ -77,7 +77,7 @@ static int omap_cf_ss_init(struct pcmcia_socket *s) /* the timer is primarily to kick this socket's pccardd */ static void omap_cf_timer(struct timer_list *t) { - struct omap_cf_socket *cf = from_timer(cf, t, timer); + struct omap_cf_socket *cf = timer_container_of(cf, t, timer); unsigned present = omap_cf_present(); if (present != cf->present) { diff --git a/drivers/pcmcia/pd6729.c b/drivers/pcmcia/pd6729.c index a0a2e7f18356..6868b60fd325 100644 --- a/drivers/pcmcia/pd6729.c +++ b/drivers/pcmcia/pd6729.c @@ -236,7 +236,8 @@ static irqreturn_t pd6729_interrupt(int irq, void *dev) static void pd6729_interrupt_wrapper(struct timer_list *t) { - struct pd6729_socket *socket = from_timer(socket, t, poll_timer); + struct pd6729_socket *socket = timer_container_of(socket, t, + poll_timer); pd6729_interrupt(0, (void *)socket); mod_timer(&socket->poll_timer, jiffies + HZ); diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c index d361124db993..87aa3f667117 100644 --- a/drivers/pcmcia/soc_common.c +++ b/drivers/pcmcia/soc_common.c @@ -460,7 +460,7 @@ static void soc_common_check_status(struct soc_pcmcia_socket *skt) /* Let's poll for events in addition to IRQs since IRQ only is unreliable... */ static void soc_common_pcmcia_poll_event(struct timer_list *t) { - struct soc_pcmcia_socket *skt = from_timer(skt, t, poll_timer); + struct soc_pcmcia_socket *skt = timer_container_of(skt, t, poll_timer); debug(skt, 4, "polling for events\n"); mod_timer(&skt->poll_timer, jiffies + SOC_PCMCIA_POLL_PERIOD); diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c index 020ea86c24ec..923ed23570a0 100644 --- a/drivers/pcmcia/yenta_socket.c +++ b/drivers/pcmcia/yenta_socket.c @@ -539,7 +539,8 @@ static irqreturn_t yenta_interrupt(int irq, void *dev_id) static void yenta_interrupt_wrapper(struct timer_list *t) { - struct yenta_socket *socket = from_timer(socket, t, poll_timer); + struct yenta_socket *socket = timer_container_of(socket, t, + poll_timer); yenta_interrupt(0, (void *)socket); socket->poll_timer.expires = jiffies + HZ; diff --git a/drivers/platform/loongarch/loongson-laptop.c b/drivers/platform/loongarch/loongson-laptop.c index 99203584949d..61b18ac206c9 100644 --- a/drivers/platform/loongarch/loongson-laptop.c +++ b/drivers/platform/loongarch/loongson-laptop.c @@ -56,8 +56,7 @@ static struct input_dev *generic_inputdev; static acpi_handle hotkey_handle; static struct key_entry hotkey_keycode_map[GENERIC_HOTKEY_MAP_MAX]; -int loongson_laptop_turn_on_backlight(void); -int loongson_laptop_turn_off_backlight(void); +static bool bl_powered; static int loongson_laptop_backlight_update(struct backlight_device *bd); /* 2. ACPI Helpers and device model */ @@ -354,16 +353,42 @@ static int ec_backlight_level(u8 level) return level; } +static int ec_backlight_set_power(bool state) +{ + int status; + union acpi_object arg0 = { ACPI_TYPE_INTEGER }; + struct acpi_object_list args = { 1, &arg0 }; + + arg0.integer.value = state; + status = acpi_evaluate_object(NULL, "\\BLSW", &args, NULL); + if (ACPI_FAILURE(status)) { + pr_info("Loongson lvds error: 0x%x\n", status); + return -EIO; + } + + return 0; +} + static int loongson_laptop_backlight_update(struct backlight_device *bd) { - int lvl = ec_backlight_level(bd->props.brightness); + bool target_powered = !backlight_is_blank(bd); + int ret = 0, lvl = ec_backlight_level(bd->props.brightness); if (lvl < 0) return -EIO; + if (ec_set_brightness(lvl)) return -EIO; - return 0; + if (target_powered != bl_powered) { + ret = ec_backlight_set_power(target_powered); + if (ret < 0) + return ret; + + bl_powered = target_powered; + } + + return ret; } static int loongson_laptop_get_brightness(struct backlight_device *bd) @@ -384,7 +409,7 @@ static const struct backlight_ops backlight_laptop_ops = { static int laptop_backlight_register(void) { - int status = 0; + int status = 0, ret; struct backlight_properties props; memset(&props, 0, sizeof(props)); @@ -392,44 +417,20 @@ static int laptop_backlight_register(void) if (!acpi_evalf(hotkey_handle, &status, "ECLL", "d")) return -EIO; - props.brightness = 1; + ret = ec_backlight_set_power(true); + if (ret) + return ret; + + bl_powered = true; + props.max_brightness = status; + props.brightness = ec_get_brightness(); + props.power = BACKLIGHT_POWER_ON; props.type = BACKLIGHT_PLATFORM; backlight_device_register("loongson_laptop", NULL, NULL, &backlight_laptop_ops, &props); - return 0; -} - -int loongson_laptop_turn_on_backlight(void) -{ - int status; - union acpi_object arg0 = { ACPI_TYPE_INTEGER }; - struct acpi_object_list args = { 1, &arg0 }; - - arg0.integer.value = 1; - status = acpi_evaluate_object(NULL, "\\BLSW", &args, NULL); - if (ACPI_FAILURE(status)) { - pr_info("Loongson lvds error: 0x%x\n", status); - return -ENODEV; - } - - return 0; -} - -int loongson_laptop_turn_off_backlight(void) -{ - int status; - union acpi_object arg0 = { ACPI_TYPE_INTEGER }; - struct acpi_object_list args = { 1, &arg0 }; - - arg0.integer.value = 0; - status = acpi_evaluate_object(NULL, "\\BLSW", &args, NULL); - if (ACPI_FAILURE(status)) { - pr_info("Loongson lvds error: 0x%x\n", status); - return -ENODEV; - } return 0; } @@ -611,11 +612,17 @@ static int __init generic_acpi_laptop_init(void) static void __exit generic_acpi_laptop_exit(void) { + int i; + if (generic_inputdev) { - if (input_device_registered) - input_unregister_device(generic_inputdev); - else + if (!input_device_registered) { input_free_device(generic_inputdev); + } else { + input_unregister_device(generic_inputdev); + + for (i = 0; i < ARRAY_SIZE(generic_sub_drivers); i++) + generic_subdriver_exit(&generic_sub_drivers[i]); + } } } diff --git a/drivers/platform/x86/intel_ips.c b/drivers/platform/x86/intel_ips.c index 9506f28fb7d8..b1b2d9caba7b 100644 --- a/drivers/platform/x86/intel_ips.c +++ b/drivers/platform/x86/intel_ips.c @@ -934,7 +934,7 @@ static u32 calc_avg_power(struct ips_driver *ips, u32 *array) static void monitor_timeout(struct timer_list *t) { - struct ips_driver *ips = from_timer(ips, t, timer); + struct ips_driver *ips = timer_container_of(ips, t, timer); wake_up_process(ips->monitor); } diff --git a/drivers/pps/clients/pps-gpio.c b/drivers/pps/clients/pps-gpio.c index 374ceefd6f2a..47d9891de368 100644 --- a/drivers/pps/clients/pps-gpio.c +++ b/drivers/pps/clients/pps-gpio.c @@ -98,7 +98,7 @@ static void pps_gpio_echo_timer_callback(struct timer_list *t) { const struct pps_gpio_device_data *info; - info = from_timer(info, t, echo_timer); + info = timer_container_of(info, t, echo_timer); gpiod_set_value(info->echo_pin, 0); } diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c index ce804438c32d..1e7f72e57557 100644 --- a/drivers/ptp/ptp_ocp.c +++ b/drivers/ptp/ptp_ocp.c @@ -1526,7 +1526,7 @@ ptp_ocp_utc_distribute(struct ptp_ocp *bp, u32 val) static void ptp_ocp_watchdog(struct timer_list *t) { - struct ptp_ocp *bp = from_timer(bp, t, watchdog); + struct ptp_ocp *bp = timer_container_of(bp, t, watchdog); unsigned long flags; u32 status, utc_offset; diff --git a/drivers/pwm/pwm-axi-pwmgen.c b/drivers/pwm/pwm-axi-pwmgen.c index 4337c8f5acf0..60dcd3542373 100644 --- a/drivers/pwm/pwm-axi-pwmgen.c +++ b/drivers/pwm/pwm-axi-pwmgen.c @@ -257,7 +257,7 @@ static int axi_pwmgen_probe(struct platform_device *pdev) struct regmap *regmap; struct pwm_chip *chip; struct axi_pwmgen_ddata *ddata; - struct clk *clk; + struct clk *axi_clk, *clk; void __iomem *io_base; int ret; @@ -280,9 +280,26 @@ static int axi_pwmgen_probe(struct platform_device *pdev) ddata = pwmchip_get_drvdata(chip); ddata->regmap = regmap; - clk = devm_clk_get_enabled(dev, NULL); + /* + * Using NULL here instead of "axi" for backwards compatibility. There + * are some dtbs that don't give clock-names and have the "ext" clock + * as the one and only clock (due to mistake in the original bindings). + */ + axi_clk = devm_clk_get_enabled(dev, NULL); + if (IS_ERR(axi_clk)) + return dev_err_probe(dev, PTR_ERR(axi_clk), "failed to get axi clock\n"); + + clk = devm_clk_get_optional_enabled(dev, "ext"); if (IS_ERR(clk)) - return dev_err_probe(dev, PTR_ERR(clk), "failed to get clock\n"); + return dev_err_probe(dev, PTR_ERR(clk), "failed to get ext clock\n"); + + /* + * If there is no "ext" clock, it means the HDL was compiled with + * ASYNC_CLK_EN=0. In this case, the AXI clock is also used for the + * PWM output clock. + */ + if (!clk) + clk = axi_clk; ret = devm_clk_rate_exclusive_get(dev, clk); if (ret) diff --git a/drivers/regulator/max14577-regulator.c b/drivers/regulator/max14577-regulator.c index 5e7171b9065a..41fd15adfd1f 100644 --- a/drivers/regulator/max14577-regulator.c +++ b/drivers/regulator/max14577-regulator.c @@ -40,11 +40,14 @@ static int max14577_reg_get_current_limit(struct regulator_dev *rdev) struct max14577 *max14577 = rdev_get_drvdata(rdev); const struct maxim_charger_current *limits = &maxim_charger_currents[max14577->dev_type]; + int ret; if (rdev_get_id(rdev) != MAX14577_CHARGER) return -EINVAL; - max14577_read_reg(rmap, MAX14577_CHG_REG_CHG_CTRL4, ®_data); + ret = max14577_read_reg(rmap, MAX14577_CHG_REG_CHG_CTRL4, ®_data); + if (ret < 0) + return ret; if ((reg_data & CHGCTRL4_MBCICHWRCL_MASK) == 0) return limits->min; diff --git a/drivers/rtc/dev.c b/drivers/rtc/dev.c index 0eeae5bcc3aa..baf1a8ca8b2b 100644 --- a/drivers/rtc/dev.c +++ b/drivers/rtc/dev.c @@ -72,7 +72,7 @@ static void rtc_uie_task(struct work_struct *work) static void rtc_uie_timer(struct timer_list *t) { - struct rtc_device *rtc = from_timer(rtc, t, uie_timer); + struct rtc_device *rtc = timer_container_of(rtc, t, uie_timer); unsigned long flags; spin_lock_irqsave(&rtc->irq_lock, flags); diff --git a/drivers/rtc/rtc-test.c b/drivers/rtc/rtc-test.c index a9f5b9466fb5..94f995febe5b 100644 --- a/drivers/rtc/rtc-test.c +++ b/drivers/rtc/rtc-test.c @@ -107,7 +107,7 @@ static const struct rtc_class_ops test_rtc_ops = { static void test_rtc_alarm_handler(struct timer_list *t) { - struct rtc_test_data *rtd = from_timer(rtd, t, alarm); + struct rtc_test_data *rtd = timer_container_of(rtd, t, alarm); rtc_update_irq(rtd->rtc, 1, RTC_AF | RTC_IRQF); } diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index cf36d3bafeca..b16efecfde4b 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -1493,7 +1493,7 @@ static void dasd_device_timeout(struct timer_list *t) unsigned long flags; struct dasd_device *device; - device = from_timer(device, t, timer); + device = timer_container_of(device, t, timer); spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); /* re-activate request queue */ dasd_device_remove_stop_bits(device, DASD_STOPPED_PENDING); @@ -2677,7 +2677,7 @@ static void dasd_block_timeout(struct timer_list *t) unsigned long flags; struct dasd_block *block; - block = from_timer(block, t, timer); + block = timer_container_of(block, t, timer); spin_lock_irqsave(get_ccwdev_lock(block->base->cdev), flags); /* re-activate request queue */ dasd_device_remove_stop_bits(block->base, DASD_STOPPED_PENDING); diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c index 6a61c0a595d9..56e43d43c713 100644 --- a/drivers/s390/char/con3215.c +++ b/drivers/s390/char/con3215.c @@ -284,7 +284,7 @@ static void raw3215_start_io(struct raw3215_info *raw) */ static void raw3215_timeout(struct timer_list *t) { - struct raw3215_info *raw = from_timer(raw, t, timer); + struct raw3215_info *raw = timer_container_of(raw, t, timer); unsigned long flags; spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); diff --git a/drivers/s390/char/con3270.c b/drivers/s390/char/con3270.c index 8402a0042c0d..b78b86e8f281 100644 --- a/drivers/s390/char/con3270.c +++ b/drivers/s390/char/con3270.c @@ -525,7 +525,7 @@ static void tty3270_update_lines_all(struct tty3270 *tp, struct raw3270_request */ static void tty3270_update(struct timer_list *t) { - struct tty3270 *tp = from_timer(tp, t, timer); + struct tty3270 *tp = timer_container_of(tp, t, timer); struct raw3270_request *wrq; u8 cmd = TC_WRITE; int rc, len; diff --git a/drivers/s390/char/tape_core.c b/drivers/s390/char/tape_core.c index 48e8417a5cff..fa063e84eafc 100644 --- a/drivers/s390/char/tape_core.c +++ b/drivers/s390/char/tape_core.c @@ -821,7 +821,7 @@ tape_delayed_next_request(struct work_struct *work) static void tape_long_busy_timeout(struct timer_list *t) { - struct tape_device *device = from_timer(device, t, lb_timeout); + struct tape_device *device = timer_container_of(device, t, lb_timeout); struct tape_request *request; spin_lock_irq(get_ccwdev_lock(device->cdev)); diff --git a/drivers/s390/char/tape_std.c b/drivers/s390/char/tape_std.c index b76038632883..7ff177406bc3 100644 --- a/drivers/s390/char/tape_std.c +++ b/drivers/s390/char/tape_std.c @@ -35,7 +35,8 @@ static void tape_std_assign_timeout(struct timer_list *t) { - struct tape_request * request = from_timer(request, t, timer); + struct tape_request * request = timer_container_of(request, t, + timer); struct tape_device * device = request->device; int rc; diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index e1b1fbdabb1b..e849d3271b0e 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c @@ -98,7 +98,7 @@ static void ccw_timeout_log(struct ccw_device *cdev) void ccw_device_timeout(struct timer_list *t) { - struct ccw_device_private *priv = from_timer(priv, t, timer); + struct ccw_device_private *priv = timer_container_of(priv, t, timer); struct ccw_device *cdev = priv->cdev; spin_lock_irq(cdev->ccwlock); diff --git a/drivers/s390/cio/eadm_sch.c b/drivers/s390/cio/eadm_sch.c index ac382355dc04..37ea30be710c 100644 --- a/drivers/s390/cio/eadm_sch.c +++ b/drivers/s390/cio/eadm_sch.c @@ -98,7 +98,7 @@ static int eadm_subchannel_clear(struct subchannel *sch) static void eadm_subchannel_timeout(struct timer_list *t) { - struct eadm_private *private = from_timer(private, t, timer); + struct eadm_private *private = timer_container_of(private, t, timer); struct subchannel *sch = private->sch; spin_lock_irq(&sch->lock); diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index 288734cd8f4b..bd95bd390b5c 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -428,7 +428,7 @@ void ap_wait(enum ap_sm_wait wait) */ void ap_request_timeout(struct timer_list *t) { - struct ap_queue *aq = from_timer(aq, t, timeout); + struct ap_queue *aq = timer_container_of(aq, t, timeout); spin_lock_bh(&aq->lock); ap_wait(ap_sm_event(aq, AP_SM_EVENT_TIMEOUT)); diff --git a/drivers/s390/net/fsm.c b/drivers/s390/net/fsm.c index 5fcdce116862..6a12d2422540 100644 --- a/drivers/s390/net/fsm.c +++ b/drivers/s390/net/fsm.c @@ -132,7 +132,7 @@ fsm_getstate_str(fsm_instance *fi) static void fsm_expire_timer(struct timer_list *t) { - fsm_timer *this = from_timer(this, t, tl); + fsm_timer *this = timer_container_of(this, t, tl); #if FSM_TIMER_DEBUG printk(KERN_DEBUG "fsm(%s): Timer %p expired\n", this->fi->name, this); diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index f5cfaebfb7c9..fe9f48c315d9 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -2619,7 +2619,8 @@ err_qdio_bufs: static void qeth_tx_completion_timer(struct timer_list *timer) { - struct qeth_qdio_out_q *queue = from_timer(queue, timer, timer); + struct qeth_qdio_out_q *queue = timer_container_of(queue, timer, + timer); napi_schedule(&queue->napi); QETH_TXQ_STAT_INC(queue, completion_timer); diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index 78d52a4c55f5..ffd994416995 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -615,7 +615,7 @@ void zfcp_erp_notify(struct zfcp_erp_action *erp_action, unsigned long set_mask) */ void zfcp_erp_timeout_handler(struct timer_list *t) { - struct zfcp_fsf_req *fsf_req = from_timer(fsf_req, t, timer); + struct zfcp_fsf_req *fsf_req = timer_container_of(fsf_req, t, timer); struct zfcp_erp_action *act; if (fsf_req->status & ZFCP_STATUS_FSFREQ_DISMISSED) @@ -629,7 +629,7 @@ void zfcp_erp_timeout_handler(struct timer_list *t) static void zfcp_erp_memwait_handler(struct timer_list *t) { - struct zfcp_erp_action *act = from_timer(act, t, timer); + struct zfcp_erp_action *act = timer_container_of(act, t, timer); zfcp_erp_notify(act, 0); } diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index d5f5f563881e..c5bba1be88f4 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -36,7 +36,7 @@ MODULE_PARM_DESC(ber_stop, static void zfcp_fsf_request_timeout_handler(struct timer_list *t) { - struct zfcp_fsf_req *fsf_req = from_timer(fsf_req, t, timer); + struct zfcp_fsf_req *fsf_req = timer_container_of(fsf_req, t, timer); struct zfcp_adapter *adapter = fsf_req->adapter; zfcp_qdio_siosl(adapter); diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c index 0957e3f8b46e..f2410bc44ad3 100644 --- a/drivers/s390/scsi/zfcp_qdio.c +++ b/drivers/s390/scsi/zfcp_qdio.c @@ -102,7 +102,8 @@ static void zfcp_qdio_request_tasklet(struct tasklet_struct *tasklet) static void zfcp_qdio_request_timer(struct timer_list *timer) { - struct zfcp_qdio *qdio = from_timer(qdio, timer, request_timer); + struct zfcp_qdio *qdio = timer_container_of(qdio, timer, + request_timer); tasklet_schedule(&qdio->request_tasklet); } diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h index 8c384c25dca1..0a5888b53d6d 100644 --- a/drivers/scsi/aacraid/aacraid.h +++ b/drivers/scsi/aacraid/aacraid.h @@ -93,7 +93,6 @@ enum { #define AAC_NUM_MGT_FIB 8 #define AAC_NUM_IO_FIB (1024 - AAC_NUM_MGT_FIB) -#define AAC_NUM_FIB (AAC_NUM_IO_FIB + AAC_NUM_MGT_FIB) #define AAC_MAX_LUN 256 diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c index ffef61c4aa01..7d9a4dce236b 100644 --- a/drivers/scsi/aacraid/commsup.c +++ b/drivers/scsi/aacraid/commsup.c @@ -48,15 +48,7 @@ static int fib_map_alloc(struct aac_dev *dev) { - if (dev->max_fib_size > AAC_MAX_NATIVE_SIZE) - dev->max_cmd_size = AAC_MAX_NATIVE_SIZE; - else - dev->max_cmd_size = dev->max_fib_size; - if (dev->max_fib_size < AAC_MAX_NATIVE_SIZE) { - dev->max_cmd_size = AAC_MAX_NATIVE_SIZE; - } else { - dev->max_cmd_size = dev->max_fib_size; - } + dev->max_cmd_size = AAC_MAX_NATIVE_SIZE; dprintk((KERN_INFO "allocate hardware fibs dma_alloc_coherent(%p, %d * (%d + %d), %p)\n", diff --git a/drivers/scsi/aic7xxx/aic79xx_core.c b/drivers/scsi/aic7xxx/aic79xx_core.c index f9372a81cd4e..6b87ea004e53 100644 --- a/drivers/scsi/aic7xxx/aic79xx_core.c +++ b/drivers/scsi/aic7xxx/aic79xx_core.c @@ -8784,7 +8784,7 @@ ahd_reset_channel(struct ahd_softc *ahd, char channel, int initiate_reset) static void ahd_stat_timer(struct timer_list *t) { - struct ahd_softc *ahd = from_timer(ahd, t, stat_timer); + struct ahd_softc *ahd = timer_container_of(ahd, t, stat_timer); u_long s; int enint_coal; diff --git a/drivers/scsi/aic94xx/aic94xx_scb.c b/drivers/scsi/aic94xx/aic94xx_scb.c index 68214a58b160..08c8dad9ad62 100644 --- a/drivers/scsi/aic94xx/aic94xx_scb.c +++ b/drivers/scsi/aic94xx/aic94xx_scb.c @@ -862,7 +862,7 @@ void asd_build_initiate_link_adm_task(struct asd_ascb *ascb, int phy_id, */ void asd_ascb_timedout(struct timer_list *t) { - struct asd_ascb *ascb = from_timer(ascb, t, timer); + struct asd_ascb *ascb = timer_container_of(ascb, t, timer); struct asd_seq_data *seq = &ascb->ha->seq; unsigned long flags; diff --git a/drivers/scsi/aic94xx/aic94xx_tmf.c b/drivers/scsi/aic94xx/aic94xx_tmf.c index d45dbf98f25e..28ac92b041fe 100644 --- a/drivers/scsi/aic94xx/aic94xx_tmf.c +++ b/drivers/scsi/aic94xx/aic94xx_tmf.c @@ -70,7 +70,7 @@ static void asd_clear_nexus_tasklet_complete(struct asd_ascb *ascb, static void asd_clear_nexus_timedout(struct timer_list *t) { - struct asd_ascb *ascb = from_timer(ascb, t, timer); + struct asd_ascb *ascb = timer_container_of(ascb, t, timer); struct tasklet_completion_status *tcs = ascb->uldd_task; ASD_DPRINTK("%s: here\n", __func__); @@ -244,7 +244,7 @@ static int asd_clear_nexus_index(struct sas_task *task) static void asd_tmf_timedout(struct timer_list *t) { - struct asd_ascb *ascb = from_timer(ascb, t, timer); + struct asd_ascb *ascb = timer_container_of(ascb, t, timer); struct tasklet_completion_status *tcs = ascb->uldd_task; ASD_DPRINTK("tmf timed out\n"); diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c index b450b1fc6bbb..fb57343a97bd 100644 --- a/drivers/scsi/arcmsr/arcmsr_hba.c +++ b/drivers/scsi/arcmsr/arcmsr_hba.c @@ -3935,7 +3935,8 @@ static int arcmsr_polling_ccbdone(struct AdapterControlBlock *acb, static void arcmsr_set_iop_datetime(struct timer_list *t) { - struct AdapterControlBlock *pacb = from_timer(pacb, t, refresh_timer); + struct AdapterControlBlock *pacb = timer_container_of(pacb, t, + refresh_timer); unsigned int next_time; struct tm tm; @@ -4263,7 +4264,8 @@ static void arcmsr_wait_firmware_ready(struct AdapterControlBlock *acb) static void arcmsr_request_device_map(struct timer_list *t) { - struct AdapterControlBlock *acb = from_timer(acb, t, eternal_timer); + struct AdapterControlBlock *acb = timer_container_of(acb, t, + eternal_timer); if (acb->acb_flags & (ACB_F_MSG_GET_CONFIG | ACB_F_BUS_RESET | ACB_F_ABORT)) { mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ)); } else { diff --git a/drivers/scsi/arm/fas216.c b/drivers/scsi/arm/fas216.c index e0b55d869a35..b1a749ab18f8 100644 --- a/drivers/scsi/arm/fas216.c +++ b/drivers/scsi/arm/fas216.c @@ -2327,7 +2327,7 @@ DEF_SCSI_QCMD(fas216_noqueue_command) */ static void fas216_eh_timer(struct timer_list *t) { - FAS216_Info *info = from_timer(info, t, eh_timer); + FAS216_Info *info = timer_container_of(info, t, eh_timer); fas216_log(info, LOG_ERROR, "error handling timed out\n"); diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index 7d1b767d87fb..dc88bc46dcc0 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -5240,7 +5240,7 @@ static void beiscsi_eqd_update_work(struct work_struct *work) static void beiscsi_hw_tpe_check(struct timer_list *t) { - struct beiscsi_hba *phba = from_timer(phba, t, hw_check); + struct beiscsi_hba *phba = timer_container_of(phba, t, hw_check); u32 wait; /* if not TPE, do nothing */ @@ -5257,7 +5257,7 @@ static void beiscsi_hw_tpe_check(struct timer_list *t) static void beiscsi_hw_health_check(struct timer_list *t) { - struct beiscsi_hba *phba = from_timer(phba, t, hw_check); + struct beiscsi_hba *phba = timer_container_of(phba, t, hw_check); beiscsi_detect_ue(phba); if (beiscsi_detect_ue(phba)) { diff --git a/drivers/scsi/bfa/bfad.c b/drivers/scsi/bfa/bfad.c index 598f2fc93ef2..ff9adfc0b332 100644 --- a/drivers/scsi/bfa/bfad.c +++ b/drivers/scsi/bfa/bfad.c @@ -685,7 +685,8 @@ ext: void bfad_bfa_tmo(struct timer_list *t) { - struct bfad_s *bfad = from_timer(bfad, t, hal_tmo); + struct bfad_s *bfad = timer_container_of(bfad, t, + hal_tmo); unsigned long flags; struct list_head doneq; diff --git a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c index de6574cccf58..58da993251e9 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c +++ b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c @@ -837,7 +837,7 @@ static int bnx2fc_net_config(struct fc_lport *lport, struct net_device *netdev) static void bnx2fc_destroy_timer(struct timer_list *t) { - struct bnx2fc_hba *hba = from_timer(hba, t, destroy_timer); + struct bnx2fc_hba *hba = timer_container_of(hba, t, destroy_timer); printk(KERN_ERR PFX "ERROR:bnx2fc_destroy_timer - " "Destroy compl not received!!\n"); diff --git a/drivers/scsi/bnx2fc/bnx2fc_tgt.c b/drivers/scsi/bnx2fc/bnx2fc_tgt.c index b8227cfef64f..77dcdfc412b1 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_tgt.c +++ b/drivers/scsi/bnx2fc/bnx2fc_tgt.c @@ -30,7 +30,7 @@ static void bnx2fc_free_conn_id(struct bnx2fc_hba *hba, u32 conn_id); static void bnx2fc_upld_timer(struct timer_list *t) { - struct bnx2fc_rport *tgt = from_timer(tgt, t, upld_timer); + struct bnx2fc_rport *tgt = timer_container_of(tgt, t, upld_timer); BNX2FC_TGT_DBG(tgt, "upld_timer - Upload compl not received!!\n"); /* fake upload completion */ @@ -43,7 +43,7 @@ static void bnx2fc_upld_timer(struct timer_list *t) static void bnx2fc_ofld_timer(struct timer_list *t) { - struct bnx2fc_rport *tgt = from_timer(tgt, t, ofld_timer); + struct bnx2fc_rport *tgt = timer_container_of(tgt, t, ofld_timer); BNX2FC_TGT_DBG(tgt, "entered bnx2fc_ofld_timer\n"); /* NOTE: This function should never be called, as diff --git a/drivers/scsi/bnx2i/bnx2i_hwi.c b/drivers/scsi/bnx2i/bnx2i_hwi.c index 6c864b093ac9..40db5190a222 100644 --- a/drivers/scsi/bnx2i/bnx2i_hwi.c +++ b/drivers/scsi/bnx2i/bnx2i_hwi.c @@ -685,7 +685,7 @@ void bnx2i_update_iscsi_conn(struct iscsi_conn *conn) */ void bnx2i_ep_ofld_timer(struct timer_list *t) { - struct bnx2i_endpoint *ep = from_timer(ep, t, ofld_timer); + struct bnx2i_endpoint *ep = timer_container_of(ep, t, ofld_timer); if (ep->state == EP_STATE_OFLD_START) { printk(KERN_ALERT "ofld_timer: CONN_OFLD timeout\n"); diff --git a/drivers/scsi/csiostor/csio_hw.c b/drivers/scsi/csiostor/csio_hw.c index beded091dff1..7aa418ebfe01 100644 --- a/drivers/scsi/csiostor/csio_hw.c +++ b/drivers/scsi/csiostor/csio_hw.c @@ -3738,7 +3738,7 @@ csio_mberr_worker(void *data) static void csio_hw_mb_timer(struct timer_list *t) { - struct csio_mbm *mbm = from_timer(mbm, t, timer); + struct csio_mbm *mbm = timer_container_of(mbm, t, timer); struct csio_hw *hw = mbm->hw; struct csio_mb *mbp = NULL; @@ -4107,7 +4107,7 @@ csio_mgmt_req_lookup(struct csio_mgmtm *mgmtm, struct csio_ioreq *io_req) static void csio_mgmt_tmo_handler(struct timer_list *t) { - struct csio_mgmtm *mgmtm = from_timer(mgmtm, t, mgmt_timer); + struct csio_mgmtm *mgmtm = timer_container_of(mgmtm, t, mgmt_timer); struct list_head *tmp; struct csio_ioreq *io_req; diff --git a/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c b/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c index 461d38e2fb19..69de9657f7cb 100644 --- a/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c +++ b/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c @@ -547,7 +547,7 @@ static int act_open_rpl_status_to_errno(int status) static void act_open_retry_timer(struct timer_list *t) { - struct cxgbi_sock *csk = from_timer(csk, t, retry_timer); + struct cxgbi_sock *csk = timer_container_of(csk, t, retry_timer); struct sk_buff *skb; log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, diff --git a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c index aaba294ecb58..42676627c3af 100644 --- a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c +++ b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c @@ -988,7 +988,7 @@ static int act_open_rpl_status_to_errno(int status) static void csk_act_open_retry_timer(struct timer_list *t) { struct sk_buff *skb = NULL; - struct cxgbi_sock *csk = from_timer(csk, t, retry_timer); + struct cxgbi_sock *csk = timer_container_of(csk, t, retry_timer); struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(csk->cdev); void (*send_act_open_func)(struct cxgbi_sock *, struct sk_buff *, struct l2t_entry *); diff --git a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c index 96b335c92603..386c8359e1cc 100644 --- a/drivers/scsi/dc395x.c +++ b/drivers/scsi/dc395x.c @@ -751,7 +751,7 @@ static void waiting_process_next(struct AdapterCtlBlk *acb) static void waiting_timeout(struct timer_list *t) { unsigned long flags; - struct AdapterCtlBlk *acb = from_timer(acb, t, waiting_timer); + struct AdapterCtlBlk *acb = timer_container_of(acb, t, waiting_timer); DC395x_LOCK_IO(acb->scsi_host, flags); waiting_process_next(acb); DC395x_UNLOCK_IO(acb->scsi_host, flags); diff --git a/drivers/scsi/elx/efct/efct_xport.c b/drivers/scsi/elx/efct/efct_xport.c index 2aca60f6428e..dfe05fab7b42 100644 --- a/drivers/scsi/elx/efct/efct_xport.c +++ b/drivers/scsi/elx/efct/efct_xport.c @@ -180,7 +180,7 @@ efct_xport_config_stats_timer(struct efct *efct); static void efct_xport_stats_timer_cb(struct timer_list *t) { - struct efct_xport *xport = from_timer(xport, t, stats_timer); + struct efct_xport *xport = timer_container_of(xport, t, stats_timer); struct efct *efct = xport->efct; efct_xport_config_stats_timer(efct); diff --git a/drivers/scsi/elx/libefc/efc_els.c b/drivers/scsi/elx/libefc/efc_els.c index 84bc81d7ce76..1786cee08729 100644 --- a/drivers/scsi/elx/libefc/efc_els.c +++ b/drivers/scsi/elx/libefc/efc_els.c @@ -147,7 +147,7 @@ efc_els_retry(struct efc_els_io_req *els); static void efc_els_delay_timer_cb(struct timer_list *t) { - struct efc_els_io_req *els = from_timer(els, t, delay_timer); + struct efc_els_io_req *els = timer_container_of(els, t, delay_timer); /* Retry delay timer expired, retry the ELS request */ efc_els_retry(els); diff --git a/drivers/scsi/elx/libefc/efc_fabric.c b/drivers/scsi/elx/libefc/efc_fabric.c index cf7e738c4edc..4ed9f46ded65 100644 --- a/drivers/scsi/elx/libefc/efc_fabric.c +++ b/drivers/scsi/elx/libefc/efc_fabric.c @@ -886,7 +886,7 @@ __efc_ns_idle(struct efc_sm_ctx *ctx, enum efc_sm_event evt, void *arg) static void gidpt_delay_timer_cb(struct timer_list *t) { - struct efc_node *node = from_timer(node, t, gidpt_delay_timer); + struct efc_node *node = timer_container_of(node, t, gidpt_delay_timer); timer_delete(&node->gidpt_delay_timer); diff --git a/drivers/scsi/esas2r/esas2r_main.c b/drivers/scsi/esas2r/esas2r_main.c index 44871746944a..3f31875ff46e 100644 --- a/drivers/scsi/esas2r/esas2r_main.c +++ b/drivers/scsi/esas2r/esas2r_main.c @@ -1585,7 +1585,7 @@ void esas2r_kickoff_timer(struct esas2r_adapter *a) static void esas2r_timer_callback(struct timer_list *t) { - struct esas2r_adapter *a = from_timer(a, t, timer); + struct esas2r_adapter *a = timer_container_of(a, t, timer); set_bit(AF2_TIMER_TICK, &a->flags2); diff --git a/drivers/scsi/fcoe/fcoe_ctlr.c b/drivers/scsi/fcoe/fcoe_ctlr.c index 56d270526c9c..8e4241c295e3 100644 --- a/drivers/scsi/fcoe/fcoe_ctlr.c +++ b/drivers/scsi/fcoe/fcoe_ctlr.c @@ -1773,7 +1773,7 @@ unlock: */ static void fcoe_ctlr_timeout(struct timer_list *t) { - struct fcoe_ctlr *fip = from_timer(fip, t, timer); + struct fcoe_ctlr *fip = timer_container_of(fip, t, timer); schedule_work(&fip->timer_work); } diff --git a/drivers/scsi/fcoe/fcoe_transport.c b/drivers/scsi/fcoe/fcoe_transport.c index a48d24af9ac3..2f478426f16e 100644 --- a/drivers/scsi/fcoe/fcoe_transport.c +++ b/drivers/scsi/fcoe/fcoe_transport.c @@ -447,7 +447,7 @@ EXPORT_SYMBOL_GPL(fcoe_check_wait_queue); */ void fcoe_queue_timer(struct timer_list *t) { - struct fcoe_port *port = from_timer(port, t, timer); + struct fcoe_port *port = timer_container_of(port, t, timer); fcoe_check_wait_queue(port->lport, NULL); } diff --git a/drivers/scsi/fnic/fdls_disc.c b/drivers/scsi/fnic/fdls_disc.c index c2b6f4eb338e..f8ab69c51dab 100644 --- a/drivers/scsi/fnic/fdls_disc.c +++ b/drivers/scsi/fnic/fdls_disc.c @@ -2074,7 +2074,8 @@ static void fdls_fdmi_register_pa(struct fnic_iport_s *iport) void fdls_fabric_timer_callback(struct timer_list *t) { - struct fnic_fdls_fabric_s *fabric = from_timer(fabric, t, retry_timer); + struct fnic_fdls_fabric_s *fabric = timer_container_of(fabric, t, + retry_timer); struct fnic_iport_s *iport = container_of(fabric, struct fnic_iport_s, fabric); struct fnic *fnic = iport->fnic; @@ -2246,7 +2247,8 @@ void fdls_fabric_timer_callback(struct timer_list *t) void fdls_fdmi_timer_callback(struct timer_list *t) { - struct fnic_fdls_fabric_s *fabric = from_timer(fabric, t, fdmi_timer); + struct fnic_fdls_fabric_s *fabric = timer_container_of(fabric, t, + fdmi_timer); struct fnic_iport_s *iport = container_of(fabric, struct fnic_iport_s, fabric); struct fnic *fnic = iport->fnic; @@ -2323,7 +2325,7 @@ static void fdls_send_delete_tport_msg(struct fnic_tport_s *tport) static void fdls_tport_timer_callback(struct timer_list *t) { - struct fnic_tport_s *tport = from_timer(tport, t, retry_timer); + struct fnic_tport_s *tport = timer_container_of(tport, t, retry_timer); struct fnic_iport_s *iport = (struct fnic_iport_s *) tport->iport; struct fnic *fnic = iport->fnic; uint16_t oxid; diff --git a/drivers/scsi/fnic/fip.c b/drivers/scsi/fnic/fip.c index 19395e2aee44..ce62ab1180bd 100644 --- a/drivers/scsi/fnic/fip.c +++ b/drivers/scsi/fnic/fip.c @@ -777,7 +777,7 @@ void fnic_work_on_fip_timer(struct work_struct *work) */ void fnic_handle_fip_timer(struct timer_list *t) { - struct fnic *fnic = from_timer(fnic, t, retry_fip_timer); + struct fnic *fnic = timer_container_of(fnic, t, retry_fip_timer); INIT_WORK(&fnic->fip_timer_work, fnic_work_on_fip_timer); queue_work(fnic_fip_queue, &fnic->fip_timer_work); @@ -790,7 +790,7 @@ void fnic_handle_fip_timer(struct timer_list *t) void fnic_handle_enode_ka_timer(struct timer_list *t) { uint8_t *frame; - struct fnic *fnic = from_timer(fnic, t, enode_ka_timer); + struct fnic *fnic = timer_container_of(fnic, t, enode_ka_timer); struct fnic_iport_s *iport = &fnic->iport; struct fip_enode_ka *penode_ka; @@ -843,7 +843,7 @@ void fnic_handle_enode_ka_timer(struct timer_list *t) void fnic_handle_vn_ka_timer(struct timer_list *t) { uint8_t *frame; - struct fnic *fnic = from_timer(fnic, t, vn_ka_timer); + struct fnic *fnic = timer_container_of(fnic, t, vn_ka_timer); struct fnic_iport_s *iport = &fnic->iport; struct fip_vn_port_ka *pvn_port_ka; @@ -998,7 +998,7 @@ void fnic_work_on_fcs_ka_timer(struct work_struct *work) */ void fnic_handle_fcs_ka_timer(struct timer_list *t) { - struct fnic *fnic = from_timer(fnic, t, fcs_ka_timer); + struct fnic *fnic = timer_container_of(fnic, t, fcs_ka_timer); INIT_WORK(&fnic->fip_timer_work, fnic_work_on_fcs_ka_timer); queue_work(fnic_fip_queue, &fnic->fip_timer_work); diff --git a/drivers/scsi/fnic/fnic_main.c b/drivers/scsi/fnic/fnic_main.c index 9a357ff42085..4cc4077ea53c 100644 --- a/drivers/scsi/fnic/fnic_main.c +++ b/drivers/scsi/fnic/fnic_main.c @@ -446,7 +446,7 @@ static int fnic_notify_set(struct fnic *fnic) static void fnic_notify_timer(struct timer_list *t) { - struct fnic *fnic = from_timer(fnic, t, notify_timer); + struct fnic *fnic = timer_container_of(fnic, t, notify_timer); fnic_handle_link_event(fnic); mod_timer(&fnic->notify_timer, diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 4864e957be0b..d1a4cc69d408 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -1016,7 +1016,7 @@ EXPORT_SYMBOL_GPL(hisi_sas_notify_phy_event); static void hisi_sas_wait_phyup_timedout(struct timer_list *t) { - struct hisi_sas_phy *phy = from_timer(phy, t, timer); + struct hisi_sas_phy *phy = timer_container_of(phy, t, timer); struct hisi_hba *hisi_hba = phy->hisi_hba; struct device *dev = hisi_hba->dev; int phy_no = phy->sas_phy.id; diff --git a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c index 6d97339371fb..fa94d7110714 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c @@ -795,7 +795,7 @@ static void phy_hard_reset_v1_hw(struct hisi_hba *hisi_hba, int phy_no) static void start_phys_v1_hw(struct timer_list *t) { - struct hisi_hba *hisi_hba = from_timer(hisi_hba, t, timer); + struct hisi_hba *hisi_hba = timer_container_of(hisi_hba, t, timer); int i; for (i = 0; i < hisi_hba->n_phy; i++) { diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index 2adfedb8484c..24cd172905f3 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -1328,7 +1328,7 @@ static void init_reg_v2_hw(struct hisi_hba *hisi_hba) static void link_timeout_enable_link(struct timer_list *t) { - struct hisi_hba *hisi_hba = from_timer(hisi_hba, t, timer); + struct hisi_hba *hisi_hba = timer_container_of(hisi_hba, t, timer); int i, reg_val; for (i = 0; i < hisi_hba->n_phy; i++) { @@ -1349,7 +1349,7 @@ static void link_timeout_enable_link(struct timer_list *t) static void link_timeout_disable_link(struct timer_list *t) { - struct hisi_hba *hisi_hba = from_timer(hisi_hba, t, timer); + struct hisi_hba *hisi_hba = timer_container_of(hisi_hba, t, timer); int i, reg_val; reg_val = hisi_sas_read32(hisi_hba, PHY_STATE); @@ -2581,7 +2581,8 @@ static void prep_ata_v2_hw(struct hisi_hba *hisi_hba, static void hisi_sas_internal_abort_quirk_timeout(struct timer_list *t) { - struct hisi_sas_slot *slot = from_timer(slot, t, internal_abort_timer); + struct hisi_sas_slot *slot = timer_container_of(slot, t, + internal_abort_timer); struct hisi_sas_port *port = slot->port; struct asd_sas_port *asd_sas_port; struct asd_sas_phy *sas_phy; diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c index 4c493b06062a..862ab0fbc893 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.c +++ b/drivers/scsi/ibmvscsi/ibmvfc.c @@ -1697,7 +1697,7 @@ static int ibmvfc_map_sg_data(struct scsi_cmnd *scmd, **/ static void ibmvfc_timeout(struct timer_list *t) { - struct ibmvfc_event *evt = from_timer(evt, t, timer); + struct ibmvfc_event *evt = timer_container_of(evt, t, timer); struct ibmvfc_host *vhost = evt->vhost; dev_err(vhost->dev, "Command timed out (%p). Resetting connection\n", evt); ibmvfc_reset_host(vhost); @@ -4630,7 +4630,7 @@ static void ibmvfc_tgt_adisc_cancel_done(struct ibmvfc_event *evt) **/ static void ibmvfc_adisc_timeout(struct timer_list *t) { - struct ibmvfc_target *tgt = from_timer(tgt, t, timer); + struct ibmvfc_target *tgt = timer_container_of(tgt, t, timer); struct ibmvfc_host *vhost = tgt->vhost; struct ibmvfc_event *evt; struct ibmvfc_tmf *tmf; diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c index d65a45860b33..3d65a498b701 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.c +++ b/drivers/scsi/ibmvscsi/ibmvscsi.c @@ -845,7 +845,8 @@ static void ibmvscsi_reset_host(struct ibmvscsi_host_data *hostdata) */ static void ibmvscsi_timeout(struct timer_list *t) { - struct srp_event_struct *evt_struct = from_timer(evt_struct, t, timer); + struct srp_event_struct *evt_struct = timer_container_of(evt_struct, + t, timer); struct ibmvscsi_host_data *hostdata = evt_struct->hostdata; dev_err(hostdata->dev, "Command timed out (%x). Resetting connection\n", diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index d89135fb8faa..b29bec6abd72 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -2589,7 +2589,7 @@ static void ipr_process_error(struct ipr_cmnd *ipr_cmd) **/ static void ipr_timeout(struct timer_list *t) { - struct ipr_cmnd *ipr_cmd = from_timer(ipr_cmd, t, timer); + struct ipr_cmnd *ipr_cmd = timer_container_of(ipr_cmd, t, timer); unsigned long lock_flags = 0; struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; @@ -2622,7 +2622,7 @@ static void ipr_timeout(struct timer_list *t) **/ static void ipr_oper_timeout(struct timer_list *t) { - struct ipr_cmnd *ipr_cmd = from_timer(ipr_cmd, t, timer); + struct ipr_cmnd *ipr_cmd = timer_container_of(ipr_cmd, t, timer); unsigned long lock_flags = 0; struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; @@ -5151,7 +5151,7 @@ static void ipr_bus_reset_done(struct ipr_cmnd *ipr_cmd) **/ static void ipr_abort_timeout(struct timer_list *t) { - struct ipr_cmnd *ipr_cmd = from_timer(ipr_cmd, t, timer); + struct ipr_cmnd *ipr_cmd = timer_container_of(ipr_cmd, t, timer); struct ipr_cmnd *reset_cmd; struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; struct ipr_cmd_pkt *cmd_pkt; @@ -7476,7 +7476,7 @@ static int ipr_ioafp_identify_hrrq(struct ipr_cmnd *ipr_cmd) **/ static void ipr_reset_timer_done(struct timer_list *t) { - struct ipr_cmnd *ipr_cmd = from_timer(ipr_cmd, t, timer); + struct ipr_cmnd *ipr_cmd = timer_container_of(ipr_cmd, t, timer); struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; unsigned long lock_flags = 0; diff --git a/drivers/scsi/isci/host.c b/drivers/scsi/isci/host.c index c108b5b940c3..6d2f4c831df7 100644 --- a/drivers/scsi/isci/host.c +++ b/drivers/scsi/isci/host.c @@ -958,7 +958,7 @@ static enum sci_status sci_controller_start_next_phy(struct isci_host *ihost) static void phy_startup_timeout(struct timer_list *t) { - struct sci_timer *tmr = from_timer(tmr, t, timer); + struct sci_timer *tmr = timer_container_of(tmr, t, timer); struct isci_host *ihost = container_of(tmr, typeof(*ihost), phy_timer); unsigned long flags; enum sci_status status; @@ -1592,7 +1592,7 @@ static const struct sci_base_state sci_controller_state_table[] = { static void controller_timeout(struct timer_list *t) { - struct sci_timer *tmr = from_timer(tmr, t, timer); + struct sci_timer *tmr = timer_container_of(tmr, t, timer); struct isci_host *ihost = container_of(tmr, typeof(*ihost), timer); struct sci_base_state_machine *sm = &ihost->sm; unsigned long flags; @@ -1737,7 +1737,7 @@ static u8 max_spin_up(struct isci_host *ihost) static void power_control_timeout(struct timer_list *t) { - struct sci_timer *tmr = from_timer(tmr, t, timer); + struct sci_timer *tmr = timer_container_of(tmr, t, timer); struct isci_host *ihost = container_of(tmr, typeof(*ihost), power_control.timer); struct isci_phy *iphy; unsigned long flags; diff --git a/drivers/scsi/isci/phy.c b/drivers/scsi/isci/phy.c index 743a3c64b0da..88237ec8b15f 100644 --- a/drivers/scsi/isci/phy.c +++ b/drivers/scsi/isci/phy.c @@ -317,7 +317,7 @@ sci_phy_link_layer_initialization(struct isci_phy *iphy, static void phy_sata_timeout(struct timer_list *t) { - struct sci_timer *tmr = from_timer(tmr, t, timer); + struct sci_timer *tmr = timer_container_of(tmr, t, timer); struct isci_phy *iphy = container_of(tmr, typeof(*iphy), sata_timer); struct isci_host *ihost = iphy->owning_port->owning_controller; unsigned long flags; diff --git a/drivers/scsi/isci/port.c b/drivers/scsi/isci/port.c index 1609aba1c9c1..10bd2aac2cb4 100644 --- a/drivers/scsi/isci/port.c +++ b/drivers/scsi/isci/port.c @@ -775,7 +775,7 @@ bool sci_port_link_detected(struct isci_port *iport, struct isci_phy *iphy) static void port_timeout(struct timer_list *t) { - struct sci_timer *tmr = from_timer(tmr, t, timer); + struct sci_timer *tmr = timer_container_of(tmr, t, timer); struct isci_port *iport = container_of(tmr, typeof(*iport), timer); struct isci_host *ihost = iport->owning_controller; unsigned long flags; diff --git a/drivers/scsi/isci/port_config.c b/drivers/scsi/isci/port_config.c index c382a257b51b..3b4820defe63 100644 --- a/drivers/scsi/isci/port_config.c +++ b/drivers/scsi/isci/port_config.c @@ -321,7 +321,7 @@ sci_mpc_agent_validate_phy_configuration(struct isci_host *ihost, static void mpc_agent_timeout(struct timer_list *t) { u8 index; - struct sci_timer *tmr = from_timer(tmr, t, timer); + struct sci_timer *tmr = timer_container_of(tmr, t, timer); struct sci_port_configuration_agent *port_agent; struct isci_host *ihost; unsigned long flags; @@ -659,7 +659,7 @@ static void sci_apc_agent_link_down( static void apc_agent_timeout(struct timer_list *t) { u32 index; - struct sci_timer *tmr = from_timer(tmr, t, timer); + struct sci_timer *tmr = timer_container_of(tmr, t, timer); struct sci_port_configuration_agent *port_agent; struct isci_host *ihost; unsigned long flags; diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c index e705c30b4e1b..16d0f02af1e4 100644 --- a/drivers/scsi/libfc/fc_fcp.c +++ b/drivers/scsi/libfc/fc_fcp.c @@ -1283,7 +1283,7 @@ static int fc_fcp_pkt_abort(struct fc_fcp_pkt *fsp) */ static void fc_lun_reset_send(struct timer_list *t) { - struct fc_fcp_pkt *fsp = from_timer(fsp, t, timer); + struct fc_fcp_pkt *fsp = timer_container_of(fsp, t, timer); struct fc_lport *lport = fsp->lp; if (lport->tt.fcp_cmd_send(lport, fsp, fc_tm_done)) { @@ -1416,7 +1416,7 @@ static void fc_fcp_cleanup(struct fc_lport *lport) */ static void fc_fcp_timeout(struct timer_list *t) { - struct fc_fcp_pkt *fsp = from_timer(fsp, t, timer); + struct fc_fcp_pkt *fsp = timer_container_of(fsp, t, timer); struct fc_rport *rport = fsp->rport; struct fc_rport_libfc_priv *rpriv = rport->dd_data; diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 1ddaf7228340..392d57e054db 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -1898,7 +1898,8 @@ EXPORT_SYMBOL_GPL(iscsi_target_alloc); static void iscsi_tmf_timedout(struct timer_list *t) { - struct iscsi_session *session = from_timer(session, t, tmf_timer); + struct iscsi_session *session = timer_container_of(session, t, + tmf_timer); spin_lock(&session->frwd_lock); if (session->tmf_state == TMF_QUEUED) { @@ -2240,7 +2241,7 @@ EXPORT_SYMBOL_GPL(iscsi_eh_cmd_timed_out); static void iscsi_check_transport_timeouts(struct timer_list *t) { - struct iscsi_conn *conn = from_timer(conn, t, transport_timer); + struct iscsi_conn *conn = timer_container_of(conn, t, transport_timer); struct iscsi_session *session = conn->session; unsigned long recv_timeout, next_timeout = 0, last_recv; diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c index feb2461b90e8..928723c90b75 100644 --- a/drivers/scsi/libsas/sas_scsi_host.c +++ b/drivers/scsi/libsas/sas_scsi_host.c @@ -865,7 +865,7 @@ void sas_task_internal_done(struct sas_task *task) void sas_task_internal_timedout(struct timer_list *t) { - struct sas_task_slow *slow = from_timer(slow, t, timer); + struct sas_task_slow *slow = timer_container_of(slow, t, timer); struct sas_task *task = slow->task; bool is_completed = true; unsigned long flags; diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c index 12c67cdd7c19..530dddd39bab 100644 --- a/drivers/scsi/lpfc/lpfc_ct.c +++ b/drivers/scsi/lpfc/lpfc_ct.c @@ -3433,7 +3433,8 @@ fdmi_cmd_exit: void lpfc_delayed_disc_tmo(struct timer_list *t) { - struct lpfc_vport *vport = from_timer(vport, t, delayed_disc_tmo); + struct lpfc_vport *vport = timer_container_of(vport, t, + delayed_disc_tmo); struct lpfc_hba *phba = vport->phba; uint32_t tmo_posted; unsigned long iflag; diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 375a879c31f1..b1a61eca8295 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -4378,7 +4378,8 @@ lpfc_cancel_retry_delay_tmo(struct lpfc_vport *vport, struct lpfc_nodelist *nlp) void lpfc_els_retry_delay(struct timer_list *t) { - struct lpfc_nodelist *ndlp = from_timer(ndlp, t, nlp_delayfunc); + struct lpfc_nodelist *ndlp = timer_container_of(ndlp, t, + nlp_delayfunc); struct lpfc_vport *vport = ndlp->vport; struct lpfc_hba *phba = vport->phba; unsigned long flags; @@ -9385,7 +9386,7 @@ out: void lpfc_els_timeout(struct timer_list *t) { - struct lpfc_vport *vport = from_timer(vport, t, els_tmofunc); + struct lpfc_vport *vport = timer_container_of(vport, t, els_tmofunc); struct lpfc_hba *phba = vport->phba; uint32_t tmo_posted; unsigned long iflag; @@ -11594,7 +11595,8 @@ err: void lpfc_fabric_block_timeout(struct timer_list *t) { - struct lpfc_hba *phba = from_timer(phba, t, fabric_block_timer); + struct lpfc_hba *phba = timer_container_of(phba, t, + fabric_block_timer); unsigned long iflags; uint32_t tmo_posted; diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 3d15a964f5c9..b88e54a7e65c 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -6059,7 +6059,7 @@ lpfc_cleanup_discovery_resources(struct lpfc_vport *vport) void lpfc_disc_timeout(struct timer_list *t) { - struct lpfc_vport *vport = from_timer(vport, t, fc_disctmo); + struct lpfc_vport *vport = timer_container_of(vport, t, fc_disctmo); struct lpfc_hba *phba = vport->phba; uint32_t tmo_posted; unsigned long flags = 0; diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 2400602a8561..20fa450def03 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -1196,7 +1196,7 @@ lpfc_hb_timeout(struct timer_list *t) uint32_t tmo_posted; unsigned long iflag; - phba = from_timer(phba, t, hb_tmofunc); + phba = timer_container_of(phba, t, hb_tmofunc); /* Check for heart beat timeout conditions */ spin_lock_irqsave(&phba->pport->work_port_lock, iflag); @@ -1228,7 +1228,7 @@ lpfc_rrq_timeout(struct timer_list *t) { struct lpfc_hba *phba; - phba = from_timer(phba, t, rrq_tmr); + phba = timer_container_of(phba, t, rrq_tmr); if (test_bit(FC_UNLOADING, &phba->pport->load_flag)) { clear_bit(HBA_RRQ_ACTIVE, &phba->hba_flag); return; @@ -5131,7 +5131,7 @@ lpfc_fcf_redisc_wait_start_timer(struct lpfc_hba *phba) static void lpfc_sli4_fcf_redisc_wait_tmo(struct timer_list *t) { - struct lpfc_hba *phba = from_timer(phba, t, fcf.redisc_wait); + struct lpfc_hba *phba = timer_container_of(phba, t, fcf.redisc_wait); /* Don't send FCF rediscovery event if timer cancelled */ spin_lock_irq(&phba->hbalock); @@ -5162,7 +5162,8 @@ lpfc_sli4_fcf_redisc_wait_tmo(struct timer_list *t) static void lpfc_vmid_poll(struct timer_list *t) { - struct lpfc_hba *phba = from_timer(phba, t, inactive_vmid_poll); + struct lpfc_hba *phba = timer_container_of(phba, t, + inactive_vmid_poll); u32 wake_up = 0; /* check if there is a need to issue QFPA */ diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 9edf80b14b1a..8acb744febcd 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -5190,7 +5190,7 @@ void lpfc_poll_start_timer(struct lpfc_hba * phba) **/ void lpfc_poll_timeout(struct timer_list *t) { - struct lpfc_hba *phba = from_timer(phba, t, fcp_poll_timer); + struct lpfc_hba *phba = timer_container_of(phba, t, fcp_poll_timer); if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) { lpfc_sli_handle_fast_ring_event(phba, diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 2ebb073e4ef3..47bbcb78fb4d 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -3925,7 +3925,7 @@ void lpfc_poll_eratt(struct timer_list *t) uint32_t eratt = 0; uint64_t sli_intr, cnt; - phba = from_timer(phba, t, eratt_poll); + phba = timer_container_of(phba, t, eratt_poll); if (test_bit(FC_UNLOADING, &phba->pport->load_flag)) return; @@ -9125,7 +9125,7 @@ out_free_mbox: void lpfc_mbox_timeout(struct timer_list *t) { - struct lpfc_hba *phba = from_timer(phba, t, sli.mbox_tmo); + struct lpfc_hba *phba = timer_container_of(phba, t, sli.mbox_tmo); unsigned long iflag; uint32_t tmo_posted; @@ -15661,7 +15661,7 @@ lpfc_sli4_intr_handler(int irq, void *dev_id) void lpfc_sli4_poll_hbtimer(struct timer_list *t) { - struct lpfc_hba *phba = from_timer(phba, t, cpuhp_poll_timer); + struct lpfc_hba *phba = timer_container_of(phba, t, cpuhp_poll_timer); struct lpfc_queue *eq; rcu_read_lock(); diff --git a/drivers/scsi/megaraid/megaraid_mbox.c b/drivers/scsi/megaraid/megaraid_mbox.c index b75f46c30759..b610cad83321 100644 --- a/drivers/scsi/megaraid/megaraid_mbox.c +++ b/drivers/scsi/megaraid/megaraid_mbox.c @@ -3836,7 +3836,7 @@ megaraid_sysfs_get_ldmap_done(uioc_t *uioc) static void megaraid_sysfs_get_ldmap_timeout(struct timer_list *t) { - struct uioc_timeout *timeout = from_timer(timeout, t, timer); + struct uioc_timeout *timeout = timer_container_of(timeout, t, timer); uioc_t *uioc = timeout->uioc; adapter_t *adapter = (adapter_t *)uioc->buf_vaddr; mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); diff --git a/drivers/scsi/megaraid/megaraid_mm.c b/drivers/scsi/megaraid/megaraid_mm.c index fd7fa7640a5e..87184e2538b0 100644 --- a/drivers/scsi/megaraid/megaraid_mm.c +++ b/drivers/scsi/megaraid/megaraid_mm.c @@ -783,7 +783,7 @@ ioctl_done(uioc_t *kioc) static void lld_timedout(struct timer_list *t) { - struct uioc_timeout *timeout = from_timer(timeout, t, timer); + struct uioc_timeout *timeout = timer_container_of(timeout, t, timer); uioc_t *kioc = timeout->uioc; kioc->status = -ETIME; diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index 5e33d411fa3d..3aac0e17cb00 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -2724,7 +2724,7 @@ out: static void megasas_sriov_heartbeat_handler(struct timer_list *t) { struct megasas_instance *instance = - from_timer(instance, t, sriov_heartbeat_timer); + timer_container_of(instance, t, sriov_heartbeat_timer); if (instance->hb_host_mem->HB.fwCounter != instance->hb_host_mem->HB.driverCounter) { diff --git a/drivers/scsi/mvsas/mv_sas.c b/drivers/scsi/mvsas/mv_sas.c index 52ac10226cb0..6c46654b9cd9 100644 --- a/drivers/scsi/mvsas/mv_sas.c +++ b/drivers/scsi/mvsas/mv_sas.c @@ -1755,7 +1755,7 @@ static int mvs_handle_event(struct mvs_info *mvi, void *data, int handler) static void mvs_sig_time_out(struct timer_list *t) { - struct mvs_phy *phy = from_timer(phy, t, timer); + struct mvs_phy *phy = timer_container_of(phy, t, timer); struct mvs_info *mvi = phy->mvi; u8 phy_no; diff --git a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c index 14ac81ec0aa0..34ba9b137789 100644 --- a/drivers/scsi/ncr53c8xx.c +++ b/drivers/scsi/ncr53c8xx.c @@ -7923,7 +7923,7 @@ irqreturn_t ncr53c8xx_intr(int irq, void *dev_id) static void ncr53c8xx_timeout(struct timer_list *t) { - struct ncb *np = from_timer(np, t, timer); + struct ncb *np = timer_container_of(np, t, timer); unsigned long flags; struct scsi_cmnd *done_list; diff --git a/drivers/scsi/pmcraid.c b/drivers/scsi/pmcraid.c index e0aeb206df8d..33f403e307eb 100644 --- a/drivers/scsi/pmcraid.c +++ b/drivers/scsi/pmcraid.c @@ -544,7 +544,7 @@ static void pmcraid_ioa_reset(struct pmcraid_cmd *); */ static void pmcraid_bist_done(struct timer_list *t) { - struct pmcraid_cmd *cmd = from_timer(cmd, t, timer); + struct pmcraid_cmd *cmd = timer_container_of(cmd, t, timer); struct pmcraid_instance *pinstance = cmd->drv_inst; unsigned long lock_flags; int rc; @@ -601,7 +601,7 @@ static void pmcraid_start_bist(struct pmcraid_cmd *cmd) */ static void pmcraid_reset_alert_done(struct timer_list *t) { - struct pmcraid_cmd *cmd = from_timer(cmd, t, timer); + struct pmcraid_cmd *cmd = timer_container_of(cmd, t, timer); struct pmcraid_instance *pinstance = cmd->drv_inst; u32 status = ioread32(pinstance->ioa_status); unsigned long lock_flags; @@ -685,7 +685,7 @@ static void pmcraid_reset_alert(struct pmcraid_cmd *cmd) */ static void pmcraid_timeout_handler(struct timer_list *t) { - struct pmcraid_cmd *cmd = from_timer(cmd, t, timer); + struct pmcraid_cmd *cmd = timer_container_of(cmd, t, timer); struct pmcraid_instance *pinstance = cmd->drv_inst; unsigned long lock_flags; diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c index 078a9c80bce2..6af018f1ca22 100644 --- a/drivers/scsi/qla1280.c +++ b/drivers/scsi/qla1280.c @@ -721,7 +721,7 @@ enum action { static void qla1280_mailbox_timeout(struct timer_list *t) { - struct scsi_qla_host *ha = from_timer(ha, t, mailbox_timer); + struct scsi_qla_host *ha = timer_container_of(ha, t, mailbox_timer); struct device_reg __iomem *reg; reg = ha->iobase; diff --git a/drivers/scsi/qla2xxx/qla_edif.c b/drivers/scsi/qla2xxx/qla_edif.c index dcde55c8ee5d..91bbd3b75bff 100644 --- a/drivers/scsi/qla2xxx/qla_edif.c +++ b/drivers/scsi/qla2xxx/qla_edif.c @@ -94,7 +94,8 @@ static struct edif_list_entry *qla_edif_list_find_sa_index(fc_port_t *fcport, /* timeout called when no traffic and delayed rx sa_index delete */ static void qla2x00_sa_replace_iocb_timeout(struct timer_list *t) { - struct edif_list_entry *edif_entry = from_timer(edif_entry, t, timer); + struct edif_list_entry *edif_entry = timer_container_of(edif_entry, t, + timer); fc_port_t *fcport = edif_entry->fcport; struct scsi_qla_host *vha = fcport->vha; struct edif_sa_ctl *sa_ctl; diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 0c2dd782b675..514934dd6f80 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -45,7 +45,7 @@ static void __qla24xx_handle_gpdb_event(scsi_qla_host_t *, struct event_arg *); void qla2x00_sp_timeout(struct timer_list *t) { - srb_t *sp = from_timer(sp, t, u.iocb_cmd.timer); + srb_t *sp = timer_container_of(sp, t, u.iocb_cmd.timer); struct srb_iocb *iocb; scsi_qla_host_t *vha = sp->vha; diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 288ce04fc2b1..d4b484c0fd9d 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -7380,7 +7380,7 @@ static void qla_wind_down_chip(scsi_qla_host_t *vha) void qla2x00_timer(struct timer_list *t) { - scsi_qla_host_t *vha = from_timer(vha, t, timer); + scsi_qla_host_t *vha = timer_container_of(vha, t, timer); unsigned long cpu_flags = 0; int start_dpc = 0; int index; diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index d540d66e6ffc..d4141656b204 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -4551,7 +4551,7 @@ static void qla4xxx_check_relogin_flash_ddb(struct iscsi_cls_session *cls_sess) **/ static void qla4xxx_timer(struct timer_list *t) { - struct scsi_qla_host *ha = from_timer(ha, t, timer); + struct scsi_qla_host *ha = timer_container_of(ha, t, timer); int start_dpc = 0; uint16_t w; diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c index a348df895dca..8ff679e67bbf 100644 --- a/drivers/scsi/scsi_devinfo.c +++ b/drivers/scsi/scsi_devinfo.c @@ -836,7 +836,7 @@ int __init scsi_init_devinfo(void) goto out; for (i = 0; scsi_static_device_list[i].vendor; i++) { - error = scsi_dev_info_list_add(1 /* compatibile */, + error = scsi_dev_info_list_add(1 /* compatible */, scsi_static_device_list[i].vendor, scsi_static_device_list[i].model, NULL, diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c index 1d784ee7671c..3d40a63e378d 100644 --- a/drivers/scsi/smartpqi/smartpqi_init.c +++ b/drivers/scsi/smartpqi/smartpqi_init.c @@ -3825,7 +3825,8 @@ static void pqi_heartbeat_timer_handler(struct timer_list *t) { int num_interrupts; u32 heartbeat_count; - struct pqi_ctrl_info *ctrl_info = from_timer(ctrl_info, t, heartbeat_timer); + struct pqi_ctrl_info *ctrl_info = timer_container_of(ctrl_info, t, + heartbeat_timer); pqi_check_ctrl_health(ctrl_info); if (pqi_ctrl_offline(ctrl_info)) diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c index 1a6eb72ca281..57637a81776d 100644 --- a/drivers/scsi/sym53c8xx_2/sym_glue.c +++ b/drivers/scsi/sym53c8xx_2/sym_glue.c @@ -545,7 +545,7 @@ static irqreturn_t sym53c8xx_intr(int irq, void *dev_id) */ static void sym53c8xx_timer(struct timer_list *t) { - struct sym_hcb *np = from_timer(np, t, s.timer); + struct sym_hcb *np = timer_container_of(np, t, s.timer); unsigned long flags; spin_lock_irqsave(np->s.host->host_lock, flags); diff --git a/drivers/spi/spi-bcm63xx-hsspi.c b/drivers/spi/spi-bcm63xx-hsspi.c index 644b44d2aef2..18261cbd413b 100644 --- a/drivers/spi/spi-bcm63xx-hsspi.c +++ b/drivers/spi/spi-bcm63xx-hsspi.c @@ -745,7 +745,7 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev) if (IS_ERR(clk)) return PTR_ERR(clk); - reset = devm_reset_control_get_optional_exclusive(dev, NULL); + reset = devm_reset_control_get_optional_shared(dev, NULL); if (IS_ERR(reset)) return PTR_ERR(reset); diff --git a/drivers/spi/spi-bcm63xx.c b/drivers/spi/spi-bcm63xx.c index c8f64ec69344..b56210734caa 100644 --- a/drivers/spi/spi-bcm63xx.c +++ b/drivers/spi/spi-bcm63xx.c @@ -523,7 +523,7 @@ static int bcm63xx_spi_probe(struct platform_device *pdev) return PTR_ERR(clk); } - reset = devm_reset_control_get_optional_exclusive(dev, NULL); + reset = devm_reset_control_get_optional_shared(dev, NULL); if (IS_ERR(reset)) return PTR_ERR(reset); diff --git a/drivers/spi/spi-pci1xxxx.c b/drivers/spi/spi-pci1xxxx.c index 330078b1d50f..c6489e90b8b9 100644 --- a/drivers/spi/spi-pci1xxxx.c +++ b/drivers/spi/spi-pci1xxxx.c @@ -685,6 +685,17 @@ static irqreturn_t pci1xxxx_spi_isr(int irq, void *dev) return pci1xxxx_spi_isr_io(irq, dev); } +static irqreturn_t pci1xxxx_spi_shared_isr(int irq, void *dev) +{ + struct pci1xxxx_spi *par = dev; + u8 i = 0; + + for (i = 0; i < par->total_hw_instances; i++) + pci1xxxx_spi_isr(irq, par->spi_int[i]); + + return IRQ_HANDLED; +} + static bool pci1xxxx_spi_can_dma(struct spi_controller *host, struct spi_device *spi, struct spi_transfer *xfer) @@ -702,6 +713,7 @@ static int pci1xxxx_spi_probe(struct pci_dev *pdev, const struct pci_device_id * struct device *dev = &pdev->dev; struct pci1xxxx_spi *spi_bus; struct spi_controller *spi_host; + int num_vector = 0; u32 regval; int ret; @@ -749,9 +761,9 @@ static int pci1xxxx_spi_probe(struct pci_dev *pdev, const struct pci_device_id * if (!spi_bus->reg_base) return -EINVAL; - ret = pci_alloc_irq_vectors(pdev, hw_inst_cnt, hw_inst_cnt, - PCI_IRQ_ALL_TYPES); - if (ret < 0) { + num_vector = pci_alloc_irq_vectors(pdev, 1, hw_inst_cnt, + PCI_IRQ_ALL_TYPES); + if (num_vector < 0) { dev_err(&pdev->dev, "Error allocating MSI vectors\n"); return ret; } @@ -765,9 +777,15 @@ static int pci1xxxx_spi_probe(struct pci_dev *pdev, const struct pci_device_id * SPI_MST_EVENT_MASK_REG_OFFSET(spi_sub_ptr->hw_inst)); spi_sub_ptr->irq = pci_irq_vector(pdev, 0); - ret = devm_request_irq(&pdev->dev, spi_sub_ptr->irq, - pci1xxxx_spi_isr, PCI1XXXX_IRQ_FLAGS, - pci_name(pdev), spi_sub_ptr); + if (num_vector >= hw_inst_cnt) + ret = devm_request_irq(&pdev->dev, spi_sub_ptr->irq, + pci1xxxx_spi_isr, PCI1XXXX_IRQ_FLAGS, + pci_name(pdev), spi_sub_ptr); + else + ret = devm_request_irq(&pdev->dev, spi_sub_ptr->irq, + pci1xxxx_spi_shared_isr, + PCI1XXXX_IRQ_FLAGS | IRQF_SHARED, + pci_name(pdev), spi_bus); if (ret < 0) { dev_err(&pdev->dev, "Unable to request irq : %d", spi_sub_ptr->irq); @@ -798,14 +816,16 @@ static int pci1xxxx_spi_probe(struct pci_dev *pdev, const struct pci_device_id * regval &= ~SPI_INTR; writel(regval, spi_bus->reg_base + SPI_MST_EVENT_MASK_REG_OFFSET(spi_sub_ptr->hw_inst)); - spi_sub_ptr->irq = pci_irq_vector(pdev, iter); - ret = devm_request_irq(&pdev->dev, spi_sub_ptr->irq, - pci1xxxx_spi_isr, PCI1XXXX_IRQ_FLAGS, - pci_name(pdev), spi_sub_ptr); - if (ret < 0) { - dev_err(&pdev->dev, "Unable to request irq : %d", - spi_sub_ptr->irq); - return -ENODEV; + if (num_vector >= hw_inst_cnt) { + spi_sub_ptr->irq = pci_irq_vector(pdev, iter); + ret = devm_request_irq(&pdev->dev, spi_sub_ptr->irq, + pci1xxxx_spi_isr, PCI1XXXX_IRQ_FLAGS, + pci_name(pdev), spi_sub_ptr); + if (ret < 0) { + dev_err(&pdev->dev, "Unable to request irq : %d", + spi_sub_ptr->irq); + return -ENODEV; + } } } diff --git a/drivers/spi/spi-qpic-snand.c b/drivers/spi/spi-qpic-snand.c index 3f747fd61d19..77d9cc65477a 100644 --- a/drivers/spi/spi-qpic-snand.c +++ b/drivers/spi/spi-qpic-snand.c @@ -639,6 +639,20 @@ static int qcom_spi_check_error(struct qcom_nand_controller *snandc) unsigned int stat; stat = buffer & BS_CORRECTABLE_ERR_MSK; + + /* + * The exact number of the corrected bits is + * unknown because the hardware only reports the + * number of the corrected bytes. + * + * Since we have no better solution at the moment, + * report that value as the number of bit errors + * despite that it is inaccurate in most cases. + */ + if (stat && stat != ecc_cfg->strength) + dev_warn_once(snandc->dev, + "Warning: due to hw limitation, the reported number of the corrected bits may be inaccurate\n"); + snandc->qspi->ecc_stats.corrected += stat; max_bitflips = max(max_bitflips, stat); } diff --git a/drivers/spmi/Kconfig b/drivers/spmi/Kconfig index 737802046314..a80cf4047b86 100644 --- a/drivers/spmi/Kconfig +++ b/drivers/spmi/Kconfig @@ -11,9 +11,18 @@ menuconfig SPMI if SPMI +config SPMI_APPLE + tristate "Apple SoC SPMI Controller platform driver" + depends on ARCH_APPLE || COMPILE_TEST + help + If you say yes to this option, support will be included for the + SPMI controller present on many Apple SoCs, including the + t8103 (M1) and t600x (M1 Pro/Max). + config SPMI_HISI3670 tristate "Hisilicon 3670 SPMI Controller" select IRQ_DOMAIN_HIERARCHY + depends on ARM64 || COMPILE_TEST depends on HAS_IOMEM help If you say yes to this option, support will be included for the diff --git a/drivers/spmi/Makefile b/drivers/spmi/Makefile index 7f152167bb05..38ac635645ba 100644 --- a/drivers/spmi/Makefile +++ b/drivers/spmi/Makefile @@ -4,6 +4,7 @@ # obj-$(CONFIG_SPMI) += spmi.o spmi-devres.o +obj-$(CONFIG_SPMI_APPLE) += spmi-apple-controller.o obj-$(CONFIG_SPMI_HISI3670) += hisi-spmi-controller.o obj-$(CONFIG_SPMI_MSM_PMIC_ARB) += spmi-pmic-arb.o obj-$(CONFIG_SPMI_MTK_PMIF) += spmi-mtk-pmif.o diff --git a/drivers/spmi/spmi-apple-controller.c b/drivers/spmi/spmi-apple-controller.c new file mode 100644 index 000000000000..697b3e8bb023 --- /dev/null +++ b/drivers/spmi/spmi-apple-controller.c @@ -0,0 +1,168 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Apple SoC SPMI device driver + * + * Copyright The Asahi Linux Contributors + * + * Inspired by: + * OpenBSD support Copyright (c) 2021 Mark Kettenis <kettenis@openbsd.org> + * Correllium support Copyright (C) 2021 Corellium LLC + * hisi-spmi-controller.c + * spmi-pmic-arb.c Copyright (c) 2021, The Linux Foundation. + */ + +#include <linux/io.h> +#include <linux/iopoll.h> +#include <linux/module.h> +#include <linux/mod_devicetable.h> +#include <linux/platform_device.h> +#include <linux/spmi.h> + +/* SPMI Controller Registers */ +#define SPMI_STATUS_REG 0 +#define SPMI_CMD_REG 0x4 +#define SPMI_RSP_REG 0x8 + +#define SPMI_RX_FIFO_EMPTY BIT(24) + +#define REG_POLL_INTERVAL_US 10000 +#define REG_POLL_TIMEOUT_US (REG_POLL_INTERVAL_US * 5) + +struct apple_spmi { + void __iomem *regs; +}; + +#define poll_reg(spmi, reg, val, cond) \ + readl_poll_timeout((spmi)->regs + (reg), (val), (cond), \ + REG_POLL_INTERVAL_US, REG_POLL_TIMEOUT_US) + +static inline u32 apple_spmi_pack_cmd(u8 opc, u8 sid, u16 saddr, size_t len) +{ + return opc | sid << 8 | saddr << 16 | (len - 1) | (1 << 15); +} + +/* Wait for Rx FIFO to have something */ +static int apple_spmi_wait_rx_not_empty(struct spmi_controller *ctrl) +{ + struct apple_spmi *spmi = spmi_controller_get_drvdata(ctrl); + int ret; + u32 status; + + ret = poll_reg(spmi, SPMI_STATUS_REG, status, !(status & SPMI_RX_FIFO_EMPTY)); + if (ret) { + dev_err(&ctrl->dev, + "failed to wait for RX FIFO not empty\n"); + return ret; + } + + return 0; +} + +static int spmi_read_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid, + u16 saddr, u8 *buf, size_t len) +{ + struct apple_spmi *spmi = spmi_controller_get_drvdata(ctrl); + u32 spmi_cmd = apple_spmi_pack_cmd(opc, sid, saddr, len); + u32 rsp; + size_t len_read = 0; + u8 i; + int ret; + + writel(spmi_cmd, spmi->regs + SPMI_CMD_REG); + + ret = apple_spmi_wait_rx_not_empty(ctrl); + if (ret) + return ret; + + /* Discard SPMI reply status */ + readl(spmi->regs + SPMI_RSP_REG); + + /* Read SPMI data reply */ + while (len_read < len) { + rsp = readl(spmi->regs + SPMI_RSP_REG); + i = 0; + while ((len_read < len) && (i < 4)) { + buf[len_read++] = ((0xff << (8 * i)) & rsp) >> (8 * i); + i += 1; + } + } + + return 0; +} + +static int spmi_write_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid, + u16 saddr, const u8 *buf, size_t len) +{ + struct apple_spmi *spmi = spmi_controller_get_drvdata(ctrl); + u32 spmi_cmd = apple_spmi_pack_cmd(opc, sid, saddr, len); + size_t i = 0, j; + int ret; + + writel(spmi_cmd, spmi->regs + SPMI_CMD_REG); + + while (i < len) { + j = 0; + spmi_cmd = 0; + while ((j < 4) & (i < len)) + spmi_cmd |= buf[i++] << (j++ * 8); + + writel(spmi_cmd, spmi->regs + SPMI_CMD_REG); + } + + ret = apple_spmi_wait_rx_not_empty(ctrl); + if (ret) + return ret; + + /* Discard */ + readl(spmi->regs + SPMI_RSP_REG); + + return 0; +} + +static int apple_spmi_probe(struct platform_device *pdev) +{ + struct apple_spmi *spmi; + struct spmi_controller *ctrl; + int ret; + + ctrl = devm_spmi_controller_alloc(&pdev->dev, sizeof(*spmi)); + if (IS_ERR(ctrl)) + return -ENOMEM; + + spmi = spmi_controller_get_drvdata(ctrl); + + spmi->regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(spmi->regs)) + return PTR_ERR(spmi->regs); + + ctrl->dev.of_node = pdev->dev.of_node; + + ctrl->read_cmd = spmi_read_cmd; + ctrl->write_cmd = spmi_write_cmd; + + ret = devm_spmi_controller_add(&pdev->dev, ctrl); + if (ret) + return dev_err_probe(&pdev->dev, ret, + "spmi_controller_add failed\n"); + + return 0; +} + +static const struct of_device_id apple_spmi_match_table[] = { + { .compatible = "apple,spmi", }, + {} +}; +MODULE_DEVICE_TABLE(of, apple_spmi_match_table); + +static struct platform_driver apple_spmi_driver = { + .probe = apple_spmi_probe, + .driver = { + .name = "apple-spmi", + .of_match_table = apple_spmi_match_table, + }, +}; +module_platform_driver(apple_spmi_driver); + +MODULE_AUTHOR("Jean-Francois Bortolotti <jeff@borto.fr>"); +MODULE_DESCRIPTION("Apple SoC SPMI driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c index 5c058db21821..91581974ef84 100644 --- a/drivers/spmi/spmi-pmic-arb.c +++ b/drivers/spmi/spmi-pmic-arb.c @@ -1737,7 +1737,7 @@ static int spmi_pmic_arb_bus_init(struct platform_device *pdev, dev_dbg(&pdev->dev, "adding irq domain for bus %d\n", bus_index); - bus->domain = irq_domain_add_tree(node, &pmic_arb_irq_domain_ops, bus); + bus->domain = irq_domain_create_tree(of_fwnode_handle(node), &pmic_arb_irq_domain_ops, bus); if (!bus->domain) { dev_err(&pdev->dev, "unable to create irq_domain\n"); return -ENOMEM; diff --git a/drivers/staging/fbtft/Kconfig b/drivers/staging/fbtft/Kconfig index dcf6a70455cc..c2655768209a 100644 --- a/drivers/staging/fbtft/Kconfig +++ b/drivers/staging/fbtft/Kconfig @@ -8,160 +8,136 @@ menuconfig FB_TFT select FB_BACKLIGHT select FB_SYSMEM_HELPERS_DEFERRED +if FB_TFT + config FB_TFT_AGM1264K_FL tristate "FB driver for the AGM1264K-FL LCD display" - depends on FB_TFT help Framebuffer support for the AGM1264K-FL LCD display (two Samsung KS0108 compatible chips) config FB_TFT_BD663474 tristate "FB driver for the BD663474 LCD Controller" - depends on FB_TFT help Generic Framebuffer support for BD663474 config FB_TFT_HX8340BN tristate "FB driver for the HX8340BN LCD Controller" - depends on FB_TFT help Generic Framebuffer support for HX8340BN config FB_TFT_HX8347D tristate "FB driver for the HX8347D LCD Controller" - depends on FB_TFT help Generic Framebuffer support for HX8347D config FB_TFT_HX8353D tristate "FB driver for the HX8353D LCD Controller" - depends on FB_TFT help Generic Framebuffer support for HX8353D config FB_TFT_HX8357D tristate "FB driver for the HX8357D LCD Controller" - depends on FB_TFT help Generic Framebuffer support for HX8357D config FB_TFT_ILI9163 tristate "FB driver for the ILI9163 LCD Controller" - depends on FB_TFT help Generic Framebuffer support for ILI9163 config FB_TFT_ILI9320 tristate "FB driver for the ILI9320 LCD Controller" - depends on FB_TFT help Generic Framebuffer support for ILI9320 config FB_TFT_ILI9325 tristate "FB driver for the ILI9325 LCD Controller" - depends on FB_TFT help Generic Framebuffer support for ILI9325 config FB_TFT_ILI9340 tristate "FB driver for the ILI9340 LCD Controller" - depends on FB_TFT help Generic Framebuffer support for ILI9340 config FB_TFT_ILI9341 tristate "FB driver for the ILI9341 LCD Controller" - depends on FB_TFT help Generic Framebuffer support for ILI9341 config FB_TFT_ILI9481 tristate "FB driver for the ILI9481 LCD Controller" - depends on FB_TFT help Generic Framebuffer support for ILI9481 config FB_TFT_ILI9486 tristate "FB driver for the ILI9486 LCD Controller" - depends on FB_TFT help Generic Framebuffer support for ILI9486 config FB_TFT_PCD8544 tristate "FB driver for the PCD8544 LCD Controller" - depends on FB_TFT help Generic Framebuffer support for PCD8544 config FB_TFT_RA8875 tristate "FB driver for the RA8875 LCD Controller" - depends on FB_TFT help Generic Framebuffer support for RA8875 config FB_TFT_S6D02A1 tristate "FB driver for the S6D02A1 LCD Controller" - depends on FB_TFT help Generic Framebuffer support for S6D02A1 config FB_TFT_S6D1121 tristate "FB driver for the S6D1211 LCD Controller" - depends on FB_TFT help Generic Framebuffer support for S6D1121 config FB_TFT_SEPS525 tristate "FB driver for the SEPS525 LCD Controller" - depends on FB_TFT help Generic Framebuffer support for SEPS525 Say Y if you have such a display that utilizes this controller. config FB_TFT_SH1106 tristate "FB driver for the SH1106 OLED Controller" - depends on FB_TFT help Framebuffer support for SH1106 config FB_TFT_SSD1289 tristate "FB driver for the SSD1289 LCD Controller" - depends on FB_TFT help Framebuffer support for SSD1289 config FB_TFT_SSD1305 tristate "FB driver for the SSD1305 OLED Controller" - depends on FB_TFT help Framebuffer support for SSD1305 config FB_TFT_SSD1306 tristate "FB driver for the SSD1306 OLED Controller" - depends on FB_TFT help Framebuffer support for SSD1306 config FB_TFT_SSD1331 tristate "FB driver for the SSD1331 LCD Controller" - depends on FB_TFT help Framebuffer support for SSD1331 config FB_TFT_SSD1351 tristate "FB driver for the SSD1351 LCD Controller" - depends on FB_TFT help Framebuffer support for SSD1351 config FB_TFT_ST7735R tristate "FB driver for the ST7735R LCD Controller" - depends on FB_TFT help Generic Framebuffer support for ST7735R config FB_TFT_ST7789V tristate "FB driver for the ST7789V LCD Controller" - depends on FB_TFT help This enables generic framebuffer support for the Sitronix ST7789V display controller. The controller is intended for small color @@ -171,30 +147,27 @@ config FB_TFT_ST7789V config FB_TFT_TINYLCD tristate "FB driver for tinylcd.com display" - depends on FB_TFT help Custom Framebuffer support for tinylcd.com display config FB_TFT_TLS8204 tristate "FB driver for the TLS8204 LCD Controller" - depends on FB_TFT help Generic Framebuffer support for TLS8204 config FB_TFT_UC1611 tristate "FB driver for the UC1611 LCD controller" - depends on FB_TFT help Generic Framebuffer support for UC1611 config FB_TFT_UC1701 tristate "FB driver for the UC1701 LCD Controller" - depends on FB_TFT help Generic Framebuffer support for UC1701 config FB_TFT_UPD161704 tristate "FB driver for the uPD161704 LCD Controller" - depends on FB_TFT help Generic Framebuffer support for uPD161704 + +endif diff --git a/drivers/staging/gpib/agilent_82350b/agilent_82350b.c b/drivers/staging/gpib/agilent_82350b/agilent_82350b.c index 445b9380ff98..94bbb3b6576d 100644 --- a/drivers/staging/gpib/agilent_82350b/agilent_82350b.c +++ b/drivers/staging/gpib/agilent_82350b/agilent_82350b.c @@ -27,10 +27,10 @@ MODULE_DESCRIPTION("GPIB driver for Agilent 82350b"); static int read_transfer_counter(struct agilent_82350b_priv *a_priv); static unsigned short read_and_clear_event_status(struct gpib_board *board); static void set_transfer_counter(struct agilent_82350b_priv *a_priv, int count); -static int agilent_82350b_write(struct gpib_board *board, uint8_t *buffer, +static int agilent_82350b_write(struct gpib_board *board, u8 *buffer, size_t length, int send_eoi, size_t *bytes_written); -static int agilent_82350b_accel_read(struct gpib_board *board, uint8_t *buffer, +static int agilent_82350b_accel_read(struct gpib_board *board, u8 *buffer, size_t length, int *end, size_t *bytes_read) { @@ -39,7 +39,7 @@ static int agilent_82350b_accel_read(struct gpib_board *board, uint8_t *buffer, int retval = 0; unsigned short event_status; int i, num_fifo_bytes; - //hardware doesn't support checking for end-of-string character when using fifo + /* hardware doesn't support checking for end-of-string character when using fifo */ if (tms_priv->eos_flags & REOS) return tms9914_read(board, tms_priv, buffer, length, end, bytes_read); @@ -50,9 +50,9 @@ static int agilent_82350b_accel_read(struct gpib_board *board, uint8_t *buffer, *bytes_read = 0; if (length == 0) return 0; - //disable fifo for the moment + /* disable fifo for the moment */ writeb(DIRECTION_GPIB_TO_HOST, a_priv->gpib_base + SRAM_ACCESS_CONTROL_REG); - // handle corner case of board not in holdoff and one byte might slip in early + /* handle corner case of board not in holdoff and one byte might slip in early */ if (tms_priv->holdoff_active == 0 && length > 1) { size_t num_bytes; @@ -67,7 +67,8 @@ static int agilent_82350b_accel_read(struct gpib_board *board, uint8_t *buffer, tms9914_release_holdoff(tms_priv); i = 0; num_fifo_bytes = length - 1; - write_byte(tms_priv, tms_priv->imr0_bits & ~HR_BIIE, IMR0); // disable BI interrupts + /* disable BI interrupts */ + write_byte(tms_priv, tms_priv->imr0_bits & ~HR_BIIE, IMR0); while (i < num_fifo_bytes && *end == 0) { int block_size; int j; @@ -111,17 +112,18 @@ static int agilent_82350b_accel_read(struct gpib_board *board, uint8_t *buffer, break; } } - write_byte(tms_priv, tms_priv->imr0_bits, IMR0); // re-enable BI interrupts + /* re-enable BI interrupts */ + write_byte(tms_priv, tms_priv->imr0_bits, IMR0); *bytes_read += i; buffer += i; length -= i; writeb(DIRECTION_GPIB_TO_HOST, a_priv->gpib_base + SRAM_ACCESS_CONTROL_REG); if (retval < 0) return retval; - // read last bytes if we havn't received an END yet + /* read last bytes if we havn't received an END yet */ if (*end == 0) { size_t num_bytes; - // try to make sure we holdoff after last byte read + /* try to make sure we holdoff after last byte read */ retval = tms9914_read(board, tms_priv, buffer, length, end, &num_bytes); *bytes_read += num_bytes; if (retval < 0) @@ -145,7 +147,7 @@ static int translate_wait_return_value(struct gpib_board *board, int retval) return 0; } -static int agilent_82350b_accel_write(struct gpib_board *board, uint8_t *buffer, +static int agilent_82350b_accel_write(struct gpib_board *board, u8 *buffer, size_t length, int send_eoi, size_t *bytes_written) { @@ -169,7 +171,7 @@ static int agilent_82350b_accel_write(struct gpib_board *board, uint8_t *buffer, event_status = read_and_clear_event_status(board); #ifdef EXPERIMENTAL - // wait for previous BO to complete if any + /* wait for previous BO to complete if any */ retval = wait_event_interruptible(board->wait, test_bit(DEV_CLEAR_BN, &tms_priv->state) || test_bit(WRITE_READY_BN, &tms_priv->state) || @@ -192,7 +194,7 @@ static int agilent_82350b_accel_write(struct gpib_board *board, uint8_t *buffer, block_size = min(fifotransferlength - i, agilent_82350b_fifo_size); set_transfer_counter(a_priv, block_size); for (j = 0; j < block_size; ++j, ++i) { - // load data into board's sram + /* load data into board's sram */ writeb(buffer[i], a_priv->sram_base + j); } writeb(ENABLE_TI_TO_SRAM, a_priv->gpib_base + SRAM_ACCESS_CONTROL_REG); @@ -262,7 +264,7 @@ static irqreturn_t agilent_82350b_interrupt(int irq, void *arg) tms9914_interrupt_have_status(board, &a_priv->tms9914_priv, tms9914_status1, tms9914_status2); } -//write-clear status bits + /* write-clear status bits */ if (event_status & (BUFFER_END_STATUS_BIT | TERM_COUNT_STATUS_BIT)) { writeb(event_status & (BUFFER_END_STATUS_BIT | TERM_COUNT_STATUS_BIT), a_priv->gpib_base + EVENT_STATUS_REG); @@ -292,12 +294,12 @@ static void set_transfer_counter(struct agilent_82350b_priv *a_priv, int count) writeb(complement & 0xff, a_priv->gpib_base + XFER_COUNT_LO_REG); writeb((complement >> 8) & 0xff, a_priv->gpib_base + XFER_COUNT_MID_REG); - //I don't think the hi count reg is even used, but oh well + /* I don't think the hi count reg is even used, but oh well */ writeb((complement >> 16) & 0xf, a_priv->gpib_base + XFER_COUNT_HI_REG); } -// wrappers for interface functions -static int agilent_82350b_read(struct gpib_board *board, uint8_t *buffer, +/* wrappers for interface functions */ +static int agilent_82350b_read(struct gpib_board *board, u8 *buffer, size_t length, int *end, size_t *bytes_read) { struct agilent_82350b_priv *priv = board->private_data; @@ -305,7 +307,7 @@ static int agilent_82350b_read(struct gpib_board *board, uint8_t *buffer, return tms9914_read(board, &priv->tms9914_priv, buffer, length, end, bytes_read); } -static int agilent_82350b_write(struct gpib_board *board, uint8_t *buffer, +static int agilent_82350b_write(struct gpib_board *board, u8 *buffer, size_t length, int send_eoi, size_t *bytes_written) { @@ -314,7 +316,7 @@ static int agilent_82350b_write(struct gpib_board *board, uint8_t *buffer, return tms9914_write(board, &priv->tms9914_priv, buffer, length, send_eoi, bytes_written); } -static int agilent_82350b_command(struct gpib_board *board, uint8_t *buffer, +static int agilent_82350b_command(struct gpib_board *board, u8 *buffer, size_t length, size_t *bytes_written) { @@ -339,9 +341,7 @@ static int agilent_82350b_go_to_standby(struct gpib_board *board) return tms9914_go_to_standby(board, &priv->tms9914_priv); } -static void agilent_82350b_request_system_control(struct gpib_board *board, - int request_control) - +static int agilent_82350b_request_system_control(struct gpib_board *board, int request_control) { struct agilent_82350b_priv *a_priv = board->private_data; @@ -355,7 +355,7 @@ static void agilent_82350b_request_system_control(struct gpib_board *board, writeb(0, a_priv->gpib_base + INTERNAL_CONFIG_REG); } writeb(a_priv->card_mode_bits, a_priv->gpib_base + CARD_MODE_REG); - tms9914_request_system_control(board, &a_priv->tms9914_priv, request_control); + return tms9914_request_system_control(board, &a_priv->tms9914_priv, request_control); } static void agilent_82350b_interface_clear(struct gpib_board *board, int assert) @@ -373,7 +373,7 @@ static void agilent_82350b_remote_enable(struct gpib_board *board, int enable) tms9914_remote_enable(board, &priv->tms9914_priv, enable); } -static int agilent_82350b_enable_eos(struct gpib_board *board, uint8_t eos_byte, +static int agilent_82350b_enable_eos(struct gpib_board *board, u8 eos_byte, int compare_8_bits) { struct agilent_82350b_priv *priv = board->private_data; @@ -412,7 +412,7 @@ static int agilent_82350b_secondary_address(struct gpib_board *board, return tms9914_secondary_address(board, &priv->tms9914_priv, address, enable); } -static int agilent_82350b_parallel_poll(struct gpib_board *board, uint8_t *result) +static int agilent_82350b_parallel_poll(struct gpib_board *board, u8 *result) { struct agilent_82350b_priv *priv = board->private_data; @@ -420,7 +420,7 @@ static int agilent_82350b_parallel_poll(struct gpib_board *board, uint8_t *resul } static void agilent_82350b_parallel_poll_configure(struct gpib_board *board, - uint8_t config) + u8 config) { struct agilent_82350b_priv *priv = board->private_data; @@ -434,14 +434,14 @@ static void agilent_82350b_parallel_poll_response(struct gpib_board *board, int tms9914_parallel_poll_response(board, &priv->tms9914_priv, ist); } -static void agilent_82350b_serial_poll_response(struct gpib_board *board, uint8_t status) +static void agilent_82350b_serial_poll_response(struct gpib_board *board, u8 status) { struct agilent_82350b_priv *priv = board->private_data; tms9914_serial_poll_response(board, &priv->tms9914_priv, status); } -static uint8_t agilent_82350b_serial_poll_status(struct gpib_board *board) +static u8 agilent_82350b_serial_poll_status(struct gpib_board *board) { struct agilent_82350b_priv *priv = board->private_data; @@ -492,7 +492,7 @@ static void agilent_82350b_free_private(struct gpib_board *board) } static int init_82350a_hardware(struct gpib_board *board, - const gpib_board_config_t *config) + const struct gpib_board_config *config) { struct agilent_82350b_priv *a_priv = board->private_data; static const unsigned int firmware_length = 5302; @@ -511,18 +511,18 @@ static int init_82350a_hardware(struct gpib_board *board, PLX9050_PCI_RETRY_DELAY_BITS(64) | PLX9050_DIRECT_SLAVE_LOCK_ENABLE_BIT; -// load borg data + /* load borg data */ borg_status = readb(a_priv->borg_base); if ((borg_status & BORG_DONE_BIT)) return 0; - // need to programme borg + /* need to programme borg */ if (!config->init_data || config->init_data_length != firmware_length) { dev_err(board->gpib_dev, "the 82350A board requires firmware after powering on.\n"); return -EIO; } dev_dbg(board->gpib_dev, "Loading firmware...\n"); - // tickle the borg + /* tickle the borg */ writel(plx_cntrl_static_bits | PLX9050_USER3_DATA_BIT, a_priv->plx_base + PLX9050_CNTRL_REG); usleep_range(1000, 2000); @@ -563,7 +563,7 @@ static int test_sram(struct gpib_board *board) struct agilent_82350b_priv *a_priv = board->private_data; unsigned int i; const unsigned int sram_length = pci_resource_len(a_priv->pci_device, SRAM_82350A_REGION); - // test SRAM + /* test SRAM */ const unsigned int byte_mask = 0xff; for (i = 0; i < sram_length; ++i) { @@ -587,7 +587,7 @@ static int test_sram(struct gpib_board *board) } static int agilent_82350b_generic_attach(struct gpib_board *board, - const gpib_board_config_t *config, + const struct gpib_board_config *config, int use_fifos) { @@ -606,7 +606,7 @@ static int agilent_82350b_generic_attach(struct gpib_board *board, tms_priv->write_byte = tms9914_iomem_write_byte; tms_priv->offset = 1; - // find board + /* find board */ a_priv->pci_device = gpib_pci_get_device(config, PCI_VENDOR_ID_AGILENT, PCI_DEVICE_ID_82350B, NULL); if (a_priv->pci_device) { @@ -702,7 +702,7 @@ static int agilent_82350b_generic_attach(struct gpib_board *board, writeb(a_priv->card_mode_bits, a_priv->gpib_base + CARD_MODE_REG); if (a_priv->model == MODEL_82350A) { - // enable PCI interrupts for 82350a + /* enable PCI interrupts for 82350a */ writel(PLX9050_LINTR1_EN_BIT | PLX9050_LINTR2_POLARITY_BIT | PLX9050_PCI_INTR_EN_BIT, a_priv->plx_base + PLX9050_INTCSR_REG); @@ -713,7 +713,7 @@ static int agilent_82350b_generic_attach(struct gpib_board *board, a_priv->gpib_base + EVENT_ENABLE_REG); writeb(ENABLE_TERM_COUNT_INTERRUPT_BIT | ENABLE_BUFFER_END_INTERRUPT_BIT | ENABLE_TMS9914_INTERRUPTS_BIT, a_priv->gpib_base + INTERRUPT_ENABLE_REG); - //write-clear event status bits + /* write-clear event status bits */ writeb(BUFFER_END_STATUS_BIT | TERM_COUNT_STATUS_BIT, a_priv->gpib_base + EVENT_STATUS_REG); } else { @@ -730,13 +730,13 @@ static int agilent_82350b_generic_attach(struct gpib_board *board, } static int agilent_82350b_unaccel_attach(struct gpib_board *board, - const gpib_board_config_t *config) + const struct gpib_board_config *config) { return agilent_82350b_generic_attach(board, config, 0); } static int agilent_82350b_accel_attach(struct gpib_board *board, - const gpib_board_config_t *config) + const struct gpib_board_config *config) { return agilent_82350b_generic_attach(board, config, 1); } @@ -747,7 +747,7 @@ static void agilent_82350b_detach(struct gpib_board *board) struct tms9914_priv *tms_priv; if (a_priv) { - if (a_priv->plx_base) // disable interrupts + if (a_priv->plx_base) /* disable interrupts */ writel(0, a_priv->plx_base + PLX9050_INTCSR_REG); tms_priv = &a_priv->tms9914_priv; @@ -773,7 +773,7 @@ static void agilent_82350b_detach(struct gpib_board *board) agilent_82350b_free_private(board); } -static gpib_interface_t agilent_82350b_unaccel_interface = { +static struct gpib_interface agilent_82350b_unaccel_interface = { .name = "agilent_82350b_unaccel", .attach = agilent_82350b_unaccel_attach, .detach = agilent_82350b_detach, @@ -790,7 +790,7 @@ static gpib_interface_t agilent_82350b_unaccel_interface = { .parallel_poll = agilent_82350b_parallel_poll, .parallel_poll_configure = agilent_82350b_parallel_poll_configure, .parallel_poll_response = agilent_82350b_parallel_poll_response, - .local_parallel_poll_mode = NULL, // XXX + .local_parallel_poll_mode = NULL, /* XXX */ .line_status = agilent_82350b_line_status, .update_status = agilent_82350b_update_status, .primary_address = agilent_82350b_primary_address, @@ -801,7 +801,7 @@ static gpib_interface_t agilent_82350b_unaccel_interface = { .return_to_local = agilent_82350b_return_to_local, }; -static gpib_interface_t agilent_82350b_interface = { +static struct gpib_interface agilent_82350b_interface = { .name = "agilent_82350b", .attach = agilent_82350b_accel_attach, .detach = agilent_82350b_detach, @@ -818,7 +818,7 @@ static gpib_interface_t agilent_82350b_interface = { .parallel_poll = agilent_82350b_parallel_poll, .parallel_poll_configure = agilent_82350b_parallel_poll_configure, .parallel_poll_response = agilent_82350b_parallel_poll_response, - .local_parallel_poll_mode = NULL, // XXX + .local_parallel_poll_mode = NULL, /* XXX */ .line_status = agilent_82350b_line_status, .update_status = agilent_82350b_update_status, .primary_address = agilent_82350b_primary_address, diff --git a/drivers/staging/gpib/agilent_82350b/agilent_82350b.h b/drivers/staging/gpib/agilent_82350b/agilent_82350b.h index 1573230c619d..ef841957297f 100644 --- a/drivers/staging/gpib/agilent_82350b/agilent_82350b.h +++ b/drivers/staging/gpib/agilent_82350b/agilent_82350b.h @@ -41,11 +41,11 @@ enum board_model { MODEL_82351A }; -// struct which defines private_data for board +/* struct which defines private_data for board */ struct agilent_82350b_priv { struct tms9914_priv tms9914_priv; struct pci_dev *pci_device; - void __iomem *plx_base; //82350a only + void __iomem *plx_base; /* 82350a only */ void __iomem *gpib_base; void __iomem *sram_base; void __iomem *misc_base; @@ -57,12 +57,12 @@ struct agilent_82350b_priv { bool using_fifos; }; -//registers +/* registers */ enum agilent_82350b_gpib_registers { CARD_MODE_REG = 0x1, - CONFIG_DATA_REG = 0x2, // 82350A specific + CONFIG_DATA_REG = 0x2, /* 82350A specific */ INTERRUPT_ENABLE_REG = 0x3, EVENT_STATUS_REG = 0x4, EVENT_ENABLE_REG = 0x5, @@ -76,8 +76,8 @@ enum agilent_82350b_gpib_registers XFER_COUNT_HI_REG = 0xe, TMS9914_BASE_REG = 0x10, INTERNAL_CONFIG_REG = 0x18, - IMR0_READ_REG = 0x19, //read - T1_DELAY_REG = 0x19, // write + IMR0_READ_REG = 0x19, /* read */ + T1_DELAY_REG = 0x19, /* write */ IMR1_READ_REG = 0x1a, ADR_READ_REG = 0x1b, SPMR_READ_REG = 0x1c, @@ -89,7 +89,7 @@ enum agilent_82350b_gpib_registers enum card_mode_bits { - ACTIVE_CONTROLLER_BIT = 0x2, // read-only + ACTIVE_CONTROLLER_BIT = 0x2, /* read-only */ CM_SYSTEM_CONTROLLER_BIT = 0x8, ENABLE_BUS_MONITOR_BIT = 0x10, ENABLE_PCI_IRQ_BIT = 0x20, @@ -115,15 +115,15 @@ enum event_status_bits { TMS9914_IRQ_STATUS_BIT = 0x1, IRQ_STATUS_BIT = 0x2, - BUFFER_END_STATUS_BIT = 0x10, // write-clear - TERM_COUNT_STATUS_BIT = 0x20, // write-clear + BUFFER_END_STATUS_BIT = 0x10, /* write-clear */ + TERM_COUNT_STATUS_BIT = 0x20, /* write-clear */ }; enum stream_status_bits { - HALTED_STATUS_BIT = 0x1, //read - RESTART_STREAM_BIT = 0x1, //write + HALTED_STATUS_BIT = 0x1, /* read */ + RESTART_STREAM_BIT = 0x1, /* write */ }; enum internal_config_bits @@ -135,9 +135,9 @@ enum internal_config_bits enum sram_access_control_bits { - DIRECTION_GPIB_TO_HOST = 0x20, // transfer direction - ENABLE_TI_TO_SRAM = 0x40, // enable fifo - ENABLE_FAST_TALKER = 0x80 // added for 82350A (not used) + DIRECTION_GPIB_TO_HOST = 0x20, /* transfer direction */ + ENABLE_TI_TO_SRAM = 0x40, /* enable fifo */ + ENABLE_FAST_TALKER = 0x80 /* added for 82350A (not used) */ }; enum borg_bits diff --git a/drivers/staging/gpib/agilent_82357a/agilent_82357a.c b/drivers/staging/gpib/agilent_82357a/agilent_82357a.c index da229965d98e..b923dc606d1d 100644 --- a/drivers/staging/gpib/agilent_82357a/agilent_82357a.c +++ b/drivers/staging/gpib/agilent_82357a/agilent_82357a.c @@ -26,7 +26,7 @@ static struct usb_interface *agilent_82357a_driver_interfaces[MAX_NUM_82357A_INT static DEFINE_MUTEX(agilent_82357a_hotplug_lock); // protect board insertion and removal static unsigned int agilent_82357a_update_status(struct gpib_board *board, - unsigned int clear_mask); + unsigned int clear_mask); static int agilent_82357a_take_control_internal(struct gpib_board *board, int synchronous); @@ -34,16 +34,17 @@ static void agilent_82357a_bulk_complete(struct urb *urb) { struct agilent_82357a_urb_ctx *context = urb->context; - up(&context->complete); + complete(&context->complete); } static void agilent_82357a_timeout_handler(struct timer_list *t) { - struct agilent_82357a_priv *a_priv = from_timer(a_priv, t, bulk_timer); + struct agilent_82357a_priv *a_priv = timer_container_of(a_priv, t, + bulk_timer); struct agilent_82357a_urb_ctx *context = &a_priv->context; context->timed_out = 1; - up(&context->complete); + complete(&context->complete); } static int agilent_82357a_send_bulk_msg(struct agilent_82357a_priv *a_priv, void *data, @@ -74,7 +75,7 @@ static int agilent_82357a_send_bulk_msg(struct agilent_82357a_priv *a_priv, void } usb_dev = interface_to_usbdev(a_priv->bus_interface); out_pipe = usb_sndbulkpipe(usb_dev, a_priv->bulk_out_endpoint); - sema_init(&context->complete, 0); + init_completion(&context->complete); context->timed_out = 0; usb_fill_bulk_urb(a_priv->bulk_urb, usb_dev, out_pipe, data, data_length, &agilent_82357a_bulk_complete, context); @@ -89,7 +90,7 @@ static int agilent_82357a_send_bulk_msg(struct agilent_82357a_priv *a_priv, void goto cleanup; } mutex_unlock(&a_priv->bulk_alloc_lock); - if (down_interruptible(&context->complete)) { + if (wait_for_completion_interruptible(&context->complete)) { retval = -ERESTARTSYS; goto cleanup; } @@ -142,7 +143,7 @@ static int agilent_82357a_receive_bulk_msg(struct agilent_82357a_priv *a_priv, v } usb_dev = interface_to_usbdev(a_priv->bus_interface); in_pipe = usb_rcvbulkpipe(usb_dev, AGILENT_82357_BULK_IN_ENDPOINT); - sema_init(&context->complete, 0); + init_completion(&context->complete); context->timed_out = 0; usb_fill_bulk_urb(a_priv->bulk_urb, usb_dev, in_pipe, data, data_length, &agilent_82357a_bulk_complete, context); @@ -157,7 +158,7 @@ static int agilent_82357a_receive_bulk_msg(struct agilent_82357a_priv *a_priv, v goto cleanup; } mutex_unlock(&a_priv->bulk_alloc_lock); - if (down_interruptible(&context->complete)) { + if (wait_for_completion_interruptible(&context->complete)) { retval = -ERESTARTSYS; goto cleanup; } @@ -420,10 +421,10 @@ cleanup: } // interface functions -int agilent_82357a_command(struct gpib_board *board, uint8_t *buffer, size_t length, +int agilent_82357a_command(struct gpib_board *board, u8 *buffer, size_t length, size_t *bytes_written); -static int agilent_82357a_read(struct gpib_board *board, uint8_t *buffer, size_t length, int *end, +static int agilent_82357a_read(struct gpib_board *board, u8 *buffer, size_t length, int *end, size_t *nbytes) { int retval; @@ -524,9 +525,10 @@ static int agilent_82357a_read(struct gpib_board *board, uint8_t *buffer, size_t } kfree(in_data); - /* Fix for a bug in 9914A that does not return the contents of ADSR - * when the board is in listener active state and ATN is not asserted. - * Set ATN here to obtain a valid board level ibsta + /* + * Fix for a bug in 9914A that does not return the contents of ADSR + * when the board is in listener active state and ATN is not asserted. + * Set ATN here to obtain a valid board level ibsta */ agilent_82357a_take_control_internal(board, 0); @@ -535,7 +537,7 @@ static int agilent_82357a_read(struct gpib_board *board, uint8_t *buffer, size_t } static ssize_t agilent_82357a_generic_write(struct gpib_board *board, - uint8_t *buffer, size_t length, + u8 *buffer, size_t length, int send_commands, int send_eoi, size_t *bytes_written) { @@ -675,13 +677,13 @@ static ssize_t agilent_82357a_generic_write(struct gpib_board *board, return 0; } -static int agilent_82357a_write(struct gpib_board *board, uint8_t *buffer, +static int agilent_82357a_write(struct gpib_board *board, u8 *buffer, size_t length, int send_eoi, size_t *bytes_written) { return agilent_82357a_generic_write(board, buffer, length, 0, send_eoi, bytes_written); } -int agilent_82357a_command(struct gpib_board *board, uint8_t *buffer, size_t length, +int agilent_82357a_command(struct gpib_board *board, u8 *buffer, size_t length, size_t *bytes_written) { return agilent_82357a_generic_write(board, buffer, length, 1, 0, bytes_written); @@ -715,9 +717,10 @@ static int agilent_82357a_take_control(struct gpib_board *board, int synchronous if (!a_priv->bus_interface) return -ENODEV; -/* It looks like the 9914 does not handle tcs properly. - * See comment above tms9914_take_control_workaround() in - * drivers/gpib/tms9914/tms9914_aux.c +/* + * It looks like the 9914 does not handle tcs properly. + * See comment above tms9914_take_control_workaround() in + * drivers/gpib/tms9914/tms9914_aux.c */ if (synchronous) return -ETIMEDOUT; @@ -754,9 +757,7 @@ static int agilent_82357a_go_to_standby(struct gpib_board *board) return 0; } -//FIXME should change prototype to return int -static void agilent_82357a_request_system_control(struct gpib_board *board, - int request_control) +static int agilent_82357a_request_system_control(struct gpib_board *board, int request_control) { struct agilent_82357a_priv *a_priv = board->private_data; struct usb_device *usb_dev; @@ -765,7 +766,7 @@ static void agilent_82357a_request_system_control(struct gpib_board *board, int i = 0; if (!a_priv->bus_interface) - return; // -ENODEV; + return -ENODEV; usb_dev = interface_to_usbdev(a_priv->bus_interface); /* 82357B needs bit to be set in 9914 AUXCR register */ @@ -774,9 +775,7 @@ static void agilent_82357a_request_system_control(struct gpib_board *board, writes[i].value = AUX_RQC; a_priv->hw_control_bits |= SYSTEM_CONTROLLER; } else { - writes[i].value = AUX_RLC; - a_priv->is_cic = 0; - a_priv->hw_control_bits &= ~SYSTEM_CONTROLLER; + return -EINVAL; } ++i; writes[i].address = HW_CONTROL; @@ -785,7 +784,7 @@ static void agilent_82357a_request_system_control(struct gpib_board *board, retval = agilent_82357a_write_registers(a_priv, writes, i); if (retval) dev_err(&usb_dev->dev, "write_registers() returned error\n"); - return;// retval; + return retval; } static void agilent_82357a_interface_clear(struct gpib_board *board, int assert) @@ -832,7 +831,7 @@ static void agilent_82357a_remote_enable(struct gpib_board *board, int enable) return;// 0; } -static int agilent_82357a_enable_eos(struct gpib_board *board, uint8_t eos_byte, +static int agilent_82357a_enable_eos(struct gpib_board *board, u8 eos_byte, int compare_8_bits) { struct agilent_82357a_priv *a_priv = board->private_data; @@ -946,7 +945,7 @@ static int agilent_82357a_secondary_address(struct gpib_board *board, return 0; } -static int agilent_82357a_parallel_poll(struct gpib_board *board, uint8_t *result) +static int agilent_82357a_parallel_poll(struct gpib_board *board, u8 *result) { struct agilent_82357a_priv *a_priv = board->private_data; struct usb_device *usb_dev; @@ -988,7 +987,7 @@ static int agilent_82357a_parallel_poll(struct gpib_board *board, uint8_t *resul return 0; } -static void agilent_82357a_parallel_poll_configure(struct gpib_board *board, uint8_t config) +static void agilent_82357a_parallel_poll_configure(struct gpib_board *board, u8 config) { //board can only be system controller return;// 0; @@ -1000,13 +999,13 @@ static void agilent_82357a_parallel_poll_response(struct gpib_board *board, int return;// 0; } -static void agilent_82357a_serial_poll_response(struct gpib_board *board, uint8_t status) +static void agilent_82357a_serial_poll_response(struct gpib_board *board, u8 status) { //board can only be system controller return;// 0; } -static uint8_t agilent_82357a_serial_poll_status(struct gpib_board *board) +static u8 agilent_82357a_serial_poll_status(struct gpib_board *board) { //board can only be system controller return 0; @@ -1292,7 +1291,7 @@ static int agilent_82357a_init(struct gpib_board *board) } static inline int agilent_82357a_device_match(struct usb_interface *interface, - const gpib_board_config_t *config) + const struct gpib_board_config *config) { struct usb_device * const usbdev = interface_to_usbdev(interface); @@ -1305,7 +1304,7 @@ static inline int agilent_82357a_device_match(struct usb_interface *interface, return 1; } -static int agilent_82357a_attach(struct gpib_board *board, const gpib_board_config_t *config) +static int agilent_82357a_attach(struct gpib_board *board, const struct gpib_board_config *config) { int retval; int i; @@ -1432,7 +1431,7 @@ static void agilent_82357a_detach(struct gpib_board *board) mutex_unlock(&agilent_82357a_hotplug_lock); } -static gpib_interface_t agilent_82357a_gpib_interface = { +static struct gpib_interface agilent_82357a_gpib_interface = { .name = "agilent_82357a", .attach = agilent_82357a_attach, .detach = agilent_82357a_detach, @@ -1591,7 +1590,7 @@ static int agilent_82357a_driver_resume(struct usb_interface *interface) { struct usb_device *usb_dev = interface_to_usbdev(interface); struct gpib_board *board; - int i, retval; + int i, retval = 0; mutex_lock(&agilent_82357a_hotplug_lock); @@ -1602,8 +1601,10 @@ static int agilent_82357a_driver_resume(struct usb_interface *interface) break; } } - if (i == MAX_NUM_82357A_INTERFACES) + if (i == MAX_NUM_82357A_INTERFACES) { + retval = -ENOENT; goto resume_exit; + } struct agilent_82357a_priv *a_priv = board->private_data; @@ -1626,7 +1627,7 @@ static int agilent_82357a_driver_resume(struct usb_interface *interface) return retval; } // set/unset system controller - agilent_82357a_request_system_control(board, board->master); + retval = agilent_82357a_request_system_control(board, board->master); // toggle ifc if master if (board->master) { agilent_82357a_interface_clear(board, 1); @@ -1644,7 +1645,7 @@ static int agilent_82357a_driver_resume(struct usb_interface *interface) resume_exit: mutex_unlock(&agilent_82357a_hotplug_lock); - return 0; + return retval; } static struct usb_driver agilent_82357a_bus_driver = { diff --git a/drivers/staging/gpib/agilent_82357a/agilent_82357a.h b/drivers/staging/gpib/agilent_82357a/agilent_82357a.h index cdbc3ec5d8bd..23aa4799eb86 100644 --- a/drivers/staging/gpib/agilent_82357a/agilent_82357a.h +++ b/drivers/staging/gpib/agilent_82357a/agilent_82357a.h @@ -6,7 +6,7 @@ #include <linux/kernel.h> #include <linux/mutex.h> -#include <linux/semaphore.h> +#include <linux/completion.h> #include <linux/usb.h> #include <linux/timer.h> #include <linux/compiler_attributes.h> @@ -115,7 +115,7 @@ enum xfer_abort_type { #define INTERRUPT_BUF_LEN 8 struct agilent_82357a_urb_ctx { - struct semaphore complete; + struct completion complete; unsigned timed_out : 1; }; diff --git a/drivers/staging/gpib/cb7210/cb7210.c b/drivers/staging/gpib/cb7210/cb7210.c index 6b22a33a8c4f..298ed306189d 100644 --- a/drivers/staging/gpib/cb7210/cb7210.c +++ b/drivers/staging/gpib/cb7210/cb7210.c @@ -27,7 +27,7 @@ MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("GPIB driver Measurement Computing boards using cb7210.2 and cbi488.2"); -static int cb7210_read(struct gpib_board *board, uint8_t *buffer, size_t length, +static int cb7210_read(struct gpib_board *board, u8 *buffer, size_t length, int *end, size_t *bytes_read); static inline int have_fifo_word(const struct cb7210_priv *cb_priv) @@ -76,7 +76,7 @@ static inline void input_fifo_enable(struct gpib_board *board, int enable) spin_unlock_irqrestore(&board->spinlock, flags); } -static int fifo_read(struct gpib_board *board, struct cb7210_priv *cb_priv, uint8_t *buffer, +static int fifo_read(struct gpib_board *board, struct cb7210_priv *cb_priv, u8 *buffer, size_t length, int *end, size_t *bytes_read) { ssize_t retval = 0; @@ -170,7 +170,7 @@ static int fifo_read(struct gpib_board *board, struct cb7210_priv *cb_priv, uint return retval; } -static int cb7210_accel_read(struct gpib_board *board, uint8_t *buffer, +static int cb7210_accel_read(struct gpib_board *board, u8 *buffer, size_t length, int *end, size_t *bytes_read) { ssize_t retval; @@ -264,7 +264,7 @@ static inline void output_fifo_enable(struct gpib_board *board, int enable) spin_unlock_irqrestore(&board->spinlock, flags); } -static int fifo_write(struct gpib_board *board, uint8_t *buffer, size_t length, +static int fifo_write(struct gpib_board *board, u8 *buffer, size_t length, size_t *bytes_written) { size_t count = 0; @@ -350,7 +350,7 @@ static int fifo_write(struct gpib_board *board, uint8_t *buffer, size_t length, return retval; } -static int cb7210_accel_write(struct gpib_board *board, uint8_t *buffer, +static int cb7210_accel_write(struct gpib_board *board, u8 *buffer, size_t length, int send_eoi, size_t *bytes_written) { struct cb7210_priv *cb_priv = board->private_data; @@ -533,14 +533,14 @@ static irqreturn_t cb7210_interrupt(int irq, void *arg) return cb7210_internal_interrupt(arg); } -static int cb_pci_attach(struct gpib_board *board, const gpib_board_config_t *config); -static int cb_isa_attach(struct gpib_board *board, const gpib_board_config_t *config); +static int cb_pci_attach(struct gpib_board *board, const struct gpib_board_config *config); +static int cb_isa_attach(struct gpib_board *board, const struct gpib_board_config *config); static void cb_pci_detach(struct gpib_board *board); static void cb_isa_detach(struct gpib_board *board); // wrappers for interface functions -static int cb7210_read(struct gpib_board *board, uint8_t *buffer, size_t length, +static int cb7210_read(struct gpib_board *board, u8 *buffer, size_t length, int *end, size_t *bytes_read) { struct cb7210_priv *priv = board->private_data; @@ -548,7 +548,7 @@ static int cb7210_read(struct gpib_board *board, uint8_t *buffer, size_t length, return nec7210_read(board, &priv->nec7210_priv, buffer, length, end, bytes_read); } -static int cb7210_write(struct gpib_board *board, uint8_t *buffer, size_t length, +static int cb7210_write(struct gpib_board *board, u8 *buffer, size_t length, int send_eoi, size_t *bytes_written) { struct cb7210_priv *priv = board->private_data; @@ -556,7 +556,7 @@ static int cb7210_write(struct gpib_board *board, uint8_t *buffer, size_t length return nec7210_write(board, &priv->nec7210_priv, buffer, length, send_eoi, bytes_written); } -static int cb7210_command(struct gpib_board *board, uint8_t *buffer, size_t length, +static int cb7210_command(struct gpib_board *board, u8 *buffer, size_t length, size_t *bytes_written) { struct cb7210_priv *priv = board->private_data; @@ -578,7 +578,7 @@ static int cb7210_go_to_standby(struct gpib_board *board) return nec7210_go_to_standby(board, &priv->nec7210_priv); } -static void cb7210_request_system_control(struct gpib_board *board, int request_control) +static int cb7210_request_system_control(struct gpib_board *board, int request_control) { struct cb7210_priv *priv = board->private_data; struct nec7210_priv *nec_priv = &priv->nec7210_priv; @@ -589,7 +589,7 @@ static void cb7210_request_system_control(struct gpib_board *board, int request_ priv->hs_mode_bits &= ~HS_SYS_CONTROL; cb7210_write_byte(priv, priv->hs_mode_bits, HS_MODE); - nec7210_request_system_control(board, nec_priv, request_control); + return nec7210_request_system_control(board, nec_priv, request_control); } static void cb7210_interface_clear(struct gpib_board *board, int assert) @@ -606,7 +606,7 @@ static void cb7210_remote_enable(struct gpib_board *board, int enable) nec7210_remote_enable(board, &priv->nec7210_priv, enable); } -static int cb7210_enable_eos(struct gpib_board *board, uint8_t eos_byte, int compare_8_bits) +static int cb7210_enable_eos(struct gpib_board *board, u8 eos_byte, int compare_8_bits) { struct cb7210_priv *priv = board->private_data; @@ -641,14 +641,14 @@ static int cb7210_secondary_address(struct gpib_board *board, unsigned int addre return nec7210_secondary_address(board, &priv->nec7210_priv, address, enable); } -static int cb7210_parallel_poll(struct gpib_board *board, uint8_t *result) +static int cb7210_parallel_poll(struct gpib_board *board, u8 *result) { struct cb7210_priv *priv = board->private_data; return nec7210_parallel_poll(board, &priv->nec7210_priv, result); } -static void cb7210_parallel_poll_configure(struct gpib_board *board, uint8_t configuration) +static void cb7210_parallel_poll_configure(struct gpib_board *board, u8 configuration) { struct cb7210_priv *priv = board->private_data; @@ -662,14 +662,14 @@ static void cb7210_parallel_poll_response(struct gpib_board *board, int ist) nec7210_parallel_poll_response(board, &priv->nec7210_priv, ist); } -static void cb7210_serial_poll_response(struct gpib_board *board, uint8_t status) +static void cb7210_serial_poll_response(struct gpib_board *board, u8 status) { struct cb7210_priv *priv = board->private_data; nec7210_serial_poll_response(board, &priv->nec7210_priv, status); } -static uint8_t cb7210_serial_poll_status(struct gpib_board *board) +static u8 cb7210_serial_poll_status(struct gpib_board *board) { struct cb7210_priv *priv = board->private_data; @@ -686,7 +686,7 @@ static void cb7210_return_to_local(struct gpib_board *board) write_byte(nec_priv, AUX_RTL, AUXMR); } -static gpib_interface_t cb_pci_unaccel_interface = { +static struct gpib_interface cb_pci_unaccel_interface = { .name = "cbi_pci_unaccel", .attach = cb_pci_attach, .detach = cb_pci_detach, @@ -714,7 +714,7 @@ static gpib_interface_t cb_pci_unaccel_interface = { .return_to_local = cb7210_return_to_local, }; -static gpib_interface_t cb_pci_accel_interface = { +static struct gpib_interface cb_pci_accel_interface = { .name = "cbi_pci_accel", .attach = cb_pci_attach, .detach = cb_pci_detach, @@ -742,7 +742,7 @@ static gpib_interface_t cb_pci_accel_interface = { .return_to_local = cb7210_return_to_local, }; -static gpib_interface_t cb_pci_interface = { +static struct gpib_interface cb_pci_interface = { .name = "cbi_pci", .attach = cb_pci_attach, .detach = cb_pci_detach, @@ -769,7 +769,7 @@ static gpib_interface_t cb_pci_interface = { .return_to_local = cb7210_return_to_local, }; -static gpib_interface_t cb_isa_unaccel_interface = { +static struct gpib_interface cb_isa_unaccel_interface = { .name = "cbi_isa_unaccel", .attach = cb_isa_attach, .detach = cb_isa_detach, @@ -797,7 +797,7 @@ static gpib_interface_t cb_isa_unaccel_interface = { .return_to_local = cb7210_return_to_local, }; -static gpib_interface_t cb_isa_interface = { +static struct gpib_interface cb_isa_interface = { .name = "cbi_isa", .attach = cb_isa_attach, .detach = cb_isa_detach, @@ -824,7 +824,7 @@ static gpib_interface_t cb_isa_interface = { .return_to_local = cb7210_return_to_local, }; -static gpib_interface_t cb_isa_accel_interface = { +static struct gpib_interface cb_isa_accel_interface = { .name = "cbi_isa_accel", .attach = cb_isa_attach, .detach = cb_isa_detach, @@ -905,7 +905,8 @@ static int cb7210_init(struct cb7210_priv *cb_priv, struct gpib_board *board) cb7210_write_byte(cb_priv, cb_priv->hs_mode_bits, HS_MODE); write_byte(nec_priv, AUX_LO_SPEED, AUXMR); - /* set clock register for maximum (20 MHz) driving frequency + /* + * set clock register for maximum (20 MHz) driving frequency * ICR should be set to clock in megahertz (1-15) and to zero * for clocks faster than 15 MHz (max 20MHz) */ @@ -926,7 +927,7 @@ static int cb7210_init(struct cb7210_priv *cb_priv, struct gpib_board *board) return 0; } -static int cb_pci_attach(struct gpib_board *board, const gpib_board_config_t *config) +static int cb_pci_attach(struct gpib_board *board, const struct gpib_board_config *config) { struct cb7210_priv *cb_priv; struct nec7210_priv *nec_priv; @@ -1031,7 +1032,7 @@ static void cb_pci_detach(struct gpib_board *board) cb7210_generic_detach(board); } -static int cb_isa_attach(struct gpib_board *board, const gpib_board_config_t *config) +static int cb_isa_attach(struct gpib_board *board, const struct gpib_board_config *config) { int isr_flags = 0; struct cb7210_priv *cb_priv; @@ -1133,7 +1134,7 @@ static struct pci_driver cb7210_pci_driver = { static int cb_gpib_config(struct pcmcia_device *link); static void cb_gpib_release(struct pcmcia_device *link); -static int cb_pcmcia_attach(struct gpib_board *board, const gpib_board_config_t *config); +static int cb_pcmcia_attach(struct gpib_board *board, const struct gpib_board_config *config); static void cb_pcmcia_detach(struct gpib_board *board); /* @@ -1246,13 +1247,8 @@ static int cb_gpib_config_iteration(struct pcmcia_device *link, void *priv_data) static int cb_gpib_config(struct pcmcia_device *link) { - struct pcmcia_device *handle; - struct local_info *dev; int retval; - handle = link; - dev = link->priv; - retval = pcmcia_loop_config(link, &cb_gpib_config_iteration, NULL); if (retval) { dev_warn(&link->dev, "no configuration found\n"); @@ -1275,9 +1271,9 @@ static int cb_gpib_config(struct pcmcia_device *link) } /* gpib_config */ /* - * After a card is removed, gpib_release() will unregister the net - * device, and release the PCMCIA configuration. If the device is - * still open, this will be postponed until it is closed. + * After a card is removed, gpib_release() will unregister the net + * device, and release the PCMCIA configuration. If the device is + * still open, this will be postponed until it is closed. */ static void cb_gpib_release(struct pcmcia_device *link) @@ -1333,7 +1329,7 @@ static void cb_pcmcia_cleanup_module(void) pcmcia_unregister_driver(&cb_gpib_cs_driver); } -static gpib_interface_t cb_pcmcia_unaccel_interface = { +static struct gpib_interface cb_pcmcia_unaccel_interface = { .name = "cbi_pcmcia_unaccel", .attach = cb_pcmcia_attach, .detach = cb_pcmcia_detach, @@ -1361,7 +1357,7 @@ static gpib_interface_t cb_pcmcia_unaccel_interface = { .return_to_local = cb7210_return_to_local, }; -static gpib_interface_t cb_pcmcia_interface = { +static struct gpib_interface cb_pcmcia_interface = { .name = "cbi_pcmcia", .attach = cb_pcmcia_attach, .detach = cb_pcmcia_detach, @@ -1389,7 +1385,7 @@ static gpib_interface_t cb_pcmcia_interface = { .return_to_local = cb7210_return_to_local, }; -static gpib_interface_t cb_pcmcia_accel_interface = { +static struct gpib_interface cb_pcmcia_accel_interface = { .name = "cbi_pcmcia_accel", .attach = cb_pcmcia_attach, .detach = cb_pcmcia_detach, @@ -1417,7 +1413,7 @@ static gpib_interface_t cb_pcmcia_accel_interface = { .return_to_local = cb7210_return_to_local, }; -static int cb_pcmcia_attach(struct gpib_board *board, const gpib_board_config_t *config) +static int cb_pcmcia_attach(struct gpib_board *board, const struct gpib_board_config *config) { struct cb7210_priv *cb_priv; struct nec7210_priv *nec_priv; diff --git a/drivers/staging/gpib/cb7210/cb7210.h b/drivers/staging/gpib/cb7210/cb7210.h index 2108fe7a8ce5..13f127563ab3 100644 --- a/drivers/staging/gpib/cb7210/cb7210.h +++ b/drivers/staging/gpib/cb7210/cb7210.h @@ -73,8 +73,8 @@ static inline int cb7210_page_in_bits(unsigned int page) return 0x50 | (page & 0xf); } -static inline uint8_t cb7210_paged_read_byte(struct cb7210_priv *cb_priv, - unsigned int register_num, unsigned int page) +static inline u8 cb7210_paged_read_byte(struct cb7210_priv *cb_priv, + unsigned int register_num, unsigned int page) { struct nec7210_priv *nec_priv = &cb_priv->nec7210_priv; u8 retval; @@ -89,8 +89,8 @@ static inline uint8_t cb7210_paged_read_byte(struct cb7210_priv *cb_priv, } // don't use for register_num < 8, since it doesn't lock -static inline uint8_t cb7210_read_byte(const struct cb7210_priv *cb_priv, - enum hs_regs register_num) +static inline u8 cb7210_read_byte(const struct cb7210_priv *cb_priv, + enum hs_regs register_num) { const struct nec7210_priv *nec_priv = &cb_priv->nec7210_priv; u8 retval; @@ -99,7 +99,7 @@ static inline uint8_t cb7210_read_byte(const struct cb7210_priv *cb_priv, return retval; } -static inline void cb7210_paged_write_byte(struct cb7210_priv *cb_priv, uint8_t data, +static inline void cb7210_paged_write_byte(struct cb7210_priv *cb_priv, u8 data, unsigned int register_num, unsigned int page) { struct nec7210_priv *nec_priv = &cb_priv->nec7210_priv; @@ -113,7 +113,7 @@ static inline void cb7210_paged_write_byte(struct cb7210_priv *cb_priv, uint8_t } // don't use for register_num < 8, since it doesn't lock -static inline void cb7210_write_byte(const struct cb7210_priv *cb_priv, uint8_t data, +static inline void cb7210_write_byte(const struct cb7210_priv *cb_priv, u8 data, enum hs_regs register_num) { const struct nec7210_priv *nec_priv = &cb_priv->nec7210_priv; @@ -134,7 +134,8 @@ enum bus_status_bits { /* CBI 488.2 HS control */ -/* when both bit 0 and 1 are set, it +/* + * when both bit 0 and 1 are set, it * 1 clears the transmit state machine to an initial condition * 2 clears any residual interrupts left latched on cbi488.2 * 3 resets all control bits in HS_MODE to zero @@ -189,11 +190,12 @@ static inline unsigned int irq_bits(unsigned int irq) } enum cb7210_aux_cmds { -/* AUX_RTL2 is an undocumented aux command which causes cb7210 to assert - * (and keep asserted) local rtl message. This is used in conjunction - * with the (stupid) cb7210 implementation - * of the normal nec7210 AUX_RTL aux command, which - * causes the rtl message to toggle between on and off. +/* + * AUX_RTL2 is an undocumented aux command which causes cb7210 to assert + * (and keep asserted) local rtl message. This is used in conjunction + * with the (stupid) cb7210 implementation + * of the normal nec7210 AUX_RTL aux command, which + * causes the rtl message to toggle between on and off. */ AUX_RTL2 = 0xd, AUX_LO_SPEED = 0x40, diff --git a/drivers/staging/gpib/cec/cec_gpib.c b/drivers/staging/gpib/cec/cec_gpib.c index a822fa428cd0..e8736cbf50e3 100644 --- a/drivers/staging/gpib/cec/cec_gpib.c +++ b/drivers/staging/gpib/cec/cec_gpib.c @@ -40,12 +40,12 @@ static irqreturn_t cec_interrupt(int irq, void *arg) #define CEC_DEV_ID 0x5cec #define CEC_SUBID 0x9050 -static int cec_pci_attach(struct gpib_board *board, const gpib_board_config_t *config); +static int cec_pci_attach(struct gpib_board *board, const struct gpib_board_config *config); static void cec_pci_detach(struct gpib_board *board); // wrappers for interface functions -static int cec_read(struct gpib_board *board, uint8_t *buffer, size_t length, int *end, +static int cec_read(struct gpib_board *board, u8 *buffer, size_t length, int *end, size_t *bytes_read) { struct cec_priv *priv = board->private_data; @@ -53,7 +53,7 @@ static int cec_read(struct gpib_board *board, uint8_t *buffer, size_t length, in return nec7210_read(board, &priv->nec7210_priv, buffer, length, end, bytes_read); } -static int cec_write(struct gpib_board *board, uint8_t *buffer, size_t length, int send_eoi, +static int cec_write(struct gpib_board *board, u8 *buffer, size_t length, int send_eoi, size_t *bytes_written) { struct cec_priv *priv = board->private_data; @@ -61,7 +61,7 @@ static int cec_write(struct gpib_board *board, uint8_t *buffer, size_t length, i return nec7210_write(board, &priv->nec7210_priv, buffer, length, send_eoi, bytes_written); } -static int cec_command(struct gpib_board *board, uint8_t *buffer, +static int cec_command(struct gpib_board *board, u8 *buffer, size_t length, size_t *bytes_written) { struct cec_priv *priv = board->private_data; @@ -83,11 +83,11 @@ static int cec_go_to_standby(struct gpib_board *board) return nec7210_go_to_standby(board, &priv->nec7210_priv); } -static void cec_request_system_control(struct gpib_board *board, int request_control) +static int cec_request_system_control(struct gpib_board *board, int request_control) { struct cec_priv *priv = board->private_data; - nec7210_request_system_control(board, &priv->nec7210_priv, request_control); + return nec7210_request_system_control(board, &priv->nec7210_priv, request_control); } static void cec_interface_clear(struct gpib_board *board, int assert) @@ -104,7 +104,7 @@ static void cec_remote_enable(struct gpib_board *board, int enable) nec7210_remote_enable(board, &priv->nec7210_priv, enable); } -static int cec_enable_eos(struct gpib_board *board, uint8_t eos_byte, int compare_8_bits) +static int cec_enable_eos(struct gpib_board *board, u8 eos_byte, int compare_8_bits) { struct cec_priv *priv = board->private_data; @@ -139,14 +139,14 @@ static int cec_secondary_address(struct gpib_board *board, unsigned int address, return nec7210_secondary_address(board, &priv->nec7210_priv, address, enable); } -static int cec_parallel_poll(struct gpib_board *board, uint8_t *result) +static int cec_parallel_poll(struct gpib_board *board, u8 *result) { struct cec_priv *priv = board->private_data; return nec7210_parallel_poll(board, &priv->nec7210_priv, result); } -static void cec_parallel_poll_configure(struct gpib_board *board, uint8_t config) +static void cec_parallel_poll_configure(struct gpib_board *board, u8 config) { struct cec_priv *priv = board->private_data; @@ -160,14 +160,14 @@ static void cec_parallel_poll_response(struct gpib_board *board, int ist) nec7210_parallel_poll_response(board, &priv->nec7210_priv, ist); } -static void cec_serial_poll_response(struct gpib_board *board, uint8_t status) +static void cec_serial_poll_response(struct gpib_board *board, u8 status) { struct cec_priv *priv = board->private_data; nec7210_serial_poll_response(board, &priv->nec7210_priv, status); } -static uint8_t cec_serial_poll_status(struct gpib_board *board) +static u8 cec_serial_poll_status(struct gpib_board *board) { struct cec_priv *priv = board->private_data; @@ -188,7 +188,7 @@ static void cec_return_to_local(struct gpib_board *board) nec7210_return_to_local(board, &priv->nec7210_priv); } -static gpib_interface_t cec_pci_interface = { +static struct gpib_interface cec_pci_interface = { .name = "cec_pci", .attach = cec_pci_attach, .detach = cec_pci_detach, @@ -265,7 +265,7 @@ static void cec_init(struct cec_priv *cec_priv, const struct gpib_board *board) nec7210_board_online(nec_priv, board); } -static int cec_pci_attach(struct gpib_board *board, const gpib_board_config_t *config) +static int cec_pci_attach(struct gpib_board *board, const struct gpib_board_config *config) { struct cec_priv *cec_priv; struct nec7210_priv *nec_priv; diff --git a/drivers/staging/gpib/common/gpib_os.c b/drivers/staging/gpib/common/gpib_os.c index 8456b97290b8..a193d64db033 100644 --- a/drivers/staging/gpib/common/gpib_os.c +++ b/drivers/staging/gpib/common/gpib_os.c @@ -26,35 +26,37 @@ MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("GPIB base support"); MODULE_ALIAS_CHARDEV_MAJOR(GPIB_CODE); -static int board_type_ioctl(gpib_file_private_t *file_priv, struct gpib_board *board, unsigned long arg); -static int read_ioctl(gpib_file_private_t *file_priv, struct gpib_board *board, +static int board_type_ioctl(struct gpib_file_private *file_priv, + struct gpib_board *board, unsigned long arg); +static int read_ioctl(struct gpib_file_private *file_priv, struct gpib_board *board, unsigned long arg); -static int write_ioctl(gpib_file_private_t *file_priv, struct gpib_board *board, +static int write_ioctl(struct gpib_file_private *file_priv, struct gpib_board *board, unsigned long arg); -static int command_ioctl(gpib_file_private_t *file_priv, struct gpib_board *board, +static int command_ioctl(struct gpib_file_private *file_priv, struct gpib_board *board, unsigned long arg); static int open_dev_ioctl(struct file *filep, struct gpib_board *board, unsigned long arg); static int close_dev_ioctl(struct file *filep, struct gpib_board *board, unsigned long arg); static int serial_poll_ioctl(struct gpib_board *board, unsigned long arg); -static int wait_ioctl(gpib_file_private_t *file_priv, struct gpib_board *board, unsigned long arg); +static int wait_ioctl(struct gpib_file_private *file_priv, + struct gpib_board *board, unsigned long arg); static int parallel_poll_ioctl(struct gpib_board *board, unsigned long arg); static int online_ioctl(struct gpib_board *board, unsigned long arg); static int remote_enable_ioctl(struct gpib_board *board, unsigned long arg); static int take_control_ioctl(struct gpib_board *board, unsigned long arg); static int line_status_ioctl(struct gpib_board *board, unsigned long arg); -static int pad_ioctl(struct gpib_board *board, gpib_file_private_t *file_priv, +static int pad_ioctl(struct gpib_board *board, struct gpib_file_private *file_priv, unsigned long arg); -static int sad_ioctl(struct gpib_board *board, gpib_file_private_t *file_priv, +static int sad_ioctl(struct gpib_board *board, struct gpib_file_private *file_priv, unsigned long arg); static int eos_ioctl(struct gpib_board *board, unsigned long arg); static int request_service_ioctl(struct gpib_board *board, unsigned long arg); static int request_service2_ioctl(struct gpib_board *board, unsigned long arg); -static int iobase_ioctl(gpib_board_config_t *config, unsigned long arg); -static int irq_ioctl(gpib_board_config_t *config, unsigned long arg); -static int dma_ioctl(gpib_board_config_t *config, unsigned long arg); -static int autospoll_ioctl(struct gpib_board *board, gpib_file_private_t *file_priv, +static int iobase_ioctl(struct gpib_board_config *config, unsigned long arg); +static int irq_ioctl(struct gpib_board_config *config, unsigned long arg); +static int dma_ioctl(struct gpib_board_config *config, unsigned long arg); +static int autospoll_ioctl(struct gpib_board *board, struct gpib_file_private *file_priv, unsigned long arg); -static int mutex_ioctl(struct gpib_board *board, gpib_file_private_t *file_priv, +static int mutex_ioctl(struct gpib_board *board, struct gpib_file_private *file_priv, unsigned long arg); static int timeout_ioctl(struct gpib_board *board, unsigned long arg); static int status_bytes_ioctl(struct gpib_board *board, unsigned long arg); @@ -64,15 +66,16 @@ static int set_local_ppoll_mode_ioctl(struct gpib_board *board, unsigned long ar static int get_local_ppoll_mode_ioctl(struct gpib_board *board, unsigned long arg); static int query_board_rsv_ioctl(struct gpib_board *board, unsigned long arg); static int interface_clear_ioctl(struct gpib_board *board, unsigned long arg); -static int select_pci_ioctl(gpib_board_config_t *config, unsigned long arg); -static int select_device_path_ioctl(gpib_board_config_t *config, unsigned long arg); +static int select_pci_ioctl(struct gpib_board_config *config, unsigned long arg); +static int select_device_path_ioctl(struct gpib_board_config *config, unsigned long arg); static int event_ioctl(struct gpib_board *board, unsigned long arg); static int request_system_control_ioctl(struct gpib_board *board, unsigned long arg); static int t1_delay_ioctl(struct gpib_board *board, unsigned long arg); -static int cleanup_open_devices(gpib_file_private_t *file_priv, struct gpib_board *board); +static int cleanup_open_devices(struct gpib_file_private *file_priv, struct gpib_board *board); -static int pop_gpib_event_nolock(struct gpib_board *board, gpib_event_queue_t *queue, short *event_type); +static int pop_gpib_event_nolock(struct gpib_board *board, + struct gpib_event_queue *queue, short *event_type); /* * Timer functions @@ -82,7 +85,7 @@ static int pop_gpib_event_nolock(struct gpib_board *board, gpib_event_queue_t *q static void watchdog_timeout(struct timer_list *t) { - struct gpib_board *board = from_timer(board, t, timer); + struct gpib_board *board = timer_container_of(board, t, timer); set_bit(TIMO_NUM, &board->status); wake_up_interruptible(&board->wait); @@ -119,7 +122,8 @@ int io_timed_out(struct gpib_board *board) return 0; } -/* this is a function instead of a constant because of Suse +/* + * this is a function instead of a constant because of Suse * defining HZ to be a function call to get_hz() */ static inline int pseudo_irq_period(void) @@ -129,7 +133,8 @@ static inline int pseudo_irq_period(void) static void pseudo_irq_handler(struct timer_list *t) { - struct gpib_pseudo_irq *pseudo_irq = from_timer(pseudo_irq, t, timer); + struct gpib_pseudo_irq *pseudo_irq = timer_container_of(pseudo_irq, t, + timer); if (pseudo_irq->handler) pseudo_irq->handler(0, pseudo_irq->board); @@ -170,7 +175,7 @@ EXPORT_SYMBOL(gpib_free_pseudo_irq); static const unsigned int serial_timeout = 1000000; -unsigned int num_status_bytes(const gpib_status_queue_t *dev) +unsigned int num_status_bytes(const struct gpib_status_queue *dev) { if (!dev) return 0; @@ -178,10 +183,10 @@ unsigned int num_status_bytes(const gpib_status_queue_t *dev) } // push status byte onto back of status byte fifo -int push_status_byte(struct gpib_board *board, gpib_status_queue_t *device, u8 poll_byte) +int push_status_byte(struct gpib_board *board, struct gpib_status_queue *device, u8 poll_byte) { struct list_head *head = &device->status_bytes; - status_byte_t *status; + struct gpib_status_byte *status; static const unsigned int max_num_status_bytes = 1024; int retval; @@ -194,7 +199,7 @@ int push_status_byte(struct gpib_board *board, gpib_status_queue_t *device, u8 p return retval; } - status = kmalloc(sizeof(status_byte_t), GFP_KERNEL); + status = kmalloc(sizeof(*status), GFP_KERNEL); if (!status) return -ENOMEM; @@ -212,11 +217,11 @@ int push_status_byte(struct gpib_board *board, gpib_status_queue_t *device, u8 p } // pop status byte from front of status byte fifo -int pop_status_byte(struct gpib_board *board, gpib_status_queue_t *device, u8 *poll_byte) +int pop_status_byte(struct gpib_board *board, struct gpib_status_queue *device, u8 *poll_byte) { struct list_head *head = &device->status_bytes; struct list_head *front = head->next; - status_byte_t *status; + struct gpib_status_byte *status; if (num_status_bytes(device) == 0) return -EIO; @@ -229,7 +234,7 @@ int pop_status_byte(struct gpib_board *board, gpib_status_queue_t *device, u8 *p return -EPIPE; } - status = list_entry(front, status_byte_t, list); + status = list_entry(front, struct gpib_status_byte, list); *poll_byte = status->poll_byte; list_del(front); @@ -243,14 +248,14 @@ int pop_status_byte(struct gpib_board *board, gpib_status_queue_t *device, u8 *p return 0; } -gpib_status_queue_t *get_gpib_status_queue(struct gpib_board *board, unsigned int pad, int sad) +struct gpib_status_queue *get_gpib_status_queue(struct gpib_board *board, unsigned int pad, int sad) { - gpib_status_queue_t *device; + struct gpib_status_queue *device; struct list_head *list_ptr; const struct list_head *head = &board->device_list; for (list_ptr = head->next; list_ptr != head; list_ptr = list_ptr->next) { - device = list_entry(list_ptr, gpib_status_queue_t, list); + device = list_entry(list_ptr, struct gpib_status_queue, list); if (gpib_address_equal(device->pad, device->sad, pad, sad)) return device; } @@ -258,10 +263,10 @@ gpib_status_queue_t *get_gpib_status_queue(struct gpib_board *board, unsigned in return NULL; } -int get_serial_poll_byte(struct gpib_board *board, unsigned int pad, int sad, unsigned int usec_timeout, - uint8_t *poll_byte) +int get_serial_poll_byte(struct gpib_board *board, unsigned int pad, int sad, + unsigned int usec_timeout, u8 *poll_byte) { - gpib_status_queue_t *device; + struct gpib_status_queue *device; device = get_gpib_status_queue(board, pad, sad); if (num_status_bytes(device)) @@ -291,7 +296,8 @@ int autopoll_all_devices(struct gpib_board *board) } dev_dbg(board->gpib_dev, "complete\n"); - /* need to wake wait queue in case someone is + /* + * need to wake wait queue in case someone is * waiting on RQS */ wake_up_interruptible(&board->wait); @@ -334,7 +340,7 @@ static int setup_serial_poll(struct gpib_board *board, unsigned int usec_timeout } static int read_serial_poll_byte(struct gpib_board *board, unsigned int pad, - int sad, unsigned int usec_timeout, uint8_t *result) + int sad, unsigned int usec_timeout, u8 *result) { u8 cmd_string[8]; int end_flag; @@ -405,7 +411,7 @@ static int cleanup_serial_poll(struct gpib_board *board, unsigned int usec_timeo } static int serial_poll_single(struct gpib_board *board, unsigned int pad, int sad, - unsigned int usec_timeout, uint8_t *result) + unsigned int usec_timeout, u8 *result) { int retval, cleanup_retval; @@ -427,7 +433,7 @@ int serial_poll_all(struct gpib_board *board, unsigned int usec_timeout) int retval = 0; struct list_head *cur; const struct list_head *head = NULL; - gpib_status_queue_t *device; + struct gpib_status_queue *device; u8 result; unsigned int num_bytes = 0; @@ -440,7 +446,7 @@ int serial_poll_all(struct gpib_board *board, unsigned int usec_timeout) return retval; for (cur = head->next; cur != head; cur = cur->next) { - device = list_entry(cur, gpib_status_queue_t, list); + device = list_entry(cur, struct gpib_status_queue, list); retval = read_serial_poll_byte(board, device->pad, device->sad, usec_timeout, &result); if (retval < 0) @@ -470,7 +476,7 @@ int serial_poll_all(struct gpib_board *board, unsigned int usec_timeout) */ int dvrsp(struct gpib_board *board, unsigned int pad, int sad, - unsigned int usec_timeout, uint8_t *result) + unsigned int usec_timeout, u8 *result) { int status = ibstatus(board); int retval; @@ -492,8 +498,8 @@ int dvrsp(struct gpib_board *board, unsigned int pad, int sad, return retval; } -static gpib_descriptor_t *handle_to_descriptor(const gpib_file_private_t *file_priv, - int handle) +static struct gpib_descriptor *handle_to_descriptor(const struct gpib_file_private *file_priv, + int handle) { if (handle < 0 || handle >= GPIB_MAX_NUM_DESCRIPTORS) { pr_err("gpib: invalid handle %i\n", handle); @@ -503,11 +509,11 @@ static gpib_descriptor_t *handle_to_descriptor(const gpib_file_private_t *file_p return file_priv->descriptors[handle]; } -static int init_gpib_file_private(gpib_file_private_t *priv) +static int init_gpib_file_private(struct gpib_file_private *priv) { memset(priv, 0, sizeof(*priv)); atomic_set(&priv->holding_mutex, 0); - priv->descriptors[0] = kmalloc(sizeof(gpib_descriptor_t), GFP_KERNEL); + priv->descriptors[0] = kmalloc(sizeof(struct gpib_descriptor), GFP_KERNEL); if (!priv->descriptors[0]) { pr_err("gpib: failed to allocate default board descriptor\n"); return -ENOMEM; @@ -522,7 +528,7 @@ int ibopen(struct inode *inode, struct file *filep) { unsigned int minor = iminor(inode); struct gpib_board *board; - gpib_file_private_t *priv; + struct gpib_file_private *priv; if (minor >= GPIB_MAX_NUM_BOARDS) { pr_err("gpib: invalid minor number of device file\n"); @@ -531,12 +537,12 @@ int ibopen(struct inode *inode, struct file *filep) board = &board_array[minor]; - filep->private_data = kmalloc(sizeof(gpib_file_private_t), GFP_KERNEL); + filep->private_data = kmalloc(sizeof(struct gpib_file_private), GFP_KERNEL); if (!filep->private_data) return -ENOMEM; priv = filep->private_data; - init_gpib_file_private((gpib_file_private_t *)filep->private_data); + init_gpib_file_private((struct gpib_file_private *)filep->private_data); if (board->use_count == 0) { int retval; @@ -560,8 +566,8 @@ int ibclose(struct inode *inode, struct file *filep) { unsigned int minor = iminor(inode); struct gpib_board *board; - gpib_file_private_t *priv = filep->private_data; - gpib_descriptor_t *desc; + struct gpib_file_private *priv = filep->private_data; + struct gpib_descriptor *desc; if (minor >= GPIB_MAX_NUM_BOARDS) { pr_err("gpib: invalid minor number of device file\n"); @@ -606,7 +612,7 @@ long ibioctl(struct file *filep, unsigned int cmd, unsigned long arg) { unsigned int minor = iminor(filep->f_path.dentry->d_inode); struct gpib_board *board; - gpib_file_private_t *file_priv = filep->private_data; + struct gpib_file_private *file_priv = filep->private_data; long retval = -ENOTTY; if (minor >= GPIB_MAX_NUM_BOARDS) { @@ -665,8 +671,9 @@ long ibioctl(struct file *filep, unsigned int cmd, unsigned long arg) retval = board_info_ioctl(board, arg); goto done; case IBMUTEX: - /* Need to unlock board->big_gpib_mutex before potentially locking board->user_mutex - * to maintain consistent locking order + /* + * Need to unlock board->big_gpib_mutex before potentially locking board->user_mutex + * to maintain consistent locking order */ mutex_unlock(&board->big_gpib_mutex); return mutex_ioctl(board, file_priv, arg); @@ -736,8 +743,9 @@ long ibioctl(struct file *filep, unsigned int cmd, unsigned long arg) retval = take_control_ioctl(board, arg); goto done; case IBCMD: - /* IO ioctls can take a long time, we need to unlock board->big_gpib_mutex - * before we call them. + /* + * IO ioctls can take a long time, we need to unlock board->big_gpib_mutex + * before we call them. */ mutex_unlock(&board->big_gpib_mutex); return command_ioctl(file_priv, board, arg); @@ -760,8 +768,9 @@ long ibioctl(struct file *filep, unsigned int cmd, unsigned long arg) retval = query_board_rsv_ioctl(board, arg); goto done; case IBRD: - /* IO ioctls can take a long time, we need to unlock board->big_gpib_mutex - * before we call them. + /* + * IO ioctls can take a long time, we need to unlock board->big_gpib_mutex + * before we call them. */ mutex_unlock(&board->big_gpib_mutex); return read_ioctl(file_priv, board, arg); @@ -790,8 +799,9 @@ long ibioctl(struct file *filep, unsigned int cmd, unsigned long arg) retval = timeout_ioctl(board, arg); goto done; case IBWRT: - /* IO ioctls can take a long time, we need to unlock board->big_gpib_mutex - * before we call them. + /* + * IO ioctls can take a long time, we need to unlock board->big_gpib_mutex + * before we call them. */ mutex_unlock(&board->big_gpib_mutex); return write_ioctl(file_priv, board, arg); @@ -806,10 +816,11 @@ done: return retval; } -static int board_type_ioctl(gpib_file_private_t *file_priv, struct gpib_board *board, unsigned long arg) +static int board_type_ioctl(struct gpib_file_private *file_priv, + struct gpib_board *board, unsigned long arg) { struct list_head *list_ptr; - board_type_ioctl_t cmd; + struct gpib_board_type_ioctl cmd; int retval; if (!capable(CAP_SYS_ADMIN)) @@ -817,15 +828,16 @@ static int board_type_ioctl(gpib_file_private_t *file_priv, struct gpib_board *b if (board->online) return -EBUSY; - retval = copy_from_user(&cmd, (void __user *)arg, sizeof(board_type_ioctl_t)); + retval = copy_from_user(&cmd, (void __user *)arg, + sizeof(struct gpib_board_type_ioctl)); if (retval) return retval; for (list_ptr = registered_drivers.next; list_ptr != ®istered_drivers; list_ptr = list_ptr->next) { - gpib_interface_list_t *entry; + struct gpib_interface_list *entry; - entry = list_entry(list_ptr, gpib_interface_list_t, list); + entry = list_entry(list_ptr, struct gpib_interface_list, list); if (strcmp(entry->interface->name, cmd.name) == 0) { int i; int had_module = file_priv->got_module; @@ -857,16 +869,16 @@ static int board_type_ioctl(gpib_file_private_t *file_priv, struct gpib_board *b return -EINVAL; } -static int read_ioctl(gpib_file_private_t *file_priv, struct gpib_board *board, +static int read_ioctl(struct gpib_file_private *file_priv, struct gpib_board *board, unsigned long arg) { - read_write_ioctl_t read_cmd; + struct gpib_read_write_ioctl read_cmd; u8 __user *userbuf; unsigned long remain; int end_flag = 0; int retval; ssize_t read_ret = 0; - gpib_descriptor_t *desc; + struct gpib_descriptor *desc; size_t nbytes; retval = copy_from_user(&read_cmd, (void __user *)arg, sizeof(read_cmd)); @@ -913,7 +925,8 @@ static int read_ioctl(gpib_file_private_t *file_priv, struct gpib_board *board, } read_cmd.completed_transfer_count = read_cmd.requested_transfer_count - remain; read_cmd.end = end_flag; - /* suppress errors (for example due to timeout or interruption by device clear) + /* + * suppress errors (for example due to timeout or interruption by device clear) * if all bytes got sent. This prevents races that can occur in the various drivers * if a device receives a device clear immediately after a transfer completes and * the driver code wasn't careful enough to handle that case. @@ -932,15 +945,15 @@ static int read_ioctl(gpib_file_private_t *file_priv, struct gpib_board *board, return read_ret; } -static int command_ioctl(gpib_file_private_t *file_priv, +static int command_ioctl(struct gpib_file_private *file_priv, struct gpib_board *board, unsigned long arg) { - read_write_ioctl_t cmd; + struct gpib_read_write_ioctl cmd; u8 __user *userbuf; unsigned long remain; int retval; int fault = 0; - gpib_descriptor_t *desc; + struct gpib_descriptor *desc; size_t bytes_written; int no_clear_io_in_prog; @@ -967,10 +980,11 @@ static int command_ioctl(gpib_file_private_t *file_priv, if (!access_ok(userbuf, remain)) return -EFAULT; - /* Write buffer loads till we empty the user supplied buffer. - * Call drivers at least once, even if remain is zero, in - * order to allow them to insure previous commands were - * completely finished, in the case of a restarted ioctl. + /* + * Write buffer loads till we empty the user supplied buffer. + * Call drivers at least once, even if remain is zero, in + * order to allow them to insure previous commands were + * completely finished, in the case of a restarted ioctl. */ atomic_set(&desc->io_in_progress, 1); @@ -1016,15 +1030,15 @@ static int command_ioctl(gpib_file_private_t *file_priv, return retval; } -static int write_ioctl(gpib_file_private_t *file_priv, struct gpib_board *board, +static int write_ioctl(struct gpib_file_private *file_priv, struct gpib_board *board, unsigned long arg) { - read_write_ioctl_t write_cmd; + struct gpib_read_write_ioctl write_cmd; u8 __user *userbuf; unsigned long remain; int retval = 0; int fault; - gpib_descriptor_t *desc; + struct gpib_descriptor *desc; fault = copy_from_user(&write_cmd, (void __user *)arg, sizeof(write_cmd)); if (fault) @@ -1068,7 +1082,8 @@ static int write_ioctl(gpib_file_private_t *file_priv, struct gpib_board *board, break; } write_cmd.completed_transfer_count = write_cmd.requested_transfer_count - remain; - /* suppress errors (for example due to timeout or interruption by device clear) + /* + * suppress errors (for example due to timeout or interruption by device clear) * if all bytes got sent. This prevents races that can occur in the various drivers * if a device receives a device clear immediately after a transfer completes and * the driver code wasn't careful enough to handle that case. @@ -1089,8 +1104,8 @@ static int write_ioctl(gpib_file_private_t *file_priv, struct gpib_board *board, static int status_bytes_ioctl(struct gpib_board *board, unsigned long arg) { - gpib_status_queue_t *device; - spoll_bytes_ioctl_t cmd; + struct gpib_status_queue *device; + struct gpib_spoll_bytes_ioctl cmd; int retval; retval = copy_from_user(&cmd, (void __user *)arg, sizeof(cmd)); @@ -1114,13 +1129,14 @@ static int increment_open_device_count(struct gpib_board *board, struct list_hea unsigned int pad, int sad) { struct list_head *list_ptr; - gpib_status_queue_t *device; + struct gpib_status_queue *device; - /* first see if address has already been opened, then increment + /* + * first see if address has already been opened, then increment * open count */ for (list_ptr = head->next; list_ptr != head; list_ptr = list_ptr->next) { - device = list_entry(list_ptr, gpib_status_queue_t, list); + device = list_entry(list_ptr, struct gpib_status_queue, list); if (gpib_address_equal(device->pad, device->sad, pad, sad)) { dev_dbg(board->gpib_dev, "incrementing open count for pad %i, sad %i\n", device->pad, device->sad); @@ -1129,8 +1145,8 @@ static int increment_open_device_count(struct gpib_board *board, struct list_hea } } - /* otherwise we need to allocate a new gpib_status_queue_t */ - device = kmalloc(sizeof(gpib_status_queue_t), GFP_ATOMIC); + /* otherwise we need to allocate a new struct gpib_status_queue */ + device = kmalloc(sizeof(struct gpib_status_queue), GFP_ATOMIC); if (!device) return -ENOMEM; init_gpib_status_queue(device); @@ -1148,11 +1164,11 @@ static int increment_open_device_count(struct gpib_board *board, struct list_hea static int subtract_open_device_count(struct gpib_board *board, struct list_head *head, unsigned int pad, int sad, unsigned int count) { - gpib_status_queue_t *device; + struct gpib_status_queue *device; struct list_head *list_ptr; for (list_ptr = head->next; list_ptr != head; list_ptr = list_ptr->next) { - device = list_entry(list_ptr, gpib_status_queue_t, list); + device = list_entry(list_ptr, struct gpib_status_queue, list); if (gpib_address_equal(device->pad, device->sad, pad, sad)) { dev_dbg(board->gpib_dev, "decrementing open count for pad %i, sad %i\n", device->pad, device->sad); @@ -1180,13 +1196,13 @@ static inline int decrement_open_device_count(struct gpib_board *board, struct l return subtract_open_device_count(board, head, pad, sad, 1); } -static int cleanup_open_devices(gpib_file_private_t *file_priv, struct gpib_board *board) +static int cleanup_open_devices(struct gpib_file_private *file_priv, struct gpib_board *board) { int retval = 0; int i; for (i = 0; i < GPIB_MAX_NUM_DESCRIPTORS; i++) { - gpib_descriptor_t *desc; + struct gpib_descriptor *desc; desc = file_priv->descriptors[i]; if (!desc) @@ -1207,9 +1223,9 @@ static int cleanup_open_devices(gpib_file_private_t *file_priv, struct gpib_boar static int open_dev_ioctl(struct file *filep, struct gpib_board *board, unsigned long arg) { - open_dev_ioctl_t open_dev_cmd; + struct gpib_open_dev_ioctl open_dev_cmd; int retval; - gpib_file_private_t *file_priv = filep->private_data; + struct gpib_file_private *file_priv = filep->private_data; int i; retval = copy_from_user(&open_dev_cmd, (void __user *)arg, sizeof(open_dev_cmd)); @@ -1225,7 +1241,7 @@ static int open_dev_ioctl(struct file *filep, struct gpib_board *board, unsigned mutex_unlock(&file_priv->descriptors_mutex); return -ERANGE; } - file_priv->descriptors[i] = kmalloc(sizeof(gpib_descriptor_t), GFP_KERNEL); + file_priv->descriptors[i] = kmalloc(sizeof(struct gpib_descriptor), GFP_KERNEL); if (!file_priv->descriptors[i]) { mutex_unlock(&file_priv->descriptors_mutex); return -ENOMEM; @@ -1242,7 +1258,8 @@ static int open_dev_ioctl(struct file *filep, struct gpib_board *board, unsigned if (retval < 0) return retval; - /* clear stuck srq state, since we may be able to find service request on + /* + * clear stuck srq state, since we may be able to find service request on * the new device */ atomic_set(&board->stuck_srq, 0); @@ -1257,8 +1274,8 @@ static int open_dev_ioctl(struct file *filep, struct gpib_board *board, unsigned static int close_dev_ioctl(struct file *filep, struct gpib_board *board, unsigned long arg) { - close_dev_ioctl_t cmd; - gpib_file_private_t *file_priv = filep->private_data; + struct gpib_close_dev_ioctl cmd; + struct gpib_file_private *file_priv = filep->private_data; int retval; retval = copy_from_user(&cmd, (void __user *)arg, sizeof(cmd)); @@ -1284,7 +1301,7 @@ static int close_dev_ioctl(struct file *filep, struct gpib_board *board, unsigne static int serial_poll_ioctl(struct gpib_board *board, unsigned long arg) { - serial_poll_ioctl_t serial_cmd; + struct gpib_serial_poll_ioctl serial_cmd; int retval; retval = copy_from_user(&serial_cmd, (void __user *)arg, sizeof(serial_cmd)); @@ -1303,12 +1320,12 @@ static int serial_poll_ioctl(struct gpib_board *board, unsigned long arg) return 0; } -static int wait_ioctl(gpib_file_private_t *file_priv, struct gpib_board *board, +static int wait_ioctl(struct gpib_file_private *file_priv, struct gpib_board *board, unsigned long arg) { - wait_ioctl_t wait_cmd; + struct gpib_wait_ioctl wait_cmd; int retval; - gpib_descriptor_t *desc; + struct gpib_descriptor *desc; retval = copy_from_user(&wait_cmd, (void __user *)arg, sizeof(wait_cmd)); if (retval) @@ -1348,7 +1365,7 @@ static int parallel_poll_ioctl(struct gpib_board *board, unsigned long arg) static int online_ioctl(struct gpib_board *board, unsigned long arg) { - online_ioctl_t online_cmd; + struct gpib_online_ioctl online_cmd; int retval; void __user *init_data = NULL; @@ -1430,12 +1447,12 @@ static int line_status_ioctl(struct gpib_board *board, unsigned long arg) return 0; } -static int pad_ioctl(struct gpib_board *board, gpib_file_private_t *file_priv, +static int pad_ioctl(struct gpib_board *board, struct gpib_file_private *file_priv, unsigned long arg) { - pad_ioctl_t cmd; + struct gpib_pad_ioctl cmd; int retval; - gpib_descriptor_t *desc; + struct gpib_descriptor *desc; retval = copy_from_user(&cmd, (void __user *)arg, sizeof(cmd)); if (retval) @@ -1466,12 +1483,12 @@ static int pad_ioctl(struct gpib_board *board, gpib_file_private_t *file_priv, return 0; } -static int sad_ioctl(struct gpib_board *board, gpib_file_private_t *file_priv, +static int sad_ioctl(struct gpib_board *board, struct gpib_file_private *file_priv, unsigned long arg) { - sad_ioctl_t cmd; + struct gpib_sad_ioctl cmd; int retval; - gpib_descriptor_t *desc; + struct gpib_descriptor *desc; retval = copy_from_user(&cmd, (void __user *)arg, sizeof(cmd)); if (retval) @@ -1503,7 +1520,7 @@ static int sad_ioctl(struct gpib_board *board, gpib_file_private_t *file_priv, static int eos_ioctl(struct gpib_board *board, unsigned long arg) { - eos_ioctl_t eos_cmd; + struct gpib_eos_ioctl eos_cmd; int retval; retval = copy_from_user(&eos_cmd, (void __user *)arg, sizeof(eos_cmd)); @@ -1527,11 +1544,11 @@ static int request_service_ioctl(struct gpib_board *board, unsigned long arg) static int request_service2_ioctl(struct gpib_board *board, unsigned long arg) { - request_service2_t request_service2_cmd; + struct gpib_request_service2 request_service2_cmd; int retval; retval = copy_from_user(&request_service2_cmd, (void __user *)arg, - sizeof(request_service2_t)); + sizeof(struct gpib_request_service2)); if (retval) return -EFAULT; @@ -1539,7 +1556,7 @@ static int request_service2_ioctl(struct gpib_board *board, unsigned long arg) request_service2_cmd.new_reason_for_service); } -static int iobase_ioctl(gpib_board_config_t *config, unsigned long arg) +static int iobase_ioctl(struct gpib_board_config *config, unsigned long arg) { u64 base_addr; int retval; @@ -1558,7 +1575,7 @@ static int iobase_ioctl(gpib_board_config_t *config, unsigned long arg) return 0; } -static int irq_ioctl(gpib_board_config_t *config, unsigned long arg) +static int irq_ioctl(struct gpib_board_config *config, unsigned long arg) { unsigned int irq; int retval; @@ -1575,7 +1592,7 @@ static int irq_ioctl(gpib_board_config_t *config, unsigned long arg) return 0; } -static int dma_ioctl(gpib_board_config_t *config, unsigned long arg) +static int dma_ioctl(struct gpib_board_config *config, unsigned long arg) { unsigned int dma_channel; int retval; @@ -1592,12 +1609,12 @@ static int dma_ioctl(gpib_board_config_t *config, unsigned long arg) return 0; } -static int autospoll_ioctl(struct gpib_board *board, gpib_file_private_t *file_priv, +static int autospoll_ioctl(struct gpib_board *board, struct gpib_file_private *file_priv, unsigned long arg) { - autospoll_ioctl_t enable; + short enable; int retval; - gpib_descriptor_t *desc; + struct gpib_descriptor *desc; retval = copy_from_user(&enable, (void __user *)arg, sizeof(enable)); if (retval) @@ -1630,7 +1647,7 @@ static int autospoll_ioctl(struct gpib_board *board, gpib_file_private_t *file_p return retval; } -static int mutex_ioctl(struct gpib_board *board, gpib_file_private_t *file_priv, +static int mutex_ioctl(struct gpib_board *board, struct gpib_file_private *file_priv, unsigned long arg) { int retval, lock_mutex; @@ -1687,7 +1704,7 @@ static int timeout_ioctl(struct gpib_board *board, unsigned long arg) static int ppc_ioctl(struct gpib_board *board, unsigned long arg) { - ppoll_config_ioctl_t cmd; + struct gpib_ppoll_config_ioctl cmd; int retval; retval = copy_from_user(&cmd, (void __user *)arg, sizeof(cmd)); @@ -1713,7 +1730,7 @@ static int ppc_ioctl(struct gpib_board *board, unsigned long arg) static int set_local_ppoll_mode_ioctl(struct gpib_board *board, unsigned long arg) { - local_ppoll_mode_ioctl_t cmd; + short cmd; int retval; retval = copy_from_user(&cmd, (void __user *)arg, sizeof(cmd)); @@ -1730,7 +1747,7 @@ static int set_local_ppoll_mode_ioctl(struct gpib_board *board, unsigned long ar static int get_local_ppoll_mode_ioctl(struct gpib_board *board, unsigned long arg) { - local_ppoll_mode_ioctl_t cmd; + short cmd; int retval; cmd = board->local_ppoll_mode; @@ -1757,7 +1774,7 @@ static int query_board_rsv_ioctl(struct gpib_board *board, unsigned long arg) static int board_info_ioctl(const struct gpib_board *board, unsigned long arg) { - board_info_ioctl_t info; + struct gpib_board_info_ioctl info; int retval; info.pad = board->pad; @@ -1790,9 +1807,9 @@ static int interface_clear_ioctl(struct gpib_board *board, unsigned long arg) return ibsic(board, usec_duration); } -static int select_pci_ioctl(gpib_board_config_t *config, unsigned long arg) +static int select_pci_ioctl(struct gpib_board_config *config, unsigned long arg) { - select_pci_ioctl_t selection; + struct gpib_select_pci_ioctl selection; int retval; if (!capable(CAP_SYS_ADMIN)) @@ -1808,19 +1825,20 @@ static int select_pci_ioctl(gpib_board_config_t *config, unsigned long arg) return 0; } -static int select_device_path_ioctl(gpib_board_config_t *config, unsigned long arg) +static int select_device_path_ioctl(struct gpib_board_config *config, unsigned long arg) { - select_device_path_ioctl_t *selection; + struct gpib_select_device_path_ioctl *selection; int retval; if (!capable(CAP_SYS_ADMIN)) return -EPERM; - selection = vmalloc(sizeof(select_device_path_ioctl_t)); + selection = vmalloc(sizeof(struct gpib_select_device_path_ioctl)); if (!selection) return -ENOMEM; - retval = copy_from_user(selection, (void __user *)arg, sizeof(select_device_path_ioctl_t)); + retval = copy_from_user(selection, (void __user *)arg, + sizeof(struct gpib_select_device_path_ioctl)); if (retval) { vfree(selection); return -EFAULT; @@ -1836,16 +1854,16 @@ static int select_device_path_ioctl(gpib_board_config_t *config, unsigned long a return 0; } -unsigned int num_gpib_events(const gpib_event_queue_t *queue) +unsigned int num_gpib_events(const struct gpib_event_queue *queue) { return queue->num_events; } static int push_gpib_event_nolock(struct gpib_board *board, short event_type) { - gpib_event_queue_t *queue = &board->event_queue; + struct gpib_event_queue *queue = &board->event_queue; struct list_head *head = &queue->event_head; - gpib_event_t *event; + struct gpib_event *event; static const unsigned int max_num_events = 1024; int retval; @@ -1858,7 +1876,7 @@ static int push_gpib_event_nolock(struct gpib_board *board, short event_type) return retval; } - event = kmalloc(sizeof(gpib_event_t), GFP_ATOMIC); + event = kmalloc(sizeof(struct gpib_event), GFP_ATOMIC); if (!event) { queue->dropped_event = 1; dev_err(board->gpib_dev, "failed to allocate memory for event\n"); @@ -1888,23 +1906,24 @@ int push_gpib_event(struct gpib_board *board, short event_type) retval = push_gpib_event_nolock(board, event_type); spin_unlock_irqrestore(&board->event_queue.lock, flags); - if (event_type == EventDevTrg) + if (event_type == EVENT_DEV_TRG) board->status |= DTAS; - if (event_type == EventDevClr) + if (event_type == EVENT_DEV_CLR) board->status |= DCAS; return retval; } EXPORT_SYMBOL(push_gpib_event); -static int pop_gpib_event_nolock(struct gpib_board *board, gpib_event_queue_t *queue, short *event_type) +static int pop_gpib_event_nolock(struct gpib_board *board, + struct gpib_event_queue *queue, short *event_type) { struct list_head *head = &queue->event_head; struct list_head *front = head->next; - gpib_event_t *event; + struct gpib_event *event; if (num_gpib_events(queue) == 0) { - *event_type = EventNone; + *event_type = EVENT_NONE; return 0; } @@ -1916,7 +1935,7 @@ static int pop_gpib_event_nolock(struct gpib_board *board, gpib_event_queue_t *q return -EPIPE; } - event = list_entry(front, gpib_event_t, list); + event = list_entry(front, struct gpib_event, list); *event_type = event->event_type; list_del(front); @@ -1931,7 +1950,7 @@ static int pop_gpib_event_nolock(struct gpib_board *board, gpib_event_queue_t *q } // pop event from front of event queue -int pop_gpib_event(struct gpib_board *board, gpib_event_queue_t *queue, short *event_type) +int pop_gpib_event(struct gpib_board *board, struct gpib_event_queue *queue, short *event_type) { unsigned long flags; int retval; @@ -1944,7 +1963,7 @@ int pop_gpib_event(struct gpib_board *board, gpib_event_queue_t *queue, short *e static int event_ioctl(struct gpib_board *board, unsigned long arg) { - event_ioctl_t user_event; + short user_event; int retval; short event; @@ -1963,21 +1982,19 @@ static int event_ioctl(struct gpib_board *board, unsigned long arg) static int request_system_control_ioctl(struct gpib_board *board, unsigned long arg) { - rsc_ioctl_t request_control; + int request_control; int retval; retval = copy_from_user(&request_control, (void __user *)arg, sizeof(request_control)); if (retval) return -EFAULT; - ibrsc(board, request_control); - - return 0; + return ibrsc(board, request_control); } static int t1_delay_ioctl(struct gpib_board *board, unsigned long arg) { - t1_delay_ioctl_t cmd; + unsigned int cmd; unsigned int delay; int retval; @@ -2011,7 +2028,7 @@ struct gpib_board board_array[GPIB_MAX_NUM_BOARDS]; LIST_HEAD(registered_drivers); -void init_gpib_descriptor(gpib_descriptor_t *desc) +void init_gpib_descriptor(struct gpib_descriptor *desc) { desc->pad = 0; desc->sad = -1; @@ -2020,9 +2037,9 @@ void init_gpib_descriptor(gpib_descriptor_t *desc) atomic_set(&desc->io_in_progress, 0); } -int gpib_register_driver(gpib_interface_t *interface, struct module *provider_module) +int gpib_register_driver(struct gpib_interface *interface, struct module *provider_module) { - struct gpib_interface_list_struct *entry; + struct gpib_interface_list *entry; entry = kmalloc(sizeof(*entry), GFP_KERNEL); if (!entry) @@ -2036,7 +2053,7 @@ int gpib_register_driver(gpib_interface_t *interface, struct module *provider_mo } EXPORT_SYMBOL(gpib_register_driver); -void gpib_unregister_driver(gpib_interface_t *interface) +void gpib_unregister_driver(struct gpib_interface *interface) { int i; struct list_head *list_ptr; @@ -2053,9 +2070,9 @@ void gpib_unregister_driver(gpib_interface_t *interface) } } for (list_ptr = registered_drivers.next; list_ptr != ®istered_drivers;) { - gpib_interface_list_t *entry; + struct gpib_interface_list *entry; - entry = list_entry(list_ptr, gpib_interface_list_t, list); + entry = list_entry(list_ptr, struct gpib_interface_list, list); list_ptr = list_ptr->next; if (entry->interface == interface) { list_del(&entry->list); @@ -2065,9 +2082,9 @@ void gpib_unregister_driver(gpib_interface_t *interface) } EXPORT_SYMBOL(gpib_unregister_driver); -static void init_gpib_board_config(gpib_board_config_t *config) +static void init_gpib_board_config(struct gpib_board_config *config) { - memset(config, 0, sizeof(gpib_board_config_t)); + memset(config, 0, sizeof(struct gpib_board_config)); config->pci_bus = -1; config->pci_slot = -1; } @@ -2143,7 +2160,7 @@ static void init_board_array(struct gpib_board *board_array, unsigned int length } } -void init_gpib_status_queue(gpib_status_queue_t *device) +void init_gpib_status_queue(struct gpib_status_queue *device) { INIT_LIST_HEAD(&device->list); INIT_LIST_HEAD(&device->status_bytes); @@ -2208,7 +2225,7 @@ int gpib_match_device_path(struct device *dev, const char *device_path_in) } EXPORT_SYMBOL(gpib_match_device_path); -struct pci_dev *gpib_pci_get_device(const gpib_board_config_t *config, unsigned int vendor_id, +struct pci_dev *gpib_pci_get_device(const struct gpib_board_config *config, unsigned int vendor_id, unsigned int device_id, struct pci_dev *from) { struct pci_dev *pci_device = from; @@ -2227,7 +2244,7 @@ struct pci_dev *gpib_pci_get_device(const gpib_board_config_t *config, unsigned } EXPORT_SYMBOL(gpib_pci_get_device); -struct pci_dev *gpib_pci_get_subsys(const gpib_board_config_t *config, unsigned int vendor_id, +struct pci_dev *gpib_pci_get_subsys(const struct gpib_board_config *config, unsigned int vendor_id, unsigned int device_id, unsigned int ss_vendor, unsigned int ss_device, struct pci_dev *from) diff --git a/drivers/staging/gpib/common/iblib.c b/drivers/staging/gpib/common/iblib.c index 432540e1bc9a..549280d9a6e9 100644 --- a/drivers/staging/gpib/common/iblib.c +++ b/drivers/staging/gpib/common/iblib.c @@ -33,9 +33,10 @@ int ibcac(struct gpib_board *board, int sync, int fallback_to_async) return 0; if (sync && (status & LACS) == 0) - /* tcs (take control synchronously) can only possibly work when - * controller is listener. Error code also needs to be -ETIMEDOUT - * or it will giveout without doing fallback. + /* + * tcs (take control synchronously) can only possibly work when + * controller is listener. Error code also needs to be -ETIMEDOUT + * or it will giveout without doing fallback. */ retval = -ETIMEDOUT; else @@ -50,7 +51,8 @@ int ibcac(struct gpib_board *board, int sync, int fallback_to_async) return retval; } -/* After ATN is asserted, it should cause any connected devices +/* + * After ATN is asserted, it should cause any connected devices * to start listening for command bytes and leave acceptor idle state. * So if ATN is asserted and neither NDAC or NRFD are asserted, * then there are no devices and ibcmd should error out immediately. @@ -96,7 +98,7 @@ static int check_for_command_acceptors(struct gpib_board *board) * must be called to initialize the GPIB and enable * the interface to leave the controller idle state. */ -int ibcmd(struct gpib_board *board, uint8_t *buf, size_t length, size_t *bytes_written) +int ibcmd(struct gpib_board *board, u8 *buf, size_t length, size_t *bytes_written) { ssize_t ret = 0; int status; @@ -218,7 +220,8 @@ int ibonline(struct gpib_board *board) board->interface->detach(board); return retval; } - /* nios2nommu on 2.6.11 uclinux kernel has weird problems + /* + * nios2nommu on 2.6.11 uclinux kernel has weird problems * with autospoll thread causing huge slowdowns */ #ifndef CONFIG_NIOS2 @@ -297,7 +300,7 @@ int iblines(const struct gpib_board *board, short *lines) * calling ibcmd. */ -int ibrd(struct gpib_board *board, uint8_t *buf, size_t length, int *end_flag, size_t *nbytes) +int ibrd(struct gpib_board *board, u8 *buf, size_t length, int *end_flag, size_t *nbytes) { ssize_t ret = 0; int retval; @@ -313,7 +316,8 @@ int ibrd(struct gpib_board *board, uint8_t *buf, size_t length, int *end_flag, s if (retval < 0) return retval; } - /* XXX resetting timer here could cause timeouts take longer than they should, + /* + * XXX resetting timer here could cause timeouts take longer than they should, * since read_ioctl calls this * function in a loop, there is probably a similar problem with writes/commands */ @@ -343,7 +347,7 @@ ibrd_out: * 1. Prior to conducting the poll the interface is placed * in the controller active state. */ -int ibrpp(struct gpib_board *board, uint8_t *result) +int ibrpp(struct gpib_board *board, u8 *result) { int retval = 0; @@ -358,7 +362,7 @@ int ibrpp(struct gpib_board *board, uint8_t *result) return retval; } -int ibppc(struct gpib_board *board, uint8_t configuration) +int ibppc(struct gpib_board *board, u8 configuration) { configuration &= 0x1f; board->interface->parallel_poll_configure(board, configuration); @@ -367,7 +371,7 @@ int ibppc(struct gpib_board *board, uint8_t configuration) return 0; } -int ibrsv2(struct gpib_board *board, uint8_t status_byte, int new_reason_for_service) +int ibrsv2(struct gpib_board *board, u8 status_byte, int new_reason_for_service) { int board_status = ibstatus(board); const unsigned int MSS = status_byte & request_service_bit; @@ -418,12 +422,21 @@ int ibsic(struct gpib_board *board, unsigned int usec_duration) return 0; } - /* FIXME make int */ -void ibrsc(struct gpib_board *board, int request_control) +int ibrsc(struct gpib_board *board, int request_control) { + int retval; + + if (!board->interface->request_system_control) + return -EPERM; + + retval = board->interface->request_system_control(board, request_control); + + if (retval) + return retval; + board->master = request_control != 0; - if (board->interface->request_system_control) - board->interface->request_system_control(board, request_control); + + return 0; } /* @@ -506,15 +519,16 @@ int ibstatus(struct gpib_board *board) return general_ibstatus(board, NULL, 0, 0, NULL); } -int general_ibstatus(struct gpib_board *board, const gpib_status_queue_t *device, - int clear_mask, int set_mask, gpib_descriptor_t *desc) +int general_ibstatus(struct gpib_board *board, const struct gpib_status_queue *device, + int clear_mask, int set_mask, struct gpib_descriptor *desc) { int status = 0; short line_status; if (board->private_data) { status = board->interface->update_status(board, clear_mask); - /* XXX should probably stop having drivers use TIMO bit in + /* + * XXX should probably stop having drivers use TIMO bit in * board->status to avoid confusion */ status &= ~TIMO; @@ -560,7 +574,7 @@ struct wait_info { static void wait_timeout(struct timer_list *t) { - struct wait_info *winfo = from_timer(winfo, t, timer); + struct wait_info *winfo = timer_container_of(winfo, t, timer); winfo->timed_out = 1; wake_up_interruptible(&winfo->board->wait); @@ -573,8 +587,8 @@ static void init_wait_info(struct wait_info *winfo) timer_setup_on_stack(&winfo->timer, wait_timeout, 0); } -static int wait_satisfied(struct wait_info *winfo, gpib_status_queue_t *status_queue, - int wait_mask, int *status, gpib_descriptor_t *desc) +static int wait_satisfied(struct wait_info *winfo, struct gpib_status_queue *status_queue, + int wait_mask, int *status, struct gpib_descriptor *desc) { struct gpib_board *board = winfo->board; int temp_status; @@ -623,10 +637,10 @@ static void remove_wait_timer(struct wait_info *winfo) * no condition is waited for. */ int ibwait(struct gpib_board *board, int wait_mask, int clear_mask, int set_mask, - int *status, unsigned long usec_timeout, gpib_descriptor_t *desc) + int *status, unsigned long usec_timeout, struct gpib_descriptor *desc) { int retval = 0; - gpib_status_queue_t *status_queue; + struct gpib_status_queue *status_queue; struct wait_info winfo; if (desc->is_board) @@ -677,7 +691,7 @@ int ibwait(struct gpib_board *board, int wait_mask, int clear_mask, int set_mask * well as the interface board itself must be * addressed by calling ibcmd. */ -int ibwrt(struct gpib_board *board, uint8_t *buf, size_t cnt, int send_eoi, size_t *bytes_written) +int ibwrt(struct gpib_board *board, u8 *buf, size_t cnt, int send_eoi, size_t *bytes_written) { int ret = 0; int retval; diff --git a/drivers/staging/gpib/common/ibsys.h b/drivers/staging/gpib/common/ibsys.h index 19960af809c2..e5a148f513a8 100644 --- a/drivers/staging/gpib/common/ibsys.h +++ b/drivers/staging/gpib/common/ibsys.h @@ -22,10 +22,13 @@ int gpib_allocate_board(struct gpib_board *board); void gpib_deallocate_board(struct gpib_board *board); -unsigned int num_status_bytes(const gpib_status_queue_t *dev); -int push_status_byte(struct gpib_board *board, gpib_status_queue_t *device, uint8_t poll_byte); -int pop_status_byte(struct gpib_board *board, gpib_status_queue_t *device, uint8_t *poll_byte); -gpib_status_queue_t *get_gpib_status_queue(struct gpib_board *board, unsigned int pad, int sad); +unsigned int num_status_bytes(const struct gpib_status_queue *dev); +int push_status_byte(struct gpib_board *board, struct gpib_status_queue *device, + u8 poll_byte); +int pop_status_byte(struct gpib_board *board, struct gpib_status_queue *device, + u8 *poll_byte); +struct gpib_status_queue *get_gpib_status_queue(struct gpib_board *board, + unsigned int pad, int sad); int get_serial_poll_byte(struct gpib_board *board, unsigned int pad, int sad, - unsigned int usec_timeout, uint8_t *poll_byte); + unsigned int usec_timeout, u8 *poll_byte); int autopoll_all_devices(struct gpib_board *board); diff --git a/drivers/staging/gpib/eastwood/fluke_gpib.c b/drivers/staging/gpib/eastwood/fluke_gpib.c index a6b1ac169f94..491356433249 100644 --- a/drivers/staging/gpib/eastwood/fluke_gpib.c +++ b/drivers/staging/gpib/eastwood/fluke_gpib.c @@ -24,15 +24,17 @@ MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("GPIB Driver for Fluke cda devices"); -static int fluke_attach_holdoff_all(struct gpib_board *board, const gpib_board_config_t *config); -static int fluke_attach_holdoff_end(struct gpib_board *board, const gpib_board_config_t *config); +static int fluke_attach_holdoff_all(struct gpib_board *board, + const struct gpib_board_config *config); +static int fluke_attach_holdoff_end(struct gpib_board *board, + const struct gpib_board_config *config); static void fluke_detach(struct gpib_board *board); static int fluke_config_dma(struct gpib_board *board, int output); static irqreturn_t fluke_gpib_internal_interrupt(struct gpib_board *board); static struct platform_device *fluke_gpib_pdev; -static uint8_t fluke_locking_read_byte(struct nec7210_priv *nec_priv, unsigned int register_number) +static u8 fluke_locking_read_byte(struct nec7210_priv *nec_priv, unsigned int register_number) { u8 retval; unsigned long flags; @@ -43,7 +45,7 @@ static uint8_t fluke_locking_read_byte(struct nec7210_priv *nec_priv, unsigned i return retval; } -static void fluke_locking_write_byte(struct nec7210_priv *nec_priv, uint8_t byte, +static void fluke_locking_write_byte(struct nec7210_priv *nec_priv, u8 byte, unsigned int register_number) { unsigned long flags; @@ -54,7 +56,7 @@ static void fluke_locking_write_byte(struct nec7210_priv *nec_priv, uint8_t byte } // wrappers for interface functions -static int fluke_read(struct gpib_board *board, uint8_t *buffer, size_t length, int *end, +static int fluke_read(struct gpib_board *board, u8 *buffer, size_t length, int *end, size_t *bytes_read) { struct fluke_priv *priv = board->private_data; @@ -62,7 +64,7 @@ static int fluke_read(struct gpib_board *board, uint8_t *buffer, size_t length, return nec7210_read(board, &priv->nec7210_priv, buffer, length, end, bytes_read); } -static int fluke_write(struct gpib_board *board, uint8_t *buffer, size_t length, +static int fluke_write(struct gpib_board *board, u8 *buffer, size_t length, int send_eoi, size_t *bytes_written) { struct fluke_priv *priv = board->private_data; @@ -70,7 +72,7 @@ static int fluke_write(struct gpib_board *board, uint8_t *buffer, size_t length, return nec7210_write(board, &priv->nec7210_priv, buffer, length, send_eoi, bytes_written); } -static int fluke_command(struct gpib_board *board, uint8_t *buffer, +static int fluke_command(struct gpib_board *board, u8 *buffer, size_t length, size_t *bytes_written) { struct fluke_priv *priv = board->private_data; @@ -92,12 +94,12 @@ static int fluke_go_to_standby(struct gpib_board *board) return nec7210_go_to_standby(board, &priv->nec7210_priv); } -static void fluke_request_system_control(struct gpib_board *board, int request_control) +static int fluke_request_system_control(struct gpib_board *board, int request_control) { struct fluke_priv *priv = board->private_data; struct nec7210_priv *nec_priv = &priv->nec7210_priv; - nec7210_request_system_control(board, nec_priv, request_control); + return nec7210_request_system_control(board, nec_priv, request_control); } static void fluke_interface_clear(struct gpib_board *board, int assert) @@ -114,7 +116,7 @@ static void fluke_remote_enable(struct gpib_board *board, int enable) nec7210_remote_enable(board, &priv->nec7210_priv, enable); } -static int fluke_enable_eos(struct gpib_board *board, uint8_t eos_byte, int compare_8_bits) +static int fluke_enable_eos(struct gpib_board *board, u8 eos_byte, int compare_8_bits) { struct fluke_priv *priv = board->private_data; @@ -149,14 +151,14 @@ static int fluke_secondary_address(struct gpib_board *board, unsigned int addres return nec7210_secondary_address(board, &priv->nec7210_priv, address, enable); } -static int fluke_parallel_poll(struct gpib_board *board, uint8_t *result) +static int fluke_parallel_poll(struct gpib_board *board, u8 *result) { struct fluke_priv *priv = board->private_data; return nec7210_parallel_poll(board, &priv->nec7210_priv, result); } -static void fluke_parallel_poll_configure(struct gpib_board *board, uint8_t configuration) +static void fluke_parallel_poll_configure(struct gpib_board *board, u8 configuration) { struct fluke_priv *priv = board->private_data; @@ -170,14 +172,14 @@ static void fluke_parallel_poll_response(struct gpib_board *board, int ist) nec7210_parallel_poll_response(board, &priv->nec7210_priv, ist); } -static void fluke_serial_poll_response(struct gpib_board *board, uint8_t status) +static void fluke_serial_poll_response(struct gpib_board *board, u8 status) { struct fluke_priv *priv = board->private_data; nec7210_serial_poll_response(board, &priv->nec7210_priv, status); } -static uint8_t fluke_serial_poll_status(struct gpib_board *board) +static u8 fluke_serial_poll_status(struct gpib_board *board) { struct fluke_priv *priv = board->private_data; @@ -254,7 +256,8 @@ static int lacs_or_read_ready(struct gpib_board *board) return retval; } -/* Wait until it is possible for a read to do something useful. This +/* + * Wait until it is possible for a read to do something useful. This * is not essential, it only exists to prevent RFD holdoff from being released pointlessly. */ static int wait_for_read(struct gpib_board *board) @@ -276,7 +279,8 @@ static int wait_for_read(struct gpib_board *board) return retval; } -/* Check if the SH state machine is in SGNS. We check twice since there is a very small chance +/* + * Check if the SH state machine is in SGNS. We check twice since there is a very small chance * we could be blowing through SGNS from SIDS to SDYS if there is already a * byte available in the handshake state machine. We are interested * in the case where the handshake is stuck in SGNS due to no byte being @@ -310,7 +314,8 @@ static int source_handshake_is_sids_or_sgns(struct fluke_priv *e_priv) (source_handshake_bits == SOURCE_HANDSHAKE_SIDS_BITS); } -/* Wait until the gpib chip is ready to accept a data out byte. +/* + * Wait until the gpib chip is ready to accept a data out byte. * If the chip is SGNS it is probably waiting for a a byte to * be written to it. */ @@ -371,7 +376,7 @@ static void fluke_dma_callback(void *arg) spin_unlock_irqrestore(&board->spinlock, flags); } -static int fluke_dma_write(struct gpib_board *board, uint8_t *buffer, size_t length, +static int fluke_dma_write(struct gpib_board *board, u8 *buffer, size_t length, size_t *bytes_written) { struct fluke_priv *e_priv = board->private_data; @@ -441,7 +446,8 @@ static int fluke_dma_write(struct gpib_board *board, uint8_t *buffer, size_t len if (test_bit(DMA_WRITE_IN_PROGRESS_BN, &nec_priv->state)) fluke_dma_callback(board); - /* if everything went fine, try to wait until last byte is actually + /* + * if everything went fine, try to wait until last byte is actually * transmitted across gpib (but don't try _too_ hard) */ if (retval == 0) @@ -456,7 +462,7 @@ cleanup: return retval; } -static int fluke_accel_write(struct gpib_board *board, uint8_t *buffer, size_t length, +static int fluke_accel_write(struct gpib_board *board, u8 *buffer, size_t length, int send_eoi, size_t *bytes_written) { struct fluke_priv *e_priv = board->private_data; @@ -508,7 +514,8 @@ static int fluke_accel_write(struct gpib_board *board, uint8_t *buffer, size_t l if (WARN_ON_ONCE(remainder != 1)) return -EFAULT; - /* wait until we are sure we will be able to write the data byte + /* + * wait until we are sure we will be able to write the data byte * into the chip before we send AUX_SEOI. This prevents a timeout * scenerio where we send AUX_SEOI but then timeout without getting * any bytes into the gpib chip. This will result in the first byte @@ -539,12 +546,14 @@ static int fluke_get_dma_residue(struct dma_chan *chan, dma_cookie_t cookie) return result; } dmaengine_tx_status(chan, cookie, &state); - // hardware doesn't support resume, so dont call this - // method unless the dma transfer is done. + /* + * hardware doesn't support resume, so dont call this + * method unless the dma transfer is done. + */ return state.residue; } -static int fluke_dma_read(struct gpib_board *board, uint8_t *buffer, +static int fluke_dma_read(struct gpib_board *board, u8 *buffer, size_t length, int *end, size_t *bytes_read) { struct fluke_priv *e_priv = board->private_data; @@ -608,7 +617,8 @@ static int fluke_dma_read(struct gpib_board *board, uint8_t *buffer, if (test_bit(DEV_CLEAR_BN, &nec_priv->state)) retval = -EINTR; - /* If we woke up because of end, wait until the dma transfer has pulled + /* + * If we woke up because of end, wait until the dma transfer has pulled * the data byte associated with the end before we cancel the dma transfer. */ if (test_bit(RECEIVED_END_BN, &nec_priv->state)) { @@ -625,7 +635,8 @@ static int fluke_dma_read(struct gpib_board *board, uint8_t *buffer, // stop the dma transfer nec7210_set_reg_bits(nec_priv, IMR2, HR_DMAI, 0); - /* delay a little just to make sure any bytes in dma controller's fifo get + /* + * delay a little just to make sure any bytes in dma controller's fifo get * written to memory before we disable it */ usleep_range(10, 15); @@ -641,14 +652,17 @@ static int fluke_dma_read(struct gpib_board *board, uint8_t *buffer, dma_unmap_single(board->dev, bus_address, length, DMA_FROM_DEVICE); memcpy(buffer, e_priv->dma_buffer, *bytes_read); - /* If we got an end interrupt, figure out if it was + /* + * If we got an end interrupt, figure out if it was * associated with the last byte we dma'd or with a * byte still sitting on the cb7210. */ spin_lock_irqsave(&board->spinlock, flags); if (test_bit(READ_READY_BN, &nec_priv->state) == 0) { - // There is no byte sitting on the cb7210. If we - // saw an end interrupt, we need to deal with it now + /* + * There is no byte sitting on the cb7210. If we + * saw an end interrupt, we need to deal with it now + */ if (test_and_clear_bit(RECEIVED_END_BN, &nec_priv->state)) *end = 1; } @@ -657,7 +671,7 @@ static int fluke_dma_read(struct gpib_board *board, uint8_t *buffer, return retval; } -static int fluke_accel_read(struct gpib_board *board, uint8_t *buffer, size_t length, +static int fluke_accel_read(struct gpib_board *board, u8 *buffer, size_t length, int *end, size_t *bytes_read) { struct fluke_priv *e_priv = board->private_data; @@ -698,7 +712,7 @@ static int fluke_accel_read(struct gpib_board *board, uint8_t *buffer, size_t le return retval; } -static gpib_interface_t fluke_unaccel_interface = { +static struct gpib_interface fluke_unaccel_interface = { .name = "fluke_unaccel", .attach = fluke_attach_holdoff_all, .detach = fluke_detach, @@ -725,7 +739,8 @@ static gpib_interface_t fluke_unaccel_interface = { .return_to_local = fluke_return_to_local, }; -/* fluke_hybrid uses dma for writes but not for reads. Added +/* + * fluke_hybrid uses dma for writes but not for reads. Added * to deal with occasional corruption of bytes seen when doing dma * reads. From looking at the cb7210 vhdl, I believe the corruption * is due to a hardware bug triggered by the cpu reading a cb7210 @@ -733,7 +748,7 @@ static gpib_interface_t fluke_unaccel_interface = { * register just as the dma controller is also doing a read. */ -static gpib_interface_t fluke_hybrid_interface = { +static struct gpib_interface fluke_hybrid_interface = { .name = "fluke_hybrid", .attach = fluke_attach_holdoff_all, .detach = fluke_detach, @@ -760,7 +775,7 @@ static gpib_interface_t fluke_hybrid_interface = { .return_to_local = fluke_return_to_local, }; -static gpib_interface_t fluke_interface = { +static struct gpib_interface fluke_interface = { .name = "fluke", .attach = fluke_attach_holdoff_end, .detach = fluke_detach, @@ -802,7 +817,7 @@ irqreturn_t fluke_gpib_internal_interrupt(struct gpib_board *board) status2 = read_byte(nec_priv, ISR2); if (status0 & FLUKE_IFCI_BIT) { - push_gpib_event(board, EventIFC); + push_gpib_event(board, EVENT_IFC); retval = IRQ_HANDLED; } @@ -914,7 +929,8 @@ static int fluke_init(struct fluke_priv *e_priv, struct gpib_board *board, int h nec7210_board_reset(nec_priv, board); write_byte(nec_priv, AUX_LO_SPEED, AUXMR); - /* set clock register for driving frequency + /* + * set clock register for driving frequency * ICR should be set to clock in megahertz (1-15) and to zero * for clocks faster than 15 MHz (max 20MHz) */ @@ -933,7 +949,8 @@ static int fluke_init(struct fluke_priv *e_priv, struct gpib_board *board, int h return 0; } -/* This function is passed to dma_request_channel() in order to +/* + * This function is passed to dma_request_channel() in order to * select the pl330 dma channel which has been hardwired to * the gpib controller. */ @@ -943,7 +960,7 @@ static bool gpib_dma_channel_filter(struct dma_chan *chan, void *filter_param) return chan->chan_id == 0; } -static int fluke_attach_impl(struct gpib_board *board, const gpib_board_config_t *config, +static int fluke_attach_impl(struct gpib_board *board, const struct gpib_board_config *config, unsigned int handshake_mode) { struct fluke_priv *e_priv; @@ -1024,10 +1041,8 @@ static int fluke_attach_impl(struct gpib_board *board, const gpib_board_config_t } irq = platform_get_irq(fluke_gpib_pdev, 0); - if (irq < 0) { - dev_err(&fluke_gpib_pdev->dev, "failed to obtain IRQ\n"); + if (irq < 0) return -EBUSY; - } retval = request_irq(irq, fluke_gpib_interrupt, isr_flags, fluke_gpib_pdev->name, board); if (retval) { dev_err(&fluke_gpib_pdev->dev, @@ -1042,19 +1057,21 @@ static int fluke_attach_impl(struct gpib_board *board, const gpib_board_config_t e_priv->dma_channel = dma_request_channel(dma_cap, gpib_dma_channel_filter, NULL); if (!e_priv->dma_channel) { dev_err(board->gpib_dev, "failed to allocate a dma channel.\n"); - // we don't error out here because unaccel interface will still - // work without dma + /* + * we don't error out here because unaccel interface will still + * work without dma + */ } return fluke_init(e_priv, board, handshake_mode); } -int fluke_attach_holdoff_all(struct gpib_board *board, const gpib_board_config_t *config) +int fluke_attach_holdoff_all(struct gpib_board *board, const struct gpib_board_config *config) { return fluke_attach_impl(board, config, HR_HLDA); } -int fluke_attach_holdoff_end(struct gpib_board *board, const gpib_board_config_t *config) +int fluke_attach_holdoff_end(struct gpib_board *board, const struct gpib_board_config *config) { return fluke_attach_impl(board, config, HR_HLDE); } diff --git a/drivers/staging/gpib/eastwood/fluke_gpib.h b/drivers/staging/gpib/eastwood/fluke_gpib.h index 3e4348196b42..493c200d0bbf 100644 --- a/drivers/staging/gpib/eastwood/fluke_gpib.h +++ b/drivers/staging/gpib/eastwood/fluke_gpib.h @@ -55,8 +55,10 @@ enum state1_bits { SOURCE_HANDSHAKE_MASK = 0x7 }; -// we customized the cb7210 vhdl to give the "data in" status -// on the unused bit 7 of the address0 register. +/* + * we customized the cb7210 vhdl to give the "data in" status + * on the unused bit 7 of the address0 register. + */ enum cb7210_address0 { DATA_IN_STATUS = 0x80 }; @@ -67,8 +69,8 @@ static inline int cb7210_page_in_bits(unsigned int page) } // don't use without locking nec_priv->register_page_lock -static inline uint8_t fluke_read_byte_nolock(struct nec7210_priv *nec_priv, - int register_num) +static inline u8 fluke_read_byte_nolock(struct nec7210_priv *nec_priv, + int register_num) { u8 retval; @@ -77,14 +79,14 @@ static inline uint8_t fluke_read_byte_nolock(struct nec7210_priv *nec_priv, } // don't use without locking nec_priv->register_page_lock -static inline void fluke_write_byte_nolock(struct nec7210_priv *nec_priv, uint8_t data, +static inline void fluke_write_byte_nolock(struct nec7210_priv *nec_priv, u8 data, int register_num) { writel(data, nec_priv->mmiobase + register_num * nec_priv->offset); } -static inline uint8_t fluke_paged_read_byte(struct fluke_priv *e_priv, - unsigned int register_num, unsigned int page) +static inline u8 fluke_paged_read_byte(struct fluke_priv *e_priv, + unsigned int register_num, unsigned int page) { struct nec7210_priv *nec_priv = &e_priv->nec7210_priv; u8 retval; @@ -99,7 +101,7 @@ static inline uint8_t fluke_paged_read_byte(struct fluke_priv *e_priv, return retval; } -static inline void fluke_paged_write_byte(struct fluke_priv *e_priv, uint8_t data, +static inline void fluke_paged_write_byte(struct fluke_priv *e_priv, u8 data, unsigned int register_num, unsigned int page) { struct nec7210_priv *nec_priv = &e_priv->nec7210_priv; @@ -124,11 +126,12 @@ enum bus_status_bits { }; enum cb7210_aux_cmds { -/* AUX_RTL2 is an undocumented aux command which causes cb7210 to assert - * (and keep asserted) local rtl message. This is used in conjunction - * with the (stupid) cb7210 implementation - * of the normal nec7210 AUX_RTL aux command, which - * causes the rtl message to toggle between on and off. +/* + * AUX_RTL2 is an undocumented aux command which causes cb7210 to assert + * (and keep asserted) local rtl message. This is used in conjunction + * with the (stupid) cb7210 implementation + * of the normal nec7210 AUX_RTL aux command, which + * causes the rtl message to toggle between on and off. */ AUX_RTL2 = 0xd, AUX_NBAF = 0xe, // new byte available false (also clears seoi) diff --git a/drivers/staging/gpib/fmh_gpib/fmh_gpib.c b/drivers/staging/gpib/fmh_gpib/fmh_gpib.c index 53f4b3fccc3c..4138f3d2bae7 100644 --- a/drivers/staging/gpib/fmh_gpib/fmh_gpib.c +++ b/drivers/staging/gpib/fmh_gpib/fmh_gpib.c @@ -32,13 +32,15 @@ MODULE_DESCRIPTION("GPIB Driver for fmh_gpib_core"); MODULE_AUTHOR("Frank Mori Hess <fmh6jj@gmail.com>"); static irqreturn_t fmh_gpib_interrupt(int irq, void *arg); -static int fmh_gpib_attach_holdoff_all(struct gpib_board *board, const gpib_board_config_t *config); -static int fmh_gpib_attach_holdoff_end(struct gpib_board *board, const gpib_board_config_t *config); +static int fmh_gpib_attach_holdoff_all(struct gpib_board *board, + const struct gpib_board_config *config); +static int fmh_gpib_attach_holdoff_end(struct gpib_board *board, + const struct gpib_board_config *config); static void fmh_gpib_detach(struct gpib_board *board); static int fmh_gpib_pci_attach_holdoff_all(struct gpib_board *board, - const gpib_board_config_t *config); + const struct gpib_board_config *config); static int fmh_gpib_pci_attach_holdoff_end(struct gpib_board *board, - const gpib_board_config_t *config); + const struct gpib_board_config *config); static void fmh_gpib_pci_detach(struct gpib_board *board); static int fmh_gpib_config_dma(struct gpib_board *board, int output); static irqreturn_t fmh_gpib_internal_interrupt(struct gpib_board *board); @@ -46,7 +48,7 @@ static struct platform_driver fmh_gpib_platform_driver; static struct pci_driver fmh_gpib_pci_driver; // wrappers for interface functions -static int fmh_gpib_read(struct gpib_board *board, uint8_t *buffer, size_t length, +static int fmh_gpib_read(struct gpib_board *board, u8 *buffer, size_t length, int *end, size_t *bytes_read) { struct fmh_priv *priv = board->private_data; @@ -54,7 +56,7 @@ static int fmh_gpib_read(struct gpib_board *board, uint8_t *buffer, size_t lengt return nec7210_read(board, &priv->nec7210_priv, buffer, length, end, bytes_read); } -static int fmh_gpib_write(struct gpib_board *board, uint8_t *buffer, size_t length, +static int fmh_gpib_write(struct gpib_board *board, u8 *buffer, size_t length, int send_eoi, size_t *bytes_written) { struct fmh_priv *priv = board->private_data; @@ -62,7 +64,7 @@ static int fmh_gpib_write(struct gpib_board *board, uint8_t *buffer, size_t leng return nec7210_write(board, &priv->nec7210_priv, buffer, length, send_eoi, bytes_written); } -static int fmh_gpib_command(struct gpib_board *board, uint8_t *buffer, size_t length, +static int fmh_gpib_command(struct gpib_board *board, u8 *buffer, size_t length, size_t *bytes_written) { struct fmh_priv *priv = board->private_data; @@ -84,12 +86,12 @@ static int fmh_gpib_go_to_standby(struct gpib_board *board) return nec7210_go_to_standby(board, &priv->nec7210_priv); } -static void fmh_gpib_request_system_control(struct gpib_board *board, int request_control) +static int fmh_gpib_request_system_control(struct gpib_board *board, int request_control) { struct fmh_priv *priv = board->private_data; struct nec7210_priv *nec_priv = &priv->nec7210_priv; - nec7210_request_system_control(board, nec_priv, request_control); + return nec7210_request_system_control(board, nec_priv, request_control); } static void fmh_gpib_interface_clear(struct gpib_board *board, int assert) @@ -106,7 +108,7 @@ static void fmh_gpib_remote_enable(struct gpib_board *board, int enable) nec7210_remote_enable(board, &priv->nec7210_priv, enable); } -static int fmh_gpib_enable_eos(struct gpib_board *board, uint8_t eos_byte, int compare_8_bits) +static int fmh_gpib_enable_eos(struct gpib_board *board, u8 eos_byte, int compare_8_bits) { struct fmh_priv *priv = board->private_data; @@ -141,14 +143,14 @@ static int fmh_gpib_secondary_address(struct gpib_board *board, unsigned int add return nec7210_secondary_address(board, &priv->nec7210_priv, address, enable); } -static int fmh_gpib_parallel_poll(struct gpib_board *board, uint8_t *result) +static int fmh_gpib_parallel_poll(struct gpib_board *board, u8 *result) { struct fmh_priv *priv = board->private_data; return nec7210_parallel_poll(board, &priv->nec7210_priv, result); } -static void fmh_gpib_parallel_poll_configure(struct gpib_board *board, uint8_t configuration) +static void fmh_gpib_parallel_poll_configure(struct gpib_board *board, u8 configuration) { struct fmh_priv *priv = board->private_data; @@ -169,7 +171,8 @@ static void fmh_gpib_local_parallel_poll_mode(struct gpib_board *board, int loca if (local) { write_byte(&priv->nec7210_priv, AUX_I_REG | LOCAL_PPOLL_MODE_BIT, AUXMR); } else { - /* For fmh_gpib_core, remote parallel poll config mode is unaffected by the + /* + * For fmh_gpib_core, remote parallel poll config mode is unaffected by the * state of the disable bit of the parallel poll register (unlike the tnt4882). * So, we don't need to worry about that. */ @@ -177,7 +180,7 @@ static void fmh_gpib_local_parallel_poll_mode(struct gpib_board *board, int loca } } -static void fmh_gpib_serial_poll_response2(struct gpib_board *board, uint8_t status, +static void fmh_gpib_serial_poll_response2(struct gpib_board *board, u8 status, int new_reason_for_service) { struct fmh_priv *priv = board->private_data; @@ -195,7 +198,8 @@ static void fmh_gpib_serial_poll_response2(struct gpib_board *board, uint8_t sta } if (reqt) { - /* It may seem like a race to issue reqt before updating + /* + * It may seem like a race to issue reqt before updating * the status byte, but it is not. The chip does not * issue the reqt until the SPMR is written to at * a later time. @@ -204,7 +208,8 @@ static void fmh_gpib_serial_poll_response2(struct gpib_board *board, uint8_t sta } else if (reqf) { write_byte(&priv->nec7210_priv, AUX_REQF, AUXMR); } - /* We need to always zero bit 6 of the status byte before writing it to + /* + * We need to always zero bit 6 of the status byte before writing it to * the SPMR to insure we are using * serial poll mode SP1, and not accidentally triggering mode SP3. */ @@ -212,7 +217,7 @@ static void fmh_gpib_serial_poll_response2(struct gpib_board *board, uint8_t sta spin_unlock_irqrestore(&board->spinlock, flags); } -static uint8_t fmh_gpib_serial_poll_status(struct gpib_board *board) +static u8 fmh_gpib_serial_poll_status(struct gpib_board *board) { struct fmh_priv *priv = board->private_data; @@ -333,7 +338,8 @@ static int wait_for_rx_fifo_half_full_or_end(struct gpib_board *board) return retval; } -/* Wait until the gpib chip is ready to accept a data out byte. +/* + * Wait until the gpib chip is ready to accept a data out byte. */ static int wait_for_data_out_ready(struct gpib_board *board) { @@ -377,7 +383,8 @@ static void fmh_gpib_dma_callback(void *arg) spin_unlock_irqrestore(&board->spinlock, flags); } -/* returns true when all the bytes of a write have been transferred to +/* + * returns true when all the bytes of a write have been transferred to * the chip and successfully transferred out over the gpib bus. */ static int fmh_gpib_all_bytes_are_sent(struct fmh_priv *e_priv) @@ -391,7 +398,7 @@ static int fmh_gpib_all_bytes_are_sent(struct fmh_priv *e_priv) return 1; } -static int fmh_gpib_dma_write(struct gpib_board *board, uint8_t *buffer, size_t length, +static int fmh_gpib_dma_write(struct gpib_board *board, u8 *buffer, size_t length, size_t *bytes_written) { struct fmh_priv *e_priv = board->private_data; @@ -469,7 +476,7 @@ cleanup: return retval; } -static int fmh_gpib_accel_write(struct gpib_board *board, uint8_t *buffer, +static int fmh_gpib_accel_write(struct gpib_board *board, u8 *buffer, size_t length, int send_eoi, size_t *bytes_written) { struct fmh_priv *e_priv = board->private_data; @@ -523,7 +530,8 @@ static int fmh_gpib_accel_write(struct gpib_board *board, uint8_t *buffer, if (WARN_ON_ONCE(remainder != 1)) return -EFAULT; - /* wait until we are sure we will be able to write the data byte + /* + * wait until we are sure we will be able to write the data byte * into the chip before we send AUX_SEOI. This prevents a timeout * scenario where we send AUX_SEOI but then timeout without getting * any bytes into the gpib chip. This will result in the first byte @@ -554,8 +562,10 @@ static int fmh_gpib_get_dma_residue(struct dma_chan *chan, dma_cookie_t cookie) return result; } dmaengine_tx_status(chan, cookie, &state); - // dma330 hardware doesn't support resume, so dont call this - // method unless the dma transfer is done. + /* + * dma330 hardware doesn't support resume, so dont call this + * method unless the dma transfer is done. + */ return state.residue; } @@ -581,10 +591,11 @@ static int wait_for_tx_fifo_half_empty(struct gpib_board *board) return retval; } -/* supports writing a chunk of data whose length must fit into the hardware'd xfer counter, +/* + * supports writing a chunk of data whose length must fit into the hardware'd xfer counter, * called in a loop by fmh_gpib_fifo_write() */ -static int fmh_gpib_fifo_write_countable(struct gpib_board *board, uint8_t *buffer, +static int fmh_gpib_fifo_write_countable(struct gpib_board *board, u8 *buffer, size_t length, int send_eoi, size_t *bytes_written) { struct fmh_priv *e_priv = board->private_data; @@ -650,7 +661,7 @@ cleanup: return retval; } -static int fmh_gpib_fifo_write(struct gpib_board *board, uint8_t *buffer, size_t length, +static int fmh_gpib_fifo_write(struct gpib_board *board, u8 *buffer, size_t length, int send_eoi, size_t *bytes_written) { struct fmh_priv *e_priv = board->private_data; @@ -697,7 +708,7 @@ static int fmh_gpib_fifo_write(struct gpib_board *board, uint8_t *buffer, size_t return retval; } -static int fmh_gpib_dma_read(struct gpib_board *board, uint8_t *buffer, +static int fmh_gpib_dma_read(struct gpib_board *board, u8 *buffer, size_t length, int *end, size_t *bytes_read) { struct fmh_priv *e_priv = board->private_data; @@ -768,8 +779,10 @@ static int fmh_gpib_dma_read(struct gpib_board *board, uint8_t *buffer, // stop the dma transfer nec7210_set_reg_bits(nec_priv, IMR2, HR_DMAI, 0); fifos_write(e_priv, 0, FIFO_CONTROL_STATUS_REG); - // give time for pl330 to transfer any in-flight data, since - // pl330 will throw it away when dmaengine_pause is called. + /* + * give time for pl330 to transfer any in-flight data, since + * pl330 will throw it away when dmaengine_pause is called. + */ usleep_range(10, 15); residue = fmh_gpib_get_dma_residue(e_priv->dma_channel, dma_cookie); if (WARN_ON_ONCE(residue > length || residue < 0)) @@ -793,14 +806,17 @@ static int fmh_gpib_dma_read(struct gpib_board *board, uint8_t *buffer, buffer[(*bytes_read)++] = fifos_read(e_priv, FIFO_DATA_REG) & fifo_data_mask; } - /* If we got an end interrupt, figure out if it was + /* + * If we got an end interrupt, figure out if it was * associated with the last byte we dma'd or with a * byte still sitting on the cb7210. */ spin_lock_irqsave(&board->spinlock, flags); if (*bytes_read > 0 && test_bit(READ_READY_BN, &nec_priv->state) == 0) { - // If there is no byte sitting on the cb7210 and we - // saw an end, we need to deal with it now + /* + * If there is no byte sitting on the cb7210 and we + * saw an end, we need to deal with it now + */ if (test_and_clear_bit(RECEIVED_END_BN, &nec_priv->state)) *end = 1; } @@ -819,7 +835,8 @@ static void fmh_gpib_release_rfd_holdoff(struct gpib_board *board, struct fmh_pr ext_status_1 = read_byte(nec_priv, EXT_STATUS_1_REG); - /* if there is an end byte sitting on the chip, don't release + /* + * if there is an end byte sitting on the chip, don't release * holdoff. We want it left set after we read out the end * byte. */ @@ -828,7 +845,8 @@ static void fmh_gpib_release_rfd_holdoff(struct gpib_board *board, struct fmh_pr if (ext_status_1 & RFD_HOLDOFF_STATUS_BIT) write_byte(nec_priv, AUX_FH, AUXMR); - /* Check if an end byte raced in before we executed the AUX_FH command. + /* + * Check if an end byte raced in before we executed the AUX_FH command. * If it did, we want to make sure the rfd holdoff is in effect. The end * byte can arrive since * AUX_RFD_HOLDOFF_ASAP doesn't immediately force the acceptor handshake @@ -846,7 +864,7 @@ static void fmh_gpib_release_rfd_holdoff(struct gpib_board *board, struct fmh_pr spin_unlock_irqrestore(&board->spinlock, flags); } -static int fmh_gpib_accel_read(struct gpib_board *board, uint8_t *buffer, size_t length, +static int fmh_gpib_accel_read(struct gpib_board *board, u8 *buffer, size_t length, int *end, size_t *bytes_read) { struct fmh_priv *e_priv = board->private_data; @@ -893,10 +911,11 @@ static int fmh_gpib_accel_read(struct gpib_board *board, uint8_t *buffer, size_t return retval; } -/* Read a chunk of data whose length is within the limits of the hardware's +/* + * Read a chunk of data whose length is within the limits of the hardware's * xfer counter. Called in a loop from fmh_gpib_fifo_read(). */ -static int fmh_gpib_fifo_read_countable(struct gpib_board *board, uint8_t *buffer, +static int fmh_gpib_fifo_read_countable(struct gpib_board *board, u8 *buffer, size_t length, int *end, size_t *bytes_read) { struct fmh_priv *e_priv = board->private_data; @@ -954,7 +973,7 @@ cleanup: return retval; } -static int fmh_gpib_fifo_read(struct gpib_board *board, uint8_t *buffer, size_t length, +static int fmh_gpib_fifo_read(struct gpib_board *board, u8 *buffer, size_t length, int *end, size_t *bytes_read) { struct fmh_priv *e_priv = board->private_data; @@ -969,7 +988,8 @@ static int fmh_gpib_fifo_read(struct gpib_board *board, uint8_t *buffer, size_t *end = 0; *bytes_read = 0; - /* Do a little prep with data in interrupt so that following wait_for_read() + /* + * Do a little prep with data in interrupt so that following wait_for_read() * will wake up if a data byte is received. */ nec7210_set_reg_bits(nec_priv, IMR1, HR_DIIE, HR_DIIE); @@ -1011,7 +1031,7 @@ static int fmh_gpib_fifo_read(struct gpib_board *board, uint8_t *buffer, size_t return retval; } -static gpib_interface_t fmh_gpib_unaccel_interface = { +static struct gpib_interface fmh_gpib_unaccel_interface = { .name = "fmh_gpib_unaccel", .attach = fmh_gpib_attach_holdoff_all, .detach = fmh_gpib_detach, @@ -1039,7 +1059,7 @@ static gpib_interface_t fmh_gpib_unaccel_interface = { .return_to_local = fmh_gpib_return_to_local, }; -static gpib_interface_t fmh_gpib_interface = { +static struct gpib_interface fmh_gpib_interface = { .name = "fmh_gpib", .attach = fmh_gpib_attach_holdoff_end, .detach = fmh_gpib_detach, @@ -1067,7 +1087,7 @@ static gpib_interface_t fmh_gpib_interface = { .return_to_local = fmh_gpib_return_to_local, }; -static gpib_interface_t fmh_gpib_pci_interface = { +static struct gpib_interface fmh_gpib_pci_interface = { .name = "fmh_gpib_pci", .attach = fmh_gpib_pci_attach_holdoff_end, .detach = fmh_gpib_pci_detach, @@ -1095,7 +1115,7 @@ static gpib_interface_t fmh_gpib_pci_interface = { .return_to_local = fmh_gpib_return_to_local, }; -static gpib_interface_t fmh_gpib_pci_unaccel_interface = { +static struct gpib_interface fmh_gpib_pci_unaccel_interface = { .name = "fmh_gpib_pci_unaccel", .attach = fmh_gpib_pci_attach_holdoff_all, .detach = fmh_gpib_pci_detach, @@ -1136,7 +1156,7 @@ irqreturn_t fmh_gpib_internal_interrupt(struct gpib_board *board) fifo_status = fifos_read(priv, FIFO_CONTROL_STATUS_REG); if (status0 & IFC_INTERRUPT_BIT) { - push_gpib_event(board, EventIFC); + push_gpib_event(board, EVENT_IFC); retval = IRQ_HANDLED; } @@ -1166,7 +1186,8 @@ irqreturn_t fmh_gpib_internal_interrupt(struct gpib_board *board) clear_bit(RFD_HOLDOFF_BN, &nec_priv->state); if (ext_status_1 & END_STATUS_BIT) { - /* only set RECEIVED_END while there is still a data + /* + * only set RECEIVED_END while there is still a data * byte sitting in the chip, to avoid spuriously * setting it multiple times after it has been cleared * during a read. @@ -1179,7 +1200,8 @@ irqreturn_t fmh_gpib_internal_interrupt(struct gpib_board *board) if ((fifo_status & TX_FIFO_HALF_EMPTY_INTERRUPT_IS_ENABLED) && (fifo_status & TX_FIFO_HALF_EMPTY)) { - /* We really only want to clear the + /* + * We really only want to clear the * TX_FIFO_HALF_EMPTY_INTERRUPT_ENABLE bit in the * FIFO_CONTROL_STATUS_REG. Since we are not being * careful, this also has a side effect of disabling @@ -1193,7 +1215,8 @@ irqreturn_t fmh_gpib_internal_interrupt(struct gpib_board *board) if ((fifo_status & RX_FIFO_HALF_FULL_INTERRUPT_IS_ENABLED) && (fifo_status & RX_FIFO_HALF_FULL)) { - /* We really only want to clear the + /* + * We really only want to clear the * RX_FIFO_HALF_FULL_INTERRUPT_ENABLE bit in the * FIFO_CONTROL_STATUS_REG. Since we are not being * careful, this also has a side effect of disabling @@ -1335,7 +1358,7 @@ static int fmh_gpib_init(struct fmh_priv *e_priv, struct gpib_board *board, int /* Match callback for driver_find_device */ static int fmh_gpib_device_match(struct device *dev, const void *data) { - const gpib_board_config_t *config = data; + const struct gpib_board_config *config = data; if (dev_get_drvdata(dev)) return 0; @@ -1351,7 +1374,7 @@ static int fmh_gpib_device_match(struct device *dev, const void *data) return 1; } -static int fmh_gpib_attach_impl(struct gpib_board *board, const gpib_board_config_t *config, +static int fmh_gpib_attach_impl(struct gpib_board *board, const struct gpib_board_config *config, unsigned int handshake_mode, int acquire_dma) { struct fmh_priv *e_priv; @@ -1424,10 +1447,8 @@ static int fmh_gpib_attach_impl(struct gpib_board *board, const gpib_board_confi (unsigned long)resource_size(e_priv->dma_port_res)); irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(board->dev, "request for IRQ failed\n"); + if (irq < 0) return -EBUSY; - } retval = request_irq(irq, fmh_gpib_interrupt, IRQF_SHARED, pdev->name, board); if (retval) { dev_err(board->dev, @@ -1444,7 +1465,8 @@ static int fmh_gpib_attach_impl(struct gpib_board *board, const gpib_board_confi return -EIO; } } - /* in the future we might want to know the half-fifo size + /* + * in the future we might want to know the half-fifo size * (dma_burst_length) even when not using dma, so go ahead an * initialize it unconditionally. */ @@ -1454,12 +1476,12 @@ static int fmh_gpib_attach_impl(struct gpib_board *board, const gpib_board_confi return fmh_gpib_init(e_priv, board, handshake_mode); } -int fmh_gpib_attach_holdoff_all(struct gpib_board *board, const gpib_board_config_t *config) +int fmh_gpib_attach_holdoff_all(struct gpib_board *board, const struct gpib_board_config *config) { return fmh_gpib_attach_impl(board, config, HR_HLDA, 0); } -int fmh_gpib_attach_holdoff_end(struct gpib_board *board, const gpib_board_config_t *config) +int fmh_gpib_attach_holdoff_end(struct gpib_board *board, const struct gpib_board_config *config) { return fmh_gpib_attach_impl(board, config, HR_HLDE, 1); } @@ -1497,7 +1519,8 @@ void fmh_gpib_detach(struct gpib_board *board) fmh_gpib_generic_detach(board); } -static int fmh_gpib_pci_attach_impl(struct gpib_board *board, const gpib_board_config_t *config, +static int fmh_gpib_pci_attach_impl(struct gpib_board *board, + const struct gpib_board_config *config, unsigned int handshake_mode) { struct fmh_priv *e_priv; @@ -1570,12 +1593,14 @@ static int fmh_gpib_pci_attach_impl(struct gpib_board *board, const gpib_board_c return fmh_gpib_init(e_priv, board, handshake_mode); } -int fmh_gpib_pci_attach_holdoff_all(struct gpib_board *board, const gpib_board_config_t *config) +int fmh_gpib_pci_attach_holdoff_all(struct gpib_board *board, + const struct gpib_board_config *config) { return fmh_gpib_pci_attach_impl(board, config, HR_HLDA); } -int fmh_gpib_pci_attach_holdoff_end(struct gpib_board *board, const gpib_board_config_t *config) +int fmh_gpib_pci_attach_holdoff_end(struct gpib_board *board, + const struct gpib_board_config *config) { int retval; struct fmh_priv *e_priv; @@ -1631,7 +1656,6 @@ MODULE_DEVICE_TABLE(of, fmh_gpib_of_match); static struct platform_driver fmh_gpib_platform_driver = { .driver = { .name = DRV_NAME, - .owner = THIS_MODULE, .of_match_table = fmh_gpib_of_match, }, .probe = &fmh_gpib_platform_probe diff --git a/drivers/staging/gpib/fmh_gpib/fmh_gpib.h b/drivers/staging/gpib/fmh_gpib/fmh_gpib.h index de6fd2164414..e7602d7e1401 100644 --- a/drivers/staging/gpib/fmh_gpib/fmh_gpib.h +++ b/drivers/staging/gpib/fmh_gpib/fmh_gpib.h @@ -124,13 +124,13 @@ static const unsigned int fifo_data_mask = 0x00ff; static const unsigned int fifo_xfer_counter_mask = 0x0fff; static const unsigned int fifo_max_burst_length_mask = 0x00ff; -static inline uint8_t gpib_cs_read_byte(struct nec7210_priv *nec_priv, - unsigned int register_num) +static inline u8 gpib_cs_read_byte(struct nec7210_priv *nec_priv, + unsigned int register_num) { return readb(nec_priv->mmiobase + register_num * nec_priv->offset); } -static inline void gpib_cs_write_byte(struct nec7210_priv *nec_priv, uint8_t data, +static inline void gpib_cs_write_byte(struct nec7210_priv *nec_priv, u8 data, unsigned int register_num) { writeb(data, nec_priv->mmiobase + register_num * nec_priv->offset); diff --git a/drivers/staging/gpib/gpio/gpib_bitbang.c b/drivers/staging/gpib/gpio/gpib_bitbang.c index 86bdd381472a..625fef24a0bf 100644 --- a/drivers/staging/gpib/gpio/gpib_bitbang.c +++ b/drivers/staging/gpib/gpio/gpib_bitbang.c @@ -32,7 +32,8 @@ #define ENABLE_IRQ(IRQ, TYPE) irq_set_irq_type(IRQ, TYPE) #define DISABLE_IRQ(IRQ) irq_set_irq_type(IRQ, IRQ_TYPE_NONE) -/* Debug print levels: +/* + * Debug print levels: * 0 = load/unload info and errors that make the driver fail; * 1 = + warnings for unforeseen events that may break the current * operation and lead to a timeout, but do not affect the @@ -65,7 +66,6 @@ #include <linux/gpio/machine.h> #include <linux/gpio.h> #include <linux/irq.h> -#include <linux/leds.h> static int sn7516x_used = 1, sn7516x; module_param(sn7516x_used, int, 0660); @@ -135,19 +135,14 @@ enum lines_t { #define SN7516X_PINS 4 #define NUM_PINS (GPIB_PINS + SN7516X_PINS) -DEFINE_LED_TRIGGER(ledtrig_gpib); -#define ACT_LED_ON do { \ +#define ACT_LED_ON do { \ if (ACT_LED) \ - gpiod_direction_output(ACT_LED, 1); \ - else \ - led_trigger_event(ledtrig_gpib, LED_FULL); } \ - while (0) -#define ACT_LED_OFF do { \ + gpiod_direction_output(ACT_LED, 1); \ + } while (0) +#define ACT_LED_OFF do { \ if (ACT_LED) \ - gpiod_direction_output(ACT_LED, 0); \ - else \ - led_trigger_event(ledtrig_gpib, LED_OFF); } \ - while (0) + gpiod_direction_output(ACT_LED, 0); \ + } while (0) static struct gpio_desc *all_descriptors[GPIB_PINS + SN7516X_PINS]; @@ -311,7 +306,6 @@ struct bb_priv { int dav_seq; long all_irqs; int dav_idle; - int atn_asserted; enum talker_function_state talker_state; enum listener_function_state listener_state; @@ -324,7 +318,7 @@ static void set_data_lines(u8 byte); static u8 get_data_lines(void); static void set_data_lines_input(void); static void set_data_lines_output(void); -static inline int check_for_eos(struct bb_priv *priv, uint8_t byte); +static inline int check_for_eos(struct bb_priv *priv, u8 byte); static void set_atn(struct gpib_board *board, int atn_asserted); static inline void SET_DIR_WRITE(struct bb_priv *priv); @@ -353,7 +347,7 @@ static char printable(char x) * * ***************************************************************************/ -static int bb_read(struct gpib_board *board, uint8_t *buffer, size_t length, +static int bb_read(struct gpib_board *board, u8 *buffer, size_t length, int *end, size_t *bytes_read) { struct bb_priv *priv = board->private_data; @@ -491,7 +485,7 @@ dav_exit: * * ***************************************************************************/ -static int bb_write(struct gpib_board *board, uint8_t *buffer, size_t length, +static int bb_write(struct gpib_board *board, u8 *buffer, size_t length, int send_eoi, size_t *bytes_written) { unsigned long flags; @@ -522,7 +516,7 @@ static int bb_write(struct gpib_board *board, uint8_t *buffer, size_t length, gpiod_get_value(NRFD), gpiod_get_value(NDAC)); if (gpiod_get_value(NRFD) && gpiod_get_value(NDAC)) { /* check for listener */ - retval = -ENODEV; + retval = -ENOTCONN; goto write_end; } @@ -619,7 +613,8 @@ static irqreturn_t bb_NRFD_interrupt(int irq, void *arg) goto nrfd_exit; } - if (priv->atn_asserted && priv->w_cnt >= priv->length) { // test for end of transfer + if (priv->w_cnt >= priv->length) { // test for missed NDAC end of transfer + dev_err(board->gpib_dev, "Unexpected NRFD exit\n"); priv->write_done = 1; priv->w_busy = 0; wake_up_interruptible(&board->wait); @@ -691,14 +686,14 @@ static irqreturn_t bb_NDAC_interrupt(int irq, void *arg) dbg_printk(3, "accepted %zu\n", priv->w_cnt - 1); - if (!priv->atn_asserted && priv->w_cnt >= priv->length) { // test for end of transfer + gpiod_set_value(DAV, 1); // Data not available + priv->dav_tx = 1; + priv->phase = 510; + + if (priv->w_cnt >= priv->length) { // test for end of transfer priv->write_done = 1; priv->w_busy = 0; wake_up_interruptible(&board->wait); - } else { - gpiod_set_value(DAV, 1); // Data not available - priv->dav_tx = 1; - priv->phase = 510; } ndac_exit: @@ -728,7 +723,7 @@ static irqreturn_t bb_SRQ_interrupt(int irq, void *arg) return IRQ_HANDLED; } -static int bb_command(struct gpib_board *board, uint8_t *buffer, +static int bb_command(struct gpib_board *board, u8 *buffer, size_t length, size_t *bytes_written) { size_t ret; @@ -855,6 +850,7 @@ static void set_atn(struct gpib_board *board, int atn_asserted) priv->listener_state = listener_addressed; if (priv->talker_state == talker_active) priv->talker_state = talker_addressed; + SET_DIR_WRITE(priv); // need to be able to read bus NRFD/NDAC } else { if (priv->listener_state == listener_addressed) { priv->listener_state = listener_active; @@ -864,14 +860,12 @@ static void set_atn(struct gpib_board *board, int atn_asserted) priv->talker_state = talker_active; } gpiod_direction_output(_ATN, !atn_asserted); - priv->atn_asserted = atn_asserted; } static int bb_take_control(struct gpib_board *board, int synchronous) { dbg_printk(2, "%d\n", synchronous); set_atn(board, 1); - set_bit(CIC_NUM, &board->status); return 0; } @@ -882,16 +876,24 @@ static int bb_go_to_standby(struct gpib_board *board) return 0; } -static void bb_request_system_control(struct gpib_board *board, int request_control) +static int bb_request_system_control(struct gpib_board *board, int request_control) { + struct bb_priv *priv = board->private_data; + dbg_printk(2, "%d\n", request_control); - if (request_control) { - set_bit(CIC_NUM, &board->status); - // drive DAV & EOI false, enable NRFD & NDAC irqs - SET_DIR_WRITE(board->private_data); - } else { - clear_bit(CIC_NUM, &board->status); - } + if (!request_control) + return -EINVAL; + + gpiod_direction_output(REN, 1); /* user space must enable REN if needed */ + gpiod_direction_output(IFC, 1); /* user space must toggle IFC if needed */ + if (sn7516x) + gpiod_direction_output(DC, 0); /* enable ATN as output on SN75161/2 */ + + gpiod_direction_input(SRQ); + + ENABLE_IRQ(priv->irq_SRQ, IRQ_TYPE_EDGE_FALLING); + + return 0; } static void bb_interface_clear(struct gpib_board *board, int assert) @@ -903,6 +905,7 @@ static void bb_interface_clear(struct gpib_board *board, int assert) gpiod_direction_output(IFC, 0); priv->talker_state = talker_idle; priv->listener_state = listener_idle; + set_bit(CIC_NUM, &board->status); } else { gpiod_direction_output(IFC, 1); } @@ -920,7 +923,7 @@ static void bb_remote_enable(struct gpib_board *board, int enable) } } -static int bb_enable_eos(struct gpib_board *board, uint8_t eos_byte, int compare_8_bits) +static int bb_enable_eos(struct gpib_board *board, u8 eos_byte, int compare_8_bits) { struct bb_priv *priv = board->private_data; @@ -987,12 +990,12 @@ static int bb_secondary_address(struct gpib_board *board, unsigned int address, return 0; } -static int bb_parallel_poll(struct gpib_board *board, uint8_t *result) +static int bb_parallel_poll(struct gpib_board *board, u8 *result) { return -ENOENT; } -static void bb_parallel_poll_configure(struct gpib_board *board, uint8_t config) +static void bb_parallel_poll_configure(struct gpib_board *board, u8 config) { } @@ -1000,11 +1003,11 @@ static void bb_parallel_poll_response(struct gpib_board *board, int ist) { } -static void bb_serial_poll_response(struct gpib_board *board, uint8_t status) +static void bb_serial_poll_response(struct gpib_board *board, u8 status) { } -static uint8_t bb_serial_poll_status(struct gpib_board *board) +static u8 bb_serial_poll_status(struct gpib_board *board) { return 0; // -ENOENT; } @@ -1120,8 +1123,7 @@ static void release_gpios(void) static int allocate_gpios(struct gpib_board *board) { - int j, retval = 0; - bool error = false; + int j; int table_index = 0; char name[256]; struct gpio_desc *desc; @@ -1132,8 +1134,8 @@ static int allocate_gpios(struct gpib_board *board) return -ENOENT; } - lookup_table = lookup_tables[0]; - lookup_table->dev_id = dev_name(board->gpib_dev); + lookup_table = lookup_tables[table_index]; + lookup_table->dev_id = dev_name(board->gpib_dev); gpiod_add_lookup_table(lookup_table); dbg_printk(1, "Allocating gpios using table index %d\n", table_index); @@ -1150,30 +1152,26 @@ try_again: gpiod_remove_lookup_table(lookup_table); table_index++; lookup_table = lookup_tables[table_index]; - if (lookup_table) { - dbg_printk(1, "Allocation failed, now using table_index %d\n", - table_index); - lookup_table->dev_id = dev_name(board->gpib_dev); - gpiod_add_lookup_table(lookup_table); - goto try_again; + if (!lookup_table) { + dev_err(board->gpib_dev, "Unable to obtain gpio descriptor for pin %d error %ld\n", + gpios_vector[j], PTR_ERR(desc)); + goto alloc_gpios_fail; } - dev_err(board->gpib_dev, "Unable to obtain gpio descriptor for pin %d error %ld\n", - gpios_vector[j], PTR_ERR(desc)); - error = true; - break; + dbg_printk(1, "Allocation failed, now using table_index %d\n", table_index); + lookup_table->dev_id = dev_name(board->gpib_dev); + gpiod_add_lookup_table(lookup_table); + goto try_again; } all_descriptors[j] = desc; } - if (error) { /* undo what already done */ - release_gpios(); - retval = -1; - } - if (lookup_table) - gpiod_remove_lookup_table(lookup_table); - // Initialize LED trigger - led_trigger_register_simple("gpib", &ledtrig_gpib); - return retval; + gpiod_remove_lookup_table(lookup_table); + + return 0; + +alloc_gpios_fail: + release_gpios(); + return -1; } static void bb_detach(struct gpib_board *board) @@ -1184,8 +1182,6 @@ static void bb_detach(struct gpib_board *board) if (!board->private_data) return; - led_trigger_unregister_simple(ledtrig_gpib); - bb_free_irq(board, &priv->irq_DAV, NAME "_DAV"); bb_free_irq(board, &priv->irq_NRFD, NAME "_NRFD"); bb_free_irq(board, &priv->irq_NDAC, NAME "_NDAC"); @@ -1206,7 +1202,7 @@ static void bb_detach(struct gpib_board *board) free_private(board); } -static int bb_attach(struct gpib_board *board, const gpib_board_config_t *config) +static int bb_attach(struct gpib_board *board, const struct gpib_board_config *config) { struct bb_priv *priv; int retval = 0; @@ -1245,7 +1241,6 @@ static int bb_attach(struct gpib_board *board, const gpib_board_config_t *config gpios_vector[&(D06) - &all_descriptors[0]] = YOGA_D06_pin_nr; gpios_vector[&(PE) - &all_descriptors[0]] = -1; gpios_vector[&(DC) - &all_descriptors[0]] = -1; - gpios_vector[&(ACT_LED) - &all_descriptors[0]] = -1; } else { dev_err(board->gpib_dev, "Unrecognized pin map %s\n", pin_map); goto bb_attach_fail; @@ -1256,7 +1251,8 @@ static int bb_attach(struct gpib_board *board, const gpib_board_config_t *config if (allocate_gpios(board)) goto bb_attach_fail; -/* Configure SN7516X control lines. +/* + * Configure SN7516X control lines. * drive ATN, IFC and REN as outputs only when master * i.e. system controller. In this mode can only be the CIC * When not master then enable device mode ATN, IFC & REN as inputs @@ -1266,6 +1262,10 @@ static int bb_attach(struct gpib_board *board, const gpib_board_config_t *config gpiod_direction_output(TE, 1); gpiod_direction_output(PE, 1); } +/* Set main control lines to a known state */ + gpiod_direction_output(IFC, 1); + gpiod_direction_output(REN, 1); + gpiod_direction_output(_ATN, 1); if (strcmp(PINMAP_2, pin_map) == 0) { /* YOGA: enable level shifters */ gpiod_direction_output(YOGA_ENABLE, 1); @@ -1293,8 +1293,6 @@ static int bb_attach(struct gpib_board *board, const gpib_board_config_t *config IRQF_TRIGGER_NONE)) goto bb_attach_fail_r; - ENABLE_IRQ(priv->irq_SRQ, IRQ_TYPE_EDGE_FALLING); - dbg_printk(0, "attached board %d\n", board->minor); goto bb_attach_out; @@ -1306,7 +1304,7 @@ bb_attach_out: return retval; } -static gpib_interface_t bb_interface = { +static struct gpib_interface bb_interface = { .name = NAME, .attach = bb_attach, .detach = bb_detach, @@ -1364,7 +1362,7 @@ inline long usec_diff(struct timespec64 *a, struct timespec64 *b) (a->tv_nsec - b->tv_nsec) / 1000); } -static inline int check_for_eos(struct bb_priv *priv, uint8_t byte) +static inline int check_for_eos(struct bb_priv *priv, u8 byte) { if (priv->eos_check) return 0; diff --git a/drivers/staging/gpib/hp_82335/hp82335.c b/drivers/staging/gpib/hp_82335/hp82335.c index fd23b1cb80f9..d0e47ef77c87 100644 --- a/drivers/staging/gpib/hp_82335/hp82335.c +++ b/drivers/staging/gpib/hp_82335/hp82335.c @@ -4,8 +4,9 @@ * copyright : (C) 2002 by Frank Mori Hess * ***************************************************************************/ -/*should enable ATN interrupts (and update board->status on occurrence), - * implement recovery from bus errors (if necessary) +/* + * should enable ATN interrupts (and update board->status on occurrence), + * implement recovery from bus errors (if necessary) */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -24,12 +25,12 @@ MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("GPIB driver for HP 82335 interface cards"); -static int hp82335_attach(struct gpib_board *board, const gpib_board_config_t *config); +static int hp82335_attach(struct gpib_board *board, const struct gpib_board_config *config); static void hp82335_detach(struct gpib_board *board); static irqreturn_t hp82335_interrupt(int irq, void *arg); // wrappers for interface functions -static int hp82335_read(struct gpib_board *board, uint8_t *buffer, size_t length, +static int hp82335_read(struct gpib_board *board, u8 *buffer, size_t length, int *end, size_t *bytes_read) { struct hp82335_priv *priv = board->private_data; @@ -37,7 +38,7 @@ static int hp82335_read(struct gpib_board *board, uint8_t *buffer, size_t length return tms9914_read(board, &priv->tms9914_priv, buffer, length, end, bytes_read); } -static int hp82335_write(struct gpib_board *board, uint8_t *buffer, size_t length, int send_eoi, +static int hp82335_write(struct gpib_board *board, u8 *buffer, size_t length, int send_eoi, size_t *bytes_written) { struct hp82335_priv *priv = board->private_data; @@ -45,7 +46,7 @@ static int hp82335_write(struct gpib_board *board, uint8_t *buffer, size_t lengt return tms9914_write(board, &priv->tms9914_priv, buffer, length, send_eoi, bytes_written); } -static int hp82335_command(struct gpib_board *board, uint8_t *buffer, size_t length, +static int hp82335_command(struct gpib_board *board, u8 *buffer, size_t length, size_t *bytes_written) { struct hp82335_priv *priv = board->private_data; @@ -67,11 +68,11 @@ static int hp82335_go_to_standby(struct gpib_board *board) return tms9914_go_to_standby(board, &priv->tms9914_priv); } -static void hp82335_request_system_control(struct gpib_board *board, int request_control) +static int hp82335_request_system_control(struct gpib_board *board, int request_control) { struct hp82335_priv *priv = board->private_data; - tms9914_request_system_control(board, &priv->tms9914_priv, request_control); + return tms9914_request_system_control(board, &priv->tms9914_priv, request_control); } static void hp82335_interface_clear(struct gpib_board *board, int assert) @@ -88,7 +89,7 @@ static void hp82335_remote_enable(struct gpib_board *board, int enable) tms9914_remote_enable(board, &priv->tms9914_priv, enable); } -static int hp82335_enable_eos(struct gpib_board *board, uint8_t eos_byte, int compare_8_bits) +static int hp82335_enable_eos(struct gpib_board *board, u8 eos_byte, int compare_8_bits) { struct hp82335_priv *priv = board->private_data; @@ -123,14 +124,14 @@ static int hp82335_secondary_address(struct gpib_board *board, unsigned int addr return tms9914_secondary_address(board, &priv->tms9914_priv, address, enable); } -static int hp82335_parallel_poll(struct gpib_board *board, uint8_t *result) +static int hp82335_parallel_poll(struct gpib_board *board, u8 *result) { struct hp82335_priv *priv = board->private_data; return tms9914_parallel_poll(board, &priv->tms9914_priv, result); } -static void hp82335_parallel_poll_configure(struct gpib_board *board, uint8_t config) +static void hp82335_parallel_poll_configure(struct gpib_board *board, u8 config) { struct hp82335_priv *priv = board->private_data; @@ -144,14 +145,14 @@ static void hp82335_parallel_poll_response(struct gpib_board *board, int ist) tms9914_parallel_poll_response(board, &priv->tms9914_priv, ist); } -static void hp82335_serial_poll_response(struct gpib_board *board, uint8_t status) +static void hp82335_serial_poll_response(struct gpib_board *board, u8 status) { struct hp82335_priv *priv = board->private_data; tms9914_serial_poll_response(board, &priv->tms9914_priv, status); } -static uint8_t hp82335_serial_poll_status(struct gpib_board *board) +static u8 hp82335_serial_poll_status(struct gpib_board *board) { struct hp82335_priv *priv = board->private_data; @@ -179,7 +180,7 @@ static void hp82335_return_to_local(struct gpib_board *board) tms9914_return_to_local(board, &priv->tms9914_priv); } -static gpib_interface_t hp82335_interface = { +static struct gpib_interface hp82335_interface = { .name = "hp82335", .attach = hp82335_attach, .detach = hp82335_detach, @@ -226,12 +227,12 @@ static inline unsigned int tms9914_to_hp82335_offset(unsigned int register_num) return 0x1ff8 + register_num; } -static uint8_t hp82335_read_byte(struct tms9914_priv *priv, unsigned int register_num) +static u8 hp82335_read_byte(struct tms9914_priv *priv, unsigned int register_num) { return tms9914_iomem_read_byte(priv, tms9914_to_hp82335_offset(register_num)); } -static void hp82335_write_byte(struct tms9914_priv *priv, uint8_t data, unsigned int register_num) +static void hp82335_write_byte(struct tms9914_priv *priv, u8 data, unsigned int register_num) { tms9914_iomem_write_byte(priv, data, tms9914_to_hp82335_offset(register_num)); } @@ -243,7 +244,7 @@ static void hp82335_clear_interrupt(struct hp82335_priv *hp_priv) writeb(0, tms_priv->mmiobase + HPREG_INTR_CLEAR); } -static int hp82335_attach(struct gpib_board *board, const gpib_board_config_t *config) +static int hp82335_attach(struct gpib_board *board, const struct gpib_board_config *config) { struct hp82335_priv *hp_priv; struct tms9914_priv *tms_priv; diff --git a/drivers/staging/gpib/hp_82341/hp_82341.c b/drivers/staging/gpib/hp_82341/hp_82341.c index f52e673dc869..1b0822b2a3b8 100644 --- a/drivers/staging/gpib/hp_82341/hp_82341.c +++ b/drivers/staging/gpib/hp_82341/hp_82341.c @@ -25,11 +25,11 @@ MODULE_DESCRIPTION("GPIB driver for hp 82341a/b/c/d boards"); static unsigned short read_and_clear_event_status(struct gpib_board *board); static void set_transfer_counter(struct hp_82341_priv *hp_priv, int count); static int read_transfer_counter(struct hp_82341_priv *hp_priv); -static int hp_82341_write(struct gpib_board *board, uint8_t *buffer, size_t length, int send_eoi, +static int hp_82341_write(struct gpib_board *board, u8 *buffer, size_t length, int send_eoi, size_t *bytes_written); static irqreturn_t hp_82341_interrupt(int irq, void *arg); -static int hp_82341_accel_read(struct gpib_board *board, uint8_t *buffer, size_t length, int *end, +static int hp_82341_accel_read(struct gpib_board *board, u8 *buffer, size_t length, int *end, size_t *bytes_read) { struct hp_82341_priv *hp_priv = board->private_data; @@ -51,11 +51,12 @@ static int hp_82341_accel_read(struct gpib_board *board, uint8_t *buffer, size_t return 0; //disable fifo for the moment outb(DIRECTION_GPIB_TO_HOST_BIT, hp_priv->iobase[3] + BUFFER_CONTROL_REG); - // Handle corner case of board not in holdoff and one byte has slipped in already. - // Also, board sometimes has problems (spurious 1 byte reads) when read fifo is - // started up with board in - // TACS under certain data holdoff conditions. Doing a 1 byte tms9914-style - // read avoids these problems. + /* + * Handle corner case of board not in holdoff and one byte has slipped in already. + * Also, board sometimes has problems (spurious 1 byte reads) when read fifo is + * started up with board in TACS under certain data holdoff conditions. + * Doing a 1 byte tms9914-style read avoids these problems. + */ if (/*tms_priv->holdoff_active == 0 && */length > 1) { size_t num_bytes; @@ -172,7 +173,7 @@ static int restart_write_fifo(struct gpib_board *board, struct hp_82341_priv *hp return 0; } -static int hp_82341_accel_write(struct gpib_board *board, uint8_t *buffer, size_t length, +static int hp_82341_accel_write(struct gpib_board *board, u8 *buffer, size_t length, int send_eoi, size_t *bytes_written) { struct hp_82341_priv *hp_priv = board->private_data; @@ -250,12 +251,12 @@ static int hp_82341_accel_write(struct gpib_board *board, uint8_t *buffer, size_ return 0; } -static int hp_82341_attach(struct gpib_board *board, const gpib_board_config_t *config); +static int hp_82341_attach(struct gpib_board *board, const struct gpib_board_config *config); static void hp_82341_detach(struct gpib_board *board); // wrappers for interface functions -static int hp_82341_read(struct gpib_board *board, uint8_t *buffer, size_t length, int *end, +static int hp_82341_read(struct gpib_board *board, u8 *buffer, size_t length, int *end, size_t *bytes_read) { struct hp_82341_priv *priv = board->private_data; @@ -263,7 +264,7 @@ static int hp_82341_read(struct gpib_board *board, uint8_t *buffer, size_t lengt return tms9914_read(board, &priv->tms9914_priv, buffer, length, end, bytes_read); } -static int hp_82341_write(struct gpib_board *board, uint8_t *buffer, size_t length, int send_eoi, +static int hp_82341_write(struct gpib_board *board, u8 *buffer, size_t length, int send_eoi, size_t *bytes_written) { struct hp_82341_priv *priv = board->private_data; @@ -271,7 +272,7 @@ static int hp_82341_write(struct gpib_board *board, uint8_t *buffer, size_t leng return tms9914_write(board, &priv->tms9914_priv, buffer, length, send_eoi, bytes_written); } -static int hp_82341_command(struct gpib_board *board, uint8_t *buffer, size_t length, +static int hp_82341_command(struct gpib_board *board, u8 *buffer, size_t length, size_t *bytes_written) { struct hp_82341_priv *priv = board->private_data; @@ -293,7 +294,7 @@ static int hp_82341_go_to_standby(struct gpib_board *board) return tms9914_go_to_standby(board, &priv->tms9914_priv); } -static void hp_82341_request_system_control(struct gpib_board *board, int request_control) +static int hp_82341_request_system_control(struct gpib_board *board, int request_control) { struct hp_82341_priv *priv = board->private_data; @@ -302,7 +303,7 @@ static void hp_82341_request_system_control(struct gpib_board *board, int reques else priv->mode_control_bits &= ~SYSTEM_CONTROLLER_BIT; outb(priv->mode_control_bits, priv->iobase[0] + MODE_CONTROL_STATUS_REG); - tms9914_request_system_control(board, &priv->tms9914_priv, request_control); + return tms9914_request_system_control(board, &priv->tms9914_priv, request_control); } static void hp_82341_interface_clear(struct gpib_board *board, int assert) @@ -319,7 +320,7 @@ static void hp_82341_remote_enable(struct gpib_board *board, int enable) tms9914_remote_enable(board, &priv->tms9914_priv, enable); } -static int hp_82341_enable_eos(struct gpib_board *board, uint8_t eos_byte, int compare_8_bits) +static int hp_82341_enable_eos(struct gpib_board *board, u8 eos_byte, int compare_8_bits) { struct hp_82341_priv *priv = board->private_data; @@ -354,14 +355,14 @@ static int hp_82341_secondary_address(struct gpib_board *board, unsigned int add return tms9914_secondary_address(board, &priv->tms9914_priv, address, enable); } -static int hp_82341_parallel_poll(struct gpib_board *board, uint8_t *result) +static int hp_82341_parallel_poll(struct gpib_board *board, u8 *result) { struct hp_82341_priv *priv = board->private_data; return tms9914_parallel_poll(board, &priv->tms9914_priv, result); } -static void hp_82341_parallel_poll_configure(struct gpib_board *board, uint8_t config) +static void hp_82341_parallel_poll_configure(struct gpib_board *board, u8 config) { struct hp_82341_priv *priv = board->private_data; @@ -375,14 +376,14 @@ static void hp_82341_parallel_poll_response(struct gpib_board *board, int ist) tms9914_parallel_poll_response(board, &priv->tms9914_priv, ist); } -static void hp_82341_serial_poll_response(struct gpib_board *board, uint8_t status) +static void hp_82341_serial_poll_response(struct gpib_board *board, u8 status) { struct hp_82341_priv *priv = board->private_data; tms9914_serial_poll_response(board, &priv->tms9914_priv, status); } -static uint8_t hp_82341_serial_poll_status(struct gpib_board *board) +static u8 hp_82341_serial_poll_status(struct gpib_board *board) { struct hp_82341_priv *priv = board->private_data; @@ -410,7 +411,7 @@ static void hp_82341_return_to_local(struct gpib_board *board) tms9914_return_to_local(board, &priv->tms9914_priv); } -static gpib_interface_t hp_82341_unaccel_interface = { +static struct gpib_interface hp_82341_unaccel_interface = { .name = "hp_82341_unaccel", .attach = hp_82341_attach, .detach = hp_82341_detach, @@ -438,7 +439,7 @@ static gpib_interface_t hp_82341_unaccel_interface = { .return_to_local = hp_82341_return_to_local, }; -static gpib_interface_t hp_82341_interface = { +static struct gpib_interface hp_82341_interface = { .name = "hp_82341", .attach = hp_82341_attach, .detach = hp_82341_detach, @@ -479,12 +480,12 @@ static void hp_82341_free_private(struct gpib_board *board) board->private_data = NULL; } -static uint8_t hp_82341_read_byte(struct tms9914_priv *priv, unsigned int register_num) +static u8 hp_82341_read_byte(struct tms9914_priv *priv, unsigned int register_num) { return inb(priv->iobase + register_num); } -static void hp_82341_write_byte(struct tms9914_priv *priv, uint8_t data, unsigned int register_num) +static void hp_82341_write_byte(struct tms9914_priv *priv, u8 data, unsigned int register_num) { outb(data, priv->iobase + register_num); } @@ -619,7 +620,8 @@ static int hp_82341_load_firmware_array(struct hp_82341_priv *hp_priv, return 0; } -static int hp_82341_load_firmware(struct hp_82341_priv *hp_priv, const gpib_board_config_t *config) +static int hp_82341_load_firmware(struct hp_82341_priv *hp_priv, + const struct gpib_board_config *config) { if (config->init_data_length == 0) { if (xilinx_done(hp_priv)) @@ -686,7 +688,7 @@ static int clear_xilinx(struct hp_82341_priv *hp_priv) return 0; } -static int hp_82341_attach(struct gpib_board *board, const gpib_board_config_t *config) +static int hp_82341_attach(struct gpib_board *board, const struct gpib_board_config *config) { struct hp_82341_priv *hp_priv; struct tms9914_priv *tms_priv; diff --git a/drivers/staging/gpib/include/gpibP.h b/drivers/staging/gpib/include/gpibP.h index 0c71a038e444..0af72934ce24 100644 --- a/drivers/staging/gpib/include/gpibP.h +++ b/drivers/staging/gpib/include/gpibP.h @@ -11,23 +11,23 @@ #include "gpib_types.h" #include "gpib_proto.h" -#include "gpib_user.h" +#include "gpib.h" #include "gpib_ioctl.h" #include <linux/fs.h> #include <linux/interrupt.h> #include <linux/io.h> -int gpib_register_driver(gpib_interface_t *interface, struct module *mod); -void gpib_unregister_driver(gpib_interface_t *interface); -struct pci_dev *gpib_pci_get_device(const gpib_board_config_t *config, unsigned int vendor_id, +int gpib_register_driver(struct gpib_interface *interface, struct module *mod); +void gpib_unregister_driver(struct gpib_interface *interface); +struct pci_dev *gpib_pci_get_device(const struct gpib_board_config *config, unsigned int vendor_id, unsigned int device_id, struct pci_dev *from); -struct pci_dev *gpib_pci_get_subsys(const gpib_board_config_t *config, unsigned int vendor_id, +struct pci_dev *gpib_pci_get_subsys(const struct gpib_board_config *config, unsigned int vendor_id, unsigned int device_id, unsigned int ss_vendor, unsigned int ss_device, struct pci_dev *from); -unsigned int num_gpib_events(const gpib_event_queue_t *queue); +unsigned int num_gpib_events(const struct gpib_event_queue *queue); int push_gpib_event(struct gpib_board *board, short event_type); -int pop_gpib_event(struct gpib_board *board, gpib_event_queue_t *queue, short *event_type); +int pop_gpib_event(struct gpib_board *board, struct gpib_event_queue *queue, short *event_type); int gpib_request_pseudo_irq(struct gpib_board *board, irqreturn_t (*handler)(int, void *)); void gpib_free_pseudo_irq(struct gpib_board *board); int gpib_match_device_path(struct device *dev, const char *device_path_in); diff --git a/drivers/staging/gpib/include/gpib_proto.h b/drivers/staging/gpib/include/gpib_proto.h index 2c7dfc02f517..42e736e3b7cd 100644 --- a/drivers/staging/gpib/include/gpib_proto.h +++ b/drivers/staging/gpib/include/gpib_proto.h @@ -8,12 +8,8 @@ int ibopen(struct inode *inode, struct file *filep); int ibclose(struct inode *inode, struct file *file); long ibioctl(struct file *filep, unsigned int cmd, unsigned long arg); -int osInit(void); -void osReset(void); void os_start_timer(struct gpib_board *board, unsigned int usec_timeout); void os_remove_timer(struct gpib_board *board); -void osSendEOI(void); -void osSendEOI(void); void init_gpib_board(struct gpib_board *board); static inline unsigned long usec_to_jiffies(unsigned int usec) { @@ -23,34 +19,31 @@ static inline unsigned long usec_to_jiffies(unsigned int usec) }; int serial_poll_all(struct gpib_board *board, unsigned int usec_timeout); -void init_gpib_descriptor(gpib_descriptor_t *desc); +void init_gpib_descriptor(struct gpib_descriptor *desc); int dvrsp(struct gpib_board *board, unsigned int pad, int sad, - unsigned int usec_timeout, uint8_t *result); -int ibAPWait(struct gpib_board *board, int pad); -int ibAPrsp(struct gpib_board *board, int padsad, char *spb); -void ibAPE(struct gpib_board *board, int pad, int v); + unsigned int usec_timeout, u8 *result); int ibcac(struct gpib_board *board, int sync, int fallback_to_async); -int ibcmd(struct gpib_board *board, uint8_t *buf, size_t length, size_t *bytes_written); +int ibcmd(struct gpib_board *board, u8 *buf, size_t length, size_t *bytes_written); int ibgts(struct gpib_board *board); int ibonline(struct gpib_board *board); int iboffline(struct gpib_board *board); int iblines(const struct gpib_board *board, short *lines); -int ibrd(struct gpib_board *board, uint8_t *buf, size_t length, int *end_flag, size_t *bytes_read); -int ibrpp(struct gpib_board *board, uint8_t *buf); -int ibrsv2(struct gpib_board *board, uint8_t status_byte, int new_reason_for_service); -void ibrsc(struct gpib_board *board, int request_control); +int ibrd(struct gpib_board *board, u8 *buf, size_t length, int *end_flag, size_t *bytes_read); +int ibrpp(struct gpib_board *board, u8 *buf); +int ibrsv2(struct gpib_board *board, u8 status_byte, int new_reason_for_service); +int ibrsc(struct gpib_board *board, int request_control); int ibsic(struct gpib_board *board, unsigned int usec_duration); int ibsre(struct gpib_board *board, int enable); int ibpad(struct gpib_board *board, unsigned int addr); int ibsad(struct gpib_board *board, int addr); int ibeos(struct gpib_board *board, int eos, int eosflags); int ibwait(struct gpib_board *board, int wait_mask, int clear_mask, int set_mask, - int *status, unsigned long usec_timeout, gpib_descriptor_t *desc); -int ibwrt(struct gpib_board *board, uint8_t *buf, size_t cnt, int send_eoi, size_t *bytes_written); + int *status, unsigned long usec_timeout, struct gpib_descriptor *desc); +int ibwrt(struct gpib_board *board, u8 *buf, size_t cnt, int send_eoi, size_t *bytes_written); int ibstatus(struct gpib_board *board); -int general_ibstatus(struct gpib_board *board, const gpib_status_queue_t *device, - int clear_mask, int set_mask, gpib_descriptor_t *desc); +int general_ibstatus(struct gpib_board *board, const struct gpib_status_queue *device, + int clear_mask, int set_mask, struct gpib_descriptor *desc); int io_timed_out(struct gpib_board *board); -int ibppc(struct gpib_board *board, uint8_t configuration); +int ibppc(struct gpib_board *board, u8 configuration); #endif /* GPIB_PROTO_INCLUDED */ diff --git a/drivers/staging/gpib/include/gpib_types.h b/drivers/staging/gpib/include/gpib_types.h index 2d9b9be683f8..db040c80d778 100644 --- a/drivers/staging/gpib/include/gpib_types.h +++ b/drivers/staging/gpib/include/gpib_types.h @@ -8,12 +8,7 @@ #define _GPIB_TYPES_H #ifdef __KERNEL__ -/* gpib_interface_t defines the interface - * between the board-specific details dealt with in the drivers - * and generic interface provided by gpib-common. - * This really should be in a different header file. - */ -#include "gpib_user.h" +#include "gpib.h" #include <linux/atomic.h> #include <linux/device.h> #include <linux/mutex.h> @@ -22,11 +17,10 @@ #include <linux/timer.h> #include <linux/interrupt.h> -typedef struct gpib_interface_struct gpib_interface_t; struct gpib_board; /* config parameters that are only used by driver attach functions */ -typedef struct { +struct gpib_board_config { /* firmware blob */ void *init_data; int init_data_length; @@ -37,11 +31,13 @@ typedef struct { unsigned int ibirq; /* dma channel to use for non-pnp cards (set by core, driver should make local copy) */ unsigned int ibdma; - /* pci bus of card, useful for distinguishing multiple identical pci cards + /* + * pci bus of card, useful for distinguishing multiple identical pci cards * (negative means don't care) */ int pci_bus; - /* pci slot of card, useful for distinguishing multiple identical pci cards + /* + * pci slot of card, useful for distinguishing multiple identical pci cards * (negative means don't care) */ int pci_slot; @@ -49,16 +45,23 @@ typedef struct { char *device_path; /* serial number of hardware to attach */ char *serial_number; -} gpib_board_config_t; +}; -struct gpib_interface_struct { +/* + * struct gpib_interface defines the interface + * between the board-specific details dealt with in the drivers + * and generic interface provided by gpib-common. + * This really should be in a different header file. + */ +struct gpib_interface { /* name of board */ char *name; /* attach() initializes board and allocates resources */ - int (*attach)(struct gpib_board *board, const gpib_board_config_t *config); + int (*attach)(struct gpib_board *board, const struct gpib_board_config *config); /* detach() shuts down board and frees resources */ void (*detach)(struct gpib_board *board); - /* read() should read at most 'length' bytes from the bus into + /* + * read() should read at most 'length' bytes from the bus into * 'buffer'. It should return when it fills the buffer or * encounters an END (EOI and or EOS if appropriate). It should set 'end' * to be nonzero if the read was terminated by an END, otherwise 'end' @@ -68,76 +71,88 @@ struct gpib_interface_struct { * return indicates error. * nbytes returns number of bytes read */ - int (*read)(struct gpib_board *board, uint8_t *buffer, size_t length, int *end, + int (*read)(struct gpib_board *board, u8 *buffer, size_t length, int *end, size_t *bytes_read); - /* write() should write 'length' bytes from buffer to the bus. + /* + * write() should write 'length' bytes from buffer to the bus. * If the boolean value send_eoi is nonzero, then EOI should * be sent along with the last byte. Returns number of bytes * written or negative value on error. */ - int (*write)(struct gpib_board *board, uint8_t *buffer, size_t length, int send_eoi, + int (*write)(struct gpib_board *board, u8 *buffer, size_t length, int send_eoi, size_t *bytes_written); - /* command() writes the command bytes in 'buffer' to the bus + /* + * command() writes the command bytes in 'buffer' to the bus * Returns zero on success or negative value on error. */ - int (*command)(struct gpib_board *board, uint8_t *buffer, size_t length, + int (*command)(struct gpib_board *board, u8 *buffer, size_t length, size_t *bytes_written); - /* Take control (assert ATN). If 'asyncronous' is nonzero, take + /* + * Take control (assert ATN). If 'asyncronous' is nonzero, take * control asyncronously (assert ATN immediately without waiting * for other processes to complete first). Should not return * until board becomes controller in charge. Returns zero no success, * nonzero on error. */ int (*take_control)(struct gpib_board *board, int asyncronous); - /* De-assert ATN. Returns zero on success, nonzer on error. + /* + * De-assert ATN. Returns zero on success, nonzer on error. */ int (*go_to_standby)(struct gpib_board *board); /* request/release control of the IFC and REN lines (system controller) */ - void (*request_system_control)(struct gpib_board *board, int request_control); - /* Asserts or de-asserts 'interface clear' (IFC) depending on + int (*request_system_control)(struct gpib_board *board, int request_control); + /* + * Asserts or de-asserts 'interface clear' (IFC) depending on * boolean value of 'assert' */ void (*interface_clear)(struct gpib_board *board, int assert); - /* Sends remote enable command if 'enable' is nonzero, disables remote mode + /* + * Sends remote enable command if 'enable' is nonzero, disables remote mode * if 'enable' is zero */ void (*remote_enable)(struct gpib_board *board, int enable); - /* enable END for reads, when byte 'eos' is received. If + /* + * enable END for reads, when byte 'eos' is received. If * 'compare_8_bits' is nonzero, then all 8 bits are compared * with the eos bytes. Otherwise only the 7 least significant * bits are compared. */ - int (*enable_eos)(struct gpib_board *board, uint8_t eos, int compare_8_bits); + int (*enable_eos)(struct gpib_board *board, u8 eos, int compare_8_bits); /* disable END on eos byte (END on EOI only)*/ void (*disable_eos)(struct gpib_board *board); /* configure parallel poll */ - void (*parallel_poll_configure)(struct gpib_board *board, uint8_t configuration); + void (*parallel_poll_configure)(struct gpib_board *board, u8 configuration); /* conduct parallel poll */ - int (*parallel_poll)(struct gpib_board *board, uint8_t *result); + int (*parallel_poll)(struct gpib_board *board, u8 *result); /* set/clear ist (individual status bit) */ void (*parallel_poll_response)(struct gpib_board *board, int ist); /* select local parallel poll configuration mode PP2 versus remote PP1 */ void (*local_parallel_poll_mode)(struct gpib_board *board, int local); - /* Returns current status of the bus lines. Should be set to + /* + * Returns current status of the bus lines. Should be set to * NULL if your board does not have the ability to query the * state of the bus lines. */ int (*line_status)(const struct gpib_board *board); - /* updates and returns the board's current status. + /* + * updates and returns the board's current status. * The meaning of the bits are specified in gpib_user.h * in the IBSTA section. The driver does not need to * worry about setting the CMPL, END, TIMO, or ERR bits. */ unsigned int (*update_status)(struct gpib_board *board, unsigned int clear_mask); - /* Sets primary address 0-30 for gpib interface card. + /* + * Sets primary address 0-30 for gpib interface card. */ int (*primary_address)(struct gpib_board *board, unsigned int address); - /* Sets and enables, or disables secondary address 0-30 + /* + * Sets and enables, or disables secondary address 0-30 * for gpib interface card. */ int (*secondary_address)(struct gpib_board *board, unsigned int address, int enable); - /* Sets the byte the board should send in response to a serial poll. + /* + * Sets the byte the board should send in response to a serial poll. * This function should also start or stop requests for service via * IEEE 488.2 reqt/reqf, based on MSS (bit 6 of the status_byte). * If the more flexible serial_poll_response2 is implemented by the @@ -149,8 +164,9 @@ struct gpib_interface_struct { * by IEEE 488.2 section 11.3.3.4.3 "Allowed Coupled Control of * STB, reqt, and reqf". */ - void (*serial_poll_response)(struct gpib_board *board, uint8_t status_byte); - /* Sets the byte the board should send in response to a serial poll. + void (*serial_poll_response)(struct gpib_board *board, u8 status_byte); + /* + * Sets the byte the board should send in response to a serial poll. * This function should also request service via IEEE 488.2 reqt/reqf * based on MSS (bit 6 of the status_byte) and new_reason_for_service. * reqt should be set true if new_reason_for_service is true, @@ -164,11 +180,12 @@ struct gpib_interface_struct { * If this method is left NULL by the driver, then the user library * function ibrsv2 will not work. */ - void (*serial_poll_response2)(struct gpib_board *board, uint8_t status_byte, + void (*serial_poll_response2)(struct gpib_board *board, u8 status_byte, int new_reason_for_service); - /* returns the byte the board will send in response to a serial poll. + /* + * returns the byte the board will send in response to a serial poll. */ - uint8_t (*serial_poll_status)(struct gpib_board *board); + u8 (*serial_poll_status)(struct gpib_board *board); /* adjust T1 delay */ int (*t1_delay)(struct gpib_board *board, unsigned int nano_sec); /* go to local mode */ @@ -179,14 +196,14 @@ struct gpib_interface_struct { unsigned skip_check_for_command_acceptors : 1; }; -typedef struct { +struct gpib_event_queue { struct list_head event_head; spinlock_t lock; // for access to event list unsigned int num_events; unsigned dropped_event : 1; -} gpib_event_queue_t; +}; -static inline void init_event_queue(gpib_event_queue_t *queue) +static inline void init_event_queue(struct gpib_event_queue *queue) { INIT_LIST_HEAD(&queue->event_head); queue->num_events = 0; @@ -210,20 +227,22 @@ static inline void init_gpib_pseudo_irq(struct gpib_pseudo_irq *pseudo_irq) } /* list so we can make a linked list of drivers */ -typedef struct gpib_interface_list_struct { +struct gpib_interface_list { struct list_head list; - gpib_interface_t *interface; + struct gpib_interface *interface; struct module *module; -} gpib_interface_list_t; +}; -/* One struct gpib_board is allocated for each physical board in the computer. +/* + * One struct gpib_board is allocated for each physical board in the computer. * It provides storage for variables local to each board, and interface * functions for performing operations on the board */ struct gpib_board { /* functions used by this board */ - gpib_interface_t *interface; - /* Pointer to module whose use count we should increment when + struct gpib_interface *interface; + /* + * Pointer to module whose use count we should increment when * interface is in use */ struct module *provider_module; @@ -231,20 +250,24 @@ struct gpib_board { u8 *buffer; /* length of buffer */ unsigned int buffer_length; - /* Used to hold the board's current status (see update_status() above) + /* + * Used to hold the board's current status (see update_status() above) */ unsigned long status; - /* Driver should only sleep on this wait queue. It is special in that the + /* + * Driver should only sleep on this wait queue. It is special in that the * core will wake this queue and set the TIMO bit in 'status' when the * watchdog timer times out. */ wait_queue_head_t wait; - /* Lock that only allows one process to access this board at a time. + /* + * Lock that only allows one process to access this board at a time. * Has to be first in any locking order, since it can be locked over * multiple ioctls. */ struct mutex user_mutex; - /* Mutex which compensates for removal of "big kernel lock" from kernel. + /* + * Mutex which compensates for removal of "big kernel lock" from kernel. * Should not be held for extended waits. */ struct mutex big_gpib_mutex; @@ -259,7 +282,8 @@ struct gpib_board { struct device *dev; /* gpib_common device gpibN */ struct device *gpib_dev; - /* 'private_data' can be used as seen fit by the driver to + /* + * 'private_data' can be used as seen fit by the driver to * store additional variables for this board */ void *private_data; @@ -284,34 +308,36 @@ struct gpib_board { /* autospoll kernel thread */ struct task_struct *autospoll_task; /* queue for recording received trigger/clear/ifc events */ - gpib_event_queue_t event_queue; + struct gpib_event_queue event_queue; /* minor number for this board's device file */ int minor; /* struct to deal with polling mode*/ struct gpib_pseudo_irq pseudo_irq; /* error dong autopoll */ atomic_t stuck_srq; - gpib_board_config_t config; + struct gpib_board_config config; /* Flag that indicates whether board is system controller of the bus */ unsigned master : 1; /* individual status bit */ unsigned ist : 1; - /* one means local parallel poll mode ieee 488.1 PP2 (or no parallel poll PP0), + /* + * one means local parallel poll mode ieee 488.1 PP2 (or no parallel poll PP0), * zero means remote parallel poll configuration mode ieee 488.1 PP1 */ unsigned local_ppoll_mode : 1; }; /* element of event queue */ -typedef struct { +struct gpib_event { struct list_head list; short event_type; -} gpib_event_t; +}; -/* Each board has a list of gpib_status_queue_t to keep track of all open devices +/* + * Each board has a list of gpib_status_queue to keep track of all open devices * on the bus, so we know what address to poll when we get a service request */ -typedef struct { +struct gpib_status_queue { /* list_head so we can make a linked list of devices */ struct list_head list; unsigned int pad; /* primary gpib address */ @@ -323,31 +349,31 @@ typedef struct { unsigned int reference_count; /* flags loss of status byte error due to limit on size of queue */ unsigned dropped_byte : 1; -} gpib_status_queue_t; +}; -typedef struct { +struct gpib_status_byte { struct list_head list; u8 poll_byte; -} status_byte_t; +}; -void init_gpib_status_queue(gpib_status_queue_t *device); +void init_gpib_status_queue(struct gpib_status_queue *device); /* Used to store device-descriptor-specific information */ -typedef struct { +struct gpib_descriptor { unsigned int pad; /* primary gpib address */ int sad; /* secondary gpib address (negative means disabled) */ atomic_t io_in_progress; unsigned is_board : 1; unsigned autopoll_enabled : 1; -} gpib_descriptor_t; +}; -typedef struct { +struct gpib_file_private { atomic_t holding_mutex; - gpib_descriptor_t *descriptors[GPIB_MAX_NUM_DESCRIPTORS]; + struct gpib_descriptor *descriptors[GPIB_MAX_NUM_DESCRIPTORS]; /* locked while descriptors are being allocated/deallocated */ struct mutex descriptors_mutex; unsigned got_module : 1; -} gpib_file_private_t; +}; #endif /* __KERNEL__ */ diff --git a/drivers/staging/gpib/include/nec7210.h b/drivers/staging/gpib/include/nec7210.h index 069896456230..312217b4580e 100644 --- a/drivers/staging/gpib/include/nec7210.h +++ b/drivers/staging/gpib/include/nec7210.h @@ -1,4 +1,4 @@ -//* SPDX-License-Identifier: GPL-2.0 */ +/* SPDX-License-Identifier: GPL-2.0 */ /*************************************************************************** * copyright : (C) 2002 by Frank Mori Hess @@ -78,19 +78,19 @@ enum { }; // interface functions -int nec7210_read(struct gpib_board *board, struct nec7210_priv *priv, uint8_t *buffer, +int nec7210_read(struct gpib_board *board, struct nec7210_priv *priv, u8 *buffer, size_t length, int *end, size_t *bytes_read); -int nec7210_write(struct gpib_board *board, struct nec7210_priv *priv, uint8_t *buffer, +int nec7210_write(struct gpib_board *board, struct nec7210_priv *priv, u8 *buffer, size_t length, int send_eoi, size_t *bytes_written); -int nec7210_command(struct gpib_board *board, struct nec7210_priv *priv, uint8_t *buffer, +int nec7210_command(struct gpib_board *board, struct nec7210_priv *priv, u8 *buffer, size_t length, size_t *bytes_written); int nec7210_take_control(struct gpib_board *board, struct nec7210_priv *priv, int syncronous); int nec7210_go_to_standby(struct gpib_board *board, struct nec7210_priv *priv); -void nec7210_request_system_control(struct gpib_board *board, - struct nec7210_priv *priv, int request_control); +int nec7210_request_system_control(struct gpib_board *board, + struct nec7210_priv *priv, int request_control); void nec7210_interface_clear(struct gpib_board *board, struct nec7210_priv *priv, int assert); void nec7210_remote_enable(struct gpib_board *board, struct nec7210_priv *priv, int enable); -int nec7210_enable_eos(struct gpib_board *board, struct nec7210_priv *priv, uint8_t eos_bytes, +int nec7210_enable_eos(struct gpib_board *board, struct nec7210_priv *priv, u8 eos_bytes, int compare_8_bits); void nec7210_disable_eos(struct gpib_board *board, struct nec7210_priv *priv); unsigned int nec7210_update_status(struct gpib_board *board, struct nec7210_priv *priv, @@ -100,14 +100,14 @@ int nec7210_primary_address(const struct gpib_board *board, struct nec7210_priv *priv, unsigned int address); int nec7210_secondary_address(const struct gpib_board *board, struct nec7210_priv *priv, unsigned int address, int enable); -int nec7210_parallel_poll(struct gpib_board *board, struct nec7210_priv *priv, uint8_t *result); -void nec7210_serial_poll_response(struct gpib_board *board, struct nec7210_priv *priv, uint8_t status); +int nec7210_parallel_poll(struct gpib_board *board, struct nec7210_priv *priv, u8 *result); +void nec7210_serial_poll_response(struct gpib_board *board, + struct nec7210_priv *priv, u8 status); void nec7210_parallel_poll_configure(struct gpib_board *board, struct nec7210_priv *priv, unsigned int configuration); void nec7210_parallel_poll_response(struct gpib_board *board, struct nec7210_priv *priv, int ist); -uint8_t nec7210_serial_poll_status(struct gpib_board *board, - struct nec7210_priv *priv); +u8 nec7210_serial_poll_status(struct gpib_board *board, struct nec7210_priv *priv); int nec7210_t1_delay(struct gpib_board *board, struct nec7210_priv *priv, unsigned int nano_sec); void nec7210_return_to_local(const struct gpib_board *board, struct nec7210_priv *priv); @@ -119,18 +119,18 @@ unsigned int nec7210_set_reg_bits(struct nec7210_priv *priv, unsigned int reg, unsigned int mask, unsigned int bits); void nec7210_set_handshake_mode(struct gpib_board *board, struct nec7210_priv *priv, int mode); void nec7210_release_rfd_holdoff(struct gpib_board *board, struct nec7210_priv *priv); -uint8_t nec7210_read_data_in(struct gpib_board *board, struct nec7210_priv *priv, int *end); +u8 nec7210_read_data_in(struct gpib_board *board, struct nec7210_priv *priv, int *end); // wrappers for io functions -uint8_t nec7210_ioport_read_byte(struct nec7210_priv *priv, unsigned int register_num); -void nec7210_ioport_write_byte(struct nec7210_priv *priv, uint8_t data, unsigned int register_num); -uint8_t nec7210_iomem_read_byte(struct nec7210_priv *priv, unsigned int register_num); -void nec7210_iomem_write_byte(struct nec7210_priv *priv, uint8_t data, unsigned int register_num); -uint8_t nec7210_locking_ioport_read_byte(struct nec7210_priv *priv, unsigned int register_num); -void nec7210_locking_ioport_write_byte(struct nec7210_priv *priv, uint8_t data, +u8 nec7210_ioport_read_byte(struct nec7210_priv *priv, unsigned int register_num); +void nec7210_ioport_write_byte(struct nec7210_priv *priv, u8 data, unsigned int register_num); +u8 nec7210_iomem_read_byte(struct nec7210_priv *priv, unsigned int register_num); +void nec7210_iomem_write_byte(struct nec7210_priv *priv, u8 data, unsigned int register_num); +u8 nec7210_locking_ioport_read_byte(struct nec7210_priv *priv, unsigned int register_num); +void nec7210_locking_ioport_write_byte(struct nec7210_priv *priv, u8 data, unsigned int register_num); -uint8_t nec7210_locking_iomem_read_byte(struct nec7210_priv *priv, unsigned int register_num); -void nec7210_locking_iomem_write_byte(struct nec7210_priv *priv, uint8_t data, +u8 nec7210_locking_iomem_read_byte(struct nec7210_priv *priv, unsigned int register_num); +void nec7210_locking_iomem_write_byte(struct nec7210_priv *priv, u8 data, unsigned int register_num); // interrupt service routine diff --git a/drivers/staging/gpib/include/nec7210_registers.h b/drivers/staging/gpib/include/nec7210_registers.h index 888803dd97f9..97c53ac8e805 100644 --- a/drivers/staging/gpib/include/nec7210_registers.h +++ b/drivers/staging/gpib/include/nec7210_registers.h @@ -17,7 +17,8 @@ enum nec7210_chipset { TNT5004, // NI (minor differences to TNT4882) }; -/* nec7210 register numbers (might need to be multiplied by +/* + * nec7210 register numbers (might need to be multiplied by * a board-dependent offset to get actually io address offset) */ // write registers diff --git a/drivers/staging/gpib/include/tms9914.h b/drivers/staging/gpib/include/tms9914.h index 424c95ad85c6..50a9d3b22619 100644 --- a/drivers/staging/gpib/include/tms9914.h +++ b/drivers/staging/gpib/include/tms9914.h @@ -1,4 +1,4 @@ -//* SPDX-License-Identifier: GPL-2.0 */ +/* SPDX-License-Identifier: GPL-2.0 */ /*************************************************************************** * copyright : (C) 2002 by Frank Mori Hess @@ -79,24 +79,25 @@ enum { }; // interface functions -int tms9914_read(struct gpib_board *board, struct tms9914_priv *priv, uint8_t *buffer, +int tms9914_read(struct gpib_board *board, struct tms9914_priv *priv, u8 *buffer, size_t length, int *end, size_t *bytes_read); -int tms9914_write(struct gpib_board *board, struct tms9914_priv *priv, uint8_t *buffer, +int tms9914_write(struct gpib_board *board, struct tms9914_priv *priv, u8 *buffer, size_t length, int send_eoi, size_t *bytes_written); -int tms9914_command(struct gpib_board *board, struct tms9914_priv *priv, uint8_t *buffer, +int tms9914_command(struct gpib_board *board, struct tms9914_priv *priv, u8 *buffer, size_t length, size_t *bytes_written); int tms9914_take_control(struct gpib_board *board, struct tms9914_priv *priv, int syncronous); -/* alternate version of tms9914_take_control which works around buggy tcs +/* + * alternate version of tms9914_take_control which works around buggy tcs * implementation. */ int tms9914_take_control_workaround(struct gpib_board *board, struct tms9914_priv *priv, int syncronous); int tms9914_go_to_standby(struct gpib_board *board, struct tms9914_priv *priv); -void tms9914_request_system_control(struct gpib_board *board, struct tms9914_priv *priv, - int request_control); +int tms9914_request_system_control(struct gpib_board *board, struct tms9914_priv *priv, + int request_control); void tms9914_interface_clear(struct gpib_board *board, struct tms9914_priv *priv, int assert); void tms9914_remote_enable(struct gpib_board *board, struct tms9914_priv *priv, int enable); -int tms9914_enable_eos(struct gpib_board *board, struct tms9914_priv *priv, uint8_t eos_bytes, +int tms9914_enable_eos(struct gpib_board *board, struct tms9914_priv *priv, u8 eos_bytes, int compare_8_bits); void tms9914_disable_eos(struct gpib_board *board, struct tms9914_priv *priv); unsigned int tms9914_update_status(struct gpib_board *board, struct tms9914_priv *priv, @@ -105,13 +106,14 @@ int tms9914_primary_address(struct gpib_board *board, struct tms9914_priv *priv, unsigned int address); int tms9914_secondary_address(struct gpib_board *board, struct tms9914_priv *priv, unsigned int address, int enable); -int tms9914_parallel_poll(struct gpib_board *board, struct tms9914_priv *priv, uint8_t *result); +int tms9914_parallel_poll(struct gpib_board *board, struct tms9914_priv *priv, u8 *result); void tms9914_parallel_poll_configure(struct gpib_board *board, - struct tms9914_priv *priv, uint8_t config); + struct tms9914_priv *priv, u8 config); void tms9914_parallel_poll_response(struct gpib_board *board, struct tms9914_priv *priv, int ist); -void tms9914_serial_poll_response(struct gpib_board *board, struct tms9914_priv *priv, uint8_t status); -uint8_t tms9914_serial_poll_status(struct gpib_board *board, struct tms9914_priv *priv); +void tms9914_serial_poll_response(struct gpib_board *board, + struct tms9914_priv *priv, u8 status); +u8 tms9914_serial_poll_status(struct gpib_board *board, struct tms9914_priv *priv); int tms9914_line_status(const struct gpib_board *board, struct tms9914_priv *priv); unsigned int tms9914_t1_delay(struct gpib_board *board, struct tms9914_priv *priv, unsigned int nano_sec); @@ -124,10 +126,10 @@ void tms9914_release_holdoff(struct tms9914_priv *priv); void tms9914_set_holdoff_mode(struct tms9914_priv *priv, enum tms9914_holdoff_mode mode); // wrappers for io functions -uint8_t tms9914_ioport_read_byte(struct tms9914_priv *priv, unsigned int register_num); -void tms9914_ioport_write_byte(struct tms9914_priv *priv, uint8_t data, unsigned int register_num); -uint8_t tms9914_iomem_read_byte(struct tms9914_priv *priv, unsigned int register_num); -void tms9914_iomem_write_byte(struct tms9914_priv *priv, uint8_t data, unsigned int register_num); +u8 tms9914_ioport_read_byte(struct tms9914_priv *priv, unsigned int register_num); +void tms9914_ioport_write_byte(struct tms9914_priv *priv, u8 data, unsigned int register_num); +u8 tms9914_iomem_read_byte(struct tms9914_priv *priv, unsigned int register_num); +void tms9914_iomem_write_byte(struct tms9914_priv *priv, u8 data, unsigned int register_num); // interrupt service routine irqreturn_t tms9914_interrupt(struct gpib_board *board, struct tms9914_priv *priv); @@ -139,7 +141,8 @@ enum { ms9914_num_registers = 8, }; -/* tms9914 register numbers (might need to be multiplied by +/* + * tms9914 register numbers (might need to be multiplied by * a board-dependent offset to get actually io address offset) */ // write registers diff --git a/drivers/staging/gpib/ines/ines.h b/drivers/staging/gpib/ines/ines.h index ff27f055a0ff..f0210ce2470d 100644 --- a/drivers/staging/gpib/ines/ines.h +++ b/drivers/staging/gpib/ines/ines.h @@ -35,44 +35,6 @@ struct ines_priv { u8 extend_mode_bits; }; -// interface functions -int ines_read(struct gpib_board *board, uint8_t *buffer, size_t length, int *end, size_t *bytes_read); -int ines_write(struct gpib_board *board, uint8_t *buffer, size_t length, - int send_eoi, size_t *bytes_written); -int ines_accel_read(struct gpib_board *board, uint8_t *buffer, size_t length, - int *end, size_t *bytes_read); -int ines_accel_write(struct gpib_board *board, uint8_t *buffer, size_t length, - int send_eoi, size_t *bytes_written); -int ines_command(struct gpib_board *board, uint8_t *buffer, size_t length, size_t *bytes_written); -int ines_take_control(struct gpib_board *board, int synchronous); -int ines_go_to_standby(struct gpib_board *board); -void ines_request_system_control(struct gpib_board *board, int request_control); -void ines_interface_clear(struct gpib_board *board, int assert); -void ines_remote_enable(struct gpib_board *board, int enable); -int ines_enable_eos(struct gpib_board *board, uint8_t eos_byte, int compare_8_bits); -void ines_disable_eos(struct gpib_board *board); -unsigned int ines_update_status(struct gpib_board *board, unsigned int clear_mask); -int ines_primary_address(struct gpib_board *board, unsigned int address); -int ines_secondary_address(struct gpib_board *board, unsigned int address, int enable); -int ines_parallel_poll(struct gpib_board *board, uint8_t *result); -void ines_parallel_poll_configure(struct gpib_board *board, uint8_t config); -void ines_parallel_poll_response(struct gpib_board *board, int ist); -void ines_serial_poll_response(struct gpib_board *board, uint8_t status); -uint8_t ines_serial_poll_status(struct gpib_board *board); -int ines_line_status(const struct gpib_board *board); -int ines_t1_delay(struct gpib_board *board, unsigned int nano_sec); -void ines_return_to_local(struct gpib_board *board); - -// interrupt service routines -irqreturn_t ines_pci_interrupt(int irq, void *arg); -irqreturn_t ines_interrupt(struct gpib_board *board); - -// utility functions -void ines_free_private(struct gpib_board *board); -int ines_generic_attach(struct gpib_board *board); -void ines_online(struct ines_priv *priv, const struct gpib_board *board, int use_accel); -void ines_set_xfer_counter(struct ines_priv *priv, unsigned int count); - /* inb/outb wrappers */ static inline unsigned int ines_inb(struct ines_priv *priv, unsigned int register_number) { @@ -87,11 +49,6 @@ static inline void ines_outb(struct ines_priv *priv, unsigned int value, register_number * priv->nec7210_priv.offset); } -// pcmcia init/cleanup - -int ines_pcmcia_init_module(void); -void ines_pcmcia_cleanup_module(void); - enum ines_regs { // read FIFO_STATUS = 0x8, diff --git a/drivers/staging/gpib/ines/ines_gpib.c b/drivers/staging/gpib/ines/ines_gpib.c index d93eb05dab90..c851fd014f48 100644 --- a/drivers/staging/gpib/ines/ines_gpib.c +++ b/drivers/staging/gpib/ines/ines_gpib.c @@ -25,7 +25,9 @@ MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("GPIB driver for Ines iGPIB 72010"); -int ines_line_status(const struct gpib_board *board) +static irqreturn_t ines_interrupt(struct gpib_board *board); + +static int ines_line_status(const struct gpib_board *board) { int status = VALID_ALL; int bcm_bits; @@ -55,7 +57,7 @@ int ines_line_status(const struct gpib_board *board) return status; } -void ines_set_xfer_counter(struct ines_priv *priv, unsigned int count) +static void ines_set_xfer_counter(struct ines_priv *priv, unsigned int count) { if (count > 0xffff) { pr_err("bug! tried to set xfer counter > 0xffff\n"); @@ -65,7 +67,7 @@ void ines_set_xfer_counter(struct ines_priv *priv, unsigned int count) ines_outb(priv, count & 0xff, XFER_COUNT_LOWER); } -int ines_t1_delay(struct gpib_board *board, unsigned int nano_sec) +static int ines_t1_delay(struct gpib_board *board, unsigned int nano_sec) { struct ines_priv *ines_priv = board->private_data; struct nec7210_priv *nec_priv = &ines_priv->nec7210_priv; @@ -95,7 +97,7 @@ static inline unsigned short num_in_fifo_bytes(struct ines_priv *ines_priv) return ines_inb(ines_priv, IN_FIFO_COUNT); } -static ssize_t pio_read(struct gpib_board *board, struct ines_priv *ines_priv, uint8_t *buffer, +static ssize_t pio_read(struct gpib_board *board, struct ines_priv *ines_priv, u8 *buffer, size_t length, size_t *nbytes) { ssize_t retval = 0; @@ -133,8 +135,8 @@ static ssize_t pio_read(struct gpib_board *board, struct ines_priv *ines_priv, u return retval; } -int ines_accel_read(struct gpib_board *board, uint8_t *buffer, - size_t length, int *end, size_t *bytes_read) +static int ines_accel_read(struct gpib_board *board, u8 *buffer, + size_t length, int *end, size_t *bytes_read) { ssize_t retval = 0; struct ines_priv *ines_priv = board->private_data; @@ -213,8 +215,8 @@ static int ines_write_wait(struct gpib_board *board, struct ines_priv *ines_priv return 0; } -int ines_accel_write(struct gpib_board *board, uint8_t *buffer, size_t length, - int send_eoi, size_t *bytes_written) +static int ines_accel_write(struct gpib_board *board, u8 *buffer, size_t length, + int send_eoi, size_t *bytes_written) { size_t count = 0; ssize_t retval = 0; @@ -264,7 +266,7 @@ int ines_accel_write(struct gpib_board *board, uint8_t *buffer, size_t length, return retval; } -irqreturn_t ines_pci_interrupt(int irq, void *arg) +static irqreturn_t ines_pci_interrupt(int irq, void *arg) { struct gpib_board *board = arg; struct ines_priv *priv = board->private_data; @@ -281,7 +283,7 @@ irqreturn_t ines_pci_interrupt(int irq, void *arg) return ines_interrupt(board); } -irqreturn_t ines_interrupt(struct gpib_board *board) +static irqreturn_t ines_interrupt(struct gpib_board *board) { struct ines_priv *priv = board->private_data; struct nec7210_priv *nec_priv = &priv->nec7210_priv; @@ -295,7 +297,7 @@ irqreturn_t ines_interrupt(struct gpib_board *board) isr3_bits = ines_inb(priv, ISR3); isr4_bits = ines_inb(priv, ISR4); if (isr3_bits & IFC_ACTIVE_BIT) { - push_gpib_event(board, EventIFC); + push_gpib_event(board, EVENT_IFC); wake++; } if (isr3_bits & FIFO_ERROR_BIT) @@ -313,9 +315,9 @@ irqreturn_t ines_interrupt(struct gpib_board *board) return IRQ_HANDLED; } -static int ines_pci_attach(struct gpib_board *board, const gpib_board_config_t *config); -static int ines_pci_accel_attach(struct gpib_board *board, const gpib_board_config_t *config); -static int ines_isa_attach(struct gpib_board *board, const gpib_board_config_t *config); +static int ines_pci_attach(struct gpib_board *board, const struct gpib_board_config *config); +static int ines_pci_accel_attach(struct gpib_board *board, const struct gpib_board_config *config); +static int ines_isa_attach(struct gpib_board *board, const struct gpib_board_config *config); static void ines_pci_detach(struct gpib_board *board); static void ines_isa_detach(struct gpib_board *board); @@ -393,8 +395,8 @@ static struct ines_pci_id pci_ids[] = { static const int num_pci_chips = ARRAY_SIZE(pci_ids); // wrappers for interface functions -int ines_read(struct gpib_board *board, uint8_t *buffer, size_t length, - int *end, size_t *bytes_read) +static int ines_read(struct gpib_board *board, u8 *buffer, size_t length, + int *end, size_t *bytes_read) { struct ines_priv *priv = board->private_data; struct nec7210_priv *nec_priv = &priv->nec7210_priv; @@ -412,134 +414,134 @@ int ines_read(struct gpib_board *board, uint8_t *buffer, size_t length, return retval; } -int ines_write(struct gpib_board *board, uint8_t *buffer, size_t length, int send_eoi, - size_t *bytes_written) +static int ines_write(struct gpib_board *board, u8 *buffer, size_t length, int send_eoi, + size_t *bytes_written) { struct ines_priv *priv = board->private_data; return nec7210_write(board, &priv->nec7210_priv, buffer, length, send_eoi, bytes_written); } -int ines_command(struct gpib_board *board, uint8_t *buffer, size_t length, size_t *bytes_written) +static int ines_command(struct gpib_board *board, u8 *buffer, size_t length, size_t *bytes_written) { struct ines_priv *priv = board->private_data; return nec7210_command(board, &priv->nec7210_priv, buffer, length, bytes_written); } -int ines_take_control(struct gpib_board *board, int synchronous) +static int ines_take_control(struct gpib_board *board, int synchronous) { struct ines_priv *priv = board->private_data; return nec7210_take_control(board, &priv->nec7210_priv, synchronous); } -int ines_go_to_standby(struct gpib_board *board) +static int ines_go_to_standby(struct gpib_board *board) { struct ines_priv *priv = board->private_data; return nec7210_go_to_standby(board, &priv->nec7210_priv); } -void ines_request_system_control(struct gpib_board *board, int request_control) +static int ines_request_system_control(struct gpib_board *board, int request_control) { struct ines_priv *priv = board->private_data; - nec7210_request_system_control(board, &priv->nec7210_priv, request_control); + return nec7210_request_system_control(board, &priv->nec7210_priv, request_control); } -void ines_interface_clear(struct gpib_board *board, int assert) +static void ines_interface_clear(struct gpib_board *board, int assert) { struct ines_priv *priv = board->private_data; nec7210_interface_clear(board, &priv->nec7210_priv, assert); } -void ines_remote_enable(struct gpib_board *board, int enable) +static void ines_remote_enable(struct gpib_board *board, int enable) { struct ines_priv *priv = board->private_data; nec7210_remote_enable(board, &priv->nec7210_priv, enable); } -int ines_enable_eos(struct gpib_board *board, uint8_t eos_byte, int compare_8_bits) +static int ines_enable_eos(struct gpib_board *board, u8 eos_byte, int compare_8_bits) { struct ines_priv *priv = board->private_data; return nec7210_enable_eos(board, &priv->nec7210_priv, eos_byte, compare_8_bits); } -void ines_disable_eos(struct gpib_board *board) +static void ines_disable_eos(struct gpib_board *board) { struct ines_priv *priv = board->private_data; nec7210_disable_eos(board, &priv->nec7210_priv); } -unsigned int ines_update_status(struct gpib_board *board, unsigned int clear_mask) +static unsigned int ines_update_status(struct gpib_board *board, unsigned int clear_mask) { struct ines_priv *priv = board->private_data; return nec7210_update_status(board, &priv->nec7210_priv, clear_mask); } -int ines_primary_address(struct gpib_board *board, unsigned int address) +static int ines_primary_address(struct gpib_board *board, unsigned int address) { struct ines_priv *priv = board->private_data; return nec7210_primary_address(board, &priv->nec7210_priv, address); } -int ines_secondary_address(struct gpib_board *board, unsigned int address, int enable) +static int ines_secondary_address(struct gpib_board *board, unsigned int address, int enable) { struct ines_priv *priv = board->private_data; return nec7210_secondary_address(board, &priv->nec7210_priv, address, enable); } -int ines_parallel_poll(struct gpib_board *board, uint8_t *result) +static int ines_parallel_poll(struct gpib_board *board, u8 *result) { struct ines_priv *priv = board->private_data; return nec7210_parallel_poll(board, &priv->nec7210_priv, result); } -void ines_parallel_poll_configure(struct gpib_board *board, uint8_t config) +static void ines_parallel_poll_configure(struct gpib_board *board, u8 config) { struct ines_priv *priv = board->private_data; nec7210_parallel_poll_configure(board, &priv->nec7210_priv, config); } -void ines_parallel_poll_response(struct gpib_board *board, int ist) +static void ines_parallel_poll_response(struct gpib_board *board, int ist) { struct ines_priv *priv = board->private_data; nec7210_parallel_poll_response(board, &priv->nec7210_priv, ist); } -void ines_serial_poll_response(struct gpib_board *board, uint8_t status) +static void ines_serial_poll_response(struct gpib_board *board, u8 status) { struct ines_priv *priv = board->private_data; nec7210_serial_poll_response(board, &priv->nec7210_priv, status); } -uint8_t ines_serial_poll_status(struct gpib_board *board) +static u8 ines_serial_poll_status(struct gpib_board *board) { struct ines_priv *priv = board->private_data; return nec7210_serial_poll_status(board, &priv->nec7210_priv); } -void ines_return_to_local(struct gpib_board *board) +static void ines_return_to_local(struct gpib_board *board) { struct ines_priv *priv = board->private_data; nec7210_return_to_local(board, &priv->nec7210_priv); } -static gpib_interface_t ines_pci_unaccel_interface = { +static struct gpib_interface ines_pci_unaccel_interface = { .name = "ines_pci_unaccel", .attach = ines_pci_attach, .detach = ines_pci_detach, @@ -567,7 +569,7 @@ static gpib_interface_t ines_pci_unaccel_interface = { .return_to_local = ines_return_to_local, }; -static gpib_interface_t ines_pci_interface = { +static struct gpib_interface ines_pci_interface = { .name = "ines_pci", .attach = ines_pci_accel_attach, .detach = ines_pci_detach, @@ -595,7 +597,7 @@ static gpib_interface_t ines_pci_interface = { .return_to_local = ines_return_to_local, }; -static gpib_interface_t ines_pci_accel_interface = { +static struct gpib_interface ines_pci_accel_interface = { .name = "ines_pci_accel", .attach = ines_pci_accel_attach, .detach = ines_pci_detach, @@ -623,7 +625,7 @@ static gpib_interface_t ines_pci_accel_interface = { .return_to_local = ines_return_to_local, }; -static gpib_interface_t ines_isa_interface = { +static struct gpib_interface ines_isa_interface = { .name = "ines_isa", .attach = ines_isa_attach, .detach = ines_isa_detach, @@ -664,13 +666,13 @@ static int ines_allocate_private(struct gpib_board *board) return 0; } -void ines_free_private(struct gpib_board *board) +static void ines_free_private(struct gpib_board *board) { kfree(board->private_data); board->private_data = NULL; } -int ines_generic_attach(struct gpib_board *board) +static int ines_generic_attach(struct gpib_board *board) { struct ines_priv *ines_priv; struct nec7210_priv *nec_priv; @@ -690,7 +692,7 @@ int ines_generic_attach(struct gpib_board *board) return 0; } -void ines_online(struct ines_priv *ines_priv, const struct gpib_board *board, int use_accel) +static void ines_online(struct ines_priv *ines_priv, const struct gpib_board *board, int use_accel) { struct nec7210_priv *nec_priv = &ines_priv->nec7210_priv; @@ -724,7 +726,7 @@ void ines_online(struct ines_priv *ines_priv, const struct gpib_board *board, in nec7210_set_reg_bits(nec_priv, IMR1, HR_DOIE | HR_DIIE, 0); } -static int ines_common_pci_attach(struct gpib_board *board, const gpib_board_config_t *config) +static int ines_common_pci_attach(struct gpib_board *board, const struct gpib_board_config *config) { struct ines_priv *ines_priv; struct nec7210_priv *nec_priv; @@ -852,7 +854,7 @@ static int ines_common_pci_attach(struct gpib_board *board, const gpib_board_con return 0; } -int ines_pci_attach(struct gpib_board *board, const gpib_board_config_t *config) +static int ines_pci_attach(struct gpib_board *board, const struct gpib_board_config *config) { struct ines_priv *ines_priv; int retval; @@ -867,7 +869,7 @@ int ines_pci_attach(struct gpib_board *board, const gpib_board_config_t *config) return 0; } -int ines_pci_accel_attach(struct gpib_board *board, const gpib_board_config_t *config) +static int ines_pci_accel_attach(struct gpib_board *board, const struct gpib_board_config *config) { struct ines_priv *ines_priv; int retval; @@ -884,7 +886,7 @@ int ines_pci_accel_attach(struct gpib_board *board, const gpib_board_config_t *c static const int ines_isa_iosize = 0x20; -int ines_isa_attach(struct gpib_board *board, const gpib_board_config_t *config) +static int ines_isa_attach(struct gpib_board *board, const struct gpib_board_config *config) { struct ines_priv *ines_priv; struct nec7210_priv *nec_priv; @@ -915,7 +917,7 @@ int ines_isa_attach(struct gpib_board *board, const gpib_board_config_t *config) return 0; } -void ines_pci_detach(struct gpib_board *board) +static void ines_pci_detach(struct gpib_board *board) { struct ines_priv *ines_priv = board->private_data; struct nec7210_priv *nec_priv; @@ -949,7 +951,7 @@ void ines_pci_detach(struct gpib_board *board) ines_free_private(board); } -void ines_isa_detach(struct gpib_board *board) +static void ines_isa_detach(struct gpib_board *board) { struct ines_priv *ines_priv = board->private_data; struct nec7210_priv *nec_priv; @@ -990,48 +992,49 @@ static struct pci_driver ines_pci_driver = { static const int ines_pcmcia_iosize = 0x20; -/* The event() function is this driver's Card Services event handler. - * It will be called by Card Services when an appropriate card status - * event is received. The config() and release() entry points are - * used to configure or release a socket, in response to card insertion - * and ejection events. They are invoked from the gpib event - * handler. +/* + * The event() function is this driver's Card Services event handler. + * It will be called by Card Services when an appropriate card status + * event is received. The config() and release() entry points are + * used to configure or release a socket, in response to card insertion + * and ejection events. They are invoked from the gpib event + * handler. */ static int ines_gpib_config(struct pcmcia_device *link); static void ines_gpib_release(struct pcmcia_device *link); -static int ines_pcmcia_attach(struct gpib_board *board, const gpib_board_config_t *config); -static int ines_pcmcia_accel_attach(struct gpib_board *board, const gpib_board_config_t *config); +static int ines_pcmcia_attach(struct gpib_board *board, const struct gpib_board_config *config); +static int ines_pcmcia_accel_attach(struct gpib_board *board, + const struct gpib_board_config *config); static void ines_pcmcia_detach(struct gpib_board *board); -static irqreturn_t ines_pcmcia_interrupt(int irq, void *arg); static int ines_common_pcmcia_attach(struct gpib_board *board); /* * A linked list of "instances" of the gpib device. Each actual - * PCMCIA card corresponds to one device instance, and is described - * by one dev_link_t structure (defined in ds.h). + * PCMCIA card corresponds to one device instance, and is described + * by one dev_link_t structure (defined in ds.h). * - * You may not want to use a linked list for this -- for example, the - * memory card driver uses an array of dev_link_t pointers, where minor - * device numbers are used to derive the corresponding array index. + * You may not want to use a linked list for this -- for example, the + * memory card driver uses an array of dev_link_t pointers, where minor + * device numbers are used to derive the corresponding array index. */ static struct pcmcia_device *curr_dev; /* - * A dev_link_t structure has fields for most things that are needed - * to keep track of a socket, but there will usually be some device - * specific information that also needs to be kept track of. The - * 'priv' pointer in a dev_link_t structure can be used to point to - * a device-specific private data structure, like this. + * A dev_link_t structure has fields for most things that are needed + * to keep track of a socket, but there will usually be some device + * specific information that also needs to be kept track of. The + * 'priv' pointer in a dev_link_t structure can be used to point to + * a device-specific private data structure, like this. * - * A driver needs to provide a dev_node_t structure for each device - * on a card. In some cases, there is only one device per card (for - * example, ethernet cards, modems). In other cases, there may be - * many actual or logical devices (SCSI adapters, memory cards with - * multiple partitions). The dev_node_t structures need to be kept - * in a linked list starting at the 'dev' field of a dev_link_t - * structure. We allocate them in the card's private data structure, - * because they generally can't be allocated dynamically. + * A driver needs to provide a dev_node_t structure for each device + * on a card. In some cases, there is only one device per card (for + * example, ethernet cards, modems). In other cases, there may be + * many actual or logical devices (SCSI adapters, memory cards with + * multiple partitions). The dev_node_t structures need to be kept + * in a linked list starting at the 'dev' field of a dev_link_t + * structure. We allocate them in the card's private data structure, + * because they generally can't be allocated dynamically. */ struct local_info { @@ -1042,13 +1045,13 @@ struct local_info { }; /* - * gpib_attach() creates an "instance" of the driver, allocating - * local data structures for one device. The device is registered - * with Card Services. + * gpib_attach() creates an "instance" of the driver, allocating + * local data structures for one device. The device is registered + * with Card Services. * - * The dev_link structure is initialized, but we don't actually - * configure the card at this point -- we wait until we receive a - * card insertion event. + * The dev_link structure is initialized, but we don't actually + * configure the card at this point -- we wait until we receive a + * card insertion event. */ static int ines_gpib_probe(struct pcmcia_device *link) { @@ -1079,10 +1082,10 @@ static int ines_gpib_probe(struct pcmcia_device *link) } /* - * This deletes a driver "instance". The device is de-registered - * with Card Services. If it has been released, all local data - * structures are freed. Otherwise, the structures will be freed - * when the device is released. + * This deletes a driver "instance". The device is de-registered + * with Card Services. If it has been released, all local data + * structures are freed. Otherwise, the structures will be freed + * when the device is released. */ static void ines_gpib_remove(struct pcmcia_device *link) { @@ -1103,18 +1106,15 @@ static int ines_gpib_config_iteration(struct pcmcia_device *link, void *priv_dat } /* - * gpib_config() is scheduled to run after a CARD_INSERTION event - * is received, to configure the PCMCIA socket, and to make the - * device available to the system. + * gpib_config() is scheduled to run after a CARD_INSERTION event + * is received, to configure the PCMCIA socket, and to make the + * device available to the system. */ static int ines_gpib_config(struct pcmcia_device *link) { - struct local_info *dev; int retval; void __iomem *virt; - dev = link->priv; - retval = pcmcia_loop_config(link, &ines_gpib_config_iteration, NULL); if (retval) { dev_warn(&link->dev, "no configuration found\n"); @@ -1125,8 +1125,9 @@ static int ines_gpib_config(struct pcmcia_device *link) dev_dbg(&link->dev, "ines_cs: manufacturer: 0x%x card: 0x%x\n", link->manf_id, link->card_id); - /* for the ines card we have to setup the configuration registers in - * attribute memory here + /* + * for the ines card we have to setup the configuration registers in + * attribute memory here */ link->resource[2]->flags |= WIN_MEMORY_TYPE_AM | WIN_DATA_WIDTH_8 | WIN_ENABLE; link->resource[2]->end = 0x1000; @@ -1159,9 +1160,9 @@ static int ines_gpib_config(struct pcmcia_device *link) } /* gpib_config */ /* - * After a card is removed, gpib_release() will unregister the net - * device, and release the PCMCIA configuration. If the device is - * still open, this will be postponed until it is closed. + * After a card is removed, gpib_release() will unregister the net + * device, and release the PCMCIA configuration. If the device is + * still open, this will be postponed until it is closed. */ static void ines_gpib_release(struct pcmcia_device *link) @@ -1210,12 +1211,12 @@ static struct pcmcia_driver ines_gpib_cs_driver = { .resume = ines_gpib_resume, }; -void ines_pcmcia_cleanup_module(void) +static void ines_pcmcia_cleanup_module(void) { pcmcia_unregister_driver(&ines_gpib_cs_driver); } -static gpib_interface_t ines_pcmcia_unaccel_interface = { +static struct gpib_interface ines_pcmcia_unaccel_interface = { .name = "ines_pcmcia_unaccel", .attach = ines_pcmcia_attach, .detach = ines_pcmcia_detach, @@ -1243,7 +1244,7 @@ static gpib_interface_t ines_pcmcia_unaccel_interface = { .return_to_local = ines_return_to_local, }; -static gpib_interface_t ines_pcmcia_accel_interface = { +static struct gpib_interface ines_pcmcia_accel_interface = { .name = "ines_pcmcia_accel", .attach = ines_pcmcia_accel_attach, .detach = ines_pcmcia_detach, @@ -1271,7 +1272,7 @@ static gpib_interface_t ines_pcmcia_accel_interface = { .return_to_local = ines_return_to_local, }; -static gpib_interface_t ines_pcmcia_interface = { +static struct gpib_interface ines_pcmcia_interface = { .name = "ines_pcmcia", .attach = ines_pcmcia_accel_attach, .detach = ines_pcmcia_detach, @@ -1299,14 +1300,14 @@ static gpib_interface_t ines_pcmcia_interface = { .return_to_local = ines_return_to_local, }; -irqreturn_t ines_pcmcia_interrupt(int irq, void *arg) +static irqreturn_t ines_pcmcia_interrupt(int irq, void *arg) { struct gpib_board *board = arg; return ines_interrupt(board); } -int ines_common_pcmcia_attach(struct gpib_board *board) +static int ines_common_pcmcia_attach(struct gpib_board *board) { struct ines_priv *ines_priv; struct nec7210_priv *nec_priv; @@ -1345,7 +1346,7 @@ int ines_common_pcmcia_attach(struct gpib_board *board) return 0; } -int ines_pcmcia_attach(struct gpib_board *board, const gpib_board_config_t *config) +static int ines_pcmcia_attach(struct gpib_board *board, const struct gpib_board_config *config) { struct ines_priv *ines_priv; int retval; @@ -1360,7 +1361,8 @@ int ines_pcmcia_attach(struct gpib_board *board, const gpib_board_config_t *conf return 0; } -int ines_pcmcia_accel_attach(struct gpib_board *board, const gpib_board_config_t *config) +static int ines_pcmcia_accel_attach(struct gpib_board *board, + const struct gpib_board_config *config) { struct ines_priv *ines_priv; int retval; @@ -1375,7 +1377,7 @@ int ines_pcmcia_accel_attach(struct gpib_board *board, const gpib_board_config_t return 0; } -void ines_pcmcia_detach(struct gpib_board *board) +static void ines_pcmcia_detach(struct gpib_board *board) { struct ines_priv *ines_priv = board->private_data; struct nec7210_priv *nec_priv; @@ -1484,7 +1486,7 @@ static void __exit ines_exit_module(void) gpib_unregister_driver(&ines_pci_unaccel_interface); gpib_unregister_driver(&ines_pci_accel_interface); gpib_unregister_driver(&ines_isa_interface); -#ifdef GPIB__PCMCIA +#ifdef CONFIG_GPIB_PCMCIA gpib_unregister_driver(&ines_pcmcia_interface); gpib_unregister_driver(&ines_pcmcia_unaccel_interface); gpib_unregister_driver(&ines_pcmcia_accel_interface); diff --git a/drivers/staging/gpib/lpvo_usb_gpib/lpvo_usb_gpib.c b/drivers/staging/gpib/lpvo_usb_gpib/lpvo_usb_gpib.c index faf96e9cc4a1..3cf5037c0cd2 100644 --- a/drivers/staging/gpib/lpvo_usb_gpib/lpvo_usb_gpib.c +++ b/drivers/staging/gpib/lpvo_usb_gpib/lpvo_usb_gpib.c @@ -36,16 +36,16 @@ MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("GPIB driver for LPVO usb devices"); /* - * Table of devices that work with this driver. + * Table of devices that work with this driver. * - * Currently, only one device is known to be used in the - * lpvo_usb_gpib adapter (FTDI 0403:6001). - * If your adapter uses a different chip, insert a line - * in the following table with proper <Vendor-id>, <Product-id>. + * Currently, only one device is known to be used in the + * lpvo_usb_gpib adapter (FTDI 0403:6001). + * If your adapter uses a different chip, insert a line + * in the following table with proper <Vendor-id>, <Product-id>. * - * To have your chip automatically handled by the driver, - * update files "/usr/local/etc/modprobe.d/lpvo_usb_gpib.conf" - * and /usr/local/etc/udev/rules.d/99-lpvo_usb_gpib.rules. + * To have your chip automatically handled by the driver, + * update files "/usr/local/etc/modprobe.d/lpvo_usb_gpib.conf" + * and /usr/local/etc/udev/rules.d/99-lpvo_usb_gpib.rules. * */ @@ -56,18 +56,18 @@ static const struct usb_device_id skel_table[] = { MODULE_DEVICE_TABLE(usb, skel_table); /* - * *** Diagnostics and Debug *** - * To enable the diagnostic and debug messages either compile with DEBUG set - * or control via the dynamic debug mechanisms. - * The module parameter "debug" controls the sending of debug messages to - * syslog. By default it is set to 0 - * debug = 0: only attach/detach messages are sent - * 1: every action is logged - * 2: extended logging; each single exchanged byte is documented - * (about twice the log volume of [1]) - * To switch debug level: - * At module loading: modprobe lpvo_usb_gpib debug={0,1,2} - * On the fly: echo {0,1,2} > /sys/modules/lpvo_usb_gpib/parameters/debug + * *** Diagnostics and Debug *** + * To enable the diagnostic and debug messages either compile with DEBUG set + * or control via the dynamic debug mechanisms. + * The module parameter "debug" controls the sending of debug messages to + * syslog. By default it is set to 0 + * debug = 0: only attach/detach messages are sent + * 1: every action is logged + * 2: extended logging; each single exchanged byte is documented + * (about twice the log volume of [1]) + * To switch debug level: + * At module loading: modprobe lpvo_usb_gpib debug={0,1,2} + * On the fly: echo {0,1,2} > /sys/modules/lpvo_usb_gpib/parameters/debug */ static int debug; @@ -169,10 +169,10 @@ static void show_status(struct gpib_board *board) } /* - * GLOBAL VARIABLES: required for - * pairing among gpib minor and usb minor. - * MAX_DEV is the max number of usb-gpib adapters; free - * to change as you like, but no more than 32 + * GLOBAL VARIABLES: required for + * pairing among gpib minor and usb minor. + * MAX_DEV is the max number of usb-gpib adapters; free + * to change as you like, but no more than 32 */ #define MAX_DEV 8 @@ -182,7 +182,7 @@ static int assigned_usb_minors; /* mask of filled slots */ static struct mutex minors_lock; /* operations on usb_minors are to be protected */ /* - * usb-skeleton prototypes + * usb-skeleton prototypes */ struct usb_skel; @@ -192,7 +192,7 @@ static int skel_do_open(struct gpib_board *, int); static int skel_do_release(struct gpib_board *); /* - * usec_diff : take difference in MICROsec between two 'timespec' + * usec_diff : take difference in MICROsec between two 'timespec' * (unix time in sec and NANOsec) */ @@ -203,7 +203,7 @@ static inline int usec_diff(struct timespec64 *a, struct timespec64 *b) } /* - * *** these routines are specific to the usb-gpib adapter *** + * *** these routines are specific to the usb-gpib adapter *** */ /** @@ -262,13 +262,11 @@ static int send_command(struct gpib_board *board, char *msg, int leng) } /* - * * set_control_line() - Set the value of a single gpib control line * * @board: the gpib_board_struct data area for this gpib interface * @line: line mask * @value: line new value (0/1) - * */ static int set_control_line(struct gpib_board *board, int line, int value) @@ -368,7 +366,7 @@ static void set_timeout(struct gpib_board *board) } /* - * now the standard interface functions - attach and detach + * now the standard interface functions - attach and detach */ /** @@ -384,7 +382,7 @@ static void set_timeout(struct gpib_board *board) * detach() will be called. Always. */ -static int usb_gpib_attach(struct gpib_board *board, const gpib_board_config_t *config) +static int usb_gpib_attach(struct gpib_board *board, const struct gpib_board_config *config) { int retval, j; u32 base = config->ibbase; @@ -464,7 +462,8 @@ static int usb_gpib_attach(struct gpib_board *board, const gpib_board_config_t * if (retval != ACK) return -EIO; - /* We must setup debug mode because we need the extended instruction + /* + * We must setup debug mode because we need the extended instruction * set to cope with the Core (gpib_common) point of view */ @@ -473,7 +472,8 @@ static int usb_gpib_attach(struct gpib_board *board, const gpib_board_config_t * if (retval != ACK) return -EIO; - /* We must keep REN off after an IFC because so it is + /* + * We must keep REN off after an IFC because so it is * assumed by the Core */ @@ -654,7 +654,8 @@ static int usb_gpib_line_status(const struct gpib_board *board) DIA_LOG(1, "%s\n", "request"); - /* if we are on the wait queue (board->wait), do not hurry + /* + * if we are on the wait queue (board->wait), do not hurry * reading status line; instead, pause a little */ @@ -705,9 +706,10 @@ static int usb_gpib_line_status(const struct gpib_board *board) /* parallel_poll */ -static int usb_gpib_parallel_poll(struct gpib_board *board, uint8_t *result) +static int usb_gpib_parallel_poll(struct gpib_board *board, u8 *result) { - /* request parallel poll asserting ATN | EOI; + /* + * request parallel poll asserting ATN | EOI; * we suppose ATN already asserted */ @@ -909,15 +911,13 @@ static void usb_gpib_remote_enable(struct gpib_board *board, int enable) /* request_system_control */ -static void usb_gpib_request_system_control(struct gpib_board *board, - int request_control) +static int usb_gpib_request_system_control(struct gpib_board *board, int request_control) { - if (request_control) - set_bit(CIC_NUM, &board->status); - else - clear_bit(CIC_NUM, &board->status); + if (!request_control) + return -EINVAL; DIA_LOG(1, "done with %d -> %lx\n", request_control, board->status); + return 0; } /* take_control */ @@ -997,7 +997,7 @@ static int usb_gpib_write(struct gpib_board *board, /* parallel_poll configure */ static void usb_gpib_parallel_poll_configure(struct gpib_board *board, - uint8_t configuration) + u8 configuration) { } @@ -1031,13 +1031,13 @@ static int usb_gpib_secondary_address(struct gpib_board *board, /* serial_poll_response */ -static void usb_gpib_serial_poll_response(struct gpib_board *board, uint8_t status) +static void usb_gpib_serial_poll_response(struct gpib_board *board, u8 status) { } /* serial_poll_status */ -static uint8_t usb_gpib_serial_poll_status(struct gpib_board *board) +static u8 usb_gpib_serial_poll_status(struct gpib_board *board) { return 0; } @@ -1053,7 +1053,7 @@ static int usb_gpib_t1_delay(struct gpib_board *board, unsigned int nano_sec) * *** module dispatch table and init/exit functions *** */ -static gpib_interface_t usb_gpib_interface = { +static struct gpib_interface usb_gpib_interface = { .name = NAME, .attach = usb_gpib_attach, .detach = usb_gpib_detach, @@ -1083,13 +1083,13 @@ static gpib_interface_t usb_gpib_interface = { }; /* - * usb_gpib_init_module(), usb_gpib_exit_module() + * usb_gpib_init_module(), usb_gpib_exit_module() * - * This functions are called every time a new device is detected - * and registered or is removed and unregistered. - * We must take note of created and destroyed usb minors to be used - * when usb_gpib_attach() and usb_gpib_detach() will be called on - * request by gpib_config. + * This functions are called every time a new device is detected + * and registered or is removed and unregistered. + * We must take note of created and destroyed usb minors to be used + * when usb_gpib_attach() and usb_gpib_detach() will be called on + * request by gpib_config. */ static int usb_gpib_init_module(struct usb_interface *interface) @@ -1107,8 +1107,9 @@ static int usb_gpib_init_module(struct usb_interface *interface) goto exit; } } else { - /* check if minor is already registered - maybe useless, but if - * it happens the code is inconsistent somewhere + /* + * check if minor is already registered - maybe useless, but if + * it happens the code is inconsistent somewhere */ for (j = 0 ; j < MAX_DEV ; j++) { @@ -1162,12 +1163,11 @@ exit: } /* - * Default latency time (16 msec) is too long. - * We must use 1 msec (best); anyhow, no more than 5 msec. - * - * Defines and function taken and modified from the kernel tree - * (see ftdi_sio.h and ftdi_sio.c). + * Default latency time (16 msec) is too long. + * We must use 1 msec (best); anyhow, no more than 5 msec. * + * Defines and function taken and modified from the kernel tree + * (see ftdi_sio.h and ftdi_sio.c). */ #define FTDI_SIO_SET_LATENCY_TIMER 9 /* Set the latency timer */ @@ -1235,7 +1235,8 @@ static int write_latency_timer(struct usb_device *udev) /* private defines */ #define MAX_TRANSFER (PAGE_SIZE - 512) -/* MAX_TRANSFER is chosen so that the VM is not stressed by +/* + * MAX_TRANSFER is chosen so that the VM is not stressed by * allocations > PAGE_SIZE and the number of packets in a page * is an integer 512 is the largest possible packet on EHCI */ @@ -1280,7 +1281,7 @@ static void skel_delete(struct kref *kref) } /* - * skel_do_open() - to be called by usb_gpib_attach + * skel_do_open() - to be called by usb_gpib_attach */ static int skel_do_open(struct gpib_board *board, int subminor) @@ -1317,7 +1318,7 @@ exit: } /* - * skel_do_release() - to be called by usb_gpib_detach + * skel_do_release() - to be called by usb_gpib_detach */ static int skel_do_release(struct gpib_board *board) @@ -1340,7 +1341,7 @@ static int skel_do_release(struct gpib_board *board) } /* - * read functions + * read functions */ static void skel_read_bulk_callback(struct urb *urb) @@ -1405,7 +1406,7 @@ static int skel_do_read_io(struct usb_skel *dev, size_t count) } /* - * skel_do_read() - read operations from lpvo_usb_gpib + * skel_do_read() - read operations from lpvo_usb_gpib */ static ssize_t skel_do_read(struct usb_skel *dev, char *buffer, size_t count) @@ -1482,7 +1483,8 @@ retry: * all data has been used * actual IO needs to be done */ - /* it seems that requests for less than dev->bulk_in_size + /* + * it seems that requests for less than dev->bulk_in_size * are not accepted */ rv = skel_do_read_io(dev, dev->bulk_in_size); @@ -1496,7 +1498,8 @@ retry: * data is available - chunk tells us how much shall be copied */ - /* Condition dev->bulk_in_copied > 0 maybe will never happen. In case, + /* + * Condition dev->bulk_in_copied > 0 maybe will never happen. In case, * signal the event and copy using the original procedure, i.e., copy * first two bytes also */ @@ -1551,7 +1554,7 @@ exit: } /* - * write functions + * write functions */ static void skel_write_bulk_callback(struct urb *urb) @@ -1581,7 +1584,7 @@ static void skel_write_bulk_callback(struct urb *urb) } /* - * skel_do_write() - write operations from lpvo_usb_gpib + * skel_do_write() - write operations from lpvo_usb_gpib */ static ssize_t skel_do_write(struct usb_skel *dev, const char *buffer, size_t count) @@ -1686,7 +1689,7 @@ exit: } /* - * services for the user space devices + * services for the user space devices */ #if USER_DEVICE /* conditional compilation of user space device */ @@ -1771,7 +1774,7 @@ static int skel_release(struct inode *inode, struct file *file) } /* - * user space access to read function + * user space access to read function */ static ssize_t skel_read(struct file *file, char __user *buffer, size_t count, @@ -1800,7 +1803,7 @@ static ssize_t skel_read(struct file *file, char __user *buffer, size_t count, } /* - * user space access to write function + * user space access to write function */ static ssize_t skel_write(struct file *file, const char __user *user_buffer, diff --git a/drivers/staging/gpib/nec7210/nec7210.c b/drivers/staging/gpib/nec7210/nec7210.c index 846c0a3fa1dc..34a1cae4f486 100644 --- a/drivers/staging/gpib/nec7210/nec7210.c +++ b/drivers/staging/gpib/nec7210/nec7210.c @@ -23,7 +23,7 @@ MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("GPIB library code for NEC uPD7210"); -int nec7210_enable_eos(struct gpib_board *board, struct nec7210_priv *priv, uint8_t eos_byte, +int nec7210_enable_eos(struct gpib_board *board, struct nec7210_priv *priv, u8 eos_byte, int compare_8_bits) { write_byte(priv, eos_byte, EOSR); @@ -44,7 +44,7 @@ void nec7210_disable_eos(struct gpib_board *board, struct nec7210_priv *priv) } EXPORT_SYMBOL(nec7210_disable_eos); -int nec7210_parallel_poll(struct gpib_board *board, struct nec7210_priv *priv, uint8_t *result) +int nec7210_parallel_poll(struct gpib_board *board, struct nec7210_priv *priv, u8 *result) { int ret; @@ -79,14 +79,15 @@ void nec7210_parallel_poll_response(struct gpib_board *board, struct nec7210_pri write_byte(priv, AUX_CPPF, AUXMR); } EXPORT_SYMBOL(nec7210_parallel_poll_response); -/* This is really only adequate for chips that do a 488.2 style reqt/reqf +/* + * This is really only adequate for chips that do a 488.2 style reqt/reqf * based on bit 6 of the SPMR (see chapter 11.3.3 of 488.2). For simpler chips that simply * set rsv directly based on bit 6, we either need to do more hardware setup to expose * the 488.2 capability (for example with NI chips), or we need to implement the * 488.2 set srv state machine in the driver (if that is even viable). */ void nec7210_serial_poll_response(struct gpib_board *board, - struct nec7210_priv *priv, uint8_t status) + struct nec7210_priv *priv, u8 status) { unsigned long flags; @@ -103,7 +104,7 @@ void nec7210_serial_poll_response(struct gpib_board *board, } EXPORT_SYMBOL(nec7210_serial_poll_response); -uint8_t nec7210_serial_poll_status(struct gpib_board *board, struct nec7210_priv *priv) +u8 nec7210_serial_poll_status(struct gpib_board *board, struct nec7210_priv *priv) { return read_byte(priv, SPSR); } @@ -202,7 +203,8 @@ unsigned int nec7210_update_status_nolock(struct gpib_board *board, struct nec72 set_bit(SPOLL_NUM, &board->status); } - /* we rely on the interrupt handler to set the + /* + * we rely on the interrupt handler to set the * rest of the status bits */ @@ -251,7 +253,7 @@ void nec7210_set_handshake_mode(struct gpib_board *board, struct nec7210_priv *p } EXPORT_SYMBOL(nec7210_set_handshake_mode); -uint8_t nec7210_read_data_in(struct gpib_board *board, struct nec7210_priv *priv, int *end) +u8 nec7210_read_data_in(struct gpib_board *board, struct nec7210_priv *priv, int *end) { unsigned long flags; u8 data; @@ -330,14 +332,15 @@ int nec7210_go_to_standby(struct gpib_board *board, struct nec7210_priv *priv) } EXPORT_SYMBOL(nec7210_go_to_standby); -void nec7210_request_system_control(struct gpib_board *board, struct nec7210_priv *priv, - int request_control) +int nec7210_request_system_control(struct gpib_board *board, struct nec7210_priv *priv, + int request_control) { if (request_control == 0) { write_byte(priv, AUX_CREN, AUXMR); write_byte(priv, AUX_CIFC, AUXMR); write_byte(priv, AUX_DSC, AUXMR); } + return 0; } EXPORT_SYMBOL(nec7210_request_system_control); @@ -415,7 +418,7 @@ static inline short nec7210_atn_has_changed(struct gpib_board *board, struct nec return -1; } -int nec7210_command(struct gpib_board *board, struct nec7210_priv *priv, uint8_t +int nec7210_command(struct gpib_board *board, struct nec7210_priv *priv, u8 *buffer, size_t length, size_t *bytes_written) { int retval = 0; @@ -464,7 +467,7 @@ int nec7210_command(struct gpib_board *board, struct nec7210_priv *priv, uint8_t } EXPORT_SYMBOL(nec7210_command); -static int pio_read(struct gpib_board *board, struct nec7210_priv *priv, uint8_t *buffer, +static int pio_read(struct gpib_board *board, struct nec7210_priv *priv, u8 *buffer, size_t length, int *end, size_t *bytes_read) { ssize_t retval = 0; @@ -482,7 +485,8 @@ static int pio_read(struct gpib_board *board, struct nec7210_priv *priv, uint8_t } if (test_bit(READ_READY_BN, &priv->state)) { if (*bytes_read == 0) { - /* We set the handshake mode here because we know + /* + * We set the handshake mode here because we know * no new bytes will arrive (it has already arrived * and is awaiting being read out of the chip) while we are changing * modes. This ensures we can reliably keep track @@ -568,7 +572,7 @@ static ssize_t __dma_read(struct gpib_board *board, struct nec7210_priv *priv, s return retval ? retval : count; } -static ssize_t dma_read(struct gpib_board *board, struct nec7210_priv *priv, uint8_t *buffer, +static ssize_t dma_read(struct gpib_board *board, struct nec7210_priv *priv, u8 *buffer, size_t length) { size_t remain = length; @@ -595,7 +599,7 @@ static ssize_t dma_read(struct gpib_board *board, struct nec7210_priv *priv, uin } #endif -int nec7210_read(struct gpib_board *board, struct nec7210_priv *priv, uint8_t *buffer, +int nec7210_read(struct gpib_board *board, struct nec7210_priv *priv, u8 *buffer, size_t length, int *end, size_t *bytes_read) { ssize_t retval = 0; @@ -642,7 +646,7 @@ static int pio_write_wait(struct gpib_board *board, struct nec7210_priv *priv, return 0; } -static int pio_write(struct gpib_board *board, struct nec7210_priv *priv, uint8_t *buffer, +static int pio_write(struct gpib_board *board, struct nec7210_priv *priv, u8 *buffer, size_t length, size_t *bytes_written) { size_t last_count = 0; @@ -662,7 +666,8 @@ static int pio_write(struct gpib_board *board, struct nec7210_priv *priv, uint8_ if (retval == -EIO) { /* resend last byte on bus error */ *bytes_written = last_count; - /* we can get unrecoverable bus errors, + /* + * we can get unrecoverable bus errors, * so give up after a while */ bus_error_count++; @@ -742,7 +747,7 @@ static ssize_t __dma_write(struct gpib_board *board, struct nec7210_priv *priv, return retval ? retval : length; } -static ssize_t dma_write(struct gpib_board *board, struct nec7210_priv *priv, uint8_t *buffer, +static ssize_t dma_write(struct gpib_board *board, struct nec7210_priv *priv, u8 *buffer, size_t length) { size_t remain = length; @@ -767,7 +772,7 @@ static ssize_t dma_write(struct gpib_board *board, struct nec7210_priv *priv, ui } #endif int nec7210_write(struct gpib_board *board, struct nec7210_priv *priv, - uint8_t *buffer, size_t length, int send_eoi, + u8 *buffer, size_t length, int send_eoi, size_t *bytes_written) { int retval = 0; @@ -805,7 +810,8 @@ int nec7210_write(struct gpib_board *board, struct nec7210_priv *priv, if (send_eoi) { size_t num_bytes; - /* We need to wait to make sure we will immediately be able to write the data byte + /* + * We need to wait to make sure we will immediately be able to write the data byte * into the chip before sending the associated AUX_SEOI command. This is really * only needed for length==1 since otherwise the earlier calls to pio_write * will have dont the wait already. @@ -827,7 +833,7 @@ int nec7210_write(struct gpib_board *board, struct nec7210_priv *priv, EXPORT_SYMBOL(nec7210_write); /* - * interrupt service routine + * interrupt service routine */ irqreturn_t nec7210_interrupt(struct gpib_board *board, struct nec7210_priv *priv) { @@ -932,13 +938,13 @@ irqreturn_t nec7210_interrupt_have_status(struct gpib_board *board, // ignore device clear events if we are controller in charge if ((address_status_bits & HR_CIC) == 0) { - push_gpib_event(board, EventDevClr); + push_gpib_event(board, EVENT_DEV_CLR); set_bit(DEV_CLEAR_BN, &priv->state); } } if (status1 & HR_DET) - push_gpib_event(board, EventDevTrg); + push_gpib_event(board, EVENT_DEV_TRG); // Addressing status has changed if (status2 & HR_ADSC) @@ -1012,16 +1018,17 @@ EXPORT_SYMBOL(nec7210_board_online); #ifdef CONFIG_HAS_IOPORT /* wrappers for io */ -uint8_t nec7210_ioport_read_byte(struct nec7210_priv *priv, unsigned int register_num) +u8 nec7210_ioport_read_byte(struct nec7210_priv *priv, unsigned int register_num) { return inb(priv->iobase + register_num * priv->offset); } EXPORT_SYMBOL(nec7210_ioport_read_byte); -void nec7210_ioport_write_byte(struct nec7210_priv *priv, uint8_t data, unsigned int register_num) +void nec7210_ioport_write_byte(struct nec7210_priv *priv, u8 data, unsigned int register_num) { if (register_num == AUXMR) - /* locking makes absolutely sure noone accesses the + /* + * locking makes absolutely sure noone accesses the * AUXMR register faster than once per microsecond */ nec7210_locking_ioport_write_byte(priv, data, register_num); @@ -1031,7 +1038,7 @@ void nec7210_ioport_write_byte(struct nec7210_priv *priv, uint8_t data, unsigned EXPORT_SYMBOL(nec7210_ioport_write_byte); /* locking variants of io wrappers, for chips that page-in registers */ -uint8_t nec7210_locking_ioport_read_byte(struct nec7210_priv *priv, unsigned int register_num) +u8 nec7210_locking_ioport_read_byte(struct nec7210_priv *priv, unsigned int register_num) { u8 retval; unsigned long flags; @@ -1043,7 +1050,7 @@ uint8_t nec7210_locking_ioport_read_byte(struct nec7210_priv *priv, unsigned int } EXPORT_SYMBOL(nec7210_locking_ioport_read_byte); -void nec7210_locking_ioport_write_byte(struct nec7210_priv *priv, uint8_t data, +void nec7210_locking_ioport_write_byte(struct nec7210_priv *priv, u8 data, unsigned int register_num) { unsigned long flags; @@ -1057,16 +1064,17 @@ void nec7210_locking_ioport_write_byte(struct nec7210_priv *priv, uint8_t data, EXPORT_SYMBOL(nec7210_locking_ioport_write_byte); #endif -uint8_t nec7210_iomem_read_byte(struct nec7210_priv *priv, unsigned int register_num) +u8 nec7210_iomem_read_byte(struct nec7210_priv *priv, unsigned int register_num) { return readb(priv->mmiobase + register_num * priv->offset); } EXPORT_SYMBOL(nec7210_iomem_read_byte); -void nec7210_iomem_write_byte(struct nec7210_priv *priv, uint8_t data, unsigned int register_num) +void nec7210_iomem_write_byte(struct nec7210_priv *priv, u8 data, unsigned int register_num) { if (register_num == AUXMR) - /* locking makes absolutely sure noone accesses the + /* + * locking makes absolutely sure noone accesses the * AUXMR register faster than once per microsecond */ nec7210_locking_iomem_write_byte(priv, data, register_num); @@ -1075,7 +1083,7 @@ void nec7210_iomem_write_byte(struct nec7210_priv *priv, uint8_t data, unsigned } EXPORT_SYMBOL(nec7210_iomem_write_byte); -uint8_t nec7210_locking_iomem_read_byte(struct nec7210_priv *priv, unsigned int register_num) +u8 nec7210_locking_iomem_read_byte(struct nec7210_priv *priv, unsigned int register_num) { u8 retval; unsigned long flags; @@ -1087,7 +1095,7 @@ uint8_t nec7210_locking_iomem_read_byte(struct nec7210_priv *priv, unsigned int } EXPORT_SYMBOL(nec7210_locking_iomem_read_byte); -void nec7210_locking_iomem_write_byte(struct nec7210_priv *priv, uint8_t data, +void nec7210_locking_iomem_write_byte(struct nec7210_priv *priv, u8 data, unsigned int register_num) { unsigned long flags; diff --git a/drivers/staging/gpib/ni_usb/ni_usb_gpib.c b/drivers/staging/gpib/ni_usb/ni_usb_gpib.c index 9f1b9927f025..7cf25c95787f 100644 --- a/drivers/staging/gpib/ni_usb/ni_usb_gpib.c +++ b/drivers/staging/gpib/ni_usb/ni_usb_gpib.c @@ -74,7 +74,8 @@ static unsigned short ni_usb_timeout_code(unsigned int usec) return 0xff; else if (usec <= 300000000) return 0x01; - /* NI driver actually uses 0xff for timeout T1000s, which is a bug in their code. + /* + * NI driver actually uses 0xff for timeout T1000s, which is a bug in their code. * I've verified on a usb-b that a code of 0x2 is correct for a 1000 sec timeout */ else if (usec <= 1000000000) @@ -92,7 +93,8 @@ static void ni_usb_bulk_complete(struct urb *urb) static void ni_usb_timeout_handler(struct timer_list *t) { - struct ni_usb_priv *ni_priv = from_timer(ni_priv, t, bulk_timer); + struct ni_usb_priv *ni_priv = timer_container_of(ni_priv, t, + bulk_timer); struct ni_usb_urb_ctx *context = &ni_priv->context; context->timed_out = 1; @@ -232,7 +234,8 @@ static int ni_usb_nonblocking_receive_bulk_msg(struct ni_usb_priv *ni_priv, mutex_unlock(&ni_priv->bulk_transfer_lock); if (interruptible) { if (wait_for_completion_interruptible(&context->complete)) { - /* If we got interrupted by a signal while + /* + * If we got interrupted by a signal while * waiting for the usb gpib to respond, we * should send a stop command so it will * finish up with whatever it was doing and @@ -240,8 +243,9 @@ static int ni_usb_nonblocking_receive_bulk_msg(struct ni_usb_priv *ni_priv, */ ni_usb_stop(ni_priv); retval = -ERESTARTSYS; - /* now do an uninterruptible wait, it shouldn't take long - * for the board to respond now. + /* + * now do an uninterruptible wait, it shouldn't take long + * for the board to respond now. */ wait_for_completion(&context->complete); } @@ -586,7 +590,7 @@ static int ni_usb_write_registers(struct ni_usb_priv *ni_priv, } // interface functions -static int ni_usb_read(struct gpib_board *board, uint8_t *buffer, size_t length, +static int ni_usb_read(struct gpib_board *board, u8 *buffer, size_t length, int *end, size_t *bytes_read) { int retval, parse_retval; @@ -684,7 +688,8 @@ static int ni_usb_read(struct gpib_board *board, uint8_t *buffer, size_t length, retval = 0; break; case NIUSB_ABORTED_ERROR: - /* this is expected if ni_usb_receive_bulk_msg got + /* + * this is expected if ni_usb_receive_bulk_msg got * interrupted by a signal and returned -ERESTARTSYS */ break; @@ -716,7 +721,7 @@ static int ni_usb_read(struct gpib_board *board, uint8_t *buffer, size_t length, return retval; } -static int ni_usb_write(struct gpib_board *board, uint8_t *buffer, size_t length, +static int ni_usb_write(struct gpib_board *board, u8 *buffer, size_t length, int send_eoi, size_t *bytes_written) { int retval; @@ -794,7 +799,8 @@ static int ni_usb_write(struct gpib_board *board, uint8_t *buffer, size_t length retval = 0; break; case NIUSB_ABORTED_ERROR: - /* this is expected if ni_usb_receive_bulk_msg got + /* + * this is expected if ni_usb_receive_bulk_msg got * interrupted by a signal and returned -ERESTARTSYS */ break; @@ -819,7 +825,7 @@ static int ni_usb_write(struct gpib_board *board, uint8_t *buffer, size_t length return retval; } -static int ni_usb_command_chunk(struct gpib_board *board, uint8_t *buffer, size_t length, +static int ni_usb_command_chunk(struct gpib_board *board, u8 *buffer, size_t length, size_t *command_bytes_written) { int retval; @@ -893,7 +899,8 @@ static int ni_usb_command_chunk(struct gpib_board *board, uint8_t *buffer, size_ case NIUSB_NO_ERROR: break; case NIUSB_ABORTED_ERROR: - /* this is expected if ni_usb_receive_bulk_msg got + /* + * this is expected if ni_usb_receive_bulk_msg got * interrupted by a signal and returned -ERESTARTSYS */ break; @@ -912,7 +919,7 @@ static int ni_usb_command_chunk(struct gpib_board *board, uint8_t *buffer, size_ return 0; } -static int ni_usb_command(struct gpib_board *board, uint8_t *buffer, size_t length, +static int ni_usb_command(struct gpib_board *board, u8 *buffer, size_t length, size_t *bytes_written) { size_t count; @@ -1049,7 +1056,7 @@ static int ni_usb_go_to_standby(struct gpib_board *board) return 0; } -static void ni_usb_request_system_control(struct gpib_board *board, int request_control) +static int ni_usb_request_system_control(struct gpib_board *board, int request_control) { int retval; struct ni_usb_priv *ni_priv = board->private_data; @@ -1059,7 +1066,7 @@ static void ni_usb_request_system_control(struct gpib_board *board, int request_ unsigned int ibsta; if (!ni_priv->bus_interface) - return; // -ENODEV; + return -ENODEV; usb_dev = interface_to_usbdev(ni_priv->bus_interface); if (request_control) { writes[i].device = NIUSB_SUBDEV_TNT4882; @@ -1091,12 +1098,12 @@ static void ni_usb_request_system_control(struct gpib_board *board, int request_ retval = ni_usb_write_registers(ni_priv, writes, i, &ibsta); if (retval < 0) { dev_err(&usb_dev->dev, "register write failed, retval=%i\n", retval); - return; // retval; + return retval; } if (!request_control) ni_priv->ren_state = 0; ni_usb_soft_update_status(board, ibsta, 0); - return; // 0; + return 0; } //FIXME maybe the interface should have a "pulse interface clear" function that can return an error? @@ -1176,7 +1183,7 @@ static void ni_usb_remote_enable(struct gpib_board *board, int enable) return;// 0; } -static int ni_usb_enable_eos(struct gpib_board *board, uint8_t eos_byte, int compare_8_bits) +static int ni_usb_enable_eos(struct gpib_board *board, u8 eos_byte, int compare_8_bits) { struct ni_usb_priv *ni_priv = board->private_data; @@ -1192,8 +1199,9 @@ static int ni_usb_enable_eos(struct gpib_board *board, uint8_t eos_byte, int com static void ni_usb_disable_eos(struct gpib_board *board) { struct ni_usb_priv *ni_priv = board->private_data; - /* adapter gets unhappy if you don't zero all the bits - * for the eos mode and eos char (returns error 4 on reads). + /* + * adapter gets unhappy if you don't zero all the bits + * for the eos mode and eos char (returns error 4 on reads). */ ni_priv->eos_mode = 0; ni_priv->eos_char = 0; @@ -1334,7 +1342,7 @@ static int ni_usb_secondary_address(struct gpib_board *board, unsigned int addre return 0; } -static int ni_usb_parallel_poll(struct gpib_board *board, uint8_t *result) +static int ni_usb_parallel_poll(struct gpib_board *board, u8 *result) { int retval; struct ni_usb_priv *ni_priv = board->private_data; @@ -1389,7 +1397,7 @@ static int ni_usb_parallel_poll(struct gpib_board *board, uint8_t *result) return retval; } -static void ni_usb_parallel_poll_configure(struct gpib_board *board, uint8_t config) +static void ni_usb_parallel_poll_configure(struct gpib_board *board, u8 config) { int retval; struct ni_usb_priv *ni_priv = board->private_data; @@ -1467,7 +1475,7 @@ static void ni_usb_serial_poll_response(struct gpib_board *board, u8 status) return;// 0; } -static uint8_t ni_usb_serial_poll_status(struct gpib_board *board) +static u8 ni_usb_serial_poll_status(struct gpib_board *board) { return 0; } @@ -2045,8 +2053,10 @@ static int ni_usb_hs_wait_for_ready(struct ni_usb_priv *ni_priv) unexpected = 1; } ++j; - // MC usb-488 (and sometimes NI-USB-HS?) sends 0x8 here; MC usb-488A sends 0x7 here - // NI-USB-HS+ sends 0x0 + /* + * MC usb-488 (and sometimes NI-USB-HS?) sends 0x8 here; MC usb-488A sends 0x7 here + * NI-USB-HS+ sends 0x0 + */ if (buffer[j] != 0x1 && buffer[j] != 0x8 && buffer[j] != 0x7 && buffer[j] != 0x0) { // [3] dev_err(&usb_dev->dev, "unexpected data: buffer[%i]=0x%x, expected 0x0, 0x1, 0x7 or 0x8\n", @@ -2127,7 +2137,8 @@ ready_out: return retval; } -/* This does some extra init for HS+ models, as observed on Windows. One of the +/* + * This does some extra init for HS+ models, as observed on Windows. One of the * control requests causes the LED to stop blinking. * I'm not sure what the other 2 requests do. None of these requests are actually required * for the adapter to work, maybe they do some init for the analyzer interface @@ -2198,14 +2209,14 @@ static int ni_usb_hs_plus_extra_init(struct ni_usb_priv *ni_priv) } static inline int ni_usb_device_match(struct usb_interface *interface, - const gpib_board_config_t *config) + const struct gpib_board_config *config) { if (gpib_match_device_path(&interface->dev, config->device_path) == 0) return 0; return 1; } -static int ni_usb_attach(struct gpib_board *board, const gpib_board_config_t *config) +static int ni_usb_attach(struct gpib_board *board, const struct gpib_board_config *config) { int retval; int i, index; @@ -2343,8 +2354,10 @@ static void ni_usb_detach(struct gpib_board *board) struct ni_usb_priv *ni_priv; mutex_lock(&ni_usb_hotplug_lock); -// under windows, software unplug does chip_reset nec7210 aux command, -// then writes 0x0 to address 0x10 of device 3 + /* + * under windows, software unplug does chip_reset nec7210 aux command, + * then writes 0x0 to address 0x10 of device 3 + */ ni_priv = board->private_data; if (ni_priv) { if (ni_priv->bus_interface) { @@ -2361,7 +2374,7 @@ static void ni_usb_detach(struct gpib_board *board) mutex_unlock(&ni_usb_hotplug_lock); } -static gpib_interface_t ni_usb_gpib_interface = { +static struct gpib_interface ni_usb_gpib_interface = { .name = "ni_usb_b", .attach = ni_usb_attach, .detach = ni_usb_detach, diff --git a/drivers/staging/gpib/ni_usb/ni_usb_gpib.h b/drivers/staging/gpib/ni_usb/ni_usb_gpib.h index 4b297db09a9b..b011e131201c 100644 --- a/drivers/staging/gpib/ni_usb/ni_usb_gpib.h +++ b/drivers/staging/gpib/ni_usb/ni_usb_gpib.h @@ -113,27 +113,37 @@ enum ni_usb_bulk_ids { enum ni_usb_error_codes { NIUSB_NO_ERROR = 0, - /* NIUSB_ABORTED_ERROR occurs when I/O is interrupted early by - * doing a NI_USB_STOP_REQUEST on the control endpoint. + /* + * NIUSB_ABORTED_ERROR occurs when I/O is interrupted early by + * doing a NI_USB_STOP_REQUEST on the control endpoint. */ NIUSB_ABORTED_ERROR = 1, - // NIUSB_READ_ATN_ERROR occurs when you do a board read while - // ATN is set + /* + * NIUSB_READ_ATN_ERROR occurs when you do a board read while + * ATN is set + */ NIUSB_ATN_STATE_ERROR = 2, - // NIUSB_ADDRESSING_ERROR occurs when you do a board - // read/write as CIC but are not in LACS/TACS + /* + * NIUSB_ADDRESSING_ERROR occurs when you do a board + * read/write as CIC but are not in LACS/TACS + */ NIUSB_ADDRESSING_ERROR = 3, - /* NIUSB_EOSMODE_ERROR occurs on reads if any eos mode or char + /* + * NIUSB_EOSMODE_ERROR occurs on reads if any eos mode or char * bits are set when REOS is not set. * Have also seen error 4 if you try to send more than 16 * command bytes at once on a usb-b. */ NIUSB_EOSMODE_ERROR = 4, - // NIUSB_NO_BUS_ERROR occurs when you try to write a command - // byte but there are no devices connected to the gpib bus + /* + * NIUSB_NO_BUS_ERROR occurs when you try to write a command + * byte but there are no devices connected to the gpib bus + */ NIUSB_NO_BUS_ERROR = 5, - // NIUSB_NO_LISTENER_ERROR occurs when you do a board write as - // CIC with no listener + /* + * NIUSB_NO_LISTENER_ERROR occurs when you do a board write as + * CIC with no listener + */ NIUSB_NO_LISTENER_ERROR = 8, // get NIUSB_TIMEOUT_ERROR on board read/write timeout NIUSB_TIMEOUT_ERROR = 10, diff --git a/drivers/staging/gpib/pc2/pc2_gpib.c b/drivers/staging/gpib/pc2/pc2_gpib.c index 96d3c09f2273..2282492025b7 100644 --- a/drivers/staging/gpib/pc2/pc2_gpib.c +++ b/drivers/staging/gpib/pc2/pc2_gpib.c @@ -90,7 +90,7 @@ irqreturn_t pc2a_interrupt(int irq, void *arg) } // wrappers for interface functions -static int pc2_read(struct gpib_board *board, uint8_t *buffer, size_t length, int *end, +static int pc2_read(struct gpib_board *board, u8 *buffer, size_t length, int *end, size_t *bytes_read) { struct pc2_priv *priv = board->private_data; @@ -98,7 +98,7 @@ static int pc2_read(struct gpib_board *board, uint8_t *buffer, size_t length, in return nec7210_read(board, &priv->nec7210_priv, buffer, length, end, bytes_read); } -static int pc2_write(struct gpib_board *board, uint8_t *buffer, size_t length, int send_eoi, +static int pc2_write(struct gpib_board *board, u8 *buffer, size_t length, int send_eoi, size_t *bytes_written) { struct pc2_priv *priv = board->private_data; @@ -106,7 +106,8 @@ static int pc2_write(struct gpib_board *board, uint8_t *buffer, size_t length, i return nec7210_write(board, &priv->nec7210_priv, buffer, length, send_eoi, bytes_written); } -static int pc2_command(struct gpib_board *board, uint8_t *buffer, size_t length, size_t *bytes_written) +static int pc2_command(struct gpib_board *board, u8 *buffer, + size_t length, size_t *bytes_written) { struct pc2_priv *priv = board->private_data; @@ -127,11 +128,11 @@ static int pc2_go_to_standby(struct gpib_board *board) return nec7210_go_to_standby(board, &priv->nec7210_priv); } -static void pc2_request_system_control(struct gpib_board *board, int request_control) +static int pc2_request_system_control(struct gpib_board *board, int request_control) { struct pc2_priv *priv = board->private_data; - nec7210_request_system_control(board, &priv->nec7210_priv, request_control); + return nec7210_request_system_control(board, &priv->nec7210_priv, request_control); } static void pc2_interface_clear(struct gpib_board *board, int assert) @@ -148,7 +149,7 @@ static void pc2_remote_enable(struct gpib_board *board, int enable) nec7210_remote_enable(board, &priv->nec7210_priv, enable); } -static int pc2_enable_eos(struct gpib_board *board, uint8_t eos_byte, int compare_8_bits) +static int pc2_enable_eos(struct gpib_board *board, u8 eos_byte, int compare_8_bits) { struct pc2_priv *priv = board->private_data; @@ -183,14 +184,14 @@ static int pc2_secondary_address(struct gpib_board *board, unsigned int address, return nec7210_secondary_address(board, &priv->nec7210_priv, address, enable); } -static int pc2_parallel_poll(struct gpib_board *board, uint8_t *result) +static int pc2_parallel_poll(struct gpib_board *board, u8 *result) { struct pc2_priv *priv = board->private_data; return nec7210_parallel_poll(board, &priv->nec7210_priv, result); } -static void pc2_parallel_poll_configure(struct gpib_board *board, uint8_t config) +static void pc2_parallel_poll_configure(struct gpib_board *board, u8 config) { struct pc2_priv *priv = board->private_data; @@ -204,14 +205,14 @@ static void pc2_parallel_poll_response(struct gpib_board *board, int ist) nec7210_parallel_poll_response(board, &priv->nec7210_priv, ist); } -static void pc2_serial_poll_response(struct gpib_board *board, uint8_t status) +static void pc2_serial_poll_response(struct gpib_board *board, u8 status) { struct pc2_priv *priv = board->private_data; nec7210_serial_poll_response(board, &priv->nec7210_priv, status); } -static uint8_t pc2_serial_poll_status(struct gpib_board *board) +static u8 pc2_serial_poll_status(struct gpib_board *board) { struct pc2_priv *priv = board->private_data; @@ -251,7 +252,7 @@ static void free_private(struct gpib_board *board) board->private_data = NULL; } -static int pc2_generic_attach(struct gpib_board *board, const gpib_board_config_t *config, +static int pc2_generic_attach(struct gpib_board *board, const struct gpib_board_config *config, enum nec7210_chipset chipset) { struct pc2_priv *pc2_priv; @@ -267,8 +268,9 @@ static int pc2_generic_attach(struct gpib_board *board, const gpib_board_config_ nec_priv->type = chipset; #ifndef PC2_DMA - /* board->dev hasn't been initialized, so forget about DMA until this driver - * is adapted to use isa_register_driver. + /* + * board->dev hasn't been initialized, so forget about DMA until this driver + * is adapted to use isa_register_driver. */ if (config->ibdma) // driver needs to be adapted to use isa_register_driver to get a struct device* @@ -294,7 +296,7 @@ static int pc2_generic_attach(struct gpib_board *board, const gpib_board_config_ return 0; } -static int pc2_attach(struct gpib_board *board, const gpib_board_config_t *config) +static int pc2_attach(struct gpib_board *board, const struct gpib_board_config *config) { int isr_flags = 0; struct pc2_priv *pc2_priv; @@ -365,7 +367,7 @@ static void pc2_detach(struct gpib_board *board) free_private(board); } -static int pc2a_common_attach(struct gpib_board *board, const gpib_board_config_t *config, +static int pc2a_common_attach(struct gpib_board *board, const struct gpib_board_config *config, unsigned int num_registers, enum nec7210_chipset chipset) { unsigned int i, j; @@ -459,17 +461,17 @@ static int pc2a_common_attach(struct gpib_board *board, const gpib_board_config_ return 0; } -static int pc2a_attach(struct gpib_board *board, const gpib_board_config_t *config) +static int pc2a_attach(struct gpib_board *board, const struct gpib_board_config *config) { return pc2a_common_attach(board, config, pc2a_iosize, NEC7210); } -static int pc2a_cb7210_attach(struct gpib_board *board, const gpib_board_config_t *config) +static int pc2a_cb7210_attach(struct gpib_board *board, const struct gpib_board_config *config) { return pc2a_common_attach(board, config, pc2a_iosize, CB7210); } -static int pc2_2a_attach(struct gpib_board *board, const gpib_board_config_t *config) +static int pc2_2a_attach(struct gpib_board *board, const struct gpib_board_config *config) { return pc2a_common_attach(board, config, pc2_2a_iosize, NAT4882); } @@ -517,7 +519,7 @@ static void pc2_2a_detach(struct gpib_board *board) pc2a_common_detach(board, pc2_2a_iosize); } -static gpib_interface_t pc2_interface = { +static struct gpib_interface pc2_interface = { .name = "pcII", .attach = pc2_attach, .detach = pc2_detach, @@ -545,7 +547,7 @@ static gpib_interface_t pc2_interface = { .return_to_local = pc2_return_to_local, }; -static gpib_interface_t pc2a_interface = { +static struct gpib_interface pc2a_interface = { .name = "pcIIa", .attach = pc2a_attach, .detach = pc2a_detach, @@ -573,7 +575,7 @@ static gpib_interface_t pc2a_interface = { .return_to_local = pc2_return_to_local, }; -static gpib_interface_t pc2a_cb7210_interface = { +static struct gpib_interface pc2a_cb7210_interface = { .name = "pcIIa_cb7210", .attach = pc2a_cb7210_attach, .detach = pc2a_detach, @@ -601,7 +603,7 @@ static gpib_interface_t pc2a_cb7210_interface = { .return_to_local = pc2_return_to_local, }; -static gpib_interface_t pc2_2a_interface = { +static struct gpib_interface pc2_2a_interface = { .name = "pcII_IIa", .attach = pc2_2a_attach, .detach = pc2_2a_detach, diff --git a/drivers/staging/gpib/tms9914/tms9914.c b/drivers/staging/gpib/tms9914/tms9914.c index 2abda9d7dfcb..04d57108efc7 100644 --- a/drivers/staging/gpib/tms9914/tms9914.c +++ b/drivers/staging/gpib/tms9914/tms9914.c @@ -53,7 +53,8 @@ int tms9914_take_control(struct gpib_board *board, struct tms9914_priv *priv, in } EXPORT_SYMBOL_GPL(tms9914_take_control); -/* The agilent 82350B has a buggy implementation of tcs which interferes with the +/* + * The agilent 82350B has a buggy implementation of tcs which interferes with the * operation of tca. It appears to be based on the controller state machine * described in the TI 9900 TMS9914A data manual published in 1982. This * manual describes tcs as putting the controller into a CWAS @@ -66,7 +67,8 @@ EXPORT_SYMBOL_GPL(tms9914_take_control); * The rest of the tms9914 based drivers still use tms9914_take_control * directly (which does issue tcs). */ -int tms9914_take_control_workaround(struct gpib_board *board, struct tms9914_priv *priv, int synchronous) +int tms9914_take_control_workaround(struct gpib_board *board, + struct tms9914_priv *priv, int synchronous) { if (synchronous) return -ETIMEDOUT; @@ -116,8 +118,8 @@ void tms9914_remote_enable(struct gpib_board *board, struct tms9914_priv *priv, } EXPORT_SYMBOL_GPL(tms9914_remote_enable); -void tms9914_request_system_control(struct gpib_board *board, struct tms9914_priv *priv, - int request_control) +int tms9914_request_system_control(struct gpib_board *board, struct tms9914_priv *priv, + int request_control) { if (request_control) { write_byte(priv, AUX_RQC, AUXCR); @@ -125,6 +127,7 @@ void tms9914_request_system_control(struct gpib_board *board, struct tms9914_pri clear_bit(CIC_NUM, &board->status); write_byte(priv, AUX_RLC, AUXCR); } + return 0; } EXPORT_SYMBOL_GPL(tms9914_request_system_control); @@ -192,7 +195,7 @@ void tms9914_release_holdoff(struct tms9914_priv *priv) } EXPORT_SYMBOL_GPL(tms9914_release_holdoff); -int tms9914_enable_eos(struct gpib_board *board, struct tms9914_priv *priv, uint8_t eos_byte, +int tms9914_enable_eos(struct gpib_board *board, struct tms9914_priv *priv, u8 eos_byte, int compare_8_bits) { priv->eos = eos_byte; @@ -209,7 +212,7 @@ void tms9914_disable_eos(struct gpib_board *board, struct tms9914_priv *priv) } EXPORT_SYMBOL(tms9914_disable_eos); -int tms9914_parallel_poll(struct gpib_board *board, struct tms9914_priv *priv, uint8_t *result) +int tms9914_parallel_poll(struct gpib_board *board, struct tms9914_priv *priv, u8 *result) { // execute parallel poll write_byte(priv, AUX_CS | AUX_RPP, AUXCR); @@ -235,7 +238,7 @@ static void set_ppoll_reg(struct tms9914_priv *priv, int enable, } void tms9914_parallel_poll_configure(struct gpib_board *board, - struct tms9914_priv *priv, uint8_t config) + struct tms9914_priv *priv, u8 config) { priv->ppoll_enable = (config & PPC_DISABLE) == 0; priv->ppoll_line = (config & PPC_DIO_MASK) + 1; @@ -251,7 +254,8 @@ void tms9914_parallel_poll_response(struct gpib_board *board, } EXPORT_SYMBOL(tms9914_parallel_poll_response); -void tms9914_serial_poll_response(struct gpib_board *board, struct tms9914_priv *priv, uint8_t status) +void tms9914_serial_poll_response(struct gpib_board *board, + struct tms9914_priv *priv, u8 status) { unsigned long flags; @@ -266,7 +270,7 @@ void tms9914_serial_poll_response(struct gpib_board *board, struct tms9914_priv } EXPORT_SYMBOL(tms9914_serial_poll_response); -uint8_t tms9914_serial_poll_status(struct gpib_board *board, struct tms9914_priv *priv) +u8 tms9914_serial_poll_status(struct gpib_board *board, struct tms9914_priv *priv) { u8 status; unsigned long flags; @@ -279,7 +283,8 @@ uint8_t tms9914_serial_poll_status(struct gpib_board *board, struct tms9914_priv } EXPORT_SYMBOL(tms9914_serial_poll_status); -int tms9914_primary_address(struct gpib_board *board, struct tms9914_priv *priv, unsigned int address) +int tms9914_primary_address(struct gpib_board *board, + struct tms9914_priv *priv, unsigned int address) { // put primary address in address0 write_byte(priv, address & ADDRESS_MASK, ADR); @@ -321,7 +326,8 @@ static void update_talker_state(struct tms9914_priv *priv, unsigned int address_ if (address_status_bits & HR_ATN) priv->talker_state = talker_addressed; else - /* this could also be serial_poll_active, but the tms9914 provides no + /* + * this could also be serial_poll_active, but the tms9914 provides no * way to distinguish, so we'll assume talker_active */ priv->talker_state = talker_active; @@ -416,7 +422,7 @@ int tms9914_line_status(const struct gpib_board *board, struct tms9914_priv *pri } EXPORT_SYMBOL(tms9914_line_status); -static int check_for_eos(struct tms9914_priv *priv, uint8_t byte) +static int check_for_eos(struct tms9914_priv *priv, u8 byte) { static const u8 seven_bit_compare_mask = 0x7f; @@ -449,7 +455,8 @@ static int wait_for_read_byte(struct gpib_board *board, struct tms9914_priv *pri return 0; } -static inline uint8_t tms9914_read_data_in(struct gpib_board *board, struct tms9914_priv *priv, int *end) +static inline u8 tms9914_read_data_in(struct gpib_board *board, + struct tms9914_priv *priv, int *end) { unsigned long flags; u8 data; @@ -480,7 +487,7 @@ static inline uint8_t tms9914_read_data_in(struct gpib_board *board, struct tms9 return data; } -static int pio_read(struct gpib_board *board, struct tms9914_priv *priv, uint8_t *buffer, +static int pio_read(struct gpib_board *board, struct tms9914_priv *priv, u8 *buffer, size_t length, int *end, size_t *bytes_read) { ssize_t retval = 0; @@ -501,7 +508,7 @@ static int pio_read(struct gpib_board *board, struct tms9914_priv *priv, uint8_t return retval; } -int tms9914_read(struct gpib_board *board, struct tms9914_priv *priv, uint8_t *buffer, +int tms9914_read(struct gpib_board *board, struct tms9914_priv *priv, u8 *buffer, size_t length, int *end, size_t *bytes_read) { ssize_t retval = 0; @@ -561,7 +568,7 @@ static int pio_write_wait(struct gpib_board *board, struct tms9914_priv *priv) return 0; } -static int pio_write(struct gpib_board *board, struct tms9914_priv *priv, uint8_t *buffer, +static int pio_write(struct gpib_board *board, struct tms9914_priv *priv, u8 *buffer, size_t length, size_t *bytes_written) { ssize_t retval = 0; @@ -585,8 +592,8 @@ static int pio_write(struct gpib_board *board, struct tms9914_priv *priv, uint8_ return length; } -int tms9914_write(struct gpib_board *board, struct tms9914_priv *priv, uint8_t *buffer, size_t length, - int send_eoi, size_t *bytes_written) +int tms9914_write(struct gpib_board *board, struct tms9914_priv *priv, + u8 *buffer, size_t length, int send_eoi, size_t *bytes_written) { ssize_t retval = 0; @@ -620,7 +627,8 @@ int tms9914_write(struct gpib_board *board, struct tms9914_priv *priv, uint8_t * } EXPORT_SYMBOL(tms9914_write); -static void check_my_address_state(struct gpib_board *board, struct tms9914_priv *priv, int cmd_byte) +static void check_my_address_state(struct gpib_board *board, + struct tms9914_priv *priv, int cmd_byte) { if (cmd_byte == MLA(board->pad)) { priv->primary_listen_addressed = 1; @@ -655,7 +663,7 @@ static void check_my_address_state(struct gpib_board *board, struct tms9914_priv } } -int tms9914_command(struct gpib_board *board, struct tms9914_priv *priv, uint8_t *buffer, +int tms9914_command(struct gpib_board *board, struct tms9914_priv *priv, u8 *buffer, size_t length, size_t *bytes_written) { int retval = 0; @@ -736,9 +744,10 @@ irqreturn_t tms9914_interrupt_have_status(struct gpib_board *board, struct tms99 unsigned short command_byte = read_byte(priv, CPTR) & gpib_command_mask; switch (command_byte) { - case PPConfig: + case PP_CONFIG: priv->ppoll_configure_state = 1; - /* AUX_PTS generates another UNC interrupt on the next command byte + /* + * AUX_PTS generates another UNC interrupt on the next command byte * if it is in the secondary address group (such as PPE and PPD). */ write_byte(priv, AUX_PTS, AUXCR); @@ -764,7 +773,7 @@ irqreturn_t tms9914_interrupt_have_status(struct gpib_board *board, struct tms99 break; } - if (in_primary_command_group(command_byte) && command_byte != PPConfig) + if (in_primary_command_group(command_byte) && command_byte != PP_CONFIG) priv->ppoll_configure_state = 0; } @@ -774,18 +783,18 @@ irqreturn_t tms9914_interrupt_have_status(struct gpib_board *board, struct tms99 } if (status1 & HR_IFC) { - push_gpib_event(board, EventIFC); + push_gpib_event(board, EVENT_IFC); clear_bit(CIC_NUM, &board->status); } if (status1 & HR_GET) { - push_gpib_event(board, EventDevTrg); + push_gpib_event(board, EVENT_DEV_TRG); // clear dac holdoff write_byte(priv, AUX_VAL, AUXCR); } if (status1 & HR_DCAS) { - push_gpib_event(board, EventDevClr); + push_gpib_event(board, EVENT_DEV_CLR); // clear dac holdoff write_byte(priv, AUX_VAL, AUXCR); set_bit(DEV_CLEAR_BN, &priv->state); @@ -859,14 +868,14 @@ EXPORT_SYMBOL_GPL(tms9914_online); #ifdef CONFIG_HAS_IOPORT // wrapper for inb -uint8_t tms9914_ioport_read_byte(struct tms9914_priv *priv, unsigned int register_num) +u8 tms9914_ioport_read_byte(struct tms9914_priv *priv, unsigned int register_num) { return inb(priv->iobase + register_num * priv->offset); } EXPORT_SYMBOL_GPL(tms9914_ioport_read_byte); // wrapper for outb -void tms9914_ioport_write_byte(struct tms9914_priv *priv, uint8_t data, unsigned int register_num) +void tms9914_ioport_write_byte(struct tms9914_priv *priv, u8 data, unsigned int register_num) { outb(data, priv->iobase + register_num * priv->offset); if (register_num == AUXCR) @@ -876,14 +885,14 @@ EXPORT_SYMBOL_GPL(tms9914_ioport_write_byte); #endif // wrapper for readb -uint8_t tms9914_iomem_read_byte(struct tms9914_priv *priv, unsigned int register_num) +u8 tms9914_iomem_read_byte(struct tms9914_priv *priv, unsigned int register_num) { return readb(priv->mmiobase + register_num * priv->offset); } EXPORT_SYMBOL_GPL(tms9914_iomem_read_byte); // wrapper for writeb -void tms9914_iomem_write_byte(struct tms9914_priv *priv, uint8_t data, unsigned int register_num) +void tms9914_iomem_write_byte(struct tms9914_priv *priv, u8 data, unsigned int register_num) { writeb(data, priv->mmiobase + register_num * priv->offset); if (register_num == AUXCR) diff --git a/drivers/staging/gpib/tnt4882/tnt4882_gpib.c b/drivers/staging/gpib/tnt4882/tnt4882_gpib.c index c35b084b6fd0..a17b69e34986 100644 --- a/drivers/staging/gpib/tnt4882/tnt4882_gpib.c +++ b/drivers/staging/gpib/tnt4882/tnt4882_gpib.c @@ -236,7 +236,7 @@ static int fifo_xfer_done(struct tnt4882_priv *tnt_priv) return retval; } -static int drain_fifo_words(struct tnt4882_priv *tnt_priv, uint8_t *buffer, int num_bytes) +static int drain_fifo_words(struct tnt4882_priv *tnt_priv, u8 *buffer, int num_bytes) { int count = 0; struct nec7210_priv *nec_priv = &tnt_priv->nec7210_priv; @@ -258,7 +258,8 @@ static void tnt4882_release_holdoff(struct gpib_board *board, struct tnt4882_pri sasr_bits = tnt_readb(tnt_priv, SASR); - /*tnt4882 not in one-chip mode won't always release holdoff unless we + /* + * tnt4882 not in one-chip mode won't always release holdoff unless we * are in the right mode when release handshake command is given */ if (sasr_bits & AEHS_BIT) /* holding off due to holdoff on end mode*/ { @@ -274,7 +275,7 @@ static void tnt4882_release_holdoff(struct gpib_board *board, struct tnt4882_pri } } -static int tnt4882_accel_read(struct gpib_board *board, uint8_t *buffer, size_t length, int *end, +static int tnt4882_accel_read(struct gpib_board *board, u8 *buffer, size_t length, int *end, size_t *bytes_read) { size_t count = 0; @@ -384,7 +385,8 @@ static int tnt4882_accel_read(struct gpib_board *board, uint8_t *buffer, size_t nec7210_set_reg_bits(nec_priv, IMR1, HR_ENDIE, 0); nec7210_set_reg_bits(nec_priv, IMR2, HR_DMAI, 0); - /* force handling of any pending interrupts (seems to be needed + /* + * force handling of any pending interrupts (seems to be needed * to keep interrupts from getting hosed, plus for syncing * with RECEIVED_END below) */ @@ -448,7 +450,7 @@ static int write_wait(struct gpib_board *board, struct tnt4882_priv *tnt_priv, return 0; } -static int generic_write(struct gpib_board *board, uint8_t *buffer, size_t length, +static int generic_write(struct gpib_board *board, u8 *buffer, size_t length, int send_eoi, int send_commands, size_t *bytes_written) { size_t count = 0; @@ -531,7 +533,8 @@ static int generic_write(struct gpib_board *board, uint8_t *buffer, size_t lengt nec7210_set_reg_bits(nec_priv, IMR1, HR_ERR, 0x0); nec7210_set_reg_bits(nec_priv, IMR2, HR_DMAO, 0x0); - /* force handling of any interrupts that happened + /* + * force handling of any interrupts that happened * while they were masked (this appears to be needed) */ tnt4882_internal_interrupt(board); @@ -539,13 +542,13 @@ static int generic_write(struct gpib_board *board, uint8_t *buffer, size_t lengt return retval; } -static int tnt4882_accel_write(struct gpib_board *board, uint8_t *buffer, size_t length, int send_eoi, - size_t *bytes_written) +static int tnt4882_accel_write(struct gpib_board *board, u8 *buffer, + size_t length, int send_eoi, size_t *bytes_written) { return generic_write(board, buffer, length, send_eoi, 0, bytes_written); } -static int tnt4882_command(struct gpib_board *board, uint8_t *buffer, size_t length, +static int tnt4882_command(struct gpib_board *board, u8 *buffer, size_t length, size_t *bytes_written) { return generic_write(board, buffer, length, 0, 1, bytes_written); @@ -566,7 +569,7 @@ static irqreturn_t tnt4882_internal_interrupt(struct gpib_board *board) imr3_bits = priv->imr3_bits; if (isr0_bits & TNT_IFCI_BIT) - push_gpib_event(board, EventIFC); + push_gpib_event(board, EVENT_IFC); //XXX don't need this wakeup, one below should do? // wake_up_interruptible(&board->wait); @@ -592,7 +595,7 @@ static irqreturn_t tnt4882_interrupt(int irq, void *arg) } // wrappers for interface functions -static int tnt4882_read(struct gpib_board *board, uint8_t *buffer, size_t length, int *end, +static int tnt4882_read(struct gpib_board *board, u8 *buffer, size_t length, int *end, size_t *bytes_read) { struct tnt4882_priv *priv = board->private_data; @@ -612,7 +615,7 @@ static int tnt4882_read(struct gpib_board *board, uint8_t *buffer, size_t length return retval; } -static int tnt4882_write(struct gpib_board *board, uint8_t *buffer, size_t length, int send_eoi, +static int tnt4882_write(struct gpib_board *board, u8 *buffer, size_t length, int send_eoi, size_t *bytes_written) { struct tnt4882_priv *priv = board->private_data; @@ -620,7 +623,7 @@ static int tnt4882_write(struct gpib_board *board, uint8_t *buffer, size_t lengt return nec7210_write(board, &priv->nec7210_priv, buffer, length, send_eoi, bytes_written); } -static int tnt4882_command_unaccel(struct gpib_board *board, uint8_t *buffer, +static int tnt4882_command_unaccel(struct gpib_board *board, u8 *buffer, size_t length, size_t *bytes_written) { struct tnt4882_priv *priv = board->private_data; @@ -642,19 +645,21 @@ static int tnt4882_go_to_standby(struct gpib_board *board) return nec7210_go_to_standby(board, &priv->nec7210_priv); } -static void tnt4882_request_system_control(struct gpib_board *board, int request_control) +static int tnt4882_request_system_control(struct gpib_board *board, int request_control) { struct tnt4882_priv *priv = board->private_data; + int retval; if (request_control) { tnt_writeb(priv, SETSC, CMDR); udelay(1); } - nec7210_request_system_control(board, &priv->nec7210_priv, request_control); + retval = nec7210_request_system_control(board, &priv->nec7210_priv, request_control); if (!request_control) { tnt_writeb(priv, CLRSC, CMDR); udelay(1); } + return retval; } static void tnt4882_interface_clear(struct gpib_board *board, int assert) @@ -671,7 +676,7 @@ static void tnt4882_remote_enable(struct gpib_board *board, int enable) nec7210_remote_enable(board, &priv->nec7210_priv, enable); } -static int tnt4882_enable_eos(struct gpib_board *board, uint8_t eos_byte, int compare_8_bits) +static int tnt4882_enable_eos(struct gpib_board *board, u8 eos_byte, int compare_8_bits) { struct tnt4882_priv *priv = board->private_data; @@ -718,7 +723,7 @@ static int tnt4882_secondary_address(struct gpib_board *board, unsigned int addr return nec7210_secondary_address(board, &priv->nec7210_priv, address, enable); } -static int tnt4882_parallel_poll(struct gpib_board *board, uint8_t *result) +static int tnt4882_parallel_poll(struct gpib_board *board, u8 *result) { struct tnt4882_priv *tnt_priv = board->private_data; @@ -735,7 +740,7 @@ static int tnt4882_parallel_poll(struct gpib_board *board, uint8_t *result) } } -static void tnt4882_parallel_poll_configure(struct gpib_board *board, uint8_t config) +static void tnt4882_parallel_poll_configure(struct gpib_board *board, u8 config) { struct tnt4882_priv *priv = board->private_data; @@ -760,17 +765,18 @@ static void tnt4882_parallel_poll_response(struct gpib_board *board, int ist) nec7210_parallel_poll_response(board, &priv->nec7210_priv, ist); } -/* this is just used by the old nec7210 isa interfaces, the newer +/* + * this is just used by the old nec7210 isa interfaces, the newer * boards use tnt4882_serial_poll_response2 */ -static void tnt4882_serial_poll_response(struct gpib_board *board, uint8_t status) +static void tnt4882_serial_poll_response(struct gpib_board *board, u8 status) { struct tnt4882_priv *priv = board->private_data; nec7210_serial_poll_response(board, &priv->nec7210_priv, status); } -static void tnt4882_serial_poll_response2(struct gpib_board *board, uint8_t status, +static void tnt4882_serial_poll_response2(struct gpib_board *board, u8 status, int new_reason_for_service) { struct tnt4882_priv *priv = board->private_data; @@ -788,7 +794,8 @@ static void tnt4882_serial_poll_response2(struct gpib_board *board, uint8_t stat priv->nec7210_priv.srq_pending = 0; } if (reqt) - /* It may seem like a race to issue reqt before updating + /* + * It may seem like a race to issue reqt before updating * the status byte, but it is not. The chip does not * issue the reqt until the SPMR is written to at * a later time. @@ -796,7 +803,8 @@ static void tnt4882_serial_poll_response2(struct gpib_board *board, uint8_t stat write_byte(&priv->nec7210_priv, AUX_REQT, AUXMR); else if (reqf) write_byte(&priv->nec7210_priv, AUX_REQF, AUXMR); - /* We need to always zero bit 6 of the status byte before writing it to + /* + * We need to always zero bit 6 of the status byte before writing it to * the SPMR to insure we are using * serial poll mode SP1, and not accidentally triggering mode SP3. */ @@ -804,7 +812,7 @@ static void tnt4882_serial_poll_response2(struct gpib_board *board, uint8_t stat spin_unlock_irqrestore(&board->spinlock, flags); } -static uint8_t tnt4882_serial_poll_status(struct gpib_board *board) +static u8 tnt4882_serial_poll_status(struct gpib_board *board) { struct tnt4882_priv *priv = board->private_data; @@ -898,7 +906,7 @@ static void tnt4882_init(struct tnt4882_priv *tnt_priv, const struct gpib_board tnt_writeb(tnt_priv, tnt_priv->imr0_bits, IMR0); } -static int ni_pci_attach(struct gpib_board *board, const gpib_board_config_t *config) +static int ni_pci_attach(struct gpib_board *board, const struct gpib_board_config *config) { struct tnt4882_priv *tnt_priv; struct nec7210_priv *nec_priv; @@ -1019,7 +1027,7 @@ static int ni_isapnp_find(struct pnp_dev **dev) return 0; } -static int ni_isa_attach_common(struct gpib_board *board, const gpib_board_config_t *config, +static int ni_isa_attach_common(struct gpib_board *board, const struct gpib_board_config *config, enum nec7210_chipset chipset) { struct tnt4882_priv *tnt_priv; @@ -1075,17 +1083,17 @@ static int ni_isa_attach_common(struct gpib_board *board, const gpib_board_confi return 0; } -static int ni_tnt_isa_attach(struct gpib_board *board, const gpib_board_config_t *config) +static int ni_tnt_isa_attach(struct gpib_board *board, const struct gpib_board_config *config) { return ni_isa_attach_common(board, config, TNT4882); } -static int ni_nat4882_isa_attach(struct gpib_board *board, const gpib_board_config_t *config) +static int ni_nat4882_isa_attach(struct gpib_board *board, const struct gpib_board_config *config) { return ni_isa_attach_common(board, config, NAT4882); } -static int ni_nec_isa_attach(struct gpib_board *board, const gpib_board_config_t *config) +static int ni_nec_isa_attach(struct gpib_board *board, const struct gpib_board_config *config) { return ni_isa_attach_common(board, config, NEC7210); } @@ -1116,7 +1124,7 @@ static int tnt4882_pci_probe(struct pci_dev *dev, const struct pci_device_id *id return 0; } -static gpib_interface_t ni_pci_interface = { +static struct gpib_interface ni_pci_interface = { .name = "ni_pci", .attach = ni_pci_attach, .detach = ni_pci_detach, @@ -1144,7 +1152,7 @@ static gpib_interface_t ni_pci_interface = { .return_to_local = tnt4882_return_to_local, }; -static gpib_interface_t ni_pci_accel_interface = { +static struct gpib_interface ni_pci_accel_interface = { .name = "ni_pci_accel", .attach = ni_pci_attach, .detach = ni_pci_detach, @@ -1172,7 +1180,7 @@ static gpib_interface_t ni_pci_accel_interface = { .return_to_local = tnt4882_return_to_local, }; -static gpib_interface_t ni_isa_interface = { +static struct gpib_interface ni_isa_interface = { .name = "ni_isa", .attach = ni_tnt_isa_attach, .detach = ni_isa_detach, @@ -1200,7 +1208,7 @@ static gpib_interface_t ni_isa_interface = { .return_to_local = tnt4882_return_to_local, }; -static gpib_interface_t ni_nat4882_isa_interface = { +static struct gpib_interface ni_nat4882_isa_interface = { .name = "ni_nat4882_isa", .attach = ni_nat4882_isa_attach, .detach = ni_isa_detach, @@ -1228,7 +1236,7 @@ static gpib_interface_t ni_nat4882_isa_interface = { .return_to_local = tnt4882_return_to_local, }; -static gpib_interface_t ni_nec_isa_interface = { +static struct gpib_interface ni_nec_isa_interface = { .name = "ni_nec_isa", .attach = ni_nec_isa_attach, .detach = ni_isa_detach, @@ -1256,7 +1264,7 @@ static gpib_interface_t ni_nec_isa_interface = { .return_to_local = tnt4882_return_to_local, }; -static gpib_interface_t ni_isa_accel_interface = { +static struct gpib_interface ni_isa_accel_interface = { .name = "ni_isa_accel", .attach = ni_tnt_isa_attach, .detach = ni_isa_detach, @@ -1284,7 +1292,7 @@ static gpib_interface_t ni_isa_accel_interface = { .return_to_local = tnt4882_return_to_local, }; -static gpib_interface_t ni_nat4882_isa_accel_interface = { +static struct gpib_interface ni_nat4882_isa_accel_interface = { .name = "ni_nat4882_isa_accel", .attach = ni_nat4882_isa_attach, .detach = ni_isa_detach, @@ -1312,7 +1320,7 @@ static gpib_interface_t ni_nat4882_isa_accel_interface = { .return_to_local = tnt4882_return_to_local, }; -static gpib_interface_t ni_nec_isa_accel_interface = { +static struct gpib_interface ni_nec_isa_accel_interface = { .name = "ni_nec_isa_accel", .attach = ni_nec_isa_attach, .detach = ni_isa_detach, @@ -1371,8 +1379,8 @@ MODULE_DEVICE_TABLE(pnp, tnt4882_pnp_table); #endif #ifdef CONFIG_GPIB_PCMCIA -static gpib_interface_t ni_pcmcia_interface; -static gpib_interface_t ni_pcmcia_accel_interface; +static struct gpib_interface ni_pcmcia_interface; +static struct gpib_interface ni_pcmcia_accel_interface; static int __init init_ni_gpib_cs(void); static void __exit exit_ni_gpib_cs(void); #endif @@ -1581,10 +1589,10 @@ static int ni_gpib_probe(struct pcmcia_device *link) } /* - * This deletes a driver "instance". The device is de-registered - * with Card Services. If it has been released, all local data - * structures are freed. Otherwise, the structures will be freed - * when the device is released. + * This deletes a driver "instance". The device is de-registered + * with Card Services. If it has been released, all local data + * structures are freed. Otherwise, the structures will be freed + * when the device is released. */ static void ni_gpib_remove(struct pcmcia_device *link) { @@ -1611,9 +1619,9 @@ static int ni_gpib_config_iteration(struct pcmcia_device *link, void *priv_data) } /* - * ni_gpib_config() is scheduled to run after a CARD_INSERTION event - * is received, to configure the PCMCIA socket, and to make the - * device available to the system. + * ni_gpib_config() is scheduled to run after a CARD_INSERTION event + * is received, to configure the PCMCIA socket, and to make the + * device available to the system. */ static int ni_gpib_config(struct pcmcia_device *link) { @@ -1702,7 +1710,7 @@ static void __exit exit_ni_gpib_cs(void) static const int pcmcia_gpib_iosize = 32; -static int ni_pcmcia_attach(struct gpib_board *board, const gpib_board_config_t *config) +static int ni_pcmcia_attach(struct gpib_board *board, const struct gpib_board_config *config) { struct local_info_t *info; struct tnt4882_priv *tnt_priv; @@ -1769,7 +1777,7 @@ static void ni_pcmcia_detach(struct gpib_board *board) tnt4882_free_private(board); } -static gpib_interface_t ni_pcmcia_interface = { +static struct gpib_interface ni_pcmcia_interface = { .name = "ni_pcmcia", .attach = ni_pcmcia_attach, .detach = ni_pcmcia_detach, @@ -1797,7 +1805,7 @@ static gpib_interface_t ni_pcmcia_interface = { .return_to_local = tnt4882_return_to_local, }; -static gpib_interface_t ni_pcmcia_accel_interface = { +static struct gpib_interface ni_pcmcia_accel_interface = { .name = "ni_pcmcia_accel", .attach = ni_pcmcia_attach, .detach = ni_pcmcia_detach, diff --git a/drivers/staging/gpib/uapi/gpib_user.h b/drivers/staging/gpib/uapi/gpib.h index 5ff4588686fd..41500cee4029 100644 --- a/drivers/staging/gpib/uapi/gpib_user.h +++ b/drivers/staging/gpib/uapi/gpib.h @@ -4,8 +4,8 @@ * copyright : (C) 2002 by Frank Mori Hess ***************************************************************************/ -#ifndef _GPIB_USER_H -#define _GPIB_USER_H +#ifndef _GPIB_H +#define _GPIB_H #define GPIB_MAX_NUM_BOARDS 16 #define GPIB_MAX_NUM_DESCRIPTORS 0x1000 @@ -53,48 +53,6 @@ enum ibsta_bits { EVENT | LOK | REM | CIC | ATN | TACS | LACS | DTAS | DCAS | SRQI, }; -/* IBERR error codes */ -enum iberr_code { - EDVR = 0, /* system error */ - ECIC = 1, /* not CIC */ - ENOL = 2, /* no listeners */ - EADR = 3, /* CIC and not addressed before I/O */ - EARG = 4, /* bad argument to function call */ - ESAC = 5, /* not SAC */ - EABO = 6, /* I/O operation was aborted */ - ENEB = 7, /* non-existent board (GPIB interface offline) */ - EDMA = 8, /* DMA hardware error detected */ - EOIP = 10, /* new I/O attempted with old I/O in progress */ - ECAP = 11, /* no capability for intended opeation */ - EFSO = 12, /* file system operation error */ - EBUS = 14, /* bus error */ - ESTB = 15, /* lost serial poll bytes */ - ESRQ = 16, /* SRQ stuck on */ - ETAB = 20 /* Table Overflow */ -}; - -/* Timeout values and meanings */ -enum gpib_timeout { - TNONE = 0, /* Infinite timeout (disabled) */ - T10us = 1, /* Timeout of 10 usec (ideal) */ - T30us = 2, /* Timeout of 30 usec (ideal) */ - T100us = 3, /* Timeout of 100 usec (ideal) */ - T300us = 4, /* Timeout of 300 usec (ideal) */ - T1ms = 5, /* Timeout of 1 msec (ideal) */ - T3ms = 6, /* Timeout of 3 msec (ideal) */ - T10ms = 7, /* Timeout of 10 msec (ideal) */ - T30ms = 8, /* Timeout of 30 msec (ideal) */ - T100ms = 9, /* Timeout of 100 msec (ideal) */ - T300ms = 10, /* Timeout of 300 msec (ideal) */ - T1s = 11, /* Timeout of 1 sec (ideal) */ - T3s = 12, /* Timeout of 3 sec (ideal) */ - T10s = 13, /* Timeout of 10 sec (ideal) */ - T30s = 14, /* Timeout of 30 sec (ideal) */ - T100s = 15, /* Timeout of 100 sec (ideal) */ - T300s = 16, /* Timeout of 300 sec (ideal) */ - T1000s = 17 /* Timeout of 1000 sec (maximum) */ -}; - /* End-of-string (EOS) modes for use with ibeos */ enum eos_flags { @@ -130,9 +88,9 @@ enum bus_control_line { enum cmd_byte { GTL = 0x1, /* go to local */ SDC = 0x4, /* selected device clear */ - PPConfig = 0x5, + PP_CONFIG = 0x5, #ifndef PPC - PPC = PPConfig, /* parallel poll configure */ + PPC = PP_CONFIG, /* parallel poll configure */ #endif GET = 0x8, /* group execute trigger */ TCT = 0x9, /* take control */ @@ -166,24 +124,24 @@ static inline unsigned int gpib_address_restrict(unsigned int addr) return addr; } -static inline uint8_t MLA(unsigned int addr) +static inline __u8 MLA(unsigned int addr) { return gpib_address_restrict(addr) | LAD; } -static inline uint8_t MTA(unsigned int addr) +static inline __u8 MTA(unsigned int addr) { return gpib_address_restrict(addr) | TAD; } -static inline uint8_t MSA(unsigned int addr) +static inline __u8 MSA(unsigned int addr) { - return gpib_address_restrict(addr) | SAD; + return (addr & 0x1f) | SAD; } -static inline uint8_t PPE_byte(unsigned int dio_line, int sense) +static inline __u8 PPE_byte(unsigned int dio_line, int sense) { - uint8_t cmd; + __u8 cmd; cmd = PPE; if (sense) @@ -192,47 +150,42 @@ static inline uint8_t PPE_byte(unsigned int dio_line, int sense) return cmd; } -static inline uint8_t CFGn(unsigned int meters) -{ - return 0x6 | (meters & 0xf); -} - /* mask of bits that actually matter in a command byte */ enum { gpib_command_mask = 0x7f, }; -static inline int is_PPE(uint8_t command) +static inline int is_PPE(__u8 command) { return (command & 0x70) == 0x60; } -static inline int is_PPD(uint8_t command) +static inline int is_PPD(__u8 command) { return (command & 0x70) == 0x70; } -static inline int in_addressed_command_group(uint8_t command) +static inline int in_addressed_command_group(__u8 command) { return (command & 0x70) == 0x0; } -static inline int in_universal_command_group(uint8_t command) +static inline int in_universal_command_group(__u8 command) { return (command & 0x70) == 0x10; } -static inline int in_listen_address_group(uint8_t command) +static inline int in_listen_address_group(__u8 command) { return (command & 0x60) == 0x20; } -static inline int in_talk_address_group(uint8_t command) +static inline int in_talk_address_group(__u8 command) { return (command & 0x60) == 0x40; } -static inline int in_primary_command_group(uint8_t command) +static inline int in_primary_command_group(__u8 command) { return in_addressed_command_group(command) || in_universal_command_group(command) || @@ -253,75 +206,73 @@ static inline int gpib_address_equal(unsigned int pad1, int sad1, unsigned int p } enum ibask_option { - IbaPAD = 0x1, - IbaSAD = 0x2, - IbaTMO = 0x3, - IbaEOT = 0x4, - IbaPPC = 0x5, /* board only */ - IbaREADDR = 0x6, /* device only */ - IbaAUTOPOLL = 0x7, /* board only */ - IbaCICPROT = 0x8, /* board only */ - IbaIRQ = 0x9, /* board only */ - IbaSC = 0xa, /* board only */ - IbaSRE = 0xb, /* board only */ - IbaEOSrd = 0xc, - IbaEOSwrt = 0xd, - IbaEOScmp = 0xe, - IbaEOSchar = 0xf, - IbaPP2 = 0x10, /* board only */ - IbaTIMING = 0x11, /* board only */ - IbaDMA = 0x12, /* board only */ - IbaReadAdjust = 0x13, - IbaWriteAdjust = 0x14, - IbaEventQueue = 0x15, /* board only */ - IbaSPollBit = 0x16, /* board only */ - IbaSpollBit = 0x16, /* board only */ - IbaSendLLO = 0x17, /* board only */ - IbaSPollTime = 0x18, /* device only */ - IbaPPollTime = 0x19, /* board only */ - IbaEndBitIsNormal = 0x1a, - IbaUnAddr = 0x1b, /* device only */ - IbaHSCableLength = 0x1f, /* board only */ - IbaIst = 0x20, /* board only */ - IbaRsv = 0x21, /* board only */ - IbaBNA = 0x200, /* device only */ + IBA_PAD = 0x1, + IBA_SAD = 0x2, + IBA_TMO = 0x3, + IBA_EOT = 0x4, + IBA_PPC = 0x5, /* board only */ + IBA_READ_DR = 0x6, /* device only */ + IBA_AUTOPOLL = 0x7, /* board only */ + IBA_CICPROT = 0x8, /* board only */ + IBA_IRQ = 0x9, /* board only */ + IBA_SC = 0xa, /* board only */ + IBA_SRE = 0xb, /* board only */ + IBA_EOS_RD = 0xc, + IBA_EOS_WRT = 0xd, + IBA_EOS_CMP = 0xe, + IBA_EOS_CHAR = 0xf, + IBA_PP2 = 0x10, /* board only */ + IBA_TIMING = 0x11, /* board only */ + IBA_DMA = 0x12, /* board only */ + IBA_READ_ADJUST = 0x13, + IBA_WRITE_ADJUST = 0x14, + IBA_EVENT_QUEUE = 0x15, /* board only */ + IBA_SPOLL_BIT = 0x16, /* board only */ + IBA_SEND_LLO = 0x17, /* board only */ + IBA_SPOLL_TIME = 0x18, /* device only */ + IBA_PPOLL_TIME = 0x19, /* board only */ + IBA_END_BIT_IS_NORMAL = 0x1a, + IBA_UN_ADDR = 0x1b, /* device only */ + IBA_HS_CABLE_LENGTH = 0x1f, /* board only */ + IBA_IST = 0x20, /* board only */ + IBA_RSV = 0x21, /* board only */ + IBA_BNA = 0x200, /* device only */ /* linux-gpib extensions */ - Iba7BitEOS = 0x1000 /* board only. Returns 1 if board supports 7 bit eos compares*/ + IBA_7_BIT_EOS = 0x1000 /* board only. Returns 1 if board supports 7 bit eos compares*/ }; enum ibconfig_option { - IbcPAD = 0x1, - IbcSAD = 0x2, - IbcTMO = 0x3, - IbcEOT = 0x4, - IbcPPC = 0x5, /* board only */ - IbcREADDR = 0x6, /* device only */ - IbcAUTOPOLL = 0x7, /* board only */ - IbcCICPROT = 0x8, /* board only */ - IbcIRQ = 0x9, /* board only */ - IbcSC = 0xa, /* board only */ - IbcSRE = 0xb, /* board only */ - IbcEOSrd = 0xc, - IbcEOSwrt = 0xd, - IbcEOScmp = 0xe, - IbcEOSchar = 0xf, - IbcPP2 = 0x10, /* board only */ - IbcTIMING = 0x11, /* board only */ - IbcDMA = 0x12, /* board only */ - IbcReadAdjust = 0x13, - IbcWriteAdjust = 0x14, - IbcEventQueue = 0x15, /* board only */ - IbcSPollBit = 0x16, /* board only */ - IbcSpollBit = 0x16, /* board only */ - IbcSendLLO = 0x17, /* board only */ - IbcSPollTime = 0x18, /* device only */ - IbcPPollTime = 0x19, /* board only */ - IbcEndBitIsNormal = 0x1a, - IbcUnAddr = 0x1b, /* device only */ - IbcHSCableLength = 0x1f, /* board only */ - IbcIst = 0x20, /* board only */ - IbcRsv = 0x21, /* board only */ - IbcBNA = 0x200 /* device only */ + IBC_PAD = 0x1, + IBC_SAD = 0x2, + IBC_TMO = 0x3, + IBC_EOT = 0x4, + IBC_PPC = 0x5, /* board only */ + IBC_READDR = 0x6, /* device only */ + IBC_AUTOPOLL = 0x7, /* board only */ + IBC_CICPROT = 0x8, /* board only */ + IBC_IRQ = 0x9, /* board only */ + IBC_SC = 0xa, /* board only */ + IBC_SRE = 0xb, /* board only */ + IBC_EOS_RD = 0xc, + IBC_EOS_WRT = 0xd, + IBC_EOS_CMP = 0xe, + IBC_EOS_CHAR = 0xf, + IBC_PP2 = 0x10, /* board only */ + IBC_TIMING = 0x11, /* board only */ + IBC_DMA = 0x12, /* board only */ + IBC_READ_ADJUST = 0x13, + IBC_WRITE_ADJUST = 0x14, + IBC_EVENT_QUEUE = 0x15, /* board only */ + IBC_SPOLL_BIT = 0x16, /* board only */ + IBC_SEND_LLO = 0x17, /* board only */ + IBC_SPOLL_TIME = 0x18, /* device only */ + IBC_PPOLL_TIME = 0x19, /* board only */ + IBC_END_BIT_IS_NORMAL = 0x1a, + IBC_UN_ADDR = 0x1b, /* device only */ + IBC_HS_CABLE_LENGTH = 0x1f, /* board only */ + IBC_IST = 0x20, /* board only */ + IBC_RSV = 0x21, /* board only */ + IBC_BNA = 0x200 /* device only */ }; enum t1_delays { @@ -335,18 +286,17 @@ enum { }; enum gpib_events { - EventNone = 0, - EventDevTrg = 1, - EventDevClr = 2, - EventIFC = 3 + EVENT_NONE = 0, + EVENT_DEV_TRG = 1, + EVENT_DEV_CLR = 2, + EVENT_IFC = 3 }; enum gpib_stb { - IbStbRQS = 0x40, /* IEEE 488.1 & 2 */ - IbStbESB = 0x20, /* IEEE 488.2 only */ - IbStbMAV = 0x10 /* IEEE 488.2 only */ + IB_STB_RQS = 0x40, /* IEEE 488.1 & 2 */ + IB_STB_ESB = 0x20, /* IEEE 488.2 only */ + IB_STB_MAV = 0x10 /* IEEE 488.2 only */ }; -#endif /* _GPIB_USER_H */ +#endif /* _GPIB_H */ -/* Check for errors */ diff --git a/drivers/staging/gpib/uapi/gpib_ioctl.h b/drivers/staging/gpib/uapi/gpib_ioctl.h index 6202865278ea..0fed5c0fa7f2 100644 --- a/drivers/staging/gpib/uapi/gpib_ioctl.h +++ b/drivers/staging/gpib/uapi/gpib_ioctl.h @@ -12,42 +12,42 @@ #define GPIB_CODE 160 -typedef struct { +struct gpib_board_type_ioctl { char name[100]; -} board_type_ioctl_t; +}; /* argument for read/write/command ioctls */ -typedef struct { - uint64_t buffer_ptr; +struct gpib_read_write_ioctl { + __u64 buffer_ptr; unsigned int requested_transfer_count; unsigned int completed_transfer_count; int end; /* end flag return for reads, end io suppression request for cmd*/ int handle; -} read_write_ioctl_t; +}; -typedef struct { +struct gpib_open_dev_ioctl { unsigned int handle; unsigned int pad; int sad; unsigned is_board : 1; -} open_dev_ioctl_t; +}; -typedef struct { +struct gpib_close_dev_ioctl { unsigned int handle; -} close_dev_ioctl_t; +}; -typedef struct { +struct gpib_serial_poll_ioctl { unsigned int pad; int sad; - uint8_t status_byte; -} serial_poll_ioctl_t; + __u8 status_byte; +}; -typedef struct { +struct gpib_eos_ioctl { int eos; int eos_flags; -} eos_ioctl_t; +}; -typedef struct { +struct gpib_wait_ioctl { int handle; int wait_mask; int clear_mask; @@ -56,21 +56,21 @@ typedef struct { int pad; int sad; unsigned int usec_timeout; -} wait_ioctl_t; +}; -typedef struct { - uint64_t init_data_ptr; +struct gpib_online_ioctl { + __u64 init_data_ptr; int init_data_length; int online; -} online_ioctl_t; +}; -typedef struct { +struct gpib_spoll_bytes_ioctl { unsigned int num_bytes; unsigned int pad; int sad; -} spoll_bytes_ioctl_t; +}; -typedef struct { +struct gpib_board_info_ioctl { unsigned int pad; int sad; int parallel_poll_configuration; @@ -79,91 +79,85 @@ typedef struct { unsigned int t1_delay; unsigned ist : 1; unsigned no_7_bit_eos : 1; -} board_info_ioctl_t; +}; -typedef struct { +struct gpib_select_pci_ioctl { int pci_bus; int pci_slot; -} select_pci_ioctl_t; +}; -typedef struct { - uint8_t config; +struct gpib_ppoll_config_ioctl { + __u8 config; unsigned set_ist : 1; unsigned clear_ist : 1; -} ppoll_config_ioctl_t; +}; -typedef struct { +struct gpib_pad_ioctl { unsigned int handle; unsigned int pad; -} pad_ioctl_t; +}; -typedef struct { +struct gpib_sad_ioctl { unsigned int handle; int sad; -} sad_ioctl_t; +}; // select a piece of hardware to attach by its sysfs device path -typedef struct { +struct gpib_select_device_path_ioctl { char device_path[0x1000]; -} select_device_path_ioctl_t; - -typedef short event_ioctl_t; -typedef int rsc_ioctl_t; -typedef unsigned int t1_delay_ioctl_t; -typedef short autospoll_ioctl_t; -typedef short local_ppoll_mode_ioctl_t; +}; // update status byte and request service -typedef struct { - uint8_t status_byte; +struct gpib_request_service2 { + __u8 status_byte; int new_reason_for_service; -} request_service2_t; +}; /* Standard functions. */ enum gpib_ioctl { - IBRD = _IOWR(GPIB_CODE, 100, read_write_ioctl_t), - IBWRT = _IOWR(GPIB_CODE, 101, read_write_ioctl_t), - IBCMD = _IOWR(GPIB_CODE, 102, read_write_ioctl_t), - IBOPENDEV = _IOWR(GPIB_CODE, 3, open_dev_ioctl_t), - IBCLOSEDEV = _IOW(GPIB_CODE, 4, close_dev_ioctl_t), - IBWAIT = _IOWR(GPIB_CODE, 5, wait_ioctl_t), - IBRPP = _IOWR(GPIB_CODE, 6, uint8_t), + IBRD = _IOWR(GPIB_CODE, 100, struct gpib_read_write_ioctl), + IBWRT = _IOWR(GPIB_CODE, 101, struct gpib_read_write_ioctl), + IBCMD = _IOWR(GPIB_CODE, 102, struct gpib_read_write_ioctl), + IBOPENDEV = _IOWR(GPIB_CODE, 3, struct gpib_open_dev_ioctl), + IBCLOSEDEV = _IOW(GPIB_CODE, 4, struct gpib_close_dev_ioctl), + IBWAIT = _IOWR(GPIB_CODE, 5, struct gpib_wait_ioctl), + IBRPP = _IOWR(GPIB_CODE, 6, __u8), IBSIC = _IOW(GPIB_CODE, 9, unsigned int), IBSRE = _IOW(GPIB_CODE, 10, int), IBGTS = _IO(GPIB_CODE, 11), IBCAC = _IOW(GPIB_CODE, 12, int), IBLINES = _IOR(GPIB_CODE, 14, short), - IBPAD = _IOW(GPIB_CODE, 15, pad_ioctl_t), - IBSAD = _IOW(GPIB_CODE, 16, sad_ioctl_t), + IBPAD = _IOW(GPIB_CODE, 15, struct gpib_pad_ioctl), + IBSAD = _IOW(GPIB_CODE, 16, struct gpib_sad_ioctl), IBTMO = _IOW(GPIB_CODE, 17, unsigned int), - IBRSP = _IOWR(GPIB_CODE, 18, serial_poll_ioctl_t), - IBEOS = _IOW(GPIB_CODE, 19, eos_ioctl_t), - IBRSV = _IOW(GPIB_CODE, 20, uint8_t), - CFCBASE = _IOW(GPIB_CODE, 21, uint64_t), + IBRSP = _IOWR(GPIB_CODE, 18, struct gpib_serial_poll_ioctl), + IBEOS = _IOW(GPIB_CODE, 19, struct gpib_eos_ioctl), + IBRSV = _IOW(GPIB_CODE, 20, __u8), + CFCBASE = _IOW(GPIB_CODE, 21, __u64), CFCIRQ = _IOW(GPIB_CODE, 22, unsigned int), CFCDMA = _IOW(GPIB_CODE, 23, unsigned int), - CFCBOARDTYPE = _IOW(GPIB_CODE, 24, board_type_ioctl_t), + CFCBOARDTYPE = _IOW(GPIB_CODE, 24, struct gpib_board_type_ioctl), IBMUTEX = _IOW(GPIB_CODE, 26, int), - IBSPOLL_BYTES = _IOWR(GPIB_CODE, 27, spoll_bytes_ioctl_t), - IBPPC = _IOW(GPIB_CODE, 28, ppoll_config_ioctl_t), - IBBOARD_INFO = _IOR(GPIB_CODE, 29, board_info_ioctl_t), + IBSPOLL_BYTES = _IOWR(GPIB_CODE, 27, struct gpib_spoll_bytes_ioctl), + IBPPC = _IOW(GPIB_CODE, 28, struct gpib_ppoll_config_ioctl), + IBBOARD_INFO = _IOR(GPIB_CODE, 29, struct gpib_board_info_ioctl), IBQUERY_BOARD_RSV = _IOR(GPIB_CODE, 31, int), - IBSELECT_PCI = _IOWR(GPIB_CODE, 32, select_pci_ioctl_t), - IBEVENT = _IOR(GPIB_CODE, 33, event_ioctl_t), - IBRSC = _IOW(GPIB_CODE, 34, rsc_ioctl_t), - IB_T1_DELAY = _IOW(GPIB_CODE, 35, t1_delay_ioctl_t), + IBSELECT_PCI = _IOWR(GPIB_CODE, 32, struct gpib_select_pci_ioctl), + IBEVENT = _IOR(GPIB_CODE, 33, short), + IBRSC = _IOW(GPIB_CODE, 34, int), + IB_T1_DELAY = _IOW(GPIB_CODE, 35, unsigned int), IBLOC = _IO(GPIB_CODE, 36), - IBAUTOSPOLL = _IOW(GPIB_CODE, 38, autospoll_ioctl_t), - IBONL = _IOW(GPIB_CODE, 39, online_ioctl_t), - IBPP2_SET = _IOW(GPIB_CODE, 40, local_ppoll_mode_ioctl_t), - IBPP2_GET = _IOR(GPIB_CODE, 41, local_ppoll_mode_ioctl_t), - IBSELECT_DEVICE_PATH = _IOW(GPIB_CODE, 43, select_device_path_ioctl_t), + IBAUTOSPOLL = _IOW(GPIB_CODE, 38, short), + IBONL = _IOW(GPIB_CODE, 39, struct gpib_online_ioctl), + IBPP2_SET = _IOW(GPIB_CODE, 40, short), + IBPP2_GET = _IOR(GPIB_CODE, 41, short), + IBSELECT_DEVICE_PATH = _IOW(GPIB_CODE, 43, struct gpib_select_device_path_ioctl), // 44 was IBSELECT_SERIAL_NUMBER - IBRSV2 = _IOW(GPIB_CODE, 45, request_service2_t) + IBRSV2 = _IOW(GPIB_CODE, 45, struct gpib_request_service2) }; #endif /* _GPIB_IOCTL_H */ diff --git a/drivers/staging/greybus/camera.c b/drivers/staging/greybus/camera.c index 5d80ace41d8e..ec9fddfc0b14 100644 --- a/drivers/staging/greybus/camera.c +++ b/drivers/staging/greybus/camera.c @@ -1165,8 +1165,8 @@ static int gb_camera_debugfs_init(struct gb_camera *gcam) gcam->debugfs.buffers[i].length = 0; debugfs_create_file_aux(entry->name, entry->mask, - gcam->debugfs.root, gcam, entry, - &gb_camera_debugfs_ops); + gcam->debugfs.root, gcam, entry, + &gb_camera_debugfs_ops); } return 0; diff --git a/drivers/staging/greybus/fw-management.c b/drivers/staging/greybus/fw-management.c index a47385175582..152949c23d65 100644 --- a/drivers/staging/greybus/fw-management.c +++ b/drivers/staging/greybus/fw-management.c @@ -123,17 +123,11 @@ static int fw_mgmt_interface_fw_version_operation(struct fw_mgmt *fw_mgmt, fw_info->major = le16_to_cpu(response.major); fw_info->minor = le16_to_cpu(response.minor); - strscpy_pad(fw_info->firmware_tag, response.firmware_tag); - - /* - * The firmware-tag should be NULL terminated, otherwise throw error but - * don't fail. - */ - if (fw_info->firmware_tag[GB_FIRMWARE_TAG_MAX_SIZE - 1] != '\0') { + ret = strscpy_pad(fw_info->firmware_tag, response.firmware_tag); + if (ret == -E2BIG) dev_err(fw_mgmt->parent, - "fw-version: firmware-tag is not NULL terminated\n"); - fw_info->firmware_tag[GB_FIRMWARE_TAG_MAX_SIZE - 1] = '\0'; - } + "fw-version: truncated firmware tag: %s\n", + fw_info->firmware_tag); return 0; } @@ -152,14 +146,12 @@ static int fw_mgmt_load_and_validate_operation(struct fw_mgmt *fw_mgmt, } request.load_method = load_method; - strscpy_pad(request.firmware_tag, tag); - /* - * The firmware-tag should be NULL terminated, otherwise throw error and - * fail. - */ - if (request.firmware_tag[GB_FIRMWARE_TAG_MAX_SIZE - 1] != '\0') { - dev_err(fw_mgmt->parent, "load-and-validate: firmware-tag is not NULL terminated\n"); + ret = strscpy_pad(request.firmware_tag, tag); + if (ret == -E2BIG) { + dev_err(fw_mgmt->parent, + "load-and-validate: truncated firmware tag: %s\n", + request.firmware_tag); return -EINVAL; } @@ -248,14 +240,11 @@ static int fw_mgmt_backend_fw_version_operation(struct fw_mgmt *fw_mgmt, struct gb_fw_mgmt_backend_fw_version_response response; int ret; - strscpy_pad(request.firmware_tag, fw_info->firmware_tag); - - /* - * The firmware-tag should be NULL terminated, otherwise throw error and - * fail. - */ - if (request.firmware_tag[GB_FIRMWARE_TAG_MAX_SIZE - 1] != '\0') { - dev_err(fw_mgmt->parent, "backend-version: firmware-tag is not NULL terminated\n"); + ret = strscpy_pad(request.firmware_tag, fw_info->firmware_tag); + if (ret == -E2BIG) { + dev_err(fw_mgmt->parent, + "backend-fw-version: truncated firmware tag: %s\n", + request.firmware_tag); return -EINVAL; } @@ -302,13 +291,10 @@ static int fw_mgmt_backend_fw_update_operation(struct fw_mgmt *fw_mgmt, int ret; ret = strscpy_pad(request.firmware_tag, tag); - - /* - * The firmware-tag should be NULL terminated, otherwise throw error and - * fail. - */ if (ret == -E2BIG) { - dev_err(fw_mgmt->parent, "backend-update: firmware-tag is not NULL terminated\n"); + dev_err(fw_mgmt->parent, + "backend-fw-update: truncated firmware tag: %s\n", + request.firmware_tag); return -EINVAL; } diff --git a/drivers/staging/greybus/gpio.c b/drivers/staging/greybus/gpio.c index 16bcf7fc8158..f81c34160f72 100644 --- a/drivers/staging/greybus/gpio.c +++ b/drivers/staging/greybus/gpio.c @@ -185,8 +185,8 @@ static int gb_gpio_get_value_operation(struct gb_gpio_controller *ggc, return 0; } -static void gb_gpio_set_value_operation(struct gb_gpio_controller *ggc, - u8 which, bool value_high) +static int gb_gpio_set_value_operation(struct gb_gpio_controller *ggc, + u8 which, bool value_high) { struct device *dev = &ggc->gbphy_dev->dev; struct gb_gpio_set_value_request request; @@ -195,7 +195,7 @@ static void gb_gpio_set_value_operation(struct gb_gpio_controller *ggc, if (ggc->lines[which].direction == 1) { dev_warn(dev, "refusing to set value of input gpio %u\n", which); - return; + return -EPERM; } request.which = which; @@ -204,10 +204,12 @@ static void gb_gpio_set_value_operation(struct gb_gpio_controller *ggc, &request, sizeof(request), NULL, 0); if (ret) { dev_err(dev, "failed to set value of gpio %u\n", which); - return; + return ret; } ggc->lines[which].value = request.value; + + return 0; } static int gb_gpio_set_debounce_operation(struct gb_gpio_controller *ggc, @@ -457,11 +459,11 @@ static int gb_gpio_get(struct gpio_chip *chip, unsigned int offset) return ggc->lines[which].value; } -static void gb_gpio_set(struct gpio_chip *chip, unsigned int offset, int value) +static int gb_gpio_set(struct gpio_chip *chip, unsigned int offset, int value) { struct gb_gpio_controller *ggc = gpiochip_get_data(chip); - gb_gpio_set_value_operation(ggc, (u8)offset, !!value); + return gb_gpio_set_value_operation(ggc, (u8)offset, !!value); } static int gb_gpio_set_config(struct gpio_chip *chip, unsigned int offset, @@ -555,7 +557,7 @@ static int gb_gpio_probe(struct gbphy_device *gbphy_dev, gpio->direction_input = gb_gpio_direction_input; gpio->direction_output = gb_gpio_direction_output; gpio->get = gb_gpio_get; - gpio->set = gb_gpio_set; + gpio->set_rv = gb_gpio_set; gpio->set_config = gb_gpio_set_config; gpio->base = -1; /* Allocate base dynamically */ gpio->ngpio = ggc->line_max + 1; diff --git a/drivers/staging/iio/accel/adis16203.c b/drivers/staging/iio/accel/adis16203.c index c1c73308800c..830ff38fda92 100644 --- a/drivers/staging/iio/accel/adis16203.c +++ b/drivers/staging/iio/accel/adis16203.c @@ -294,7 +294,7 @@ static int adis16203_probe(struct spi_device *spi) static const struct of_device_id adis16203_of_match[] = { { .compatible = "adi,adis16203" }, - { }, + { } }; MODULE_DEVICE_TABLE(of, adis16203_of_match); diff --git a/drivers/staging/iio/adc/ad7816.c b/drivers/staging/iio/adc/ad7816.c index 081b17f49863..4774df778de9 100644 --- a/drivers/staging/iio/adc/ad7816.c +++ b/drivers/staging/iio/adc/ad7816.c @@ -431,7 +431,7 @@ static const struct spi_device_id ad7816_id[] = { { "ad7816", ID_AD7816 }, { "ad7817", ID_AD7817 }, { "ad7818", ID_AD7818 }, - {} + { } }; MODULE_DEVICE_TABLE(spi, ad7816_id); diff --git a/drivers/staging/iio/addac/adt7316-i2c.c b/drivers/staging/iio/addac/adt7316-i2c.c index e6ad088636f6..f45968ef94ea 100644 --- a/drivers/staging/iio/addac/adt7316-i2c.c +++ b/drivers/staging/iio/addac/adt7316-i2c.c @@ -127,7 +127,7 @@ static const struct of_device_id adt7316_of_match[] = { { .compatible = "adi,adt7516" }, { .compatible = "adi,adt7517" }, { .compatible = "adi,adt7519" }, - { }, + { } }; MODULE_DEVICE_TABLE(of, adt7316_of_match); diff --git a/drivers/staging/iio/addac/adt7316.c b/drivers/staging/iio/addac/adt7316.c index f4260786d50a..16f30c4f1aa0 100644 --- a/drivers/staging/iio/addac/adt7316.c +++ b/drivers/staging/iio/addac/adt7316.c @@ -1794,7 +1794,7 @@ static int adt7316_setup_irq(struct iio_dev *indio_dev) struct adt7316_chip_info *chip = iio_priv(indio_dev); int irq_type, ret; - irq_type = irqd_get_trigger_type(irq_get_irq_data(chip->bus.irq)); + irq_type = irq_get_trigger_type(chip->bus.irq); switch (irq_type) { case IRQF_TRIGGER_HIGH: diff --git a/drivers/staging/iio/frequency/ad9832.c b/drivers/staging/iio/frequency/ad9832.c index db42810c7664..49388da5a684 100644 --- a/drivers/staging/iio/frequency/ad9832.c +++ b/drivers/staging/iio/frequency/ad9832.c @@ -7,6 +7,8 @@ #include <asm/div64.h> +#include <linux/bitfield.h> +#include <linux/bits.h> #include <linux/clk.h> #include <linux/device.h> #include <linux/err.h> @@ -16,6 +18,7 @@ #include <linux/slab.h> #include <linux/spi/spi.h> #include <linux/sysfs.h> +#include <linux/unaligned.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> @@ -59,17 +62,17 @@ #define AD9832_CMD_SLEEPRESCLR 0xC #define AD9832_FREQ BIT(11) -#define AD9832_PHASE(x) (((x) & 3) << 9) +#define AD9832_PHASE_MASK GENMASK(10, 9) #define AD9832_SYNC BIT(13) #define AD9832_SELSRC BIT(12) #define AD9832_SLEEP BIT(13) #define AD9832_RESET BIT(12) #define AD9832_CLR BIT(11) -#define CMD_SHIFT 12 -#define ADD_SHIFT 8 #define AD9832_FREQ_BITS 32 #define AD9832_PHASE_BITS 12 -#define RES_MASK(bits) ((1 << (bits)) - 1) +#define AD9832_CMD_MSK GENMASK(15, 12) +#define AD9832_ADD_MSK GENMASK(11, 8) +#define AD9832_DAT_MSK GENMASK(7, 0) /** * struct ad9832_state - driver instance specific data @@ -127,6 +130,8 @@ static int ad9832_write_frequency(struct ad9832_state *st, { unsigned long clk_freq; unsigned long regval; + u8 regval_bytes[4]; + u16 freq_cmd; clk_freq = clk_get_rate(st->mclk); @@ -134,19 +139,15 @@ static int ad9832_write_frequency(struct ad9832_state *st, return -EINVAL; regval = ad9832_calc_freqreg(clk_freq, fout); + put_unaligned_be32(regval, regval_bytes); - st->freq_data[0] = cpu_to_be16((AD9832_CMD_FRE8BITSW << CMD_SHIFT) | - (addr << ADD_SHIFT) | - ((regval >> 24) & 0xFF)); - st->freq_data[1] = cpu_to_be16((AD9832_CMD_FRE16BITSW << CMD_SHIFT) | - ((addr - 1) << ADD_SHIFT) | - ((regval >> 16) & 0xFF)); - st->freq_data[2] = cpu_to_be16((AD9832_CMD_FRE8BITSW << CMD_SHIFT) | - ((addr - 2) << ADD_SHIFT) | - ((regval >> 8) & 0xFF)); - st->freq_data[3] = cpu_to_be16((AD9832_CMD_FRE16BITSW << CMD_SHIFT) | - ((addr - 3) << ADD_SHIFT) | - ((regval >> 0) & 0xFF)); + for (int i = 0; i < ARRAY_SIZE(regval_bytes); i++) { + freq_cmd = (i % 2 == 0) ? AD9832_CMD_FRE8BITSW : AD9832_CMD_FRE16BITSW; + + st->freq_data[i] = cpu_to_be16(FIELD_PREP(AD9832_CMD_MSK, freq_cmd) | + FIELD_PREP(AD9832_ADD_MSK, addr - i) | + FIELD_PREP(AD9832_DAT_MSK, regval_bytes[i])); + } return spi_sync(st->spi, &st->freq_msg); } @@ -154,15 +155,21 @@ static int ad9832_write_frequency(struct ad9832_state *st, static int ad9832_write_phase(struct ad9832_state *st, unsigned long addr, unsigned long phase) { + u8 phase_bytes[2]; + u16 phase_cmd; + if (phase >= BIT(AD9832_PHASE_BITS)) return -EINVAL; - st->phase_data[0] = cpu_to_be16((AD9832_CMD_PHA8BITSW << CMD_SHIFT) | - (addr << ADD_SHIFT) | - ((phase >> 8) & 0xFF)); - st->phase_data[1] = cpu_to_be16((AD9832_CMD_PHA16BITSW << CMD_SHIFT) | - ((addr - 1) << ADD_SHIFT) | - (phase & 0xFF)); + put_unaligned_be16(phase, phase_bytes); + + for (int i = 0; i < ARRAY_SIZE(phase_bytes); i++) { + phase_cmd = (i % 2 == 0) ? AD9832_CMD_PHA8BITSW : AD9832_CMD_PHA16BITSW; + + st->phase_data[i] = cpu_to_be16(FIELD_PREP(AD9832_CMD_MSK, phase_cmd) | + FIELD_PREP(AD9832_ADD_MSK, addr - i) | + FIELD_PREP(AD9832_DAT_MSK, phase_bytes[i])); + } return spi_sync(st->spi, &st->phase_msg); } @@ -193,25 +200,23 @@ static ssize_t ad9832_write(struct device *dev, struct device_attribute *attr, ret = ad9832_write_phase(st, this_attr->address, val); break; case AD9832_PINCTRL_EN: - if (val) - st->ctrl_ss &= ~AD9832_SELSRC; - else - st->ctrl_ss |= AD9832_SELSRC; - st->data = cpu_to_be16((AD9832_CMD_SYNCSELSRC << CMD_SHIFT) | - st->ctrl_ss); + st->ctrl_ss &= ~AD9832_SELSRC; + st->ctrl_ss |= FIELD_PREP(AD9832_SELSRC, val ? 0 : 1); + + st->data = cpu_to_be16(FIELD_PREP(AD9832_CMD_MSK, AD9832_CMD_SYNCSELSRC) | + st->ctrl_ss); ret = spi_sync(st->spi, &st->msg); break; case AD9832_FREQ_SYM: - if (val == 1) { - st->ctrl_fp |= AD9832_FREQ; - } else if (val == 0) { + if (val == 1 || val == 0) { st->ctrl_fp &= ~AD9832_FREQ; + st->ctrl_fp |= FIELD_PREP(AD9832_FREQ, val ? 1 : 0); } else { ret = -EINVAL; break; } - st->data = cpu_to_be16((AD9832_CMD_FPSELECT << CMD_SHIFT) | - st->ctrl_fp); + st->data = cpu_to_be16(FIELD_PREP(AD9832_CMD_MSK, AD9832_CMD_FPSELECT) | + st->ctrl_fp); ret = spi_sync(st->spi, &st->msg); break; case AD9832_PHASE_SYM: @@ -220,22 +225,21 @@ static ssize_t ad9832_write(struct device *dev, struct device_attribute *attr, break; } - st->ctrl_fp &= ~AD9832_PHASE(3); - st->ctrl_fp |= AD9832_PHASE(val); + st->ctrl_fp &= ~AD9832_PHASE_MASK; + st->ctrl_fp |= FIELD_PREP(AD9832_PHASE_MASK, val); - st->data = cpu_to_be16((AD9832_CMD_FPSELECT << CMD_SHIFT) | - st->ctrl_fp); + st->data = cpu_to_be16(FIELD_PREP(AD9832_CMD_MSK, AD9832_CMD_FPSELECT) | + st->ctrl_fp); ret = spi_sync(st->spi, &st->msg); break; case AD9832_OUTPUT_EN: if (val) - st->ctrl_src &= ~(AD9832_RESET | AD9832_SLEEP | - AD9832_CLR); + st->ctrl_src &= ~(AD9832_RESET | AD9832_SLEEP | AD9832_CLR); else - st->ctrl_src |= AD9832_RESET; + st->ctrl_src |= FIELD_PREP(AD9832_RESET, 1); - st->data = cpu_to_be16((AD9832_CMD_SLEEPRESCLR << CMD_SHIFT) | - st->ctrl_src); + st->data = cpu_to_be16(FIELD_PREP(AD9832_CMD_MSK, AD9832_CMD_SLEEPRESCLR) | + st->ctrl_src); ret = spi_sync(st->spi, &st->msg); break; default: @@ -367,8 +371,8 @@ static int ad9832_probe(struct spi_device *spi) spi_message_add_tail(&st->phase_xfer[1], &st->phase_msg); st->ctrl_src = AD9832_SLEEP | AD9832_RESET | AD9832_CLR; - st->data = cpu_to_be16((AD9832_CMD_SLEEPRESCLR << CMD_SHIFT) | - st->ctrl_src); + st->data = cpu_to_be16(FIELD_PREP(AD9832_CMD_MSK, AD9832_CMD_SLEEPRESCLR) | + st->ctrl_src); ret = spi_sync(st->spi, &st->msg); if (ret) { dev_err(&spi->dev, "device init failed\n"); @@ -402,16 +406,24 @@ static int ad9832_probe(struct spi_device *spi) return devm_iio_device_register(&spi->dev, indio_dev); } +static const struct of_device_id ad9832_of_match[] = { + { .compatible = "adi,ad9832" }, + { .compatible = "adi,ad9835" }, + { } +}; +MODULE_DEVICE_TABLE(of, ad9832_of_match); + static const struct spi_device_id ad9832_id[] = { {"ad9832", 0}, {"ad9835", 0}, - {} + { } }; MODULE_DEVICE_TABLE(spi, ad9832_id); static struct spi_driver ad9832_driver = { .driver = { .name = "ad9832", + .of_match_table = ad9832_of_match, }, .probe = ad9832_probe, .id_table = ad9832_id, diff --git a/drivers/staging/iio/frequency/ad9832.h b/drivers/staging/iio/frequency/ad9832.h index 98dfbd9289ab..d0d840edb8d2 100644 --- a/drivers/staging/iio/frequency/ad9832.h +++ b/drivers/staging/iio/frequency/ad9832.h @@ -13,7 +13,6 @@ /** * struct ad9832_platform_data - platform specific information - * @mclk: master clock in Hz * @freq0: power up freq0 tuning word in Hz * @freq1: power up freq1 tuning word in Hz * @phase0: power up phase0 value [0..4095] correlates with 0..2PI diff --git a/drivers/staging/iio/frequency/ad9834.c b/drivers/staging/iio/frequency/ad9834.c index 50413da2aa65..0038eb234d40 100644 --- a/drivers/staging/iio/frequency/ad9834.c +++ b/drivers/staging/iio/frequency/ad9834.c @@ -479,7 +479,7 @@ static const struct spi_device_id ad9834_id[] = { {"ad9834", ID_AD9834}, {"ad9837", ID_AD9837}, {"ad9838", ID_AD9838}, - {} + { } }; MODULE_DEVICE_TABLE(spi, ad9834_id); @@ -488,7 +488,7 @@ static const struct of_device_id ad9834_of_match[] = { {.compatible = "adi,ad9834"}, {.compatible = "adi,ad9837"}, {.compatible = "adi,ad9838"}, - {} + { } }; MODULE_DEVICE_TABLE(of, ad9834_of_match); diff --git a/drivers/staging/iio/impedance-analyzer/ad5933.c b/drivers/staging/iio/impedance-analyzer/ad5933.c index d5544fc2fe98..85a4223295cd 100644 --- a/drivers/staging/iio/impedance-analyzer/ad5933.c +++ b/drivers/staging/iio/impedance-analyzer/ad5933.c @@ -271,11 +271,12 @@ static ssize_t ad5933_show_frequency(struct device *dev, u8 d8[4]; } dat; - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; + ret = ad5933_i2c_read(st->client, this_attr->address, 3, &dat.d8[1]); - iio_device_release_direct_mode(indio_dev); + + iio_device_release_direct(indio_dev); if (ret < 0) return ret; @@ -305,11 +306,12 @@ static ssize_t ad5933_store_frequency(struct device *dev, if (val > AD5933_MAX_OUTPUT_FREQ_Hz) return -EINVAL; - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; + ret = ad5933_set_freq(st, this_attr->address, val); - iio_device_release_direct_mode(indio_dev); + + iio_device_release_direct(indio_dev); return ret ? ret : len; } @@ -384,9 +386,9 @@ static ssize_t ad5933_store(struct device *dev, return ret; } - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; + mutex_lock(&st->lock); switch ((u32)this_attr->address) { case AD5933_OUT_RANGE: @@ -411,7 +413,7 @@ static ssize_t ad5933_store(struct device *dev, ret = ad5933_cmd(st, 0); break; case AD5933_OUT_SETTLING_CYCLES: - val = clamp(val, (u16)0, (u16)0x7FF); + val = clamp(val, (u16)0, (u16)0x7FC); st->settling_cycles = val; /* 2x, 4x handling, see datasheet */ @@ -438,7 +440,8 @@ static ssize_t ad5933_store(struct device *dev, } mutex_unlock(&st->lock); - iio_device_release_direct_mode(indio_dev); + + iio_device_release_direct(indio_dev); return ret ? ret : len; } @@ -506,9 +509,9 @@ static int ad5933_read_raw(struct iio_dev *indio_dev, switch (m) { case IIO_CHAN_INFO_RAW: - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; + ret = ad5933_cmd(st, AD5933_CTRL_MEASURE_TEMP); if (ret < 0) goto out; @@ -521,7 +524,8 @@ static int ad5933_read_raw(struct iio_dev *indio_dev, 2, (u8 *)&dat); if (ret < 0) goto out; - iio_device_release_direct_mode(indio_dev); + + iio_device_release_direct(indio_dev); *val = sign_extend32(be16_to_cpu(dat), 13); return IIO_VAL_INT; @@ -533,7 +537,7 @@ static int ad5933_read_raw(struct iio_dev *indio_dev, return -EINVAL; out: - iio_device_release_direct_mode(indio_dev); + iio_device_release_direct(indio_dev); return ret; } @@ -724,7 +728,7 @@ static int ad5933_probe(struct i2c_client *client) static const struct i2c_device_id ad5933_id[] = { { "ad5933" }, { "ad5934" }, - {} + { } }; MODULE_DEVICE_TABLE(i2c, ad5933_id); @@ -732,7 +736,7 @@ MODULE_DEVICE_TABLE(i2c, ad5933_id); static const struct of_device_id ad5933_of_match[] = { { .compatible = "adi,ad5933" }, { .compatible = "adi,ad5934" }, - { }, + { } }; MODULE_DEVICE_TABLE(of, ad5933_of_match); diff --git a/drivers/staging/media/imx/imx-ic-prpencvf.c b/drivers/staging/media/imx/imx-ic-prpencvf.c index 2855ba2296ac..77360bfe081a 100644 --- a/drivers/staging/media/imx/imx-ic-prpencvf.c +++ b/drivers/staging/media/imx/imx-ic-prpencvf.c @@ -295,7 +295,7 @@ static irqreturn_t prp_nfb4eof_interrupt(int irq, void *dev_id) */ static void prp_eof_timeout(struct timer_list *t) { - struct prp_priv *priv = from_timer(priv, t, eof_timeout_timer); + struct prp_priv *priv = timer_container_of(priv, t, eof_timeout_timer); struct imx_media_video_dev *vdev = priv->vdev; struct imx_ic_priv *ic_priv = priv->ic_priv; diff --git a/drivers/staging/media/imx/imx-media-csi.c b/drivers/staging/media/imx/imx-media-csi.c index f1d7fce8c020..a7cd3ef95fc3 100644 --- a/drivers/staging/media/imx/imx-media-csi.c +++ b/drivers/staging/media/imx/imx-media-csi.c @@ -356,7 +356,7 @@ static irqreturn_t csi_idmac_nfb4eof_interrupt(int irq, void *dev_id) */ static void csi_idmac_eof_timeout(struct timer_list *t) { - struct csi_priv *priv = from_timer(priv, t, eof_timeout_timer); + struct csi_priv *priv = timer_container_of(priv, t, eof_timeout_timer); struct imx_media_video_dev *vdev = priv->vdev; v4l2_err(&priv->sd, "EOF timeout\n"); diff --git a/drivers/staging/rtl8723bs/core/rtw_ap.c b/drivers/staging/rtl8723bs/core/rtw_ap.c index 50022bb5911e..383a6f7c06f4 100644 --- a/drivers/staging/rtl8723bs/core/rtw_ap.c +++ b/drivers/staging/rtl8723bs/core/rtw_ap.c @@ -389,7 +389,7 @@ void update_bmc_sta(struct adapter *padapter) psta->qos_option = 0; psta->htpriv.ht_option = false; - psta->ieee8021x_blocked = 0; + psta->ieee8021x_blocked = false; memset((void *)&psta->sta_stats, 0, sizeof(struct stainfo_stats)); diff --git a/drivers/staging/rtl8723bs/core/rtw_btcoex.c b/drivers/staging/rtl8723bs/core/rtw_btcoex.c index d54095f50113..f4b19ef7b341 100644 --- a/drivers/staging/rtl8723bs/core/rtw_btcoex.c +++ b/drivers/staging/rtl8723bs/core/rtw_btcoex.c @@ -8,14 +8,14 @@ #include <rtw_btcoex.h> #include <hal_btcoex.h> -void rtw_btcoex_MediaStatusNotify(struct adapter *padapter, u8 mediaStatus) +void rtw_btcoex_MediaStatusNotify(struct adapter *padapter, u8 media_status) { - if ((mediaStatus == RT_MEDIA_CONNECT) + if ((media_status == RT_MEDIA_CONNECT) && (check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE) == true)) { rtw_hal_set_hwreg(padapter, HW_VAR_DL_RSVD_PAGE, NULL); } - hal_btcoex_MediaStatusNotify(padapter, mediaStatus); + hal_btcoex_MediaStatusNotify(padapter, media_status); } void rtw_btcoex_HaltNotify(struct adapter *padapter) @@ -52,14 +52,14 @@ void rtw_btcoex_RejectApAggregatedPacket(struct adapter *padapter, u8 enable) void rtw_btcoex_LPS_Enter(struct adapter *padapter) { struct pwrctrl_priv *pwrpriv; - u8 lpsVal; + u8 lps_val; pwrpriv = adapter_to_pwrctl(padapter); pwrpriv->bpower_saving = true; - lpsVal = hal_btcoex_LpsVal(padapter); - rtw_set_ps_mode(padapter, PS_MODE_MIN, 0, lpsVal, "BTCOEX"); + lps_val = hal_btcoex_LpsVal(padapter); + rtw_set_ps_mode(padapter, PS_MODE_MIN, 0, lps_val, "BTCOEX"); } void rtw_btcoex_LPS_Leave(struct adapter *padapter) diff --git a/drivers/staging/rtl8723bs/core/rtw_cmd.c b/drivers/staging/rtl8723bs/core/rtw_cmd.c index 1c9e8b01d9d8..437934dd255e 100644 --- a/drivers/staging/rtl8723bs/core/rtw_cmd.c +++ b/drivers/staging/rtl8723bs/core/rtw_cmd.c @@ -273,9 +273,9 @@ struct cmd_obj *_rtw_dequeue_cmd(struct __queue *queue) /* spin_lock_bh(&(queue->lock)); */ spin_lock_irqsave(&queue->lock, irqL); - if (list_empty(&queue->queue)) + if (list_empty(&queue->queue)) { obj = NULL; - else { + } else { obj = container_of(get_next(&queue->queue), struct cmd_obj, list); list_del_init(&obj->list); } @@ -695,7 +695,6 @@ u8 rtw_joinbss_cmd(struct adapter *padapter, struct wlan_network *pnetwork) /* for ies is fix buf size */ t_len = sizeof(struct wlan_bssid_ex); - /* for hidden ap to set fw_state here */ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE|WIFI_ADHOC_STATE) != true) { switch (ndis_network_mode) { @@ -738,7 +737,6 @@ u8 rtw_joinbss_cmd(struct adapter *padapter, struct wlan_network *pnetwork) psecnetwork->ie_length = rtw_restruct_sec_ie(padapter, &pnetwork->network.ies[0], &psecnetwork->ies[0], pnetwork->network.ie_length); - pqospriv->qos_option = 0; if (pregistrypriv->wmm_enable) { @@ -1032,7 +1030,6 @@ u8 rtw_reset_securitypriv_cmd(struct adapter *padapter) init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); - /* rtw_enqueue_cmd(pcmdpriv, ph2c); */ res = rtw_enqueue_cmd(pcmdpriv, ph2c); exit: @@ -1099,7 +1096,6 @@ u8 rtw_dynamic_chk_wk_cmd(struct adapter *padapter) pdrvextra_cmd_parm->pbuf = NULL; init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); - /* rtw_enqueue_cmd(pcmdpriv, ph2c); */ res = rtw_enqueue_cmd(pcmdpriv, ph2c); exit: @@ -1256,7 +1252,6 @@ static void dynamic_chk_wk_hdl(struct adapter *padapter) /* */ hal_btcoex_Handler(padapter); - /* always call rtw_ps_processor() at last one. */ rtw_ps_processor(padapter); } @@ -1367,7 +1362,6 @@ u8 rtw_dm_in_lps_wk_cmd(struct adapter *padapter) struct cmd_priv *pcmdpriv = &padapter->cmdpriv; u8 res = _SUCCESS; - ph2c = rtw_zmalloc(sizeof(struct cmd_obj)); if (!ph2c) { res = _FAIL; @@ -1850,7 +1844,6 @@ void rtw_createbss_cmd_callback(struct adapter *padapter, struct cmd_obj *pcmd) spin_lock_bh(&pmlmepriv->lock); - if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { psta = rtw_get_stainfo(&padapter->stapriv, pnetwork->mac_address); if (!psta) { diff --git a/drivers/staging/rtl8723bs/core/rtw_ieee80211.c b/drivers/staging/rtl8723bs/core/rtw_ieee80211.c index 0ed420f3d096..53d4c113b19c 100644 --- a/drivers/staging/rtl8723bs/core/rtw_ieee80211.c +++ b/drivers/staging/rtl8723bs/core/rtw_ieee80211.c @@ -988,11 +988,10 @@ void rtw_macaddr_cfg(struct device *dev, u8 *mac_addr) if (is_broadcast_ether_addr(mac) || is_zero_ether_addr(mac)) { addr = of_get_property(np, "local-mac-address", &len); - if (addr && len == ETH_ALEN) { + if (addr && len == ETH_ALEN) ether_addr_copy(mac_addr, addr); - } else { + else eth_random_addr(mac_addr); - } } } diff --git a/drivers/staging/rtl8723bs/core/rtw_mlme.c b/drivers/staging/rtl8723bs/core/rtw_mlme.c index 58de0c2fdd68..6301dbbcc472 100644 --- a/drivers/staging/rtl8723bs/core/rtw_mlme.c +++ b/drivers/staging/rtl8723bs/core/rtw_mlme.c @@ -1460,8 +1460,8 @@ void rtw_wmm_event_callback(struct adapter *padapter, u8 *pbuf) */ void _rtw_join_timeout_handler(struct timer_list *t) { - struct adapter *adapter = from_timer(adapter, t, - mlmepriv.assoc_timer); + struct adapter *adapter = timer_container_of(adapter, t, + mlmepriv.assoc_timer); struct mlme_priv *pmlmepriv = &adapter->mlmepriv; if (adapter->bDriverStopped || adapter->bSurpriseRemoved) @@ -1504,8 +1504,8 @@ void _rtw_join_timeout_handler(struct timer_list *t) */ void rtw_scan_timeout_handler(struct timer_list *t) { - struct adapter *adapter = from_timer(adapter, t, - mlmepriv.scan_to_timer); + struct adapter *adapter = timer_container_of(adapter, t, + mlmepriv.scan_to_timer); struct mlme_priv *pmlmepriv = &adapter->mlmepriv; spin_lock_bh(&pmlmepriv->lock); @@ -2022,12 +2022,12 @@ signed int rtw_restruct_sec_ie(struct adapter *adapter, u8 *in_ie, u8 *out_ie, u } iEntry = SecIsInPMKIDList(adapter, pmlmepriv->assoc_bssid); - if (iEntry < 0) { + if (iEntry < 0) return ielength; - } else { - if (authmode == WLAN_EID_RSN) - ielength = rtw_append_pmkid(adapter, iEntry, out_ie, ielength); - } + + if (authmode == WLAN_EID_RSN) + ielength = rtw_append_pmkid(adapter, iEntry, out_ie, ielength); + return ielength; } diff --git a/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c b/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c index 3d36b6f005e0..bc980d21d50e 100644 --- a/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c +++ b/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c @@ -3511,7 +3511,7 @@ void issue_action_BA(struct adapter *padapter, unsigned char *raddr, unsigned ch /* if ((psta = rtw_get_stainfo(pstapriv, pmlmeinfo->network.mac_address)) != NULL) */ psta = rtw_get_stainfo(pstapriv, raddr); if (psta) { - start_seq = (psta->sta_xmitpriv.txseq_tid[status & 0x07]&0xfff) + 1; + start_seq = (psta->sta_xmitpriv.txseq_tid[status & 0x07] % 4096u) + 1; psta->BA_starting_seqctrl[status & 0x07] = start_seq; @@ -5088,7 +5088,7 @@ void linked_status_chk(struct adapter *padapter) void survey_timer_hdl(struct timer_list *t) { struct adapter *padapter = - from_timer(padapter, t, mlmeextpriv.survey_timer); + timer_container_of(padapter, t, mlmeextpriv.survey_timer); struct cmd_obj *ph2c; struct sitesurvey_parm *psurveyPara; struct cmd_priv *pcmdpriv = &padapter->cmdpriv; @@ -5123,7 +5123,7 @@ void survey_timer_hdl(struct timer_list *t) void link_timer_hdl(struct timer_list *t) { struct adapter *padapter = - from_timer(padapter, t, mlmeextpriv.link_timer); + timer_container_of(padapter, t, mlmeextpriv.link_timer); /* static unsigned int rx_pkt = 0; */ /* static u64 tx_cnt = 0; */ /* struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); */ @@ -5161,7 +5161,7 @@ void link_timer_hdl(struct timer_list *t) void addba_timer_hdl(struct timer_list *t) { - struct sta_info *psta = from_timer(psta, t, addba_retry_timer); + struct sta_info *psta = timer_container_of(psta, t, addba_retry_timer); struct ht_priv *phtpriv; if (!psta) @@ -5179,7 +5179,7 @@ void addba_timer_hdl(struct timer_list *t) void sa_query_timer_hdl(struct timer_list *t) { struct adapter *padapter = - from_timer(padapter, t, mlmeextpriv.sa_query_timer); + timer_container_of(padapter, t, mlmeextpriv.sa_query_timer); struct mlme_priv *pmlmepriv = &padapter->mlmepriv; /* disconnect */ spin_lock_bh(&pmlmepriv->lock); diff --git a/drivers/staging/rtl8723bs/core/rtw_pwrctrl.c b/drivers/staging/rtl8723bs/core/rtw_pwrctrl.c index c60e179bb2e1..6a2583d0d3eb 100644 --- a/drivers/staging/rtl8723bs/core/rtw_pwrctrl.c +++ b/drivers/staging/rtl8723bs/core/rtw_pwrctrl.c @@ -8,7 +8,6 @@ #include <hal_data.h> #include <linux/jiffies.h> - void _ips_enter(struct adapter *padapter) { struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); @@ -56,9 +55,8 @@ int _ips_leave(struct adapter *padapter) pwrpriv->ips_leave_cnts++; result = rtw_ips_pwr_up(padapter); - if (result == _SUCCESS) { + if (result == _SUCCESS) pwrpriv->rf_pwrstate = rf_on; - } pwrpriv->bips_processing = false; pwrpriv->bkeepfwalive = false; @@ -177,7 +175,7 @@ exit: static void pwr_state_check_handler(struct timer_list *t) { struct pwrctrl_priv *pwrctrlpriv = - from_timer(pwrctrlpriv, t, pwr_state_check_timer); + timer_container_of(pwrctrlpriv, t, pwr_state_check_timer); struct adapter *padapter = pwrctrlpriv->adapter; rtw_ps_cmd(padapter); @@ -549,9 +547,8 @@ void LeaveAllPowerSaveMode(struct adapter *Adapter) LPS_Leave_check(Adapter); } else { - if (adapter_to_pwrctl(Adapter)->rf_pwrstate == rf_off) { + if (adapter_to_pwrctl(Adapter)->rf_pwrstate == rf_off) ips_leave(Adapter); - } } } @@ -677,7 +674,8 @@ exit: */ static void pwr_rpwm_timeout_handler(struct timer_list *t) { - struct pwrctrl_priv *pwrpriv = from_timer(pwrpriv, t, pwr_rpwm_timer); + struct pwrctrl_priv *pwrpriv = timer_container_of(pwrpriv, t, + pwr_rpwm_timer); if ((pwrpriv->rpwm == pwrpriv->cpwm) || (pwrpriv->cpwm >= PS_STATE_S2)) return; @@ -996,7 +994,6 @@ void rtw_init_pwrctrl_priv(struct adapter *padapter) pwrctrlpriv->wowlan_ap_mode = false; } - void rtw_free_pwrctrl_priv(struct adapter *adapter) { } diff --git a/drivers/staging/rtl8723bs/core/rtw_recv.c b/drivers/staging/rtl8723bs/core/rtw_recv.c index 895116e9f4e7..8ae527b6e0d6 100644 --- a/drivers/staging/rtl8723bs/core/rtw_recv.c +++ b/drivers/staging/rtl8723bs/core/rtw_recv.c @@ -1641,7 +1641,7 @@ static int check_indicate_seq(struct recv_reorder_ctrl *preorder_ctrl, u16 seq_n struct dvobj_priv *psdpriv = padapter->dvobj; struct debug_priv *pdbgpriv = &psdpriv->drv_dbg; u8 wsize = preorder_ctrl->wsize_b; - u16 wend = (preorder_ctrl->indicate_seq + wsize - 1) & 0xFFF;/* 4096; */ + u16 wend = (preorder_ctrl->indicate_seq + wsize - 1) % 4096u; /* Rx Reorder initialize condition. */ if (preorder_ctrl->indicate_seq == 0xFFFF) @@ -1657,7 +1657,7 @@ static int check_indicate_seq(struct recv_reorder_ctrl *preorder_ctrl, u16 seq_n /* 2. Incoming SeqNum is larger than the WinEnd => Window shift N */ /* */ if (SN_EQUAL(seq_num, preorder_ctrl->indicate_seq)) { - preorder_ctrl->indicate_seq = (preorder_ctrl->indicate_seq + 1) & 0xFFF; + preorder_ctrl->indicate_seq = (preorder_ctrl->indicate_seq + 1) % 4096u; } else if (SN_LESS(wend, seq_num)) { /* boundary situation, when seq_num cross 0xFFF */ @@ -1772,7 +1772,7 @@ static int recv_indicatepkts_in_order(struct adapter *padapter, struct recv_reor list_del_init(&(prframe->u.hdr.list)); if (SN_EQUAL(preorder_ctrl->indicate_seq, pattrib->seq_num)) - preorder_ctrl->indicate_seq = (preorder_ctrl->indicate_seq + 1) & 0xFFF; + preorder_ctrl->indicate_seq = (preorder_ctrl->indicate_seq + 1) % 4096u; /* Set this as a lock to make sure that only one thread is indicating packet. */ /* pTS->RxIndicateState = RXTS_INDICATE_PROCESSING; */ @@ -1908,7 +1908,7 @@ _err_exit: void rtw_reordering_ctrl_timeout_handler(struct timer_list *t) { struct recv_reorder_ctrl *preorder_ctrl = - from_timer(preorder_ctrl, t, reordering_ctrl_timer); + timer_container_of(preorder_ctrl, t, reordering_ctrl_timer); struct adapter *padapter = preorder_ctrl->padapter; struct __queue *ppending_recvframe_queue = &preorder_ctrl->pending_recvframe_queue; @@ -2087,7 +2087,7 @@ _recv_entry_drop: static void rtw_signal_stat_timer_hdl(struct timer_list *t) { struct adapter *adapter = - from_timer(adapter, t, recvpriv.signal_stat_timer); + timer_container_of(adapter, t, recvpriv.signal_stat_timer); struct recv_priv *recvpriv = &adapter->recvpriv; u32 tmp_s, tmp_q; diff --git a/drivers/staging/rtl8723bs/core/rtw_xmit.c b/drivers/staging/rtl8723bs/core/rtw_xmit.c index 297c93d65315..026d58b4bd7f 100644 --- a/drivers/staging/rtl8723bs/core/rtw_xmit.c +++ b/drivers/staging/rtl8723bs/core/rtw_xmit.c @@ -943,7 +943,7 @@ s32 rtw_make_wlanhdr(struct adapter *padapter, u8 *hdr, struct pkt_attrib *pattr if (psta) { psta->sta_xmitpriv.txseq_tid[pattrib->priority]++; - psta->sta_xmitpriv.txseq_tid[pattrib->priority] &= 0xFFF; + psta->sta_xmitpriv.txseq_tid[pattrib->priority] %= 4096u; pattrib->seqnum = psta->sta_xmitpriv.txseq_tid[pattrib->priority]; SetSeqNum(hdr, pattrib->seqnum); @@ -963,11 +963,14 @@ s32 rtw_make_wlanhdr(struct adapter *padapter, u8 *hdr, struct pkt_attrib *pattr if (SN_LESS(pattrib->seqnum, tx_seq)) { pattrib->ampdu_en = false;/* AGG BK */ } else if (SN_EQUAL(pattrib->seqnum, tx_seq)) { - psta->BA_starting_seqctrl[pattrib->priority & 0x0f] = (tx_seq+1)&0xfff; + psta->BA_starting_seqctrl[pattrib->priority & 0x0f] = + (tx_seq + 1) % 4096u; pattrib->ampdu_en = true;/* AGG EN */ } else { - psta->BA_starting_seqctrl[pattrib->priority & 0x0f] = (pattrib->seqnum+1)&0xfff; + psta->BA_starting_seqctrl[pattrib->priority & 0x0f] = + (pattrib->seqnum + 1) % 4096u; + pattrib->ampdu_en = true;/* AGG EN */ } } @@ -1936,7 +1939,6 @@ static void do_queue_select(struct adapter *padapter, struct pkt_attrib *pattrib s32 rtw_xmit(struct adapter *padapter, struct sk_buff **ppkt) { static unsigned long start; - static u32 drop_cnt; struct xmit_priv *pxmitpriv = &padapter->xmitpriv; struct xmit_frame *pxmitframe = NULL; @@ -1948,15 +1950,11 @@ s32 rtw_xmit(struct adapter *padapter, struct sk_buff **ppkt) pxmitframe = rtw_alloc_xmitframe(pxmitpriv); - if (jiffies_to_msecs(jiffies - start) > 2000) { + if (jiffies_to_msecs(jiffies - start) > 2000) start = jiffies; - drop_cnt = 0; - } - if (!pxmitframe) { - drop_cnt++; + if (!pxmitframe) return -1; - } res = update_attrib(padapter, *ppkt, &pxmitframe->attrib); diff --git a/drivers/staging/rtl8723bs/hal/HalBtc8723b2Ant.c b/drivers/staging/rtl8723bs/hal/HalBtc8723b2Ant.c index c1c7b5cc17a7..d32dbf94858f 100644 --- a/drivers/staging/rtl8723bs/hal/HalBtc8723b2Ant.c +++ b/drivers/staging/rtl8723bs/hal/HalBtc8723b2Ant.c @@ -1100,7 +1100,7 @@ static bool halbtc8723b2ant_IsCommonAction(struct btc_coexist *pBtCoexist) bCommon = true; } else { - if (BT_8723B_2ANT_BT_STATUS_NON_CONNECTED_IDLE == pCoexDm->btStatus) { + if (pCoexDm->btStatus == BT_8723B_2ANT_BT_STATUS_NON_CONNECTED_IDLE) { bLowPwrDisable = false; pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_DISABLE_LOW_POWER, &bLowPwrDisable); halbtc8723b2ant_LimitedRx(pBtCoexist, NORMAL_EXEC, false, false, 0x8); @@ -1115,7 +1115,7 @@ static bool halbtc8723b2ant_IsCommonAction(struct btc_coexist *pBtCoexist) halbtc8723b2ant_SwMechanism2(pBtCoexist, false, false, false, 0x18); bCommon = true; - } else if (BT_8723B_2ANT_BT_STATUS_CONNECTED_IDLE == pCoexDm->btStatus) { + } else if (pCoexDm->btStatus == BT_8723B_2ANT_BT_STATUS_CONNECTED_IDLE) { bLowPwrDisable = true; pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_DISABLE_LOW_POWER, &bLowPwrDisable); @@ -1605,7 +1605,7 @@ static void halbtc8723b2ant_ActionSco(struct btc_coexist *pBtCoexist) pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); - if (BTC_WIFI_BW_LEGACY == wifiBw) /* for SCO quality at 11b/g mode */ + if (wifiBw == BTC_WIFI_BW_LEGACY) /* for SCO quality at 11b/g mode */ halbtc8723b2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 2); else /* for SCO quality & wifi performance balance at 11n mode */ halbtc8723b2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 8); @@ -1613,7 +1613,7 @@ static void halbtc8723b2ant_ActionSco(struct btc_coexist *pBtCoexist) halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, false, 0); /* for voice quality */ /* sw mechanism */ - if (BTC_WIFI_BW_HT40 == wifiBw) { + if (wifiBw == BTC_WIFI_BW_HT40) { if ( (wifiRssiState == BTC_RSSI_STATE_HIGH) || (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) @@ -1660,7 +1660,7 @@ static void halbtc8723b2ant_ActionHid(struct btc_coexist *pBtCoexist) pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); - if (BTC_WIFI_BW_LEGACY == wifiBw) /* for HID at 11b/g mode */ + if (wifiBw == BTC_WIFI_BW_LEGACY) /* for HID at 11b/g mode */ halbtc8723b2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 7); else /* for HID quality & wifi performance balance at 11n mode */ halbtc8723b2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 9); @@ -1674,7 +1674,7 @@ static void halbtc8723b2ant_ActionHid(struct btc_coexist *pBtCoexist) halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 13); /* sw mechanism */ - if (BTC_WIFI_BW_HT40 == wifiBw) { + if (wifiBw == BTC_WIFI_BW_HT40) { if ( (wifiRssiState == BTC_RSSI_STATE_HIGH) || (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) @@ -1723,7 +1723,7 @@ static void halbtc8723b2ant_ActionA2dp(struct btc_coexist *pBtCoexist) /* sw mechanism */ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); - if (BTC_WIFI_BW_HT40 == wifiBw) { + if (wifiBw == BTC_WIFI_BW_HT40) { halbtc8723b2ant_SwMechanism1(pBtCoexist, true, false, false, false); halbtc8723b2ant_SwMechanism2(pBtCoexist, true, false, true, 0x18); } else { @@ -1755,7 +1755,7 @@ static void halbtc8723b2ant_ActionA2dp(struct btc_coexist *pBtCoexist) /* sw mechanism */ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); - if (BTC_WIFI_BW_HT40 == wifiBw) { + if (wifiBw == BTC_WIFI_BW_HT40) { if ( (wifiRssiState == BTC_RSSI_STATE_HIGH) || (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) @@ -1805,7 +1805,7 @@ static void halbtc8723b2ant_ActionA2dpPanHs(struct btc_coexist *pBtCoexist) /* sw mechanism */ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); - if (BTC_WIFI_BW_HT40 == wifiBw) { + if (wifiBw == BTC_WIFI_BW_HT40) { if ( (wifiRssiState == BTC_RSSI_STATE_HIGH) || (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) @@ -1861,7 +1861,7 @@ static void halbtc8723b2ant_ActionPanEdr(struct btc_coexist *pBtCoexist) /* sw mechanism */ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); - if (BTC_WIFI_BW_HT40 == wifiBw) { + if (wifiBw == BTC_WIFI_BW_HT40) { if ( (wifiRssiState == BTC_RSSI_STATE_HIGH) || (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) @@ -1912,7 +1912,7 @@ static void halbtc8723b2ant_ActionPanHs(struct btc_coexist *pBtCoexist) halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, false, 1); pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); - if (BTC_WIFI_BW_HT40 == wifiBw) { + if (wifiBw == BTC_WIFI_BW_HT40) { if ( (wifiRssiState == BTC_RSSI_STATE_HIGH) || (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) @@ -1964,7 +1964,7 @@ static void halbtc8723b2ant_ActionPanEdrA2dp(struct btc_coexist *pBtCoexist) (btRssiState == BTC_RSSI_STATE_STAY_HIGH) ) { halbtc8723b2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 12); - if (BTC_WIFI_BW_HT40 == wifiBw) + if (wifiBw == BTC_WIFI_BW_HT40) halbtc8723b2ant_TdmaDurationAdjust(pBtCoexist, false, true, 3); else halbtc8723b2ant_TdmaDurationAdjust(pBtCoexist, false, false, 3); @@ -1974,7 +1974,7 @@ static void halbtc8723b2ant_ActionPanEdrA2dp(struct btc_coexist *pBtCoexist) } /* sw mechanism */ - if (BTC_WIFI_BW_HT40 == wifiBw) { + if (wifiBw == BTC_WIFI_BW_HT40) { if ( (wifiRssiState == BTC_RSSI_STATE_HIGH) || (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) @@ -2019,7 +2019,7 @@ static void halbtc8723b2ant_ActionPanEdrHid(struct btc_coexist *pBtCoexist) (btRssiState == BTC_RSSI_STATE_HIGH) || (btRssiState == BTC_RSSI_STATE_STAY_HIGH) ) { - if (BTC_WIFI_BW_HT40 == wifiBw) { + if (wifiBw == BTC_WIFI_BW_HT40) { halbtc8723b2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 3); halbtc8723b2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 11); pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x1, 0xfffff, 0x780); @@ -2037,7 +2037,7 @@ static void halbtc8723b2ant_ActionPanEdrHid(struct btc_coexist *pBtCoexist) } /* sw mechanism */ - if (BTC_WIFI_BW_HT40 == wifiBw) { + if (wifiBw == BTC_WIFI_BW_HT40) { if ( (wifiRssiState == BTC_RSSI_STATE_HIGH) || (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) @@ -2090,7 +2090,7 @@ static void halbtc8723b2ant_ActionHidA2dpPanEdr(struct btc_coexist *pBtCoexist) (btRssiState == BTC_RSSI_STATE_HIGH) || (btRssiState == BTC_RSSI_STATE_STAY_HIGH) ) { - if (BTC_WIFI_BW_HT40 == wifiBw) + if (wifiBw == BTC_WIFI_BW_HT40) halbtc8723b2ant_TdmaDurationAdjust(pBtCoexist, true, true, 2); else halbtc8723b2ant_TdmaDurationAdjust(pBtCoexist, true, false, 3); @@ -2098,7 +2098,7 @@ static void halbtc8723b2ant_ActionHidA2dpPanEdr(struct btc_coexist *pBtCoexist) halbtc8723b2ant_TdmaDurationAdjust(pBtCoexist, true, true, 3); /* sw mechanism */ - if (BTC_WIFI_BW_HT40 == wifiBw) { + if (wifiBw == BTC_WIFI_BW_HT40) { if ( (wifiRssiState == BTC_RSSI_STATE_HIGH) || (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) @@ -2140,7 +2140,7 @@ static void halbtc8723b2ant_ActionHidA2dp(struct btc_coexist *pBtCoexist) halbtc8723b2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6); pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); - if (BTC_WIFI_BW_LEGACY == wifiBw) { + if (wifiBw == BTC_WIFI_BW_LEGACY) { if (BTC_RSSI_HIGH(btRssiState)) halbtc8723b2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 2); else if (BTC_RSSI_MEDIUM(btRssiState)) @@ -2173,7 +2173,7 @@ static void halbtc8723b2ant_ActionHidA2dp(struct btc_coexist *pBtCoexist) halbtc8723b2ant_TdmaDurationAdjust(pBtCoexist, true, true, 2); /* sw mechanism */ - if (BTC_WIFI_BW_HT40 == wifiBw) { + if (wifiBw == BTC_WIFI_BW_HT40) { if ( (wifiRssiState == BTC_RSSI_STATE_HIGH) || (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) @@ -2391,12 +2391,12 @@ void EXhalbtc8723b2ant_InitCoexDm(struct btc_coexist *pBtCoexist) void EXhalbtc8723b2ant_IpsNotify(struct btc_coexist *pBtCoexist, u8 type) { - if (BTC_IPS_ENTER == type) { + if (type == BTC_IPS_ENTER) { pCoexSta->bUnderIps = true; halbtc8723b2ant_WifiOffHwCfg(pBtCoexist); halbtc8723b2ant_IgnoreWlanAct(pBtCoexist, FORCE_EXEC, true); halbtc8723b2ant_CoexAllOff(pBtCoexist); - } else if (BTC_IPS_LEAVE == type) { + } else if (type == BTC_IPS_LEAVE) { pCoexSta->bUnderIps = false; halbtc8723b2ant_InitHwConfig(pBtCoexist, false); halbtc8723b2ant_InitCoexDm(pBtCoexist); @@ -2406,24 +2406,24 @@ void EXhalbtc8723b2ant_IpsNotify(struct btc_coexist *pBtCoexist, u8 type) void EXhalbtc8723b2ant_LpsNotify(struct btc_coexist *pBtCoexist, u8 type) { - if (BTC_LPS_ENABLE == type) { + if (type == BTC_LPS_ENABLE) { pCoexSta->bUnderLps = true; - } else if (BTC_LPS_DISABLE == type) { + } else if (type == BTC_LPS_DISABLE) { pCoexSta->bUnderLps = false; } } void EXhalbtc8723b2ant_ScanNotify(struct btc_coexist *pBtCoexist, u8 type) { - if (BTC_SCAN_START == type) { - } else if (BTC_SCAN_FINISH == type) { + if (type == BTC_SCAN_START) { + } else if (type == BTC_SCAN_FINISH) { } } void EXhalbtc8723b2ant_ConnectNotify(struct btc_coexist *pBtCoexist, u8 type) { - if (BTC_ASSOCIATE_START == type) { - } else if (BTC_ASSOCIATE_FINISH == type) { + if (type == BTC_ASSOCIATE_START) { + } else if (type == BTC_ASSOCIATE_FINISH) { } } @@ -2436,11 +2436,11 @@ void EXhalbtc8723b2ant_MediaStatusNotify(struct btc_coexist *pBtCoexist, u8 type /* only 2.4G we need to inform bt the chnl mask */ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U1_WIFI_CENTRAL_CHNL, &wifiCentralChnl); - if ((BTC_MEDIA_CONNECT == type) && (wifiCentralChnl <= 14)) { + if ((type == BTC_MEDIA_CONNECT) && (wifiCentralChnl <= 14)) { H2C_Parameter[0] = 0x1; H2C_Parameter[1] = wifiCentralChnl; pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); - if (BTC_WIFI_BW_HT40 == wifiBw) + if (wifiBw == BTC_WIFI_BW_HT40) H2C_Parameter[2] = 0x30; else { pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U1_AP_NUM, &apNum); @@ -2573,9 +2573,9 @@ void EXhalbtc8723b2ant_BtInfoNotify( } if ( - (BT_8723B_2ANT_BT_STATUS_ACL_BUSY == pCoexDm->btStatus) || - (BT_8723B_2ANT_BT_STATUS_SCO_BUSY == pCoexDm->btStatus) || - (BT_8723B_2ANT_BT_STATUS_ACL_SCO_BUSY == pCoexDm->btStatus) + (pCoexDm->btStatus == BT_8723B_2ANT_BT_STATUS_ACL_BUSY) || + (pCoexDm->btStatus == BT_8723B_2ANT_BT_STATUS_SCO_BUSY) || + (pCoexDm->btStatus == BT_8723B_2ANT_BT_STATUS_ACL_SCO_BUSY) ) { bBtBusy = true; bLimitedDig = true; @@ -2603,8 +2603,8 @@ void EXhalbtc8723b2ant_HaltNotify(struct btc_coexist *pBtCoexist) void EXhalbtc8723b2ant_PnpNotify(struct btc_coexist *pBtCoexist, u8 pnpState) { - if (BTC_WIFI_PNP_SLEEP == pnpState) { - } else if (BTC_WIFI_PNP_WAKE_UP == pnpState) { + if (pnpState == BTC_WIFI_PNP_SLEEP) { + } else if (pnpState == BTC_WIFI_PNP_WAKE_UP) { halbtc8723b2ant_InitHwConfig(pBtCoexist, false); halbtc8723b2ant_InitCoexDm(pBtCoexist); halbtc8723b2ant_QueryBtInfo(pBtCoexist); diff --git a/drivers/staging/rtl8723bs/hal/hal_btcoex.c b/drivers/staging/rtl8723bs/hal/hal_btcoex.c index b72cf520d576..9105594d2dde 100644 --- a/drivers/staging/rtl8723bs/hal/hal_btcoex.c +++ b/drivers/staging/rtl8723bs/hal/hal_btcoex.c @@ -91,7 +91,7 @@ static void halbtcoutsrc_LeaveLowPower(struct btc_coexist *pBtCoexist) stime = jiffies; do { ready = rtw_register_task_alive(padapter, BTCOEX_ALIVE); - if (_SUCCESS == ready) + if (ready == _SUCCESS) break; utime = jiffies_to_msecs(jiffies - stime); @@ -668,7 +668,7 @@ static void halbtcoutsrc_WriteLocalReg1Byte(void *pBtcContext, u32 RegAddr, u8 D struct btc_coexist *pBtCoexist = (struct btc_coexist *)pBtcContext; struct adapter *Adapter = pBtCoexist->Adapter; - if (BTC_INTF_SDIO == pBtCoexist->chipInterface) + if (pBtCoexist->chipInterface == BTC_INTF_SDIO) rtw_write8(Adapter, SDIO_LOCAL_BASE | RegAddr, Data); else rtw_write8(Adapter, RegAddr, Data); @@ -894,7 +894,7 @@ void EXhalbtcoutsrc_IpsNotify(struct btc_coexist *pBtCoexist, u8 type) if (pBtCoexist->bManualControl) return; - if (IPS_NONE == type) + if (type == IPS_NONE) ipsType = BTC_IPS_LEAVE; else ipsType = BTC_IPS_ENTER; @@ -922,7 +922,7 @@ void EXhalbtcoutsrc_LpsNotify(struct btc_coexist *pBtCoexist, u8 type) if (pBtCoexist->bManualControl) return; - if (PS_MODE_ACTIVE == type) + if (type == PS_MODE_ACTIVE) lpsType = BTC_LPS_DISABLE; else lpsType = BTC_LPS_ENABLE; @@ -1000,7 +1000,7 @@ void EXhalbtcoutsrc_MediaStatusNotify(struct btc_coexist *pBtCoexist, enum if (pBtCoexist->bManualControl) return; - if (RT_MEDIA_CONNECT == mediaStatus) + if (mediaStatus == RT_MEDIA_CONNECT) mStatus = BTC_MEDIA_CONNECT; else mStatus = BTC_MEDIA_DISCONNECT; @@ -1026,11 +1026,11 @@ void EXhalbtcoutsrc_SpecialPacketNotify(struct btc_coexist *pBtCoexist, u8 pktTy if (pBtCoexist->bManualControl) return; - if (PACKET_DHCP == pktType) { + if (pktType == PACKET_DHCP) { packetType = BTC_PACKET_DHCP; - } else if (PACKET_EAPOL == pktType) { + } else if (pktType == PACKET_EAPOL) { packetType = BTC_PACKET_EAPOL; - } else if (PACKET_ARP == pktType) { + } else if (pktType == PACKET_ARP) { packetType = BTC_PACKET_ARP; } else { return; @@ -1114,13 +1114,13 @@ void EXhalbtcoutsrc_Periodical(struct btc_coexist *pBtCoexist) void EXhalbtcoutsrc_SetAntNum(u8 type, u8 antNum) { - if (BT_COEX_ANT_TYPE_PG == type) { + if (type == BT_COEX_ANT_TYPE_PG) { GLBtCoexist.boardInfo.pgAntNum = antNum; GLBtCoexist.boardInfo.btdmAntNum = antNum; - } else if (BT_COEX_ANT_TYPE_ANTDIV == type) { + } else if (type == BT_COEX_ANT_TYPE_ANTDIV) { GLBtCoexist.boardInfo.btdmAntNum = antNum; /* GLBtCoexist.boardInfo.btdmAntPos = BTC_ANTENNA_AT_MAIN_PORT; */ - } else if (BT_COEX_ANT_TYPE_DETECTED == type) { + } else if (type == BT_COEX_ANT_TYPE_DETECTED) { GLBtCoexist.boardInfo.btdmAntNum = antNum; /* GLBtCoexist.boardInfo.btdmAntPos = BTC_ANTENNA_AT_MAIN_PORT; */ } diff --git a/drivers/staging/rtl8723bs/hal/hal_com.c b/drivers/staging/rtl8723bs/hal/hal_com.c index 1213a91cffff..d91e2461fd7e 100644 --- a/drivers/staging/rtl8723bs/hal/hal_com.c +++ b/drivers/staging/rtl8723bs/hal/hal_com.c @@ -890,15 +890,14 @@ static u32 Array_kfreemap[] = { void rtw_bb_rf_gain_offset(struct adapter *padapter) { u8 value = padapter->eeprompriv.EEPROMRFGainOffset; - u32 res, i = 0; u32 *Array = Array_kfreemap; u32 v1 = 0, v2 = 0, target = 0; + u32 i = 0; if (value & BIT4) { if (padapter->eeprompriv.EEPROMRFGainVal != 0xff) { - res = rtw_hal_read_rfreg(padapter, RF_PATH_A, 0x7f, 0xffffffff); - res &= 0xfff87fff; - /* res &= 0xfff87fff; */ + rtw_hal_read_rfreg(padapter, RF_PATH_A, 0x7f, 0xffffffff); + for (i = 0; i < ARRAY_SIZE(Array_kfreemap); i += 2) { v1 = Array[i]; v2 = Array[i+1]; @@ -909,9 +908,7 @@ void rtw_bb_rf_gain_offset(struct adapter *padapter) } PHY_SetRFReg(padapter, RF_PATH_A, REG_RF_BB_GAIN_OFFSET, BIT18|BIT17|BIT16|BIT15, target); - /* res |= (padapter->eeprompriv.EEPROMRFGainVal & 0x0f)<< 15; */ - /* rtw_hal_write_rfreg(padapter, RF_PATH_A, REG_RF_BB_GAIN_OFFSET, RF_GAIN_OFFSET_MASK, res); */ - res = rtw_hal_read_rfreg(padapter, RF_PATH_A, 0x7f, 0xffffffff); + rtw_hal_read_rfreg(padapter, RF_PATH_A, 0x7f, 0xffffffff); } } } diff --git a/drivers/staging/rtl8723bs/hal/odm_CfoTracking.c b/drivers/staging/rtl8723bs/hal/odm_CfoTracking.c index 928c58be6c9b..666a9f44012d 100644 --- a/drivers/staging/rtl8723bs/hal/odm_CfoTracking.c +++ b/drivers/staging/rtl8723bs/hal/odm_CfoTracking.c @@ -155,9 +155,9 @@ void ODM_CfoTracking(void *pDM_VOID) /* 4 1.6 Big jump */ if (pCfoTrack->bAdjust) { if (CFO_ave > CFO_TH_XTAL_LOW) - Adjust_Xtal = Adjust_Xtal+((CFO_ave-CFO_TH_XTAL_LOW)>>2); + Adjust_Xtal = Adjust_Xtal + ((CFO_ave - CFO_TH_XTAL_LOW) >> 2); else if (CFO_ave < (-CFO_TH_XTAL_LOW)) - Adjust_Xtal = Adjust_Xtal+((CFO_TH_XTAL_LOW-CFO_ave)>>2); + Adjust_Xtal = Adjust_Xtal + ((CFO_TH_XTAL_LOW - CFO_ave) >> 2); } /* 4 1.7 Adjust Crystal Cap. */ diff --git a/drivers/staging/rtl8723bs/hal/odm_DIG.c b/drivers/staging/rtl8723bs/hal/odm_DIG.c index 97a51546463a..1e2946a23beb 100644 --- a/drivers/staging/rtl8723bs/hal/odm_DIG.c +++ b/drivers/staging/rtl8723bs/hal/odm_DIG.c @@ -56,7 +56,7 @@ void odm_NHMBBInit(void *pDM_VOID) { struct dm_odm_t *pDM_Odm = (struct dm_odm_t *)pDM_VOID; - pDM_Odm->adaptivity_flag = 0; + pDM_Odm->adaptivity_flag = false; pDM_Odm->tolerance_cnt = 3; pDM_Odm->NHMLastTxOkcnt = 0; pDM_Odm->NHMLastRxOkcnt = 0; diff --git a/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c b/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c index e15ec6452fd0..893cab0532ed 100644 --- a/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c +++ b/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c @@ -501,8 +501,7 @@ void Hal_GetEfuseDefinition( switch (type) { case TYPE_EFUSE_MAX_SECTION: { - u8 *pMax_section; - pMax_section = pOut; + u8 *pMax_section = pOut; if (efuseType == EFUSE_WIFI) *pMax_section = EFUSE_MAX_SECTION_8723B; @@ -513,8 +512,7 @@ void Hal_GetEfuseDefinition( case TYPE_EFUSE_REAL_CONTENT_LEN: { - u16 *pu2Tmp; - pu2Tmp = pOut; + u16 *pu2Tmp = pOut; if (efuseType == EFUSE_WIFI) *pu2Tmp = EFUSE_REAL_CONTENT_LEN_8723B; @@ -525,8 +523,7 @@ void Hal_GetEfuseDefinition( case TYPE_AVAILABLE_EFUSE_BYTES_BANK: { - u16 *pu2Tmp; - pu2Tmp = pOut; + u16 *pu2Tmp = pOut; if (efuseType == EFUSE_WIFI) *pu2Tmp = (EFUSE_REAL_CONTENT_LEN_8723B-EFUSE_OOB_PROTECT_BYTES); @@ -537,8 +534,7 @@ void Hal_GetEfuseDefinition( case TYPE_AVAILABLE_EFUSE_BYTES_TOTAL: { - u16 *pu2Tmp; - pu2Tmp = pOut; + u16 *pu2Tmp = pOut; if (efuseType == EFUSE_WIFI) *pu2Tmp = (EFUSE_REAL_CONTENT_LEN_8723B-EFUSE_OOB_PROTECT_BYTES); @@ -549,8 +545,7 @@ void Hal_GetEfuseDefinition( case TYPE_EFUSE_MAP_LEN: { - u16 *pu2Tmp; - pu2Tmp = pOut; + u16 *pu2Tmp = pOut; if (efuseType == EFUSE_WIFI) *pu2Tmp = EFUSE_MAX_MAP_LEN; @@ -561,8 +556,7 @@ void Hal_GetEfuseDefinition( case TYPE_EFUSE_PROTECT_BYTES_BANK: { - u8 *pu1Tmp; - pu1Tmp = pOut; + u8 *pu1Tmp = pOut; if (efuseType == EFUSE_WIFI) *pu1Tmp = EFUSE_OOB_PROTECT_BYTES; @@ -573,8 +567,7 @@ void Hal_GetEfuseDefinition( case TYPE_EFUSE_CONTENT_LEN_BANK: { - u16 *pu2Tmp; - pu2Tmp = pOut; + u16 *pu2Tmp = pOut; if (efuseType == EFUSE_WIFI) *pu2Tmp = EFUSE_REAL_CONTENT_LEN_8723B; @@ -585,8 +578,7 @@ void Hal_GetEfuseDefinition( default: { - u8 *pu1Tmp; - pu1Tmp = pOut; + u8 *pu1Tmp = pOut; *pu1Tmp = 0; } break; @@ -835,9 +827,8 @@ static void hal_ReadEFuse_BT( } if (offset < EFUSE_BT_MAX_SECTION) { - u16 addr; + u16 addr = offset * PGPKT_DATA_SIZE; - addr = offset * PGPKT_DATA_SIZE; for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++) { /* Check word enable condition in the section */ if (!(wden & (0x01<<i))) { @@ -1196,10 +1187,9 @@ void rtl8723b_InitBeaconParameters(struct adapter *padapter) { struct hal_com_data *pHalData = GET_HAL_DATA(padapter); u16 val16; - u8 val8; + u8 val8 = DIS_TSF_UDT; - val8 = DIS_TSF_UDT; val16 = val8 | (val8 << 8); /* port0 and port1 */ /* Enable prot0 beacon function for PSTDMA */ @@ -1496,10 +1486,7 @@ s32 rtl8723b_InitLLTTable(struct adapter *padapter) { unsigned long start, passing_time; u32 val32; - s32 ret; - - - ret = _FAIL; + s32 ret = _FAIL; val32 = rtw_read32(padapter, REG_AUTO_LLT); val32 |= BIT_AUTO_INIT_LLT; @@ -2273,9 +2260,8 @@ void rtl8723b_fill_fake_txdesc( /* Encrypt the data frame if under security mode excepct null data. Suggested by CCW. */ /* */ if (bDataFrame) { - u32 EncAlg; + u32 EncAlg = padapter->securitypriv.dot11PrivacyAlgrthm; - EncAlg = padapter->securitypriv.dot11PrivacyAlgrthm; switch (EncAlg) { case _NO_PRIVACY_: SET_TX_DESC_SEC_TYPE_8723B(pDesc, 0x0); @@ -2378,9 +2364,7 @@ static void hw_var_set_opmode(struct adapter *padapter, u8 variable, u8 *val) static void hw_var_set_macaddr(struct adapter *padapter, u8 variable, u8 *val) { u8 idx = 0; - u32 reg_macid; - - reg_macid = REG_MACID; + u32 reg_macid = REG_MACID; for (idx = 0 ; idx < 6; idx++) rtw_write8(GET_PRIMARY_ADAPTER(padapter), (reg_macid+idx), val[idx]); @@ -2389,9 +2373,7 @@ static void hw_var_set_macaddr(struct adapter *padapter, u8 variable, u8 *val) static void hw_var_set_bssid(struct adapter *padapter, u8 variable, u8 *val) { u8 idx = 0; - u32 reg_bssid; - - reg_bssid = REG_BSSID; + u32 reg_bssid = REG_BSSID; for (idx = 0 ; idx < 6; idx++) rtw_write8(padapter, (reg_bssid+idx), val[idx]); @@ -2399,9 +2381,7 @@ static void hw_var_set_bssid(struct adapter *padapter, u8 variable, u8 *val) static void hw_var_set_bcn_func(struct adapter *padapter, u8 variable, u8 *val) { - u32 bcn_ctrl_reg; - - bcn_ctrl_reg = REG_BCN_CTRL; + u32 bcn_ctrl_reg = REG_BCN_CTRL; if (*(u8 *)val) rtw_write8(padapter, bcn_ctrl_reg, (EN_BCN_FUNCTION | EN_TXBCN_RPT)); @@ -2422,12 +2402,8 @@ static void hw_var_set_correct_tsf(struct adapter *padapter, u8 variable, u8 *va { u8 val8; u64 tsf; - struct mlme_ext_priv *pmlmeext; - struct mlme_ext_info *pmlmeinfo; - - - pmlmeext = &padapter->mlmeextpriv; - pmlmeinfo = &pmlmeext->mlmext_info; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; tsf = pmlmeext->TSFValue-do_div(pmlmeext->TSFValue, (pmlmeinfo->bcn_interval*1024))-1024; /* us */ @@ -2543,15 +2519,12 @@ static void hw_var_set_mlme_join(struct adapter *padapter, u8 variable, u8 *val) u8 val8; u16 val16; u32 val32; - u8 RetryLimit; - u8 type; - struct mlme_priv *pmlmepriv; + u8 RetryLimit = 0x30; + u8 type = *(u8 *)val; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; struct eeprom_priv *pEEPROM; - RetryLimit = 0x30; - type = *(u8 *)val; - pmlmepriv = &padapter->mlmepriv; pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter); if (type == 0) { /* prepare to join */ @@ -2850,12 +2823,11 @@ void SetHwReg8723B(struct adapter *padapter, u8 variable, u8 *val) case HW_VAR_ACK_PREAMBLE: { - u8 regTmp; + u8 regTmp = 0; u8 bShortPreamble = *val; /* Joseph marked out for Netgear 3500 TKIP channel 7 issue.(Temporarily) */ /* regTmp = (pHalData->nCur40MhzPrimeSC)<<5; */ - regTmp = 0; if (bShortPreamble) regTmp |= 0x80; rtw_write8(padapter, REG_RRSR+2, regTmp); @@ -3226,9 +3198,7 @@ void GetHwReg8723B(struct adapter *padapter, u8 variable, u8 *val) */ u8 SetHalDefVar8723B(struct adapter *padapter, enum hal_def_variable variable, void *pval) { - u8 bResult; - - bResult = _SUCCESS; + u8 bResult = _SUCCESS; switch (variable) { default: @@ -3244,9 +3214,7 @@ u8 SetHalDefVar8723B(struct adapter *padapter, enum hal_def_variable variable, v */ u8 GetHalDefVar8723B(struct adapter *padapter, enum hal_def_variable variable, void *pval) { - u8 bResult; - - bResult = _SUCCESS; + u8 bResult = _SUCCESS; switch (variable) { case HAL_DEF_MAX_RECVBUF_SZ: @@ -3281,9 +3249,8 @@ u8 GetHalDefVar8723B(struct adapter *padapter, enum hal_def_variable variable, v case HW_DEF_RA_INFO_DUMP: { u8 mac_id = *(u8 *)pval; - u32 cmd; + u32 cmd = 0x40000100 | mac_id; - cmd = 0x40000100 | mac_id; rtw_write32(padapter, REG_HMEBOX_DBG_2_8723B, cmd); msleep(10); rtw_read32(padapter, 0x2F0); // info 1 diff --git a/drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c b/drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c index 5dc1c12fe03e..842e19b53421 100644 --- a/drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c +++ b/drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c @@ -120,13 +120,10 @@ free_xmitbuf: */ s32 rtl8723bs_xmit_buf_handler(struct adapter *padapter) { - struct xmit_priv *pxmitpriv; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; u8 queue_empty, queue_pending; s32 ret; - - pxmitpriv = &padapter->xmitpriv; - if (wait_for_completion_interruptible(&pxmitpriv->xmit_comp)) { netdev_emerg(padapter->pnetdev, "%s: down SdioXmitBufSema fail!\n", __func__); @@ -357,12 +354,9 @@ static s32 xmit_xmitframes(struct adapter *padapter, struct xmit_priv *pxmitpriv */ static s32 rtl8723bs_xmit_handler(struct adapter *padapter) { - struct xmit_priv *pxmitpriv; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; s32 ret; - - pxmitpriv = &padapter->xmitpriv; - if (wait_for_completion_interruptible(&pxmitpriv->SdioXmitStart)) { netdev_emerg(padapter->pnetdev, "%s: SdioXmitStart fail!\n", __func__); @@ -408,13 +402,9 @@ next: int rtl8723bs_xmit_thread(void *context) { - s32 ret; - struct adapter *padapter; - struct xmit_priv *pxmitpriv; - - ret = _SUCCESS; - padapter = context; - pxmitpriv = &padapter->xmitpriv; + s32 ret = _SUCCESS; + struct adapter *padapter = context; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; allow_signal(SIGTERM); @@ -435,16 +425,13 @@ s32 rtl8723bs_mgnt_xmit( ) { s32 ret = _SUCCESS; - struct pkt_attrib *pattrib; - struct xmit_buf *pxmitbuf; + struct pkt_attrib *pattrib = &pmgntframe->attrib; + struct xmit_buf *pxmitbuf = pmgntframe->pxmitbuf; struct xmit_priv *pxmitpriv = &padapter->xmitpriv; struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter); u8 *pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; u8 txdesc_size = TXDESC_SIZE; - pattrib = &pmgntframe->attrib; - pxmitbuf = pmgntframe->pxmitbuf; - rtl8723b_update_txdesc(pmgntframe, pmgntframe->buf_addr); pxmitbuf->len = txdesc_size + pattrib->last_txcmdsz; @@ -557,15 +544,13 @@ s32 rtl8723bs_init_xmit_priv(struct adapter *padapter) void rtl8723bs_free_xmit_priv(struct adapter *padapter) { - struct xmit_priv *pxmitpriv; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; struct xmit_buf *pxmitbuf; - struct __queue *pqueue; + struct __queue *pqueue = &pxmitpriv->pending_xmitbuf_queue; struct list_head *plist, *phead; struct list_head tmplist; - pxmitpriv = &padapter->xmitpriv; - pqueue = &pxmitpriv->pending_xmitbuf_queue; phead = get_list_head(pqueue); INIT_LIST_HEAD(&tmplist); diff --git a/drivers/staging/rtl8723bs/include/hal_pwr_seq.h b/drivers/staging/rtl8723bs/include/hal_pwr_seq.h index b93d74a5b9a5..48bf7f66a06e 100644 --- a/drivers/staging/rtl8723bs/include/hal_pwr_seq.h +++ b/drivers/staging/rtl8723bs/include/hal_pwr_seq.h @@ -209,7 +209,7 @@ #define RTL8723B_TRANS_END \ /* format */ \ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, comments here*/ \ - {0xFFFF, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, 0, PWR_CMD_END, 0, 0}, + {0xFFFF, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, 0, PWR_CMD_END, 0, 0}, extern struct wlan_pwr_cfg rtl8723B_power_on_flow[RTL8723B_TRANS_CARDEMU_TO_ACT_STEPS+RTL8723B_TRANS_END_STEPS]; diff --git a/drivers/staging/rtl8723bs/include/sta_info.h b/drivers/staging/rtl8723bs/include/sta_info.h index b3535fed3de7..63343998266a 100644 --- a/drivers/staging/rtl8723bs/include/sta_info.h +++ b/drivers/staging/rtl8723bs/include/sta_info.h @@ -86,7 +86,7 @@ struct sta_info { uint qos_option; u8 hwaddr[ETH_ALEN]; - uint ieee8021x_blocked; /* 0: allowed, 1:blocked */ + bool ieee8021x_blocked; uint dot118021XPrivacy; /* aes, tkip... */ union Keytype dot11tkiptxmickey; union Keytype dot11tkiprxmickey; diff --git a/drivers/staging/rtl8723bs/os_dep/mlme_linux.c b/drivers/staging/rtl8723bs/os_dep/mlme_linux.c index 1904e82a24b5..fd4ae870a617 100644 --- a/drivers/staging/rtl8723bs/os_dep/mlme_linux.c +++ b/drivers/staging/rtl8723bs/os_dep/mlme_linux.c @@ -9,7 +9,7 @@ static void _dynamic_check_timer_handler(struct timer_list *t) { struct adapter *adapter = - from_timer(adapter, t, mlmepriv.dynamic_chk_timer); + timer_container_of(adapter, t, mlmepriv.dynamic_chk_timer); rtw_dynamic_check_timer_handler(adapter); @@ -19,7 +19,7 @@ static void _dynamic_check_timer_handler(struct timer_list *t) static void _rtw_set_scan_deny_timer_hdl(struct timer_list *t) { struct adapter *adapter = - from_timer(adapter, t, mlmepriv.set_scan_deny_timer); + timer_container_of(adapter, t, mlmepriv.set_scan_deny_timer); rtw_clear_scan_deny(adapter); } diff --git a/drivers/staging/rtl8723bs/os_dep/recv_linux.c b/drivers/staging/rtl8723bs/os_dep/recv_linux.c index ca808ded61ac..98d3e4777210 100644 --- a/drivers/staging/rtl8723bs/os_dep/recv_linux.c +++ b/drivers/staging/rtl8723bs/os_dep/recv_linux.c @@ -45,9 +45,8 @@ void rtw_os_recv_resource_free(struct recv_priv *precvpriv) /* free os related resource in struct recv_buf */ void rtw_os_recvbuf_resource_free(struct adapter *padapter, struct recv_buf *precvbuf) { - if (precvbuf->pskb) { + if (precvbuf->pskb) dev_kfree_skb_any(precvbuf->pskb); - } } struct sk_buff *rtw_os_alloc_msdu_pkt(union recv_frame *prframe, u16 nSubframe_Length, u8 *pdata) @@ -160,21 +159,19 @@ void rtw_handle_tkip_mic_err(struct adapter *padapter, u8 bgroup) } } - if (bgroup) { + if (bgroup) key_type |= NL80211_KEYTYPE_GROUP; - } else { + else key_type |= NL80211_KEYTYPE_PAIRWISE; - } cfg80211_michael_mic_failure(padapter->pnetdev, (u8 *)&pmlmepriv->assoc_bssid[0], key_type, -1, NULL, GFP_ATOMIC); memset(&ev, 0x00, sizeof(ev)); - if (bgroup) { + if (bgroup) ev.flags |= IW_MICFAILURE_GROUP; - } else { + else ev.flags |= IW_MICFAILURE_PAIRWISE; - } ev.src_addr.sa_family = ARPHRD_ETHER; memcpy(ev.src_addr.sa_data, &pmlmepriv->assoc_bssid[0], ETH_ALEN); diff --git a/drivers/staging/sm750fb/Makefile b/drivers/staging/sm750fb/Makefile index b89aa4c12e9d..f7e227df0e54 100644 --- a/drivers/staging/sm750fb/Makefile +++ b/drivers/staging/sm750fb/Makefile @@ -3,5 +3,4 @@ obj-$(CONFIG_FB_SM750) += sm750fb.o sm750fb-objs := sm750.o sm750_hw.o sm750_accel.o sm750_cursor.o \ ddk750_chip.o ddk750_power.o ddk750_mode.o \ - ddk750_display.o ddk750_swi2c.o ddk750_sii164.o \ - ddk750_dvi.o ddk750_hwi2c.o + ddk750_display.o ddk750_swi2c.o diff --git a/drivers/staging/sm750fb/TODO b/drivers/staging/sm750fb/TODO index 9dd57c566257..7ce632d040b3 100644 --- a/drivers/staging/sm750fb/TODO +++ b/drivers/staging/sm750fb/TODO @@ -3,9 +3,6 @@ TODO: - use kernel coding style - refine the code and remove unused code - Implement hardware acceleration for imageblit if image->depth > 1 -- check on hardware effects of removal of USE_HW_I2C and USE_DVICHIP (these two - are supposed to be sample code which is given here if someone wants to - use those functionalities) - must be ported to the atomic kms framework in the drm subsystem (which will give you a basic fbdev driver for free) diff --git a/drivers/staging/sm750fb/ddk750.h b/drivers/staging/sm750fb/ddk750.h index 64ef4d258a91..8a32f8cf3a98 100644 --- a/drivers/staging/sm750fb/ddk750.h +++ b/drivers/staging/sm750fb/ddk750.h @@ -14,8 +14,5 @@ #include "ddk750_chip.h" #include "ddk750_display.h" #include "ddk750_power.h" -#ifdef USE_HW_I2C -#include "ddk750_hwi2c.h" -#endif #include "ddk750_swi2c.h" #endif diff --git a/drivers/staging/sm750fb/ddk750_display.c b/drivers/staging/sm750fb/ddk750_display.c index 172624ff98b0..4e390541a507 100644 --- a/drivers/staging/sm750fb/ddk750_display.c +++ b/drivers/staging/sm750fb/ddk750_display.c @@ -3,7 +3,6 @@ #include "ddk750_chip.h" #include "ddk750_display.h" #include "ddk750_power.h" -#include "ddk750_dvi.h" static void set_display_control(int ctrl, int disp_state) { diff --git a/drivers/staging/sm750fb/ddk750_dvi.c b/drivers/staging/sm750fb/ddk750_dvi.c deleted file mode 100644 index 8b81e8642f9e..000000000000 --- a/drivers/staging/sm750fb/ddk750_dvi.c +++ /dev/null @@ -1,62 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#define USE_DVICHIP -#ifdef USE_DVICHIP -#include "ddk750_chip.h" -#include "ddk750_reg.h" -#include "ddk750_dvi.h" -#include "ddk750_sii164.h" - -/* - * This global variable contains all the supported driver and its corresponding - * function API. Please set the function pointer to NULL whenever the function - * is not supported. - */ -static struct dvi_ctrl_device dcft_supported_dvi_controller[] = { -#ifdef DVI_CTRL_SII164 - { - .init = sii164_init_chip, - .get_vendor_id = sii164_get_vendor_id, - .get_device_id = sii164GetDeviceID, -#ifdef SII164_FULL_FUNCTIONS - .reset_chip = sii164ResetChip, - .get_chip_string = sii164GetChipString, - .set_power = sii164SetPower, - .enable_hot_plug_detection = sii164EnableHotPlugDetection, - .is_connected = sii164IsConnected, - .check_interrupt = sii164CheckInterrupt, - .clear_interrupt = sii164ClearInterrupt, -#endif - }, -#endif -}; - -int dvi_init(unsigned char edge_select, - unsigned char bus_select, - unsigned char dual_edge_clk_select, - unsigned char hsync_enable, - unsigned char vsync_enable, - unsigned char deskew_enable, - unsigned char deskew_setting, - unsigned char continuous_sync_enable, - unsigned char pll_filter_enable, - unsigned char pll_filter_value) -{ - struct dvi_ctrl_device *current_dvi_ctrl; - - current_dvi_ctrl = dcft_supported_dvi_controller; - if (current_dvi_ctrl->init) { - return current_dvi_ctrl->init(edge_select, - bus_select, - dual_edge_clk_select, - hsync_enable, - vsync_enable, - deskew_enable, - deskew_setting, - continuous_sync_enable, - pll_filter_enable, - pll_filter_value); - } - return -1; /* error */ -} - -#endif diff --git a/drivers/staging/sm750fb/ddk750_dvi.h b/drivers/staging/sm750fb/ddk750_dvi.h deleted file mode 100644 index c2518b73bdbd..000000000000 --- a/drivers/staging/sm750fb/ddk750_dvi.h +++ /dev/null @@ -1,57 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef DDK750_DVI_H__ -#define DDK750_DVI_H__ - -/* dvi chip stuffs structros */ - -typedef long (*PFN_DVICTRL_INIT)(unsigned char edge_select, - unsigned char bus_select, - unsigned char dual_edge_clk_select, - unsigned char hsync_enable, - unsigned char vsync_enable, - unsigned char deskew_enable, - unsigned char deskew_setting, - unsigned char continuous_sync_enable, - unsigned char pll_filter_enable, - unsigned char pll_filter_value); - -typedef void (*PFN_DVICTRL_RESETCHIP)(void); -typedef char* (*PFN_DVICTRL_GETCHIPSTRING)(void); -typedef unsigned short (*PFN_DVICTRL_GETVENDORID)(void); -typedef unsigned short (*PFN_DVICTRL_GETDEVICEID)(void); -typedef void (*PFN_DVICTRL_SETPOWER)(unsigned char power_up); -typedef void (*PFN_DVICTRL_HOTPLUGDETECTION)(unsigned char enable_hot_plug); -typedef unsigned char (*PFN_DVICTRL_ISCONNECTED)(void); -typedef unsigned char (*PFN_DVICTRL_CHECKINTERRUPT)(void); -typedef void (*PFN_DVICTRL_CLEARINTERRUPT)(void); - -/* Structure to hold all the function pointer to the DVI Controller. */ -struct dvi_ctrl_device { - PFN_DVICTRL_INIT init; - PFN_DVICTRL_RESETCHIP reset_chip; - PFN_DVICTRL_GETCHIPSTRING get_chip_string; - PFN_DVICTRL_GETVENDORID get_vendor_id; - PFN_DVICTRL_GETDEVICEID get_device_id; - PFN_DVICTRL_SETPOWER set_power; - PFN_DVICTRL_HOTPLUGDETECTION enable_hot_plug_detection; - PFN_DVICTRL_ISCONNECTED is_connected; - PFN_DVICTRL_CHECKINTERRUPT check_interrupt; - PFN_DVICTRL_CLEARINTERRUPT clear_interrupt; -}; - -#define DVI_CTRL_SII164 - -/* dvi functions prototype */ -int dvi_init(unsigned char edge_select, - unsigned char bus_select, - unsigned char dual_edge_clk_select, - unsigned char hsync_enable, - unsigned char vsync_enable, - unsigned char deskew_enable, - unsigned char deskew_setting, - unsigned char continuous_sync_enable, - unsigned char pll_filter_enable, - unsigned char pll_filter_value); - -#endif - diff --git a/drivers/staging/sm750fb/ddk750_hwi2c.c b/drivers/staging/sm750fb/ddk750_hwi2c.c deleted file mode 100644 index 8482689b665b..000000000000 --- a/drivers/staging/sm750fb/ddk750_hwi2c.c +++ /dev/null @@ -1,247 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#define USE_HW_I2C -#ifdef USE_HW_I2C -#include "ddk750_chip.h" -#include "ddk750_reg.h" -#include "ddk750_hwi2c.h" -#include "ddk750_power.h" - -#define MAX_HWI2C_FIFO 16 -#define HWI2C_WAIT_TIMEOUT 0xF0000 - -int sm750_hw_i2c_init(unsigned char bus_speed_mode) -{ - unsigned int value; - - /* Enable GPIO 30 & 31 as IIC clock & data */ - value = peek32(GPIO_MUX); - - value |= (GPIO_MUX_30 | GPIO_MUX_31); - poke32(GPIO_MUX, value); - - /* - * Enable Hardware I2C power. - * TODO: Check if we need to enable GPIO power? - */ - sm750_enable_i2c(1); - - /* Enable the I2C Controller and set the bus speed mode */ - value = peek32(I2C_CTRL) & ~(I2C_CTRL_MODE | I2C_CTRL_EN); - if (bus_speed_mode) - value |= I2C_CTRL_MODE; - value |= I2C_CTRL_EN; - poke32(I2C_CTRL, value); - - return 0; -} - -void sm750_hw_i2c_close(void) -{ - unsigned int value; - - /* Disable I2C controller */ - value = peek32(I2C_CTRL) & ~I2C_CTRL_EN; - poke32(I2C_CTRL, value); - - /* Disable I2C Power */ - sm750_enable_i2c(0); - - /* Set GPIO 30 & 31 back as GPIO pins */ - value = peek32(GPIO_MUX); - value &= ~GPIO_MUX_30; - value &= ~GPIO_MUX_31; - poke32(GPIO_MUX, value); -} - -static long hw_i2c_wait_tx_done(void) -{ - unsigned int timeout; - - /* Wait until the transfer is completed. */ - timeout = HWI2C_WAIT_TIMEOUT; - while (!(peek32(I2C_STATUS) & I2C_STATUS_TX) && (timeout != 0)) - timeout--; - - if (timeout == 0) - return -1; - - return 0; -} - -/* - * This function writes data to the i2c slave device registers. - * - * Parameters: - * addr - i2c Slave device address - * length - Total number of bytes to be written to the device - * buf - The buffer that contains the data to be written to the - * i2c device. - * - * Return Value: - * Total number of bytes those are actually written. - */ -static unsigned int hw_i2c_write_data(unsigned char addr, - unsigned int length, - unsigned char *buf) -{ - unsigned char count, i; - unsigned int total_bytes = 0; - - /* Set the Device Address */ - poke32(I2C_SLAVE_ADDRESS, addr & ~0x01); - - /* - * Write data. - * Note: - * Only 16 byte can be accessed per i2c start instruction. - */ - do { - /* - * Reset I2C by writing 0 to I2C_RESET register to - * clear the previous status. - */ - poke32(I2C_RESET, 0); - - /* Set the number of bytes to be written */ - if (length < MAX_HWI2C_FIFO) - count = length - 1; - else - count = MAX_HWI2C_FIFO - 1; - poke32(I2C_BYTE_COUNT, count); - - /* Move the data to the I2C data register */ - for (i = 0; i <= count; i++) - poke32(I2C_DATA0 + i, *buf++); - - /* Start the I2C */ - poke32(I2C_CTRL, peek32(I2C_CTRL) | I2C_CTRL_CTRL); - - /* Wait until the transfer is completed. */ - if (hw_i2c_wait_tx_done() != 0) - break; - - /* Subtract length */ - length -= (count + 1); - - /* Total byte written */ - total_bytes += (count + 1); - - } while (length > 0); - - return total_bytes; -} - -/* - * This function reads data from the slave device and stores them - * in the given buffer - * - * Parameters: - * addr - i2c Slave device address - * length - Total number of bytes to be read - * buf - Pointer to a buffer to be filled with the data read - * from the slave device. It has to be the same size as the - * length to make sure that it can keep all the data read. - * - * Return Value: - * Total number of actual bytes read from the slave device - */ -static unsigned int hw_i2c_read_data(unsigned char addr, - unsigned int length, - unsigned char *buf) -{ - unsigned char count, i; - unsigned int total_bytes = 0; - - /* Set the Device Address */ - poke32(I2C_SLAVE_ADDRESS, addr | 0x01); - - /* - * Read data and save them to the buffer. - * Note: - * Only 16 byte can be accessed per i2c start instruction. - */ - do { - /* - * Reset I2C by writing 0 to I2C_RESET register to - * clear all the status. - */ - poke32(I2C_RESET, 0); - - /* Set the number of bytes to be read */ - if (length <= MAX_HWI2C_FIFO) - count = length - 1; - else - count = MAX_HWI2C_FIFO - 1; - poke32(I2C_BYTE_COUNT, count); - - /* Start the I2C */ - poke32(I2C_CTRL, peek32(I2C_CTRL) | I2C_CTRL_CTRL); - - /* Wait until transaction done. */ - if (hw_i2c_wait_tx_done() != 0) - break; - - /* Save the data to the given buffer */ - for (i = 0; i <= count; i++) - *buf++ = peek32(I2C_DATA0 + i); - - /* Subtract length by 16 */ - length -= (count + 1); - - /* Number of bytes read. */ - total_bytes += (count + 1); - - } while (length > 0); - - return total_bytes; -} - -/* - * This function reads the slave device's register - * - * Parameters: - * deviceAddress - i2c Slave device address which register - * to be read from - * registerIndex - Slave device's register to be read - * - * Return Value: - * Register value - */ -unsigned char sm750_hw_i2c_read_reg(unsigned char addr, unsigned char reg) -{ - unsigned char value = 0xFF; - - if (hw_i2c_write_data(addr, 1, ®) == 1) - hw_i2c_read_data(addr, 1, &value); - - return value; -} - -/* - * This function writes a value to the slave device's register - * - * Parameters: - * deviceAddress - i2c Slave device address which register - * to be written - * registerIndex - Slave device's register to be written - * data - Data to be written to the register - * - * Result: - * 0 - Success - * -1 - Fail - */ -int sm750_hw_i2c_write_reg(unsigned char addr, - unsigned char reg, - unsigned char data) -{ - unsigned char value[2]; - - value[0] = reg; - value[1] = data; - if (hw_i2c_write_data(addr, 2, value) == 2) - return 0; - - return -1; -} - -#endif diff --git a/drivers/staging/sm750fb/ddk750_hwi2c.h b/drivers/staging/sm750fb/ddk750_hwi2c.h deleted file mode 100644 index 337c6493ca61..000000000000 --- a/drivers/staging/sm750fb/ddk750_hwi2c.h +++ /dev/null @@ -1,12 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef DDK750_HWI2C_H__ -#define DDK750_HWI2C_H__ - -/* hwi2c functions */ -int sm750_hw_i2c_init(unsigned char bus_speed_mode); -void sm750_hw_i2c_close(void); - -unsigned char sm750_hw_i2c_read_reg(unsigned char addr, unsigned char reg); -int sm750_hw_i2c_write_reg(unsigned char addr, unsigned char reg, - unsigned char data); -#endif diff --git a/drivers/staging/sm750fb/ddk750_power.h b/drivers/staging/sm750fb/ddk750_power.h index 63c9e8b6ffb3..5cbb11986bb8 100644 --- a/drivers/staging/sm750fb/ddk750_power.h +++ b/drivers/staging/sm750fb/ddk750_power.h @@ -3,10 +3,10 @@ #define DDK750_POWER_H__ enum dpms { - crtDPMS_ON = 0x0, - crtDPMS_STANDBY = 0x1, - crtDPMS_SUSPEND = 0x2, - crtDPMS_OFF = 0x3, + CRT_DPMS_ON = 0x0, + CRT_DPMS_STANDBY = 0x1, + CRT_DPMS_SUSPEND = 0x2, + CRT_DPMS_OFF = 0x3, }; #define set_DAC(off) { \ diff --git a/drivers/staging/sm750fb/ddk750_sii164.c b/drivers/staging/sm750fb/ddk750_sii164.c deleted file mode 100644 index 2532b60245ac..000000000000 --- a/drivers/staging/sm750fb/ddk750_sii164.c +++ /dev/null @@ -1,408 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#define USE_DVICHIP -#ifdef USE_DVICHIP - -#include "ddk750_sii164.h" -#include "ddk750_hwi2c.h" - -/* I2C Address of each SII164 chip */ -#define SII164_I2C_ADDRESS 0x70 - -/* Define this definition to use hardware i2c. */ -#define USE_HW_I2C - -#ifdef USE_HW_I2C - #define i2cWriteReg sm750_hw_i2c_write_reg - #define i2cReadReg sm750_hw_i2c_read_reg -#else - #define i2cWriteReg sm750_sw_i2c_write_reg - #define i2cReadReg sm750_sw_i2c_read_reg -#endif - -/* SII164 Vendor and Device ID */ -#define SII164_VENDOR_ID 0x0001 -#define SII164_DEVICE_ID 0x0006 - -#ifdef SII164_FULL_FUNCTIONS -/* Name of the DVI Controller chip */ -static char *gDviCtrlChipName = "Silicon Image SiI 164"; -#endif - -/* - * sii164_get_vendor_id - * This function gets the vendor ID of the DVI controller chip. - * - * Output: - * Vendor ID - */ -unsigned short sii164_get_vendor_id(void) -{ - unsigned short vendorID; - - vendorID = ((unsigned short)i2cReadReg(SII164_I2C_ADDRESS, - SII164_VENDOR_ID_HIGH) << 8) | - (unsigned short)i2cReadReg(SII164_I2C_ADDRESS, - SII164_VENDOR_ID_LOW); - - return vendorID; -} - -/* - * sii164GetDeviceID - * This function gets the device ID of the DVI controller chip. - * - * Output: - * Device ID - */ -unsigned short sii164GetDeviceID(void) -{ - unsigned short deviceID; - - deviceID = ((unsigned short)i2cReadReg(SII164_I2C_ADDRESS, - SII164_DEVICE_ID_HIGH) << 8) | - (unsigned short)i2cReadReg(SII164_I2C_ADDRESS, - SII164_DEVICE_ID_LOW); - - return deviceID; -} - -/* - * DVI.C will handle all SiI164 chip stuffs and try its best to make code - * minimal and useful - */ - -/* - * sii164_init_chip - * This function initialize and detect the DVI controller chip. - * - * Input: - * edge_select - Edge Select: - * 0 = Input data is falling edge latched (falling - * edge latched first in dual edge mode) - * 1 = Input data is rising edge latched (rising - * edge latched first in dual edge mode) - * bus_select - Input Bus Select: - * 0 = Input data bus is 12-bits wide - * 1 = Input data bus is 24-bits wide - * dual_edge_clk_select - Dual Edge Clock Select - * 0 = Input data is single edge latched - * 1 = Input data is dual edge latched - * hsync_enable - Horizontal Sync Enable: - * 0 = HSYNC input is transmitted as fixed LOW - * 1 = HSYNC input is transmitted as is - * vsync_enable - Vertical Sync Enable: - * 0 = VSYNC input is transmitted as fixed LOW - * 1 = VSYNC input is transmitted as is - * deskew_enable - De-skewing Enable: - * 0 = De-skew disabled - * 1 = De-skew enabled - * deskew_setting - De-skewing Setting (increment of 260psec) - * 0 = 1 step --> minimum setup / maximum hold - * 1 = 2 step - * 2 = 3 step - * 3 = 4 step - * 4 = 5 step - * 5 = 6 step - * 6 = 7 step - * 7 = 8 step --> maximum setup / minimum hold - * continuous_sync_enable- SYNC Continuous: - * 0 = Disable - * 1 = Enable - * pll_filter_enable - PLL Filter Enable - * 0 = Disable PLL Filter - * 1 = Enable PLL Filter - * pll_filter_value - PLL Filter characteristics: - * 0~7 (recommended value is 4) - * - * Output: - * 0 - Success - * -1 - Fail. - */ -long sii164_init_chip(unsigned char edge_select, - unsigned char bus_select, - unsigned char dual_edge_clk_select, - unsigned char hsync_enable, - unsigned char vsync_enable, - unsigned char deskew_enable, - unsigned char deskew_setting, - unsigned char continuous_sync_enable, - unsigned char pll_filter_enable, - unsigned char pll_filter_value) -{ - unsigned char config; - - /* Initialize the i2c bus */ -#ifdef USE_HW_I2C - /* Use fast mode. */ - sm750_hw_i2c_init(1); -#else - sm750_sw_i2c_init(DEFAULT_I2C_SCL, DEFAULT_I2C_SDA); -#endif - - /* Check if SII164 Chip exists */ - if ((sii164_get_vendor_id() == SII164_VENDOR_ID) && - (sii164GetDeviceID() == SII164_DEVICE_ID)) { - /* - * Initialize SII164 controller chip. - */ - - /* Select the edge */ - if (edge_select == 0) - config = SII164_CONFIGURATION_LATCH_FALLING; - else - config = SII164_CONFIGURATION_LATCH_RISING; - - /* Select bus wide */ - if (bus_select == 0) - config |= SII164_CONFIGURATION_BUS_12BITS; - else - config |= SII164_CONFIGURATION_BUS_24BITS; - - /* Select Dual/Single Edge Clock */ - if (dual_edge_clk_select == 0) - config |= SII164_CONFIGURATION_CLOCK_SINGLE; - else - config |= SII164_CONFIGURATION_CLOCK_DUAL; - - /* Select HSync Enable */ - if (hsync_enable == 0) - config |= SII164_CONFIGURATION_HSYNC_FORCE_LOW; - else - config |= SII164_CONFIGURATION_HSYNC_AS_IS; - - /* Select VSync Enable */ - if (vsync_enable == 0) - config |= SII164_CONFIGURATION_VSYNC_FORCE_LOW; - else - config |= SII164_CONFIGURATION_VSYNC_AS_IS; - - i2cWriteReg(SII164_I2C_ADDRESS, SII164_CONFIGURATION, config); - - /* - * De-skew enabled with default 111b value. - * This fixes some artifacts problem in some mode on board 2.2. - * Somehow this fix does not affect board 2.1. - */ - if (deskew_enable == 0) - config = SII164_DESKEW_DISABLE; - else - config = SII164_DESKEW_ENABLE; - - switch (deskew_setting) { - case 0: - config |= SII164_DESKEW_1_STEP; - break; - case 1: - config |= SII164_DESKEW_2_STEP; - break; - case 2: - config |= SII164_DESKEW_3_STEP; - break; - case 3: - config |= SII164_DESKEW_4_STEP; - break; - case 4: - config |= SII164_DESKEW_5_STEP; - break; - case 5: - config |= SII164_DESKEW_6_STEP; - break; - case 6: - config |= SII164_DESKEW_7_STEP; - break; - case 7: - config |= SII164_DESKEW_8_STEP; - break; - } - i2cWriteReg(SII164_I2C_ADDRESS, SII164_DESKEW, config); - - /* Enable/Disable Continuous Sync. */ - if (continuous_sync_enable == 0) - config = SII164_PLL_FILTER_SYNC_CONTINUOUS_DISABLE; - else - config = SII164_PLL_FILTER_SYNC_CONTINUOUS_ENABLE; - - /* Enable/Disable PLL Filter */ - if (pll_filter_enable == 0) - config |= SII164_PLL_FILTER_DISABLE; - else - config |= SII164_PLL_FILTER_ENABLE; - - /* Set the PLL Filter value */ - config |= ((pll_filter_value & 0x07) << 1); - - i2cWriteReg(SII164_I2C_ADDRESS, SII164_PLL, config); - - /* Recover from Power Down and enable output. */ - config = i2cReadReg(SII164_I2C_ADDRESS, SII164_CONFIGURATION); - config |= SII164_CONFIGURATION_POWER_NORMAL; - i2cWriteReg(SII164_I2C_ADDRESS, SII164_CONFIGURATION, config); - - return 0; - } - - /* Return -1 if initialization fails. */ - return -1; -} - -/* below sii164 function is not necessary */ - -#ifdef SII164_FULL_FUNCTIONS - -/* - * sii164ResetChip - * This function resets the DVI Controller Chip. - */ -void sii164ResetChip(void) -{ - /* Power down */ - sii164SetPower(0); - sii164SetPower(1); -} - -/* - * sii164GetChipString - * This function returns a char string name of the current DVI Controller - * chip. - * - * It's convenient for application need to display the chip name. - */ -char *sii164GetChipString(void) -{ - return gDviCtrlChipName; -} - -/* - * sii164SetPower - * This function sets the power configuration of the DVI Controller Chip. - * - * Input: - * powerUp - Flag to set the power down or up - */ -void sii164SetPower(unsigned char powerUp) -{ - unsigned char config; - - config = i2cReadReg(SII164_I2C_ADDRESS, SII164_CONFIGURATION); - if (powerUp == 1) { - /* Power up the chip */ - config &= ~SII164_CONFIGURATION_POWER_MASK; - config |= SII164_CONFIGURATION_POWER_NORMAL; - i2cWriteReg(SII164_I2C_ADDRESS, SII164_CONFIGURATION, config); - } else { - /* Power down the chip */ - config &= ~SII164_CONFIGURATION_POWER_MASK; - config |= SII164_CONFIGURATION_POWER_DOWN; - i2cWriteReg(SII164_I2C_ADDRESS, SII164_CONFIGURATION, config); - } -} - -/* - * sii164SelectHotPlugDetectionMode - * This function selects the mode of the hot plug detection. - */ -static -void sii164SelectHotPlugDetectionMode(enum sii164_hot_plug_mode hotPlugMode) -{ - unsigned char detectReg; - - detectReg = i2cReadReg(SII164_I2C_ADDRESS, SII164_DETECT) & - ~SII164_DETECT_MONITOR_SENSE_OUTPUT_FLAG; - switch (hotPlugMode) { - case SII164_HOTPLUG_DISABLE: - detectReg |= SII164_DETECT_MONITOR_SENSE_OUTPUT_HIGH; - break; - case SII164_HOTPLUG_USE_MDI: - detectReg &= ~SII164_DETECT_INTERRUPT_MASK; - detectReg |= SII164_DETECT_INTERRUPT_BY_HTPLG_PIN; - detectReg |= SII164_DETECT_MONITOR_SENSE_OUTPUT_MDI; - break; - case SII164_HOTPLUG_USE_RSEN: - detectReg |= SII164_DETECT_MONITOR_SENSE_OUTPUT_RSEN; - break; - case SII164_HOTPLUG_USE_HTPLG: - detectReg |= SII164_DETECT_MONITOR_SENSE_OUTPUT_HTPLG; - break; - } - - i2cWriteReg(SII164_I2C_ADDRESS, SII164_DETECT, detectReg); -} - -/* - * sii164EnableHotPlugDetection - * This function enables the Hot Plug detection. - * - * enableHotPlug - Enable (=1) / disable (=0) Hot Plug detection - */ -void sii164EnableHotPlugDetection(unsigned char enableHotPlug) -{ - unsigned char detectReg; - - detectReg = i2cReadReg(SII164_I2C_ADDRESS, SII164_DETECT); - - /* Depending on each DVI controller, need to enable the hot plug based - * on each individual chip design. - */ - if (enableHotPlug != 0) - sii164SelectHotPlugDetectionMode(SII164_HOTPLUG_USE_MDI); - else - sii164SelectHotPlugDetectionMode(SII164_HOTPLUG_DISABLE); -} - -/* - * sii164IsConnected - * Check if the DVI Monitor is connected. - * - * Output: - * 0 - Not Connected - * 1 - Connected - */ -unsigned char sii164IsConnected(void) -{ - unsigned char hotPlugValue; - - hotPlugValue = i2cReadReg(SII164_I2C_ADDRESS, SII164_DETECT) & - SII164_DETECT_HOT_PLUG_STATUS_MASK; - if (hotPlugValue == SII164_DETECT_HOT_PLUG_STATUS_ON) - return 1; - else - return 0; -} - -/* - * sii164CheckInterrupt - * Checks if interrupt has occurred. - * - * Output: - * 0 - No interrupt - * 1 - Interrupt occurs - */ -unsigned char sii164CheckInterrupt(void) -{ - unsigned char detectReg; - - detectReg = i2cReadReg(SII164_I2C_ADDRESS, SII164_DETECT) & - SII164_DETECT_MONITOR_STATE_MASK; - if (detectReg == SII164_DETECT_MONITOR_STATE_CHANGE) - return 1; - else - return 0; -} - -/* - * sii164ClearInterrupt - * Clear the hot plug interrupt. - */ -void sii164ClearInterrupt(void) -{ - unsigned char detectReg; - - /* Clear the MDI interrupt */ - detectReg = i2cReadReg(SII164_I2C_ADDRESS, SII164_DETECT); - i2cWriteReg(SII164_I2C_ADDRESS, SII164_DETECT, - detectReg | SII164_DETECT_MONITOR_STATE_CLEAR); -} - -#endif - -#endif diff --git a/drivers/staging/sm750fb/ddk750_sii164.h b/drivers/staging/sm750fb/ddk750_sii164.h deleted file mode 100644 index 71a7c1cb42c4..000000000000 --- a/drivers/staging/sm750fb/ddk750_sii164.h +++ /dev/null @@ -1,174 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef DDK750_SII164_H__ -#define DDK750_SII164_H__ - -#define USE_DVICHIP - -/* Hot Plug detection mode structure */ -enum sii164_hot_plug_mode { - SII164_HOTPLUG_DISABLE = 0, /* Disable Hot Plug output bit - * (always high). - */ - - SII164_HOTPLUG_USE_MDI, /* Use Monitor Detect Interrupt bit. */ - SII164_HOTPLUG_USE_RSEN, /* Use Receiver Sense detect bit. */ - SII164_HOTPLUG_USE_HTPLG /* Use Hot Plug detect bit. */ -}; - -/* Silicon Image SiI164 chip prototype */ -long sii164_init_chip(unsigned char edgeSelect, - unsigned char busSelect, - unsigned char dualEdgeClkSelect, - unsigned char hsyncEnable, - unsigned char vsyncEnable, - unsigned char deskewEnable, - unsigned char deskewSetting, - unsigned char continuousSyncEnable, - unsigned char pllFilterEnable, - unsigned char pllFilterValue); - -unsigned short sii164_get_vendor_id(void); -unsigned short sii164GetDeviceID(void); - -#ifdef SII164_FULL_FUNCTIONS -void sii164ResetChip(void); -char *sii164GetChipString(void); -void sii164SetPower(unsigned char powerUp); -void sii164EnableHotPlugDetection(unsigned char enableHotPlug); -unsigned char sii164IsConnected(void); -unsigned char sii164CheckInterrupt(void); -void sii164ClearInterrupt(void); -#endif -/* - * below register definition is used for - * Silicon Image SiI164 DVI controller chip - */ -/* - * Vendor ID registers - */ -#define SII164_VENDOR_ID_LOW 0x00 -#define SII164_VENDOR_ID_HIGH 0x01 - -/* - * Device ID registers - */ -#define SII164_DEVICE_ID_LOW 0x02 -#define SII164_DEVICE_ID_HIGH 0x03 - -/* - * Device Revision - */ -#define SII164_DEVICE_REVISION 0x04 - -/* - * Frequency Limitation registers - */ -#define SII164_FREQUENCY_LIMIT_LOW 0x06 -#define SII164_FREQUENCY_LIMIT_HIGH 0x07 - -/* - * Power Down and Input Signal Configuration registers - */ -#define SII164_CONFIGURATION 0x08 - -/* Power down (PD) */ -#define SII164_CONFIGURATION_POWER_DOWN 0x00 -#define SII164_CONFIGURATION_POWER_NORMAL 0x01 -#define SII164_CONFIGURATION_POWER_MASK 0x01 - -/* Input Edge Latch Select (EDGE) */ -#define SII164_CONFIGURATION_LATCH_FALLING 0x00 -#define SII164_CONFIGURATION_LATCH_RISING 0x02 - -/* Bus Select (BSEL) */ -#define SII164_CONFIGURATION_BUS_12BITS 0x00 -#define SII164_CONFIGURATION_BUS_24BITS 0x04 - -/* Dual Edge Clock Select (DSEL) */ -#define SII164_CONFIGURATION_CLOCK_SINGLE 0x00 -#define SII164_CONFIGURATION_CLOCK_DUAL 0x08 - -/* Horizontal Sync Enable (HEN) */ -#define SII164_CONFIGURATION_HSYNC_FORCE_LOW 0x00 -#define SII164_CONFIGURATION_HSYNC_AS_IS 0x10 - -/* Vertical Sync Enable (VEN) */ -#define SII164_CONFIGURATION_VSYNC_FORCE_LOW 0x00 -#define SII164_CONFIGURATION_VSYNC_AS_IS 0x20 - -/* - * Detection registers - */ -#define SII164_DETECT 0x09 - -/* Monitor Detect Interrupt (MDI) */ -#define SII164_DETECT_MONITOR_STATE_CHANGE 0x00 -#define SII164_DETECT_MONITOR_STATE_NO_CHANGE 0x01 -#define SII164_DETECT_MONITOR_STATE_CLEAR 0x01 -#define SII164_DETECT_MONITOR_STATE_MASK 0x01 - -/* Hot Plug detect Input (HTPLG) */ -#define SII164_DETECT_HOT_PLUG_STATUS_OFF 0x00 -#define SII164_DETECT_HOT_PLUG_STATUS_ON 0x02 -#define SII164_DETECT_HOT_PLUG_STATUS_MASK 0x02 - -/* Receiver Sense (RSEN) */ -#define SII164_DETECT_RECEIVER_SENSE_NOT_DETECTED 0x00 -#define SII164_DETECT_RECEIVER_SENSE_DETECTED 0x04 - -/* Interrupt Generation Method (TSEL) */ -#define SII164_DETECT_INTERRUPT_BY_RSEN_PIN 0x00 -#define SII164_DETECT_INTERRUPT_BY_HTPLG_PIN 0x08 -#define SII164_DETECT_INTERRUPT_MASK 0x08 - -/* Monitor Sense Output (MSEN) */ -#define SII164_DETECT_MONITOR_SENSE_OUTPUT_HIGH 0x00 -#define SII164_DETECT_MONITOR_SENSE_OUTPUT_MDI 0x10 -#define SII164_DETECT_MONITOR_SENSE_OUTPUT_RSEN 0x20 -#define SII164_DETECT_MONITOR_SENSE_OUTPUT_HTPLG 0x30 -#define SII164_DETECT_MONITOR_SENSE_OUTPUT_FLAG 0x30 - -/* - * Skewing registers - */ -#define SII164_DESKEW 0x0A - -/* General Purpose Input (CTL[3:1]) */ -#define SII164_DESKEW_GENERAL_PURPOSE_INPUT_MASK 0x0E - -/* De-skewing Enable bit (DKEN) */ -#define SII164_DESKEW_DISABLE 0x00 -#define SII164_DESKEW_ENABLE 0x10 - -/* De-skewing Setting (DK[3:1])*/ -#define SII164_DESKEW_1_STEP 0x00 -#define SII164_DESKEW_2_STEP 0x20 -#define SII164_DESKEW_3_STEP 0x40 -#define SII164_DESKEW_4_STEP 0x60 -#define SII164_DESKEW_5_STEP 0x80 -#define SII164_DESKEW_6_STEP 0xA0 -#define SII164_DESKEW_7_STEP 0xC0 -#define SII164_DESKEW_8_STEP 0xE0 - -/* - * User Configuration Data registers (CFG 7:0) - */ -#define SII164_USER_CONFIGURATION 0x0B - -/* - * PLL registers - */ -#define SII164_PLL 0x0C - -/* PLL Filter Value (PLLF) */ -#define SII164_PLL_FILTER_VALUE_MASK 0x0E - -/* PLL Filter Enable (PFEN) */ -#define SII164_PLL_FILTER_DISABLE 0x00 -#define SII164_PLL_FILTER_ENABLE 0x01 - -/* Sync Continuous (SCNT) */ -#define SII164_PLL_FILTER_SYNC_CONTINUOUS_DISABLE 0x00 -#define SII164_PLL_FILTER_SYNC_CONTINUOUS_ENABLE 0x80 - -#endif diff --git a/drivers/staging/sm750fb/sm750.c b/drivers/staging/sm750fb/sm750.c index 04c1b32a22c5..1d929aca399c 100644 --- a/drivers/staging/sm750fb/sm750.c +++ b/drivers/staging/sm750fb/sm750.c @@ -120,12 +120,12 @@ static int lynxfb_ops_cursor(struct fb_info *info, struct fb_cursor *fbcursor) sm750_hw_cursor_disable(cursor); if (fbcursor->set & FB_CUR_SETSIZE) - sm750_hw_cursor_setSize(cursor, + sm750_hw_cursor_set_size(cursor, fbcursor->image.width, fbcursor->image.height); if (fbcursor->set & FB_CUR_SETPOS) - sm750_hw_cursor_setPos(cursor, + sm750_hw_cursor_set_pos(cursor, fbcursor->image.dx - info->var.xoffset, fbcursor->image.dy - info->var.yoffset); @@ -141,14 +141,12 @@ static int lynxfb_ops_cursor(struct fb_info *info, struct fb_cursor *fbcursor) ((info->cmap.green[fbcursor->image.bg_color] & 0xfc00) >> 5) | ((info->cmap.blue[fbcursor->image.bg_color] & 0xf800) >> 11); - sm750_hw_cursor_setColor(cursor, fg, bg); + sm750_hw_cursor_set_color(cursor, fg, bg); } if (fbcursor->set & (FB_CUR_SETSHAPE | FB_CUR_SETIMAGE)) { - sm750_hw_cursor_setData(cursor, - fbcursor->rop, - fbcursor->image.data, - fbcursor->mask); + sm750_hw_cursor_set_data(cursor, fbcursor->rop, fbcursor->image.data, + fbcursor->mask); } if (fbcursor->enable) @@ -394,9 +392,9 @@ static int lynxfb_ops_set_par(struct fb_info *info) pr_err("bpp %d not supported\n", var->bits_per_pixel); return ret; } - ret = hw_sm750_crtc_setMode(crtc, var, fix); + ret = hw_sm750_crtc_set_mode(crtc, var, fix); if (!ret) - ret = hw_sm750_output_setMode(output, var, fix); + ret = hw_sm750_output_set_mode(output, var, fix); return ret; } @@ -514,7 +512,7 @@ static int lynxfb_ops_check_var(struct fb_var_screeninfo *var, return -ENOMEM; } - return hw_sm750_crtc_checkMode(crtc, var); + return hw_sm750_crtc_check_mode(crtc, var); } static int lynxfb_ops_setcolreg(unsigned int regno, @@ -547,7 +545,7 @@ static int lynxfb_ops_setcolreg(unsigned int regno, red >>= 8; green >>= 8; blue >>= 8; - ret = hw_sm750_setColReg(crtc, regno, red, green, blue); + ret = hw_sm750_set_col_reg(crtc, regno, red, green, blue); goto exit; } @@ -608,10 +606,10 @@ static int sm750fb_set_drv(struct lynxfb_par *par) crtc->ywrapstep = 0; output->proc_setBLANK = (sm750_dev->revid == SM750LE_REVISION_ID) ? - hw_sm750le_setBLANK : hw_sm750_setBLANK; + hw_sm750le_set_blank : hw_sm750_set_blank; /* chip specific phase */ sm750_dev->accel.de_wait = (sm750_dev->revid == SM750LE_REVISION_ID) ? - hw_sm750le_deWait : hw_sm750_deWait; + hw_sm750le_de_wait : hw_sm750_de_wait; switch (sm750_dev->dataflow) { case sm750_simul_pri: output->paths = sm750_pnc; diff --git a/drivers/staging/sm750fb/sm750.h b/drivers/staging/sm750fb/sm750.h index aff69661c8e6..9cf8b3d30aac 100644 --- a/drivers/staging/sm750fb/sm750.h +++ b/drivers/staging/sm750fb/sm750.h @@ -193,26 +193,26 @@ static inline unsigned long ps_to_hz(unsigned int psvalue) int hw_sm750_map(struct sm750_dev *sm750_dev, struct pci_dev *pdev); int hw_sm750_inithw(struct sm750_dev *sm750_dev, struct pci_dev *pdev); -void hw_sm750_initAccel(struct sm750_dev *sm750_dev); -int hw_sm750_deWait(void); -int hw_sm750le_deWait(void); +void hw_sm750_init_accel(struct sm750_dev *sm750_dev); +int hw_sm750_de_wait(void); +int hw_sm750le_de_wait(void); -int hw_sm750_output_setMode(struct lynxfb_output *output, - struct fb_var_screeninfo *var, - struct fb_fix_screeninfo *fix); +int hw_sm750_output_set_mode(struct lynxfb_output *output, + struct fb_var_screeninfo *var, + struct fb_fix_screeninfo *fix); -int hw_sm750_crtc_checkMode(struct lynxfb_crtc *crtc, - struct fb_var_screeninfo *var); +int hw_sm750_crtc_check_mode(struct lynxfb_crtc *crtc, + struct fb_var_screeninfo *var); -int hw_sm750_crtc_setMode(struct lynxfb_crtc *crtc, - struct fb_var_screeninfo *var, - struct fb_fix_screeninfo *fix); +int hw_sm750_crtc_set_mode(struct lynxfb_crtc *crtc, + struct fb_var_screeninfo *var, + struct fb_fix_screeninfo *fix); -int hw_sm750_setColReg(struct lynxfb_crtc *crtc, ushort index, - ushort red, ushort green, ushort blue); +int hw_sm750_set_col_reg(struct lynxfb_crtc *crtc, ushort index, + ushort red, ushort green, ushort blue); -int hw_sm750_setBLANK(struct lynxfb_output *output, int blank); -int hw_sm750le_setBLANK(struct lynxfb_output *output, int blank); +int hw_sm750_set_blank(struct lynxfb_output *output, int blank); +int hw_sm750le_set_blank(struct lynxfb_output *output, int blank); int hw_sm750_pan_display(struct lynxfb_crtc *crtc, const struct fb_var_screeninfo *var, const struct fb_info *info); diff --git a/drivers/staging/sm750fb/sm750_cursor.c b/drivers/staging/sm750fb/sm750_cursor.c index eea4d1bd36ce..7ede144905c9 100644 --- a/drivers/staging/sm750fb/sm750_cursor.c +++ b/drivers/staging/sm750fb/sm750_cursor.c @@ -57,13 +57,13 @@ void sm750_hw_cursor_disable(struct lynx_cursor *cursor) poke32(HWC_ADDRESS, 0); } -void sm750_hw_cursor_setSize(struct lynx_cursor *cursor, int w, int h) +void sm750_hw_cursor_set_size(struct lynx_cursor *cursor, int w, int h) { cursor->w = w; cursor->h = h; } -void sm750_hw_cursor_setPos(struct lynx_cursor *cursor, int x, int y) +void sm750_hw_cursor_set_pos(struct lynx_cursor *cursor, int x, int y) { u32 reg; @@ -72,7 +72,7 @@ void sm750_hw_cursor_setPos(struct lynx_cursor *cursor, int x, int y) poke32(HWC_LOCATION, reg); } -void sm750_hw_cursor_setColor(struct lynx_cursor *cursor, u32 fg, u32 bg) +void sm750_hw_cursor_set_color(struct lynx_cursor *cursor, u32 fg, u32 bg) { u32 reg = (fg << HWC_COLOR_12_2_RGB565_SHIFT) & HWC_COLOR_12_2_RGB565_MASK; @@ -81,8 +81,8 @@ void sm750_hw_cursor_setColor(struct lynx_cursor *cursor, u32 fg, u32 bg) poke32(HWC_COLOR_3, 0xffe0); } -void sm750_hw_cursor_setData(struct lynx_cursor *cursor, u16 rop, - const u8 *pcol, const u8 *pmsk) +void sm750_hw_cursor_set_data(struct lynx_cursor *cursor, u16 rop, + const u8 *pcol, const u8 *pmsk) { int i, j, count, pitch, offset; u8 color, mask, opr; @@ -131,8 +131,8 @@ void sm750_hw_cursor_setData(struct lynx_cursor *cursor, u16 rop, } } -void sm750_hw_cursor_setData2(struct lynx_cursor *cursor, u16 rop, - const u8 *pcol, const u8 *pmsk) +void sm750_hw_cursor_set_data2(struct lynx_cursor *cursor, u16 rop, + const u8 *pcol, const u8 *pmsk) { int i, j, count, pitch, offset; u8 color, mask; diff --git a/drivers/staging/sm750fb/sm750_cursor.h b/drivers/staging/sm750fb/sm750_cursor.h index b59643dd61ed..88fa02f6377a 100644 --- a/drivers/staging/sm750fb/sm750_cursor.h +++ b/drivers/staging/sm750fb/sm750_cursor.h @@ -5,11 +5,11 @@ /* hw_cursor_xxx works for voyager,718 and 750 */ void sm750_hw_cursor_enable(struct lynx_cursor *cursor); void sm750_hw_cursor_disable(struct lynx_cursor *cursor); -void sm750_hw_cursor_setSize(struct lynx_cursor *cursor, int w, int h); -void sm750_hw_cursor_setPos(struct lynx_cursor *cursor, int x, int y); -void sm750_hw_cursor_setColor(struct lynx_cursor *cursor, u32 fg, u32 bg); -void sm750_hw_cursor_setData(struct lynx_cursor *cursor, u16 rop, - const u8 *data, const u8 *mask); -void sm750_hw_cursor_setData2(struct lynx_cursor *cursor, u16 rop, +void sm750_hw_cursor_set_size(struct lynx_cursor *cursor, int w, int h); +void sm750_hw_cursor_set_pos(struct lynx_cursor *cursor, int x, int y); +void sm750_hw_cursor_set_color(struct lynx_cursor *cursor, u32 fg, u32 bg); +void sm750_hw_cursor_set_data(struct lynx_cursor *cursor, u16 rop, const u8 *data, const u8 *mask); +void sm750_hw_cursor_set_data2(struct lynx_cursor *cursor, u16 rop, + const u8 *data, const u8 *mask); #endif diff --git a/drivers/staging/sm750fb/sm750_hw.c b/drivers/staging/sm750fb/sm750_hw.c index 4bc89218c11c..7119b67efe11 100644 --- a/drivers/staging/sm750fb/sm750_hw.c +++ b/drivers/staging/sm750fb/sm750_hw.c @@ -55,9 +55,8 @@ int hw_sm750_map(struct sm750_dev *sm750_dev, struct pci_dev *pdev) pr_err("mmio failed\n"); ret = -EFAULT; goto exit; - } else { - pr_info("mmio virtual addr = %p\n", sm750_dev->pvReg); } + pr_info("mmio virtual addr = %p\n", sm750_dev->pvReg); sm750_dev->accel.dprBase = sm750_dev->pvReg + DE_BASE_ADDR_TYPE1; sm750_dev->accel.dpPortBase = sm750_dev->pvReg + DE_PORT_ADDR_TYPE1; @@ -84,9 +83,8 @@ int hw_sm750_map(struct sm750_dev *sm750_dev, struct pci_dev *pdev) pr_err("Map video memory failed\n"); ret = -EFAULT; goto exit; - } else { - pr_info("video memory vaddr = %p\n", sm750_dev->pvMem); } + pr_info("video memory vaddr = %p\n", sm750_dev->pvMem); exit: return ret; } @@ -175,14 +173,14 @@ int hw_sm750_inithw(struct sm750_dev *sm750_dev, struct pci_dev *pdev) /* init 2d engine */ if (!sm750_dev->accel_off) - hw_sm750_initAccel(sm750_dev); + hw_sm750_init_accel(sm750_dev); return 0; } -int hw_sm750_output_setMode(struct lynxfb_output *output, - struct fb_var_screeninfo *var, - struct fb_fix_screeninfo *fix) +int hw_sm750_output_set_mode(struct lynxfb_output *output, + struct fb_var_screeninfo *var, + struct fb_fix_screeninfo *fix) { int ret; enum disp_output disp_set; @@ -221,8 +219,8 @@ int hw_sm750_output_setMode(struct lynxfb_output *output, return ret; } -int hw_sm750_crtc_checkMode(struct lynxfb_crtc *crtc, - struct fb_var_screeninfo *var) +int hw_sm750_crtc_check_mode(struct lynxfb_crtc *crtc, + struct fb_var_screeninfo *var) { struct sm750_dev *sm750_dev; struct lynxfb_par *par = container_of(crtc, struct lynxfb_par, crtc); @@ -247,9 +245,9 @@ int hw_sm750_crtc_checkMode(struct lynxfb_crtc *crtc, } /* set the controller's mode for @crtc charged with @var and @fix parameters */ -int hw_sm750_crtc_setMode(struct lynxfb_crtc *crtc, - struct fb_var_screeninfo *var, - struct fb_fix_screeninfo *fix) +int hw_sm750_crtc_set_mode(struct lynxfb_crtc *crtc, + struct fb_var_screeninfo *var, + struct fb_fix_screeninfo *fix) { int ret, fmt; u32 reg; @@ -372,8 +370,8 @@ exit: return ret; } -int hw_sm750_setColReg(struct lynxfb_crtc *crtc, ushort index, ushort red, - ushort green, ushort blue) +int hw_sm750_set_col_reg(struct lynxfb_crtc *crtc, ushort index, ushort red, + ushort green, ushort blue) { static unsigned int add[] = { PANEL_PALETTE_RAM, CRT_PALETTE_RAM }; @@ -382,7 +380,7 @@ int hw_sm750_setColReg(struct lynxfb_crtc *crtc, ushort index, ushort red, return 0; } -int hw_sm750le_setBLANK(struct lynxfb_output *output, int blank) +int hw_sm750le_set_blank(struct lynxfb_output *output, int blank) { int dpms, crtdb; @@ -423,7 +421,7 @@ int hw_sm750le_setBLANK(struct lynxfb_output *output, int blank) return 0; } -int hw_sm750_setBLANK(struct lynxfb_output *output, int blank) +int hw_sm750_set_blank(struct lynxfb_output *output, int blank) { unsigned int dpms, pps, crtdb; @@ -476,7 +474,7 @@ int hw_sm750_setBLANK(struct lynxfb_output *output, int blank) return 0; } -void hw_sm750_initAccel(struct sm750_dev *sm750_dev) +void hw_sm750_init_accel(struct sm750_dev *sm750_dev) { u32 reg; @@ -506,7 +504,7 @@ void hw_sm750_initAccel(struct sm750_dev *sm750_dev) sm750_dev->accel.de_init(&sm750_dev->accel); } -int hw_sm750le_deWait(void) +int hw_sm750le_de_wait(void) { int i = 0x10000000; unsigned int mask = DE_STATE2_DE_STATUS_BUSY | DE_STATE2_DE_FIFO_EMPTY | @@ -523,7 +521,7 @@ int hw_sm750le_deWait(void) return -1; } -int hw_sm750_deWait(void) +int hw_sm750_de_wait(void) { int i = 0x10000000; unsigned int mask = SYSTEM_CTRL_DE_STATUS_BUSY | diff --git a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-ctl.c b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-ctl.c index 1c1f040122d7..7d0ddd5c8cce 100644 --- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-ctl.c +++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-ctl.c @@ -71,6 +71,7 @@ static int snd_bcm2835_ctl_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol); + struct snd_ctl_elem_info info; int val, *valp; int changed = 0; @@ -84,6 +85,11 @@ static int snd_bcm2835_ctl_put(struct snd_kcontrol *kcontrol, return -EINVAL; val = ucontrol->value.integer.value[0]; + + snd_bcm2835_ctl_info(kcontrol, &info); + if (val < info.value.integer.min || val > info.value.integer.max) + return -EINVAL; + mutex_lock(&chip->audio_mutex); if (val != *valp) { *valp = val; diff --git a/drivers/staging/vc04_services/bcm2835-camera/controls.c b/drivers/staging/vc04_services/bcm2835-camera/controls.c index 6bce45925bf1..e670226f1edf 100644 --- a/drivers/staging/vc04_services/bcm2835-camera/controls.c +++ b/drivers/staging/vc04_services/bcm2835-camera/controls.c @@ -533,17 +533,15 @@ static int ctrl_set_image_effect(struct bcm2835_mmal_dev *dev, control = &dev->component[COMP_CAMERA]->control; - ret = vchiq_mmal_port_parameter_set( - dev->instance, control, - MMAL_PARAMETER_IMAGE_EFFECT_PARAMETERS, - &imagefx, sizeof(imagefx)); + ret = vchiq_mmal_port_parameter_set(dev->instance, control, + MMAL_PARAMETER_IMAGE_EFFECT_PARAMETERS, + &imagefx, sizeof(imagefx)); if (ret) goto exit; - ret = vchiq_mmal_port_parameter_set( - dev->instance, control, - MMAL_PARAMETER_COLOUR_EFFECT, - &dev->colourfx, sizeof(dev->colourfx)); + ret = vchiq_mmal_port_parameter_set(dev->instance, control, + MMAL_PARAMETER_COLOUR_EFFECT, + &dev->colourfx, sizeof(dev->colourfx)); } exit: diff --git a/drivers/target/iscsi/iscsi_target_erl0.c b/drivers/target/iscsi/iscsi_target_erl0.c index f0d7eebfcad6..24db6b07493e 100644 --- a/drivers/target/iscsi/iscsi_target_erl0.c +++ b/drivers/target/iscsi/iscsi_target_erl0.c @@ -743,7 +743,8 @@ int iscsit_check_post_dataout( void iscsit_handle_time2retain_timeout(struct timer_list *t) { - struct iscsit_session *sess = from_timer(sess, t, time2retain_timer); + struct iscsit_session *sess = timer_container_of(sess, t, + time2retain_timer); struct iscsi_portal_group *tpg = sess->tpg; struct se_portal_group *se_tpg = &tpg->tpg_se_tpg; diff --git a/drivers/target/iscsi/iscsi_target_erl1.c b/drivers/target/iscsi/iscsi_target_erl1.c index e7c3c4cdaae4..d8ca06e697d6 100644 --- a/drivers/target/iscsi/iscsi_target_erl1.c +++ b/drivers/target/iscsi/iscsi_target_erl1.c @@ -1094,7 +1094,7 @@ void iscsit_handle_dataout_timeout(struct timer_list *t) { u32 pdu_length = 0, pdu_offset = 0; u32 r2t_length = 0, r2t_offset = 0; - struct iscsit_cmd *cmd = from_timer(cmd, t, dataout_timer); + struct iscsit_cmd *cmd = timer_container_of(cmd, t, dataout_timer); struct iscsit_conn *conn = cmd->conn; struct iscsit_session *sess = NULL; struct iscsi_node_attrib *na; diff --git a/drivers/target/iscsi/iscsi_target_util.c b/drivers/target/iscsi/iscsi_target_util.c index 0bd62ab9a1cd..5e6cf34929b5 100644 --- a/drivers/target/iscsi/iscsi_target_util.c +++ b/drivers/target/iscsi/iscsi_target_util.c @@ -851,7 +851,8 @@ static int iscsit_add_nopin(struct iscsit_conn *conn, int want_response) void iscsit_handle_nopin_response_timeout(struct timer_list *t) { - struct iscsit_conn *conn = from_timer(conn, t, nopin_response_timer); + struct iscsit_conn *conn = timer_container_of(conn, t, + nopin_response_timer); struct iscsit_session *sess = conn->sess; iscsit_inc_conn_usage_count(conn); @@ -931,7 +932,7 @@ void iscsit_stop_nopin_response_timer(struct iscsit_conn *conn) void iscsit_handle_nopin_timeout(struct timer_list *t) { - struct iscsit_conn *conn = from_timer(conn, t, nopin_timer); + struct iscsit_conn *conn = timer_container_of(conn, t, nopin_timer); iscsit_inc_conn_usage_count(conn); @@ -998,7 +999,7 @@ void iscsit_stop_nopin_timer(struct iscsit_conn *conn) void iscsit_login_timeout(struct timer_list *t) { - struct iscsit_conn *conn = from_timer(conn, t, login_timer); + struct iscsit_conn *conn = timer_container_of(conn, t, login_timer); struct iscsi_login *login = conn->login; pr_debug("Entering iscsi_target_login_timeout >>>>>>>>>>>>>>>>>>>\n"); diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index 43872ccc07cc..3fd963612775 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -1564,7 +1564,7 @@ static void tcmu_device_timedout(struct tcmu_dev *udev) static void tcmu_cmd_timedout(struct timer_list *t) { - struct tcmu_dev *udev = from_timer(udev, t, cmd_timer); + struct tcmu_dev *udev = timer_container_of(udev, t, cmd_timer); pr_debug("%s cmd timeout has expired\n", udev->name); tcmu_device_timedout(udev); @@ -1572,7 +1572,7 @@ static void tcmu_cmd_timedout(struct timer_list *t) static void tcmu_qfull_timedout(struct timer_list *t) { - struct tcmu_dev *udev = from_timer(udev, t, qfull_timer); + struct tcmu_dev *udev = timer_container_of(udev, t, qfull_timer); pr_debug("%s qfull timeout has expired\n", udev->name); tcmu_device_timedout(udev); diff --git a/drivers/thunderbolt/ctl.c b/drivers/thunderbolt/ctl.c index cd15e84c47f4..1db2e951b53f 100644 --- a/drivers/thunderbolt/ctl.c +++ b/drivers/thunderbolt/ctl.c @@ -151,6 +151,11 @@ static void tb_cfg_request_dequeue(struct tb_cfg_request *req) struct tb_ctl *ctl = req->ctl; mutex_lock(&ctl->request_queue_lock); + if (!test_bit(TB_CFG_REQUEST_ACTIVE, &req->flags)) { + mutex_unlock(&ctl->request_queue_lock); + return; + } + list_del(&req->list); clear_bit(TB_CFG_REQUEST_ACTIVE, &req->flags); if (test_bit(TB_CFG_REQUEST_CANCELED, &req->flags)) diff --git a/drivers/thunderbolt/domain.c b/drivers/thunderbolt/domain.c index 144d0232a70c..a3a7c8059eee 100644 --- a/drivers/thunderbolt/domain.c +++ b/drivers/thunderbolt/domain.c @@ -217,7 +217,7 @@ static ssize_t boot_acl_store(struct device *dev, struct device_attribute *attr, ret = tb->cm_ops->set_boot_acl(tb, acl, tb->nboot_acl); if (!ret) { /* Notify userspace about the change */ - kobject_uevent(&tb->dev.kobj, KOBJ_CHANGE); + tb_domain_event(tb, NULL); } mutex_unlock(&tb->lock); diff --git a/drivers/thunderbolt/icm.c b/drivers/thunderbolt/icm.c index 7859bccc592d..f213d9174dc5 100644 --- a/drivers/thunderbolt/icm.c +++ b/drivers/thunderbolt/icm.c @@ -22,6 +22,7 @@ #include "ctl.h" #include "nhi_regs.h" #include "tb.h" +#include "tunnel.h" #define PCIE2CIO_CMD 0x30 #define PCIE2CIO_CMD_TIMEOUT BIT(31) @@ -379,6 +380,27 @@ static bool icm_firmware_running(const struct tb_nhi *nhi) return !!(val & REG_FW_STS_ICM_EN); } +static void icm_xdomain_activated(struct tb_xdomain *xd, bool activated) +{ + struct tb_port *nhi_port, *dst_port; + struct tb *tb = xd->tb; + + nhi_port = tb_switch_find_port(tb->root_switch, TB_TYPE_NHI); + dst_port = tb_xdomain_downstream_port(xd); + + if (activated) + tb_tunnel_event(tb, TB_TUNNEL_ACTIVATED, TB_TUNNEL_DMA, + nhi_port, dst_port); + else + tb_tunnel_event(tb, TB_TUNNEL_DEACTIVATED, TB_TUNNEL_DMA, + nhi_port, dst_port); +} + +static void icm_dp_event(struct tb *tb) +{ + tb_tunnel_event(tb, TB_TUNNEL_CHANGED, TB_TUNNEL_DP, NULL, NULL); +} + static bool icm_fr_is_supported(struct tb *tb) { return !x86_apple_machine; @@ -584,6 +606,7 @@ static int icm_fr_approve_xdomain_paths(struct tb *tb, struct tb_xdomain *xd, if (reply.hdr.flags & ICM_FLAGS_ERROR) return -EIO; + icm_xdomain_activated(xd, true); return 0; } @@ -603,6 +626,8 @@ static int icm_fr_disconnect_xdomain_paths(struct tb *tb, struct tb_xdomain *xd, nhi_mailbox_cmd(tb->nhi, cmd, 1); usleep_range(10, 50); nhi_mailbox_cmd(tb->nhi, cmd, 2); + + icm_xdomain_activated(xd, false); return 0; } @@ -1151,6 +1176,7 @@ static int icm_tr_approve_xdomain_paths(struct tb *tb, struct tb_xdomain *xd, if (reply.hdr.flags & ICM_FLAGS_ERROR) return -EIO; + icm_xdomain_activated(xd, true); return 0; } @@ -1191,7 +1217,12 @@ static int icm_tr_disconnect_xdomain_paths(struct tb *tb, struct tb_xdomain *xd, return ret; usleep_range(10, 50); - return icm_tr_xdomain_tear_down(tb, xd, 2); + ret = icm_tr_xdomain_tear_down(tb, xd, 2); + if (ret) + return ret; + + icm_xdomain_activated(xd, false); + return 0; } static void @@ -1718,6 +1749,9 @@ static void icm_handle_notification(struct work_struct *work) if (tb_is_xdomain_enabled()) icm->xdomain_disconnected(tb, n->pkg); break; + case ICM_EVENT_DP_CONFIG_CHANGED: + icm_dp_event(tb); + break; case ICM_EVENT_RTD3_VETO: icm->rtd3_veto(tb, n->pkg); break; diff --git a/drivers/thunderbolt/switch.c b/drivers/thunderbolt/switch.c index 6a2116cbb06f..28febb95f8fa 100644 --- a/drivers/thunderbolt/switch.c +++ b/drivers/thunderbolt/switch.c @@ -3599,6 +3599,7 @@ void tb_switch_suspend(struct tb_switch *sw, bool runtime) flags |= TB_WAKE_ON_USB4; flags |= TB_WAKE_ON_USB3 | TB_WAKE_ON_PCIE | TB_WAKE_ON_DP; } else if (device_may_wakeup(&sw->dev)) { + flags |= TB_WAKE_ON_CONNECT | TB_WAKE_ON_DISCONNECT; flags |= TB_WAKE_ON_USB4 | TB_WAKE_ON_USB3 | TB_WAKE_ON_PCIE; } diff --git a/drivers/thunderbolt/tb.c b/drivers/thunderbolt/tb.c index 8c527af98927..c14ab1fbeeaf 100644 --- a/drivers/thunderbolt/tb.c +++ b/drivers/thunderbolt/tb.c @@ -952,6 +952,15 @@ static int tb_tunnel_usb3(struct tb *tb, struct tb_switch *sw) tb_port_dbg(up, "available bandwidth for new USB3 tunnel %d/%d Mb/s\n", available_up, available_down); + /* + * If the available bandwidth is less than 1.5 Gb/s notify + * userspace that the connected isochronous device may not work + * properly. + */ + if (available_up < 1500 || available_down < 1500) + tb_tunnel_event(tb, TB_TUNNEL_LOW_BANDWIDTH, TB_TUNNEL_USB3, + down, up); + tunnel = tb_tunnel_alloc_usb3(tb, up, down, available_up, available_down); if (!tunnel) { @@ -2000,8 +2009,10 @@ static void tb_tunnel_one_dp(struct tb *tb, struct tb_port *in, ret = tb_available_bandwidth(tb, in, out, &available_up, &available_down, true); - if (ret) + if (ret) { + tb_tunnel_event(tb, TB_TUNNEL_NO_BANDWIDTH, TB_TUNNEL_DP, in, out); goto err_reclaim_usb; + } tb_dbg(tb, "available bandwidth for new DP tunnel %u/%u Mb/s\n", available_up, available_down); @@ -2622,8 +2633,12 @@ static int tb_alloc_dp_bandwidth(struct tb_tunnel *tunnel, int *requested_up, } } - return tb_tunnel_alloc_bandwidth(tunnel, requested_up, - requested_down); + ret = tb_tunnel_alloc_bandwidth(tunnel, requested_up, + requested_down); + if (ret) + goto fail; + + return 0; } /* @@ -2699,6 +2714,7 @@ fail: "failing the request by rewriting allocated %d/%d Mb/s\n", allocated_up, allocated_down); tb_tunnel_alloc_bandwidth(tunnel, &allocated_up, &allocated_down); + tb_tunnel_event(tb, TB_TUNNEL_NO_BANDWIDTH, TB_TUNNEL_DP, in, out); } return ret; diff --git a/drivers/thunderbolt/tb.h b/drivers/thunderbolt/tb.h index b54147a1ba87..87afd5a7c504 100644 --- a/drivers/thunderbolt/tb.h +++ b/drivers/thunderbolt/tb.h @@ -804,6 +804,19 @@ static inline void tb_domain_put(struct tb *tb) put_device(&tb->dev); } +/** + * tb_domain_event() - Notify userspace about an event in domain + * @tb: Domain where event occurred + * @envp: Array of uevent environment strings (can be %NULL) + * + * This function provides a way to notify userspace about any events + * that take place in the domain. + */ +static inline void tb_domain_event(struct tb *tb, char *envp[]) +{ + kobject_uevent_env(&tb->dev.kobj, KOBJ_CHANGE, envp); +} + struct tb_nvm *tb_nvm_alloc(struct device *dev); int tb_nvm_read_version(struct tb_nvm *nvm); int tb_nvm_validate(struct tb_nvm *nvm); @@ -1468,6 +1481,7 @@ static inline struct usb4_port *tb_to_usb4_port_device(struct device *dev) struct usb4_port *usb4_port_device_add(struct tb_port *port); void usb4_port_device_remove(struct usb4_port *usb4); int usb4_port_device_resume(struct usb4_port *usb4); +int usb4_port_index(const struct tb_switch *sw, const struct tb_port *port); static inline bool usb4_port_device_is_offline(const struct usb4_port *usb4) { diff --git a/drivers/thunderbolt/tb_msgs.h b/drivers/thunderbolt/tb_msgs.h index a1670a96cbdc..144f7332d5d2 100644 --- a/drivers/thunderbolt/tb_msgs.h +++ b/drivers/thunderbolt/tb_msgs.h @@ -118,6 +118,7 @@ enum icm_event_code { ICM_EVENT_DEVICE_DISCONNECTED = 0x4, ICM_EVENT_XDOMAIN_CONNECTED = 0x6, ICM_EVENT_XDOMAIN_DISCONNECTED = 0x7, + ICM_EVENT_DP_CONFIG_CHANGED = 0x8, ICM_EVENT_RTD3_VETO = 0xa, }; diff --git a/drivers/thunderbolt/tunnel.c b/drivers/thunderbolt/tunnel.c index 76254ed3f47f..d52efe3f658c 100644 --- a/drivers/thunderbolt/tunnel.c +++ b/drivers/thunderbolt/tunnel.c @@ -100,6 +100,14 @@ MODULE_PARM_DESC(bw_alloc_mode, static const char * const tb_tunnel_names[] = { "PCI", "DP", "DMA", "USB3" }; +static const char * const tb_event_names[] = { + [TB_TUNNEL_ACTIVATED] = "activated", + [TB_TUNNEL_CHANGED] = "changed", + [TB_TUNNEL_DEACTIVATED] = "deactivated", + [TB_TUNNEL_LOW_BANDWIDTH] = "low bandwidth", + [TB_TUNNEL_NO_BANDWIDTH] = "insufficient bandwidth", +}; + /* Synchronizes kref_get()/put() of struct tb_tunnel */ static DEFINE_MUTEX(tb_tunnel_lock); @@ -220,6 +228,72 @@ void tb_tunnel_put(struct tb_tunnel *tunnel) mutex_unlock(&tb_tunnel_lock); } +/** + * tb_tunnel_event() - Notify userspace about tunneling event + * @tb: Domain where the event occurred + * @event: Event that happened + * @type: Type of the tunnel in question + * @src_port: Tunnel source port (can be %NULL) + * @dst_port: Tunnel destination port (can be %NULL) + * + * Notifies userspace about tunneling @event in the domain. The tunnel + * does not need to exist (e.g the tunnel was not activated because + * there is not enough bandwidth). If the @src_port and @dst_port are + * given fill in full %TUNNEL_DETAILS environment variable. Otherwise + * uses the shorter one (just the tunnel type). + */ +void tb_tunnel_event(struct tb *tb, enum tb_tunnel_event event, + enum tb_tunnel_type type, + const struct tb_port *src_port, + const struct tb_port *dst_port) +{ + char *envp[3] = { NULL }; + + if (WARN_ON_ONCE(event >= ARRAY_SIZE(tb_event_names))) + return; + if (WARN_ON_ONCE(type >= ARRAY_SIZE(tb_tunnel_names))) + return; + + envp[0] = kasprintf(GFP_KERNEL, "TUNNEL_EVENT=%s", tb_event_names[event]); + if (!envp[0]) + return; + + if (src_port != NULL && dst_port != NULL) { + envp[1] = kasprintf(GFP_KERNEL, "TUNNEL_DETAILS=%llx:%u <-> %llx:%u (%s)", + tb_route(src_port->sw), src_port->port, + tb_route(dst_port->sw), dst_port->port, + tb_tunnel_names[type]); + } else { + envp[1] = kasprintf(GFP_KERNEL, "TUNNEL_DETAILS=(%s)", + tb_tunnel_names[type]); + } + + if (envp[1]) + tb_domain_event(tb, envp); + + kfree(envp[1]); + kfree(envp[0]); +} + +static inline void tb_tunnel_set_active(struct tb_tunnel *tunnel, bool active) +{ + if (active) { + tunnel->state = TB_TUNNEL_ACTIVE; + tb_tunnel_event(tunnel->tb, TB_TUNNEL_ACTIVATED, tunnel->type, + tunnel->src_port, tunnel->dst_port); + } else { + tunnel->state = TB_TUNNEL_INACTIVE; + tb_tunnel_event(tunnel->tb, TB_TUNNEL_DEACTIVATED, tunnel->type, + tunnel->src_port, tunnel->dst_port); + } +} + +static inline void tb_tunnel_changed(struct tb_tunnel *tunnel) +{ + tb_tunnel_event(tunnel->tb, TB_TUNNEL_CHANGED, tunnel->type, + tunnel->src_port, tunnel->dst_port); +} + static int tb_pci_set_ext_encapsulation(struct tb_tunnel *tunnel, bool enable) { struct tb_port *port = tb_upstream_port(tunnel->dst_port->sw); @@ -992,7 +1066,7 @@ static void tb_dp_dprx_work(struct work_struct *work) return; } } else { - tunnel->state = TB_TUNNEL_ACTIVE; + tb_tunnel_set_active(tunnel, true); } mutex_unlock(&tb->lock); } @@ -2326,7 +2400,7 @@ int tb_tunnel_activate(struct tb_tunnel *tunnel) } } - tunnel->state = TB_TUNNEL_ACTIVE; + tb_tunnel_set_active(tunnel, true); return 0; err: @@ -2356,7 +2430,7 @@ void tb_tunnel_deactivate(struct tb_tunnel *tunnel) if (tunnel->post_deactivate) tunnel->post_deactivate(tunnel); - tunnel->state = TB_TUNNEL_INACTIVE; + tb_tunnel_set_active(tunnel, false); } /** @@ -2449,8 +2523,16 @@ int tb_tunnel_alloc_bandwidth(struct tb_tunnel *tunnel, int *alloc_up, if (!tb_tunnel_is_active(tunnel)) return -ENOTCONN; - if (tunnel->alloc_bandwidth) - return tunnel->alloc_bandwidth(tunnel, alloc_up, alloc_down); + if (tunnel->alloc_bandwidth) { + int ret; + + ret = tunnel->alloc_bandwidth(tunnel, alloc_up, alloc_down); + if (ret) + return ret; + + tb_tunnel_changed(tunnel); + return 0; + } return -EOPNOTSUPP; } diff --git a/drivers/thunderbolt/tunnel.h b/drivers/thunderbolt/tunnel.h index 8a0a0cb21a89..5e9fb73d5220 100644 --- a/drivers/thunderbolt/tunnel.h +++ b/drivers/thunderbolt/tunnel.h @@ -194,6 +194,29 @@ static inline bool tb_tunnel_direction_downstream(const struct tb_tunnel *tunnel tunnel->dst_port); } +/** + * enum tb_tunnel_event - Tunnel related events + * @TB_TUNNEL_ACTIVATED: A tunnel was activated + * @TB_TUNNEL_CHANGED: There is a tunneling change in the domain. Includes + * full %TUNNEL_DETAILS if the tunnel in question is known + * (ICM does not provide that information). + * @TB_TUNNEL_DEACTIVATED: A tunnel was torn down + * @TB_TUNNEL_LOW_BANDWIDTH: Tunnel bandwidth is not optimal + * @TB_TUNNEL_NO_BANDWIDTH: There is not enough bandwidth for a tunnel + */ +enum tb_tunnel_event { + TB_TUNNEL_ACTIVATED, + TB_TUNNEL_CHANGED, + TB_TUNNEL_DEACTIVATED, + TB_TUNNEL_LOW_BANDWIDTH, + TB_TUNNEL_NO_BANDWIDTH, +}; + +void tb_tunnel_event(struct tb *tb, enum tb_tunnel_event event, + enum tb_tunnel_type type, + const struct tb_port *src_port, + const struct tb_port *dst_port); + const char *tb_tunnel_type_name(const struct tb_tunnel *tunnel); #define __TB_TUNNEL_PRINT(level, tunnel, fmt, arg...) \ diff --git a/drivers/thunderbolt/usb4.c b/drivers/thunderbolt/usb4.c index e51d01671d8e..fce3c0f2354a 100644 --- a/drivers/thunderbolt/usb4.c +++ b/drivers/thunderbolt/usb4.c @@ -440,10 +440,10 @@ int usb4_switch_set_wake(struct tb_switch *sw, unsigned int flags) bool configured = val & PORT_CS_19_PC; usb4 = port->usb4; - if (((flags & TB_WAKE_ON_CONNECT) | + if (((flags & TB_WAKE_ON_CONNECT) && device_may_wakeup(&usb4->dev)) && !configured) val |= PORT_CS_19_WOC; - if (((flags & TB_WAKE_ON_DISCONNECT) | + if (((flags & TB_WAKE_ON_DISCONNECT) && device_may_wakeup(&usb4->dev)) && configured) val |= PORT_CS_19_WOD; if ((flags & TB_WAKE_ON_USB4) && configured) @@ -935,7 +935,15 @@ int usb4_switch_dealloc_dp_resource(struct tb_switch *sw, struct tb_port *in) return status ? -EIO : 0; } -static int usb4_port_idx(const struct tb_switch *sw, const struct tb_port *port) +/** + * usb4_port_index() - Finds matching USB4 port index + * @sw: USB4 router + * @port: USB4 protocol or lane adapter + * + * Finds matching USB4 port index (starting from %0) that given @port goes + * through. + */ +int usb4_port_index(const struct tb_switch *sw, const struct tb_port *port) { struct tb_port *p; int usb4_idx = 0; @@ -969,7 +977,7 @@ static int usb4_port_idx(const struct tb_switch *sw, const struct tb_port *port) struct tb_port *usb4_switch_map_pcie_down(struct tb_switch *sw, const struct tb_port *port) { - int usb4_idx = usb4_port_idx(sw, port); + int usb4_idx = usb4_port_index(sw, port); struct tb_port *p; int pcie_idx = 0; @@ -1000,7 +1008,7 @@ struct tb_port *usb4_switch_map_pcie_down(struct tb_switch *sw, struct tb_port *usb4_switch_map_usb3_down(struct tb_switch *sw, const struct tb_port *port) { - int usb4_idx = usb4_port_idx(sw, port); + int usb4_idx = usb4_port_index(sw, port); struct tb_port *p; int usb_idx = 0; diff --git a/drivers/thunderbolt/usb4_port.c b/drivers/thunderbolt/usb4_port.c index 5150879888ca..852a45fcd19d 100644 --- a/drivers/thunderbolt/usb4_port.c +++ b/drivers/thunderbolt/usb4_port.c @@ -105,6 +105,49 @@ static void usb4_port_online(struct usb4_port *usb4) tb_acpi_power_off_retimers(port); } +/** + * usb4_usb3_port_match() - Matches USB4 port device with USB 3.x port device + * @usb4_port_dev: USB4 port device + * @usb3_port_fwnode: USB 3.x port firmware node + * + * Checks if USB 3.x port @usb3_port_fwnode is tunneled through USB4 port @usb4_port_dev. + * Returns true if match is found, false otherwise. + * + * Function is designed to be used with component framework (component_match_add). + */ +bool usb4_usb3_port_match(struct device *usb4_port_dev, + const struct fwnode_handle *usb3_port_fwnode) +{ + struct fwnode_handle *nhi_fwnode __free(fwnode_handle) = NULL; + struct usb4_port *usb4; + struct tb_switch *sw; + struct tb_nhi *nhi; + u8 usb4_port_num; + struct tb *tb; + + usb4 = tb_to_usb4_port_device(usb4_port_dev); + if (!usb4) + return false; + + sw = usb4->port->sw; + tb = sw->tb; + nhi = tb->nhi; + + nhi_fwnode = fwnode_find_reference(usb3_port_fwnode, "usb4-host-interface", 0); + if (IS_ERR(nhi_fwnode)) + return false; + + /* Check if USB3 fwnode references same NHI where USB4 port resides */ + if (!device_match_fwnode(&nhi->pdev->dev, nhi_fwnode)) + return false; + + if (fwnode_property_read_u8(usb3_port_fwnode, "usb4-port-number", &usb4_port_num)) + return false; + + return usb4_port_index(sw, usb4->port) == usb4_port_num; +} +EXPORT_SYMBOL_GPL(usb4_usb3_port_match); + static ssize_t offline_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -276,12 +319,10 @@ struct usb4_port *usb4_port_device_add(struct tb_port *port) return ERR_PTR(ret); } - if (dev_fwnode(&usb4->dev)) { - ret = component_add(&usb4->dev, &connector_ops); - if (ret) { - dev_err(&usb4->dev, "failed to add component\n"); - device_unregister(&usb4->dev); - } + ret = component_add(&usb4->dev, &connector_ops); + if (ret) { + dev_err(&usb4->dev, "failed to add component\n"); + device_unregister(&usb4->dev); } if (!tb_is_upstream_port(port)) @@ -306,8 +347,7 @@ struct usb4_port *usb4_port_device_add(struct tb_port *port) */ void usb4_port_device_remove(struct usb4_port *usb4) { - if (dev_fwnode(&usb4->dev)) - component_del(&usb4->dev, &connector_ops); + component_del(&usb4->dev, &connector_ops); device_unregister(&usb4->dev); } diff --git a/drivers/tty/ipwireless/hardware.c b/drivers/tty/ipwireless/hardware.c index c13f52337035..e18848267be4 100644 --- a/drivers/tty/ipwireless/hardware.c +++ b/drivers/tty/ipwireless/hardware.c @@ -1676,7 +1676,7 @@ void ipwireless_init_hardware_v2_v3(struct ipw_hardware *hw) static void ipwireless_setup_timer(struct timer_list *t) { - struct ipw_hardware *hw = from_timer(hw, t, setup_timer); + struct ipw_hardware *hw = timer_container_of(hw, t, setup_timer); hw->init_loops++; diff --git a/drivers/tty/mips_ejtag_fdc.c b/drivers/tty/mips_ejtag_fdc.c index fa47bfcf9e86..ba7690c3e15e 100644 --- a/drivers/tty/mips_ejtag_fdc.c +++ b/drivers/tty/mips_ejtag_fdc.c @@ -683,7 +683,8 @@ static irqreturn_t mips_ejtag_fdc_isr(int irq, void *dev_id) */ static void mips_ejtag_fdc_tty_timer(struct timer_list *t) { - struct mips_ejtag_fdc_tty *priv = from_timer(priv, t, poll_timer); + struct mips_ejtag_fdc_tty *priv = timer_container_of(priv, t, + poll_timer); mips_ejtag_fdc_handle(priv); if (!priv->removing) diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c index 4d45eca4929a..2fc13cc02cc5 100644 --- a/drivers/tty/mxser.c +++ b/drivers/tty/mxser.c @@ -1812,7 +1812,7 @@ static int mxser_probe(struct pci_dev *pdev, /* io address */ ioaddress = pci_resource_start(pdev, 2); - retval = pci_request_region(pdev, 2, "mxser(IO)"); + retval = pcim_request_region(pdev, 2, "mxser(IO)"); if (retval) goto err_zero; @@ -1822,7 +1822,7 @@ static int mxser_probe(struct pci_dev *pdev, /* vector */ ioaddress = pci_resource_start(pdev, 3); - retval = pci_request_region(pdev, 3, "mxser(vector)"); + retval = pcim_request_region(pdev, 3, "mxser(vector)"); if (retval) goto err_zero; brd->vector = ioaddress; diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 40a336ef8c7e..7fc535452c0b 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -1971,7 +1971,7 @@ static void gsm_control_response(struct gsm_mux *gsm, unsigned int command, static void gsm_control_keep_alive(struct timer_list *t) { - struct gsm_mux *gsm = from_timer(gsm, t, ka_timer); + struct gsm_mux *gsm = timer_container_of(gsm, t, ka_timer); unsigned long flags; spin_lock_irqsave(&gsm->control_lock, flags); @@ -2028,7 +2028,7 @@ static void gsm_control_transmit(struct gsm_mux *gsm, struct gsm_control *ctrl) static void gsm_control_retransmit(struct timer_list *t) { - struct gsm_mux *gsm = from_timer(gsm, t, t2_timer); + struct gsm_mux *gsm = timer_container_of(gsm, t, t2_timer); struct gsm_control *ctrl; unsigned long flags; spin_lock_irqsave(&gsm->control_lock, flags); @@ -2229,7 +2229,7 @@ static int gsm_dlci_negotiate(struct gsm_dlci *dlci) static void gsm_dlci_t1(struct timer_list *t) { - struct gsm_dlci *dlci = from_timer(dlci, t, t1); + struct gsm_dlci *dlci = timer_container_of(dlci, t, t1); struct gsm_mux *gsm = dlci->gsm; switch (dlci->state) { @@ -2489,7 +2489,7 @@ static void gsm_dlci_command(struct gsm_dlci *dlci, const u8 *data, int len) */ static void gsm_kick_timer(struct timer_list *t) { - struct gsm_mux *gsm = from_timer(gsm, t, kick_timer); + struct gsm_mux *gsm = timer_container_of(gsm, t, kick_timer); unsigned long flags; int sent = 0; diff --git a/drivers/tty/serdev/core.c b/drivers/tty/serdev/core.c index eb2a2e58fe78..0213381fa358 100644 --- a/drivers/tty/serdev/core.c +++ b/drivers/tty/serdev/core.c @@ -118,12 +118,11 @@ int serdev_device_add(struct serdev_device *serdev) err = device_add(&serdev->dev); if (err < 0) { - dev_err(&serdev->dev, "Can't add %s, status %pe\n", - dev_name(&serdev->dev), ERR_PTR(err)); + dev_err(&serdev->dev, "Failed to add serdev: %d\n", err); goto err_clear_serdev; } - dev_dbg(&serdev->dev, "device %s registered\n", dev_name(&serdev->dev)); + dev_dbg(&serdev->dev, "serdev registered successfully\n"); return 0; @@ -783,8 +782,7 @@ int serdev_controller_add(struct serdev_controller *ctrl) goto err_rpm_disable; } - dev_dbg(&ctrl->dev, "serdev%d registered: dev:%p\n", - ctrl->nr, &ctrl->dev); + dev_dbg(&ctrl->dev, "serdev controller registered: dev:%p\n", &ctrl->dev); return 0; err_rpm_disable: diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h index b861585ca02a..18530c31a598 100644 --- a/drivers/tty/serial/8250/8250.h +++ b/drivers/tty/serial/8250/8250.h @@ -223,12 +223,6 @@ static inline bool serial8250_clear_THRI(struct uart_8250_port *up) struct uart_8250_port *serial8250_setup_port(int index); struct uart_8250_port *serial8250_get_port(int line); -void serial8250_rpm_get(struct uart_8250_port *p); -void serial8250_rpm_put(struct uart_8250_port *p); - -void serial8250_rpm_get_tx(struct uart_8250_port *p); -void serial8250_rpm_put_tx(struct uart_8250_port *p); - int serial8250_em485_config(struct uart_port *port, struct ktermios *termios, struct serial_rs485 *rs485); void serial8250_em485_start_tx(struct uart_8250_port *p, bool toggle_ier); diff --git a/drivers/tty/serial/8250/8250_aspeed_vuart.c b/drivers/tty/serial/8250/8250_aspeed_vuart.c index 392447038bfb..26fc0464f1cc 100644 --- a/drivers/tty/serial/8250/8250_aspeed_vuart.c +++ b/drivers/tty/serial/8250/8250_aspeed_vuart.c @@ -304,7 +304,8 @@ static void aspeed_vuart_unthrottle(struct uart_port *port) static void aspeed_vuart_unthrottle_exp(struct timer_list *timer) { - struct aspeed_vuart *vuart = from_timer(vuart, timer, unthrottle_timer); + struct aspeed_vuart *vuart = timer_container_of(vuart, timer, + unthrottle_timer); struct uart_8250_port *up = vuart->port; if (!tty_buffer_space_avail(&up->port.state->port)) { diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index 5a56f853cf6d..7a6050f1c094 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -206,7 +206,7 @@ static void serial_unlink_irq_chain(struct uart_8250_port *up) */ static void serial8250_timeout(struct timer_list *t) { - struct uart_8250_port *up = from_timer(up, t, timer); + struct uart_8250_port *up = timer_container_of(up, t, timer); up->port.handle_irq(&up->port); mod_timer(&up->timer, jiffies + uart_poll_timeout(&up->port)); @@ -214,7 +214,7 @@ static void serial8250_timeout(struct timer_list *t) static void serial8250_backup_timeout(struct timer_list *t) { - struct uart_8250_port *up = from_timer(up, t, timer); + struct uart_8250_port *up = timer_container_of(up, t, timer); unsigned int iir, ier = 0, lsr; unsigned long flags; @@ -461,7 +461,7 @@ static int univ8250_console_match(struct console *co, char *name, int idx, char *options) { char match[] = "uart"; /* 8250-specific earlycon name */ - unsigned char iotype; + enum uart_iotype iotype; resource_size_t addr; int i; diff --git a/drivers/tty/serial/8250/8250_early.c b/drivers/tty/serial/8250/8250_early.c index 842422921765..dc0371857ecb 100644 --- a/drivers/tty/serial/8250/8250_early.c +++ b/drivers/tty/serial/8250/8250_early.c @@ -77,6 +77,8 @@ static void serial8250_early_out(struct uart_port *port, int offset, int value) outb(value, port->iobase + offset); break; #endif + default: + break; } } diff --git a/drivers/tty/serial/8250/8250_ni.c b/drivers/tty/serial/8250/8250_ni.c index b10a42d2ad63..b0e44fb00b3a 100644 --- a/drivers/tty/serial/8250/8250_ni.c +++ b/drivers/tty/serial/8250/8250_ni.c @@ -10,14 +10,18 @@ * Copyright 2012-2023 National Instruments Corporation */ -#include <linux/acpi.h> #include <linux/bitfield.h> +#include <linux/bits.h> +#include <linux/clk.h> #include <linux/device.h> #include <linux/io.h> #include <linux/init.h> +#include <linux/mod_devicetable.h> #include <linux/module.h> +#include <linux/platform_device.h> #include <linux/property.h> -#include <linux/clk.h> +#include <linux/serial_core.h> +#include <linux/types.h> #include "8250.h" @@ -90,10 +94,10 @@ static int ni16550_disable_transceivers(struct uart_port *port) { u8 pcr; - pcr = port->serial_in(port, NI16550_PCR_OFFSET); + pcr = serial_port_in(port, NI16550_PCR_OFFSET); pcr &= ~NI16550_PCR_TXVR_ENABLE_BIT; dev_dbg(port->dev, "disable transceivers: write pcr: 0x%02x\n", pcr); - port->serial_out(port, NI16550_PCR_OFFSET, pcr); + serial_port_out(port, NI16550_PCR_OFFSET, pcr); return 0; } @@ -105,7 +109,7 @@ static int ni16550_rs485_config(struct uart_port *port, struct uart_8250_port *up = container_of(port, struct uart_8250_port, port); u8 pcr; - pcr = serial_in(up, NI16550_PCR_OFFSET); + pcr = serial_port_in(port, NI16550_PCR_OFFSET); pcr &= ~NI16550_PCR_WIRE_MODE_MASK; if ((rs485->flags & SER_RS485_MODE_RS422) || @@ -120,7 +124,7 @@ static int ni16550_rs485_config(struct uart_port *port, } dev_dbg(port->dev, "config rs485: write pcr: 0x%02x, acr: %02x\n", pcr, up->acr); - serial_out(up, NI16550_PCR_OFFSET, pcr); + serial_port_out(port, NI16550_PCR_OFFSET, pcr); serial_icr_write(up, UART_ACR, up->acr); return 0; @@ -224,31 +228,26 @@ static int ni16550_get_regs(struct platform_device *pdev, { struct resource *regs; - regs = platform_get_resource(pdev, IORESOURCE_IO, 0); - if (regs) { + regs = platform_get_mem_or_io(pdev, 0); + if (!regs) + return dev_err_probe(&pdev->dev, -EINVAL, "no registers defined\n"); + + switch (resource_type(regs)) { + case IORESOURCE_IO: port->iotype = UPIO_PORT; port->iobase = regs->start; return 0; - } - - regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (regs) { + case IORESOURCE_MEM: port->iotype = UPIO_MEM; port->mapbase = regs->start; port->mapsize = resource_size(regs); port->flags |= UPF_IOREMAP; - port->membase = devm_ioremap(&pdev->dev, port->mapbase, - port->mapsize); - if (!port->membase) - return -ENOMEM; - return 0; + default: + return -EINVAL; } - - dev_err(&pdev->dev, "no registers defined\n"); - return -EINVAL; } /* @@ -280,12 +279,11 @@ static int ni16550_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct uart_8250_port uart = {}; unsigned int txfifosz, rxfifosz; - unsigned int prescaler = 0; + unsigned int prescaler; struct ni16550_data *data; const char *portmode; bool rs232_property; int ret; - int irq; data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); if (!data) @@ -293,10 +291,6 @@ static int ni16550_probe(struct platform_device *pdev) spin_lock_init(&uart.port.lock); - irq = platform_get_irq(pdev, 0); - if (irq < 0) - return irq; - ret = ni16550_get_regs(pdev, &uart.port); if (ret < 0) return ret; @@ -307,10 +301,7 @@ static int ni16550_probe(struct platform_device *pdev) info = device_get_match_data(dev); uart.port.dev = dev; - uart.port.irq = irq; - uart.port.irqflags = IRQF_SHARED; - uart.port.flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF - | UPF_FIXED_PORT | UPF_FIXED_TYPE; + uart.port.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_PORT | UPF_FIXED_TYPE; uart.port.startup = ni16550_port_startup; uart.port.shutdown = ni16550_port_shutdown; @@ -332,28 +323,26 @@ static int ni16550_probe(struct platform_device *pdev) /* * Declaration of the base clock frequency can come from one of: * - static declaration in this driver (for older ACPI IDs) - * - a "clock-frquency" ACPI + * - a "clock-frequency" ACPI */ - if (info->uartclk) - uart.port.uartclk = info->uartclk; - if (device_property_read_u32(dev, "clock-frequency", - &uart.port.uartclk)) { + uart.port.uartclk = info->uartclk; + + ret = uart_read_port_properties(&uart.port); + if (ret) + return ret; + + if (!uart.port.uartclk) { data->clk = devm_clk_get_enabled(dev, NULL); if (!IS_ERR(data->clk)) uart.port.uartclk = clk_get_rate(data->clk); } - if (!uart.port.uartclk) { - dev_err(dev, "unable to determine clock frequency!\n"); - ret = -ENODEV; - goto err; - } + if (!uart.port.uartclk) + return dev_err_probe(dev, -ENODEV, "unable to determine clock frequency!\n"); - if (info->prescaler) - prescaler = info->prescaler; + prescaler = info->prescaler; device_property_read_u32(dev, "clock-prescaler", &prescaler); - - if (prescaler != 0) { + if (prescaler) { uart.port.set_mctrl = ni16550_set_mctrl; ni16550_config_prescaler(&uart, (u8)prescaler); } @@ -393,14 +382,11 @@ static int ni16550_probe(struct platform_device *pdev) ret = serial8250_register_8250_port(&uart); if (ret < 0) - goto err; + return ret; data->line = ret; platform_set_drvdata(pdev, data); return 0; - -err: - return ret; } static void ni16550_remove(struct platform_device *pdev) @@ -410,7 +396,6 @@ static void ni16550_remove(struct platform_device *pdev) serial8250_unregister_port(data->line); } -#ifdef CONFIG_ACPI /* NI 16550 RS-485 Interface */ static const struct ni16550_device_info nic7750 = { .uartclk = 33333333, @@ -435,20 +420,20 @@ static const struct ni16550_device_info nic7a69 = { .uartclk = 29629629, .prescaler = 0x09, }; + static const struct acpi_device_id ni16550_acpi_match[] = { { "NIC7750", (kernel_ulong_t)&nic7750 }, { "NIC7772", (kernel_ulong_t)&nic7772 }, { "NIC792B", (kernel_ulong_t)&nic792b }, { "NIC7A69", (kernel_ulong_t)&nic7a69 }, - { }, + { } }; MODULE_DEVICE_TABLE(acpi, ni16550_acpi_match); -#endif static struct platform_driver ni16550_driver = { .driver = { .name = "ni16550", - .acpi_match_table = ACPI_PTR(ni16550_acpi_match), + .acpi_match_table = ni16550_acpi_match, }, .probe = ni16550_probe, .remove = ni16550_remove, diff --git a/drivers/tty/serial/8250/8250_of.c b/drivers/tty/serial/8250/8250_of.c index 11c860ea80f6..d178b6c54ea1 100644 --- a/drivers/tty/serial/8250/8250_of.c +++ b/drivers/tty/serial/8250/8250_of.c @@ -24,6 +24,7 @@ struct of_serial_info { struct clk *clk; + struct clk *bus_clk; struct reset_control *rst; int type; int line; @@ -123,12 +124,22 @@ static int of_platform_serial_setup(struct platform_device *ofdev, /* Get clk rate through clk driver if present */ if (!port->uartclk) { - info->clk = devm_clk_get_enabled(dev, NULL); + struct clk *bus_clk; + + bus_clk = devm_clk_get_optional_enabled(dev, "bus"); + if (IS_ERR(bus_clk)) { + ret = dev_err_probe(dev, PTR_ERR(bus_clk), "failed to get bus clock\n"); + goto err_pmruntime; + } + + /* If the bus clock is required, core clock must be named */ + info->clk = devm_clk_get_enabled(dev, bus_clk ? "core" : NULL); if (IS_ERR(info->clk)) { ret = dev_err_probe(dev, PTR_ERR(info->clk), "failed to get clock\n"); goto err_pmruntime; } + info->bus_clk = bus_clk; port->uartclk = clk_get_rate(info->clk); } /* If current-speed was set, then try not to change it. */ @@ -290,6 +301,7 @@ static int of_serial_suspend(struct device *dev) if (!uart_console(port) || console_suspend_enabled) { pm_runtime_put_sync(dev); clk_disable_unprepare(info->clk); + clk_disable_unprepare(info->bus_clk); } return 0; } @@ -302,6 +314,7 @@ static int of_serial_resume(struct device *dev) if (!uart_console(port) || console_suspend_enabled) { pm_runtime_get_sync(dev); + clk_prepare_enable(info->bus_clk); clk_prepare_enable(info->clk); } diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index 2a0ce11f405d..72ae08d6204f 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -1173,16 +1173,6 @@ static int omap_8250_tx_dma(struct uart_8250_port *p) return 0; } - sg_init_table(&sg, 1); - ret = kfifo_dma_out_prepare_mapped(&tport->xmit_fifo, &sg, 1, - UART_XMIT_SIZE, dma->tx_addr); - if (ret != 1) { - serial8250_clear_THRI(p); - return 0; - } - - dma->tx_size = sg_dma_len(&sg); - if (priv->habit & OMAP_DMA_TX_KICK) { unsigned char c; u8 tx_lvl; @@ -1207,18 +1197,22 @@ static int omap_8250_tx_dma(struct uart_8250_port *p) ret = -EBUSY; goto err; } - if (dma->tx_size < 4) { + if (kfifo_len(&tport->xmit_fifo) < 4) { ret = -EINVAL; goto err; } - if (!kfifo_get(&tport->xmit_fifo, &c)) { + if (!uart_fifo_out(&p->port, &c, 1)) { ret = -EINVAL; goto err; } skip_byte = c; - /* now we need to recompute due to kfifo_get */ - kfifo_dma_out_prepare_mapped(&tport->xmit_fifo, &sg, 1, - UART_XMIT_SIZE, dma->tx_addr); + } + + sg_init_table(&sg, 1); + ret = kfifo_dma_out_prepare_mapped(&tport->xmit_fifo, &sg, 1, UART_XMIT_SIZE, dma->tx_addr); + if (ret != 1) { + ret = -EINVAL; + goto err; } desc = dmaengine_prep_slave_sg(dma->txchan, &sg, 1, DMA_MEM_TO_DEV, @@ -1228,6 +1222,7 @@ static int omap_8250_tx_dma(struct uart_8250_port *p) goto err; } + dma->tx_size = sg_dma_len(&sg); dma->tx_running = 1; desc->callback = omap_8250_dma_tx_complete; diff --git a/drivers/tty/serial/8250/8250_pci1xxxx.c b/drivers/tty/serial/8250/8250_pci1xxxx.c index e9c51d4e447d..4c149db84692 100644 --- a/drivers/tty/serial/8250/8250_pci1xxxx.c +++ b/drivers/tty/serial/8250/8250_pci1xxxx.c @@ -115,6 +115,7 @@ #define UART_RESET_REG 0x94 #define UART_RESET_D3_RESET_DISABLE BIT(16) +#define UART_RESET_HOT_RESET_DISABLE BIT(17) #define UART_BURST_STATUS_REG 0x9C #define UART_TX_BURST_FIFO 0xA0 @@ -620,6 +621,10 @@ static int pci1xxxx_suspend(struct device *dev) } data = readl(p + UART_RESET_REG); + + if (priv->dev_rev >= 0xC0) + data |= UART_RESET_HOT_RESET_DISABLE; + writel(data | UART_RESET_D3_RESET_DISABLE, p + UART_RESET_REG); if (wakeup) @@ -647,7 +652,12 @@ static int pci1xxxx_resume(struct device *dev) } data = readl(p + UART_RESET_REG); + + if (priv->dev_rev >= 0xC0) + data &= ~UART_RESET_HOT_RESET_DISABLE; + writel(data & ~UART_RESET_D3_RESET_DISABLE, p + UART_RESET_REG); + iounmap(p); for (i = 0; i < priv->nr; i++) { diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 8ac452cea36c..6d7b8c4667c9 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -517,22 +517,20 @@ void serial8250_clear_and_reinit_fifos(struct uart_8250_port *p) } EXPORT_SYMBOL_GPL(serial8250_clear_and_reinit_fifos); -void serial8250_rpm_get(struct uart_8250_port *p) +static void serial8250_rpm_get(struct uart_8250_port *p) { if (!(p->capabilities & UART_CAP_RPM)) return; pm_runtime_get_sync(p->port.dev); } -EXPORT_SYMBOL_GPL(serial8250_rpm_get); -void serial8250_rpm_put(struct uart_8250_port *p) +static void serial8250_rpm_put(struct uart_8250_port *p) { if (!(p->capabilities & UART_CAP_RPM)) return; pm_runtime_mark_last_busy(p->port.dev); pm_runtime_put_autosuspend(p->port.dev); } -EXPORT_SYMBOL_GPL(serial8250_rpm_put); /** * serial8250_em485_init() - put uart_8250_port into rs485 emulating @@ -647,7 +645,7 @@ EXPORT_SYMBOL_GPL(serial8250_em485_config); * once and disable_runtime_pm_tx() will still disable RPM because the fifo is * empty and the HW can idle again. */ -void serial8250_rpm_get_tx(struct uart_8250_port *p) +static void serial8250_rpm_get_tx(struct uart_8250_port *p) { unsigned char rpm_active; @@ -659,9 +657,8 @@ void serial8250_rpm_get_tx(struct uart_8250_port *p) return; pm_runtime_get_sync(p->port.dev); } -EXPORT_SYMBOL_GPL(serial8250_rpm_get_tx); -void serial8250_rpm_put_tx(struct uart_8250_port *p) +static void serial8250_rpm_put_tx(struct uart_8250_port *p) { unsigned char rpm_active; @@ -674,7 +671,6 @@ void serial8250_rpm_put_tx(struct uart_8250_port *p) pm_runtime_mark_last_busy(p->port.dev); pm_runtime_put_autosuspend(p->port.dev); } -EXPORT_SYMBOL_GPL(serial8250_rpm_put_tx); /* * IER sleep support. UARTs which have EFRs need the "extended @@ -2993,6 +2989,8 @@ static int serial8250_request_std_resource(struct uart_8250_port *up) if (!request_region(port->iobase, size, "serial")) return -EBUSY; return 0; + case UPIO_UNKNOWN: + break; } return 0; @@ -3025,6 +3023,8 @@ static void serial8250_release_std_resource(struct uart_8250_port *up) case UPIO_PORT: release_region(port->iobase, size); break; + case UPIO_UNKNOWN: + break; } } diff --git a/drivers/tty/serial/8250/8250_rsa.c b/drivers/tty/serial/8250/8250_rsa.c index 82f2593b4c59..4c8b9671bd41 100644 --- a/drivers/tty/serial/8250/8250_rsa.c +++ b/drivers/tty/serial/8250/8250_rsa.c @@ -43,6 +43,8 @@ static void rsa8250_release_resource(struct uart_8250_port *up) case UPIO_PORT: release_region(port->iobase + offset, size); break; + default: + break; } } diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig index bd3d636ff962..f64ef0819cd4 100644 --- a/drivers/tty/serial/8250/Kconfig +++ b/drivers/tty/serial/8250/Kconfig @@ -572,7 +572,7 @@ config SERIAL_8250_BCM7271 config SERIAL_8250_NI tristate "NI 16550 based serial port" depends on SERIAL_8250 - depends on (X86 && ACPI) || COMPILE_TEST + depends on X86 || COMPILE_TEST help This driver supports the integrated serial ports on National Instruments (NI) controller hardware. This is required for all NI diff --git a/drivers/tty/serial/altera_uart.c b/drivers/tty/serial/altera_uart.c index 011f38681131..837991dc4db9 100644 --- a/drivers/tty/serial/altera_uart.c +++ b/drivers/tty/serial/altera_uart.c @@ -275,7 +275,7 @@ static irqreturn_t altera_uart_interrupt(int irq, void *data) static void altera_uart_timer(struct timer_list *t) { - struct altera_uart *pp = from_timer(pp, t, tmr); + struct altera_uart *pp = timer_container_of(pp, t, tmr); struct uart_port *port = &pp->port; altera_uart_interrupt(0, port); diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index 11d65097578c..22939841b1de 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -1046,7 +1046,7 @@ static inline void pl011_dma_rx_stop(struct uart_amba_port *uap) */ static void pl011_dma_rx_poll(struct timer_list *t) { - struct uart_amba_port *uap = from_timer(uap, t, dmarx.timer); + struct uart_amba_port *uap = timer_container_of(uap, t, dmarx.timer); struct tty_port *port = &uap->port.state->port; struct pl011_dmarx_data *dmarx = &uap->dmarx; struct dma_chan *rxchan = uap->dmarx.chan; @@ -2476,7 +2476,7 @@ static int pl011_console_setup(struct console *co, char *options) static int pl011_console_match(struct console *co, char *name, int idx, char *options) { - unsigned char iotype; + enum uart_iotype iotype; resource_size_t addr; int i; diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index 18dba502144d..08dd8f887956 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -1266,8 +1266,8 @@ chan_err: static void atmel_uart_timer_callback(struct timer_list *t) { - struct atmel_uart_port *atmel_port = from_timer(atmel_port, t, - uart_timer); + struct atmel_uart_port *atmel_port = timer_container_of(atmel_port, t, + uart_timer); struct uart_port *port = &atmel_port->uart; if (!atomic_read(&atmel_port->tasklet_shutdown)) { diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index fe5aed99d55a..2790b4078e7e 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -403,6 +403,8 @@ static inline void lpuart32_write(struct uart_port *port, u32 val, case UPIO_MEM32BE: iowrite32be(val, port->membase + off); break; + default: + break; } } @@ -563,8 +565,9 @@ static dma_addr_t lpuart_dma_datareg_addr(struct lpuart_port *sport) return sport->port.mapbase + UARTDATA; case UPIO_MEM32BE: return sport->port.mapbase + UARTDATA + sizeof(u32) - 1; + default: + return sport->port.mapbase + UARTDR; } - return sport->port.mapbase + UARTDR; } static int lpuart_dma_tx_request(struct uart_port *port) @@ -1304,7 +1307,7 @@ static irqreturn_t lpuart32_int(int irq, void *dev_id) */ static void lpuart_timer_func(struct timer_list *t) { - struct lpuart_port *sport = from_timer(sport, t, lpuart_timer); + struct lpuart_port *sport = timer_container_of(sport, t, lpuart_timer); enum dma_status dmastat; struct dma_chan *chan = sport->dma_rx_chan; struct circ_buf *ring = &sport->rx_ring; diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index e4b6f1bfdc95..bd02ee898f5d 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -1165,7 +1165,7 @@ static void imx_uart_break_ctl(struct uart_port *port, int break_state) */ static void imx_uart_timeout(struct timer_list *t) { - struct imx_port *sport = from_timer(sport, t, timer); + struct imx_port *sport = timer_container_of(sport, t, timer); unsigned long flags; if (sport->port.state) { diff --git a/drivers/tty/serial/jsm/jsm_tty.c b/drivers/tty/serial/jsm/jsm_tty.c index ce0fef7e2c66..be2f130696b3 100644 --- a/drivers/tty/serial/jsm/jsm_tty.c +++ b/drivers/tty/serial/jsm/jsm_tty.c @@ -451,6 +451,7 @@ int jsm_uart_port_init(struct jsm_board *brd) if (!brd->channels[i]) continue; + brd->channels[i]->uart_port.dev = &brd->pci_dev->dev; brd->channels[i]->uart_port.irq = brd->irq; brd->channels[i]->uart_port.uartclk = 14745600; brd->channels[i]->uart_port.type = PORT_JSM; diff --git a/drivers/tty/serial/lantiq.c b/drivers/tty/serial/lantiq.c index 58a3ab030d67..62cd9e0bb377 100644 --- a/drivers/tty/serial/lantiq.c +++ b/drivers/tty/serial/lantiq.c @@ -773,10 +773,8 @@ static int fetch_irq_intel(struct device *dev, struct ltq_uart_port *ltq_port) int ret; ret = platform_get_irq(to_platform_device(dev), 0); - if (ret < 0) { - dev_err(dev, "failed to fetch IRQ for serial port\n"); + if (ret < 0) return ret; - } ltq_port->common_irq = ret; port->irq = ret; diff --git a/drivers/tty/serial/liteuart.c b/drivers/tty/serial/liteuart.c index 3a0960c97c77..6429e8f11f36 100644 --- a/drivers/tty/serial/liteuart.c +++ b/drivers/tty/serial/liteuart.c @@ -152,7 +152,7 @@ static irqreturn_t liteuart_interrupt(int irq, void *data) static void liteuart_timer(struct timer_list *t) { - struct liteuart_port *uart = from_timer(uart, t, timer); + struct liteuart_port *uart = timer_container_of(uart, t, timer); struct uart_port *port = &uart->port; liteuart_interrupt(0, port); diff --git a/drivers/tty/serial/max3100.c b/drivers/tty/serial/max3100.c index f2dd83692b2c..67d80f8f801e 100644 --- a/drivers/tty/serial/max3100.c +++ b/drivers/tty/serial/max3100.c @@ -16,6 +16,7 @@ /* 4 MAX3100s should be enough for everyone */ #define MAX_MAX3100 4 +#include <linux/bitops.h> #include <linux/container_of.h> #include <linux/delay.h> #include <linux/device.h> @@ -133,7 +134,7 @@ static int max3100_do_parity(struct max3100_port *s, u16 c) else c &= 0xff; - parity = parity ^ (hweight8(c) & 1); + parity = parity ^ parity8(c); return parity; } @@ -308,7 +309,7 @@ static void max3100_dowork(struct max3100_port *s) static void max3100_timeout(struct timer_list *t) { - struct max3100_port *s = from_timer(s, t, timer); + struct max3100_port *s = timer_container_of(s, t, timer); max3100_dowork(s); mod_timer(&s->timer, jiffies + uart_poll_timeout(&s->port)); diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 35369a2f77b2..541c790c0109 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -1189,13 +1189,16 @@ static int max310x_gpio_get(struct gpio_chip *chip, unsigned int offset) return !!((val >> 4) & (1 << (offset % 4))); } -static void max310x_gpio_set(struct gpio_chip *chip, unsigned int offset, int value) +static int max310x_gpio_set(struct gpio_chip *chip, unsigned int offset, + int value) { struct max310x_port *s = gpiochip_get_data(chip); struct uart_port *port = &s->p[offset / 4].port; max310x_port_update(port, MAX310X_GPIODATA_REG, 1 << (offset % 4), value ? 1 << (offset % 4) : 0); + + return 0; } static int max310x_gpio_direction_input(struct gpio_chip *chip, unsigned int offset) @@ -1411,7 +1414,7 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty s->gpio.direction_input = max310x_gpio_direction_input; s->gpio.get = max310x_gpio_get; s->gpio.direction_output= max310x_gpio_direction_output; - s->gpio.set = max310x_gpio_set; + s->gpio.set_rv = max310x_gpio_set; s->gpio.set_config = max310x_gpio_set_config; s->gpio.base = -1; s->gpio.ngpio = devtype->nr * 4; diff --git a/drivers/tty/serial/milbeaut_usio.c b/drivers/tty/serial/milbeaut_usio.c index 059bea18dbab..4e47dca2c4ed 100644 --- a/drivers/tty/serial/milbeaut_usio.c +++ b/drivers/tty/serial/milbeaut_usio.c @@ -523,7 +523,10 @@ static int mlb_usio_probe(struct platform_device *pdev) } port->membase = devm_ioremap(&pdev->dev, res->start, resource_size(res)); - + if (!port->membase) { + ret = -ENOMEM; + goto failed; + } ret = platform_get_irq_byname(pdev, "rx"); mlb_usio_irq[index][RX] = ret; diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c index a80ce7aaf309..0293b6210aa6 100644 --- a/drivers/tty/serial/qcom_geni_serial.c +++ b/drivers/tty/serial/qcom_geni_serial.c @@ -98,6 +98,8 @@ #define DMA_RX_BUF_SIZE 2048 +static DEFINE_IDA(port_ida); + struct qcom_geni_device_data { bool console; enum geni_se_xfer_mode mode; @@ -253,10 +255,24 @@ static struct qcom_geni_serial_port *get_port_from_line(int line, bool console) struct qcom_geni_serial_port *port; int nr_ports = console ? GENI_UART_CONS_PORTS : GENI_UART_PORTS; - if (line < 0 || line >= nr_ports) - return ERR_PTR(-ENXIO); + if (console) { + if (line < 0 || line >= nr_ports) + return ERR_PTR(-ENXIO); + + port = &qcom_geni_console_port; + } else { + int max_alias_num = of_alias_get_highest_id("serial"); + + if (line < 0 || line >= nr_ports) + line = ida_alloc_range(&port_ida, max_alias_num + 1, nr_ports, GFP_KERNEL); + else + line = ida_alloc_range(&port_ida, line, nr_ports, GFP_KERNEL); + + if (line < 0) + return ERR_PTR(-ENXIO); - port = console ? &qcom_geni_console_port : &qcom_geni_uart_ports[line]; + port = &qcom_geni_uart_ports[line]; + } return port; } @@ -1761,6 +1777,7 @@ static int qcom_geni_serial_probe(struct platform_device *pdev) port->wakeup_irq); if (ret) { device_init_wakeup(&pdev->dev, false); + ida_free(&port_ida, uport->line); uart_remove_one_port(drv, uport); return ret; } @@ -1772,10 +1789,12 @@ static int qcom_geni_serial_probe(struct platform_device *pdev) static void qcom_geni_serial_remove(struct platform_device *pdev) { struct qcom_geni_serial_port *port = platform_get_drvdata(pdev); + struct uart_port *uport = &port->uport; struct uart_driver *drv = port->private_data.drv; dev_pm_clear_wake_irq(&pdev->dev); device_init_wakeup(&pdev->dev, false); + ida_free(&port_ida, uport->line); uart_remove_one_port(drv, &port->uport); } diff --git a/drivers/tty/serial/sa1100.c b/drivers/tty/serial/sa1100.c index 8587ebbe1073..72b1bb76415c 100644 --- a/drivers/tty/serial/sa1100.c +++ b/drivers/tty/serial/sa1100.c @@ -111,7 +111,7 @@ static void sa1100_mctrl_check(struct sa1100_port *sport) */ static void sa1100_timeout(struct timer_list *t) { - struct sa1100_port *sport = from_timer(sport, t, timer); + struct sa1100_port *sport = timer_container_of(sport, t, timer); unsigned long flags; if (sport->port.state) { diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c index 210fff7164c1..2fb58c626daf 100644 --- a/drivers/tty/serial/samsung_tty.c +++ b/drivers/tty/serial/samsung_tty.c @@ -52,7 +52,7 @@ #define S3C24XX_SERIAL_MINOR 64 #ifdef CONFIG_ARM64 -#define UART_NR 12 +#define UART_NR 18 #else #define UART_NR CONFIG_SERIAL_SAMSUNG_UARTS #endif @@ -190,6 +190,8 @@ static void wr_reg(const struct uart_port *port, u32 reg, u32 val) case UPIO_MEM32: writel_relaxed(val, portaddr(port, reg)); break; + default: + break; } } @@ -2713,6 +2715,8 @@ static void wr_reg_barrier(const struct uart_port *port, u32 reg, u32 val) case UPIO_MEM32: writel(val, portaddr(port, reg)); break; + default: + break; } } diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c index 560f45ed19ae..5ea8aadb6e69 100644 --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c @@ -1333,13 +1333,16 @@ static int sc16is7xx_gpio_get(struct gpio_chip *chip, unsigned offset) return !!(val & BIT(offset)); } -static void sc16is7xx_gpio_set(struct gpio_chip *chip, unsigned offset, int val) +static int sc16is7xx_gpio_set(struct gpio_chip *chip, unsigned int offset, + int val) { struct sc16is7xx_port *s = gpiochip_get_data(chip); struct uart_port *port = &s->p[0].port; sc16is7xx_port_update(port, SC16IS7XX_IOSTATE_REG, BIT(offset), val ? BIT(offset) : 0); + + return 0; } static int sc16is7xx_gpio_direction_input(struct gpio_chip *chip, @@ -1422,7 +1425,7 @@ static int sc16is7xx_setup_gpio_chip(struct sc16is7xx_port *s) s->gpio.direction_input = sc16is7xx_gpio_direction_input; s->gpio.get = sc16is7xx_gpio_get; s->gpio.direction_output = sc16is7xx_gpio_direction_output; - s->gpio.set = sc16is7xx_gpio_set; + s->gpio.set_rv = sc16is7xx_gpio_set; s->gpio.base = -1; s->gpio.ngpio = s->devtype->nr_gpio; s->gpio.can_sleep = 1; diff --git a/drivers/tty/serial/sccnxp.c b/drivers/tty/serial/sccnxp.c index 553e3c1321ca..4ceca11ce600 100644 --- a/drivers/tty/serial/sccnxp.c +++ b/drivers/tty/serial/sccnxp.c @@ -500,7 +500,7 @@ static void sccnxp_handle_events(struct sccnxp_port *s) static void sccnxp_timer(struct timer_list *t) { - struct sccnxp_port *s = from_timer(s, t, timer); + struct sccnxp_port *s = timer_container_of(s, t, timer); unsigned long flags; spin_lock_irqsave(&s->lock, flags); diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 88669972d9a0..1f7708a91fc6 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -75,22 +75,23 @@ static inline void uart_port_deref(struct uart_port *uport) wake_up(&uport->state->remove_wait); } -#define uart_port_lock(state, flags) \ - ({ \ - struct uart_port *__uport = uart_port_ref(state); \ - if (__uport) \ - uart_port_lock_irqsave(__uport, &flags); \ - __uport; \ - }) - -#define uart_port_unlock(uport, flags) \ - ({ \ - struct uart_port *__uport = uport; \ - if (__uport) { \ - uart_port_unlock_irqrestore(__uport, flags); \ - uart_port_deref(__uport); \ - } \ - }) +static inline struct uart_port *uart_port_ref_lock(struct uart_state *state, unsigned long *flags) +{ + struct uart_port *uport = uart_port_ref(state); + + if (uport) + uart_port_lock_irqsave(uport, flags); + + return uport; +} + +static inline void uart_port_unlock_deref(struct uart_port *uport, unsigned long flags) +{ + if (uport) { + uart_port_unlock_irqrestore(uport, flags); + uart_port_deref(uport); + } +} static inline struct uart_port *uart_port_check(struct uart_state *state) { @@ -127,10 +128,10 @@ static void uart_stop(struct tty_struct *tty) struct uart_port *port; unsigned long flags; - port = uart_port_lock(state, flags); + port = uart_port_ref_lock(state, &flags); if (port) port->ops->stop_tx(port); - uart_port_unlock(port, flags); + uart_port_unlock_deref(port, flags); } static void __uart_start(struct uart_state *state) @@ -168,9 +169,9 @@ static void uart_start(struct tty_struct *tty) struct uart_port *port; unsigned long flags; - port = uart_port_lock(state, flags); + port = uart_port_ref_lock(state, &flags); __uart_start(state); - uart_port_unlock(port, flags); + uart_port_unlock_deref(port, flags); } static void @@ -258,14 +259,14 @@ static int uart_alloc_xmit_buf(struct tty_port *port) if (!page) return -ENOMEM; - uport = uart_port_lock(state, flags); + uport = uart_port_ref_lock(state, &flags); if (!state->port.xmit_buf) { state->port.xmit_buf = (unsigned char *)page; kfifo_init(&state->port.xmit_fifo, state->port.xmit_buf, PAGE_SIZE); - uart_port_unlock(uport, flags); + uart_port_unlock_deref(uport, flags); } else { - uart_port_unlock(uport, flags); + uart_port_unlock_deref(uport, flags); /* * Do not free() the page under the port lock, see * uart_free_xmit_buf(). @@ -289,11 +290,11 @@ static void uart_free_xmit_buf(struct tty_port *port) * console driver may need to allocate/free a debug object, which * can end up in printk() recursion. */ - uport = uart_port_lock(state, flags); + uport = uart_port_ref_lock(state, &flags); xmit_buf = port->xmit_buf; port->xmit_buf = NULL; INIT_KFIFO(port->xmit_fifo); - uart_port_unlock(uport, flags); + uart_port_unlock_deref(uport, flags); free_page((unsigned long)xmit_buf); } @@ -592,15 +593,15 @@ static int uart_put_char(struct tty_struct *tty, u8 c) unsigned long flags; int ret = 0; - port = uart_port_lock(state, flags); + port = uart_port_ref_lock(state, &flags); if (!state->port.xmit_buf) { - uart_port_unlock(port, flags); + uart_port_unlock_deref(port, flags); return 0; } if (port) ret = kfifo_put(&state->port.xmit_fifo, c); - uart_port_unlock(port, flags); + uart_port_unlock_deref(port, flags); return ret; } @@ -623,9 +624,9 @@ static ssize_t uart_write(struct tty_struct *tty, const u8 *buf, size_t count) if (WARN_ON(!state)) return -EL3HLT; - port = uart_port_lock(state, flags); + port = uart_port_ref_lock(state, &flags); if (!state->port.xmit_buf) { - uart_port_unlock(port, flags); + uart_port_unlock_deref(port, flags); return 0; } @@ -633,7 +634,7 @@ static ssize_t uart_write(struct tty_struct *tty, const u8 *buf, size_t count) ret = kfifo_in(&state->port.xmit_fifo, buf, count); __uart_start(state); - uart_port_unlock(port, flags); + uart_port_unlock_deref(port, flags); return ret; } @@ -644,9 +645,9 @@ static unsigned int uart_write_room(struct tty_struct *tty) unsigned long flags; unsigned int ret; - port = uart_port_lock(state, flags); + port = uart_port_ref_lock(state, &flags); ret = kfifo_avail(&state->port.xmit_fifo); - uart_port_unlock(port, flags); + uart_port_unlock_deref(port, flags); return ret; } @@ -657,9 +658,9 @@ static unsigned int uart_chars_in_buffer(struct tty_struct *tty) unsigned long flags; unsigned int ret; - port = uart_port_lock(state, flags); + port = uart_port_ref_lock(state, &flags); ret = kfifo_len(&state->port.xmit_fifo); - uart_port_unlock(port, flags); + uart_port_unlock_deref(port, flags); return ret; } @@ -678,13 +679,13 @@ static void uart_flush_buffer(struct tty_struct *tty) pr_debug("uart_flush_buffer(%d) called\n", tty->index); - port = uart_port_lock(state, flags); + port = uart_port_ref_lock(state, &flags); if (!port) return; kfifo_reset(&state->port.xmit_fifo); if (port->ops->flush_buffer) port->ops->flush_buffer(port); - uart_port_unlock(port, flags); + uart_port_unlock_deref(port, flags); tty_port_tty_wakeup(&state->port); } @@ -1275,14 +1276,13 @@ static int uart_get_icount(struct tty_struct *tty, struct uart_state *state = tty->driver_data; struct uart_icount cnow; struct uart_port *uport; + unsigned long flags; - uport = uart_port_ref(state); + uport = uart_port_ref_lock(state, &flags); if (!uport) return -EIO; - uart_port_lock_irq(uport); memcpy(&cnow, &uport->icount, sizeof(struct uart_icount)); - uart_port_unlock_irq(uport); - uart_port_deref(uport); + uart_port_unlock_deref(uport, flags); icount->cts = cnow.cts; icount->dsr = cnow.dsr; @@ -1914,9 +1914,10 @@ static bool uart_carrier_raised(struct tty_port *port) { struct uart_state *state = container_of(port, struct uart_state, port); struct uart_port *uport; + unsigned long flags; int mctrl; - uport = uart_port_ref(state); + uport = uart_port_ref_lock(state, &flags); /* * Should never observe uport == NULL since checks for hangup should * abort the tty_port_block_til_ready() loop before checking for carrier @@ -1925,11 +1926,9 @@ static bool uart_carrier_raised(struct tty_port *port) */ if (WARN_ON(!uport)) return true; - uart_port_lock_irq(uport); uart_enable_ms(uport); mctrl = uport->ops->get_mctrl(uport); - uart_port_unlock_irq(uport); - uart_port_deref(uport); + uart_port_unlock_deref(uport, flags); return mctrl & TIOCM_CAR; } @@ -2178,8 +2177,8 @@ uart_get_console(struct uart_port *ports, int nr, struct console *co) * * Returns: 0 on success or -%EINVAL on failure */ -int uart_parse_earlycon(char *p, unsigned char *iotype, resource_size_t *addr, - char **options) +int uart_parse_earlycon(char *p, enum uart_iotype *iotype, + resource_size_t *addr, char **options) { if (strncmp(p, "mmio,", 5) == 0) { *iotype = UPIO_MEM; @@ -3289,9 +3288,9 @@ bool uart_match_port(const struct uart_port *port1, case UPIO_AU: case UPIO_TSI: return port1->mapbase == port2->mapbase; + default: + return false; } - - return false; } EXPORT_SYMBOL(uart_match_port); diff --git a/drivers/tty/serial/sh-sci-common.h b/drivers/tty/serial/sh-sci-common.h new file mode 100644 index 000000000000..bd9d9cfac1c8 --- /dev/null +++ b/drivers/tty/serial/sh-sci-common.h @@ -0,0 +1,167 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef __SH_SCI_COMMON_H__ +#define __SH_SCI_COMMON_H__ + +#include <linux/serial_core.h> + +enum SCI_CLKS { + SCI_FCK, /* Functional Clock */ + SCI_SCK, /* Optional External Clock */ + SCI_BRG_INT, /* Optional BRG Internal Clock Source */ + SCI_SCIF_CLK, /* Optional BRG External Clock Source */ + SCI_NUM_CLKS +}; + +/* Offsets into the sci_port->irqs array */ +enum { + SCIx_ERI_IRQ, + SCIx_RXI_IRQ, + SCIx_TXI_IRQ, + SCIx_BRI_IRQ, + SCIx_DRI_IRQ, + SCIx_TEI_IRQ, + SCIx_NR_IRQS, + + SCIx_MUX_IRQ = SCIx_NR_IRQS, /* special case */ +}; + +/* Bit x set means sampling rate x + 1 is supported */ +#define SCI_SR(x) BIT((x) - 1) +#define SCI_SR_RANGE(x, y) GENMASK((y) - 1, (x) - 1) + +void sci_release_port(struct uart_port *port); +int sci_request_port(struct uart_port *port); +void sci_config_port(struct uart_port *port, int flags); +int sci_verify_port(struct uart_port *port, struct serial_struct *ser); +void sci_pm(struct uart_port *port, unsigned int state, + unsigned int oldstate); + +struct plat_sci_reg { + u8 offset; + u8 size; +}; + +struct sci_port_params_bits { + unsigned int rxtx_enable; + unsigned int te_clear; + unsigned int poll_sent_bits; +}; + +struct sci_common_regs { + unsigned int status; + unsigned int control; +}; + +/* The actual number of needed registers. This is used by sci only */ +#define SCI_NR_REGS 20 + +struct sci_port_params { + const struct plat_sci_reg regs[SCI_NR_REGS]; + const struct sci_common_regs *common_regs; + const struct sci_port_params_bits *param_bits; + unsigned int fifosize; + unsigned int overrun_reg; + unsigned int overrun_mask; + unsigned int sampling_rate_mask; + unsigned int error_mask; + unsigned int error_clear; +}; + +struct sci_port_ops { + u32 (*read_reg)(struct uart_port *port, int reg); + void (*write_reg)(struct uart_port *port, int reg, int value); + void (*clear_SCxSR)(struct uart_port *port, unsigned int mask); + + void (*transmit_chars)(struct uart_port *port); + void (*receive_chars)(struct uart_port *port); + + void (*poll_put_char)(struct uart_port *port, unsigned char c); + + int (*set_rtrg)(struct uart_port *port, int rx_trig); + int (*rtrg_enabled)(struct uart_port *port); + + void (*shutdown_complete)(struct uart_port *port); + + void (*prepare_console_write)(struct uart_port *port, u32 ctrl); + void (*console_save)(struct uart_port *port); + void (*console_restore)(struct uart_port *port); + size_t (*suspend_regs_size)(void); +}; + +struct sci_of_data { + const struct sci_port_params *params; + const struct uart_ops *uart_ops; + const struct sci_port_ops *ops; + unsigned short regtype; + unsigned short type; +}; + +struct sci_port { + struct uart_port port; + + /* Platform configuration */ + const struct sci_port_params *params; + const struct plat_sci_port *cfg; + + unsigned int sampling_rate_mask; + resource_size_t reg_size; + struct mctrl_gpios *gpios; + + /* Clocks */ + struct clk *clks[SCI_NUM_CLKS]; + unsigned long clk_rates[SCI_NUM_CLKS]; + + int irqs[SCIx_NR_IRQS]; + char *irqstr[SCIx_NR_IRQS]; + + struct dma_chan *chan_tx; + struct dma_chan *chan_rx; + + struct reset_control *rstc; + struct sci_suspend_regs *suspend_regs; + +#ifdef CONFIG_SERIAL_SH_SCI_DMA + struct dma_chan *chan_tx_saved; + struct dma_chan *chan_rx_saved; + dma_cookie_t cookie_tx; + dma_cookie_t cookie_rx[2]; + dma_cookie_t active_rx; + dma_addr_t tx_dma_addr; + unsigned int tx_dma_len; + struct scatterlist sg_rx[2]; + void *rx_buf[2]; + size_t buf_len_rx; + struct work_struct work_tx; + struct hrtimer rx_timer; + unsigned int rx_timeout; /* microseconds */ +#endif + unsigned int rx_frame; + int rx_trigger; + struct timer_list rx_fifo_timer; + int rx_fifo_timeout; + u16 hscif_tot; + + const struct sci_port_ops *ops; + + bool has_rtscts; + bool autorts; + bool tx_occurred; +}; + +#define to_sci_port(uart) container_of((uart), struct sci_port, port) + +void sci_port_disable(struct sci_port *sci_port); +void sci_port_enable(struct sci_port *sci_port); + +int sci_startup(struct uart_port *port); +void sci_shutdown(struct uart_port *port); + +#define min_sr(_port) ffs((_port)->sampling_rate_mask) +#define max_sr(_port) fls((_port)->sampling_rate_mask) + +#ifdef CONFIG_SERIAL_SH_SCI_EARLYCON +int __init scix_early_console_setup(struct earlycon_device *device, const struct sci_of_data *data); +#endif + +#endif /* __SH_SCI_COMMON_H__ */ diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 7e7813ccda41..1c356544a832 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -56,19 +56,7 @@ #include "serial_mctrl_gpio.h" #include "sh-sci.h" - -/* Offsets into the sci_port->irqs array */ -enum { - SCIx_ERI_IRQ, - SCIx_RXI_IRQ, - SCIx_TXI_IRQ, - SCIx_BRI_IRQ, - SCIx_DRI_IRQ, - SCIx_TEI_IRQ, - SCIx_NR_IRQS, - - SCIx_MUX_IRQ = SCIx_NR_IRQS, /* special case */ -}; +#include "sh-sci-common.h" #define SCIx_IRQ_IS_MUXED(port) \ ((port)->irqs[SCIx_ERI_IRQ] == \ @@ -76,32 +64,38 @@ enum { ((port)->irqs[SCIx_ERI_IRQ] && \ ((port)->irqs[SCIx_RXI_IRQ] < 0)) -enum SCI_CLKS { - SCI_FCK, /* Functional Clock */ - SCI_SCK, /* Optional External Clock */ - SCI_BRG_INT, /* Optional BRG Internal Clock Source */ - SCI_SCIF_CLK, /* Optional BRG External Clock Source */ - SCI_NUM_CLKS -}; - -/* Bit x set means sampling rate x + 1 is supported */ -#define SCI_SR(x) BIT((x) - 1) -#define SCI_SR_RANGE(x, y) GENMASK((y) - 1, (x) - 1) - #define SCI_SR_SCIFAB SCI_SR(5) | SCI_SR(7) | SCI_SR(11) | \ SCI_SR(13) | SCI_SR(16) | SCI_SR(17) | \ SCI_SR(19) | SCI_SR(27) -#define min_sr(_port) ffs((_port)->sampling_rate_mask) -#define max_sr(_port) fls((_port)->sampling_rate_mask) - /* Iterate over all supported sampling rates, from high to low */ #define for_each_sr(_sr, _port) \ for ((_sr) = max_sr(_port); (_sr) >= min_sr(_port); (_sr)--) \ if ((_port)->sampling_rate_mask & SCI_SR((_sr))) -struct plat_sci_reg { - u8 offset, size; +#define SCI_NPORTS CONFIG_SERIAL_SH_SCI_NR_UARTS + +static struct sci_port sci_ports[SCI_NPORTS]; +static unsigned long sci_ports_in_use; +static struct uart_driver sci_uart_driver; +static bool sci_uart_earlycon; +static bool sci_uart_earlycon_dev_probing; + +static const struct sci_port_params_bits sci_sci_port_params_bits = { + .rxtx_enable = SCSCR_RE | SCSCR_TE, + .te_clear = SCSCR_TE | SCSCR_TEIE, + .poll_sent_bits = SCI_TDRE | SCI_TEND +}; + +static const struct sci_port_params_bits sci_scif_port_params_bits = { + .rxtx_enable = SCSCR_RE | SCSCR_TE, + .te_clear = SCSCR_TE | SCSCR_TEIE, + .poll_sent_bits = SCIF_TDFE | SCIF_TEND +}; + +static const struct sci_common_regs sci_common_regs = { + .status = SCxSR, + .control = SCSCR, }; struct sci_suspend_regs { @@ -118,77 +112,9 @@ struct sci_suspend_regs { u8 semr; }; -struct sci_port_params { - const struct plat_sci_reg regs[SCIx_NR_REGS]; - unsigned int fifosize; - unsigned int overrun_reg; - unsigned int overrun_mask; - unsigned int sampling_rate_mask; - unsigned int error_mask; - unsigned int error_clear; -}; - -struct sci_port { - struct uart_port port; - - /* Platform configuration */ - const struct sci_port_params *params; - const struct plat_sci_port *cfg; - unsigned int sampling_rate_mask; - resource_size_t reg_size; - struct mctrl_gpios *gpios; - - /* Clocks */ - struct clk *clks[SCI_NUM_CLKS]; - unsigned long clk_rates[SCI_NUM_CLKS]; - - int irqs[SCIx_NR_IRQS]; - char *irqstr[SCIx_NR_IRQS]; - - struct dma_chan *chan_tx; - struct dma_chan *chan_rx; - - struct reset_control *rstc; - -#ifdef CONFIG_SERIAL_SH_SCI_DMA - struct dma_chan *chan_tx_saved; - struct dma_chan *chan_rx_saved; - dma_cookie_t cookie_tx; - dma_cookie_t cookie_rx[2]; - dma_cookie_t active_rx; - dma_addr_t tx_dma_addr; - unsigned int tx_dma_len; - struct scatterlist sg_rx[2]; - void *rx_buf[2]; - size_t buf_len_rx; - struct work_struct work_tx; - struct hrtimer rx_timer; - unsigned int rx_timeout; /* microseconds */ -#endif - unsigned int rx_frame; - int rx_trigger; - struct timer_list rx_fifo_timer; - int rx_fifo_timeout; - struct sci_suspend_regs suspend_regs; - u16 hscif_tot; - - bool has_rtscts; - bool autorts; - bool tx_occurred; -}; - -#define SCI_NPORTS CONFIG_SERIAL_SH_SCI_NR_UARTS - -static struct sci_port sci_ports[SCI_NPORTS]; -static unsigned long sci_ports_in_use; -static struct uart_driver sci_uart_driver; -static bool sci_uart_earlycon; -static bool sci_uart_earlycon_dev_probing; - -static inline struct sci_port * -to_sci_port(struct uart_port *uart) +static size_t sci_suspend_regs_size(void) { - return container_of(uart, struct sci_port, port); + return sizeof(struct sci_suspend_regs); } static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = { @@ -211,6 +137,8 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = { .sampling_rate_mask = SCI_SR(32), .error_mask = SCI_DEFAULT_ERROR_MASK | SCI_ORER, .error_clear = SCI_ERROR_CLEAR & ~SCI_ORER, + .param_bits = &sci_sci_port_params_bits, + .common_regs = &sci_common_regs, }, /* @@ -233,6 +161,8 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = { .sampling_rate_mask = SCI_SR(32), .error_mask = SCI_DEFAULT_ERROR_MASK | SCI_ORER, .error_clear = SCI_ERROR_CLEAR & ~SCI_ORER, + .param_bits = &sci_scif_port_params_bits, + .common_regs = &sci_common_regs, }, /* @@ -257,6 +187,8 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = { .sampling_rate_mask = SCI_SR_SCIFAB, .error_mask = SCIF_DEFAULT_ERROR_MASK | SCIFA_ORER, .error_clear = SCIF_ERROR_CLEAR & ~SCIFA_ORER, + .param_bits = &sci_scif_port_params_bits, + .common_regs = &sci_common_regs, }, /* @@ -282,6 +214,8 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = { .sampling_rate_mask = SCI_SR_SCIFAB, .error_mask = SCIF_DEFAULT_ERROR_MASK | SCIFA_ORER, .error_clear = SCIF_ERROR_CLEAR & ~SCIFA_ORER, + .param_bits = &sci_scif_port_params_bits, + .common_regs = &sci_common_regs, }, /* @@ -307,10 +241,12 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = { .sampling_rate_mask = SCI_SR(32), .error_mask = SCIF_DEFAULT_ERROR_MASK, .error_clear = SCIF_ERROR_CLEAR, + .param_bits = &sci_scif_port_params_bits, + .common_regs = &sci_common_regs, }, /* - * The "SCIFA" that is in RZ/A2, RZ/G2L and RZ/T. + * The "SCIFA" that is in RZ/A2, RZ/G2L and RZ/T1. * It looks like a normal SCIF with FIFO data, but with a * compressed address space. Also, the break out of interrupts * are different: ERI/BRI, RXI, TXI, TEI, DRI. @@ -335,6 +271,8 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = { .sampling_rate_mask = SCI_SR(32), .error_mask = SCIF_DEFAULT_ERROR_MASK, .error_clear = SCIF_ERROR_CLEAR, + .param_bits = &sci_scif_port_params_bits, + .common_regs = &sci_common_regs, }, /* @@ -366,6 +304,8 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = { .sampling_rate_mask = SCI_SR(32), .error_mask = SCIF_DEFAULT_ERROR_MASK, .error_clear = SCIF_ERROR_CLEAR, + .param_bits = &sci_scif_port_params_bits, + .common_regs = &sci_common_regs, }, /* @@ -388,6 +328,8 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = { .sampling_rate_mask = SCI_SR(32), .error_mask = SCIF_DEFAULT_ERROR_MASK, .error_clear = SCIF_ERROR_CLEAR, + .param_bits = &sci_scif_port_params_bits, + .common_regs = &sci_common_regs, }, /* @@ -412,6 +354,8 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = { .sampling_rate_mask = SCI_SR(32), .error_mask = SCIF_DEFAULT_ERROR_MASK, .error_clear = SCIF_ERROR_CLEAR, + .param_bits = &sci_scif_port_params_bits, + .common_regs = &sci_common_regs, }, /* @@ -439,6 +383,8 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = { .sampling_rate_mask = SCI_SR(32), .error_mask = SCIF_DEFAULT_ERROR_MASK, .error_clear = SCIF_ERROR_CLEAR, + .param_bits = &sci_scif_port_params_bits, + .common_regs = &sci_common_regs, }, /* @@ -468,6 +414,8 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = { .sampling_rate_mask = SCI_SR_RANGE(8, 32), .error_mask = SCIF_DEFAULT_ERROR_MASK, .error_clear = SCIF_ERROR_CLEAR, + .param_bits = &sci_scif_port_params_bits, + .common_regs = &sci_common_regs, }, /* @@ -492,6 +440,8 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = { .sampling_rate_mask = SCI_SR(32), .error_mask = SCIF_DEFAULT_ERROR_MASK, .error_clear = SCIF_ERROR_CLEAR, + .param_bits = &sci_scif_port_params_bits, + .common_regs = &sci_common_regs, }, /* @@ -519,6 +469,8 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = { .sampling_rate_mask = SCI_SR(32), .error_mask = SCIF_DEFAULT_ERROR_MASK, .error_clear = SCIF_ERROR_CLEAR, + .param_bits = &sci_scif_port_params_bits, + .common_regs = &sci_common_regs, }, /* @@ -542,6 +494,8 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = { .sampling_rate_mask = SCI_SR(16), .error_mask = SCIF_DEFAULT_ERROR_MASK | SCIFA_ORER, .error_clear = SCIF_ERROR_CLEAR & ~SCIFA_ORER, + .param_bits = &sci_scif_port_params_bits, + .common_regs = &sci_common_regs, }, }; @@ -579,7 +533,7 @@ static void sci_serial_out(struct uart_port *p, int offset, int value) WARN(1, "Invalid register access\n"); } -static void sci_port_enable(struct sci_port *sci_port) +void sci_port_enable(struct sci_port *sci_port) { unsigned int i; @@ -595,7 +549,7 @@ static void sci_port_enable(struct sci_port *sci_port) sci_port->port.uartclk = sci_port->clk_rates[SCI_FCK]; } -static void sci_port_disable(struct sci_port *sci_port) +void sci_port_disable(struct sci_port *sci_port) { unsigned int i; @@ -735,12 +689,13 @@ static void sci_clear_SCxSR(struct uart_port *port, unsigned int mask) static int sci_poll_get_char(struct uart_port *port) { unsigned short status; + struct sci_port *s = to_sci_port(port); int c; do { status = sci_serial_in(port, SCxSR); if (status & SCxSR_ERRORS(port)) { - sci_clear_SCxSR(port, SCxSR_ERROR_CLEAR(port)); + s->ops->clear_SCxSR(port, SCxSR_ERROR_CLEAR(port)); continue; } break; @@ -753,7 +708,7 @@ static int sci_poll_get_char(struct uart_port *port) /* Dummy read */ sci_serial_in(port, SCxSR); - sci_clear_SCxSR(port, SCxSR_RDxF_CLEAR(port)); + s->ops->clear_SCxSR(port, SCxSR_RDxF_CLEAR(port)); return c; } @@ -761,14 +716,16 @@ static int sci_poll_get_char(struct uart_port *port) static void sci_poll_put_char(struct uart_port *port, unsigned char c) { - unsigned short status; + struct sci_port *s = to_sci_port(port); + const struct sci_common_regs *regs = s->params->common_regs; + unsigned int status; do { - status = sci_serial_in(port, SCxSR); + status = s->ops->read_reg(port, regs->status); } while (!(status & SCxSR_TDxE(port))); sci_serial_out(port, SCxTDR, c); - sci_clear_SCxSR(port, SCxSR_TDxE_CLEAR(port) & ~SCxSR_TEND(port)); + s->ops->clear_SCxSR(port, SCxSR_TDxE_CLEAR(port) & ~SCxSR_TEND(port)); } #endif /* CONFIG_CONSOLE_POLL || CONFIG_SERIAL_SH_SCI_CONSOLE || CONFIG_SERIAL_SH_SCI_EARLYCON */ @@ -911,7 +868,7 @@ static void sci_transmit_chars(struct uart_port *port) port->icount.tx++; } while (--count > 0); - sci_clear_SCxSR(port, SCxSR_TDxE_CLEAR(port)); + s->ops->clear_SCxSR(port, SCxSR_TDxE_CLEAR(port)); if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(port); @@ -930,6 +887,7 @@ static void sci_transmit_chars(struct uart_port *port) static void sci_receive_chars(struct uart_port *port) { struct tty_port *tport = &port->state->port; + struct sci_port *s = to_sci_port(port); int i, count, copied = 0; unsigned short status; unsigned char flag; @@ -984,7 +942,7 @@ static void sci_receive_chars(struct uart_port *port) } sci_serial_in(port, SCxSR); /* dummy read */ - sci_clear_SCxSR(port, SCxSR_RDxF_CLEAR(port)); + s->ops->clear_SCxSR(port, SCxSR_RDxF_CLEAR(port)); copied += count; port->icount.rx += count; @@ -997,16 +955,17 @@ static void sci_receive_chars(struct uart_port *port) /* TTY buffers full; read from RX reg to prevent lockup */ sci_serial_in(port, SCxRDR); sci_serial_in(port, SCxSR); /* dummy read */ - sci_clear_SCxSR(port, SCxSR_RDxF_CLEAR(port)); + s->ops->clear_SCxSR(port, SCxSR_RDxF_CLEAR(port)); } } static int sci_handle_errors(struct uart_port *port) { int copied = 0; - unsigned short status = sci_serial_in(port, SCxSR); - struct tty_port *tport = &port->state->port; struct sci_port *s = to_sci_port(port); + const struct sci_common_regs *regs = s->params->common_regs; + unsigned int status = s->ops->read_reg(port, regs->status); + struct tty_port *tport = &port->state->port; /* Handle overruns */ if (status & s->params->overrun_mask) { @@ -1161,11 +1120,11 @@ static int scif_rtrg_enabled(struct uart_port *port) static void rx_fifo_timer_fn(struct timer_list *t) { - struct sci_port *s = from_timer(s, t, rx_fifo_timer); + struct sci_port *s = timer_container_of(s, t, rx_fifo_timer); struct uart_port *port = &s->port; dev_dbg(port->dev, "Rx timed out\n"); - scif_set_rtrg(port, 1); + s->ops->set_rtrg(port, 1); } static ssize_t rx_fifo_trigger_show(struct device *dev, @@ -1190,9 +1149,9 @@ static ssize_t rx_fifo_trigger_store(struct device *dev, if (ret) return ret; - sci->rx_trigger = scif_set_rtrg(port, r); + sci->rx_trigger = sci->ops->set_rtrg(port, r); if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) - scif_set_rtrg(port, 1); + sci->ops->set_rtrg(port, 1); return count; } @@ -1235,7 +1194,7 @@ static ssize_t rx_fifo_timeout_store(struct device *dev, sci->hscif_tot = r << HSSCR_TOT_SHIFT; } else { sci->rx_fifo_timeout = r; - scif_set_rtrg(port, 1); + sci->ops->set_rtrg(port, 1); if (r > 0) timer_setup(&sci->rx_fifo_timer, rx_fifo_timer_fn, 0); } @@ -1360,7 +1319,7 @@ static void sci_dma_rx_reenable_irq(struct sci_port *s) s->cfg->regtype == SCIx_RZ_SCIFA_REGTYPE) { enable_irq(s->irqs[SCIx_RXI_IRQ]); if (s->cfg->regtype == SCIx_RZ_SCIFA_REGTYPE) - scif_set_rtrg(port, s->rx_trigger); + s->ops->set_rtrg(port, s->rx_trigger); else scr &= ~SCSCR_RDRQE; } @@ -1798,7 +1757,7 @@ static irqreturn_t sci_rx_interrupt(int irq, void *ptr) s->cfg->regtype == SCIx_RZ_SCIFA_REGTYPE) { disable_irq_nosync(s->irqs[SCIx_RXI_IRQ]); if (s->cfg->regtype == SCIx_RZ_SCIFA_REGTYPE) { - scif_set_rtrg(port, 1); + s->ops->set_rtrg(port, 1); scr |= SCSCR_RIE; } else { scr |= SCSCR_RDRQE; @@ -1824,8 +1783,8 @@ handle_pio: #endif if (s->rx_trigger > 1 && s->rx_fifo_timeout > 0) { - if (!scif_rtrg_enabled(port)) - scif_set_rtrg(port, s->rx_trigger); + if (!s->ops->rtrg_enabled(port)) + s->ops->set_rtrg(port, s->rx_trigger); mod_timer(&s->rx_fifo_timer, jiffies + DIV_ROUND_UP( s->rx_frame * HZ * s->rx_fifo_timeout, 1000000)); @@ -1835,7 +1794,7 @@ handle_pio: * of whether the I_IXOFF is set, otherwise, how is the interrupt * to be disabled? */ - sci_receive_chars(port); + s->ops->receive_chars(port); return IRQ_HANDLED; } @@ -1844,9 +1803,10 @@ static irqreturn_t sci_tx_interrupt(int irq, void *ptr) { struct uart_port *port = ptr; unsigned long flags; + struct sci_port *s = to_sci_port(port); uart_port_lock_irqsave(port, &flags); - sci_transmit_chars(port); + s->ops->transmit_chars(port); uart_port_unlock_irqrestore(port, flags); return IRQ_HANDLED; @@ -1855,16 +1815,18 @@ static irqreturn_t sci_tx_interrupt(int irq, void *ptr) static irqreturn_t sci_tx_end_interrupt(int irq, void *ptr) { struct uart_port *port = ptr; + struct sci_port *s = to_sci_port(port); + const struct sci_common_regs *regs = s->params->common_regs; unsigned long flags; - unsigned short ctrl; + u32 ctrl; if (port->type != PORT_SCI) return sci_tx_interrupt(irq, ptr); uart_port_lock_irqsave(port, &flags); - ctrl = sci_serial_in(port, SCSCR); - ctrl &= ~(SCSCR_TE | SCSCR_TEIE); - sci_serial_out(port, SCSCR, ctrl); + ctrl = s->ops->read_reg(port, regs->control) & + ~(s->params->param_bits->te_clear); + s->ops->write_reg(port, regs->control, ctrl); uart_port_unlock_irqrestore(port, flags); return IRQ_HANDLED; @@ -1873,6 +1835,7 @@ static irqreturn_t sci_tx_end_interrupt(int irq, void *ptr) static irqreturn_t sci_br_interrupt(int irq, void *ptr) { struct uart_port *port = ptr; + struct sci_port *s = to_sci_port(port); /* Handle BREAKs */ sci_handle_breaks(port); @@ -1880,7 +1843,7 @@ static irqreturn_t sci_br_interrupt(int irq, void *ptr) /* drop invalid character received before break was detected */ sci_serial_in(port, SCxRDR); - sci_clear_SCxSR(port, SCxSR_BREAK_CLEAR(port)); + s->ops->clear_SCxSR(port, SCxSR_BREAK_CLEAR(port)); return IRQ_HANDLED; } @@ -1908,15 +1871,15 @@ static irqreturn_t sci_er_interrupt(int irq, void *ptr) if (sci_handle_errors(port)) { /* discard character in rx buffer */ sci_serial_in(port, SCxSR); - sci_clear_SCxSR(port, SCxSR_RDxF_CLEAR(port)); + s->ops->clear_SCxSR(port, SCxSR_RDxF_CLEAR(port)); } } else { sci_handle_fifo_overrun(port); if (!s->chan_rx) - sci_receive_chars(port); + s->ops->receive_chars(port); } - sci_clear_SCxSR(port, SCxSR_ERROR_CLEAR(port)); + s->ops->clear_SCxSR(port, SCxSR_ERROR_CLEAR(port)); /* Kick the transmission */ if (!s->chan_tx) @@ -2286,7 +2249,17 @@ static void sci_break_ctl(struct uart_port *port, int break_state) uart_port_unlock_irqrestore(port, flags); } -static int sci_startup(struct uart_port *port) +static void sci_shutdown_complete(struct uart_port *port) +{ + struct sci_port *s = to_sci_port(port); + u16 scr; + + scr = sci_serial_in(port, SCSCR); + sci_serial_out(port, SCSCR, + scr & (SCSCR_CKE1 | SCSCR_CKE0 | s->hscif_tot)); +} + +int sci_startup(struct uart_port *port) { struct sci_port *s = to_sci_port(port); int ret; @@ -2305,11 +2278,10 @@ static int sci_startup(struct uart_port *port) return 0; } -static void sci_shutdown(struct uart_port *port) +void sci_shutdown(struct uart_port *port) { struct sci_port *s = to_sci_port(port); unsigned long flags; - u16 scr; dev_dbg(port->dev, "%s(%d)\n", __func__, port->line); @@ -2319,13 +2291,7 @@ static void sci_shutdown(struct uart_port *port) uart_port_lock_irqsave(port, &flags); sci_stop_rx(port); sci_stop_tx(port); - /* - * Stop RX and TX, disable related interrupts, keep clock source - * and HSCIF TOT bits - */ - scr = sci_serial_in(port, SCSCR); - sci_serial_out(port, SCSCR, - scr & (SCSCR_CKE1 | SCSCR_CKE0 | s->hscif_tot)); + s->ops->shutdown_complete(port); uart_port_unlock_irqrestore(port, flags); #ifdef CONFIG_SERIAL_SH_SCI_DMA @@ -2402,8 +2368,8 @@ static int sci_brg_calc(struct sci_port *s, unsigned int bps, /* calculate sample rate, BRR, and clock select */ static int sci_scbrr_calc(struct sci_port *s, unsigned int bps, - unsigned int *brr, unsigned int *srr, - unsigned int *cks) + unsigned int *brr, unsigned int *srr, + unsigned int *cks) { unsigned long freq = s->clk_rates[SCI_FCK]; unsigned int sr, br, prediv, scrate, c; @@ -2480,9 +2446,9 @@ static void sci_reset(struct uart_port *port) if (reg->size) sci_serial_out(port, SCFCR, SCFCR_RFRST | SCFCR_TFRST); - sci_clear_SCxSR(port, - SCxSR_RDxF_CLEAR(port) & SCxSR_ERROR_CLEAR(port) & - SCxSR_BREAK_CLEAR(port)); + s->ops->clear_SCxSR(port, + SCxSR_RDxF_CLEAR(port) & SCxSR_ERROR_CLEAR(port) & + SCxSR_BREAK_CLEAR(port)); if (sci_getreg(port, SCLSR)->size) { status = sci_serial_in(port, SCLSR); status &= ~(SCLSR_TO | SCLSR_ORER); @@ -2491,14 +2457,14 @@ static void sci_reset(struct uart_port *port) if (s->rx_trigger > 1) { if (s->rx_fifo_timeout) { - scif_set_rtrg(port, 1); + s->ops->set_rtrg(port, 1); timer_setup(&s->rx_fifo_timer, rx_fifo_timer_fn, 0); } else { if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) - scif_set_rtrg(port, 1); + s->ops->set_rtrg(port, 1); else - scif_set_rtrg(port, s->rx_trigger); + s->ops->set_rtrg(port, s->rx_trigger); } } } @@ -2758,7 +2724,7 @@ done: sci_enable_ms(port); } -static void sci_pm(struct uart_port *port, unsigned int state, +void sci_pm(struct uart_port *port, unsigned int state, unsigned int oldstate) { struct sci_port *sci_port = to_sci_port(port); @@ -2821,7 +2787,7 @@ static int sci_remap_port(struct uart_port *port) return 0; } -static void sci_release_port(struct uart_port *port) +void sci_release_port(struct uart_port *port) { struct sci_port *sport = to_sci_port(port); @@ -2833,7 +2799,7 @@ static void sci_release_port(struct uart_port *port) release_mem_region(port->mapbase, sport->reg_size); } -static int sci_request_port(struct uart_port *port) +int sci_request_port(struct uart_port *port) { struct resource *res; struct sci_port *sport = to_sci_port(port); @@ -2855,7 +2821,7 @@ static int sci_request_port(struct uart_port *port) return 0; } -static void sci_config_port(struct uart_port *port, int flags) +void sci_config_port(struct uart_port *port, int flags) { if (flags & UART_CONFIG_TYPE) { struct sci_port *sport = to_sci_port(port); @@ -2865,7 +2831,7 @@ static void sci_config_port(struct uart_port *port, int flags) } } -static int sci_verify_port(struct uart_port *port, struct serial_struct *ser) +int sci_verify_port(struct uart_port *port, struct serial_struct *ser) { if (ser->baud_base < 2400) /* No paper tape reader for Mitch.. */ @@ -2874,6 +2840,75 @@ static int sci_verify_port(struct uart_port *port, struct serial_struct *ser) return 0; } +static void sci_prepare_console_write(struct uart_port *port, u32 ctrl) +{ + struct sci_port *s = to_sci_port(port); + u32 ctrl_temp = + s->params->param_bits->rxtx_enable | + (s->cfg->scscr & ~(SCSCR_CKE1 | SCSCR_CKE0)) | + (ctrl & (SCSCR_CKE1 | SCSCR_CKE0)) | + s->hscif_tot; + sci_serial_out(port, SCSCR, ctrl_temp); +} + +static void sci_console_save(struct uart_port *port) +{ + struct sci_port *s = to_sci_port(port); + struct sci_suspend_regs *regs = s->suspend_regs; + + if (sci_getreg(port, SCDL)->size) + regs->scdl = sci_serial_in(port, SCDL); + if (sci_getreg(port, SCCKS)->size) + regs->sccks = sci_serial_in(port, SCCKS); + if (sci_getreg(port, SCSMR)->size) + regs->scsmr = sci_serial_in(port, SCSMR); + if (sci_getreg(port, SCSCR)->size) + regs->scscr = sci_serial_in(port, SCSCR); + if (sci_getreg(port, SCFCR)->size) + regs->scfcr = sci_serial_in(port, SCFCR); + if (sci_getreg(port, SCSPTR)->size) + regs->scsptr = sci_serial_in(port, SCSPTR); + if (sci_getreg(port, SCBRR)->size) + regs->scbrr = sci_serial_in(port, SCBRR); + if (sci_getreg(port, HSSRR)->size) + regs->hssrr = sci_serial_in(port, HSSRR); + if (sci_getreg(port, SCPCR)->size) + regs->scpcr = sci_serial_in(port, SCPCR); + if (sci_getreg(port, SCPDR)->size) + regs->scpdr = sci_serial_in(port, SCPDR); + if (sci_getreg(port, SEMR)->size) + regs->semr = sci_serial_in(port, SEMR); +} + +static void sci_console_restore(struct uart_port *port) +{ + struct sci_port *s = to_sci_port(port); + struct sci_suspend_regs *regs = s->suspend_regs; + + if (sci_getreg(port, SCDL)->size) + sci_serial_out(port, SCDL, regs->scdl); + if (sci_getreg(port, SCCKS)->size) + sci_serial_out(port, SCCKS, regs->sccks); + if (sci_getreg(port, SCSMR)->size) + sci_serial_out(port, SCSMR, regs->scsmr); + if (sci_getreg(port, SCSCR)->size) + sci_serial_out(port, SCSCR, regs->scscr); + if (sci_getreg(port, SCFCR)->size) + sci_serial_out(port, SCFCR, regs->scfcr); + if (sci_getreg(port, SCSPTR)->size) + sci_serial_out(port, SCSPTR, regs->scsptr); + if (sci_getreg(port, SCBRR)->size) + sci_serial_out(port, SCBRR, regs->scbrr); + if (sci_getreg(port, HSSRR)->size) + sci_serial_out(port, HSSRR, regs->hssrr); + if (sci_getreg(port, SCPCR)->size) + sci_serial_out(port, SCPCR, regs->scpcr); + if (sci_getreg(port, SCPDR)->size) + sci_serial_out(port, SCPDR, regs->scpdr); + if (sci_getreg(port, SEMR)->size) + sci_serial_out(port, SEMR, regs->semr); +} + static const struct uart_ops sci_uart_ops = { .tx_empty = sci_tx_empty, .set_mctrl = sci_set_mctrl, @@ -2899,6 +2934,25 @@ static const struct uart_ops sci_uart_ops = { #endif }; +static const struct sci_port_ops sci_port_ops = { + .read_reg = sci_serial_in, + .write_reg = sci_serial_out, + .clear_SCxSR = sci_clear_SCxSR, + .transmit_chars = sci_transmit_chars, + .receive_chars = sci_receive_chars, +#if defined(CONFIG_SERIAL_SH_SCI_CONSOLE) || \ + defined(CONFIG_SERIAL_SH_SCI_EARLYCON) + .poll_put_char = sci_poll_put_char, +#endif + .set_rtrg = scif_set_rtrg, + .rtrg_enabled = scif_rtrg_enabled, + .shutdown_complete = sci_shutdown_complete, + .prepare_console_write = sci_prepare_console_write, + .console_save = sci_console_save, + .console_restore = sci_console_restore, + .suspend_regs_size = sci_suspend_regs_size, +}; + static int sci_init_clocks(struct sci_port *sci_port, struct device *dev) { const char *clk_names[] = { @@ -2942,10 +2996,13 @@ static int sci_init_clocks(struct sci_port *sci_port, struct device *dev) } static const struct sci_port_params * -sci_probe_regmap(const struct plat_sci_port *cfg) +sci_probe_regmap(const struct plat_sci_port *cfg, struct sci_port *sci_port) { unsigned int regtype; + sci_port->ops = &sci_port_ops; + sci_port->port.ops = &sci_uart_ops; + if (cfg->regtype != SCIx_PROBE_REGTYPE) return &sci_port_params[cfg->regtype]; @@ -2993,7 +3050,6 @@ static int sci_init_single(struct platform_device *dev, sci_port->cfg = p; - port->ops = &sci_uart_ops; port->iotype = UPIO_MEM; port->line = index; port->has_sysrq = IS_ENABLED(CONFIG_SERIAL_SH_SCI_CONSOLE); @@ -3033,10 +3089,6 @@ static int sci_init_single(struct platform_device *dev, for (i = 1; i < ARRAY_SIZE(sci_port->irqs); i++) sci_port->irqs[i] = sci_port->irqs[0]; - sci_port->params = sci_probe_regmap(p); - if (unlikely(sci_port->params == NULL)) - return -EINVAL; - switch (p->type) { case PORT_SCIFB: sci_port->rx_trigger = 48; @@ -3104,7 +3156,7 @@ static int sci_init_single(struct platform_device *dev, defined(CONFIG_SERIAL_SH_SCI_EARLYCON) static void serial_console_putchar(struct uart_port *port, unsigned char ch) { - sci_poll_put_char(port, ch); + to_sci_port(port)->ops->poll_put_char(port, ch); } /* @@ -3116,7 +3168,9 @@ static void serial_console_write(struct console *co, const char *s, { struct sci_port *sci_port = &sci_ports[co->index]; struct uart_port *port = &sci_port->port; - unsigned short bits, ctrl, ctrl_temp; + const struct sci_common_regs *regs = sci_port->params->common_regs; + unsigned int bits; + u32 ctrl; unsigned long flags; int locked = 1; @@ -3128,21 +3182,21 @@ static void serial_console_write(struct console *co, const char *s, uart_port_lock_irqsave(port, &flags); /* first save SCSCR then disable interrupts, keep clock source */ - ctrl = sci_serial_in(port, SCSCR); - ctrl_temp = SCSCR_RE | SCSCR_TE | - (sci_port->cfg->scscr & ~(SCSCR_CKE1 | SCSCR_CKE0)) | - (ctrl & (SCSCR_CKE1 | SCSCR_CKE0)); - sci_serial_out(port, SCSCR, ctrl_temp | sci_port->hscif_tot); + + ctrl = sci_port->ops->read_reg(port, regs->control); + sci_port->ops->prepare_console_write(port, ctrl); uart_console_write(port, s, count, serial_console_putchar); /* wait until fifo is empty and last bit has been transmitted */ - bits = SCxSR_TDxE(port) | SCxSR_TEND(port); - while ((sci_serial_in(port, SCxSR) & bits) != bits) + + bits = sci_port->params->param_bits->poll_sent_bits; + + while ((sci_port->ops->read_reg(port, regs->status) & bits) != bits) cpu_relax(); /* restore the SCSCR */ - sci_serial_out(port, SCSCR, ctrl); + sci_port->ops->write_reg(port, regs->control, ctrl); if (locked) uart_port_unlock_irqrestore(port, flags); @@ -3220,13 +3274,18 @@ static struct console early_serial_console = { static int sci_probe_earlyprintk(struct platform_device *pdev) { const struct plat_sci_port *cfg = dev_get_platdata(&pdev->dev); + struct sci_port *sp = &sci_ports[pdev->id]; if (early_serial_console.data) return -EEXIST; early_serial_console.index = pdev->id; - sci_init_single(pdev, &sci_ports[pdev->id], pdev->id, cfg, true); + sp->params = sci_probe_regmap(cfg, sp); + if (!sp->params) + return -ENODEV; + + sci_init_single(pdev, sp, pdev->id, cfg, true); if (!strstr(early_serial_buf, "keep")) early_serial_console.flags |= CON_BOOT; @@ -3275,59 +3334,126 @@ static void sci_remove(struct platform_device *dev) device_remove_file(&dev->dev, &dev_attr_rx_fifo_timeout); } +static const struct sci_of_data of_sci_scif_sh2 = { + .type = PORT_SCIF, + .regtype = SCIx_SH2_SCIF_FIFODATA_REGTYPE, + .ops = &sci_port_ops, + .uart_ops = &sci_uart_ops, + .params = &sci_port_params[SCIx_SH2_SCIF_FIFODATA_REGTYPE], +}; + +static const struct sci_of_data of_sci_scif_rz_scifa = { + .type = PORT_SCIF, + .regtype = SCIx_RZ_SCIFA_REGTYPE, + .ops = &sci_port_ops, + .uart_ops = &sci_uart_ops, + .params = &sci_port_params[SCIx_RZ_SCIFA_REGTYPE], +}; + +static const struct sci_of_data of_sci_scif_rzv2h = { + .type = PORT_SCIF, + .regtype = SCIx_RZV2H_SCIF_REGTYPE, + .ops = &sci_port_ops, + .uart_ops = &sci_uart_ops, + .params = &sci_port_params[SCIx_RZV2H_SCIF_REGTYPE], +}; + +static const struct sci_of_data of_sci_rcar_scif = { + .type = PORT_SCIF, + .regtype = SCIx_SH4_SCIF_BRG_REGTYPE, + .ops = &sci_port_ops, + .uart_ops = &sci_uart_ops, + .params = &sci_port_params[SCIx_SH4_SCIF_BRG_REGTYPE], +}; -#define SCI_OF_DATA(type, regtype) (void *)((type) << 16 | (regtype)) -#define SCI_OF_TYPE(data) ((unsigned long)(data) >> 16) -#define SCI_OF_REGTYPE(data) ((unsigned long)(data) & 0xffff) +static const struct sci_of_data of_sci_scif_sh4 = { + .type = PORT_SCIF, + .regtype = SCIx_SH4_SCIF_REGTYPE, + .ops = &sci_port_ops, + .uart_ops = &sci_uart_ops, + .params = &sci_port_params[SCIx_SH4_SCIF_REGTYPE], +}; + +static const struct sci_of_data of_sci_scifa = { + .type = PORT_SCIFA, + .regtype = SCIx_SCIFA_REGTYPE, + .ops = &sci_port_ops, + .uart_ops = &sci_uart_ops, + .params = &sci_port_params[SCIx_SCIFA_REGTYPE], +}; + +static const struct sci_of_data of_sci_scifb = { + .type = PORT_SCIFB, + .regtype = SCIx_SCIFB_REGTYPE, + .ops = &sci_port_ops, + .uart_ops = &sci_uart_ops, + .params = &sci_port_params[SCIx_SCIFB_REGTYPE], +}; + +static const struct sci_of_data of_sci_hscif = { + .type = PORT_HSCIF, + .regtype = SCIx_HSCIF_REGTYPE, + .ops = &sci_port_ops, + .uart_ops = &sci_uart_ops, + .params = &sci_port_params[SCIx_HSCIF_REGTYPE], +}; + +static const struct sci_of_data of_sci_sci = { + .type = PORT_SCI, + .regtype = SCIx_SCI_REGTYPE, + .ops = &sci_port_ops, + .uart_ops = &sci_uart_ops, + .params = &sci_port_params[SCIx_SCI_REGTYPE], +}; static const struct of_device_id of_sci_match[] __maybe_unused = { /* SoC-specific types */ { .compatible = "renesas,scif-r7s72100", - .data = SCI_OF_DATA(PORT_SCIF, SCIx_SH2_SCIF_FIFODATA_REGTYPE), + .data = &of_sci_scif_sh2, }, { .compatible = "renesas,scif-r7s9210", - .data = SCI_OF_DATA(PORT_SCIF, SCIx_RZ_SCIFA_REGTYPE), + .data = &of_sci_scif_rz_scifa, }, { .compatible = "renesas,scif-r9a07g044", - .data = SCI_OF_DATA(PORT_SCIF, SCIx_RZ_SCIFA_REGTYPE), + .data = &of_sci_scif_rz_scifa, }, { .compatible = "renesas,scif-r9a09g057", - .data = SCI_OF_DATA(PORT_SCIF, SCIx_RZV2H_SCIF_REGTYPE), + .data = &of_sci_scif_rzv2h, }, /* Family-specific types */ { .compatible = "renesas,rcar-gen1-scif", - .data = SCI_OF_DATA(PORT_SCIF, SCIx_SH4_SCIF_BRG_REGTYPE), + .data = &of_sci_rcar_scif, }, { .compatible = "renesas,rcar-gen2-scif", - .data = SCI_OF_DATA(PORT_SCIF, SCIx_SH4_SCIF_BRG_REGTYPE), + .data = &of_sci_rcar_scif, }, { .compatible = "renesas,rcar-gen3-scif", - .data = SCI_OF_DATA(PORT_SCIF, SCIx_SH4_SCIF_BRG_REGTYPE), + .data = &of_sci_rcar_scif }, { .compatible = "renesas,rcar-gen4-scif", - .data = SCI_OF_DATA(PORT_SCIF, SCIx_SH4_SCIF_BRG_REGTYPE), + .data = &of_sci_rcar_scif }, /* Generic types */ { .compatible = "renesas,scif", - .data = SCI_OF_DATA(PORT_SCIF, SCIx_SH4_SCIF_REGTYPE), + .data = &of_sci_scif_sh4, }, { .compatible = "renesas,scifa", - .data = SCI_OF_DATA(PORT_SCIFA, SCIx_SCIFA_REGTYPE), + .data = &of_sci_scifa, }, { .compatible = "renesas,scifb", - .data = SCI_OF_DATA(PORT_SCIFB, SCIx_SCIFB_REGTYPE), + .data = &of_sci_scifb, }, { .compatible = "renesas,hscif", - .data = SCI_OF_DATA(PORT_HSCIF, SCIx_HSCIF_REGTYPE), + .data = &of_sci_hscif, }, { .compatible = "renesas,sci", - .data = SCI_OF_DATA(PORT_SCI, SCIx_SCI_REGTYPE), + .data = &of_sci_sci, }, { /* Terminator */ }, @@ -3346,7 +3472,7 @@ static struct plat_sci_port *sci_parse_dt(struct platform_device *pdev, struct reset_control *rstc; struct plat_sci_port *p; struct sci_port *sp; - const void *data; + const struct sci_of_data *data; int id, ret; if (!IS_ENABLED(CONFIG_OF) || !np) @@ -3393,8 +3519,12 @@ static struct plat_sci_port *sci_parse_dt(struct platform_device *pdev, sp->rstc = rstc; *dev_id = id; - p->type = SCI_OF_TYPE(data); - p->regtype = SCI_OF_REGTYPE(data); + p->type = data->type; + p->regtype = data->regtype; + + sp->ops = data->ops; + sp->port.ops = data->uart_ops; + sp->params = data->params; sp->has_rtscts = of_property_read_bool(np, "uart-has-rtscts"); @@ -3501,6 +3631,7 @@ static int sci_probe(struct platform_device *dev) p = sci_parse_dt(dev, &dev_id); if (IS_ERR(p)) return PTR_ERR(p); + sp = &sci_ports[dev_id]; } else { p = dev->dev.platform_data; if (p == NULL) { @@ -3509,9 +3640,17 @@ static int sci_probe(struct platform_device *dev) } dev_id = dev->id; + sp = &sci_ports[dev_id]; + sp->params = sci_probe_regmap(p, sp); + if (!sp->params) + return -ENODEV; } - sp = &sci_ports[dev_id]; + sp->suspend_regs = devm_kzalloc(&dev->dev, + sp->ops->suspend_regs_size(), + GFP_KERNEL); + if (!sp->suspend_regs) + return -ENOMEM; /* * In case: @@ -3563,64 +3702,6 @@ static int sci_probe(struct platform_device *dev) return 0; } -static void sci_console_save(struct sci_port *s) -{ - struct sci_suspend_regs *regs = &s->suspend_regs; - struct uart_port *port = &s->port; - - if (sci_getreg(port, SCDL)->size) - regs->scdl = sci_serial_in(port, SCDL); - if (sci_getreg(port, SCCKS)->size) - regs->sccks = sci_serial_in(port, SCCKS); - if (sci_getreg(port, SCSMR)->size) - regs->scsmr = sci_serial_in(port, SCSMR); - if (sci_getreg(port, SCSCR)->size) - regs->scscr = sci_serial_in(port, SCSCR); - if (sci_getreg(port, SCFCR)->size) - regs->scfcr = sci_serial_in(port, SCFCR); - if (sci_getreg(port, SCSPTR)->size) - regs->scsptr = sci_serial_in(port, SCSPTR); - if (sci_getreg(port, SCBRR)->size) - regs->scbrr = sci_serial_in(port, SCBRR); - if (sci_getreg(port, HSSRR)->size) - regs->hssrr = sci_serial_in(port, HSSRR); - if (sci_getreg(port, SCPCR)->size) - regs->scpcr = sci_serial_in(port, SCPCR); - if (sci_getreg(port, SCPDR)->size) - regs->scpdr = sci_serial_in(port, SCPDR); - if (sci_getreg(port, SEMR)->size) - regs->semr = sci_serial_in(port, SEMR); -} - -static void sci_console_restore(struct sci_port *s) -{ - struct sci_suspend_regs *regs = &s->suspend_regs; - struct uart_port *port = &s->port; - - if (sci_getreg(port, SCDL)->size) - sci_serial_out(port, SCDL, regs->scdl); - if (sci_getreg(port, SCCKS)->size) - sci_serial_out(port, SCCKS, regs->sccks); - if (sci_getreg(port, SCSMR)->size) - sci_serial_out(port, SCSMR, regs->scsmr); - if (sci_getreg(port, SCSCR)->size) - sci_serial_out(port, SCSCR, regs->scscr); - if (sci_getreg(port, SCFCR)->size) - sci_serial_out(port, SCFCR, regs->scfcr); - if (sci_getreg(port, SCSPTR)->size) - sci_serial_out(port, SCSPTR, regs->scsptr); - if (sci_getreg(port, SCBRR)->size) - sci_serial_out(port, SCBRR, regs->scbrr); - if (sci_getreg(port, HSSRR)->size) - sci_serial_out(port, HSSRR, regs->hssrr); - if (sci_getreg(port, SCPCR)->size) - sci_serial_out(port, SCPCR, regs->scpcr); - if (sci_getreg(port, SCPDR)->size) - sci_serial_out(port, SCPDR, regs->scpdr); - if (sci_getreg(port, SEMR)->size) - sci_serial_out(port, SEMR, regs->semr); -} - static __maybe_unused int sci_suspend(struct device *dev) { struct sci_port *sport = dev_get_drvdata(dev); @@ -3628,8 +3709,10 @@ static __maybe_unused int sci_suspend(struct device *dev) if (sport) { uart_suspend_port(&sci_uart_driver, &sport->port); - if (!console_suspend_enabled && uart_console(&sport->port)) - sci_console_save(sport); + if (!console_suspend_enabled && uart_console(&sport->port)) { + if (sport->ops->console_save) + sport->ops->console_save(&sport->port); + } else return reset_control_assert(sport->rstc); } @@ -3643,7 +3726,8 @@ static __maybe_unused int sci_resume(struct device *dev) if (sport) { if (!console_suspend_enabled && uart_console(&sport->port)) { - sci_console_restore(sport); + if (sport->ops->console_restore) + sport->ops->console_restore(&sport->port); } else { int ret = reset_control_deassert(sport->rstc); @@ -3707,21 +3791,31 @@ static int early_console_exit(struct console *co) return 0; } -static int __init early_console_setup(struct earlycon_device *device, - int type) +int __init scix_early_console_setup(struct earlycon_device *device, + const struct sci_of_data *data) { + const struct sci_common_regs *regs; + if (!device->port.membase) return -ENODEV; - device->port.type = type; + device->port.type = data->type; sci_ports[0].port = device->port; - port_cfg.type = type; + + port_cfg.type = data->type; + port_cfg.regtype = data->regtype; + sci_ports[0].cfg = &port_cfg; - sci_ports[0].params = sci_probe_regmap(&port_cfg); + sci_ports[0].params = data->params; + sci_ports[0].ops = data->ops; + sci_ports[0].port.ops = data->uart_ops; sci_uart_earlycon = true; - port_cfg.scscr = sci_serial_in(&sci_ports[0].port, SCSCR); - sci_serial_out(&sci_ports[0].port, SCSCR, - SCSCR_RE | SCSCR_TE | port_cfg.scscr); + regs = sci_ports[0].params->common_regs; + + port_cfg.scscr = sci_ports[0].ops->read_reg(&sci_ports[0].port, regs->control); + sci_ports[0].ops->write_reg(&sci_ports[0].port, + regs->control, + sci_ports[0].params->param_bits->rxtx_enable | port_cfg.scscr); device->con->write = serial_console_write; device->con->exit = early_console_exit; @@ -3731,41 +3825,39 @@ static int __init early_console_setup(struct earlycon_device *device, static int __init sci_early_console_setup(struct earlycon_device *device, const char *opt) { - return early_console_setup(device, PORT_SCI); + return scix_early_console_setup(device, &of_sci_sci); } static int __init scif_early_console_setup(struct earlycon_device *device, const char *opt) { - return early_console_setup(device, PORT_SCIF); + return scix_early_console_setup(device, &of_sci_scif_sh4); } static int __init rzscifa_early_console_setup(struct earlycon_device *device, const char *opt) { - port_cfg.regtype = SCIx_RZ_SCIFA_REGTYPE; - return early_console_setup(device, PORT_SCIF); + return scix_early_console_setup(device, &of_sci_scif_rz_scifa); } static int __init rzv2hscif_early_console_setup(struct earlycon_device *device, const char *opt) { - port_cfg.regtype = SCIx_RZV2H_SCIF_REGTYPE; - return early_console_setup(device, PORT_SCIF); + return scix_early_console_setup(device, &of_sci_scif_rzv2h); } static int __init scifa_early_console_setup(struct earlycon_device *device, const char *opt) { - return early_console_setup(device, PORT_SCIFA); + return scix_early_console_setup(device, &of_sci_scifa); } static int __init scifb_early_console_setup(struct earlycon_device *device, const char *opt) { - return early_console_setup(device, PORT_SCIFB); + return scix_early_console_setup(device, &of_sci_scifb); } static int __init hscif_early_console_setup(struct earlycon_device *device, const char *opt) { - return early_console_setup(device, PORT_HSCIF); + return scix_early_console_setup(device, &of_sci_hscif); } OF_EARLYCON_DECLARE(sci, "renesas,sci", sci_early_console_setup); diff --git a/drivers/tty/serial/sh-sci.h b/drivers/tty/serial/sh-sci.h index 0b65563c4e9e..951681aba586 100644 --- a/drivers/tty/serial/sh-sci.h +++ b/drivers/tty/serial/sh-sci.h @@ -32,8 +32,6 @@ enum { HSRTRGR, /* Rx FIFO Data Count Trigger Register */ HSTTRGR, /* Tx FIFO Data Count Trigger Register */ SEMR, /* Serial extended mode register */ - - SCIx_NR_REGS, }; diff --git a/drivers/tty/serial/sifive.c b/drivers/tty/serial/sifive.c index 054a8e630ace..110d67613192 100644 --- a/drivers/tty/serial/sifive.c +++ b/drivers/tty/serial/sifive.c @@ -141,6 +141,7 @@ * @baud_rate: UART serial line rate (e.g., 115200 baud) * @clk: reference to this device's clock * @clk_notifier: clock rate change notifier for upstream clock changes + * @console_line_ended: indicate that the console line is fully written * * Configuration data specific to this SiFive UART. */ @@ -151,6 +152,7 @@ struct sifive_serial_port { unsigned long baud_rate; struct clk *clk; struct notifier_block clk_notifier; + bool console_line_ended; }; /* @@ -785,33 +787,88 @@ static void sifive_serial_console_putchar(struct uart_port *port, unsigned char __ssp_wait_for_xmitr(ssp); __ssp_transmit_char(ssp, ch); + + ssp->console_line_ended = (ch == '\n'); +} + +static void sifive_serial_device_lock(struct console *co, unsigned long *flags) +{ + struct uart_port *up = &sifive_serial_console_ports[co->index]->port; + + __uart_port_lock_irqsave(up, flags); +} + +static void sifive_serial_device_unlock(struct console *co, unsigned long flags) +{ + struct uart_port *up = &sifive_serial_console_ports[co->index]->port; + + __uart_port_unlock_irqrestore(up, flags); } -static void sifive_serial_console_write(struct console *co, const char *s, - unsigned int count) +static void sifive_serial_console_write_atomic(struct console *co, + struct nbcon_write_context *wctxt) { struct sifive_serial_port *ssp = sifive_serial_console_ports[co->index]; - unsigned long flags; + struct uart_port *port = &ssp->port; unsigned int ier; - int locked = 1; if (!ssp) return; - if (oops_in_progress) - locked = uart_port_trylock_irqsave(&ssp->port, &flags); - else - uart_port_lock_irqsave(&ssp->port, &flags); + if (!nbcon_enter_unsafe(wctxt)) + return; ier = __ssp_readl(ssp, SIFIVE_SERIAL_IE_OFFS); __ssp_writel(0, SIFIVE_SERIAL_IE_OFFS, ssp); - uart_console_write(&ssp->port, s, count, sifive_serial_console_putchar); + if (!ssp->console_line_ended) + uart_console_write(port, "\n", 1, sifive_serial_console_putchar); + uart_console_write(port, wctxt->outbuf, wctxt->len, + sifive_serial_console_putchar); __ssp_writel(ier, SIFIVE_SERIAL_IE_OFFS, ssp); - if (locked) - uart_port_unlock_irqrestore(&ssp->port, flags); + nbcon_exit_unsafe(wctxt); +} + +static void sifive_serial_console_write_thread(struct console *co, + struct nbcon_write_context *wctxt) +{ + struct sifive_serial_port *ssp = sifive_serial_console_ports[co->index]; + struct uart_port *port = &ssp->port; + unsigned int ier; + + if (!ssp) + return; + + if (!nbcon_enter_unsafe(wctxt)) + return; + + ier = __ssp_readl(ssp, SIFIVE_SERIAL_IE_OFFS); + __ssp_writel(0, SIFIVE_SERIAL_IE_OFFS, ssp); + + if (nbcon_exit_unsafe(wctxt)) { + int len = READ_ONCE(wctxt->len); + int i; + + for (i = 0; i < len; i++) { + if (!nbcon_enter_unsafe(wctxt)) + break; + + uart_console_write(port, wctxt->outbuf + i, 1, + sifive_serial_console_putchar); + + if (!nbcon_exit_unsafe(wctxt)) + break; + } + } + + while (!nbcon_enter_unsafe(wctxt)) + nbcon_reacquire_nobuf(wctxt); + + __ssp_writel(ier, SIFIVE_SERIAL_IE_OFFS, ssp); + + nbcon_exit_unsafe(wctxt); } static int sifive_serial_console_setup(struct console *co, char *options) @@ -829,6 +886,8 @@ static int sifive_serial_console_setup(struct console *co, char *options) if (!ssp) return -ENODEV; + ssp->console_line_ended = true; + if (options) uart_parse_options(options, &baud, &parity, &bits, &flow); @@ -839,10 +898,13 @@ static struct uart_driver sifive_serial_uart_driver; static struct console sifive_serial_console = { .name = SIFIVE_TTY_PREFIX, - .write = sifive_serial_console_write, + .write_atomic = sifive_serial_console_write_atomic, + .write_thread = sifive_serial_console_write_thread, + .device_lock = sifive_serial_device_lock, + .device_unlock = sifive_serial_device_unlock, .device = uart_console_device, .setup = sifive_serial_console_setup, - .flags = CON_PRINTBUFFER, + .flags = CON_PRINTBUFFER | CON_NBCON, .index = -1, .data = &sifive_serial_uart_driver, }; diff --git a/drivers/tty/serial/tegra-utc.c b/drivers/tty/serial/tegra-utc.c index 39b14fe813c9..0c70d3e7b9b9 100644 --- a/drivers/tty/serial/tegra-utc.c +++ b/drivers/tty/serial/tegra-utc.c @@ -434,7 +434,7 @@ static void tegra_utc_console_write_atomic(struct console *cons, struct nbcon_wr outbuf += burst_size; len -= burst_size; - }; + } nbcon_exit_unsafe(wctxt); } diff --git a/drivers/tty/serial/uartlite.c b/drivers/tty/serial/uartlite.c index a41e7fc373b7..39c1fd1ff9ce 100644 --- a/drivers/tty/serial/uartlite.c +++ b/drivers/tty/serial/uartlite.c @@ -880,16 +880,6 @@ of_err: pm_runtime_set_active(&pdev->dev); pm_runtime_enable(&pdev->dev); - if (!ulite_uart_driver.state) { - dev_dbg(&pdev->dev, "uartlite: calling uart_register_driver()\n"); - ret = uart_register_driver(&ulite_uart_driver); - if (ret < 0) { - dev_err(&pdev->dev, "Failed to register driver\n"); - clk_disable_unprepare(pdata->clk); - return ret; - } - } - ret = ulite_assign(&pdev->dev, id, res->start, irq, pdata); pm_runtime_mark_last_busy(&pdev->dev); @@ -929,16 +919,25 @@ static struct platform_driver ulite_platform_driver = { static int __init ulite_init(void) { + int ret; + + pr_debug("uartlite: calling uart_register_driver()\n"); + ret = uart_register_driver(&ulite_uart_driver); + if (ret) + return ret; pr_debug("uartlite: calling platform_driver_register()\n"); - return platform_driver_register(&ulite_platform_driver); + ret = platform_driver_register(&ulite_platform_driver); + if (ret) + uart_unregister_driver(&ulite_uart_driver); + + return ret; } static void __exit ulite_exit(void) { platform_driver_unregister(&ulite_platform_driver); - if (ulite_uart_driver.state) - uart_unregister_driver(&ulite_uart_driver); + uart_unregister_driver(&ulite_uart_driver); } module_init(ulite_init); diff --git a/drivers/tty/synclink_gt.c b/drivers/tty/synclink_gt.c index 4c703f42680d..3865b10d2d43 100644 --- a/drivers/tty/synclink_gt.c +++ b/drivers/tty/synclink_gt.c @@ -5002,7 +5002,7 @@ static int adapter_test(struct slgt_info *info) */ static void tx_timeout(struct timer_list *t) { - struct slgt_info *info = from_timer(info, t, tx_timer); + struct slgt_info *info = timer_container_of(info, t, tx_timer); unsigned long flags; DBGINFO(("%s tx_timeout\n", info->device_name)); @@ -5026,7 +5026,7 @@ static void tx_timeout(struct timer_list *t) */ static void rx_timeout(struct timer_list *t) { - struct slgt_info *info = from_timer(info, t, rx_timer); + struct slgt_info *info = timer_container_of(info, t, rx_timer); unsigned long flags; DBGINFO(("%s rx_timeout\n", info->device_name)); diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c index 6853c4660e7c..d77c03d22227 100644 --- a/drivers/tty/sysrq.c +++ b/drivers/tty/sysrq.c @@ -712,7 +712,8 @@ static void sysrq_parse_reset_sequence(struct sysrq_state *state) static void sysrq_do_reset(struct timer_list *t) { - struct sysrq_state *state = from_timer(state, t, keyreset_timer); + struct sysrq_state *state = timer_container_of(state, t, + keyreset_timer); state->reset_requested = true; diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index ca9b7d7bad2b..e2d92cf70eb7 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -276,11 +276,10 @@ static void check_tty_count(struct tty_struct *tty, const char *routine) struct list_head *p; int count = 0, kopen_count = 0; - spin_lock(&tty->files_lock); - list_for_each(p, &tty->tty_files) { - count++; - } - spin_unlock(&tty->files_lock); + scoped_guard(spinlock, &tty->files_lock) + list_for_each(p, &tty->tty_files) + count++; + if (tty->driver->type == TTY_DRIVER_TYPE_PTY && tty->driver->subtype == PTY_TYPE_SLAVE && tty->link && tty->link->count) @@ -378,7 +377,7 @@ EXPORT_SYMBOL_GPL(tty_dev_name_to_number); */ struct tty_driver *tty_find_polling_driver(char *name, int *line) { - struct tty_driver *p, *res = NULL; + struct tty_driver *p; int tty_line = 0; int len; char *str, *stp; @@ -392,7 +391,8 @@ struct tty_driver *tty_find_polling_driver(char *name, int *line) len = str - name; tty_line = simple_strtoul(str, &str, 10); - mutex_lock(&tty_mutex); + guard(mutex)(&tty_mutex); + /* Search through the tty devices to look for a match */ list_for_each_entry(p, &tty_drivers, tty_drivers) { if (!len || strncmp(name, p->name, len) != 0) @@ -405,14 +405,12 @@ struct tty_driver *tty_find_polling_driver(char *name, int *line) if (tty_line >= 0 && tty_line < p->num && p->ops && p->ops->poll_init && !p->ops->poll_init(p, tty_line, stp)) { - res = tty_driver_kref_get(p); *line = tty_line; - break; + return tty_driver_kref_get(p); } } - mutex_unlock(&tty_mutex); - return res; + return NULL; } EXPORT_SYMBOL_GPL(tty_find_polling_driver); #endif @@ -531,16 +529,15 @@ EXPORT_SYMBOL_GPL(tty_wakeup); */ static struct file *tty_release_redirect(struct tty_struct *tty) { - struct file *f = NULL; + guard(spinlock)(&redirect_lock); - spin_lock(&redirect_lock); if (redirect && file_tty(redirect) == tty) { - f = redirect; + struct file *f = redirect; redirect = NULL; + return f; } - spin_unlock(&redirect_lock); - return f; + return NULL; } /** @@ -765,11 +762,8 @@ void __stop_tty(struct tty_struct *tty) */ void stop_tty(struct tty_struct *tty) { - unsigned long flags; - - spin_lock_irqsave(&tty->flow.lock, flags); + guard(spinlock_irqsave)(&tty->flow.lock); __stop_tty(tty); - spin_unlock_irqrestore(&tty->flow.lock, flags); } EXPORT_SYMBOL(stop_tty); @@ -796,11 +790,8 @@ void __start_tty(struct tty_struct *tty) */ void start_tty(struct tty_struct *tty) { - unsigned long flags; - - spin_lock_irqsave(&tty->flow.lock, flags); + guard(spinlock_irqsave)(&tty->flow.lock); __start_tty(tty); - spin_unlock_irqrestore(&tty->flow.lock, flags); } EXPORT_SYMBOL(start_tty); @@ -809,7 +800,8 @@ static void tty_update_time(struct tty_struct *tty, bool mtime) time64_t sec = ktime_get_real_seconds(); struct tty_file_private *priv; - spin_lock(&tty->files_lock); + guard(spinlock)(&tty->files_lock); + list_for_each_entry(priv, &tty->tty_files, list) { struct inode *inode = file_inode(priv->file); struct timespec64 time = mtime ? inode_get_mtime(inode) : inode_get_atime(inode); @@ -827,7 +819,6 @@ static void tty_update_time(struct tty_struct *tty, bool mtime) inode_set_atime(inode, sec, 0); } } - spin_unlock(&tty->files_lock); } /* @@ -2314,13 +2305,12 @@ static int tiocsti(struct tty_struct *tty, u8 __user *p) */ static int tiocgwinsz(struct tty_struct *tty, struct winsize __user *arg) { - int err; + guard(mutex)(&tty->winsize_mutex); - mutex_lock(&tty->winsize_mutex); - err = copy_to_user(arg, &tty->winsize, sizeof(*arg)); - mutex_unlock(&tty->winsize_mutex); + if (copy_to_user(arg, &tty->winsize, sizeof(*arg))) + return -EFAULT; - return err ? -EFAULT : 0; + return 0; } /** @@ -2335,10 +2325,10 @@ int tty_do_resize(struct tty_struct *tty, struct winsize *ws) { struct pid *pgrp; - /* Lock the tty */ - mutex_lock(&tty->winsize_mutex); + guard(mutex)(&tty->winsize_mutex); + if (!memcmp(ws, &tty->winsize, sizeof(*ws))) - goto done; + return 0; /* Signal the foreground process group */ pgrp = tty_get_pgrp(tty); @@ -2347,8 +2337,7 @@ int tty_do_resize(struct tty_struct *tty, struct winsize *ws) put_pid(pgrp); tty->winsize = *ws; -done: - mutex_unlock(&tty->winsize_mutex); + return 0; } EXPORT_SYMBOL(tty_do_resize); @@ -2409,13 +2398,14 @@ static int tioccons(struct file *file) return -EBADF; if (!(file->f_mode & FMODE_CAN_WRITE)) return -EINVAL; - spin_lock(&redirect_lock); - if (redirect) { - spin_unlock(&redirect_lock); + + guard(spinlock)(&redirect_lock); + + if (redirect) return -EBUSY; - } + redirect = get_file(file); - spin_unlock(&redirect_lock); + return 0; } @@ -3028,11 +3018,9 @@ void __do_SAK(struct tty_struct *tty) struct task_struct *g, *p; struct pid *session; int i; - unsigned long flags; - spin_lock_irqsave(&tty->ctrl.lock, flags); - session = get_pid(tty->ctrl.session); - spin_unlock_irqrestore(&tty->ctrl.lock, flags); + scoped_guard(spinlock_irqsave, &tty->ctrl.lock) + session = get_pid(tty->ctrl.session); tty_ldisc_flush(tty); @@ -3055,7 +3043,7 @@ void __do_SAK(struct tty_struct *tty) PIDTYPE_SID); continue; } - task_lock(p); + guard(task_lock)(p); i = iterate_fd(p->files, 0, this_tty, tty); if (i != 0) { tty_notice(tty, "SAK: killed process %d (%s): by fd#%d\n", @@ -3063,7 +3051,6 @@ void __do_SAK(struct tty_struct *tty) group_send_sig_info(SIGKILL, SEND_SIG_PRIV, p, PIDTYPE_SID); } - task_unlock(p); } read_unlock(&tasklist_lock); put_pid(session); @@ -3465,9 +3452,8 @@ int tty_register_driver(struct tty_driver *driver) goto err_unreg_char; } - mutex_lock(&tty_mutex); - list_add(&driver->tty_drivers, &tty_drivers); - mutex_unlock(&tty_mutex); + scoped_guard(mutex, &tty_mutex) + list_add(&driver->tty_drivers, &tty_drivers); if (!(driver->flags & TTY_DRIVER_DYNAMIC_DEV)) { for (i = 0; i < driver->num; i++) { @@ -3486,9 +3472,8 @@ err_unreg_devs: for (i--; i >= 0; i--) tty_unregister_device(driver, i); - mutex_lock(&tty_mutex); - list_del(&driver->tty_drivers); - mutex_unlock(&tty_mutex); + scoped_guard(mutex, &tty_mutex) + list_del(&driver->tty_drivers); err_unreg_char: unregister_chrdev_region(dev, driver->num); @@ -3507,9 +3492,8 @@ void tty_unregister_driver(struct tty_driver *driver) { unregister_chrdev_region(MKDEV(driver->major, driver->minor_start), driver->num); - mutex_lock(&tty_mutex); - list_del(&driver->tty_drivers); - mutex_unlock(&tty_mutex); + scoped_guard(mutex, &tty_mutex) + list_del(&driver->tty_drivers); } EXPORT_SYMBOL(tty_unregister_driver); diff --git a/drivers/tty/tty_ioctl.c b/drivers/tty/tty_ioctl.c index 85de90eebc7b..90c70d8d14e3 100644 --- a/drivers/tty/tty_ioctl.c +++ b/drivers/tty/tty_ioctl.c @@ -122,21 +122,19 @@ EXPORT_SYMBOL(tty_unthrottle); */ bool tty_throttle_safe(struct tty_struct *tty) { - bool ret = true; - - mutex_lock(&tty->throttle_mutex); - if (!tty_throttled(tty)) { - if (tty->flow_change != TTY_THROTTLE_SAFE) - ret = false; - else { - set_bit(TTY_THROTTLED, &tty->flags); - if (tty->ops->throttle) - tty->ops->throttle(tty); - } - } - mutex_unlock(&tty->throttle_mutex); + guard(mutex)(&tty->throttle_mutex); - return ret; + if (tty_throttled(tty)) + return true; + + if (tty->flow_change != TTY_THROTTLE_SAFE) + return false; + + set_bit(TTY_THROTTLED, &tty->flags); + if (tty->ops->throttle) + tty->ops->throttle(tty); + + return true; } /** @@ -152,21 +150,19 @@ bool tty_throttle_safe(struct tty_struct *tty) */ bool tty_unthrottle_safe(struct tty_struct *tty) { - bool ret = true; + guard(mutex)(&tty->throttle_mutex); - mutex_lock(&tty->throttle_mutex); - if (tty_throttled(tty)) { - if (tty->flow_change != TTY_UNTHROTTLE_SAFE) - ret = false; - else { - clear_bit(TTY_THROTTLED, &tty->flags); - if (tty->ops->unthrottle) - tty->ops->unthrottle(tty); - } - } - mutex_unlock(&tty->throttle_mutex); + if (!tty_throttled(tty)) + return true; - return ret; + if (tty->flow_change != TTY_UNTHROTTLE_SAFE) + return false; + + clear_bit(TTY_THROTTLED, &tty->flags); + if (tty->ops->unthrottle) + tty->ops->unthrottle(tty); + + return true; } /** diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c index 14cca33d2269..4af1fbf73f51 100644 --- a/drivers/tty/tty_port.c +++ b/drivers/tty/tty_port.c @@ -200,26 +200,6 @@ struct device *tty_port_register_device_attr_serdev(struct tty_port *port, EXPORT_SYMBOL_GPL(tty_port_register_device_attr_serdev); /** - * tty_port_register_device_serdev - register tty or serdev device - * @port: tty_port of the device - * @driver: tty_driver for this device - * @index: index of the tty - * @host: serial port hardware controller device - * @parent: parent if exists, otherwise NULL - * - * Register a serdev or tty device depending on if the parent device has any - * defined serdev clients or not. - */ -struct device *tty_port_register_device_serdev(struct tty_port *port, - struct tty_driver *driver, unsigned index, - struct device *host, struct device *parent) -{ - return tty_port_register_device_attr_serdev(port, driver, index, - host, parent, NULL, NULL); -} -EXPORT_SYMBOL_GPL(tty_port_register_device_serdev); - -/** * tty_port_unregister_device - deregister a tty or serdev device * @port: tty_port of the device * @driver: tty_driver for this device diff --git a/drivers/tty/vcc.c b/drivers/tty/vcc.c index 7ac3048377d5..2960031ace72 100644 --- a/drivers/tty/vcc.c +++ b/drivers/tty/vcc.c @@ -356,7 +356,7 @@ done: static void vcc_rx_timer(struct timer_list *t) { - struct vcc_port *port = from_timer(port, t, rx_timer); + struct vcc_port *port = timer_container_of(port, t, rx_timer); struct vio_driver_state *vio; unsigned long flags; int rv; @@ -382,7 +382,7 @@ done: static void vcc_tx_timer(struct timer_list *t) { - struct vcc_port *port = from_timer(port, t, tx_timer); + struct vcc_port *port = timer_container_of(port, t, tx_timer); struct vio_vcc *pkt; unsigned long flags; size_t tosend = 0; diff --git a/drivers/tty/vt/.gitignore b/drivers/tty/vt/.gitignore index 0221709b177d..a74859bab862 100644 --- a/drivers/tty/vt/.gitignore +++ b/drivers/tty/vt/.gitignore @@ -2,3 +2,6 @@ /conmakehash /consolemap_deftbl.c /defkeymap.c +/ucs_fallback_table.h +/ucs_recompose_table.h +/ucs_width_table.h diff --git a/drivers/tty/vt/Makefile b/drivers/tty/vt/Makefile index 2c8ce8b592ed..ae746dcdeec8 100644 --- a/drivers/tty/vt/Makefile +++ b/drivers/tty/vt/Makefile @@ -7,10 +7,12 @@ FONTMAPFILE = cp437.uni obj-$(CONFIG_VT) += vt_ioctl.o vc_screen.o \ selection.o keyboard.o \ vt.o defkeymap.o -obj-$(CONFIG_CONSOLE_TRANSLATIONS) += consolemap.o consolemap_deftbl.o +obj-$(CONFIG_CONSOLE_TRANSLATIONS) += consolemap.o consolemap_deftbl.o \ + ucs.o # Files generated that shall be removed upon make clean -clean-files := consolemap_deftbl.c defkeymap.c +clean-files := consolemap_deftbl.c defkeymap.c \ + ucs_width_table.h ucs_recompose_table.h ucs_fallback_table.h hostprogs += conmakehash @@ -33,3 +35,31 @@ $(obj)/defkeymap.c: $(obj)/%.c: $(src)/%.map loadkeys --mktable --unicode $< > $@ endif + +$(obj)/ucs.o: $(src)/ucs.c $(obj)/ucs_width_table.h \ + $(obj)/ucs_recompose_table.h $(obj)/ucs_fallback_table.h + +# You may uncomment one of those to have the UCS tables be regenerated +# during the build process. By default the _shipped versions are used. +# +#GENERATE_UCS_TABLES := 1 +#GENERATE_UCS_TABLES := 2 # invokes gen_ucs_recompose_table.py with --full + +ifdef GENERATE_UCS_TABLES + +$(obj)/ucs_width_table.h: $(src)/gen_ucs_width_table.py + $(PYTHON3) $< -o $@ + +ifeq ($(GENERATE_UCS_TABLES),2) +gen_recomp_arg := --full +else +gen_recomp_arg := +endif + +$(obj)/ucs_recompose_table.h: $(src)/gen_ucs_recompose_table.py + $(PYTHON3) $< -o $@ $(gen_recomp_arg) + +$(obj)/ucs_fallback_table.h: $(src)/gen_ucs_fallback_table.py + $(PYTHON3) $< -o $@ + +endif diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c index 82d70083fead..bb4bb272ebec 100644 --- a/drivers/tty/vt/consolemap.c +++ b/drivers/tty/vt/consolemap.c @@ -870,8 +870,6 @@ int conv_uni_to_pc(struct vc_data *conp, long ucs) return -4; /* Not found */ else if (ucs < 0x20) return -1; /* Not a printable character */ - else if (ucs == 0xfeff || (ucs >= 0x200b && ucs <= 0x200f)) - return -2; /* Zero-width space */ /* * UNI_DIRECT_BASE indicates the start of the region in the User Zone * which always has a 1:1 mapping to the currently loaded font. The diff --git a/drivers/tty/vt/gen_ucs_fallback_table.py b/drivers/tty/vt/gen_ucs_fallback_table.py new file mode 100755 index 000000000000..6e09c1cb6d4b --- /dev/null +++ b/drivers/tty/vt/gen_ucs_fallback_table.py @@ -0,0 +1,360 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: GPL-2.0 +# +# Leverage Python's unidecode module to generate ucs_fallback_table.h +# +# The generated table maps complex characters to their simpler fallback forms +# for a terminal display when corresponding glyphs are unavailable. +# +# Usage: +# python3 gen_ucs_fallback_table.py # Generate fallback tables +# python3 gen_ucs_fallback_table.py -o FILE # Specify output file + +import unicodedata +from unidecode import unidecode +import sys +import argparse +from collections import defaultdict + +# Try to get unidecode version +try: + from importlib.metadata import version + unidecode_version = version('unidecode') +except: + unidecode_version = 'unknown' + +# This script's file name +from pathlib import Path +this_file = Path(__file__).name + +# Default output file name +DEFAULT_OUT_FILE = "ucs_fallback_table.h" + +# Define the range marker value +RANGE_MARKER = 0x00 + +def generate_fallback_map(): + """Generate a fallback map using unidecode for all relevant Unicode points.""" + fallback_map = {} + + # Process BMP characters (0x0000 - 0xFFFF) to keep table size manageable + for cp in range(0x0080, 0x10000): # Skip ASCII range (0x00-0x7F) + char = chr(cp) + + # Skip unassigned/control characters + try: + if not unicodedata.name(char, ''): + continue + except ValueError: + continue + + # Get the unidecode transliteration + ascii_version = unidecode(char) + + # Only store if it results in a single character mapping + if len(ascii_version) == 1: + fallback_map[cp] = ord(ascii_version) + + # Apply manual overrides for special cases + fallback_map.update(get_special_overrides()) + + return fallback_map + +def get_special_overrides(): + """Get special case overrides that need different handling than unidecode + provides... or doesn't provide at all.""" + + overrides = {} + + # Multi-character unidecode output + # These map to single chars instead of unidecode's multiple-char mappings + # In a terminal fallback context, we need a single character rather than multiple + overrides[0x00C6] = ord('E') # Æ LATIN CAPITAL LETTER AE -> E (unidecode: "AE") + overrides[0x00E6] = ord('e') # æ LATIN SMALL LETTER AE -> e (unidecode: "ae") + overrides[0x0152] = ord('E') # Å’ LATIN CAPITAL LIGATURE OE -> E (unidecode: "OE") + overrides[0x0153] = ord('e') # Å“ LATIN SMALL LETTER LIGATURE OE -> e (unidecode: "oe") + overrides[0x00DF] = ord('s') # ß LATIN SMALL LETTER SHARP S -> s (unidecode: "ss") + + # Comparison operators that unidecode renders as multiple characters + overrides[0x2264] = ord('<') # ≤ LESS-THAN OR EQUAL TO -> < (unidecode: "<=") + overrides[0x2265] = ord('>') # ≥ GREATER-THAN OR EQUAL TO -> > (unidecode: ">=") + + # Unidecode returns an empty string for these + overrides[0x2260] = ord('#') # ≠NOT EQUAL TO -> # (unidecode: empty string) + + # Quadrant block characters that unidecode doesn't map + for cp in range(0x2596, 0x259F+1): + overrides[cp] = ord('#') # â–– â–— â–˜ â–™ etc. - map to # (unidecode: empty string) + + # Directional arrows + # These provide better semantic meaning than unidecode's mappings + overrides[0x2192] = ord('>') # → RIGHTWARDS ARROW -> > (unidecode: "-") + overrides[0x2190] = ord('<') # ↠LEFTWARDS ARROW -> < (unidecode: "-") + overrides[0x2191] = ord('^') # ↑ UPWARDS ARROW -> ^ (unidecode: "|") + overrides[0x2193] = ord('v') # ↓ DOWNWARDS ARROW -> v (unidecode: "|") + + # Double arrows with their directional semantic mappings + overrides[0x21D0] = ord('<') # ⇠LEFTWARDS DOUBLE ARROW -> < + overrides[0x21D1] = ord('^') # ⇑ UPWARDS DOUBLE ARROW -> ^ + overrides[0x21D2] = ord('>') # ⇒ RIGHTWARDS DOUBLE ARROW -> > + overrides[0x21D3] = ord('v') # ⇓ DOWNWARDS DOUBLE ARROW -> v + + # Halfwidth arrows + # These need the same treatment as their normal-width counterparts + overrides[0xFFE9] = ord('<') # ï¿© HALFWIDTH LEFTWARDS ARROW -> < (unidecode: "-") + overrides[0xFFEA] = ord('^') # ↑ HALFWIDTH UPWARDS ARROW -> ^ (unidecode: "|") + overrides[0xFFEB] = ord('>') # ï¿« HALFWIDTH RIGHTWARDS ARROW -> > (unidecode: "-") + overrides[0xFFEC] = ord('v') # ↓ HALFWIDTH DOWNWARDS ARROW -> v (unidecode: "|") + + # Currency symbols - each mapped to a representative letter + overrides[0x00A2] = ord('c') # ¢ CENT SIGN -> c + overrides[0x00A3] = ord('L') # £ POUND SIGN -> L + overrides[0x00A5] = ord('Y') # Â¥ YEN SIGN -> Y + overrides[0x20AC] = ord('E') # € EURO SIGN -> E + + # Symbols mapped to letters + overrides[0x00A7] = ord('S') # § SECTION SIGN -> S + overrides[0x00A9] = ord('C') # © COPYRIGHT SIGN -> C + overrides[0x00AE] = ord('R') # ® REGISTERED SIGN -> R + overrides[0x2122] = ord('T') # â„¢ TRADE MARK SIGN -> T + + # Degree-related symbols + overrides[0x00B0] = ord('o') # ° DEGREE SIGN -> o + overrides[0x2103] = ord('C') # ℃ DEGREE CELSIUS -> C + overrides[0x2109] = ord('F') # ℉ DEGREE FAHRENHEIT -> F + + # Angle quotation marks + overrides[0x00AB] = ord('<') # « LEFT-POINTING DOUBLE ANGLE QUOTATION MARK -> < + overrides[0x00BB] = ord('>') # » RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK -> > + + # Operators with circular shape + overrides[0x2218] = ord('o') # ∘ RING OPERATOR -> o + overrides[0x2219] = ord('.') # ∙ BULLET OPERATOR -> . + + # Negated mathematical symbols (preserving the negation semantics) + # Negated symbols mapped to exclamation mark (semantically "not") + for cp in (0x2204, 0x2209, 0x220C, 0x2224, 0x2226, 0x226E, 0x226F, 0x2280, 0x2281, 0x2284, 0x2285): + overrides[cp] = ord('!') # Negated math symbols -> ! (not) + + # Negated symbols mapped to hash sign (semantically "not equal") + for cp in (0x2241, 0x2244, 0x2249, 0x2262, 0x2268, 0x2269, 0x226D, 0x228A, 0x228B): + overrides[cp] = ord('#') # Negated equality symbols -> # (not equal) + + # Negated arrows - all mapped to exclamation mark + for cp in (0x219A, 0x219B, 0x21AE, 0x21CD, 0x21CE, 0x21CF): + overrides[cp] = ord('!') # Negated arrows -> ! (not) + + # Dashes and hyphens + for cp in (0x2010, 0x2011, 0x2012, 0x2013, 0x2014, 0x2015, 0x2043, 0x2052): + overrides[cp] = ord('-') # Dashes and hyphens -> - + + # Question mark punctuation + for cp in (0x203D, 0x2047, 0x2048): + overrides[cp] = ord('?') # Question marks -> ? + + # Exclamation mark punctuation + for cp in (0x203C, 0x2049): + overrides[cp] = ord('!') # Exclamation marks -> ! + + # Asterisk-like symbols + for cp in (0x2042, 0x2051, 0x2055): + overrides[cp] = ord('*') + + # Other specific punctuation with unique mappings + overrides[0x201E] = ord('"') # „ DOUBLE LOW-9 QUOTATION MARK + overrides[0x2023] = ord('>') # ‣ TRIANGULAR BULLET + overrides[0x2026] = ord('.') # … HORIZONTAL ELLIPSIS + overrides[0x2033] = ord('"') # ″ DOUBLE PRIME + overrides[0x204B] = ord('P') # â‹ REVERSED PILCROW SIGN + overrides[0x204C] = ord('<') # ⌠BLACK LEFTWARDS BULLET + overrides[0x204D] = ord('>') # â BLACK RIGHTWARDS BULLET + overrides[0x204F] = ord(';') # â REVERSED SEMICOLON + overrides[0x205B] = ord(':') # â› FOUR DOT MARK + + # Check marks + overrides[0x2713] = ord('v') # ✓ CHECK MARK + overrides[0x2714] = ord('V') # ✔ HEAVY CHECK MARK + + # X marks - lowercase for regular, uppercase for heavy + for cp in (0x2715, 0x2717): + overrides[cp] = ord('x') # Regular X marks -> x + for cp in (0x2716, 0x2718): + overrides[cp] = ord('X') # Heavy X marks -> X + + # Stars and asterisk-like symbols mapped to '*' + for cp in (0x2605, 0x2606, 0x262A, 0x269D, 0x2698): + overrides[cp] = ord('*') # All star and asterisk symbols -> * + for cp in range(0x2721, 0x2746+1): + overrides[cp] = ord('*') # All star and asterisk symbols -> * + for cp in range(0x2749, 0x274B+1): + overrides[cp] = ord('*') # Last set of asterisk symbols -> * + for cp in (0x229B, 0x22C6, 0x235F, 0x2363): + overrides[cp] = ord('*') # Star operators -> * + + # Special exclusions with fallback value of 0 + # These will be filtered out in organize_by_pages() + + # Exclude U+2028 (LINE SEPARATOR) + overrides[0x2028] = 0 # LINE SEPARATOR (unidecode: '\n') + + # Full-width to ASCII mapping (covering all printable ASCII 33-126) + # 0xFF01 (ï¼) to 0xFF5E (~) -> ASCII 33 (!) to 126 (~) + # Those are excluded here to reduce the table size. + # It is more efficient to process them programmatically in + # ucs.c:ucs_get_fallback(). + for cp in range(0xFF01, 0xFF5E + 1): + overrides[cp] = 0 # Double-width ASCII characters + + return overrides + +def organize_by_pages(fallback_map): + """Organize the fallback mappings by their high byte (page).""" + # Group by high byte (page) + page_groups = defaultdict(list) + for code, fallback in fallback_map.items(): + # Skip characters with fallback value of 0 (excluded characters) + if fallback == 0: + continue + + page = code >> 8 # Get the high byte (page) + offset = code & 0xFF # Get the low byte (offset within page) + page_groups[page].append((offset, fallback)) + + # Sort each page's entries by offset + for page in page_groups: + page_groups[page].sort() + + return page_groups + +def compress_ranges(page_groups): + """Compress consecutive entries with the same fallback character into ranges. + A range is only compressed if it contains 3 or more consecutive entries.""" + + compressed_pages = {} + + for page, entries in page_groups.items(): + compressed_entries = [] + i = 0 + while i < len(entries): + start_offset, fallback = entries[i] + + # Look ahead to find consecutive entries with the same fallback + j = i + 1 + while (j < len(entries) and + entries[j][0] == entries[j-1][0] + 1 and # consecutive offsets + entries[j][1] == fallback): # same fallback + j += 1 + + # Calculate the range end + end_offset = entries[j-1][0] + + # If we found a range with 3 or more entries (worth compressing) + if j - i >= 3: + # Add a range entry + compressed_entries.append((start_offset, RANGE_MARKER)) + compressed_entries.append((end_offset, fallback)) + else: + # Add the individual entries as is + for k in range(i, j): + compressed_entries.append(entries[k]) + + i = j + + compressed_pages[page] = compressed_entries + + return compressed_pages + +def cp_name(cp): + """Get the Unicode character name for a code point.""" + try: + return unicodedata.name(chr(cp)) + except: + return f"U+{cp:04X}" + +def generate_fallback_tables(out_file=DEFAULT_OUT_FILE): + """Generate the fallback character tables.""" + # Generate fallback map using unidecode + fallback_map = generate_fallback_map() + print(f"Generated {len(fallback_map)} total fallback mappings") + + # Organize by pages + page_groups = organize_by_pages(fallback_map) + print(f"Organized into {len(page_groups)} pages") + + # Compress ranges + compressed_pages = compress_ranges(page_groups) + total_compressed_entries = sum(len(entries) for entries in compressed_pages.values()) + print(f"Total compressed entries: {total_compressed_entries}") + + # Create output file + with open(out_file, 'w') as f: + f.write(f"""\ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * {out_file} - Unicode character fallback table + * + * Auto-generated by {this_file} + * + * Unicode Version: {unicodedata.unidata_version} + * Unidecode Version: {unidecode_version} + * + * This file contains optimized tables that map complex Unicode characters + * to simpler fallback characters for terminal display when corresponding + * glyphs are unavailable. + */ + +static const struct ucs_page_desc ucs_fallback_pages[] = {{ +""") + + # Convert compressed_pages to a sorted list of (page, entries) tuples + sorted_pages = sorted(compressed_pages.items()) + + # Track the start index for each page + start_index = 0 + + # Write page descriptors + for page, entries in sorted_pages: + count = len(entries) + f.write(f"\t{{ 0x{page:02X}, {count}, {start_index} }},\n") + start_index += count + + # Write entries array + f.write("""\ +}; + +/* Page entries array (referenced by page descriptors) */ +static const struct ucs_page_entry ucs_fallback_entries[] = { +""") + + # Write all entries + for page, entries in sorted_pages: + page_hex = f"0x{page:02X}" + f.write(f"\t/* Entries for page {page_hex} */\n") + + for i, (offset, fallback) in enumerate(entries): + # Convert to hex for better readability + offset_hex = f"0x{offset:02X}" + fallback_hex = f"0x{fallback:02X}" + + # Handle comments + codepoint = (page << 8) | offset + + if fallback == RANGE_MARKER: + comment = f"{cp_name(codepoint)} -> ..." + else: + comment = f"{cp_name(codepoint)} -> '{chr(fallback)}'" + f.write(f"\t{{ 0x{offset:02X}, 0x{fallback:02X} }}, /* {comment} */\n") + + f.write(f"""\ +}}; + +#define UCS_PAGE_ENTRY_RANGE_MARKER {RANGE_MARKER} +""") + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="Generate Unicode fallback character tables") + parser.add_argument("-o", "--output", dest="output_file", default=DEFAULT_OUT_FILE, + help=f"Output file name (default: {DEFAULT_OUT_FILE})") + args = parser.parse_args() + + generate_fallback_tables(out_file=args.output_file) diff --git a/drivers/tty/vt/gen_ucs_recompose_table.py b/drivers/tty/vt/gen_ucs_recompose_table.py new file mode 100755 index 000000000000..4434a436ac9e --- /dev/null +++ b/drivers/tty/vt/gen_ucs_recompose_table.py @@ -0,0 +1,257 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: GPL-2.0 +# +# Leverage Python's unicodedata module to generate ucs_recompose_table.h +# +# The generated table maps base character + combining mark pairs to their +# precomposed equivalents. +# +# Usage: +# python3 gen_ucs_recompose_table.py # Generate with common recomposition pairs +# python3 gen_ucs_recompose_table.py --full # Generate with all recomposition pairs + +import unicodedata +import sys +import argparse +import textwrap + +# This script's file name +from pathlib import Path +this_file = Path(__file__).name + +# Default output file name +DEFAULT_OUT_FILE = "ucs_recompose_table.h" + +common_recompose_description = "most commonly used Latin, Greek, and Cyrillic recomposition pairs only" +COMMON_RECOMPOSITION_PAIRS = [ + # Latin letters with accents - uppercase + (0x0041, 0x0300, 0x00C0), # A + COMBINING GRAVE ACCENT = LATIN CAPITAL LETTER A WITH GRAVE + (0x0041, 0x0301, 0x00C1), # A + COMBINING ACUTE ACCENT = LATIN CAPITAL LETTER A WITH ACUTE + (0x0041, 0x0302, 0x00C2), # A + COMBINING CIRCUMFLEX ACCENT = LATIN CAPITAL LETTER A WITH CIRCUMFLEX + (0x0041, 0x0303, 0x00C3), # A + COMBINING TILDE = LATIN CAPITAL LETTER A WITH TILDE + (0x0041, 0x0308, 0x00C4), # A + COMBINING DIAERESIS = LATIN CAPITAL LETTER A WITH DIAERESIS + (0x0041, 0x030A, 0x00C5), # A + COMBINING RING ABOVE = LATIN CAPITAL LETTER A WITH RING ABOVE + (0x0043, 0x0327, 0x00C7), # C + COMBINING CEDILLA = LATIN CAPITAL LETTER C WITH CEDILLA + (0x0045, 0x0300, 0x00C8), # E + COMBINING GRAVE ACCENT = LATIN CAPITAL LETTER E WITH GRAVE + (0x0045, 0x0301, 0x00C9), # E + COMBINING ACUTE ACCENT = LATIN CAPITAL LETTER E WITH ACUTE + (0x0045, 0x0302, 0x00CA), # E + COMBINING CIRCUMFLEX ACCENT = LATIN CAPITAL LETTER E WITH CIRCUMFLEX + (0x0045, 0x0308, 0x00CB), # E + COMBINING DIAERESIS = LATIN CAPITAL LETTER E WITH DIAERESIS + (0x0049, 0x0300, 0x00CC), # I + COMBINING GRAVE ACCENT = LATIN CAPITAL LETTER I WITH GRAVE + (0x0049, 0x0301, 0x00CD), # I + COMBINING ACUTE ACCENT = LATIN CAPITAL LETTER I WITH ACUTE + (0x0049, 0x0302, 0x00CE), # I + COMBINING CIRCUMFLEX ACCENT = LATIN CAPITAL LETTER I WITH CIRCUMFLEX + (0x0049, 0x0308, 0x00CF), # I + COMBINING DIAERESIS = LATIN CAPITAL LETTER I WITH DIAERESIS + (0x004E, 0x0303, 0x00D1), # N + COMBINING TILDE = LATIN CAPITAL LETTER N WITH TILDE + (0x004F, 0x0300, 0x00D2), # O + COMBINING GRAVE ACCENT = LATIN CAPITAL LETTER O WITH GRAVE + (0x004F, 0x0301, 0x00D3), # O + COMBINING ACUTE ACCENT = LATIN CAPITAL LETTER O WITH ACUTE + (0x004F, 0x0302, 0x00D4), # O + COMBINING CIRCUMFLEX ACCENT = LATIN CAPITAL LETTER O WITH CIRCUMFLEX + (0x004F, 0x0303, 0x00D5), # O + COMBINING TILDE = LATIN CAPITAL LETTER O WITH TILDE + (0x004F, 0x0308, 0x00D6), # O + COMBINING DIAERESIS = LATIN CAPITAL LETTER O WITH DIAERESIS + (0x0055, 0x0300, 0x00D9), # U + COMBINING GRAVE ACCENT = LATIN CAPITAL LETTER U WITH GRAVE + (0x0055, 0x0301, 0x00DA), # U + COMBINING ACUTE ACCENT = LATIN CAPITAL LETTER U WITH ACUTE + (0x0055, 0x0302, 0x00DB), # U + COMBINING CIRCUMFLEX ACCENT = LATIN CAPITAL LETTER U WITH CIRCUMFLEX + (0x0055, 0x0308, 0x00DC), # U + COMBINING DIAERESIS = LATIN CAPITAL LETTER U WITH DIAERESIS + (0x0059, 0x0301, 0x00DD), # Y + COMBINING ACUTE ACCENT = LATIN CAPITAL LETTER Y WITH ACUTE + + # Latin letters with accents - lowercase + (0x0061, 0x0300, 0x00E0), # a + COMBINING GRAVE ACCENT = LATIN SMALL LETTER A WITH GRAVE + (0x0061, 0x0301, 0x00E1), # a + COMBINING ACUTE ACCENT = LATIN SMALL LETTER A WITH ACUTE + (0x0061, 0x0302, 0x00E2), # a + COMBINING CIRCUMFLEX ACCENT = LATIN SMALL LETTER A WITH CIRCUMFLEX + (0x0061, 0x0303, 0x00E3), # a + COMBINING TILDE = LATIN SMALL LETTER A WITH TILDE + (0x0061, 0x0308, 0x00E4), # a + COMBINING DIAERESIS = LATIN SMALL LETTER A WITH DIAERESIS + (0x0061, 0x030A, 0x00E5), # a + COMBINING RING ABOVE = LATIN SMALL LETTER A WITH RING ABOVE + (0x0063, 0x0327, 0x00E7), # c + COMBINING CEDILLA = LATIN SMALL LETTER C WITH CEDILLA + (0x0065, 0x0300, 0x00E8), # e + COMBINING GRAVE ACCENT = LATIN SMALL LETTER E WITH GRAVE + (0x0065, 0x0301, 0x00E9), # e + COMBINING ACUTE ACCENT = LATIN SMALL LETTER E WITH ACUTE + (0x0065, 0x0302, 0x00EA), # e + COMBINING CIRCUMFLEX ACCENT = LATIN SMALL LETTER E WITH CIRCUMFLEX + (0x0065, 0x0308, 0x00EB), # e + COMBINING DIAERESIS = LATIN SMALL LETTER E WITH DIAERESIS + (0x0069, 0x0300, 0x00EC), # i + COMBINING GRAVE ACCENT = LATIN SMALL LETTER I WITH GRAVE + (0x0069, 0x0301, 0x00ED), # i + COMBINING ACUTE ACCENT = LATIN SMALL LETTER I WITH ACUTE + (0x0069, 0x0302, 0x00EE), # i + COMBINING CIRCUMFLEX ACCENT = LATIN SMALL LETTER I WITH CIRCUMFLEX + (0x0069, 0x0308, 0x00EF), # i + COMBINING DIAERESIS = LATIN SMALL LETTER I WITH DIAERESIS + (0x006E, 0x0303, 0x00F1), # n + COMBINING TILDE = LATIN SMALL LETTER N WITH TILDE + (0x006F, 0x0300, 0x00F2), # o + COMBINING GRAVE ACCENT = LATIN SMALL LETTER O WITH GRAVE + (0x006F, 0x0301, 0x00F3), # o + COMBINING ACUTE ACCENT = LATIN SMALL LETTER O WITH ACUTE + (0x006F, 0x0302, 0x00F4), # o + COMBINING CIRCUMFLEX ACCENT = LATIN SMALL LETTER O WITH CIRCUMFLEX + (0x006F, 0x0303, 0x00F5), # o + COMBINING TILDE = LATIN SMALL LETTER O WITH TILDE + (0x006F, 0x0308, 0x00F6), # o + COMBINING DIAERESIS = LATIN SMALL LETTER O WITH DIAERESIS + (0x0075, 0x0300, 0x00F9), # u + COMBINING GRAVE ACCENT = LATIN SMALL LETTER U WITH GRAVE + (0x0075, 0x0301, 0x00FA), # u + COMBINING ACUTE ACCENT = LATIN SMALL LETTER U WITH ACUTE + (0x0075, 0x0302, 0x00FB), # u + COMBINING CIRCUMFLEX ACCENT = LATIN SMALL LETTER U WITH CIRCUMFLEX + (0x0075, 0x0308, 0x00FC), # u + COMBINING DIAERESIS = LATIN SMALL LETTER U WITH DIAERESIS + (0x0079, 0x0301, 0x00FD), # y + COMBINING ACUTE ACCENT = LATIN SMALL LETTER Y WITH ACUTE + (0x0079, 0x0308, 0x00FF), # y + COMBINING DIAERESIS = LATIN SMALL LETTER Y WITH DIAERESIS + + # Common Greek characters + (0x0391, 0x0301, 0x0386), # Α + COMBINING ACUTE ACCENT = GREEK CAPITAL LETTER ALPHA WITH TONOS + (0x0395, 0x0301, 0x0388), # Ε + COMBINING ACUTE ACCENT = GREEK CAPITAL LETTER EPSILON WITH TONOS + (0x0397, 0x0301, 0x0389), # Η + COMBINING ACUTE ACCENT = GREEK CAPITAL LETTER ETA WITH TONOS + (0x0399, 0x0301, 0x038A), # Ι + COMBINING ACUTE ACCENT = GREEK CAPITAL LETTER IOTA WITH TONOS + (0x039F, 0x0301, 0x038C), # Ο + COMBINING ACUTE ACCENT = GREEK CAPITAL LETTER OMICRON WITH TONOS + (0x03A5, 0x0301, 0x038E), # Î¥ + COMBINING ACUTE ACCENT = GREEK CAPITAL LETTER UPSILON WITH TONOS + (0x03A9, 0x0301, 0x038F), # Ω + COMBINING ACUTE ACCENT = GREEK CAPITAL LETTER OMEGA WITH TONOS + (0x03B1, 0x0301, 0x03AC), # α + COMBINING ACUTE ACCENT = GREEK SMALL LETTER ALPHA WITH TONOS + (0x03B5, 0x0301, 0x03AD), # ε + COMBINING ACUTE ACCENT = GREEK SMALL LETTER EPSILON WITH TONOS + (0x03B7, 0x0301, 0x03AE), # η + COMBINING ACUTE ACCENT = GREEK SMALL LETTER ETA WITH TONOS + (0x03B9, 0x0301, 0x03AF), # ι + COMBINING ACUTE ACCENT = GREEK SMALL LETTER IOTA WITH TONOS + (0x03BF, 0x0301, 0x03CC), # ο + COMBINING ACUTE ACCENT = GREEK SMALL LETTER OMICRON WITH TONOS + (0x03C5, 0x0301, 0x03CD), # Ï… + COMBINING ACUTE ACCENT = GREEK SMALL LETTER UPSILON WITH TONOS + (0x03C9, 0x0301, 0x03CE), # ω + COMBINING ACUTE ACCENT = GREEK SMALL LETTER OMEGA WITH TONOS + + # Common Cyrillic characters + (0x0418, 0x0306, 0x0419), # И + COMBINING BREVE = CYRILLIC CAPITAL LETTER SHORT I + (0x0438, 0x0306, 0x0439), # и + COMBINING BREVE = CYRILLIC SMALL LETTER SHORT I + (0x0423, 0x0306, 0x040E), # У + COMBINING BREVE = CYRILLIC CAPITAL LETTER SHORT U + (0x0443, 0x0306, 0x045E), # у + COMBINING BREVE = CYRILLIC SMALL LETTER SHORT U +] + +full_recompose_description = "all possible recomposition pairs from the Unicode BMP" +def collect_all_recomposition_pairs(): + """Collect all possible recomposition pairs from the Unicode data.""" + # Map to store recomposition pairs: (base, combining) -> recomposed + recompose_map = {} + + # Process all assigned Unicode code points in BMP (Basic Multilingual Plane) + # We limit to BMP (0x0000-0xFFFF) to keep our table smaller with uint16_t + for cp in range(0, 0x10000): + try: + char = chr(cp) + + # Skip unassigned or control characters + if not unicodedata.name(char, ''): + continue + + # Find decomposition + decomp = unicodedata.decomposition(char) + if not decomp or '<' in decomp: # Skip compatibility decompositions + continue + + # Parse the decomposition + parts = decomp.split() + if len(parts) == 2: # Simple base + combining mark + base = int(parts[0], 16) + combining = int(parts[1], 16) + + # Only store if both are in BMP + if base < 0x10000 and combining < 0x10000: + recompose_map[(base, combining)] = cp + + except (ValueError, TypeError): + continue + + # Convert to a list of tuples and sort for binary search + recompose_list = [(base, combining, recomposed) + for (base, combining), recomposed in recompose_map.items()] + recompose_list.sort() + + return recompose_list + +def validate_common_pairs(full_list): + """Validate that all common pairs are in the full list. + + Raises: + ValueError: If any common pair is missing or has a different recomposition + value than what's in the full table. + """ + full_pairs = {(base, combining): recomposed for base, combining, recomposed in full_list} + for base, combining, recomposed in COMMON_RECOMPOSITION_PAIRS: + full_recomposed = full_pairs.get((base, combining)) + if full_recomposed is None: + error_msg = f"Error: Common pair (0x{base:04X}, 0x{combining:04X}) not found in full data" + print(error_msg) + raise ValueError(error_msg) + elif full_recomposed != recomposed: + error_msg = (f"Error: Common pair (0x{base:04X}, 0x{combining:04X}) has different recomposition: " + f"0x{recomposed:04X} vs 0x{full_recomposed:04X}") + print(error_msg) + raise ValueError(error_msg) + +def generate_recomposition_table(use_full_list=False, out_file=DEFAULT_OUT_FILE): + """Generate the recomposition C table.""" + + # Collect all recomposition pairs for validation + full_recompose_list = collect_all_recomposition_pairs() + + # Decide which list to use + if use_full_list: + print("Using full recomposition list...") + recompose_list = full_recompose_list + table_description = full_recompose_description + alt_list = COMMON_RECOMPOSITION_PAIRS + alt_description = common_recompose_description + else: + print("Using common recomposition list...") + # Validate that all common pairs are in the full list + validate_common_pairs(full_recompose_list) + recompose_list = sorted(COMMON_RECOMPOSITION_PAIRS) + table_description = common_recompose_description + alt_list = full_recompose_list + alt_description = full_recompose_description + generation_mode = " --full" if use_full_list else "" + alternative_mode = " --full" if not use_full_list else "" + table_description_detail = f"{table_description} ({len(recompose_list)} entries)" + alt_description_detail = f"{alt_description} ({len(alt_list)} entries)" + + # Calculate min/max values for boundary checks + min_base = min(base for base, _, _ in recompose_list) + max_base = max(base for base, _, _ in recompose_list) + min_combining = min(combining for _, combining, _ in recompose_list) + max_combining = max(combining for _, combining, _ in recompose_list) + + # Generate implementation file + with open(out_file, 'w') as f: + f.write(f"""\ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * {out_file} - Unicode character recomposition + * + * Auto-generated by {this_file}{generation_mode} + * + * Unicode Version: {unicodedata.unidata_version} + * +{textwrap.fill( + f"This file contains a table with {table_description_detail}. " + + f"To generate a table with {alt_description_detail} instead, run:", + width=75, initial_indent=" * ", subsequent_indent=" * ")} + * + * python3 {this_file}{alternative_mode} + */ + +/* + * Table of {table_description} + * Sorted by base character and then combining mark for binary search + */ +static const struct ucs_recomposition ucs_recomposition_table[] = {{ +""") + + for base, combining, recomposed in recompose_list: + try: + base_name = unicodedata.name(chr(base)) + combining_name = unicodedata.name(chr(combining)) + recomposed_name = unicodedata.name(chr(recomposed)) + comment = f"/* {base_name} + {combining_name} = {recomposed_name} */" + except ValueError: + comment = f"/* U+{base:04X} + U+{combining:04X} = U+{recomposed:04X} */" + f.write(f"\t{{ 0x{base:04X}, 0x{combining:04X}, 0x{recomposed:04X} }}, {comment}\n") + + f.write(f"""\ +}}; + +/* + * Boundary values for quick rejection + * These are calculated by analyzing the table during generation + */ +#define UCS_RECOMPOSE_MIN_BASE 0x{min_base:04X} +#define UCS_RECOMPOSE_MAX_BASE 0x{max_base:04X} +#define UCS_RECOMPOSE_MIN_MARK 0x{min_combining:04X} +#define UCS_RECOMPOSE_MAX_MARK 0x{max_combining:04X} +""") + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="Generate Unicode recomposition table") + parser.add_argument("--full", action="store_true", + help="Generate a full recomposition table (default: common pairs only)") + parser.add_argument("-o", "--output", dest="output_file", default=DEFAULT_OUT_FILE, + help=f"Output file name (default: {DEFAULT_OUT_FILE})") + args = parser.parse_args() + + generate_recomposition_table(use_full_list=args.full, out_file=args.output_file) diff --git a/drivers/tty/vt/gen_ucs_width_table.py b/drivers/tty/vt/gen_ucs_width_table.py new file mode 100755 index 000000000000..76e80ebeff13 --- /dev/null +++ b/drivers/tty/vt/gen_ucs_width_table.py @@ -0,0 +1,307 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: GPL-2.0 +# +# Leverage Python's unicodedata module to generate ucs_width_table.h + +import unicodedata +import sys +import argparse + +# This script's file name +from pathlib import Path +this_file = Path(__file__).name + +# Default output file name +DEFAULT_OUT_FILE = "ucs_width_table.h" + +# --- Global Constants for Width Assignments --- + +# Known zero-width characters +KNOWN_ZERO_WIDTH = ( + 0x200B, # ZERO WIDTH SPACE + 0x200C, # ZERO WIDTH NON-JOINER + 0x200D, # ZERO WIDTH JOINER + 0x2060, # WORD JOINER + 0xFEFF # ZERO WIDTH NO-BREAK SPACE (BOM) +) + +# Zero-width emoji modifiers and components +# NOTE: Some of these characters would normally be single-width according to +# East Asian Width properties, but we deliberately override them to be +# zero-width because they function as modifiers in emoji sequences. +EMOJI_ZERO_WIDTH = [ + # Skin tone modifiers + (0x1F3FB, 0x1F3FF), # Emoji modifiers (skin tones) + + # Variation selectors (note: VS16 is treated specially in vt.c) + (0xFE00, 0xFE0F), # Variation Selectors 1-16 + + # Gender and hair style modifiers + # These would be single-width by Unicode properties, but are zero-width + # when part of emoji + (0x2640, 0x2640), # Female sign + (0x2642, 0x2642), # Male sign + (0x26A7, 0x26A7), # Transgender symbol + (0x1F9B0, 0x1F9B3), # Hair components (red, curly, white, bald) + + # Tag characters + (0xE0020, 0xE007E), # Tags +] + +# Regional indicators (flag components) +REGIONAL_INDICATORS = (0x1F1E6, 0x1F1FF) # Regional indicator symbols A-Z + +# Double-width emoji ranges +# +# Many emoji characters are classified as single-width according to Unicode +# Standard Annex #11 East Asian Width property (N or Neutral), but we +# deliberately override them to be double-width. References: +# 1. Unicode Technical Standard #51: Unicode Emoji +# (https://www.unicode.org/reports/tr51/) +# 2. Principle of "emoji presentation" in WHATWG CSS Text specification +# (https://drafts.csswg.org/css-text-3/#character-properties) +# 3. Terminal emulator implementations (iTerm2, Windows Terminal, etc.) which +# universally render emoji as double-width characters regardless of their +# Unicode EAW property +# 4. W3C Work Item: Requirements for Japanese Text Layout - Section 3.8.1 +# Emoji width (https://www.w3.org/TR/jlreq/) +EMOJI_RANGES = [ + (0x1F000, 0x1F02F), # Mahjong Tiles (EAW: N, but displayed as double-width) + (0x1F0A0, 0x1F0FF), # Playing Cards (EAW: N, but displayed as double-width) + (0x1F300, 0x1F5FF), # Miscellaneous Symbols and Pictographs + (0x1F600, 0x1F64F), # Emoticons + (0x1F680, 0x1F6FF), # Transport and Map Symbols + (0x1F700, 0x1F77F), # Alchemical Symbols + (0x1F780, 0x1F7FF), # Geometric Shapes Extended + (0x1F800, 0x1F8FF), # Supplemental Arrows-C + (0x1F900, 0x1F9FF), # Supplemental Symbols and Pictographs + (0x1FA00, 0x1FA6F), # Chess Symbols + (0x1FA70, 0x1FAFF), # Symbols and Pictographs Extended-A +] + +def create_width_tables(): + """ + Creates Unicode character width tables and returns the data structures. + + Returns: + tuple: (zero_width_ranges, double_width_ranges) + """ + + # Width data mapping + width_map = {} # Maps code points to width (0, 1, 2) + + # Mark emoji modifiers as zero-width + for start, end in EMOJI_ZERO_WIDTH: + for cp in range(start, end + 1): + width_map[cp] = 0 + + # Mark all regional indicators as single-width as they are usually paired + # providing a combined width of 2 when displayed together. + start, end = REGIONAL_INDICATORS + for cp in range(start, end + 1): + width_map[cp] = 1 + + # Process all assigned Unicode code points (Basic Multilingual Plane + + # Supplementary Planes) Range 0x0 to 0x10FFFF (the full Unicode range) + for block_start in range(0, 0x110000, 0x1000): + block_end = block_start + 0x1000 + for cp in range(block_start, block_end): + try: + char = chr(cp) + + # Skip if already processed + if cp in width_map: + continue + + # Check for combining marks and a format characters + category = unicodedata.category(char) + + # Combining marks + if category.startswith('M'): + width_map[cp] = 0 + continue + + # Format characters + # Since we have no support for bidirectional text, all format + # characters (category Cf) can be treated with width 0 (zero) + # for simplicity, as they don't need to occupy visual space + # in a non-bidirectional text environment. + if category == 'Cf': + width_map[cp] = 0 + continue + + # Known zero-width characters + if cp in KNOWN_ZERO_WIDTH: + width_map[cp] = 0 + continue + + # Use East Asian Width property + eaw = unicodedata.east_asian_width(char) + if eaw in ('F', 'W'): # Fullwidth or Wide + width_map[cp] = 2 + elif eaw in ('Na', 'H', 'N', 'A'): # Narrow, Halfwidth, Neutral, Ambiguous + width_map[cp] = 1 + else: + # Default to single-width for unknown + width_map[cp] = 1 + + except (ValueError, OverflowError): + # Skip invalid code points + continue + + # Process Emoji - generally double-width + for start, end in EMOJI_RANGES: + for cp in range(start, end + 1): + if cp not in width_map or width_map[cp] != 0: # Don't override zero-width + try: + char = chr(cp) + width_map[cp] = 2 + except (ValueError, OverflowError): + continue + + # Optimize to create range tables + def ranges_optimize(width_data, target_width): + points = sorted([cp for cp, width in width_data.items() if width == target_width]) + if not points: + return [] + + # Group consecutive code points into ranges + ranges = [] + start = points[0] + prev = start + + for cp in points[1:]: + if cp > prev + 1: + ranges.append((start, prev)) + start = cp + prev = cp + + # Add the last range + ranges.append((start, prev)) + return ranges + + # Extract ranges for each width + zero_width_ranges = ranges_optimize(width_map, 0) + double_width_ranges = ranges_optimize(width_map, 2) + + return zero_width_ranges, double_width_ranges + +def write_tables(zero_width_ranges, double_width_ranges, out_file=DEFAULT_OUT_FILE): + """ + Write the generated tables to C header file. + + Args: + zero_width_ranges: List of (start, end) ranges for zero-width characters + double_width_ranges: List of (start, end) ranges for double-width characters + out_file: Output file name (default: DEFAULT_OUT_FILE) + """ + + # Function to split ranges into BMP (16-bit) and non-BMP (above 16-bit) + def split_ranges_by_size(ranges): + bmp_ranges = [] + non_bmp_ranges = [] + + for start, end in ranges: + if end <= 0xFFFF: + bmp_ranges.append((start, end)) + elif start > 0xFFFF: + non_bmp_ranges.append((start, end)) + else: + # Split the range at 0xFFFF + bmp_ranges.append((start, 0xFFFF)) + non_bmp_ranges.append((0x10000, end)) + + return bmp_ranges, non_bmp_ranges + + # Split ranges into BMP and non-BMP + zero_width_bmp, zero_width_non_bmp = split_ranges_by_size(zero_width_ranges) + double_width_bmp, double_width_non_bmp = split_ranges_by_size(double_width_ranges) + + # Function to generate code point description comments + def get_code_point_comment(start, end): + try: + start_char_desc = unicodedata.name(chr(start)) + if start == end: + return f"/* {start_char_desc} */" + else: + end_char_desc = unicodedata.name(chr(end)) + return f"/* {start_char_desc} - {end_char_desc} */" + except: + if start == end: + return f"/* U+{start:04X} */" + else: + return f"/* U+{start:04X} - U+{end:04X} */" + + # Generate C tables + with open(out_file, 'w') as f: + f.write(f"""\ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * {out_file} - Unicode character width + * + * Auto-generated by {this_file} + * + * Unicode Version: {unicodedata.unidata_version} + */ + +/* Zero-width character ranges (BMP - Basic Multilingual Plane, U+0000 to U+FFFF) */ +static const struct ucs_interval16 ucs_zero_width_bmp_ranges[] = {{ +""") + + for start, end in zero_width_bmp: + comment = get_code_point_comment(start, end) + f.write(f"\t{{ 0x{start:04X}, 0x{end:04X} }}, {comment}\n") + + f.write("""\ +}; + +/* Zero-width character ranges (non-BMP, U+10000 and above) */ +static const struct ucs_interval32 ucs_zero_width_non_bmp_ranges[] = { +""") + + for start, end in zero_width_non_bmp: + comment = get_code_point_comment(start, end) + f.write(f"\t{{ 0x{start:05X}, 0x{end:05X} }}, {comment}\n") + + f.write("""\ +}; + +/* Double-width character ranges (BMP - Basic Multilingual Plane, U+0000 to U+FFFF) */ +static const struct ucs_interval16 ucs_double_width_bmp_ranges[] = { +""") + + for start, end in double_width_bmp: + comment = get_code_point_comment(start, end) + f.write(f"\t{{ 0x{start:04X}, 0x{end:04X} }}, {comment}\n") + + f.write("""\ +}; + +/* Double-width character ranges (non-BMP, U+10000 and above) */ +static const struct ucs_interval32 ucs_double_width_non_bmp_ranges[] = { +""") + + for start, end in double_width_non_bmp: + comment = get_code_point_comment(start, end) + f.write(f"\t{{ 0x{start:05X}, 0x{end:05X} }}, {comment}\n") + + f.write("};\n") + +if __name__ == "__main__": + # Parse command line arguments + parser = argparse.ArgumentParser(description="Generate Unicode width tables") + parser.add_argument("-o", "--output", dest="output_file", default=DEFAULT_OUT_FILE, + help=f"Output file name (default: {DEFAULT_OUT_FILE})") + args = parser.parse_args() + + # Write tables to header file + zero_width_ranges, double_width_ranges = create_width_tables() + write_tables(zero_width_ranges, double_width_ranges, out_file=args.output_file) + + # Print summary + zero_width_count = sum(end - start + 1 for start, end in zero_width_ranges) + double_width_count = sum(end - start + 1 for start, end in double_width_ranges) + print(f"Generated {args.output_file} with:") + print(f"- {len(zero_width_ranges)} zero-width ranges covering ~{zero_width_count} code points") + print(f"- {len(double_width_ranges)} double-width ranges covering ~{double_width_count} code points") + print(f"- Unicode Version: {unicodedata.unidata_version}") diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c index ae92e6a50a65..dc585079c2fb 100644 --- a/drivers/tty/vt/keyboard.c +++ b/drivers/tty/vt/keyboard.c @@ -376,6 +376,17 @@ static void to_utf8(struct vc_data *vc, uint c) } } +static void put_queue_utf8(struct vc_data *vc, u32 value) +{ + if (kbd->kbdmode == VC_UNICODE) + to_utf8(vc, value); + else { + int c = conv_uni_to_8bit(value); + if (c != -1) + put_queue(vc, c); + } +} + /* FIXME: review locking for vt.c callers */ static void set_leds(void) { @@ -454,13 +465,7 @@ static unsigned int handle_diacr(struct vc_data *vc, unsigned int ch) if (ch == ' ' || ch == (BRL_UC_ROW|0) || ch == d) return d; - if (kbd->kbdmode == VC_UNICODE) - to_utf8(vc, d); - else { - int c = conv_uni_to_8bit(d); - if (c != -1) - put_queue(vc, c); - } + put_queue_utf8(vc, d); return ch; } @@ -471,13 +476,7 @@ static unsigned int handle_diacr(struct vc_data *vc, unsigned int ch) static void fn_enter(struct vc_data *vc) { if (diacr) { - if (kbd->kbdmode == VC_UNICODE) - to_utf8(vc, diacr); - else { - int c = conv_uni_to_8bit(diacr); - if (c != -1) - put_queue(vc, c); - } + put_queue_utf8(vc, diacr); diacr = 0; } @@ -685,13 +684,7 @@ static void k_unicode(struct vc_data *vc, unsigned int value, char up_flag) diacr = value; return; } - if (kbd->kbdmode == VC_UNICODE) - to_utf8(vc, value); - else { - int c = conv_uni_to_8bit(value); - if (c != -1) - put_queue(vc, c); - } + put_queue_utf8(vc, value); } /* @@ -1519,7 +1512,7 @@ static void kbd_keycode(unsigned int keycode, int down, bool hw_raw) if ((raw_mode || kbd->kbdmode == VC_OFF) && type != KT_SPEC && type != KT_SHIFT) return; - (*k_handler[type])(vc, keysym & 0xff, !down); + (*k_handler[type])(vc, KVAL(keysym), !down); param.ledstate = kbd->ledflagstate; atomic_notifier_call_chain(&keyboard_notifier_list, KBD_POST_KEYSYM, ¶m); diff --git a/drivers/tty/vt/selection.c b/drivers/tty/vt/selection.c index 791e2f1f7c0b..24b0a53e5a79 100644 --- a/drivers/tty/vt/selection.c +++ b/drivers/tty/vt/selection.c @@ -403,6 +403,12 @@ int paste_selection(struct tty_struct *tty) DECLARE_WAITQUEUE(wait, current); int ret = 0; + bool bp = vc->vc_bracketed_paste; + static const char bracketed_paste_start[] = "\033[200~"; + static const char bracketed_paste_end[] = "\033[201~"; + const char *bps = bp ? bracketed_paste_start : NULL; + const char *bpe = bp ? bracketed_paste_end : NULL; + console_lock(); poke_blanked_console(); console_unlock(); @@ -414,7 +420,7 @@ int paste_selection(struct tty_struct *tty) add_wait_queue(&vc->paste_wait, &wait); mutex_lock(&vc_sel.lock); - while (vc_sel.buffer && vc_sel.buf_len > pasted) { + while (vc_sel.buffer && (vc_sel.buf_len > pasted || bpe)) { set_current_state(TASK_INTERRUPTIBLE); if (signal_pending(current)) { ret = -EINTR; @@ -427,10 +433,27 @@ int paste_selection(struct tty_struct *tty) continue; } __set_current_state(TASK_RUNNING); + + if (bps) { + bps += tty_ldisc_receive_buf(ld, bps, NULL, strlen(bps)); + if (*bps != '\0') + continue; + bps = NULL; + } + count = vc_sel.buf_len - pasted; - count = tty_ldisc_receive_buf(ld, vc_sel.buffer + pasted, NULL, - count); - pasted += count; + if (count) { + pasted += tty_ldisc_receive_buf(ld, vc_sel.buffer + pasted, + NULL, count); + if (vc_sel.buf_len > pasted) + continue; + } + + if (bpe) { + bpe += tty_ldisc_receive_buf(ld, bpe, NULL, strlen(bpe)); + if (*bpe == '\0') + bpe = NULL; + } } mutex_unlock(&vc_sel.lock); remove_wait_queue(&vc->paste_wait, &wait); diff --git a/drivers/tty/vt/ucs.c b/drivers/tty/vt/ucs.c new file mode 100644 index 000000000000..6ead622b7713 --- /dev/null +++ b/drivers/tty/vt/ucs.c @@ -0,0 +1,251 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * ucs.c - Universal Character Set processing + */ + +#include <linux/array_size.h> +#include <linux/bsearch.h> +#include <linux/consolemap.h> +#include <linux/minmax.h> + +struct ucs_interval16 { + u16 first; + u16 last; +}; + +struct ucs_interval32 { + u32 first; + u32 last; +}; + +#include "ucs_width_table.h" + +static int interval16_cmp(const void *key, const void *element) +{ + u16 cp = *(u16 *)key; + const struct ucs_interval16 *entry = element; + + if (cp < entry->first) + return -1; + if (cp > entry->last) + return 1; + return 0; +} + +static int interval32_cmp(const void *key, const void *element) +{ + u32 cp = *(u32 *)key; + const struct ucs_interval32 *entry = element; + + if (cp < entry->first) + return -1; + if (cp > entry->last) + return 1; + return 0; +} + +static bool cp_in_range16(u16 cp, const struct ucs_interval16 *ranges, size_t size) +{ + if (cp < ranges[0].first || cp > ranges[size - 1].last) + return false; + + return __inline_bsearch(&cp, ranges, size, sizeof(*ranges), + interval16_cmp) != NULL; +} + +static bool cp_in_range32(u32 cp, const struct ucs_interval32 *ranges, size_t size) +{ + if (cp < ranges[0].first || cp > ranges[size - 1].last) + return false; + + return __inline_bsearch(&cp, ranges, size, sizeof(*ranges), + interval32_cmp) != NULL; +} + +#define UCS_IS_BMP(cp) ((cp) <= 0xffff) + +/** + * ucs_is_zero_width() - Determine if a Unicode code point is zero-width. + * @cp: Unicode code point (UCS-4) + * + * Return: true if the character is zero-width, false otherwise + */ +bool ucs_is_zero_width(u32 cp) +{ + if (UCS_IS_BMP(cp)) + return cp_in_range16(cp, ucs_zero_width_bmp_ranges, + ARRAY_SIZE(ucs_zero_width_bmp_ranges)); + else + return cp_in_range32(cp, ucs_zero_width_non_bmp_ranges, + ARRAY_SIZE(ucs_zero_width_non_bmp_ranges)); +} + +/** + * ucs_is_double_width() - Determine if a Unicode code point is double-width. + * @cp: Unicode code point (UCS-4) + * + * Return: true if the character is double-width, false otherwise + */ +bool ucs_is_double_width(u32 cp) +{ + if (UCS_IS_BMP(cp)) + return cp_in_range16(cp, ucs_double_width_bmp_ranges, + ARRAY_SIZE(ucs_double_width_bmp_ranges)); + else + return cp_in_range32(cp, ucs_double_width_non_bmp_ranges, + ARRAY_SIZE(ucs_double_width_non_bmp_ranges)); +} + +/* + * Structure for base with combining mark pairs and resulting recompositions. + * Using u16 to save space since all values are within BMP range. + */ +struct ucs_recomposition { + u16 base; /* base character */ + u16 mark; /* combining mark */ + u16 recomposed; /* corresponding recomposed character */ +}; + +#include "ucs_recompose_table.h" + +struct compare_key { + u16 base; + u16 mark; +}; + +static int recomposition_cmp(const void *key, const void *element) +{ + const struct compare_key *search_key = key; + const struct ucs_recomposition *entry = element; + + /* Compare base character first */ + if (search_key->base < entry->base) + return -1; + if (search_key->base > entry->base) + return 1; + + /* Base characters match, now compare combining character */ + if (search_key->mark < entry->mark) + return -1; + if (search_key->mark > entry->mark) + return 1; + + /* Both match */ + return 0; +} + +/** + * ucs_recompose() - Attempt to recompose two Unicode characters into a single character. + * @base: Base Unicode code point (UCS-4) + * @mark: Combining mark Unicode code point (UCS-4) + * + * Return: Recomposed Unicode code point, or 0 if no recomposition is possible + */ +u32 ucs_recompose(u32 base, u32 mark) +{ + /* Check if characters are within the range of our table */ + if (base < UCS_RECOMPOSE_MIN_BASE || base > UCS_RECOMPOSE_MAX_BASE || + mark < UCS_RECOMPOSE_MIN_MARK || mark > UCS_RECOMPOSE_MAX_MARK) + return 0; + + struct compare_key key = { base, mark }; + struct ucs_recomposition *result = + __inline_bsearch(&key, ucs_recomposition_table, + ARRAY_SIZE(ucs_recomposition_table), + sizeof(*ucs_recomposition_table), + recomposition_cmp); + + return result ? result->recomposed : 0; +} + +/* + * The fallback table structures implement a 2-level lookup. + */ + +struct ucs_page_desc { + u8 page; /* Page index (high byte of code points) */ + u8 count; /* Number of entries in this page */ + u16 start; /* Start index in entries array */ +}; + +struct ucs_page_entry { + u8 offset; /* Offset within page (0-255) */ + u8 fallback; /* Fallback character or range start marker */ +}; + +#include "ucs_fallback_table.h" + +static int ucs_page_desc_cmp(const void *key, const void *element) +{ + u8 page = *(u8 *)key; + const struct ucs_page_desc *entry = element; + + if (page < entry->page) + return -1; + if (page > entry->page) + return 1; + return 0; +} + +static int ucs_page_entry_cmp(const void *key, const void *element) +{ + u8 offset = *(u8 *)key; + const struct ucs_page_entry *entry = element; + + if (offset < entry->offset) + return -1; + if (entry->fallback == UCS_PAGE_ENTRY_RANGE_MARKER) { + if (offset > entry[1].offset) + return 1; + } else { + if (offset > entry->offset) + return 1; + } + return 0; +} + +/** + * ucs_get_fallback() - Get a substitution for the provided Unicode character + * @base: Base Unicode code point (UCS-4) + * + * Get a simpler fallback character for the provided Unicode character. + * This is used for terminal display when corresponding glyph is unavailable. + * The substitution may not be as good as the actual glyph for the original + * character but still way more helpful than a squared question mark. + * + * Return: Fallback Unicode code point, or 0 if none is available + */ +u32 ucs_get_fallback(u32 cp) +{ + const struct ucs_page_desc *page; + const struct ucs_page_entry *entry; + u8 page_idx = cp >> 8, offset = cp; + + if (!UCS_IS_BMP(cp)) + return 0; + + /* + * Full-width to ASCII mapping (covering all printable ASCII 33-126) + * 0xFF01 (ï¼) to 0xFF5E (~) -> ASCII 33 (!) to 126 (~) + * We process them programmatically to reduce the table size. + */ + if (cp >= 0xFF01 && cp <= 0xFF5E) + return cp - 0xFF01 + 33; + + page = __inline_bsearch(&page_idx, ucs_fallback_pages, + ARRAY_SIZE(ucs_fallback_pages), + sizeof(*ucs_fallback_pages), + ucs_page_desc_cmp); + if (!page) + return 0; + + entry = __inline_bsearch(&offset, ucs_fallback_entries + page->start, + page->count, sizeof(*ucs_fallback_entries), + ucs_page_entry_cmp); + if (!entry) + return 0; + + if (entry->fallback == UCS_PAGE_ENTRY_RANGE_MARKER) + entry++; + return entry->fallback; +} diff --git a/drivers/tty/vt/ucs_fallback_table.h_shipped b/drivers/tty/vt/ucs_fallback_table.h_shipped new file mode 100644 index 000000000000..2da5a8fe1cf1 --- /dev/null +++ b/drivers/tty/vt/ucs_fallback_table.h_shipped @@ -0,0 +1,3346 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * ucs_fallback_table.h - Unicode character fallback table + * + * Auto-generated by gen_ucs_fallback_table.py + * + * Unicode Version: 16.0.0 + * Unidecode Version: 1.3.8 + * + * This file contains optimized tables that map complex Unicode characters + * to simpler fallback characters for terminal display when corresponding + * glyphs are unavailable. + */ + +static const struct ucs_page_desc ucs_fallback_pages[] = { + { 0x00, 62, 0 }, + { 0x01, 218, 62 }, + { 0x02, 196, 280 }, + { 0x03, 96, 476 }, + { 0x04, 113, 572 }, + { 0x05, 100, 685 }, + { 0x06, 119, 785 }, + { 0x07, 91, 904 }, + { 0x09, 99, 995 }, + { 0x0A, 78, 1094 }, + { 0x0B, 79, 1172 }, + { 0x0C, 85, 1251 }, + { 0x0D, 73, 1336 }, + { 0x0E, 83, 1409 }, + { 0x0F, 69, 1492 }, + { 0x10, 93, 1561 }, + { 0x11, 51, 1654 }, + { 0x13, 22, 1705 }, + { 0x14, 30, 1727 }, + { 0x15, 17, 1757 }, + { 0x16, 81, 1774 }, + { 0x17, 47, 1855 }, + { 0x18, 96, 1902 }, + { 0x1D, 105, 1998 }, + { 0x1E, 246, 2103 }, + { 0x1F, 94, 2349 }, + { 0x20, 107, 2443 }, + { 0x21, 136, 2550 }, + { 0x22, 34, 2686 }, + { 0x23, 4, 2720 }, + { 0x24, 72, 2724 }, + { 0x25, 60, 2796 }, + { 0x26, 6, 2856 }, + { 0x27, 18, 2862 }, + { 0x28, 64, 2880 }, + { 0x29, 1, 2944 }, + { 0x2C, 15, 2945 }, + { 0x2E, 29, 2960 }, + { 0x30, 53, 2989 }, + { 0x31, 50, 3042 }, + { 0x32, 5, 3092 }, + { 0xA0, 4, 3097 }, + { 0xC5, 2, 3101 }, + { 0xC6, 2, 3103 }, + { 0xC7, 1, 3105 }, + { 0xFB, 35, 3106 }, + { 0xFE, 37, 3141 }, + { 0xFF, 50, 3178 }, +}; + +/* Page entries array (referenced by page descriptors) */ +static const struct ucs_page_entry ucs_fallback_entries[] = { + /* Entries for page 0x00 */ + { 0xA0, 0x20 }, /* NO-BREAK SPACE -> ' ' */ + { 0xA1, 0x21 }, /* INVERTED EXCLAMATION MARK -> '!' */ + { 0xA2, 0x63 }, /* CENT SIGN -> 'c' */ + { 0xA3, 0x4C }, /* POUND SIGN -> 'L' */ + { 0xA5, 0x59 }, /* YEN SIGN -> 'Y' */ + { 0xA6, 0x7C }, /* BROKEN BAR -> '|' */ + { 0xA7, 0x53 }, /* SECTION SIGN -> 'S' */ + { 0xA8, 0x22 }, /* DIAERESIS -> '"' */ + { 0xA9, 0x43 }, /* COPYRIGHT SIGN -> 'C' */ + { 0xAA, 0x61 }, /* FEMININE ORDINAL INDICATOR -> 'a' */ + { 0xAB, 0x3C }, /* LEFT-POINTING DOUBLE ANGLE QUOTATION MARK -> '<' */ + { 0xAC, 0x21 }, /* NOT SIGN -> '!' */ + { 0xAE, 0x52 }, /* REGISTERED SIGN -> 'R' */ + { 0xAF, 0x2D }, /* MACRON -> '-' */ + { 0xB0, 0x6F }, /* DEGREE SIGN -> 'o' */ + { 0xB2, 0x32 }, /* SUPERSCRIPT TWO -> '2' */ + { 0xB3, 0x33 }, /* SUPERSCRIPT THREE -> '3' */ + { 0xB4, 0x27 }, /* ACUTE ACCENT -> ''' */ + { 0xB5, 0x75 }, /* MICRO SIGN -> 'u' */ + { 0xB6, 0x50 }, /* PILCROW SIGN -> 'P' */ + { 0xB7, 0x2A }, /* MIDDLE DOT -> '*' */ + { 0xB8, 0x2C }, /* CEDILLA -> ',' */ + { 0xB9, 0x31 }, /* SUPERSCRIPT ONE -> '1' */ + { 0xBA, 0x6F }, /* MASCULINE ORDINAL INDICATOR -> 'o' */ + { 0xBB, 0x3E }, /* RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK -> '>' */ + { 0xBF, 0x3F }, /* INVERTED QUESTION MARK -> '?' */ + { 0xC0, 0x00 }, /* LATIN CAPITAL LETTER A WITH GRAVE -> ... */ + { 0xC5, 0x41 }, /* LATIN CAPITAL LETTER A WITH RING ABOVE -> 'A' */ + { 0xC6, 0x45 }, /* LATIN CAPITAL LETTER AE -> 'E' */ + { 0xC7, 0x43 }, /* LATIN CAPITAL LETTER C WITH CEDILLA -> 'C' */ + { 0xC8, 0x00 }, /* LATIN CAPITAL LETTER E WITH GRAVE -> ... */ + { 0xCB, 0x45 }, /* LATIN CAPITAL LETTER E WITH DIAERESIS -> 'E' */ + { 0xCC, 0x00 }, /* LATIN CAPITAL LETTER I WITH GRAVE -> ... */ + { 0xCF, 0x49 }, /* LATIN CAPITAL LETTER I WITH DIAERESIS -> 'I' */ + { 0xD0, 0x44 }, /* LATIN CAPITAL LETTER ETH -> 'D' */ + { 0xD1, 0x4E }, /* LATIN CAPITAL LETTER N WITH TILDE -> 'N' */ + { 0xD2, 0x00 }, /* LATIN CAPITAL LETTER O WITH GRAVE -> ... */ + { 0xD6, 0x4F }, /* LATIN CAPITAL LETTER O WITH DIAERESIS -> 'O' */ + { 0xD7, 0x78 }, /* MULTIPLICATION SIGN -> 'x' */ + { 0xD8, 0x4F }, /* LATIN CAPITAL LETTER O WITH STROKE -> 'O' */ + { 0xD9, 0x00 }, /* LATIN CAPITAL LETTER U WITH GRAVE -> ... */ + { 0xDC, 0x55 }, /* LATIN CAPITAL LETTER U WITH DIAERESIS -> 'U' */ + { 0xDD, 0x59 }, /* LATIN CAPITAL LETTER Y WITH ACUTE -> 'Y' */ + { 0xDF, 0x73 }, /* LATIN SMALL LETTER SHARP S -> 's' */ + { 0xE0, 0x00 }, /* LATIN SMALL LETTER A WITH GRAVE -> ... */ + { 0xE5, 0x61 }, /* LATIN SMALL LETTER A WITH RING ABOVE -> 'a' */ + { 0xE6, 0x65 }, /* LATIN SMALL LETTER AE -> 'e' */ + { 0xE7, 0x63 }, /* LATIN SMALL LETTER C WITH CEDILLA -> 'c' */ + { 0xE8, 0x00 }, /* LATIN SMALL LETTER E WITH GRAVE -> ... */ + { 0xEB, 0x65 }, /* LATIN SMALL LETTER E WITH DIAERESIS -> 'e' */ + { 0xEC, 0x00 }, /* LATIN SMALL LETTER I WITH GRAVE -> ... */ + { 0xEF, 0x69 }, /* LATIN SMALL LETTER I WITH DIAERESIS -> 'i' */ + { 0xF0, 0x64 }, /* LATIN SMALL LETTER ETH -> 'd' */ + { 0xF1, 0x6E }, /* LATIN SMALL LETTER N WITH TILDE -> 'n' */ + { 0xF2, 0x00 }, /* LATIN SMALL LETTER O WITH GRAVE -> ... */ + { 0xF6, 0x6F }, /* LATIN SMALL LETTER O WITH DIAERESIS -> 'o' */ + { 0xF7, 0x2F }, /* DIVISION SIGN -> '/' */ + { 0xF8, 0x6F }, /* LATIN SMALL LETTER O WITH STROKE -> 'o' */ + { 0xF9, 0x00 }, /* LATIN SMALL LETTER U WITH GRAVE -> ... */ + { 0xFC, 0x75 }, /* LATIN SMALL LETTER U WITH DIAERESIS -> 'u' */ + { 0xFD, 0x79 }, /* LATIN SMALL LETTER Y WITH ACUTE -> 'y' */ + { 0xFF, 0x79 }, /* LATIN SMALL LETTER Y WITH DIAERESIS -> 'y' */ + /* Entries for page 0x01 */ + { 0x00, 0x41 }, /* LATIN CAPITAL LETTER A WITH MACRON -> 'A' */ + { 0x01, 0x61 }, /* LATIN SMALL LETTER A WITH MACRON -> 'a' */ + { 0x02, 0x41 }, /* LATIN CAPITAL LETTER A WITH BREVE -> 'A' */ + { 0x03, 0x61 }, /* LATIN SMALL LETTER A WITH BREVE -> 'a' */ + { 0x04, 0x41 }, /* LATIN CAPITAL LETTER A WITH OGONEK -> 'A' */ + { 0x05, 0x61 }, /* LATIN SMALL LETTER A WITH OGONEK -> 'a' */ + { 0x06, 0x43 }, /* LATIN CAPITAL LETTER C WITH ACUTE -> 'C' */ + { 0x07, 0x63 }, /* LATIN SMALL LETTER C WITH ACUTE -> 'c' */ + { 0x08, 0x43 }, /* LATIN CAPITAL LETTER C WITH CIRCUMFLEX -> 'C' */ + { 0x09, 0x63 }, /* LATIN SMALL LETTER C WITH CIRCUMFLEX -> 'c' */ + { 0x0A, 0x43 }, /* LATIN CAPITAL LETTER C WITH DOT ABOVE -> 'C' */ + { 0x0B, 0x63 }, /* LATIN SMALL LETTER C WITH DOT ABOVE -> 'c' */ + { 0x0C, 0x43 }, /* LATIN CAPITAL LETTER C WITH CARON -> 'C' */ + { 0x0D, 0x63 }, /* LATIN SMALL LETTER C WITH CARON -> 'c' */ + { 0x0E, 0x44 }, /* LATIN CAPITAL LETTER D WITH CARON -> 'D' */ + { 0x0F, 0x64 }, /* LATIN SMALL LETTER D WITH CARON -> 'd' */ + { 0x10, 0x44 }, /* LATIN CAPITAL LETTER D WITH STROKE -> 'D' */ + { 0x11, 0x64 }, /* LATIN SMALL LETTER D WITH STROKE -> 'd' */ + { 0x12, 0x45 }, /* LATIN CAPITAL LETTER E WITH MACRON -> 'E' */ + { 0x13, 0x65 }, /* LATIN SMALL LETTER E WITH MACRON -> 'e' */ + { 0x14, 0x45 }, /* LATIN CAPITAL LETTER E WITH BREVE -> 'E' */ + { 0x15, 0x65 }, /* LATIN SMALL LETTER E WITH BREVE -> 'e' */ + { 0x16, 0x45 }, /* LATIN CAPITAL LETTER E WITH DOT ABOVE -> 'E' */ + { 0x17, 0x65 }, /* LATIN SMALL LETTER E WITH DOT ABOVE -> 'e' */ + { 0x18, 0x45 }, /* LATIN CAPITAL LETTER E WITH OGONEK -> 'E' */ + { 0x19, 0x65 }, /* LATIN SMALL LETTER E WITH OGONEK -> 'e' */ + { 0x1A, 0x45 }, /* LATIN CAPITAL LETTER E WITH CARON -> 'E' */ + { 0x1B, 0x65 }, /* LATIN SMALL LETTER E WITH CARON -> 'e' */ + { 0x1C, 0x47 }, /* LATIN CAPITAL LETTER G WITH CIRCUMFLEX -> 'G' */ + { 0x1D, 0x67 }, /* LATIN SMALL LETTER G WITH CIRCUMFLEX -> 'g' */ + { 0x1E, 0x47 }, /* LATIN CAPITAL LETTER G WITH BREVE -> 'G' */ + { 0x1F, 0x67 }, /* LATIN SMALL LETTER G WITH BREVE -> 'g' */ + { 0x20, 0x47 }, /* LATIN CAPITAL LETTER G WITH DOT ABOVE -> 'G' */ + { 0x21, 0x67 }, /* LATIN SMALL LETTER G WITH DOT ABOVE -> 'g' */ + { 0x22, 0x47 }, /* LATIN CAPITAL LETTER G WITH CEDILLA -> 'G' */ + { 0x23, 0x67 }, /* LATIN SMALL LETTER G WITH CEDILLA -> 'g' */ + { 0x24, 0x48 }, /* LATIN CAPITAL LETTER H WITH CIRCUMFLEX -> 'H' */ + { 0x25, 0x68 }, /* LATIN SMALL LETTER H WITH CIRCUMFLEX -> 'h' */ + { 0x26, 0x48 }, /* LATIN CAPITAL LETTER H WITH STROKE -> 'H' */ + { 0x27, 0x68 }, /* LATIN SMALL LETTER H WITH STROKE -> 'h' */ + { 0x28, 0x49 }, /* LATIN CAPITAL LETTER I WITH TILDE -> 'I' */ + { 0x29, 0x69 }, /* LATIN SMALL LETTER I WITH TILDE -> 'i' */ + { 0x2A, 0x49 }, /* LATIN CAPITAL LETTER I WITH MACRON -> 'I' */ + { 0x2B, 0x69 }, /* LATIN SMALL LETTER I WITH MACRON -> 'i' */ + { 0x2C, 0x49 }, /* LATIN CAPITAL LETTER I WITH BREVE -> 'I' */ + { 0x2D, 0x69 }, /* LATIN SMALL LETTER I WITH BREVE -> 'i' */ + { 0x2E, 0x49 }, /* LATIN CAPITAL LETTER I WITH OGONEK -> 'I' */ + { 0x2F, 0x69 }, /* LATIN SMALL LETTER I WITH OGONEK -> 'i' */ + { 0x30, 0x49 }, /* LATIN CAPITAL LETTER I WITH DOT ABOVE -> 'I' */ + { 0x31, 0x69 }, /* LATIN SMALL LETTER DOTLESS I -> 'i' */ + { 0x34, 0x4A }, /* LATIN CAPITAL LETTER J WITH CIRCUMFLEX -> 'J' */ + { 0x35, 0x6A }, /* LATIN SMALL LETTER J WITH CIRCUMFLEX -> 'j' */ + { 0x36, 0x4B }, /* LATIN CAPITAL LETTER K WITH CEDILLA -> 'K' */ + { 0x37, 0x6B }, /* LATIN SMALL LETTER K WITH CEDILLA -> 'k' */ + { 0x38, 0x6B }, /* LATIN SMALL LETTER KRA -> 'k' */ + { 0x39, 0x4C }, /* LATIN CAPITAL LETTER L WITH ACUTE -> 'L' */ + { 0x3A, 0x6C }, /* LATIN SMALL LETTER L WITH ACUTE -> 'l' */ + { 0x3B, 0x4C }, /* LATIN CAPITAL LETTER L WITH CEDILLA -> 'L' */ + { 0x3C, 0x6C }, /* LATIN SMALL LETTER L WITH CEDILLA -> 'l' */ + { 0x3D, 0x4C }, /* LATIN CAPITAL LETTER L WITH CARON -> 'L' */ + { 0x3E, 0x6C }, /* LATIN SMALL LETTER L WITH CARON -> 'l' */ + { 0x3F, 0x4C }, /* LATIN CAPITAL LETTER L WITH MIDDLE DOT -> 'L' */ + { 0x40, 0x6C }, /* LATIN SMALL LETTER L WITH MIDDLE DOT -> 'l' */ + { 0x41, 0x4C }, /* LATIN CAPITAL LETTER L WITH STROKE -> 'L' */ + { 0x42, 0x6C }, /* LATIN SMALL LETTER L WITH STROKE -> 'l' */ + { 0x43, 0x4E }, /* LATIN CAPITAL LETTER N WITH ACUTE -> 'N' */ + { 0x44, 0x6E }, /* LATIN SMALL LETTER N WITH ACUTE -> 'n' */ + { 0x45, 0x4E }, /* LATIN CAPITAL LETTER N WITH CEDILLA -> 'N' */ + { 0x46, 0x6E }, /* LATIN SMALL LETTER N WITH CEDILLA -> 'n' */ + { 0x47, 0x4E }, /* LATIN CAPITAL LETTER N WITH CARON -> 'N' */ + { 0x48, 0x6E }, /* LATIN SMALL LETTER N WITH CARON -> 'n' */ + { 0x4C, 0x4F }, /* LATIN CAPITAL LETTER O WITH MACRON -> 'O' */ + { 0x4D, 0x6F }, /* LATIN SMALL LETTER O WITH MACRON -> 'o' */ + { 0x4E, 0x4F }, /* LATIN CAPITAL LETTER O WITH BREVE -> 'O' */ + { 0x4F, 0x6F }, /* LATIN SMALL LETTER O WITH BREVE -> 'o' */ + { 0x50, 0x4F }, /* LATIN CAPITAL LETTER O WITH DOUBLE ACUTE -> 'O' */ + { 0x51, 0x6F }, /* LATIN SMALL LETTER O WITH DOUBLE ACUTE -> 'o' */ + { 0x52, 0x45 }, /* LATIN CAPITAL LIGATURE OE -> 'E' */ + { 0x53, 0x65 }, /* LATIN SMALL LIGATURE OE -> 'e' */ + { 0x54, 0x52 }, /* LATIN CAPITAL LETTER R WITH ACUTE -> 'R' */ + { 0x55, 0x72 }, /* LATIN SMALL LETTER R WITH ACUTE -> 'r' */ + { 0x56, 0x52 }, /* LATIN CAPITAL LETTER R WITH CEDILLA -> 'R' */ + { 0x57, 0x72 }, /* LATIN SMALL LETTER R WITH CEDILLA -> 'r' */ + { 0x58, 0x52 }, /* LATIN CAPITAL LETTER R WITH CARON -> 'R' */ + { 0x59, 0x72 }, /* LATIN SMALL LETTER R WITH CARON -> 'r' */ + { 0x5A, 0x53 }, /* LATIN CAPITAL LETTER S WITH ACUTE -> 'S' */ + { 0x5B, 0x73 }, /* LATIN SMALL LETTER S WITH ACUTE -> 's' */ + { 0x5C, 0x53 }, /* LATIN CAPITAL LETTER S WITH CIRCUMFLEX -> 'S' */ + { 0x5D, 0x73 }, /* LATIN SMALL LETTER S WITH CIRCUMFLEX -> 's' */ + { 0x5E, 0x53 }, /* LATIN CAPITAL LETTER S WITH CEDILLA -> 'S' */ + { 0x5F, 0x73 }, /* LATIN SMALL LETTER S WITH CEDILLA -> 's' */ + { 0x60, 0x53 }, /* LATIN CAPITAL LETTER S WITH CARON -> 'S' */ + { 0x61, 0x73 }, /* LATIN SMALL LETTER S WITH CARON -> 's' */ + { 0x62, 0x54 }, /* LATIN CAPITAL LETTER T WITH CEDILLA -> 'T' */ + { 0x63, 0x74 }, /* LATIN SMALL LETTER T WITH CEDILLA -> 't' */ + { 0x64, 0x54 }, /* LATIN CAPITAL LETTER T WITH CARON -> 'T' */ + { 0x65, 0x74 }, /* LATIN SMALL LETTER T WITH CARON -> 't' */ + { 0x66, 0x54 }, /* LATIN CAPITAL LETTER T WITH STROKE -> 'T' */ + { 0x67, 0x74 }, /* LATIN SMALL LETTER T WITH STROKE -> 't' */ + { 0x68, 0x55 }, /* LATIN CAPITAL LETTER U WITH TILDE -> 'U' */ + { 0x69, 0x75 }, /* LATIN SMALL LETTER U WITH TILDE -> 'u' */ + { 0x6A, 0x55 }, /* LATIN CAPITAL LETTER U WITH MACRON -> 'U' */ + { 0x6B, 0x75 }, /* LATIN SMALL LETTER U WITH MACRON -> 'u' */ + { 0x6C, 0x55 }, /* LATIN CAPITAL LETTER U WITH BREVE -> 'U' */ + { 0x6D, 0x75 }, /* LATIN SMALL LETTER U WITH BREVE -> 'u' */ + { 0x6E, 0x55 }, /* LATIN CAPITAL LETTER U WITH RING ABOVE -> 'U' */ + { 0x6F, 0x75 }, /* LATIN SMALL LETTER U WITH RING ABOVE -> 'u' */ + { 0x70, 0x55 }, /* LATIN CAPITAL LETTER U WITH DOUBLE ACUTE -> 'U' */ + { 0x71, 0x75 }, /* LATIN SMALL LETTER U WITH DOUBLE ACUTE -> 'u' */ + { 0x72, 0x55 }, /* LATIN CAPITAL LETTER U WITH OGONEK -> 'U' */ + { 0x73, 0x75 }, /* LATIN SMALL LETTER U WITH OGONEK -> 'u' */ + { 0x74, 0x57 }, /* LATIN CAPITAL LETTER W WITH CIRCUMFLEX -> 'W' */ + { 0x75, 0x77 }, /* LATIN SMALL LETTER W WITH CIRCUMFLEX -> 'w' */ + { 0x76, 0x59 }, /* LATIN CAPITAL LETTER Y WITH CIRCUMFLEX -> 'Y' */ + { 0x77, 0x79 }, /* LATIN SMALL LETTER Y WITH CIRCUMFLEX -> 'y' */ + { 0x78, 0x59 }, /* LATIN CAPITAL LETTER Y WITH DIAERESIS -> 'Y' */ + { 0x79, 0x5A }, /* LATIN CAPITAL LETTER Z WITH ACUTE -> 'Z' */ + { 0x7A, 0x7A }, /* LATIN SMALL LETTER Z WITH ACUTE -> 'z' */ + { 0x7B, 0x5A }, /* LATIN CAPITAL LETTER Z WITH DOT ABOVE -> 'Z' */ + { 0x7C, 0x7A }, /* LATIN SMALL LETTER Z WITH DOT ABOVE -> 'z' */ + { 0x7D, 0x5A }, /* LATIN CAPITAL LETTER Z WITH CARON -> 'Z' */ + { 0x7E, 0x7A }, /* LATIN SMALL LETTER Z WITH CARON -> 'z' */ + { 0x7F, 0x73 }, /* LATIN SMALL LETTER LONG S -> 's' */ + { 0x80, 0x62 }, /* LATIN SMALL LETTER B WITH STROKE -> 'b' */ + { 0x81, 0x42 }, /* LATIN CAPITAL LETTER B WITH HOOK -> 'B' */ + { 0x82, 0x42 }, /* LATIN CAPITAL LETTER B WITH TOPBAR -> 'B' */ + { 0x83, 0x62 }, /* LATIN SMALL LETTER B WITH TOPBAR -> 'b' */ + { 0x84, 0x36 }, /* LATIN CAPITAL LETTER TONE SIX -> '6' */ + { 0x85, 0x36 }, /* LATIN SMALL LETTER TONE SIX -> '6' */ + { 0x86, 0x4F }, /* LATIN CAPITAL LETTER OPEN O -> 'O' */ + { 0x87, 0x43 }, /* LATIN CAPITAL LETTER C WITH HOOK -> 'C' */ + { 0x88, 0x63 }, /* LATIN SMALL LETTER C WITH HOOK -> 'c' */ + { 0x89, 0x00 }, /* LATIN CAPITAL LETTER AFRICAN D -> ... */ + { 0x8B, 0x44 }, /* LATIN CAPITAL LETTER D WITH TOPBAR -> 'D' */ + { 0x8C, 0x64 }, /* LATIN SMALL LETTER D WITH TOPBAR -> 'd' */ + { 0x8D, 0x64 }, /* LATIN SMALL LETTER TURNED DELTA -> 'd' */ + { 0x8E, 0x33 }, /* LATIN CAPITAL LETTER REVERSED E -> '3' */ + { 0x8F, 0x40 }, /* LATIN CAPITAL LETTER SCHWA -> '@' */ + { 0x90, 0x45 }, /* LATIN CAPITAL LETTER OPEN E -> 'E' */ + { 0x91, 0x46 }, /* LATIN CAPITAL LETTER F WITH HOOK -> 'F' */ + { 0x92, 0x66 }, /* LATIN SMALL LETTER F WITH HOOK -> 'f' */ + { 0x93, 0x47 }, /* LATIN CAPITAL LETTER G WITH HOOK -> 'G' */ + { 0x94, 0x47 }, /* LATIN CAPITAL LETTER GAMMA -> 'G' */ + { 0x96, 0x49 }, /* LATIN CAPITAL LETTER IOTA -> 'I' */ + { 0x97, 0x49 }, /* LATIN CAPITAL LETTER I WITH STROKE -> 'I' */ + { 0x98, 0x4B }, /* LATIN CAPITAL LETTER K WITH HOOK -> 'K' */ + { 0x99, 0x6B }, /* LATIN SMALL LETTER K WITH HOOK -> 'k' */ + { 0x9A, 0x6C }, /* LATIN SMALL LETTER L WITH BAR -> 'l' */ + { 0x9B, 0x6C }, /* LATIN SMALL LETTER LAMBDA WITH STROKE -> 'l' */ + { 0x9C, 0x57 }, /* LATIN CAPITAL LETTER TURNED M -> 'W' */ + { 0x9D, 0x4E }, /* LATIN CAPITAL LETTER N WITH LEFT HOOK -> 'N' */ + { 0x9E, 0x6E }, /* LATIN SMALL LETTER N WITH LONG RIGHT LEG -> 'n' */ + { 0x9F, 0x4F }, /* LATIN CAPITAL LETTER O WITH MIDDLE TILDE -> 'O' */ + { 0xA0, 0x4F }, /* LATIN CAPITAL LETTER O WITH HORN -> 'O' */ + { 0xA1, 0x6F }, /* LATIN SMALL LETTER O WITH HORN -> 'o' */ + { 0xA4, 0x50 }, /* LATIN CAPITAL LETTER P WITH HOOK -> 'P' */ + { 0xA5, 0x70 }, /* LATIN SMALL LETTER P WITH HOOK -> 'p' */ + { 0xA7, 0x32 }, /* LATIN CAPITAL LETTER TONE TWO -> '2' */ + { 0xA8, 0x32 }, /* LATIN SMALL LETTER TONE TWO -> '2' */ + { 0xAB, 0x74 }, /* LATIN SMALL LETTER T WITH PALATAL HOOK -> 't' */ + { 0xAC, 0x54 }, /* LATIN CAPITAL LETTER T WITH HOOK -> 'T' */ + { 0xAD, 0x74 }, /* LATIN SMALL LETTER T WITH HOOK -> 't' */ + { 0xAE, 0x54 }, /* LATIN CAPITAL LETTER T WITH RETROFLEX HOOK -> 'T' */ + { 0xAF, 0x55 }, /* LATIN CAPITAL LETTER U WITH HORN -> 'U' */ + { 0xB0, 0x75 }, /* LATIN SMALL LETTER U WITH HORN -> 'u' */ + { 0xB1, 0x59 }, /* LATIN CAPITAL LETTER UPSILON -> 'Y' */ + { 0xB2, 0x56 }, /* LATIN CAPITAL LETTER V WITH HOOK -> 'V' */ + { 0xB3, 0x59 }, /* LATIN CAPITAL LETTER Y WITH HOOK -> 'Y' */ + { 0xB4, 0x79 }, /* LATIN SMALL LETTER Y WITH HOOK -> 'y' */ + { 0xB5, 0x5A }, /* LATIN CAPITAL LETTER Z WITH STROKE -> 'Z' */ + { 0xB6, 0x7A }, /* LATIN SMALL LETTER Z WITH STROKE -> 'z' */ + { 0xBB, 0x32 }, /* LATIN LETTER TWO WITH STROKE -> '2' */ + { 0xBC, 0x35 }, /* LATIN CAPITAL LETTER TONE FIVE -> '5' */ + { 0xBD, 0x35 }, /* LATIN SMALL LETTER TONE FIVE -> '5' */ + { 0xBF, 0x77 }, /* LATIN LETTER WYNN -> 'w' */ + { 0xC0, 0x7C }, /* LATIN LETTER DENTAL CLICK -> '|' */ + { 0xC3, 0x21 }, /* LATIN LETTER RETROFLEX CLICK -> '!' */ + { 0xCD, 0x41 }, /* LATIN CAPITAL LETTER A WITH CARON -> 'A' */ + { 0xCE, 0x61 }, /* LATIN SMALL LETTER A WITH CARON -> 'a' */ + { 0xCF, 0x49 }, /* LATIN CAPITAL LETTER I WITH CARON -> 'I' */ + { 0xD0, 0x69 }, /* LATIN SMALL LETTER I WITH CARON -> 'i' */ + { 0xD1, 0x4F }, /* LATIN CAPITAL LETTER O WITH CARON -> 'O' */ + { 0xD2, 0x6F }, /* LATIN SMALL LETTER O WITH CARON -> 'o' */ + { 0xD3, 0x55 }, /* LATIN CAPITAL LETTER U WITH CARON -> 'U' */ + { 0xD4, 0x75 }, /* LATIN SMALL LETTER U WITH CARON -> 'u' */ + { 0xD5, 0x55 }, /* LATIN CAPITAL LETTER U WITH DIAERESIS AND MACRON -> 'U' */ + { 0xD6, 0x75 }, /* LATIN SMALL LETTER U WITH DIAERESIS AND MACRON -> 'u' */ + { 0xD7, 0x55 }, /* LATIN CAPITAL LETTER U WITH DIAERESIS AND ACUTE -> 'U' */ + { 0xD8, 0x75 }, /* LATIN SMALL LETTER U WITH DIAERESIS AND ACUTE -> 'u' */ + { 0xD9, 0x55 }, /* LATIN CAPITAL LETTER U WITH DIAERESIS AND CARON -> 'U' */ + { 0xDA, 0x75 }, /* LATIN SMALL LETTER U WITH DIAERESIS AND CARON -> 'u' */ + { 0xDB, 0x55 }, /* LATIN CAPITAL LETTER U WITH DIAERESIS AND GRAVE -> 'U' */ + { 0xDC, 0x75 }, /* LATIN SMALL LETTER U WITH DIAERESIS AND GRAVE -> 'u' */ + { 0xDD, 0x40 }, /* LATIN SMALL LETTER TURNED E -> '@' */ + { 0xDE, 0x41 }, /* LATIN CAPITAL LETTER A WITH DIAERESIS AND MACRON -> 'A' */ + { 0xDF, 0x61 }, /* LATIN SMALL LETTER A WITH DIAERESIS AND MACRON -> 'a' */ + { 0xE0, 0x41 }, /* LATIN CAPITAL LETTER A WITH DOT ABOVE AND MACRON -> 'A' */ + { 0xE1, 0x61 }, /* LATIN SMALL LETTER A WITH DOT ABOVE AND MACRON -> 'a' */ + { 0xE4, 0x47 }, /* LATIN CAPITAL LETTER G WITH STROKE -> 'G' */ + { 0xE5, 0x67 }, /* LATIN SMALL LETTER G WITH STROKE -> 'g' */ + { 0xE6, 0x47 }, /* LATIN CAPITAL LETTER G WITH CARON -> 'G' */ + { 0xE7, 0x67 }, /* LATIN SMALL LETTER G WITH CARON -> 'g' */ + { 0xE8, 0x4B }, /* LATIN CAPITAL LETTER K WITH CARON -> 'K' */ + { 0xE9, 0x6B }, /* LATIN SMALL LETTER K WITH CARON -> 'k' */ + { 0xEA, 0x4F }, /* LATIN CAPITAL LETTER O WITH OGONEK -> 'O' */ + { 0xEB, 0x6F }, /* LATIN SMALL LETTER O WITH OGONEK -> 'o' */ + { 0xEC, 0x4F }, /* LATIN CAPITAL LETTER O WITH OGONEK AND MACRON -> 'O' */ + { 0xED, 0x6F }, /* LATIN SMALL LETTER O WITH OGONEK AND MACRON -> 'o' */ + { 0xF0, 0x6A }, /* LATIN SMALL LETTER J WITH CARON -> 'j' */ + { 0xF4, 0x47 }, /* LATIN CAPITAL LETTER G WITH ACUTE -> 'G' */ + { 0xF5, 0x67 }, /* LATIN SMALL LETTER G WITH ACUTE -> 'g' */ + { 0xF7, 0x57 }, /* LATIN CAPITAL LETTER WYNN -> 'W' */ + { 0xF8, 0x4E }, /* LATIN CAPITAL LETTER N WITH GRAVE -> 'N' */ + { 0xF9, 0x6E }, /* LATIN SMALL LETTER N WITH GRAVE -> 'n' */ + { 0xFA, 0x41 }, /* LATIN CAPITAL LETTER A WITH RING ABOVE AND ACUTE -> 'A' */ + { 0xFB, 0x61 }, /* LATIN SMALL LETTER A WITH RING ABOVE AND ACUTE -> 'a' */ + { 0xFE, 0x4F }, /* LATIN CAPITAL LETTER O WITH STROKE AND ACUTE -> 'O' */ + { 0xFF, 0x6F }, /* LATIN SMALL LETTER O WITH STROKE AND ACUTE -> 'o' */ + /* Entries for page 0x02 */ + { 0x00, 0x41 }, /* LATIN CAPITAL LETTER A WITH DOUBLE GRAVE -> 'A' */ + { 0x01, 0x61 }, /* LATIN SMALL LETTER A WITH DOUBLE GRAVE -> 'a' */ + { 0x02, 0x41 }, /* LATIN CAPITAL LETTER A WITH INVERTED BREVE -> 'A' */ + { 0x03, 0x61 }, /* LATIN SMALL LETTER A WITH INVERTED BREVE -> 'a' */ + { 0x04, 0x45 }, /* LATIN CAPITAL LETTER E WITH DOUBLE GRAVE -> 'E' */ + { 0x05, 0x65 }, /* LATIN SMALL LETTER E WITH DOUBLE GRAVE -> 'e' */ + { 0x06, 0x45 }, /* LATIN CAPITAL LETTER E WITH INVERTED BREVE -> 'E' */ + { 0x07, 0x65 }, /* LATIN SMALL LETTER E WITH INVERTED BREVE -> 'e' */ + { 0x08, 0x49 }, /* LATIN CAPITAL LETTER I WITH DOUBLE GRAVE -> 'I' */ + { 0x09, 0x69 }, /* LATIN SMALL LETTER I WITH DOUBLE GRAVE -> 'i' */ + { 0x0A, 0x49 }, /* LATIN CAPITAL LETTER I WITH INVERTED BREVE -> 'I' */ + { 0x0B, 0x69 }, /* LATIN SMALL LETTER I WITH INVERTED BREVE -> 'i' */ + { 0x0C, 0x4F }, /* LATIN CAPITAL LETTER O WITH DOUBLE GRAVE -> 'O' */ + { 0x0D, 0x6F }, /* LATIN SMALL LETTER O WITH DOUBLE GRAVE -> 'o' */ + { 0x0E, 0x4F }, /* LATIN CAPITAL LETTER O WITH INVERTED BREVE -> 'O' */ + { 0x0F, 0x6F }, /* LATIN SMALL LETTER O WITH INVERTED BREVE -> 'o' */ + { 0x10, 0x52 }, /* LATIN CAPITAL LETTER R WITH DOUBLE GRAVE -> 'R' */ + { 0x11, 0x72 }, /* LATIN SMALL LETTER R WITH DOUBLE GRAVE -> 'r' */ + { 0x12, 0x52 }, /* LATIN CAPITAL LETTER R WITH INVERTED BREVE -> 'R' */ + { 0x13, 0x72 }, /* LATIN SMALL LETTER R WITH INVERTED BREVE -> 'r' */ + { 0x14, 0x55 }, /* LATIN CAPITAL LETTER U WITH DOUBLE GRAVE -> 'U' */ + { 0x15, 0x75 }, /* LATIN SMALL LETTER U WITH DOUBLE GRAVE -> 'u' */ + { 0x16, 0x55 }, /* LATIN CAPITAL LETTER U WITH INVERTED BREVE -> 'U' */ + { 0x17, 0x75 }, /* LATIN SMALL LETTER U WITH INVERTED BREVE -> 'u' */ + { 0x18, 0x53 }, /* LATIN CAPITAL LETTER S WITH COMMA BELOW -> 'S' */ + { 0x19, 0x73 }, /* LATIN SMALL LETTER S WITH COMMA BELOW -> 's' */ + { 0x1A, 0x54 }, /* LATIN CAPITAL LETTER T WITH COMMA BELOW -> 'T' */ + { 0x1B, 0x74 }, /* LATIN SMALL LETTER T WITH COMMA BELOW -> 't' */ + { 0x1C, 0x59 }, /* LATIN CAPITAL LETTER YOGH -> 'Y' */ + { 0x1D, 0x79 }, /* LATIN SMALL LETTER YOGH -> 'y' */ + { 0x1E, 0x48 }, /* LATIN CAPITAL LETTER H WITH CARON -> 'H' */ + { 0x1F, 0x68 }, /* LATIN SMALL LETTER H WITH CARON -> 'h' */ + { 0x20, 0x4E }, /* LATIN CAPITAL LETTER N WITH LONG RIGHT LEG -> 'N' */ + { 0x21, 0x64 }, /* LATIN SMALL LETTER D WITH CURL -> 'd' */ + { 0x24, 0x5A }, /* LATIN CAPITAL LETTER Z WITH HOOK -> 'Z' */ + { 0x25, 0x7A }, /* LATIN SMALL LETTER Z WITH HOOK -> 'z' */ + { 0x26, 0x41 }, /* LATIN CAPITAL LETTER A WITH DOT ABOVE -> 'A' */ + { 0x27, 0x61 }, /* LATIN SMALL LETTER A WITH DOT ABOVE -> 'a' */ + { 0x28, 0x45 }, /* LATIN CAPITAL LETTER E WITH CEDILLA -> 'E' */ + { 0x29, 0x65 }, /* LATIN SMALL LETTER E WITH CEDILLA -> 'e' */ + { 0x2A, 0x4F }, /* LATIN CAPITAL LETTER O WITH DIAERESIS AND MACRON -> 'O' */ + { 0x2B, 0x6F }, /* LATIN SMALL LETTER O WITH DIAERESIS AND MACRON -> 'o' */ + { 0x2C, 0x4F }, /* LATIN CAPITAL LETTER O WITH TILDE AND MACRON -> 'O' */ + { 0x2D, 0x6F }, /* LATIN SMALL LETTER O WITH TILDE AND MACRON -> 'o' */ + { 0x2E, 0x4F }, /* LATIN CAPITAL LETTER O WITH DOT ABOVE -> 'O' */ + { 0x2F, 0x6F }, /* LATIN SMALL LETTER O WITH DOT ABOVE -> 'o' */ + { 0x30, 0x4F }, /* LATIN CAPITAL LETTER O WITH DOT ABOVE AND MACRON -> 'O' */ + { 0x31, 0x6F }, /* LATIN SMALL LETTER O WITH DOT ABOVE AND MACRON -> 'o' */ + { 0x32, 0x59 }, /* LATIN CAPITAL LETTER Y WITH MACRON -> 'Y' */ + { 0x33, 0x79 }, /* LATIN SMALL LETTER Y WITH MACRON -> 'y' */ + { 0x34, 0x6C }, /* LATIN SMALL LETTER L WITH CURL -> 'l' */ + { 0x35, 0x6E }, /* LATIN SMALL LETTER N WITH CURL -> 'n' */ + { 0x36, 0x74 }, /* LATIN SMALL LETTER T WITH CURL -> 't' */ + { 0x37, 0x6A }, /* LATIN SMALL LETTER DOTLESS J -> 'j' */ + { 0x3A, 0x41 }, /* LATIN CAPITAL LETTER A WITH STROKE -> 'A' */ + { 0x3B, 0x43 }, /* LATIN CAPITAL LETTER C WITH STROKE -> 'C' */ + { 0x3C, 0x63 }, /* LATIN SMALL LETTER C WITH STROKE -> 'c' */ + { 0x3D, 0x4C }, /* LATIN CAPITAL LETTER L WITH BAR -> 'L' */ + { 0x3E, 0x54 }, /* LATIN CAPITAL LETTER T WITH DIAGONAL STROKE -> 'T' */ + { 0x3F, 0x73 }, /* LATIN SMALL LETTER S WITH SWASH TAIL -> 's' */ + { 0x40, 0x7A }, /* LATIN SMALL LETTER Z WITH SWASH TAIL -> 'z' */ + { 0x43, 0x42 }, /* LATIN CAPITAL LETTER B WITH STROKE -> 'B' */ + { 0x44, 0x55 }, /* LATIN CAPITAL LETTER U BAR -> 'U' */ + { 0x45, 0x5E }, /* LATIN CAPITAL LETTER TURNED V -> '^' */ + { 0x46, 0x45 }, /* LATIN CAPITAL LETTER E WITH STROKE -> 'E' */ + { 0x47, 0x65 }, /* LATIN SMALL LETTER E WITH STROKE -> 'e' */ + { 0x48, 0x4A }, /* LATIN CAPITAL LETTER J WITH STROKE -> 'J' */ + { 0x49, 0x6A }, /* LATIN SMALL LETTER J WITH STROKE -> 'j' */ + { 0x4A, 0x71 }, /* LATIN CAPITAL LETTER SMALL Q WITH HOOK TAIL -> 'q' */ + { 0x4B, 0x71 }, /* LATIN SMALL LETTER Q WITH HOOK TAIL -> 'q' */ + { 0x4C, 0x52 }, /* LATIN CAPITAL LETTER R WITH STROKE -> 'R' */ + { 0x4D, 0x72 }, /* LATIN SMALL LETTER R WITH STROKE -> 'r' */ + { 0x4E, 0x59 }, /* LATIN CAPITAL LETTER Y WITH STROKE -> 'Y' */ + { 0x4F, 0x79 }, /* LATIN SMALL LETTER Y WITH STROKE -> 'y' */ + { 0x50, 0x00 }, /* LATIN SMALL LETTER TURNED A -> ... */ + { 0x52, 0x61 }, /* LATIN SMALL LETTER TURNED ALPHA -> 'a' */ + { 0x53, 0x62 }, /* LATIN SMALL LETTER B WITH HOOK -> 'b' */ + { 0x54, 0x6F }, /* LATIN SMALL LETTER OPEN O -> 'o' */ + { 0x55, 0x63 }, /* LATIN SMALL LETTER C WITH CURL -> 'c' */ + { 0x56, 0x64 }, /* LATIN SMALL LETTER D WITH TAIL -> 'd' */ + { 0x57, 0x64 }, /* LATIN SMALL LETTER D WITH HOOK -> 'd' */ + { 0x58, 0x65 }, /* LATIN SMALL LETTER REVERSED E -> 'e' */ + { 0x59, 0x40 }, /* LATIN SMALL LETTER SCHWA -> '@' */ + { 0x5A, 0x40 }, /* LATIN SMALL LETTER SCHWA WITH HOOK -> '@' */ + { 0x5B, 0x00 }, /* LATIN SMALL LETTER OPEN E -> ... */ + { 0x5E, 0x65 }, /* LATIN SMALL LETTER CLOSED REVERSED OPEN E -> 'e' */ + { 0x5F, 0x6A }, /* LATIN SMALL LETTER DOTLESS J WITH STROKE -> 'j' */ + { 0x60, 0x00 }, /* LATIN SMALL LETTER G WITH HOOK -> ... */ + { 0x63, 0x67 }, /* LATIN SMALL LETTER GAMMA -> 'g' */ + { 0x64, 0x75 }, /* LATIN SMALL LETTER RAMS HORN -> 'u' */ + { 0x65, 0x59 }, /* LATIN SMALL LETTER TURNED H -> 'Y' */ + { 0x66, 0x68 }, /* LATIN SMALL LETTER H WITH HOOK -> 'h' */ + { 0x67, 0x68 }, /* LATIN SMALL LETTER HENG WITH HOOK -> 'h' */ + { 0x68, 0x69 }, /* LATIN SMALL LETTER I WITH STROKE -> 'i' */ + { 0x69, 0x69 }, /* LATIN SMALL LETTER IOTA -> 'i' */ + { 0x6A, 0x49 }, /* LATIN LETTER SMALL CAPITAL I -> 'I' */ + { 0x6B, 0x00 }, /* LATIN SMALL LETTER L WITH MIDDLE TILDE -> ... */ + { 0x6D, 0x6C }, /* LATIN SMALL LETTER L WITH RETROFLEX HOOK -> 'l' */ + { 0x6F, 0x57 }, /* LATIN SMALL LETTER TURNED M -> 'W' */ + { 0x70, 0x57 }, /* LATIN SMALL LETTER TURNED M WITH LONG LEG -> 'W' */ + { 0x71, 0x6D }, /* LATIN SMALL LETTER M WITH HOOK -> 'm' */ + { 0x72, 0x00 }, /* LATIN SMALL LETTER N WITH LEFT HOOK -> ... */ + { 0x74, 0x6E }, /* LATIN LETTER SMALL CAPITAL N -> 'n' */ + { 0x75, 0x6F }, /* LATIN SMALL LETTER BARRED O -> 'o' */ + { 0x77, 0x4F }, /* LATIN SMALL LETTER CLOSED OMEGA -> 'O' */ + { 0x78, 0x46 }, /* LATIN SMALL LETTER PHI -> 'F' */ + { 0x79, 0x00 }, /* LATIN SMALL LETTER TURNED R -> ... */ + { 0x7F, 0x72 }, /* LATIN SMALL LETTER REVERSED R WITH FISHHOOK -> 'r' */ + { 0x80, 0x52 }, /* LATIN LETTER SMALL CAPITAL R -> 'R' */ + { 0x81, 0x52 }, /* LATIN LETTER SMALL CAPITAL INVERTED R -> 'R' */ + { 0x82, 0x73 }, /* LATIN SMALL LETTER S WITH HOOK -> 's' */ + { 0x83, 0x53 }, /* LATIN SMALL LETTER ESH -> 'S' */ + { 0x84, 0x6A }, /* LATIN SMALL LETTER DOTLESS J WITH STROKE AND HOOK -> 'j' */ + { 0x85, 0x53 }, /* LATIN SMALL LETTER SQUAT REVERSED ESH -> 'S' */ + { 0x86, 0x53 }, /* LATIN SMALL LETTER ESH WITH CURL -> 'S' */ + { 0x87, 0x74 }, /* LATIN SMALL LETTER TURNED T -> 't' */ + { 0x88, 0x74 }, /* LATIN SMALL LETTER T WITH RETROFLEX HOOK -> 't' */ + { 0x89, 0x75 }, /* LATIN SMALL LETTER U BAR -> 'u' */ + { 0x8A, 0x55 }, /* LATIN SMALL LETTER UPSILON -> 'U' */ + { 0x8B, 0x76 }, /* LATIN SMALL LETTER V WITH HOOK -> 'v' */ + { 0x8C, 0x5E }, /* LATIN SMALL LETTER TURNED V -> '^' */ + { 0x8D, 0x77 }, /* LATIN SMALL LETTER TURNED W -> 'w' */ + { 0x8E, 0x79 }, /* LATIN SMALL LETTER TURNED Y -> 'y' */ + { 0x8F, 0x59 }, /* LATIN LETTER SMALL CAPITAL Y -> 'Y' */ + { 0x90, 0x7A }, /* LATIN SMALL LETTER Z WITH RETROFLEX HOOK -> 'z' */ + { 0x91, 0x7A }, /* LATIN SMALL LETTER Z WITH CURL -> 'z' */ + { 0x92, 0x5A }, /* LATIN SMALL LETTER EZH -> 'Z' */ + { 0x93, 0x5A }, /* LATIN SMALL LETTER EZH WITH CURL -> 'Z' */ + { 0x94, 0x00 }, /* LATIN LETTER GLOTTAL STOP -> ... */ + { 0x96, 0x3F }, /* LATIN LETTER INVERTED GLOTTAL STOP -> '?' */ + { 0x97, 0x43 }, /* LATIN LETTER STRETCHED C -> 'C' */ + { 0x98, 0x40 }, /* LATIN LETTER BILABIAL CLICK -> '@' */ + { 0x99, 0x42 }, /* LATIN LETTER SMALL CAPITAL B -> 'B' */ + { 0x9A, 0x45 }, /* LATIN SMALL LETTER CLOSED OPEN E -> 'E' */ + { 0x9B, 0x47 }, /* LATIN LETTER SMALL CAPITAL G WITH HOOK -> 'G' */ + { 0x9C, 0x48 }, /* LATIN LETTER SMALL CAPITAL H -> 'H' */ + { 0x9D, 0x6A }, /* LATIN SMALL LETTER J WITH CROSSED-TAIL -> 'j' */ + { 0x9E, 0x6B }, /* LATIN SMALL LETTER TURNED K -> 'k' */ + { 0x9F, 0x4C }, /* LATIN LETTER SMALL CAPITAL L -> 'L' */ + { 0xA0, 0x71 }, /* LATIN SMALL LETTER Q WITH HOOK -> 'q' */ + { 0xA1, 0x3F }, /* LATIN LETTER GLOTTAL STOP WITH STROKE -> '?' */ + { 0xA2, 0x3F }, /* LATIN LETTER REVERSED GLOTTAL STOP WITH STROKE -> '?' */ + { 0xAE, 0x00 }, /* LATIN SMALL LETTER TURNED H WITH FISHHOOK -> ... */ + { 0xB1, 0x68 }, /* MODIFIER LETTER SMALL H WITH HOOK -> 'h' */ + { 0xB2, 0x6A }, /* MODIFIER LETTER SMALL J -> 'j' */ + { 0xB3, 0x00 }, /* MODIFIER LETTER SMALL R -> ... */ + { 0xB6, 0x72 }, /* MODIFIER LETTER SMALL CAPITAL INVERTED R -> 'r' */ + { 0xB7, 0x77 }, /* MODIFIER LETTER SMALL W -> 'w' */ + { 0xB8, 0x79 }, /* MODIFIER LETTER SMALL Y -> 'y' */ + { 0xB9, 0x27 }, /* MODIFIER LETTER PRIME -> ''' */ + { 0xBA, 0x22 }, /* MODIFIER LETTER DOUBLE PRIME -> '"' */ + { 0xBB, 0x60 }, /* MODIFIER LETTER TURNED COMMA -> '`' */ + { 0xBC, 0x27 }, /* MODIFIER LETTER APOSTROPHE -> ''' */ + { 0xBD, 0x60 }, /* MODIFIER LETTER REVERSED COMMA -> '`' */ + { 0xBE, 0x60 }, /* MODIFIER LETTER RIGHT HALF RING -> '`' */ + { 0xBF, 0x27 }, /* MODIFIER LETTER LEFT HALF RING -> ''' */ + { 0xC0, 0x3F }, /* MODIFIER LETTER GLOTTAL STOP -> '?' */ + { 0xC1, 0x3F }, /* MODIFIER LETTER REVERSED GLOTTAL STOP -> '?' */ + { 0xC2, 0x3C }, /* MODIFIER LETTER LEFT ARROWHEAD -> '<' */ + { 0xC3, 0x3E }, /* MODIFIER LETTER RIGHT ARROWHEAD -> '>' */ + { 0xC4, 0x5E }, /* MODIFIER LETTER UP ARROWHEAD -> '^' */ + { 0xC5, 0x56 }, /* MODIFIER LETTER DOWN ARROWHEAD -> 'V' */ + { 0xC6, 0x5E }, /* MODIFIER LETTER CIRCUMFLEX ACCENT -> '^' */ + { 0xC7, 0x56 }, /* CARON -> 'V' */ + { 0xC8, 0x27 }, /* MODIFIER LETTER VERTICAL LINE -> ''' */ + { 0xC9, 0x2D }, /* MODIFIER LETTER MACRON -> '-' */ + { 0xCA, 0x2F }, /* MODIFIER LETTER ACUTE ACCENT -> '/' */ + { 0xCB, 0x5C }, /* MODIFIER LETTER GRAVE ACCENT -> '\' */ + { 0xCC, 0x2C }, /* MODIFIER LETTER LOW VERTICAL LINE -> ',' */ + { 0xCD, 0x5F }, /* MODIFIER LETTER LOW MACRON -> '_' */ + { 0xCE, 0x5C }, /* MODIFIER LETTER LOW GRAVE ACCENT -> '\' */ + { 0xCF, 0x2F }, /* MODIFIER LETTER LOW ACUTE ACCENT -> '/' */ + { 0xD0, 0x3A }, /* MODIFIER LETTER TRIANGULAR COLON -> ':' */ + { 0xD1, 0x2E }, /* MODIFIER LETTER HALF TRIANGULAR COLON -> '.' */ + { 0xD2, 0x60 }, /* MODIFIER LETTER CENTRED RIGHT HALF RING -> '`' */ + { 0xD3, 0x27 }, /* MODIFIER LETTER CENTRED LEFT HALF RING -> ''' */ + { 0xD4, 0x5E }, /* MODIFIER LETTER UP TACK -> '^' */ + { 0xD5, 0x56 }, /* MODIFIER LETTER DOWN TACK -> 'V' */ + { 0xD6, 0x2B }, /* MODIFIER LETTER PLUS SIGN -> '+' */ + { 0xD7, 0x2D }, /* MODIFIER LETTER MINUS SIGN -> '-' */ + { 0xD8, 0x56 }, /* BREVE -> 'V' */ + { 0xD9, 0x2E }, /* DOT ABOVE -> '.' */ + { 0xDA, 0x40 }, /* RING ABOVE -> '@' */ + { 0xDB, 0x2C }, /* OGONEK -> ',' */ + { 0xDC, 0x7E }, /* SMALL TILDE -> '~' */ + { 0xDD, 0x22 }, /* DOUBLE ACUTE ACCENT -> '"' */ + { 0xDE, 0x52 }, /* MODIFIER LETTER RHOTIC HOOK -> 'R' */ + { 0xDF, 0x58 }, /* MODIFIER LETTER CROSS ACCENT -> 'X' */ + { 0xE0, 0x47 }, /* MODIFIER LETTER SMALL GAMMA -> 'G' */ + { 0xE1, 0x6C }, /* MODIFIER LETTER SMALL L -> 'l' */ + { 0xE2, 0x73 }, /* MODIFIER LETTER SMALL S -> 's' */ + { 0xE3, 0x78 }, /* MODIFIER LETTER SMALL X -> 'x' */ + { 0xE4, 0x3F }, /* MODIFIER LETTER SMALL REVERSED GLOTTAL STOP -> '?' */ + { 0xEC, 0x56 }, /* MODIFIER LETTER VOICING -> 'V' */ + { 0xED, 0x3D }, /* MODIFIER LETTER UNASPIRATED -> '=' */ + { 0xEE, 0x22 }, /* MODIFIER LETTER DOUBLE APOSTROPHE -> '"' */ + /* Entries for page 0x03 */ + { 0x63, 0x61 }, /* COMBINING LATIN SMALL LETTER A -> 'a' */ + { 0x64, 0x65 }, /* COMBINING LATIN SMALL LETTER E -> 'e' */ + { 0x65, 0x69 }, /* COMBINING LATIN SMALL LETTER I -> 'i' */ + { 0x66, 0x6F }, /* COMBINING LATIN SMALL LETTER O -> 'o' */ + { 0x67, 0x75 }, /* COMBINING LATIN SMALL LETTER U -> 'u' */ + { 0x68, 0x63 }, /* COMBINING LATIN SMALL LETTER C -> 'c' */ + { 0x69, 0x64 }, /* COMBINING LATIN SMALL LETTER D -> 'd' */ + { 0x6A, 0x68 }, /* COMBINING LATIN SMALL LETTER H -> 'h' */ + { 0x6B, 0x6D }, /* COMBINING LATIN SMALL LETTER M -> 'm' */ + { 0x6C, 0x72 }, /* COMBINING LATIN SMALL LETTER R -> 'r' */ + { 0x6D, 0x74 }, /* COMBINING LATIN SMALL LETTER T -> 't' */ + { 0x6E, 0x76 }, /* COMBINING LATIN SMALL LETTER V -> 'v' */ + { 0x6F, 0x78 }, /* COMBINING LATIN SMALL LETTER X -> 'x' */ + { 0x74, 0x27 }, /* GREEK NUMERAL SIGN -> ''' */ + { 0x75, 0x2C }, /* GREEK LOWER NUMERAL SIGN -> ',' */ + { 0x7E, 0x3F }, /* GREEK QUESTION MARK -> '?' */ + { 0x86, 0x41 }, /* GREEK CAPITAL LETTER ALPHA WITH TONOS -> 'A' */ + { 0x87, 0x3B }, /* GREEK ANO TELEIA -> ';' */ + { 0x88, 0x45 }, /* GREEK CAPITAL LETTER EPSILON WITH TONOS -> 'E' */ + { 0x89, 0x45 }, /* GREEK CAPITAL LETTER ETA WITH TONOS -> 'E' */ + { 0x8A, 0x49 }, /* GREEK CAPITAL LETTER IOTA WITH TONOS -> 'I' */ + { 0x8C, 0x4F }, /* GREEK CAPITAL LETTER OMICRON WITH TONOS -> 'O' */ + { 0x8E, 0x55 }, /* GREEK CAPITAL LETTER UPSILON WITH TONOS -> 'U' */ + { 0x8F, 0x4F }, /* GREEK CAPITAL LETTER OMEGA WITH TONOS -> 'O' */ + { 0x90, 0x49 }, /* GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS -> 'I' */ + { 0x91, 0x41 }, /* GREEK CAPITAL LETTER ALPHA -> 'A' */ + { 0x92, 0x42 }, /* GREEK CAPITAL LETTER BETA -> 'B' */ + { 0x93, 0x47 }, /* GREEK CAPITAL LETTER GAMMA -> 'G' */ + { 0x94, 0x44 }, /* GREEK CAPITAL LETTER DELTA -> 'D' */ + { 0x95, 0x45 }, /* GREEK CAPITAL LETTER EPSILON -> 'E' */ + { 0x96, 0x5A }, /* GREEK CAPITAL LETTER ZETA -> 'Z' */ + { 0x97, 0x45 }, /* GREEK CAPITAL LETTER ETA -> 'E' */ + { 0x99, 0x49 }, /* GREEK CAPITAL LETTER IOTA -> 'I' */ + { 0x9A, 0x4B }, /* GREEK CAPITAL LETTER KAPPA -> 'K' */ + { 0x9B, 0x4C }, /* GREEK CAPITAL LETTER LAMDA -> 'L' */ + { 0x9C, 0x4D }, /* GREEK CAPITAL LETTER MU -> 'M' */ + { 0x9D, 0x4E }, /* GREEK CAPITAL LETTER NU -> 'N' */ + { 0x9F, 0x4F }, /* GREEK CAPITAL LETTER OMICRON -> 'O' */ + { 0xA0, 0x50 }, /* GREEK CAPITAL LETTER PI -> 'P' */ + { 0xA1, 0x52 }, /* GREEK CAPITAL LETTER RHO -> 'R' */ + { 0xA3, 0x53 }, /* GREEK CAPITAL LETTER SIGMA -> 'S' */ + { 0xA4, 0x54 }, /* GREEK CAPITAL LETTER TAU -> 'T' */ + { 0xA5, 0x55 }, /* GREEK CAPITAL LETTER UPSILON -> 'U' */ + { 0xA9, 0x4F }, /* GREEK CAPITAL LETTER OMEGA -> 'O' */ + { 0xAA, 0x49 }, /* GREEK CAPITAL LETTER IOTA WITH DIALYTIKA -> 'I' */ + { 0xAB, 0x55 }, /* GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA -> 'U' */ + { 0xAC, 0x61 }, /* GREEK SMALL LETTER ALPHA WITH TONOS -> 'a' */ + { 0xAD, 0x65 }, /* GREEK SMALL LETTER EPSILON WITH TONOS -> 'e' */ + { 0xAE, 0x65 }, /* GREEK SMALL LETTER ETA WITH TONOS -> 'e' */ + { 0xAF, 0x69 }, /* GREEK SMALL LETTER IOTA WITH TONOS -> 'i' */ + { 0xB0, 0x75 }, /* GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS -> 'u' */ + { 0xB1, 0x61 }, /* GREEK SMALL LETTER ALPHA -> 'a' */ + { 0xB2, 0x62 }, /* GREEK SMALL LETTER BETA -> 'b' */ + { 0xB3, 0x67 }, /* GREEK SMALL LETTER GAMMA -> 'g' */ + { 0xB4, 0x64 }, /* GREEK SMALL LETTER DELTA -> 'd' */ + { 0xB5, 0x65 }, /* GREEK SMALL LETTER EPSILON -> 'e' */ + { 0xB6, 0x7A }, /* GREEK SMALL LETTER ZETA -> 'z' */ + { 0xB7, 0x65 }, /* GREEK SMALL LETTER ETA -> 'e' */ + { 0xB9, 0x69 }, /* GREEK SMALL LETTER IOTA -> 'i' */ + { 0xBA, 0x6B }, /* GREEK SMALL LETTER KAPPA -> 'k' */ + { 0xBB, 0x6C }, /* GREEK SMALL LETTER LAMDA -> 'l' */ + { 0xBC, 0x6D }, /* GREEK SMALL LETTER MU -> 'm' */ + { 0xBD, 0x6E }, /* GREEK SMALL LETTER NU -> 'n' */ + { 0xBE, 0x78 }, /* GREEK SMALL LETTER XI -> 'x' */ + { 0xBF, 0x6F }, /* GREEK SMALL LETTER OMICRON -> 'o' */ + { 0xC0, 0x70 }, /* GREEK SMALL LETTER PI -> 'p' */ + { 0xC1, 0x72 }, /* GREEK SMALL LETTER RHO -> 'r' */ + { 0xC2, 0x73 }, /* GREEK SMALL LETTER FINAL SIGMA -> 's' */ + { 0xC3, 0x73 }, /* GREEK SMALL LETTER SIGMA -> 's' */ + { 0xC4, 0x74 }, /* GREEK SMALL LETTER TAU -> 't' */ + { 0xC5, 0x75 }, /* GREEK SMALL LETTER UPSILON -> 'u' */ + { 0xC9, 0x6F }, /* GREEK SMALL LETTER OMEGA -> 'o' */ + { 0xCA, 0x69 }, /* GREEK SMALL LETTER IOTA WITH DIALYTIKA -> 'i' */ + { 0xCB, 0x75 }, /* GREEK SMALL LETTER UPSILON WITH DIALYTIKA -> 'u' */ + { 0xCC, 0x6F }, /* GREEK SMALL LETTER OMICRON WITH TONOS -> 'o' */ + { 0xCD, 0x75 }, /* GREEK SMALL LETTER UPSILON WITH TONOS -> 'u' */ + { 0xCE, 0x6F }, /* GREEK SMALL LETTER OMEGA WITH TONOS -> 'o' */ + { 0xD0, 0x62 }, /* GREEK BETA SYMBOL -> 'b' */ + { 0xD2, 0x00 }, /* GREEK UPSILON WITH HOOK SYMBOL -> ... */ + { 0xD4, 0x55 }, /* GREEK UPSILON WITH DIAERESIS AND HOOK SYMBOL -> 'U' */ + { 0xD6, 0x70 }, /* GREEK PI SYMBOL -> 'p' */ + { 0xD7, 0x26 }, /* GREEK KAI SYMBOL -> '&' */ + { 0xDC, 0x57 }, /* GREEK LETTER DIGAMMA -> 'W' */ + { 0xDD, 0x77 }, /* GREEK SMALL LETTER DIGAMMA -> 'w' */ + { 0xDE, 0x51 }, /* GREEK LETTER KOPPA -> 'Q' */ + { 0xDF, 0x71 }, /* GREEK SMALL LETTER KOPPA -> 'q' */ + { 0xE4, 0x46 }, /* COPTIC CAPITAL LETTER FEI -> 'F' */ + { 0xE5, 0x66 }, /* COPTIC SMALL LETTER FEI -> 'f' */ + { 0xE8, 0x48 }, /* COPTIC CAPITAL LETTER HORI -> 'H' */ + { 0xE9, 0x68 }, /* COPTIC SMALL LETTER HORI -> 'h' */ + { 0xEA, 0x47 }, /* COPTIC CAPITAL LETTER GANGIA -> 'G' */ + { 0xEB, 0x67 }, /* COPTIC SMALL LETTER GANGIA -> 'g' */ + { 0xF0, 0x6B }, /* GREEK KAPPA SYMBOL -> 'k' */ + { 0xF1, 0x72 }, /* GREEK RHO SYMBOL -> 'r' */ + { 0xF2, 0x63 }, /* GREEK LUNATE SIGMA SYMBOL -> 'c' */ + { 0xF3, 0x6A }, /* GREEK LETTER YOT -> 'j' */ + /* Entries for page 0x04 */ + { 0x06, 0x49 }, /* CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I -> 'I' */ + { 0x08, 0x4A }, /* CYRILLIC CAPITAL LETTER JE -> 'J' */ + { 0x0D, 0x49 }, /* CYRILLIC CAPITAL LETTER I WITH GRAVE -> 'I' */ + { 0x0E, 0x55 }, /* CYRILLIC CAPITAL LETTER SHORT U -> 'U' */ + { 0x10, 0x41 }, /* CYRILLIC CAPITAL LETTER A -> 'A' */ + { 0x11, 0x42 }, /* CYRILLIC CAPITAL LETTER BE -> 'B' */ + { 0x12, 0x56 }, /* CYRILLIC CAPITAL LETTER VE -> 'V' */ + { 0x13, 0x47 }, /* CYRILLIC CAPITAL LETTER GHE -> 'G' */ + { 0x14, 0x44 }, /* CYRILLIC CAPITAL LETTER DE -> 'D' */ + { 0x15, 0x45 }, /* CYRILLIC CAPITAL LETTER IE -> 'E' */ + { 0x17, 0x5A }, /* CYRILLIC CAPITAL LETTER ZE -> 'Z' */ + { 0x18, 0x49 }, /* CYRILLIC CAPITAL LETTER I -> 'I' */ + { 0x19, 0x49 }, /* CYRILLIC CAPITAL LETTER SHORT I -> 'I' */ + { 0x1A, 0x4B }, /* CYRILLIC CAPITAL LETTER KA -> 'K' */ + { 0x1B, 0x4C }, /* CYRILLIC CAPITAL LETTER EL -> 'L' */ + { 0x1C, 0x4D }, /* CYRILLIC CAPITAL LETTER EM -> 'M' */ + { 0x1D, 0x4E }, /* CYRILLIC CAPITAL LETTER EN -> 'N' */ + { 0x1E, 0x4F }, /* CYRILLIC CAPITAL LETTER O -> 'O' */ + { 0x1F, 0x50 }, /* CYRILLIC CAPITAL LETTER PE -> 'P' */ + { 0x20, 0x52 }, /* CYRILLIC CAPITAL LETTER ER -> 'R' */ + { 0x21, 0x53 }, /* CYRILLIC CAPITAL LETTER ES -> 'S' */ + { 0x22, 0x54 }, /* CYRILLIC CAPITAL LETTER TE -> 'T' */ + { 0x23, 0x55 }, /* CYRILLIC CAPITAL LETTER U -> 'U' */ + { 0x24, 0x46 }, /* CYRILLIC CAPITAL LETTER EF -> 'F' */ + { 0x2A, 0x27 }, /* CYRILLIC CAPITAL LETTER HARD SIGN -> ''' */ + { 0x2B, 0x59 }, /* CYRILLIC CAPITAL LETTER YERU -> 'Y' */ + { 0x2C, 0x27 }, /* CYRILLIC CAPITAL LETTER SOFT SIGN -> ''' */ + { 0x2D, 0x45 }, /* CYRILLIC CAPITAL LETTER E -> 'E' */ + { 0x30, 0x61 }, /* CYRILLIC SMALL LETTER A -> 'a' */ + { 0x31, 0x62 }, /* CYRILLIC SMALL LETTER BE -> 'b' */ + { 0x32, 0x76 }, /* CYRILLIC SMALL LETTER VE -> 'v' */ + { 0x33, 0x67 }, /* CYRILLIC SMALL LETTER GHE -> 'g' */ + { 0x34, 0x64 }, /* CYRILLIC SMALL LETTER DE -> 'd' */ + { 0x35, 0x65 }, /* CYRILLIC SMALL LETTER IE -> 'e' */ + { 0x37, 0x7A }, /* CYRILLIC SMALL LETTER ZE -> 'z' */ + { 0x38, 0x69 }, /* CYRILLIC SMALL LETTER I -> 'i' */ + { 0x39, 0x69 }, /* CYRILLIC SMALL LETTER SHORT I -> 'i' */ + { 0x3A, 0x6B }, /* CYRILLIC SMALL LETTER KA -> 'k' */ + { 0x3B, 0x6C }, /* CYRILLIC SMALL LETTER EL -> 'l' */ + { 0x3C, 0x6D }, /* CYRILLIC SMALL LETTER EM -> 'm' */ + { 0x3D, 0x6E }, /* CYRILLIC SMALL LETTER EN -> 'n' */ + { 0x3E, 0x6F }, /* CYRILLIC SMALL LETTER O -> 'o' */ + { 0x3F, 0x70 }, /* CYRILLIC SMALL LETTER PE -> 'p' */ + { 0x40, 0x72 }, /* CYRILLIC SMALL LETTER ER -> 'r' */ + { 0x41, 0x73 }, /* CYRILLIC SMALL LETTER ES -> 's' */ + { 0x42, 0x74 }, /* CYRILLIC SMALL LETTER TE -> 't' */ + { 0x43, 0x75 }, /* CYRILLIC SMALL LETTER U -> 'u' */ + { 0x44, 0x66 }, /* CYRILLIC SMALL LETTER EF -> 'f' */ + { 0x4A, 0x27 }, /* CYRILLIC SMALL LETTER HARD SIGN -> ''' */ + { 0x4B, 0x79 }, /* CYRILLIC SMALL LETTER YERU -> 'y' */ + { 0x4C, 0x27 }, /* CYRILLIC SMALL LETTER SOFT SIGN -> ''' */ + { 0x4D, 0x65 }, /* CYRILLIC SMALL LETTER E -> 'e' */ + { 0x56, 0x69 }, /* CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I -> 'i' */ + { 0x58, 0x6A }, /* CYRILLIC SMALL LETTER JE -> 'j' */ + { 0x5D, 0x69 }, /* CYRILLIC SMALL LETTER I WITH GRAVE -> 'i' */ + { 0x5E, 0x75 }, /* CYRILLIC SMALL LETTER SHORT U -> 'u' */ + { 0x60, 0x4F }, /* CYRILLIC CAPITAL LETTER OMEGA -> 'O' */ + { 0x61, 0x6F }, /* CYRILLIC SMALL LETTER OMEGA -> 'o' */ + { 0x62, 0x45 }, /* CYRILLIC CAPITAL LETTER YAT -> 'E' */ + { 0x63, 0x65 }, /* CYRILLIC SMALL LETTER YAT -> 'e' */ + { 0x66, 0x45 }, /* CYRILLIC CAPITAL LETTER LITTLE YUS -> 'E' */ + { 0x67, 0x65 }, /* CYRILLIC SMALL LETTER LITTLE YUS -> 'e' */ + { 0x6A, 0x4F }, /* CYRILLIC CAPITAL LETTER BIG YUS -> 'O' */ + { 0x6B, 0x6F }, /* CYRILLIC SMALL LETTER BIG YUS -> 'o' */ + { 0x72, 0x46 }, /* CYRILLIC CAPITAL LETTER FITA -> 'F' */ + { 0x73, 0x66 }, /* CYRILLIC SMALL LETTER FITA -> 'f' */ + { 0x74, 0x59 }, /* CYRILLIC CAPITAL LETTER IZHITSA -> 'Y' */ + { 0x75, 0x79 }, /* CYRILLIC SMALL LETTER IZHITSA -> 'y' */ + { 0x76, 0x59 }, /* CYRILLIC CAPITAL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT -> 'Y' */ + { 0x77, 0x79 }, /* CYRILLIC SMALL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT -> 'y' */ + { 0x78, 0x75 }, /* CYRILLIC CAPITAL LETTER UK -> 'u' */ + { 0x79, 0x75 }, /* CYRILLIC SMALL LETTER UK -> 'u' */ + { 0x7A, 0x4F }, /* CYRILLIC CAPITAL LETTER ROUND OMEGA -> 'O' */ + { 0x7B, 0x6F }, /* CYRILLIC SMALL LETTER ROUND OMEGA -> 'o' */ + { 0x7C, 0x4F }, /* CYRILLIC CAPITAL LETTER OMEGA WITH TITLO -> 'O' */ + { 0x7D, 0x6F }, /* CYRILLIC SMALL LETTER OMEGA WITH TITLO -> 'o' */ + { 0x80, 0x51 }, /* CYRILLIC CAPITAL LETTER KOPPA -> 'Q' */ + { 0x81, 0x71 }, /* CYRILLIC SMALL LETTER KOPPA -> 'q' */ + { 0x8C, 0x22 }, /* CYRILLIC CAPITAL LETTER SEMISOFT SIGN -> '"' */ + { 0x8D, 0x22 }, /* CYRILLIC SMALL LETTER SEMISOFT SIGN -> '"' */ + { 0xAE, 0x55 }, /* CYRILLIC CAPITAL LETTER STRAIGHT U -> 'U' */ + { 0xAF, 0x75 }, /* CYRILLIC SMALL LETTER STRAIGHT U -> 'u' */ + { 0xBA, 0x48 }, /* CYRILLIC CAPITAL LETTER SHHA -> 'H' */ + { 0xBB, 0x68 }, /* CYRILLIC SMALL LETTER SHHA -> 'h' */ + { 0xC0, 0x60 }, /* CYRILLIC LETTER PALOCHKA -> '`' */ + { 0xD0, 0x61 }, /* CYRILLIC CAPITAL LETTER A WITH BREVE -> 'a' */ + { 0xD1, 0x61 }, /* CYRILLIC SMALL LETTER A WITH BREVE -> 'a' */ + { 0xD2, 0x41 }, /* CYRILLIC CAPITAL LETTER A WITH DIAERESIS -> 'A' */ + { 0xD3, 0x61 }, /* CYRILLIC SMALL LETTER A WITH DIAERESIS -> 'a' */ + { 0xD8, 0x00 }, /* CYRILLIC CAPITAL LETTER SCHWA -> ... */ + { 0xDB, 0x40 }, /* CYRILLIC SMALL LETTER SCHWA WITH DIAERESIS -> '@' */ + { 0xDE, 0x5A }, /* CYRILLIC CAPITAL LETTER ZE WITH DIAERESIS -> 'Z' */ + { 0xDF, 0x7A }, /* CYRILLIC SMALL LETTER ZE WITH DIAERESIS -> 'z' */ + { 0xE2, 0x49 }, /* CYRILLIC CAPITAL LETTER I WITH MACRON -> 'I' */ + { 0xE3, 0x69 }, /* CYRILLIC SMALL LETTER I WITH MACRON -> 'i' */ + { 0xE4, 0x49 }, /* CYRILLIC CAPITAL LETTER I WITH DIAERESIS -> 'I' */ + { 0xE5, 0x69 }, /* CYRILLIC SMALL LETTER I WITH DIAERESIS -> 'i' */ + { 0xE6, 0x4F }, /* CYRILLIC CAPITAL LETTER O WITH DIAERESIS -> 'O' */ + { 0xE7, 0x6F }, /* CYRILLIC SMALL LETTER O WITH DIAERESIS -> 'o' */ + { 0xE8, 0x4F }, /* CYRILLIC CAPITAL LETTER BARRED O -> 'O' */ + { 0xE9, 0x6F }, /* CYRILLIC SMALL LETTER BARRED O -> 'o' */ + { 0xEA, 0x4F }, /* CYRILLIC CAPITAL LETTER BARRED O WITH DIAERESIS -> 'O' */ + { 0xEB, 0x6F }, /* CYRILLIC SMALL LETTER BARRED O WITH DIAERESIS -> 'o' */ + { 0xEC, 0x45 }, /* CYRILLIC CAPITAL LETTER E WITH DIAERESIS -> 'E' */ + { 0xED, 0x65 }, /* CYRILLIC SMALL LETTER E WITH DIAERESIS -> 'e' */ + { 0xEE, 0x55 }, /* CYRILLIC CAPITAL LETTER U WITH MACRON -> 'U' */ + { 0xEF, 0x75 }, /* CYRILLIC SMALL LETTER U WITH MACRON -> 'u' */ + { 0xF0, 0x55 }, /* CYRILLIC CAPITAL LETTER U WITH DIAERESIS -> 'U' */ + { 0xF1, 0x75 }, /* CYRILLIC SMALL LETTER U WITH DIAERESIS -> 'u' */ + { 0xF2, 0x55 }, /* CYRILLIC CAPITAL LETTER U WITH DOUBLE ACUTE -> 'U' */ + { 0xF3, 0x75 }, /* CYRILLIC SMALL LETTER U WITH DOUBLE ACUTE -> 'u' */ + { 0xF8, 0x59 }, /* CYRILLIC CAPITAL LETTER YERU WITH DIAERESIS -> 'Y' */ + { 0xF9, 0x79 }, /* CYRILLIC SMALL LETTER YERU WITH DIAERESIS -> 'y' */ + /* Entries for page 0x05 */ + { 0x31, 0x41 }, /* ARMENIAN CAPITAL LETTER AYB -> 'A' */ + { 0x32, 0x42 }, /* ARMENIAN CAPITAL LETTER BEN -> 'B' */ + { 0x33, 0x47 }, /* ARMENIAN CAPITAL LETTER GIM -> 'G' */ + { 0x34, 0x44 }, /* ARMENIAN CAPITAL LETTER DA -> 'D' */ + { 0x35, 0x45 }, /* ARMENIAN CAPITAL LETTER ECH -> 'E' */ + { 0x36, 0x5A }, /* ARMENIAN CAPITAL LETTER ZA -> 'Z' */ + { 0x37, 0x45 }, /* ARMENIAN CAPITAL LETTER EH -> 'E' */ + { 0x38, 0x45 }, /* ARMENIAN CAPITAL LETTER ET -> 'E' */ + { 0x3B, 0x49 }, /* ARMENIAN CAPITAL LETTER INI -> 'I' */ + { 0x3C, 0x4C }, /* ARMENIAN CAPITAL LETTER LIWN -> 'L' */ + { 0x3F, 0x4B }, /* ARMENIAN CAPITAL LETTER KEN -> 'K' */ + { 0x40, 0x48 }, /* ARMENIAN CAPITAL LETTER HO -> 'H' */ + { 0x44, 0x4D }, /* ARMENIAN CAPITAL LETTER MEN -> 'M' */ + { 0x45, 0x59 }, /* ARMENIAN CAPITAL LETTER YI -> 'Y' */ + { 0x46, 0x4E }, /* ARMENIAN CAPITAL LETTER NOW -> 'N' */ + { 0x48, 0x4F }, /* ARMENIAN CAPITAL LETTER VO -> 'O' */ + { 0x4A, 0x50 }, /* ARMENIAN CAPITAL LETTER PEH -> 'P' */ + { 0x4B, 0x4A }, /* ARMENIAN CAPITAL LETTER JHEH -> 'J' */ + { 0x4D, 0x53 }, /* ARMENIAN CAPITAL LETTER SEH -> 'S' */ + { 0x4E, 0x56 }, /* ARMENIAN CAPITAL LETTER VEW -> 'V' */ + { 0x4F, 0x54 }, /* ARMENIAN CAPITAL LETTER TIWN -> 'T' */ + { 0x50, 0x52 }, /* ARMENIAN CAPITAL LETTER REH -> 'R' */ + { 0x52, 0x57 }, /* ARMENIAN CAPITAL LETTER YIWN -> 'W' */ + { 0x55, 0x4F }, /* ARMENIAN CAPITAL LETTER OH -> 'O' */ + { 0x56, 0x46 }, /* ARMENIAN CAPITAL LETTER FEH -> 'F' */ + { 0x59, 0x3C }, /* ARMENIAN MODIFIER LETTER LEFT HALF RING -> '<' */ + { 0x5A, 0x27 }, /* ARMENIAN APOSTROPHE -> ''' */ + { 0x5B, 0x2F }, /* ARMENIAN EMPHASIS MARK -> '/' */ + { 0x5C, 0x21 }, /* ARMENIAN EXCLAMATION MARK -> '!' */ + { 0x5D, 0x2C }, /* ARMENIAN COMMA -> ',' */ + { 0x5E, 0x3F }, /* ARMENIAN QUESTION MARK -> '?' */ + { 0x5F, 0x2E }, /* ARMENIAN ABBREVIATION MARK -> '.' */ + { 0x61, 0x61 }, /* ARMENIAN SMALL LETTER AYB -> 'a' */ + { 0x62, 0x62 }, /* ARMENIAN SMALL LETTER BEN -> 'b' */ + { 0x63, 0x67 }, /* ARMENIAN SMALL LETTER GIM -> 'g' */ + { 0x64, 0x64 }, /* ARMENIAN SMALL LETTER DA -> 'd' */ + { 0x65, 0x65 }, /* ARMENIAN SMALL LETTER ECH -> 'e' */ + { 0x66, 0x7A }, /* ARMENIAN SMALL LETTER ZA -> 'z' */ + { 0x67, 0x65 }, /* ARMENIAN SMALL LETTER EH -> 'e' */ + { 0x68, 0x65 }, /* ARMENIAN SMALL LETTER ET -> 'e' */ + { 0x6B, 0x69 }, /* ARMENIAN SMALL LETTER INI -> 'i' */ + { 0x6C, 0x6C }, /* ARMENIAN SMALL LETTER LIWN -> 'l' */ + { 0x6F, 0x6B }, /* ARMENIAN SMALL LETTER KEN -> 'k' */ + { 0x70, 0x68 }, /* ARMENIAN SMALL LETTER HO -> 'h' */ + { 0x74, 0x6D }, /* ARMENIAN SMALL LETTER MEN -> 'm' */ + { 0x75, 0x79 }, /* ARMENIAN SMALL LETTER YI -> 'y' */ + { 0x76, 0x6E }, /* ARMENIAN SMALL LETTER NOW -> 'n' */ + { 0x78, 0x6F }, /* ARMENIAN SMALL LETTER VO -> 'o' */ + { 0x7A, 0x70 }, /* ARMENIAN SMALL LETTER PEH -> 'p' */ + { 0x7B, 0x6A }, /* ARMENIAN SMALL LETTER JHEH -> 'j' */ + { 0x7D, 0x73 }, /* ARMENIAN SMALL LETTER SEH -> 's' */ + { 0x7E, 0x76 }, /* ARMENIAN SMALL LETTER VEW -> 'v' */ + { 0x7F, 0x74 }, /* ARMENIAN SMALL LETTER TIWN -> 't' */ + { 0x80, 0x72 }, /* ARMENIAN SMALL LETTER REH -> 'r' */ + { 0x82, 0x77 }, /* ARMENIAN SMALL LETTER YIWN -> 'w' */ + { 0x85, 0x6F }, /* ARMENIAN SMALL LETTER OH -> 'o' */ + { 0x86, 0x66 }, /* ARMENIAN SMALL LETTER FEH -> 'f' */ + { 0x89, 0x3A }, /* ARMENIAN FULL STOP -> ':' */ + { 0x8A, 0x2D }, /* ARMENIAN HYPHEN -> '-' */ + { 0xB1, 0x65 }, /* HEBREW POINT HATAF SEGOL -> 'e' */ + { 0xB2, 0x61 }, /* HEBREW POINT HATAF PATAH -> 'a' */ + { 0xB3, 0x6F }, /* HEBREW POINT HATAF QAMATS -> 'o' */ + { 0xB4, 0x69 }, /* HEBREW POINT HIRIQ -> 'i' */ + { 0xB5, 0x65 }, /* HEBREW POINT TSERE -> 'e' */ + { 0xB6, 0x65 }, /* HEBREW POINT SEGOL -> 'e' */ + { 0xB7, 0x61 }, /* HEBREW POINT PATAH -> 'a' */ + { 0xB8, 0x61 }, /* HEBREW POINT QAMATS -> 'a' */ + { 0xB9, 0x6F }, /* HEBREW POINT HOLAM -> 'o' */ + { 0xBA, 0x6F }, /* HEBREW POINT HOLAM HASER FOR VAV -> 'o' */ + { 0xBB, 0x75 }, /* HEBREW POINT QUBUTS -> 'u' */ + { 0xBE, 0x2D }, /* HEBREW PUNCTUATION MAQAF -> '-' */ + { 0xC0, 0x7C }, /* HEBREW PUNCTUATION PASEQ -> '|' */ + { 0xC3, 0x2E }, /* HEBREW PUNCTUATION SOF PASUQ -> '.' */ + { 0xC6, 0x6E }, /* HEBREW PUNCTUATION NUN HAFUKHA -> 'n' */ + { 0xC7, 0x6F }, /* HEBREW POINT QAMATS QATAN -> 'o' */ + { 0xD0, 0x41 }, /* HEBREW LETTER ALEF -> 'A' */ + { 0xD1, 0x62 }, /* HEBREW LETTER BET -> 'b' */ + { 0xD2, 0x67 }, /* HEBREW LETTER GIMEL -> 'g' */ + { 0xD3, 0x64 }, /* HEBREW LETTER DALET -> 'd' */ + { 0xD4, 0x68 }, /* HEBREW LETTER HE -> 'h' */ + { 0xD5, 0x76 }, /* HEBREW LETTER VAV -> 'v' */ + { 0xD6, 0x7A }, /* HEBREW LETTER ZAYIN -> 'z' */ + { 0xD7, 0x48 }, /* HEBREW LETTER HET -> 'H' */ + { 0xD8, 0x54 }, /* HEBREW LETTER TET -> 'T' */ + { 0xD9, 0x79 }, /* HEBREW LETTER YOD -> 'y' */ + { 0xDC, 0x6C }, /* HEBREW LETTER LAMED -> 'l' */ + { 0xDD, 0x6D }, /* HEBREW LETTER FINAL MEM -> 'm' */ + { 0xDE, 0x6D }, /* HEBREW LETTER MEM -> 'm' */ + { 0xDF, 0x6E }, /* HEBREW LETTER FINAL NUN -> 'n' */ + { 0xE0, 0x6E }, /* HEBREW LETTER NUN -> 'n' */ + { 0xE1, 0x73 }, /* HEBREW LETTER SAMEKH -> 's' */ + { 0xE2, 0x60 }, /* HEBREW LETTER AYIN -> '`' */ + { 0xE3, 0x70 }, /* HEBREW LETTER FINAL PE -> 'p' */ + { 0xE4, 0x70 }, /* HEBREW LETTER PE -> 'p' */ + { 0xE7, 0x6B }, /* HEBREW LETTER QOF -> 'k' */ + { 0xE8, 0x72 }, /* HEBREW LETTER RESH -> 'r' */ + { 0xEA, 0x74 }, /* HEBREW LETTER TAV -> 't' */ + { 0xF0, 0x56 }, /* HEBREW LIGATURE YIDDISH DOUBLE VAV -> 'V' */ + { 0xF3, 0x27 }, /* HEBREW PUNCTUATION GERESH -> ''' */ + { 0xF4, 0x22 }, /* HEBREW PUNCTUATION GERSHAYIM -> '"' */ + /* Entries for page 0x06 */ + { 0x0C, 0x2C }, /* ARABIC COMMA -> ',' */ + { 0x1B, 0x3B }, /* ARABIC SEMICOLON -> ';' */ + { 0x1F, 0x3F }, /* ARABIC QUESTION MARK -> '?' */ + { 0x22, 0x61 }, /* ARABIC LETTER ALEF WITH MADDA ABOVE -> 'a' */ + { 0x23, 0x27 }, /* ARABIC LETTER ALEF WITH HAMZA ABOVE -> ''' */ + { 0x28, 0x62 }, /* ARABIC LETTER BEH -> 'b' */ + { 0x29, 0x40 }, /* ARABIC LETTER TEH MARBUTA -> '@' */ + { 0x2A, 0x74 }, /* ARABIC LETTER TEH -> 't' */ + { 0x2C, 0x6A }, /* ARABIC LETTER JEEM -> 'j' */ + { 0x2D, 0x48 }, /* ARABIC LETTER HAH -> 'H' */ + { 0x2F, 0x64 }, /* ARABIC LETTER DAL -> 'd' */ + { 0x31, 0x72 }, /* ARABIC LETTER REH -> 'r' */ + { 0x32, 0x7A }, /* ARABIC LETTER ZAIN -> 'z' */ + { 0x33, 0x73 }, /* ARABIC LETTER SEEN -> 's' */ + { 0x35, 0x53 }, /* ARABIC LETTER SAD -> 'S' */ + { 0x36, 0x44 }, /* ARABIC LETTER DAD -> 'D' */ + { 0x37, 0x54 }, /* ARABIC LETTER TAH -> 'T' */ + { 0x38, 0x5A }, /* ARABIC LETTER ZAH -> 'Z' */ + { 0x39, 0x60 }, /* ARABIC LETTER AIN -> '`' */ + { 0x3A, 0x47 }, /* ARABIC LETTER GHAIN -> 'G' */ + { 0x41, 0x66 }, /* ARABIC LETTER FEH -> 'f' */ + { 0x42, 0x71 }, /* ARABIC LETTER QAF -> 'q' */ + { 0x43, 0x6B }, /* ARABIC LETTER KAF -> 'k' */ + { 0x44, 0x6C }, /* ARABIC LETTER LAM -> 'l' */ + { 0x45, 0x6D }, /* ARABIC LETTER MEEM -> 'm' */ + { 0x46, 0x6E }, /* ARABIC LETTER NOON -> 'n' */ + { 0x47, 0x68 }, /* ARABIC LETTER HEH -> 'h' */ + { 0x48, 0x77 }, /* ARABIC LETTER WAW -> 'w' */ + { 0x49, 0x7E }, /* ARABIC LETTER ALEF MAKSURA -> '~' */ + { 0x4A, 0x79 }, /* ARABIC LETTER YEH -> 'y' */ + { 0x4E, 0x61 }, /* ARABIC FATHA -> 'a' */ + { 0x4F, 0x75 }, /* ARABIC DAMMA -> 'u' */ + { 0x50, 0x69 }, /* ARABIC KASRA -> 'i' */ + { 0x51, 0x57 }, /* ARABIC SHADDA -> 'W' */ + { 0x54, 0x27 }, /* ARABIC HAMZA ABOVE -> ''' */ + { 0x55, 0x27 }, /* ARABIC HAMZA BELOW -> ''' */ + { 0x60, 0x30 }, /* ARABIC-INDIC DIGIT ZERO -> '0' */ + { 0x61, 0x31 }, /* ARABIC-INDIC DIGIT ONE -> '1' */ + { 0x62, 0x32 }, /* ARABIC-INDIC DIGIT TWO -> '2' */ + { 0x63, 0x33 }, /* ARABIC-INDIC DIGIT THREE -> '3' */ + { 0x64, 0x34 }, /* ARABIC-INDIC DIGIT FOUR -> '4' */ + { 0x65, 0x35 }, /* ARABIC-INDIC DIGIT FIVE -> '5' */ + { 0x66, 0x36 }, /* ARABIC-INDIC DIGIT SIX -> '6' */ + { 0x67, 0x37 }, /* ARABIC-INDIC DIGIT SEVEN -> '7' */ + { 0x68, 0x38 }, /* ARABIC-INDIC DIGIT EIGHT -> '8' */ + { 0x69, 0x39 }, /* ARABIC-INDIC DIGIT NINE -> '9' */ + { 0x6A, 0x25 }, /* ARABIC PERCENT SIGN -> '%' */ + { 0x6B, 0x2E }, /* ARABIC DECIMAL SEPARATOR -> '.' */ + { 0x6C, 0x2C }, /* ARABIC THOUSANDS SEPARATOR -> ',' */ + { 0x6D, 0x2A }, /* ARABIC FIVE POINTED STAR -> '*' */ + { 0x71, 0x00 }, /* ARABIC LETTER ALEF WASLA -> ... */ + { 0x73, 0x27 }, /* ARABIC LETTER ALEF WITH WAVY HAMZA BELOW -> ''' */ + { 0x75, 0x27 }, /* ARABIC LETTER HIGH HAMZA ALEF -> ''' */ + { 0x7B, 0x62 }, /* ARABIC LETTER BEEH -> 'b' */ + { 0x7C, 0x74 }, /* ARABIC LETTER TEH WITH RING -> 't' */ + { 0x7D, 0x54 }, /* ARABIC LETTER TEH WITH THREE DOTS ABOVE DOWNWARDS -> 'T' */ + { 0x7E, 0x70 }, /* ARABIC LETTER PEH -> 'p' */ + { 0x82, 0x48 }, /* ARABIC LETTER HAH WITH TWO DOTS VERTICAL ABOVE -> 'H' */ + { 0x85, 0x48 }, /* ARABIC LETTER HAH WITH THREE DOTS ABOVE -> 'H' */ + { 0x89, 0x44 }, /* ARABIC LETTER DAL WITH RING -> 'D' */ + { 0x8A, 0x44 }, /* ARABIC LETTER DAL WITH DOT BELOW -> 'D' */ + { 0x8E, 0x64 }, /* ARABIC LETTER DUL -> 'd' */ + { 0x8F, 0x44 }, /* ARABIC LETTER DAL WITH THREE DOTS ABOVE DOWNWARDS -> 'D' */ + { 0x90, 0x44 }, /* ARABIC LETTER DAL WITH FOUR DOTS ABOVE -> 'D' */ + { 0x92, 0x00 }, /* ARABIC LETTER REH WITH SMALL V -> ... */ + { 0x97, 0x52 }, /* ARABIC LETTER REH WITH TWO DOTS ABOVE -> 'R' */ + { 0x98, 0x6A }, /* ARABIC LETTER JEH -> 'j' */ + { 0x99, 0x52 }, /* ARABIC LETTER REH WITH FOUR DOTS ABOVE -> 'R' */ + { 0x9A, 0x00 }, /* ARABIC LETTER SEEN WITH DOT BELOW AND DOT ABOVE -> ... */ + { 0x9E, 0x53 }, /* ARABIC LETTER SAD WITH THREE DOTS ABOVE -> 'S' */ + { 0x9F, 0x54 }, /* ARABIC LETTER TAH WITH THREE DOTS ABOVE -> 'T' */ + { 0xA1, 0x00 }, /* ARABIC LETTER DOTLESS FEH -> ... */ + { 0xA3, 0x46 }, /* ARABIC LETTER FEH WITH DOT BELOW -> 'F' */ + { 0xA4, 0x76 }, /* ARABIC LETTER VEH -> 'v' */ + { 0xA5, 0x66 }, /* ARABIC LETTER FEH WITH THREE DOTS BELOW -> 'f' */ + { 0xA7, 0x51 }, /* ARABIC LETTER QAF WITH DOT ABOVE -> 'Q' */ + { 0xA8, 0x51 }, /* ARABIC LETTER QAF WITH THREE DOTS ABOVE -> 'Q' */ + { 0xAA, 0x6B }, /* ARABIC LETTER SWASH KAF -> 'k' */ + { 0xAB, 0x4B }, /* ARABIC LETTER KAF WITH RING -> 'K' */ + { 0xAC, 0x4B }, /* ARABIC LETTER KAF WITH DOT ABOVE -> 'K' */ + { 0xAE, 0x4B }, /* ARABIC LETTER KAF WITH THREE DOTS BELOW -> 'K' */ + { 0xAF, 0x67 }, /* ARABIC LETTER GAF -> 'g' */ + { 0xB0, 0x47 }, /* ARABIC LETTER GAF WITH RING -> 'G' */ + { 0xB1, 0x4E }, /* ARABIC LETTER NGOEH -> 'N' */ + { 0xB2, 0x00 }, /* ARABIC LETTER GAF WITH TWO DOTS BELOW -> ... */ + { 0xB4, 0x47 }, /* ARABIC LETTER GAF WITH THREE DOTS ABOVE -> 'G' */ + { 0xB5, 0x00 }, /* ARABIC LETTER LAM WITH SMALL V -> ... */ + { 0xB8, 0x4C }, /* ARABIC LETTER LAM WITH THREE DOTS BELOW -> 'L' */ + { 0xB9, 0x00 }, /* ARABIC LETTER NOON WITH DOT BELOW -> ... */ + { 0xBD, 0x4E }, /* ARABIC LETTER NOON WITH THREE DOTS ABOVE -> 'N' */ + { 0xBE, 0x68 }, /* ARABIC LETTER HEH DOACHASHMEE -> 'h' */ + { 0xC1, 0x68 }, /* ARABIC LETTER HEH GOAL -> 'h' */ + { 0xC2, 0x48 }, /* ARABIC LETTER HEH GOAL WITH HAMZA ABOVE -> 'H' */ + { 0xC3, 0x40 }, /* ARABIC LETTER TEH MARBUTA GOAL -> '@' */ + { 0xC4, 0x57 }, /* ARABIC LETTER WAW WITH RING -> 'W' */ + { 0xC7, 0x75 }, /* ARABIC LETTER U -> 'u' */ + { 0xCA, 0x57 }, /* ARABIC LETTER WAW WITH TWO DOTS ABOVE -> 'W' */ + { 0xCB, 0x76 }, /* ARABIC LETTER VE -> 'v' */ + { 0xCC, 0x79 }, /* ARABIC LETTER FARSI YEH -> 'y' */ + { 0xCD, 0x59 }, /* ARABIC LETTER YEH WITH TAIL -> 'Y' */ + { 0xCE, 0x59 }, /* ARABIC LETTER YEH WITH SMALL V -> 'Y' */ + { 0xCF, 0x57 }, /* ARABIC LETTER WAW WITH DOT ABOVE -> 'W' */ + { 0xD2, 0x79 }, /* ARABIC LETTER YEH BARREE -> 'y' */ + { 0xD4, 0x2E }, /* ARABIC FULL STOP -> '.' */ + { 0xDD, 0x40 }, /* ARABIC END OF AYAH -> '@' */ + { 0xDE, 0x23 }, /* ARABIC START OF RUB EL HIZB -> '#' */ + { 0xE9, 0x5E }, /* ARABIC PLACE OF SAJDAH -> '^' */ + { 0xF0, 0x30 }, /* EXTENDED ARABIC-INDIC DIGIT ZERO -> '0' */ + { 0xF1, 0x31 }, /* EXTENDED ARABIC-INDIC DIGIT ONE -> '1' */ + { 0xF2, 0x32 }, /* EXTENDED ARABIC-INDIC DIGIT TWO -> '2' */ + { 0xF3, 0x33 }, /* EXTENDED ARABIC-INDIC DIGIT THREE -> '3' */ + { 0xF4, 0x34 }, /* EXTENDED ARABIC-INDIC DIGIT FOUR -> '4' */ + { 0xF5, 0x35 }, /* EXTENDED ARABIC-INDIC DIGIT FIVE -> '5' */ + { 0xF6, 0x36 }, /* EXTENDED ARABIC-INDIC DIGIT SIX -> '6' */ + { 0xF7, 0x37 }, /* EXTENDED ARABIC-INDIC DIGIT SEVEN -> '7' */ + { 0xF8, 0x38 }, /* EXTENDED ARABIC-INDIC DIGIT EIGHT -> '8' */ + { 0xF9, 0x39 }, /* EXTENDED ARABIC-INDIC DIGIT NINE -> '9' */ + { 0xFB, 0x44 }, /* ARABIC LETTER DAD WITH DOT BELOW -> 'D' */ + { 0xFD, 0x26 }, /* ARABIC SIGN SINDHI AMPERSAND -> '&' */ + /* Entries for page 0x07 */ + { 0x01, 0x2F }, /* SYRIAC SUPRALINEAR FULL STOP -> '/' */ + { 0x02, 0x2C }, /* SYRIAC SUBLINEAR FULL STOP -> ',' */ + { 0x03, 0x21 }, /* SYRIAC SUPRALINEAR COLON -> '!' */ + { 0x04, 0x21 }, /* SYRIAC SUBLINEAR COLON -> '!' */ + { 0x05, 0x2D }, /* SYRIAC HORIZONTAL COLON -> '-' */ + { 0x06, 0x2C }, /* SYRIAC COLON SKEWED LEFT -> ',' */ + { 0x07, 0x2C }, /* SYRIAC COLON SKEWED RIGHT -> ',' */ + { 0x08, 0x3B }, /* SYRIAC SUPRALINEAR COLON SKEWED LEFT -> ';' */ + { 0x09, 0x3F }, /* SYRIAC SUBLINEAR COLON SKEWED RIGHT -> '?' */ + { 0x0A, 0x7E }, /* SYRIAC CONTRACTION -> '~' */ + { 0x0B, 0x7B }, /* SYRIAC HARKLEAN OBELUS -> '{' */ + { 0x0C, 0x7D }, /* SYRIAC HARKLEAN METOBELUS -> '}' */ + { 0x0D, 0x2A }, /* SYRIAC HARKLEAN ASTERISCUS -> '*' */ + { 0x10, 0x27 }, /* SYRIAC LETTER ALAPH -> ''' */ + { 0x12, 0x62 }, /* SYRIAC LETTER BETH -> 'b' */ + { 0x13, 0x67 }, /* SYRIAC LETTER GAMAL -> 'g' */ + { 0x14, 0x67 }, /* SYRIAC LETTER GAMAL GARSHUNI -> 'g' */ + { 0x15, 0x64 }, /* SYRIAC LETTER DALATH -> 'd' */ + { 0x16, 0x64 }, /* SYRIAC LETTER DOTLESS DALATH RISH -> 'd' */ + { 0x17, 0x68 }, /* SYRIAC LETTER HE -> 'h' */ + { 0x18, 0x77 }, /* SYRIAC LETTER WAW -> 'w' */ + { 0x19, 0x7A }, /* SYRIAC LETTER ZAIN -> 'z' */ + { 0x1A, 0x48 }, /* SYRIAC LETTER HETH -> 'H' */ + { 0x1B, 0x74 }, /* SYRIAC LETTER TETH -> 't' */ + { 0x1C, 0x74 }, /* SYRIAC LETTER TETH GARSHUNI -> 't' */ + { 0x1D, 0x79 }, /* SYRIAC LETTER YUDH -> 'y' */ + { 0x1F, 0x6B }, /* SYRIAC LETTER KAPH -> 'k' */ + { 0x20, 0x6C }, /* SYRIAC LETTER LAMADH -> 'l' */ + { 0x21, 0x6D }, /* SYRIAC LETTER MIM -> 'm' */ + { 0x22, 0x6E }, /* SYRIAC LETTER NUN -> 'n' */ + { 0x23, 0x73 }, /* SYRIAC LETTER SEMKATH -> 's' */ + { 0x24, 0x73 }, /* SYRIAC LETTER FINAL SEMKATH -> 's' */ + { 0x25, 0x60 }, /* SYRIAC LETTER E -> '`' */ + { 0x26, 0x70 }, /* SYRIAC LETTER PE -> 'p' */ + { 0x27, 0x70 }, /* SYRIAC LETTER REVERSED PE -> 'p' */ + { 0x28, 0x53 }, /* SYRIAC LETTER SADHE -> 'S' */ + { 0x29, 0x71 }, /* SYRIAC LETTER QAPH -> 'q' */ + { 0x2A, 0x72 }, /* SYRIAC LETTER RISH -> 'r' */ + { 0x2C, 0x74 }, /* SYRIAC LETTER TAW -> 't' */ + { 0x30, 0x00 }, /* SYRIAC PTHAHA ABOVE -> ... */ + { 0x32, 0x61 }, /* SYRIAC PTHAHA DOTTED -> 'a' */ + { 0x33, 0x00 }, /* SYRIAC ZQAPHA ABOVE -> ... */ + { 0x35, 0x41 }, /* SYRIAC ZQAPHA DOTTED -> 'A' */ + { 0x36, 0x00 }, /* SYRIAC RBASA ABOVE -> ... */ + { 0x38, 0x65 }, /* SYRIAC DOTTED ZLAMA HORIZONTAL -> 'e' */ + { 0x39, 0x45 }, /* SYRIAC DOTTED ZLAMA ANGULAR -> 'E' */ + { 0x3A, 0x69 }, /* SYRIAC HBASA ABOVE -> 'i' */ + { 0x3B, 0x69 }, /* SYRIAC HBASA BELOW -> 'i' */ + { 0x3C, 0x00 }, /* SYRIAC HBASA-ESASA DOTTED -> ... */ + { 0x3E, 0x75 }, /* SYRIAC ESASA BELOW -> 'u' */ + { 0x3F, 0x6F }, /* SYRIAC RWAHA -> 'o' */ + { 0x41, 0x60 }, /* SYRIAC QUSHSHAYA -> '`' */ + { 0x42, 0x27 }, /* SYRIAC RUKKAKHA -> ''' */ + { 0x45, 0x58 }, /* SYRIAC THREE DOTS ABOVE -> 'X' */ + { 0x46, 0x51 }, /* SYRIAC THREE DOTS BELOW -> 'Q' */ + { 0x47, 0x40 }, /* SYRIAC OBLIQUE LINE ABOVE -> '@' */ + { 0x48, 0x40 }, /* SYRIAC OBLIQUE LINE BELOW -> '@' */ + { 0x49, 0x7C }, /* SYRIAC MUSIC -> '|' */ + { 0x4A, 0x2B }, /* SYRIAC BARREKH -> '+' */ + { 0x80, 0x68 }, /* THAANA LETTER HAA -> 'h' */ + { 0x82, 0x6E }, /* THAANA LETTER NOONU -> 'n' */ + { 0x83, 0x72 }, /* THAANA LETTER RAA -> 'r' */ + { 0x84, 0x62 }, /* THAANA LETTER BAA -> 'b' */ + { 0x85, 0x4C }, /* THAANA LETTER LHAVIYANI -> 'L' */ + { 0x86, 0x6B }, /* THAANA LETTER KAAFU -> 'k' */ + { 0x87, 0x27 }, /* THAANA LETTER ALIFU -> ''' */ + { 0x88, 0x76 }, /* THAANA LETTER VAAVU -> 'v' */ + { 0x89, 0x6D }, /* THAANA LETTER MEEMU -> 'm' */ + { 0x8A, 0x66 }, /* THAANA LETTER FAAFU -> 'f' */ + { 0x8D, 0x6C }, /* THAANA LETTER LAAMU -> 'l' */ + { 0x8E, 0x67 }, /* THAANA LETTER GAAFU -> 'g' */ + { 0x90, 0x73 }, /* THAANA LETTER SEENU -> 's' */ + { 0x91, 0x64 }, /* THAANA LETTER DAVIYANI -> 'd' */ + { 0x92, 0x7A }, /* THAANA LETTER ZAVIYANI -> 'z' */ + { 0x93, 0x74 }, /* THAANA LETTER TAVIYANI -> 't' */ + { 0x94, 0x79 }, /* THAANA LETTER YAA -> 'y' */ + { 0x95, 0x70 }, /* THAANA LETTER PAVIYANI -> 'p' */ + { 0x96, 0x6A }, /* THAANA LETTER JAVIYANI -> 'j' */ + { 0x9C, 0x7A }, /* THAANA LETTER ZAA -> 'z' */ + { 0x9E, 0x73 }, /* THAANA LETTER SAADHU -> 's' */ + { 0x9F, 0x64 }, /* THAANA LETTER DAADHU -> 'd' */ + { 0xA0, 0x74 }, /* THAANA LETTER TO -> 't' */ + { 0xA1, 0x7A }, /* THAANA LETTER ZO -> 'z' */ + { 0xA2, 0x60 }, /* THAANA LETTER AINU -> '`' */ + { 0xA4, 0x71 }, /* THAANA LETTER QAAFU -> 'q' */ + { 0xA5, 0x77 }, /* THAANA LETTER WAAVU -> 'w' */ + { 0xA6, 0x61 }, /* THAANA ABAFILI -> 'a' */ + { 0xA8, 0x69 }, /* THAANA IBIFILI -> 'i' */ + { 0xAA, 0x75 }, /* THAANA UBUFILI -> 'u' */ + { 0xAC, 0x65 }, /* THAANA EBEFILI -> 'e' */ + { 0xAE, 0x6F }, /* THAANA OBOFILI -> 'o' */ + /* Entries for page 0x09 */ + { 0x01, 0x4E }, /* DEVANAGARI SIGN CANDRABINDU -> 'N' */ + { 0x02, 0x4E }, /* DEVANAGARI SIGN ANUSVARA -> 'N' */ + { 0x03, 0x48 }, /* DEVANAGARI SIGN VISARGA -> 'H' */ + { 0x05, 0x61 }, /* DEVANAGARI LETTER A -> 'a' */ + { 0x07, 0x69 }, /* DEVANAGARI LETTER I -> 'i' */ + { 0x09, 0x75 }, /* DEVANAGARI LETTER U -> 'u' */ + { 0x0B, 0x52 }, /* DEVANAGARI LETTER VOCALIC R -> 'R' */ + { 0x0C, 0x4C }, /* DEVANAGARI LETTER VOCALIC L -> 'L' */ + { 0x0E, 0x65 }, /* DEVANAGARI LETTER SHORT E -> 'e' */ + { 0x0F, 0x65 }, /* DEVANAGARI LETTER E -> 'e' */ + { 0x12, 0x6F }, /* DEVANAGARI LETTER SHORT O -> 'o' */ + { 0x13, 0x6F }, /* DEVANAGARI LETTER O -> 'o' */ + { 0x15, 0x6B }, /* DEVANAGARI LETTER KA -> 'k' */ + { 0x17, 0x67 }, /* DEVANAGARI LETTER GA -> 'g' */ + { 0x1A, 0x63 }, /* DEVANAGARI LETTER CA -> 'c' */ + { 0x1C, 0x6A }, /* DEVANAGARI LETTER JA -> 'j' */ + { 0x24, 0x74 }, /* DEVANAGARI LETTER TA -> 't' */ + { 0x26, 0x64 }, /* DEVANAGARI LETTER DA -> 'd' */ + { 0x28, 0x6E }, /* DEVANAGARI LETTER NA -> 'n' */ + { 0x2A, 0x70 }, /* DEVANAGARI LETTER PA -> 'p' */ + { 0x2C, 0x62 }, /* DEVANAGARI LETTER BA -> 'b' */ + { 0x2E, 0x6D }, /* DEVANAGARI LETTER MA -> 'm' */ + { 0x2F, 0x79 }, /* DEVANAGARI LETTER YA -> 'y' */ + { 0x30, 0x72 }, /* DEVANAGARI LETTER RA -> 'r' */ + { 0x32, 0x6C }, /* DEVANAGARI LETTER LA -> 'l' */ + { 0x33, 0x6C }, /* DEVANAGARI LETTER LLA -> 'l' */ + { 0x35, 0x76 }, /* DEVANAGARI LETTER VA -> 'v' */ + { 0x38, 0x73 }, /* DEVANAGARI LETTER SA -> 's' */ + { 0x39, 0x68 }, /* DEVANAGARI LETTER HA -> 'h' */ + { 0x3C, 0x27 }, /* DEVANAGARI SIGN NUKTA -> ''' */ + { 0x3D, 0x27 }, /* DEVANAGARI SIGN AVAGRAHA -> ''' */ + { 0x3F, 0x69 }, /* DEVANAGARI VOWEL SIGN I -> 'i' */ + { 0x41, 0x75 }, /* DEVANAGARI VOWEL SIGN U -> 'u' */ + { 0x43, 0x52 }, /* DEVANAGARI VOWEL SIGN VOCALIC R -> 'R' */ + { 0x46, 0x65 }, /* DEVANAGARI VOWEL SIGN SHORT E -> 'e' */ + { 0x47, 0x65 }, /* DEVANAGARI VOWEL SIGN E -> 'e' */ + { 0x4A, 0x6F }, /* DEVANAGARI VOWEL SIGN SHORT O -> 'o' */ + { 0x4B, 0x6F }, /* DEVANAGARI VOWEL SIGN O -> 'o' */ + { 0x51, 0x27 }, /* DEVANAGARI STRESS SIGN UDATTA -> ''' */ + { 0x52, 0x27 }, /* DEVANAGARI STRESS SIGN ANUDATTA -> ''' */ + { 0x53, 0x60 }, /* DEVANAGARI GRAVE ACCENT -> '`' */ + { 0x54, 0x27 }, /* DEVANAGARI ACUTE ACCENT -> ''' */ + { 0x58, 0x71 }, /* DEVANAGARI LETTER QA -> 'q' */ + { 0x5B, 0x7A }, /* DEVANAGARI LETTER ZA -> 'z' */ + { 0x5E, 0x66 }, /* DEVANAGARI LETTER FA -> 'f' */ + { 0x62, 0x4C }, /* DEVANAGARI VOWEL SIGN VOCALIC L -> 'L' */ + { 0x66, 0x30 }, /* DEVANAGARI DIGIT ZERO -> '0' */ + { 0x67, 0x31 }, /* DEVANAGARI DIGIT ONE -> '1' */ + { 0x68, 0x32 }, /* DEVANAGARI DIGIT TWO -> '2' */ + { 0x69, 0x33 }, /* DEVANAGARI DIGIT THREE -> '3' */ + { 0x6A, 0x34 }, /* DEVANAGARI DIGIT FOUR -> '4' */ + { 0x6B, 0x35 }, /* DEVANAGARI DIGIT FIVE -> '5' */ + { 0x6C, 0x36 }, /* DEVANAGARI DIGIT SIX -> '6' */ + { 0x6D, 0x37 }, /* DEVANAGARI DIGIT SEVEN -> '7' */ + { 0x6E, 0x38 }, /* DEVANAGARI DIGIT EIGHT -> '8' */ + { 0x6F, 0x39 }, /* DEVANAGARI DIGIT NINE -> '9' */ + { 0x70, 0x2E }, /* DEVANAGARI ABBREVIATION SIGN -> '.' */ + { 0x81, 0x4E }, /* BENGALI SIGN CANDRABINDU -> 'N' */ + { 0x82, 0x4E }, /* BENGALI SIGN ANUSVARA -> 'N' */ + { 0x83, 0x48 }, /* BENGALI SIGN VISARGA -> 'H' */ + { 0x85, 0x61 }, /* BENGALI LETTER A -> 'a' */ + { 0x87, 0x69 }, /* BENGALI LETTER I -> 'i' */ + { 0x89, 0x75 }, /* BENGALI LETTER U -> 'u' */ + { 0x8B, 0x52 }, /* BENGALI LETTER VOCALIC R -> 'R' */ + { 0x8F, 0x65 }, /* BENGALI LETTER E -> 'e' */ + { 0x93, 0x6F }, /* BENGALI LETTER O -> 'o' */ + { 0x95, 0x6B }, /* BENGALI LETTER KA -> 'k' */ + { 0x97, 0x67 }, /* BENGALI LETTER GA -> 'g' */ + { 0x9A, 0x63 }, /* BENGALI LETTER CA -> 'c' */ + { 0x9C, 0x6A }, /* BENGALI LETTER JA -> 'j' */ + { 0xA4, 0x74 }, /* BENGALI LETTER TA -> 't' */ + { 0xA6, 0x64 }, /* BENGALI LETTER DA -> 'd' */ + { 0xA8, 0x6E }, /* BENGALI LETTER NA -> 'n' */ + { 0xAA, 0x70 }, /* BENGALI LETTER PA -> 'p' */ + { 0xAC, 0x62 }, /* BENGALI LETTER BA -> 'b' */ + { 0xAE, 0x6D }, /* BENGALI LETTER MA -> 'm' */ + { 0xAF, 0x79 }, /* BENGALI LETTER YA -> 'y' */ + { 0xB0, 0x72 }, /* BENGALI LETTER RA -> 'r' */ + { 0xB2, 0x6C }, /* BENGALI LETTER LA -> 'l' */ + { 0xB8, 0x73 }, /* BENGALI LETTER SA -> 's' */ + { 0xB9, 0x68 }, /* BENGALI LETTER HA -> 'h' */ + { 0xBC, 0x27 }, /* BENGALI SIGN NUKTA -> ''' */ + { 0xBF, 0x69 }, /* BENGALI VOWEL SIGN I -> 'i' */ + { 0xC1, 0x75 }, /* BENGALI VOWEL SIGN U -> 'u' */ + { 0xC3, 0x52 }, /* BENGALI VOWEL SIGN VOCALIC R -> 'R' */ + { 0xC7, 0x65 }, /* BENGALI VOWEL SIGN E -> 'e' */ + { 0xCB, 0x6F }, /* BENGALI VOWEL SIGN O -> 'o' */ + { 0xD7, 0x2B }, /* BENGALI AU LENGTH MARK -> '+' */ + { 0xE2, 0x4C }, /* BENGALI VOWEL SIGN VOCALIC L -> 'L' */ + { 0xE6, 0x30 }, /* BENGALI DIGIT ZERO -> '0' */ + { 0xE7, 0x31 }, /* BENGALI DIGIT ONE -> '1' */ + { 0xE8, 0x32 }, /* BENGALI DIGIT TWO -> '2' */ + { 0xE9, 0x33 }, /* BENGALI DIGIT THREE -> '3' */ + { 0xEA, 0x34 }, /* BENGALI DIGIT FOUR -> '4' */ + { 0xEB, 0x35 }, /* BENGALI DIGIT FIVE -> '5' */ + { 0xEC, 0x36 }, /* BENGALI DIGIT SIX -> '6' */ + { 0xED, 0x37 }, /* BENGALI DIGIT SEVEN -> '7' */ + { 0xEE, 0x38 }, /* BENGALI DIGIT EIGHT -> '8' */ + { 0xEF, 0x39 }, /* BENGALI DIGIT NINE -> '9' */ + /* Entries for page 0x0A */ + { 0x02, 0x4E }, /* GURMUKHI SIGN BINDI -> 'N' */ + { 0x05, 0x61 }, /* GURMUKHI LETTER A -> 'a' */ + { 0x07, 0x69 }, /* GURMUKHI LETTER I -> 'i' */ + { 0x09, 0x75 }, /* GURMUKHI LETTER U -> 'u' */ + { 0x15, 0x6B }, /* GURMUKHI LETTER KA -> 'k' */ + { 0x17, 0x67 }, /* GURMUKHI LETTER GA -> 'g' */ + { 0x1A, 0x63 }, /* GURMUKHI LETTER CA -> 'c' */ + { 0x1C, 0x6A }, /* GURMUKHI LETTER JA -> 'j' */ + { 0x24, 0x74 }, /* GURMUKHI LETTER TA -> 't' */ + { 0x26, 0x64 }, /* GURMUKHI LETTER DA -> 'd' */ + { 0x28, 0x6E }, /* GURMUKHI LETTER NA -> 'n' */ + { 0x2A, 0x70 }, /* GURMUKHI LETTER PA -> 'p' */ + { 0x2C, 0x62 }, /* GURMUKHI LETTER BA -> 'b' */ + { 0x2E, 0x6D }, /* GURMUKHI LETTER MA -> 'm' */ + { 0x2F, 0x79 }, /* GURMUKHI LETTER YA -> 'y' */ + { 0x30, 0x72 }, /* GURMUKHI LETTER RA -> 'r' */ + { 0x32, 0x6C }, /* GURMUKHI LETTER LA -> 'l' */ + { 0x35, 0x76 }, /* GURMUKHI LETTER VA -> 'v' */ + { 0x38, 0x73 }, /* GURMUKHI LETTER SA -> 's' */ + { 0x39, 0x68 }, /* GURMUKHI LETTER HA -> 'h' */ + { 0x3C, 0x27 }, /* GURMUKHI SIGN NUKTA -> ''' */ + { 0x3F, 0x69 }, /* GURMUKHI VOWEL SIGN I -> 'i' */ + { 0x41, 0x75 }, /* GURMUKHI VOWEL SIGN U -> 'u' */ + { 0x5B, 0x7A }, /* GURMUKHI LETTER ZA -> 'z' */ + { 0x5E, 0x66 }, /* GURMUKHI LETTER FA -> 'f' */ + { 0x66, 0x30 }, /* GURMUKHI DIGIT ZERO -> '0' */ + { 0x67, 0x31 }, /* GURMUKHI DIGIT ONE -> '1' */ + { 0x68, 0x32 }, /* GURMUKHI DIGIT TWO -> '2' */ + { 0x69, 0x33 }, /* GURMUKHI DIGIT THREE -> '3' */ + { 0x6A, 0x34 }, /* GURMUKHI DIGIT FOUR -> '4' */ + { 0x6B, 0x35 }, /* GURMUKHI DIGIT FIVE -> '5' */ + { 0x6C, 0x36 }, /* GURMUKHI DIGIT SIX -> '6' */ + { 0x6D, 0x37 }, /* GURMUKHI DIGIT SEVEN -> '7' */ + { 0x6E, 0x38 }, /* GURMUKHI DIGIT EIGHT -> '8' */ + { 0x6F, 0x39 }, /* GURMUKHI DIGIT NINE -> '9' */ + { 0x70, 0x4E }, /* GURMUKHI TIPPI -> 'N' */ + { 0x71, 0x48 }, /* GURMUKHI ADDAK -> 'H' */ + { 0x81, 0x4E }, /* GUJARATI SIGN CANDRABINDU -> 'N' */ + { 0x82, 0x4E }, /* GUJARATI SIGN ANUSVARA -> 'N' */ + { 0x83, 0x48 }, /* GUJARATI SIGN VISARGA -> 'H' */ + { 0x85, 0x61 }, /* GUJARATI LETTER A -> 'a' */ + { 0x87, 0x69 }, /* GUJARATI LETTER I -> 'i' */ + { 0x89, 0x75 }, /* GUJARATI LETTER U -> 'u' */ + { 0x8B, 0x52 }, /* GUJARATI LETTER VOCALIC R -> 'R' */ + { 0x8F, 0x65 }, /* GUJARATI LETTER E -> 'e' */ + { 0x93, 0x6F }, /* GUJARATI LETTER O -> 'o' */ + { 0x95, 0x6B }, /* GUJARATI LETTER KA -> 'k' */ + { 0x97, 0x67 }, /* GUJARATI LETTER GA -> 'g' */ + { 0x9A, 0x63 }, /* GUJARATI LETTER CA -> 'c' */ + { 0x9C, 0x6A }, /* GUJARATI LETTER JA -> 'j' */ + { 0xA4, 0x74 }, /* GUJARATI LETTER TA -> 't' */ + { 0xA6, 0x64 }, /* GUJARATI LETTER DA -> 'd' */ + { 0xA8, 0x6E }, /* GUJARATI LETTER NA -> 'n' */ + { 0xAA, 0x70 }, /* GUJARATI LETTER PA -> 'p' */ + { 0xAC, 0x62 }, /* GUJARATI LETTER BA -> 'b' */ + { 0xAE, 0x6D }, /* GUJARATI LETTER MA -> 'm' */ + { 0xB0, 0x72 }, /* GUJARATI LETTER RA -> 'r' */ + { 0xB2, 0x6C }, /* GUJARATI LETTER LA -> 'l' */ + { 0xB5, 0x76 }, /* GUJARATI LETTER VA -> 'v' */ + { 0xB8, 0x73 }, /* GUJARATI LETTER SA -> 's' */ + { 0xB9, 0x68 }, /* GUJARATI LETTER HA -> 'h' */ + { 0xBC, 0x27 }, /* GUJARATI SIGN NUKTA -> ''' */ + { 0xBD, 0x27 }, /* GUJARATI SIGN AVAGRAHA -> ''' */ + { 0xBF, 0x69 }, /* GUJARATI VOWEL SIGN I -> 'i' */ + { 0xC1, 0x75 }, /* GUJARATI VOWEL SIGN U -> 'u' */ + { 0xC3, 0x52 }, /* GUJARATI VOWEL SIGN VOCALIC R -> 'R' */ + { 0xC7, 0x65 }, /* GUJARATI VOWEL SIGN E -> 'e' */ + { 0xCB, 0x6F }, /* GUJARATI VOWEL SIGN O -> 'o' */ + { 0xE6, 0x30 }, /* GUJARATI DIGIT ZERO -> '0' */ + { 0xE7, 0x31 }, /* GUJARATI DIGIT ONE -> '1' */ + { 0xE8, 0x32 }, /* GUJARATI DIGIT TWO -> '2' */ + { 0xE9, 0x33 }, /* GUJARATI DIGIT THREE -> '3' */ + { 0xEA, 0x34 }, /* GUJARATI DIGIT FOUR -> '4' */ + { 0xEB, 0x35 }, /* GUJARATI DIGIT FIVE -> '5' */ + { 0xEC, 0x36 }, /* GUJARATI DIGIT SIX -> '6' */ + { 0xED, 0x37 }, /* GUJARATI DIGIT SEVEN -> '7' */ + { 0xEE, 0x38 }, /* GUJARATI DIGIT EIGHT -> '8' */ + { 0xEF, 0x39 }, /* GUJARATI DIGIT NINE -> '9' */ + /* Entries for page 0x0B */ + { 0x01, 0x4E }, /* ORIYA SIGN CANDRABINDU -> 'N' */ + { 0x02, 0x4E }, /* ORIYA SIGN ANUSVARA -> 'N' */ + { 0x03, 0x48 }, /* ORIYA SIGN VISARGA -> 'H' */ + { 0x05, 0x61 }, /* ORIYA LETTER A -> 'a' */ + { 0x07, 0x69 }, /* ORIYA LETTER I -> 'i' */ + { 0x09, 0x75 }, /* ORIYA LETTER U -> 'u' */ + { 0x0B, 0x52 }, /* ORIYA LETTER VOCALIC R -> 'R' */ + { 0x0C, 0x4C }, /* ORIYA LETTER VOCALIC L -> 'L' */ + { 0x0F, 0x65 }, /* ORIYA LETTER E -> 'e' */ + { 0x13, 0x6F }, /* ORIYA LETTER O -> 'o' */ + { 0x15, 0x6B }, /* ORIYA LETTER KA -> 'k' */ + { 0x17, 0x67 }, /* ORIYA LETTER GA -> 'g' */ + { 0x1A, 0x63 }, /* ORIYA LETTER CA -> 'c' */ + { 0x1C, 0x6A }, /* ORIYA LETTER JA -> 'j' */ + { 0x24, 0x74 }, /* ORIYA LETTER TA -> 't' */ + { 0x26, 0x64 }, /* ORIYA LETTER DA -> 'd' */ + { 0x28, 0x6E }, /* ORIYA LETTER NA -> 'n' */ + { 0x2A, 0x70 }, /* ORIYA LETTER PA -> 'p' */ + { 0x2C, 0x62 }, /* ORIYA LETTER BA -> 'b' */ + { 0x2E, 0x6D }, /* ORIYA LETTER MA -> 'm' */ + { 0x2F, 0x79 }, /* ORIYA LETTER YA -> 'y' */ + { 0x30, 0x72 }, /* ORIYA LETTER RA -> 'r' */ + { 0x32, 0x6C }, /* ORIYA LETTER LA -> 'l' */ + { 0x38, 0x73 }, /* ORIYA LETTER SA -> 's' */ + { 0x39, 0x68 }, /* ORIYA LETTER HA -> 'h' */ + { 0x3C, 0x27 }, /* ORIYA SIGN NUKTA -> ''' */ + { 0x3D, 0x27 }, /* ORIYA SIGN AVAGRAHA -> ''' */ + { 0x3F, 0x69 }, /* ORIYA VOWEL SIGN I -> 'i' */ + { 0x41, 0x75 }, /* ORIYA VOWEL SIGN U -> 'u' */ + { 0x43, 0x52 }, /* ORIYA VOWEL SIGN VOCALIC R -> 'R' */ + { 0x47, 0x65 }, /* ORIYA VOWEL SIGN E -> 'e' */ + { 0x4B, 0x6F }, /* ORIYA VOWEL SIGN O -> 'o' */ + { 0x56, 0x2B }, /* ORIYA AI LENGTH MARK -> '+' */ + { 0x57, 0x2B }, /* ORIYA AU LENGTH MARK -> '+' */ + { 0x66, 0x30 }, /* ORIYA DIGIT ZERO -> '0' */ + { 0x67, 0x31 }, /* ORIYA DIGIT ONE -> '1' */ + { 0x68, 0x32 }, /* ORIYA DIGIT TWO -> '2' */ + { 0x69, 0x33 }, /* ORIYA DIGIT THREE -> '3' */ + { 0x6A, 0x34 }, /* ORIYA DIGIT FOUR -> '4' */ + { 0x6B, 0x35 }, /* ORIYA DIGIT FIVE -> '5' */ + { 0x6C, 0x36 }, /* ORIYA DIGIT SIX -> '6' */ + { 0x6D, 0x37 }, /* ORIYA DIGIT SEVEN -> '7' */ + { 0x6E, 0x38 }, /* ORIYA DIGIT EIGHT -> '8' */ + { 0x6F, 0x39 }, /* ORIYA DIGIT NINE -> '9' */ + { 0x82, 0x4E }, /* TAMIL SIGN ANUSVARA -> 'N' */ + { 0x83, 0x48 }, /* TAMIL SIGN VISARGA -> 'H' */ + { 0x85, 0x61 }, /* TAMIL LETTER A -> 'a' */ + { 0x87, 0x69 }, /* TAMIL LETTER I -> 'i' */ + { 0x89, 0x75 }, /* TAMIL LETTER U -> 'u' */ + { 0x8E, 0x65 }, /* TAMIL LETTER E -> 'e' */ + { 0x92, 0x6F }, /* TAMIL LETTER O -> 'o' */ + { 0x95, 0x6B }, /* TAMIL LETTER KA -> 'k' */ + { 0x9A, 0x63 }, /* TAMIL LETTER CA -> 'c' */ + { 0x9C, 0x6A }, /* TAMIL LETTER JA -> 'j' */ + { 0xA4, 0x74 }, /* TAMIL LETTER TA -> 't' */ + { 0xA8, 0x6E }, /* TAMIL LETTER NA -> 'n' */ + { 0xAA, 0x70 }, /* TAMIL LETTER PA -> 'p' */ + { 0xAE, 0x6D }, /* TAMIL LETTER MA -> 'm' */ + { 0xAF, 0x79 }, /* TAMIL LETTER YA -> 'y' */ + { 0xB0, 0x72 }, /* TAMIL LETTER RA -> 'r' */ + { 0xB2, 0x6C }, /* TAMIL LETTER LA -> 'l' */ + { 0xB5, 0x76 }, /* TAMIL LETTER VA -> 'v' */ + { 0xB8, 0x73 }, /* TAMIL LETTER SA -> 's' */ + { 0xB9, 0x68 }, /* TAMIL LETTER HA -> 'h' */ + { 0xBF, 0x69 }, /* TAMIL VOWEL SIGN I -> 'i' */ + { 0xC1, 0x75 }, /* TAMIL VOWEL SIGN U -> 'u' */ + { 0xC6, 0x65 }, /* TAMIL VOWEL SIGN E -> 'e' */ + { 0xCA, 0x6F }, /* TAMIL VOWEL SIGN O -> 'o' */ + { 0xD7, 0x2B }, /* TAMIL AU LENGTH MARK -> '+' */ + { 0xE6, 0x30 }, /* TAMIL DIGIT ZERO -> '0' */ + { 0xE7, 0x31 }, /* TAMIL DIGIT ONE -> '1' */ + { 0xE8, 0x32 }, /* TAMIL DIGIT TWO -> '2' */ + { 0xE9, 0x33 }, /* TAMIL DIGIT THREE -> '3' */ + { 0xEA, 0x34 }, /* TAMIL DIGIT FOUR -> '4' */ + { 0xEB, 0x35 }, /* TAMIL DIGIT FIVE -> '5' */ + { 0xEC, 0x36 }, /* TAMIL DIGIT SIX -> '6' */ + { 0xED, 0x37 }, /* TAMIL DIGIT SEVEN -> '7' */ + { 0xEE, 0x38 }, /* TAMIL DIGIT EIGHT -> '8' */ + { 0xEF, 0x39 }, /* TAMIL DIGIT NINE -> '9' */ + /* Entries for page 0x0C */ + { 0x01, 0x4E }, /* TELUGU SIGN CANDRABINDU -> 'N' */ + { 0x02, 0x4E }, /* TELUGU SIGN ANUSVARA -> 'N' */ + { 0x03, 0x48 }, /* TELUGU SIGN VISARGA -> 'H' */ + { 0x05, 0x61 }, /* TELUGU LETTER A -> 'a' */ + { 0x07, 0x69 }, /* TELUGU LETTER I -> 'i' */ + { 0x09, 0x75 }, /* TELUGU LETTER U -> 'u' */ + { 0x0B, 0x52 }, /* TELUGU LETTER VOCALIC R -> 'R' */ + { 0x0C, 0x4C }, /* TELUGU LETTER VOCALIC L -> 'L' */ + { 0x0E, 0x65 }, /* TELUGU LETTER E -> 'e' */ + { 0x12, 0x6F }, /* TELUGU LETTER O -> 'o' */ + { 0x15, 0x6B }, /* TELUGU LETTER KA -> 'k' */ + { 0x17, 0x67 }, /* TELUGU LETTER GA -> 'g' */ + { 0x1A, 0x63 }, /* TELUGU LETTER CA -> 'c' */ + { 0x1C, 0x6A }, /* TELUGU LETTER JA -> 'j' */ + { 0x24, 0x74 }, /* TELUGU LETTER TA -> 't' */ + { 0x26, 0x64 }, /* TELUGU LETTER DA -> 'd' */ + { 0x28, 0x6E }, /* TELUGU LETTER NA -> 'n' */ + { 0x2A, 0x70 }, /* TELUGU LETTER PA -> 'p' */ + { 0x2C, 0x62 }, /* TELUGU LETTER BA -> 'b' */ + { 0x2E, 0x6D }, /* TELUGU LETTER MA -> 'm' */ + { 0x2F, 0x79 }, /* TELUGU LETTER YA -> 'y' */ + { 0x30, 0x72 }, /* TELUGU LETTER RA -> 'r' */ + { 0x32, 0x6C }, /* TELUGU LETTER LA -> 'l' */ + { 0x35, 0x76 }, /* TELUGU LETTER VA -> 'v' */ + { 0x38, 0x73 }, /* TELUGU LETTER SA -> 's' */ + { 0x39, 0x68 }, /* TELUGU LETTER HA -> 'h' */ + { 0x3F, 0x69 }, /* TELUGU VOWEL SIGN I -> 'i' */ + { 0x41, 0x75 }, /* TELUGU VOWEL SIGN U -> 'u' */ + { 0x43, 0x52 }, /* TELUGU VOWEL SIGN VOCALIC R -> 'R' */ + { 0x46, 0x65 }, /* TELUGU VOWEL SIGN E -> 'e' */ + { 0x4A, 0x6F }, /* TELUGU VOWEL SIGN O -> 'o' */ + { 0x55, 0x2B }, /* TELUGU LENGTH MARK -> '+' */ + { 0x56, 0x2B }, /* TELUGU AI LENGTH MARK -> '+' */ + { 0x66, 0x30 }, /* TELUGU DIGIT ZERO -> '0' */ + { 0x67, 0x31 }, /* TELUGU DIGIT ONE -> '1' */ + { 0x68, 0x32 }, /* TELUGU DIGIT TWO -> '2' */ + { 0x69, 0x33 }, /* TELUGU DIGIT THREE -> '3' */ + { 0x6A, 0x34 }, /* TELUGU DIGIT FOUR -> '4' */ + { 0x6B, 0x35 }, /* TELUGU DIGIT FIVE -> '5' */ + { 0x6C, 0x36 }, /* TELUGU DIGIT SIX -> '6' */ + { 0x6D, 0x37 }, /* TELUGU DIGIT SEVEN -> '7' */ + { 0x6E, 0x38 }, /* TELUGU DIGIT EIGHT -> '8' */ + { 0x6F, 0x39 }, /* TELUGU DIGIT NINE -> '9' */ + { 0x82, 0x4E }, /* KANNADA SIGN ANUSVARA -> 'N' */ + { 0x83, 0x48 }, /* KANNADA SIGN VISARGA -> 'H' */ + { 0x85, 0x61 }, /* KANNADA LETTER A -> 'a' */ + { 0x87, 0x69 }, /* KANNADA LETTER I -> 'i' */ + { 0x89, 0x75 }, /* KANNADA LETTER U -> 'u' */ + { 0x8B, 0x52 }, /* KANNADA LETTER VOCALIC R -> 'R' */ + { 0x8C, 0x4C }, /* KANNADA LETTER VOCALIC L -> 'L' */ + { 0x8E, 0x65 }, /* KANNADA LETTER E -> 'e' */ + { 0x92, 0x6F }, /* KANNADA LETTER O -> 'o' */ + { 0x95, 0x6B }, /* KANNADA LETTER KA -> 'k' */ + { 0x97, 0x67 }, /* KANNADA LETTER GA -> 'g' */ + { 0x9A, 0x63 }, /* KANNADA LETTER CA -> 'c' */ + { 0x9C, 0x6A }, /* KANNADA LETTER JA -> 'j' */ + { 0xA4, 0x74 }, /* KANNADA LETTER TA -> 't' */ + { 0xA6, 0x64 }, /* KANNADA LETTER DA -> 'd' */ + { 0xA8, 0x6E }, /* KANNADA LETTER NA -> 'n' */ + { 0xAA, 0x70 }, /* KANNADA LETTER PA -> 'p' */ + { 0xAC, 0x62 }, /* KANNADA LETTER BA -> 'b' */ + { 0xAE, 0x6D }, /* KANNADA LETTER MA -> 'm' */ + { 0xAF, 0x79 }, /* KANNADA LETTER YA -> 'y' */ + { 0xB0, 0x72 }, /* KANNADA LETTER RA -> 'r' */ + { 0xB2, 0x6C }, /* KANNADA LETTER LA -> 'l' */ + { 0xB5, 0x76 }, /* KANNADA LETTER VA -> 'v' */ + { 0xB8, 0x73 }, /* KANNADA LETTER SA -> 's' */ + { 0xB9, 0x68 }, /* KANNADA LETTER HA -> 'h' */ + { 0xBF, 0x69 }, /* KANNADA VOWEL SIGN I -> 'i' */ + { 0xC1, 0x75 }, /* KANNADA VOWEL SIGN U -> 'u' */ + { 0xC3, 0x52 }, /* KANNADA VOWEL SIGN VOCALIC R -> 'R' */ + { 0xC6, 0x65 }, /* KANNADA VOWEL SIGN E -> 'e' */ + { 0xCA, 0x6F }, /* KANNADA VOWEL SIGN O -> 'o' */ + { 0xD5, 0x2B }, /* KANNADA LENGTH MARK -> '+' */ + { 0xD6, 0x2B }, /* KANNADA AI LENGTH MARK -> '+' */ + { 0xE6, 0x30 }, /* KANNADA DIGIT ZERO -> '0' */ + { 0xE7, 0x31 }, /* KANNADA DIGIT ONE -> '1' */ + { 0xE8, 0x32 }, /* KANNADA DIGIT TWO -> '2' */ + { 0xE9, 0x33 }, /* KANNADA DIGIT THREE -> '3' */ + { 0xEA, 0x34 }, /* KANNADA DIGIT FOUR -> '4' */ + { 0xEB, 0x35 }, /* KANNADA DIGIT FIVE -> '5' */ + { 0xEC, 0x36 }, /* KANNADA DIGIT SIX -> '6' */ + { 0xED, 0x37 }, /* KANNADA DIGIT SEVEN -> '7' */ + { 0xEE, 0x38 }, /* KANNADA DIGIT EIGHT -> '8' */ + { 0xEF, 0x39 }, /* KANNADA DIGIT NINE -> '9' */ + /* Entries for page 0x0D */ + { 0x02, 0x4E }, /* MALAYALAM SIGN ANUSVARA -> 'N' */ + { 0x03, 0x48 }, /* MALAYALAM SIGN VISARGA -> 'H' */ + { 0x05, 0x61 }, /* MALAYALAM LETTER A -> 'a' */ + { 0x07, 0x69 }, /* MALAYALAM LETTER I -> 'i' */ + { 0x09, 0x75 }, /* MALAYALAM LETTER U -> 'u' */ + { 0x0B, 0x52 }, /* MALAYALAM LETTER VOCALIC R -> 'R' */ + { 0x0C, 0x4C }, /* MALAYALAM LETTER VOCALIC L -> 'L' */ + { 0x0E, 0x65 }, /* MALAYALAM LETTER E -> 'e' */ + { 0x12, 0x6F }, /* MALAYALAM LETTER O -> 'o' */ + { 0x15, 0x6B }, /* MALAYALAM LETTER KA -> 'k' */ + { 0x17, 0x67 }, /* MALAYALAM LETTER GA -> 'g' */ + { 0x1A, 0x63 }, /* MALAYALAM LETTER CA -> 'c' */ + { 0x1C, 0x6A }, /* MALAYALAM LETTER JA -> 'j' */ + { 0x24, 0x74 }, /* MALAYALAM LETTER TA -> 't' */ + { 0x26, 0x64 }, /* MALAYALAM LETTER DA -> 'd' */ + { 0x28, 0x6E }, /* MALAYALAM LETTER NA -> 'n' */ + { 0x2A, 0x70 }, /* MALAYALAM LETTER PA -> 'p' */ + { 0x2C, 0x62 }, /* MALAYALAM LETTER BA -> 'b' */ + { 0x2E, 0x6D }, /* MALAYALAM LETTER MA -> 'm' */ + { 0x2F, 0x79 }, /* MALAYALAM LETTER YA -> 'y' */ + { 0x30, 0x72 }, /* MALAYALAM LETTER RA -> 'r' */ + { 0x32, 0x6C }, /* MALAYALAM LETTER LA -> 'l' */ + { 0x35, 0x76 }, /* MALAYALAM LETTER VA -> 'v' */ + { 0x38, 0x73 }, /* MALAYALAM LETTER SA -> 's' */ + { 0x39, 0x68 }, /* MALAYALAM LETTER HA -> 'h' */ + { 0x3F, 0x69 }, /* MALAYALAM VOWEL SIGN I -> 'i' */ + { 0x41, 0x75 }, /* MALAYALAM VOWEL SIGN U -> 'u' */ + { 0x43, 0x52 }, /* MALAYALAM VOWEL SIGN VOCALIC R -> 'R' */ + { 0x46, 0x65 }, /* MALAYALAM VOWEL SIGN E -> 'e' */ + { 0x4A, 0x6F }, /* MALAYALAM VOWEL SIGN O -> 'o' */ + { 0x57, 0x2B }, /* MALAYALAM AU LENGTH MARK -> '+' */ + { 0x66, 0x30 }, /* MALAYALAM DIGIT ZERO -> '0' */ + { 0x67, 0x31 }, /* MALAYALAM DIGIT ONE -> '1' */ + { 0x68, 0x32 }, /* MALAYALAM DIGIT TWO -> '2' */ + { 0x69, 0x33 }, /* MALAYALAM DIGIT THREE -> '3' */ + { 0x6A, 0x34 }, /* MALAYALAM DIGIT FOUR -> '4' */ + { 0x6B, 0x35 }, /* MALAYALAM DIGIT FIVE -> '5' */ + { 0x6C, 0x36 }, /* MALAYALAM DIGIT SIX -> '6' */ + { 0x6D, 0x37 }, /* MALAYALAM DIGIT SEVEN -> '7' */ + { 0x6E, 0x38 }, /* MALAYALAM DIGIT EIGHT -> '8' */ + { 0x6F, 0x39 }, /* MALAYALAM DIGIT NINE -> '9' */ + { 0x82, 0x4E }, /* SINHALA SIGN ANUSVARAYA -> 'N' */ + { 0x83, 0x48 }, /* SINHALA SIGN VISARGAYA -> 'H' */ + { 0x85, 0x61 }, /* SINHALA LETTER AYANNA -> 'a' */ + { 0x89, 0x69 }, /* SINHALA LETTER IYANNA -> 'i' */ + { 0x8B, 0x75 }, /* SINHALA LETTER UYANNA -> 'u' */ + { 0x8D, 0x52 }, /* SINHALA LETTER IRUYANNA -> 'R' */ + { 0x8F, 0x4C }, /* SINHALA LETTER ILUYANNA -> 'L' */ + { 0x91, 0x65 }, /* SINHALA LETTER EYANNA -> 'e' */ + { 0x94, 0x6F }, /* SINHALA LETTER OYANNA -> 'o' */ + { 0x9A, 0x6B }, /* SINHALA LETTER ALPAPRAANA KAYANNA -> 'k' */ + { 0x9C, 0x67 }, /* SINHALA LETTER ALPAPRAANA GAYANNA -> 'g' */ + { 0xA0, 0x63 }, /* SINHALA LETTER ALPAPRAANA CAYANNA -> 'c' */ + { 0xA2, 0x6A }, /* SINHALA LETTER ALPAPRAANA JAYANNA -> 'j' */ + { 0xAD, 0x74 }, /* SINHALA LETTER ALPAPRAANA TAYANNA -> 't' */ + { 0xAF, 0x64 }, /* SINHALA LETTER ALPAPRAANA DAYANNA -> 'd' */ + { 0xB1, 0x6E }, /* SINHALA LETTER DANTAJA NAYANNA -> 'n' */ + { 0xB4, 0x70 }, /* SINHALA LETTER ALPAPRAANA PAYANNA -> 'p' */ + { 0xB6, 0x62 }, /* SINHALA LETTER ALPAPRAANA BAYANNA -> 'b' */ + { 0xB8, 0x6D }, /* SINHALA LETTER MAYANNA -> 'm' */ + { 0xBA, 0x79 }, /* SINHALA LETTER YAYANNA -> 'y' */ + { 0xBB, 0x72 }, /* SINHALA LETTER RAYANNA -> 'r' */ + { 0xBD, 0x6C }, /* SINHALA LETTER DANTAJA LAYANNA -> 'l' */ + { 0xC0, 0x76 }, /* SINHALA LETTER VAYANNA -> 'v' */ + { 0xC3, 0x73 }, /* SINHALA LETTER DANTAJA SAYANNA -> 's' */ + { 0xC4, 0x68 }, /* SINHALA LETTER HAYANNA -> 'h' */ + { 0xC6, 0x66 }, /* SINHALA LETTER FAYANNA -> 'f' */ + { 0xD2, 0x69 }, /* SINHALA VOWEL SIGN KETTI IS-PILLA -> 'i' */ + { 0xD4, 0x75 }, /* SINHALA VOWEL SIGN KETTI PAA-PILLA -> 'u' */ + { 0xD8, 0x52 }, /* SINHALA VOWEL SIGN GAETTA-PILLA -> 'R' */ + { 0xD9, 0x65 }, /* SINHALA VOWEL SIGN KOMBUVA -> 'e' */ + { 0xDC, 0x6F }, /* SINHALA VOWEL SIGN KOMBUVA HAA AELA-PILLA -> 'o' */ + { 0xDF, 0x4C }, /* SINHALA VOWEL SIGN GAYANUKITTA -> 'L' */ + /* Entries for page 0x0E */ + { 0x01, 0x6B }, /* THAI CHARACTER KO KAI -> 'k' */ + { 0x0D, 0x79 }, /* THAI CHARACTER YO YING -> 'y' */ + { 0x0E, 0x64 }, /* THAI CHARACTER DO CHADA -> 'd' */ + { 0x0F, 0x74 }, /* THAI CHARACTER TO PATAK -> 't' */ + { 0x13, 0x6E }, /* THAI CHARACTER NO NEN -> 'n' */ + { 0x14, 0x64 }, /* THAI CHARACTER DO DEK -> 'd' */ + { 0x15, 0x74 }, /* THAI CHARACTER TO TAO -> 't' */ + { 0x19, 0x6E }, /* THAI CHARACTER NO NU -> 'n' */ + { 0x1A, 0x62 }, /* THAI CHARACTER BO BAIMAI -> 'b' */ + { 0x1B, 0x70 }, /* THAI CHARACTER PO PLA -> 'p' */ + { 0x1D, 0x66 }, /* THAI CHARACTER FO FA -> 'f' */ + { 0x1F, 0x66 }, /* THAI CHARACTER FO FAN -> 'f' */ + { 0x21, 0x6D }, /* THAI CHARACTER MO MA -> 'm' */ + { 0x22, 0x79 }, /* THAI CHARACTER YO YAK -> 'y' */ + { 0x23, 0x72 }, /* THAI CHARACTER RO RUA -> 'r' */ + { 0x24, 0x52 }, /* THAI CHARACTER RU -> 'R' */ + { 0x25, 0x6C }, /* THAI CHARACTER LO LING -> 'l' */ + { 0x26, 0x4C }, /* THAI CHARACTER LU -> 'L' */ + { 0x27, 0x77 }, /* THAI CHARACTER WO WAEN -> 'w' */ + { 0x28, 0x00 }, /* THAI CHARACTER SO SALA -> ... */ + { 0x2A, 0x73 }, /* THAI CHARACTER SO SUA -> 's' */ + { 0x2B, 0x68 }, /* THAI CHARACTER HO HIP -> 'h' */ + { 0x2C, 0x6C }, /* THAI CHARACTER LO CHULA -> 'l' */ + { 0x2D, 0x60 }, /* THAI CHARACTER O ANG -> '`' */ + { 0x2E, 0x68 }, /* THAI CHARACTER HO NOKHUK -> 'h' */ + { 0x2F, 0x7E }, /* THAI CHARACTER PAIYANNOI -> '~' */ + { 0x30, 0x61 }, /* THAI CHARACTER SARA A -> 'a' */ + { 0x31, 0x61 }, /* THAI CHARACTER MAI HAN-AKAT -> 'a' */ + { 0x34, 0x69 }, /* THAI CHARACTER SARA I -> 'i' */ + { 0x38, 0x75 }, /* THAI CHARACTER SARA U -> 'u' */ + { 0x3A, 0x27 }, /* THAI CHARACTER PHINTHU -> ''' */ + { 0x40, 0x65 }, /* THAI CHARACTER SARA E -> 'e' */ + { 0x42, 0x6F }, /* THAI CHARACTER SARA O -> 'o' */ + { 0x46, 0x2B }, /* THAI CHARACTER MAIYAMOK -> '+' */ + { 0x4D, 0x4D }, /* THAI CHARACTER NIKHAHIT -> 'M' */ + { 0x50, 0x30 }, /* THAI DIGIT ZERO -> '0' */ + { 0x51, 0x31 }, /* THAI DIGIT ONE -> '1' */ + { 0x52, 0x32 }, /* THAI DIGIT TWO -> '2' */ + { 0x53, 0x33 }, /* THAI DIGIT THREE -> '3' */ + { 0x54, 0x34 }, /* THAI DIGIT FOUR -> '4' */ + { 0x55, 0x35 }, /* THAI DIGIT FIVE -> '5' */ + { 0x56, 0x36 }, /* THAI DIGIT SIX -> '6' */ + { 0x57, 0x37 }, /* THAI DIGIT SEVEN -> '7' */ + { 0x58, 0x38 }, /* THAI DIGIT EIGHT -> '8' */ + { 0x59, 0x39 }, /* THAI DIGIT NINE -> '9' */ + { 0x81, 0x6B }, /* LAO LETTER KO -> 'k' */ + { 0x8A, 0x73 }, /* LAO LETTER SO TAM -> 's' */ + { 0x94, 0x64 }, /* LAO LETTER DO -> 'd' */ + { 0x95, 0x68 }, /* LAO LETTER TO -> 'h' */ + { 0x99, 0x6E }, /* LAO LETTER NO -> 'n' */ + { 0x9A, 0x62 }, /* LAO LETTER BO -> 'b' */ + { 0x9B, 0x70 }, /* LAO LETTER PO -> 'p' */ + { 0x9D, 0x66 }, /* LAO LETTER FO TAM -> 'f' */ + { 0x9F, 0x66 }, /* LAO LETTER FO SUNG -> 'f' */ + { 0xA1, 0x6D }, /* LAO LETTER MO -> 'm' */ + { 0xA2, 0x79 }, /* LAO LETTER YO -> 'y' */ + { 0xA3, 0x72 }, /* LAO LETTER LO LING -> 'r' */ + { 0xA5, 0x6C }, /* LAO LETTER LO LOOT -> 'l' */ + { 0xA7, 0x77 }, /* LAO LETTER WO -> 'w' */ + { 0xAA, 0x73 }, /* LAO LETTER SO SUNG -> 's' */ + { 0xAB, 0x68 }, /* LAO LETTER HO SUNG -> 'h' */ + { 0xAD, 0x60 }, /* LAO LETTER O -> '`' */ + { 0xAF, 0x7E }, /* LAO ELLIPSIS -> '~' */ + { 0xB0, 0x61 }, /* LAO VOWEL SIGN A -> 'a' */ + { 0xB4, 0x69 }, /* LAO VOWEL SIGN I -> 'i' */ + { 0xB6, 0x79 }, /* LAO VOWEL SIGN Y -> 'y' */ + { 0xB8, 0x75 }, /* LAO VOWEL SIGN U -> 'u' */ + { 0xBB, 0x6F }, /* LAO VOWEL SIGN MAI KON -> 'o' */ + { 0xBC, 0x6C }, /* LAO SEMIVOWEL SIGN LO -> 'l' */ + { 0xC0, 0x65 }, /* LAO VOWEL SIGN E -> 'e' */ + { 0xC2, 0x6F }, /* LAO VOWEL SIGN O -> 'o' */ + { 0xC6, 0x2B }, /* LAO KO LA -> '+' */ + { 0xCD, 0x4D }, /* LAO NIGGAHITA -> 'M' */ + { 0xD0, 0x30 }, /* LAO DIGIT ZERO -> '0' */ + { 0xD1, 0x31 }, /* LAO DIGIT ONE -> '1' */ + { 0xD2, 0x32 }, /* LAO DIGIT TWO -> '2' */ + { 0xD3, 0x33 }, /* LAO DIGIT THREE -> '3' */ + { 0xD4, 0x34 }, /* LAO DIGIT FOUR -> '4' */ + { 0xD5, 0x35 }, /* LAO DIGIT FIVE -> '5' */ + { 0xD6, 0x36 }, /* LAO DIGIT SIX -> '6' */ + { 0xD7, 0x37 }, /* LAO DIGIT SEVEN -> '7' */ + { 0xD8, 0x38 }, /* LAO DIGIT EIGHT -> '8' */ + { 0xD9, 0x39 }, /* LAO DIGIT NINE -> '9' */ + /* Entries for page 0x0F */ + { 0x0B, 0x2D }, /* TIBETAN MARK INTERSYLLABIC TSHEG -> '-' */ + { 0x20, 0x30 }, /* TIBETAN DIGIT ZERO -> '0' */ + { 0x21, 0x31 }, /* TIBETAN DIGIT ONE -> '1' */ + { 0x22, 0x32 }, /* TIBETAN DIGIT TWO -> '2' */ + { 0x23, 0x33 }, /* TIBETAN DIGIT THREE -> '3' */ + { 0x24, 0x34 }, /* TIBETAN DIGIT FOUR -> '4' */ + { 0x25, 0x35 }, /* TIBETAN DIGIT FIVE -> '5' */ + { 0x26, 0x36 }, /* TIBETAN DIGIT SIX -> '6' */ + { 0x27, 0x37 }, /* TIBETAN DIGIT SEVEN -> '7' */ + { 0x28, 0x38 }, /* TIBETAN DIGIT EIGHT -> '8' */ + { 0x29, 0x39 }, /* TIBETAN DIGIT NINE -> '9' */ + { 0x34, 0x2B }, /* TIBETAN MARK BSDUS RTAGS -> '+' */ + { 0x35, 0x2A }, /* TIBETAN MARK NGAS BZUNG NYI ZLA -> '*' */ + { 0x36, 0x5E }, /* TIBETAN MARK CARET -DZUD RTAGS BZHI MIG CAN -> '^' */ + { 0x37, 0x5F }, /* TIBETAN MARK NGAS BZUNG SGOR RTAGS -> '_' */ + { 0x39, 0x7E }, /* TIBETAN MARK TSA -PHRU -> '~' */ + { 0x3B, 0x5D }, /* TIBETAN MARK GUG RTAGS GYAS -> ']' */ + { 0x40, 0x6B }, /* TIBETAN LETTER KA -> 'k' */ + { 0x42, 0x67 }, /* TIBETAN LETTER GA -> 'g' */ + { 0x45, 0x63 }, /* TIBETAN LETTER CA -> 'c' */ + { 0x47, 0x6A }, /* TIBETAN LETTER JA -> 'j' */ + { 0x4F, 0x74 }, /* TIBETAN LETTER TA -> 't' */ + { 0x51, 0x64 }, /* TIBETAN LETTER DA -> 'd' */ + { 0x53, 0x6E }, /* TIBETAN LETTER NA -> 'n' */ + { 0x54, 0x70 }, /* TIBETAN LETTER PA -> 'p' */ + { 0x56, 0x62 }, /* TIBETAN LETTER BA -> 'b' */ + { 0x58, 0x6D }, /* TIBETAN LETTER MA -> 'm' */ + { 0x5D, 0x77 }, /* TIBETAN LETTER WA -> 'w' */ + { 0x5F, 0x7A }, /* TIBETAN LETTER ZA -> 'z' */ + { 0x60, 0x27 }, /* TIBETAN LETTER -A -> ''' */ + { 0x61, 0x79 }, /* TIBETAN LETTER YA -> 'y' */ + { 0x62, 0x72 }, /* TIBETAN LETTER RA -> 'r' */ + { 0x63, 0x6C }, /* TIBETAN LETTER LA -> 'l' */ + { 0x66, 0x73 }, /* TIBETAN LETTER SA -> 's' */ + { 0x67, 0x68 }, /* TIBETAN LETTER HA -> 'h' */ + { 0x68, 0x61 }, /* TIBETAN LETTER A -> 'a' */ + { 0x6A, 0x72 }, /* TIBETAN LETTER FIXED-FORM RA -> 'r' */ + { 0x72, 0x69 }, /* TIBETAN VOWEL SIGN I -> 'i' */ + { 0x74, 0x75 }, /* TIBETAN VOWEL SIGN U -> 'u' */ + { 0x76, 0x52 }, /* TIBETAN VOWEL SIGN VOCALIC R -> 'R' */ + { 0x78, 0x4C }, /* TIBETAN VOWEL SIGN VOCALIC L -> 'L' */ + { 0x7A, 0x65 }, /* TIBETAN VOWEL SIGN E -> 'e' */ + { 0x7C, 0x6F }, /* TIBETAN VOWEL SIGN O -> 'o' */ + { 0x7E, 0x4D }, /* TIBETAN SIGN RJES SU NGA RO -> 'M' */ + { 0x7F, 0x48 }, /* TIBETAN SIGN RNAM BCAD -> 'H' */ + { 0x80, 0x69 }, /* TIBETAN VOWEL SIGN REVERSED I -> 'i' */ + { 0x90, 0x6B }, /* TIBETAN SUBJOINED LETTER KA -> 'k' */ + { 0x92, 0x67 }, /* TIBETAN SUBJOINED LETTER GA -> 'g' */ + { 0x95, 0x63 }, /* TIBETAN SUBJOINED LETTER CA -> 'c' */ + { 0x97, 0x6A }, /* TIBETAN SUBJOINED LETTER JA -> 'j' */ + { 0x9F, 0x74 }, /* TIBETAN SUBJOINED LETTER TA -> 't' */ + { 0xA1, 0x64 }, /* TIBETAN SUBJOINED LETTER DA -> 'd' */ + { 0xA3, 0x6E }, /* TIBETAN SUBJOINED LETTER NA -> 'n' */ + { 0xA4, 0x70 }, /* TIBETAN SUBJOINED LETTER PA -> 'p' */ + { 0xA6, 0x62 }, /* TIBETAN SUBJOINED LETTER BA -> 'b' */ + { 0xA8, 0x6D }, /* TIBETAN SUBJOINED LETTER MA -> 'm' */ + { 0xAD, 0x77 }, /* TIBETAN SUBJOINED LETTER WA -> 'w' */ + { 0xAF, 0x7A }, /* TIBETAN SUBJOINED LETTER ZA -> 'z' */ + { 0xB0, 0x27 }, /* TIBETAN SUBJOINED LETTER -A -> ''' */ + { 0xB1, 0x79 }, /* TIBETAN SUBJOINED LETTER YA -> 'y' */ + { 0xB2, 0x72 }, /* TIBETAN SUBJOINED LETTER RA -> 'r' */ + { 0xB3, 0x6C }, /* TIBETAN SUBJOINED LETTER LA -> 'l' */ + { 0xB6, 0x73 }, /* TIBETAN SUBJOINED LETTER SA -> 's' */ + { 0xB7, 0x68 }, /* TIBETAN SUBJOINED LETTER HA -> 'h' */ + { 0xB8, 0x61 }, /* TIBETAN SUBJOINED LETTER A -> 'a' */ + { 0xBA, 0x77 }, /* TIBETAN SUBJOINED LETTER FIXED-FORM WA -> 'w' */ + { 0xBB, 0x79 }, /* TIBETAN SUBJOINED LETTER FIXED-FORM YA -> 'y' */ + { 0xBC, 0x72 }, /* TIBETAN SUBJOINED LETTER FIXED-FORM RA -> 'r' */ + { 0xBE, 0x58 }, /* TIBETAN KU RU KHA -> 'X' */ + /* Entries for page 0x10 */ + { 0x00, 0x6B }, /* MYANMAR LETTER KA -> 'k' */ + { 0x02, 0x67 }, /* MYANMAR LETTER GA -> 'g' */ + { 0x05, 0x63 }, /* MYANMAR LETTER CA -> 'c' */ + { 0x07, 0x6A }, /* MYANMAR LETTER JA -> 'j' */ + { 0x12, 0x64 }, /* MYANMAR LETTER DA -> 'd' */ + { 0x14, 0x6E }, /* MYANMAR LETTER NA -> 'n' */ + { 0x15, 0x70 }, /* MYANMAR LETTER PA -> 'p' */ + { 0x17, 0x62 }, /* MYANMAR LETTER BA -> 'b' */ + { 0x19, 0x6D }, /* MYANMAR LETTER MA -> 'm' */ + { 0x1A, 0x79 }, /* MYANMAR LETTER YA -> 'y' */ + { 0x1B, 0x72 }, /* MYANMAR LETTER RA -> 'r' */ + { 0x1C, 0x6C }, /* MYANMAR LETTER LA -> 'l' */ + { 0x1D, 0x77 }, /* MYANMAR LETTER WA -> 'w' */ + { 0x1E, 0x73 }, /* MYANMAR LETTER SA -> 's' */ + { 0x1F, 0x68 }, /* MYANMAR LETTER HA -> 'h' */ + { 0x21, 0x61 }, /* MYANMAR LETTER A -> 'a' */ + { 0x23, 0x69 }, /* MYANMAR LETTER I -> 'i' */ + { 0x25, 0x75 }, /* MYANMAR LETTER U -> 'u' */ + { 0x27, 0x65 }, /* MYANMAR LETTER E -> 'e' */ + { 0x29, 0x6F }, /* MYANMAR LETTER O -> 'o' */ + { 0x2D, 0x69 }, /* MYANMAR VOWEL SIGN I -> 'i' */ + { 0x2F, 0x75 }, /* MYANMAR VOWEL SIGN U -> 'u' */ + { 0x31, 0x65 }, /* MYANMAR VOWEL SIGN E -> 'e' */ + { 0x36, 0x4E }, /* MYANMAR SIGN ANUSVARA -> 'N' */ + { 0x37, 0x27 }, /* MYANMAR SIGN DOT BELOW -> ''' */ + { 0x38, 0x3A }, /* MYANMAR SIGN VISARGA -> ':' */ + { 0x40, 0x30 }, /* MYANMAR DIGIT ZERO -> '0' */ + { 0x41, 0x31 }, /* MYANMAR DIGIT ONE -> '1' */ + { 0x42, 0x32 }, /* MYANMAR DIGIT TWO -> '2' */ + { 0x43, 0x33 }, /* MYANMAR DIGIT THREE -> '3' */ + { 0x44, 0x34 }, /* MYANMAR DIGIT FOUR -> '4' */ + { 0x45, 0x35 }, /* MYANMAR DIGIT FIVE -> '5' */ + { 0x46, 0x36 }, /* MYANMAR DIGIT SIX -> '6' */ + { 0x47, 0x37 }, /* MYANMAR DIGIT SEVEN -> '7' */ + { 0x48, 0x38 }, /* MYANMAR DIGIT EIGHT -> '8' */ + { 0x49, 0x39 }, /* MYANMAR DIGIT NINE -> '9' */ + { 0x52, 0x52 }, /* MYANMAR LETTER VOCALIC R -> 'R' */ + { 0x54, 0x4C }, /* MYANMAR LETTER VOCALIC L -> 'L' */ + { 0x56, 0x52 }, /* MYANMAR VOWEL SIGN VOCALIC R -> 'R' */ + { 0x58, 0x4C }, /* MYANMAR VOWEL SIGN VOCALIC L -> 'L' */ + { 0xA0, 0x41 }, /* GEORGIAN CAPITAL LETTER AN -> 'A' */ + { 0xA1, 0x42 }, /* GEORGIAN CAPITAL LETTER BAN -> 'B' */ + { 0xA2, 0x47 }, /* GEORGIAN CAPITAL LETTER GAN -> 'G' */ + { 0xA3, 0x44 }, /* GEORGIAN CAPITAL LETTER DON -> 'D' */ + { 0xA4, 0x45 }, /* GEORGIAN CAPITAL LETTER EN -> 'E' */ + { 0xA5, 0x56 }, /* GEORGIAN CAPITAL LETTER VIN -> 'V' */ + { 0xA6, 0x5A }, /* GEORGIAN CAPITAL LETTER ZEN -> 'Z' */ + { 0xA8, 0x49 }, /* GEORGIAN CAPITAL LETTER IN -> 'I' */ + { 0xA9, 0x4B }, /* GEORGIAN CAPITAL LETTER KAN -> 'K' */ + { 0xAA, 0x4C }, /* GEORGIAN CAPITAL LETTER LAS -> 'L' */ + { 0xAB, 0x4D }, /* GEORGIAN CAPITAL LETTER MAN -> 'M' */ + { 0xAC, 0x4E }, /* GEORGIAN CAPITAL LETTER NAR -> 'N' */ + { 0xAD, 0x4F }, /* GEORGIAN CAPITAL LETTER ON -> 'O' */ + { 0xAE, 0x50 }, /* GEORGIAN CAPITAL LETTER PAR -> 'P' */ + { 0xB0, 0x52 }, /* GEORGIAN CAPITAL LETTER RAE -> 'R' */ + { 0xB1, 0x53 }, /* GEORGIAN CAPITAL LETTER SAN -> 'S' */ + { 0xB2, 0x54 }, /* GEORGIAN CAPITAL LETTER TAR -> 'T' */ + { 0xB3, 0x55 }, /* GEORGIAN CAPITAL LETTER UN -> 'U' */ + { 0xB7, 0x51 }, /* GEORGIAN CAPITAL LETTER QAR -> 'Q' */ + { 0xBC, 0x43 }, /* GEORGIAN CAPITAL LETTER CIL -> 'C' */ + { 0xBE, 0x58 }, /* GEORGIAN CAPITAL LETTER XAN -> 'X' */ + { 0xBF, 0x4A }, /* GEORGIAN CAPITAL LETTER JHAN -> 'J' */ + { 0xC0, 0x48 }, /* GEORGIAN CAPITAL LETTER HAE -> 'H' */ + { 0xC1, 0x45 }, /* GEORGIAN CAPITAL LETTER HE -> 'E' */ + { 0xC2, 0x59 }, /* GEORGIAN CAPITAL LETTER HIE -> 'Y' */ + { 0xC3, 0x57 }, /* GEORGIAN CAPITAL LETTER WE -> 'W' */ + { 0xD0, 0x61 }, /* GEORGIAN LETTER AN -> 'a' */ + { 0xD1, 0x62 }, /* GEORGIAN LETTER BAN -> 'b' */ + { 0xD2, 0x67 }, /* GEORGIAN LETTER GAN -> 'g' */ + { 0xD3, 0x64 }, /* GEORGIAN LETTER DON -> 'd' */ + { 0xD4, 0x65 }, /* GEORGIAN LETTER EN -> 'e' */ + { 0xD5, 0x76 }, /* GEORGIAN LETTER VIN -> 'v' */ + { 0xD6, 0x7A }, /* GEORGIAN LETTER ZEN -> 'z' */ + { 0xD8, 0x69 }, /* GEORGIAN LETTER IN -> 'i' */ + { 0xD9, 0x6B }, /* GEORGIAN LETTER KAN -> 'k' */ + { 0xDA, 0x6C }, /* GEORGIAN LETTER LAS -> 'l' */ + { 0xDB, 0x6D }, /* GEORGIAN LETTER MAN -> 'm' */ + { 0xDC, 0x6E }, /* GEORGIAN LETTER NAR -> 'n' */ + { 0xDD, 0x6F }, /* GEORGIAN LETTER ON -> 'o' */ + { 0xDE, 0x70 }, /* GEORGIAN LETTER PAR -> 'p' */ + { 0xE0, 0x72 }, /* GEORGIAN LETTER RAE -> 'r' */ + { 0xE1, 0x73 }, /* GEORGIAN LETTER SAN -> 's' */ + { 0xE2, 0x74 }, /* GEORGIAN LETTER TAR -> 't' */ + { 0xE3, 0x75 }, /* GEORGIAN LETTER UN -> 'u' */ + { 0xE7, 0x71 }, /* GEORGIAN LETTER QAR -> 'q' */ + { 0xEC, 0x63 }, /* GEORGIAN LETTER CIL -> 'c' */ + { 0xEE, 0x78 }, /* GEORGIAN LETTER XAN -> 'x' */ + { 0xEF, 0x6A }, /* GEORGIAN LETTER JHAN -> 'j' */ + { 0xF0, 0x68 }, /* GEORGIAN LETTER HAE -> 'h' */ + { 0xF1, 0x65 }, /* GEORGIAN LETTER HE -> 'e' */ + { 0xF2, 0x79 }, /* GEORGIAN LETTER HIE -> 'y' */ + { 0xF3, 0x77 }, /* GEORGIAN LETTER WE -> 'w' */ + { 0xF6, 0x66 }, /* GEORGIAN LETTER FI -> 'f' */ + /* Entries for page 0x11 */ + { 0x00, 0x67 }, /* HANGUL CHOSEONG KIYEOK -> 'g' */ + { 0x02, 0x6E }, /* HANGUL CHOSEONG NIEUN -> 'n' */ + { 0x03, 0x64 }, /* HANGUL CHOSEONG TIKEUT -> 'd' */ + { 0x05, 0x72 }, /* HANGUL CHOSEONG RIEUL -> 'r' */ + { 0x06, 0x6D }, /* HANGUL CHOSEONG MIEUM -> 'm' */ + { 0x07, 0x62 }, /* HANGUL CHOSEONG PIEUP -> 'b' */ + { 0x09, 0x73 }, /* HANGUL CHOSEONG SIOS -> 's' */ + { 0x0C, 0x6A }, /* HANGUL CHOSEONG CIEUC -> 'j' */ + { 0x0E, 0x63 }, /* HANGUL CHOSEONG CHIEUCH -> 'c' */ + { 0x0F, 0x6B }, /* HANGUL CHOSEONG KHIEUKH -> 'k' */ + { 0x10, 0x74 }, /* HANGUL CHOSEONG THIEUTH -> 't' */ + { 0x11, 0x70 }, /* HANGUL CHOSEONG PHIEUPH -> 'p' */ + { 0x12, 0x68 }, /* HANGUL CHOSEONG HIEUH -> 'h' */ + { 0x35, 0x73 }, /* HANGUL CHOSEONG SIOS-IEUNG -> 's' */ + { 0x40, 0x5A }, /* HANGUL CHOSEONG PANSIOS -> 'Z' */ + { 0x41, 0x67 }, /* HANGUL CHOSEONG IEUNG-KIYEOK -> 'g' */ + { 0x42, 0x64 }, /* HANGUL CHOSEONG IEUNG-TIKEUT -> 'd' */ + { 0x43, 0x6D }, /* HANGUL CHOSEONG IEUNG-MIEUM -> 'm' */ + { 0x44, 0x62 }, /* HANGUL CHOSEONG IEUNG-PIEUP -> 'b' */ + { 0x45, 0x73 }, /* HANGUL CHOSEONG IEUNG-SIOS -> 's' */ + { 0x46, 0x5A }, /* HANGUL CHOSEONG IEUNG-PANSIOS -> 'Z' */ + { 0x48, 0x6A }, /* HANGUL CHOSEONG IEUNG-CIEUC -> 'j' */ + { 0x49, 0x63 }, /* HANGUL CHOSEONG IEUNG-CHIEUCH -> 'c' */ + { 0x4A, 0x74 }, /* HANGUL CHOSEONG IEUNG-THIEUTH -> 't' */ + { 0x4B, 0x70 }, /* HANGUL CHOSEONG IEUNG-PHIEUPH -> 'p' */ + { 0x4C, 0x4E }, /* HANGUL CHOSEONG YESIEUNG -> 'N' */ + { 0x4D, 0x6A }, /* HANGUL CHOSEONG CIEUC-IEUNG -> 'j' */ + { 0x59, 0x51 }, /* HANGUL CHOSEONG YEORINHIEUH -> 'Q' */ + { 0x61, 0x61 }, /* HANGUL JUNGSEONG A -> 'a' */ + { 0x66, 0x65 }, /* HANGUL JUNGSEONG E -> 'e' */ + { 0x69, 0x6F }, /* HANGUL JUNGSEONG O -> 'o' */ + { 0x6E, 0x75 }, /* HANGUL JUNGSEONG U -> 'u' */ + { 0x75, 0x69 }, /* HANGUL JUNGSEONG I -> 'i' */ + { 0x9E, 0x55 }, /* HANGUL JUNGSEONG ARAEA -> 'U' */ + { 0xA8, 0x67 }, /* HANGUL JONGSEONG KIYEOK -> 'g' */ + { 0xAB, 0x6E }, /* HANGUL JONGSEONG NIEUN -> 'n' */ + { 0xAE, 0x64 }, /* HANGUL JONGSEONG TIKEUT -> 'd' */ + { 0xAF, 0x6C }, /* HANGUL JONGSEONG RIEUL -> 'l' */ + { 0xB7, 0x6D }, /* HANGUL JONGSEONG MIEUM -> 'm' */ + { 0xB8, 0x62 }, /* HANGUL JONGSEONG PIEUP -> 'b' */ + { 0xBA, 0x73 }, /* HANGUL JONGSEONG SIOS -> 's' */ + { 0xBD, 0x6A }, /* HANGUL JONGSEONG CIEUC -> 'j' */ + { 0xBE, 0x63 }, /* HANGUL JONGSEONG CHIEUCH -> 'c' */ + { 0xBF, 0x6B }, /* HANGUL JONGSEONG KHIEUKH -> 'k' */ + { 0xC0, 0x74 }, /* HANGUL JONGSEONG THIEUTH -> 't' */ + { 0xC1, 0x70 }, /* HANGUL JONGSEONG PHIEUPH -> 'p' */ + { 0xC2, 0x68 }, /* HANGUL JONGSEONG HIEUH -> 'h' */ + { 0xEB, 0x5A }, /* HANGUL JONGSEONG PANSIOS -> 'Z' */ + { 0xEC, 0x67 }, /* HANGUL JONGSEONG IEUNG-KIYEOK -> 'g' */ + { 0xF0, 0x4E }, /* HANGUL JONGSEONG YESIEUNG -> 'N' */ + { 0xF9, 0x51 }, /* HANGUL JONGSEONG YEORINHIEUH -> 'Q' */ + /* Entries for page 0x13 */ + { 0x61, 0x20 }, /* ETHIOPIC WORDSPACE -> ' ' */ + { 0x62, 0x2E }, /* ETHIOPIC FULL STOP -> '.' */ + { 0x63, 0x2C }, /* ETHIOPIC COMMA -> ',' */ + { 0x64, 0x3B }, /* ETHIOPIC SEMICOLON -> ';' */ + { 0x65, 0x3A }, /* ETHIOPIC COLON -> ':' */ + { 0x67, 0x3F }, /* ETHIOPIC QUESTION MARK -> '?' */ + { 0x69, 0x31 }, /* ETHIOPIC DIGIT ONE -> '1' */ + { 0x6A, 0x32 }, /* ETHIOPIC DIGIT TWO -> '2' */ + { 0x6B, 0x33 }, /* ETHIOPIC DIGIT THREE -> '3' */ + { 0x6C, 0x34 }, /* ETHIOPIC DIGIT FOUR -> '4' */ + { 0x6D, 0x35 }, /* ETHIOPIC DIGIT FIVE -> '5' */ + { 0x6E, 0x36 }, /* ETHIOPIC DIGIT SIX -> '6' */ + { 0x6F, 0x37 }, /* ETHIOPIC DIGIT SEVEN -> '7' */ + { 0x70, 0x38 }, /* ETHIOPIC DIGIT EIGHT -> '8' */ + { 0x71, 0x39 }, /* ETHIOPIC DIGIT NINE -> '9' */ + { 0xA0, 0x61 }, /* CHEROKEE LETTER A -> 'a' */ + { 0xA1, 0x65 }, /* CHEROKEE LETTER E -> 'e' */ + { 0xA2, 0x69 }, /* CHEROKEE LETTER I -> 'i' */ + { 0xA3, 0x6F }, /* CHEROKEE LETTER O -> 'o' */ + { 0xA4, 0x75 }, /* CHEROKEE LETTER U -> 'u' */ + { 0xA5, 0x76 }, /* CHEROKEE LETTER V -> 'v' */ + { 0xCD, 0x73 }, /* CHEROKEE LETTER S -> 's' */ + /* Entries for page 0x14 */ + { 0x01, 0x65 }, /* CANADIAN SYLLABICS E -> 'e' */ + { 0x03, 0x69 }, /* CANADIAN SYLLABICS I -> 'i' */ + { 0x05, 0x6F }, /* CANADIAN SYLLABICS O -> 'o' */ + { 0x09, 0x69 }, /* CANADIAN SYLLABICS CARRIER I -> 'i' */ + { 0x0A, 0x61 }, /* CANADIAN SYLLABICS A -> 'a' */ + { 0x1D, 0x77 }, /* CANADIAN SYLLABICS Y-CREE W -> 'w' */ + { 0x1E, 0x27 }, /* CANADIAN SYLLABICS GLOTTAL STOP -> ''' */ + { 0x1F, 0x74 }, /* CANADIAN SYLLABICS FINAL ACUTE -> 't' */ + { 0x20, 0x6B }, /* CANADIAN SYLLABICS FINAL GRAVE -> 'k' */ + { 0x22, 0x73 }, /* CANADIAN SYLLABICS FINAL TOP HALF RING -> 's' */ + { 0x23, 0x6E }, /* CANADIAN SYLLABICS FINAL RIGHT HALF RING -> 'n' */ + { 0x24, 0x77 }, /* CANADIAN SYLLABICS FINAL RING -> 'w' */ + { 0x25, 0x6E }, /* CANADIAN SYLLABICS FINAL DOUBLE ACUTE -> 'n' */ + { 0x27, 0x77 }, /* CANADIAN SYLLABICS FINAL MIDDLE DOT -> 'w' */ + { 0x28, 0x63 }, /* CANADIAN SYLLABICS FINAL SHORT HORIZONTAL STROKE -> 'c' */ + { 0x29, 0x3F }, /* CANADIAN SYLLABICS FINAL PLUS -> '?' */ + { 0x2A, 0x6C }, /* CANADIAN SYLLABICS FINAL DOWN TACK -> 'l' */ + { 0x49, 0x70 }, /* CANADIAN SYLLABICS P -> 'p' */ + { 0x4A, 0x70 }, /* CANADIAN SYLLABICS WEST-CREE P -> 'p' */ + { 0x4B, 0x68 }, /* CANADIAN SYLLABICS CARRIER H -> 'h' */ + { 0x66, 0x74 }, /* CANADIAN SYLLABICS T -> 't' */ + { 0x83, 0x6B }, /* CANADIAN SYLLABICS K -> 'k' */ + { 0xA1, 0x63 }, /* CANADIAN SYLLABICS C -> 'c' */ + { 0xBB, 0x6D }, /* CANADIAN SYLLABICS M -> 'm' */ + { 0xBC, 0x6D }, /* CANADIAN SYLLABICS WEST-CREE M -> 'm' */ + { 0xBE, 0x6D }, /* CANADIAN SYLLABICS ATHAPASCAN M -> 'm' */ + { 0xBF, 0x6D }, /* CANADIAN SYLLABICS SAYISI M -> 'm' */ + { 0xD0, 0x6E }, /* CANADIAN SYLLABICS N -> 'n' */ + { 0xEA, 0x00 }, /* CANADIAN SYLLABICS L -> ... */ + { 0xEC, 0x6C }, /* CANADIAN SYLLABICS MEDIAL L -> 'l' */ + /* Entries for page 0x15 */ + { 0x05, 0x73 }, /* CANADIAN SYLLABICS S -> 's' */ + { 0x06, 0x73 }, /* CANADIAN SYLLABICS ATHAPASCAN S -> 's' */ + { 0x08, 0x73 }, /* CANADIAN SYLLABICS BLACKFOOT S -> 's' */ + { 0x3E, 0x00 }, /* CANADIAN SYLLABICS Y -> ... */ + { 0x40, 0x79 }, /* CANADIAN SYLLABICS WEST-CREE Y -> 'y' */ + { 0x50, 0x00 }, /* CANADIAN SYLLABICS R -> ... */ + { 0x52, 0x72 }, /* CANADIAN SYLLABICS MEDIAL R -> 'r' */ + { 0x5D, 0x66 }, /* CANADIAN SYLLABICS F -> 'f' */ + { 0x7B, 0x68 }, /* CANADIAN SYLLABICS NUNAVIK H -> 'h' */ + { 0x7C, 0x68 }, /* CANADIAN SYLLABICS NUNAVUT H -> 'h' */ + { 0x85, 0x71 }, /* CANADIAN SYLLABICS Q -> 'q' */ + { 0xAF, 0x62 }, /* CANADIAN SYLLABICS AIVILIK B -> 'b' */ + { 0xB0, 0x65 }, /* CANADIAN SYLLABICS BLACKFOOT E -> 'e' */ + { 0xB1, 0x69 }, /* CANADIAN SYLLABICS BLACKFOOT I -> 'i' */ + { 0xB2, 0x6F }, /* CANADIAN SYLLABICS BLACKFOOT O -> 'o' */ + { 0xB3, 0x61 }, /* CANADIAN SYLLABICS BLACKFOOT A -> 'a' */ + { 0xEE, 0x70 }, /* CANADIAN SYLLABICS CARRIER P -> 'p' */ + /* Entries for page 0x16 */ + { 0x46, 0x7A }, /* CANADIAN SYLLABICS CARRIER Z -> 'z' */ + { 0x47, 0x7A }, /* CANADIAN SYLLABICS CARRIER INITIAL Z -> 'z' */ + { 0x6D, 0x58 }, /* CANADIAN SYLLABICS CHI SIGN -> 'X' */ + { 0x6E, 0x2E }, /* CANADIAN SYLLABICS FULL STOP -> '.' */ + { 0x80, 0x20 }, /* OGHAM SPACE MARK -> ' ' */ + { 0x81, 0x62 }, /* OGHAM LETTER BEITH -> 'b' */ + { 0x82, 0x6C }, /* OGHAM LETTER LUIS -> 'l' */ + { 0x83, 0x66 }, /* OGHAM LETTER FEARN -> 'f' */ + { 0x84, 0x73 }, /* OGHAM LETTER SAIL -> 's' */ + { 0x85, 0x6E }, /* OGHAM LETTER NION -> 'n' */ + { 0x86, 0x68 }, /* OGHAM LETTER UATH -> 'h' */ + { 0x87, 0x64 }, /* OGHAM LETTER DAIR -> 'd' */ + { 0x88, 0x74 }, /* OGHAM LETTER TINNE -> 't' */ + { 0x89, 0x63 }, /* OGHAM LETTER COLL -> 'c' */ + { 0x8A, 0x71 }, /* OGHAM LETTER CEIRT -> 'q' */ + { 0x8B, 0x6D }, /* OGHAM LETTER MUIN -> 'm' */ + { 0x8C, 0x67 }, /* OGHAM LETTER GORT -> 'g' */ + { 0x8E, 0x7A }, /* OGHAM LETTER STRAIF -> 'z' */ + { 0x8F, 0x72 }, /* OGHAM LETTER RUIS -> 'r' */ + { 0x90, 0x61 }, /* OGHAM LETTER AILM -> 'a' */ + { 0x91, 0x6F }, /* OGHAM LETTER ONN -> 'o' */ + { 0x92, 0x75 }, /* OGHAM LETTER UR -> 'u' */ + { 0x93, 0x65 }, /* OGHAM LETTER EADHADH -> 'e' */ + { 0x94, 0x69 }, /* OGHAM LETTER IODHADH -> 'i' */ + { 0x98, 0x70 }, /* OGHAM LETTER IFIN -> 'p' */ + { 0x99, 0x78 }, /* OGHAM LETTER EAMHANCHOLL -> 'x' */ + { 0x9A, 0x70 }, /* OGHAM LETTER PEITH -> 'p' */ + { 0x9B, 0x3C }, /* OGHAM FEATHER MARK -> '<' */ + { 0x9C, 0x3E }, /* OGHAM REVERSED FEATHER MARK -> '>' */ + { 0xA0, 0x66 }, /* RUNIC LETTER FEHU FEOH FE F -> 'f' */ + { 0xA1, 0x76 }, /* RUNIC LETTER V -> 'v' */ + { 0xA2, 0x75 }, /* RUNIC LETTER URUZ UR U -> 'u' */ + { 0xA4, 0x79 }, /* RUNIC LETTER Y -> 'y' */ + { 0xA5, 0x77 }, /* RUNIC LETTER W -> 'w' */ + { 0xA8, 0x61 }, /* RUNIC LETTER ANSUZ A -> 'a' */ + { 0xA9, 0x6F }, /* RUNIC LETTER OS O -> 'o' */ + { 0xAC, 0x00 }, /* RUNIC LETTER LONG-BRANCH-OSS O -> ... */ + { 0xAE, 0x6F }, /* RUNIC LETTER O -> 'o' */ + { 0xB1, 0x72 }, /* RUNIC LETTER RAIDO RAD REID R -> 'r' */ + { 0xB2, 0x6B }, /* RUNIC LETTER KAUNA -> 'k' */ + { 0xB3, 0x63 }, /* RUNIC LETTER CEN -> 'c' */ + { 0xB4, 0x6B }, /* RUNIC LETTER KAUN K -> 'k' */ + { 0xB5, 0x67 }, /* RUNIC LETTER G -> 'g' */ + { 0xB7, 0x67 }, /* RUNIC LETTER GEBO GYFU G -> 'g' */ + { 0xB8, 0x67 }, /* RUNIC LETTER GAR -> 'g' */ + { 0xB9, 0x77 }, /* RUNIC LETTER WUNJO WYNN W -> 'w' */ + { 0xBA, 0x00 }, /* RUNIC LETTER HAGLAZ H -> ... */ + { 0xBD, 0x68 }, /* RUNIC LETTER SHORT-TWIG-HAGALL H -> 'h' */ + { 0xBE, 0x00 }, /* RUNIC LETTER NAUDIZ NYD NAUD N -> ... */ + { 0xC0, 0x6E }, /* RUNIC LETTER DOTTED-N -> 'n' */ + { 0xC1, 0x69 }, /* RUNIC LETTER ISAZ IS ISS I -> 'i' */ + { 0xC2, 0x65 }, /* RUNIC LETTER E -> 'e' */ + { 0xC3, 0x6A }, /* RUNIC LETTER JERAN J -> 'j' */ + { 0xC4, 0x67 }, /* RUNIC LETTER GER -> 'g' */ + { 0xC6, 0x61 }, /* RUNIC LETTER SHORT-TWIG-AR A -> 'a' */ + { 0xC8, 0x70 }, /* RUNIC LETTER PERTHO PEORTH P -> 'p' */ + { 0xC9, 0x7A }, /* RUNIC LETTER ALGIZ EOLHX -> 'z' */ + { 0xCA, 0x00 }, /* RUNIC LETTER SOWILO S -> ... */ + { 0xCC, 0x73 }, /* RUNIC LETTER SHORT-TWIG-SOL S -> 's' */ + { 0xCD, 0x63 }, /* RUNIC LETTER C -> 'c' */ + { 0xCE, 0x7A }, /* RUNIC LETTER Z -> 'z' */ + { 0xCF, 0x74 }, /* RUNIC LETTER TIWAZ TIR TYR T -> 't' */ + { 0xD0, 0x74 }, /* RUNIC LETTER SHORT-TWIG-TYR T -> 't' */ + { 0xD1, 0x64 }, /* RUNIC LETTER D -> 'd' */ + { 0xD2, 0x62 }, /* RUNIC LETTER BERKANAN BEORC BJARKAN B -> 'b' */ + { 0xD3, 0x62 }, /* RUNIC LETTER SHORT-TWIG-BJARKAN B -> 'b' */ + { 0xD4, 0x70 }, /* RUNIC LETTER DOTTED-P -> 'p' */ + { 0xD5, 0x70 }, /* RUNIC LETTER OPEN-P -> 'p' */ + { 0xD6, 0x65 }, /* RUNIC LETTER EHWAZ EH E -> 'e' */ + { 0xD7, 0x00 }, /* RUNIC LETTER MANNAZ MAN M -> ... */ + { 0xD9, 0x6D }, /* RUNIC LETTER SHORT-TWIG-MADR M -> 'm' */ + { 0xDA, 0x6C }, /* RUNIC LETTER LAUKAZ LAGU LOGR L -> 'l' */ + { 0xDB, 0x6C }, /* RUNIC LETTER DOTTED-L -> 'l' */ + { 0xDE, 0x64 }, /* RUNIC LETTER DAGAZ DAEG D -> 'd' */ + { 0xDF, 0x6F }, /* RUNIC LETTER OTHALAN ETHEL O -> 'o' */ + { 0xE5, 0x73 }, /* RUNIC LETTER STAN -> 's' */ + { 0xE9, 0x71 }, /* RUNIC LETTER Q -> 'q' */ + { 0xEA, 0x78 }, /* RUNIC LETTER X -> 'x' */ + { 0xEB, 0x2E }, /* RUNIC SINGLE PUNCTUATION -> '.' */ + { 0xEC, 0x3A }, /* RUNIC MULTIPLE PUNCTUATION -> ':' */ + { 0xED, 0x2B }, /* RUNIC CROSS PUNCTUATION -> '+' */ + /* Entries for page 0x17 */ + { 0x80, 0x6B }, /* KHMER LETTER KA -> 'k' */ + { 0x82, 0x67 }, /* KHMER LETTER KO -> 'g' */ + { 0x85, 0x63 }, /* KHMER LETTER CA -> 'c' */ + { 0x87, 0x6A }, /* KHMER LETTER CO -> 'j' */ + { 0x8A, 0x74 }, /* KHMER LETTER DA -> 't' */ + { 0x8C, 0x64 }, /* KHMER LETTER DO -> 'd' */ + { 0x8F, 0x74 }, /* KHMER LETTER TA -> 't' */ + { 0x91, 0x64 }, /* KHMER LETTER TO -> 'd' */ + { 0x93, 0x6E }, /* KHMER LETTER NO -> 'n' */ + { 0x94, 0x70 }, /* KHMER LETTER BA -> 'p' */ + { 0x96, 0x62 }, /* KHMER LETTER PO -> 'b' */ + { 0x98, 0x6D }, /* KHMER LETTER MO -> 'm' */ + { 0x99, 0x79 }, /* KHMER LETTER YO -> 'y' */ + { 0x9A, 0x72 }, /* KHMER LETTER RO -> 'r' */ + { 0x9B, 0x6C }, /* KHMER LETTER LO -> 'l' */ + { 0x9C, 0x76 }, /* KHMER LETTER VO -> 'v' */ + { 0x9F, 0x73 }, /* KHMER LETTER SA -> 's' */ + { 0xA0, 0x68 }, /* KHMER LETTER HA -> 'h' */ + { 0xA1, 0x6C }, /* KHMER LETTER LA -> 'l' */ + { 0xA2, 0x71 }, /* KHMER LETTER QA -> 'q' */ + { 0xA3, 0x61 }, /* KHMER INDEPENDENT VOWEL QAQ -> 'a' */ + { 0xA5, 0x69 }, /* KHMER INDEPENDENT VOWEL QI -> 'i' */ + { 0xA7, 0x75 }, /* KHMER INDEPENDENT VOWEL QU -> 'u' */ + { 0xAF, 0x65 }, /* KHMER INDEPENDENT VOWEL QE -> 'e' */ + { 0xB4, 0x61 }, /* KHMER VOWEL INHERENT AQ -> 'a' */ + { 0xB7, 0x69 }, /* KHMER VOWEL SIGN I -> 'i' */ + { 0xB9, 0x79 }, /* KHMER VOWEL SIGN Y -> 'y' */ + { 0xBB, 0x75 }, /* KHMER VOWEL SIGN U -> 'u' */ + { 0xC1, 0x65 }, /* KHMER VOWEL SIGN E -> 'e' */ + { 0xC6, 0x4D }, /* KHMER SIGN NIKAHIT -> 'M' */ + { 0xC7, 0x48 }, /* KHMER SIGN REAHMUK -> 'H' */ + { 0xCC, 0x72 }, /* KHMER SIGN ROBAT -> 'r' */ + { 0xCE, 0x21 }, /* KHMER SIGN KAKABAT -> '!' */ + { 0xD4, 0x2E }, /* KHMER SIGN KHAN -> '.' */ + { 0xD6, 0x3A }, /* KHMER SIGN CAMNUC PII KUUH -> ':' */ + { 0xD7, 0x2B }, /* KHMER SIGN LEK TOO -> '+' */ + { 0xDC, 0x27 }, /* KHMER SIGN AVAKRAHASANYA -> ''' */ + { 0xE0, 0x30 }, /* KHMER DIGIT ZERO -> '0' */ + { 0xE1, 0x31 }, /* KHMER DIGIT ONE -> '1' */ + { 0xE2, 0x32 }, /* KHMER DIGIT TWO -> '2' */ + { 0xE3, 0x33 }, /* KHMER DIGIT THREE -> '3' */ + { 0xE4, 0x34 }, /* KHMER DIGIT FOUR -> '4' */ + { 0xE5, 0x35 }, /* KHMER DIGIT FIVE -> '5' */ + { 0xE6, 0x36 }, /* KHMER DIGIT SIX -> '6' */ + { 0xE7, 0x37 }, /* KHMER DIGIT SEVEN -> '7' */ + { 0xE8, 0x38 }, /* KHMER DIGIT EIGHT -> '8' */ + { 0xE9, 0x39 }, /* KHMER DIGIT NINE -> '9' */ + /* Entries for page 0x18 */ + { 0x07, 0x2D }, /* MONGOLIAN SIBE SYLLABLE BOUNDARY MARKER -> '-' */ + { 0x10, 0x30 }, /* MONGOLIAN DIGIT ZERO -> '0' */ + { 0x11, 0x31 }, /* MONGOLIAN DIGIT ONE -> '1' */ + { 0x12, 0x32 }, /* MONGOLIAN DIGIT TWO -> '2' */ + { 0x13, 0x33 }, /* MONGOLIAN DIGIT THREE -> '3' */ + { 0x14, 0x34 }, /* MONGOLIAN DIGIT FOUR -> '4' */ + { 0x15, 0x35 }, /* MONGOLIAN DIGIT FIVE -> '5' */ + { 0x16, 0x36 }, /* MONGOLIAN DIGIT SIX -> '6' */ + { 0x17, 0x37 }, /* MONGOLIAN DIGIT SEVEN -> '7' */ + { 0x18, 0x38 }, /* MONGOLIAN DIGIT EIGHT -> '8' */ + { 0x19, 0x39 }, /* MONGOLIAN DIGIT NINE -> '9' */ + { 0x20, 0x61 }, /* MONGOLIAN LETTER A -> 'a' */ + { 0x21, 0x65 }, /* MONGOLIAN LETTER E -> 'e' */ + { 0x22, 0x69 }, /* MONGOLIAN LETTER I -> 'i' */ + { 0x23, 0x6F }, /* MONGOLIAN LETTER O -> 'o' */ + { 0x24, 0x75 }, /* MONGOLIAN LETTER U -> 'u' */ + { 0x25, 0x4F }, /* MONGOLIAN LETTER OE -> 'O' */ + { 0x26, 0x55 }, /* MONGOLIAN LETTER UE -> 'U' */ + { 0x28, 0x6E }, /* MONGOLIAN LETTER NA -> 'n' */ + { 0x2A, 0x62 }, /* MONGOLIAN LETTER BA -> 'b' */ + { 0x2B, 0x70 }, /* MONGOLIAN LETTER PA -> 'p' */ + { 0x2C, 0x71 }, /* MONGOLIAN LETTER QA -> 'q' */ + { 0x2D, 0x67 }, /* MONGOLIAN LETTER GA -> 'g' */ + { 0x2E, 0x6D }, /* MONGOLIAN LETTER MA -> 'm' */ + { 0x2F, 0x6C }, /* MONGOLIAN LETTER LA -> 'l' */ + { 0x30, 0x73 }, /* MONGOLIAN LETTER SA -> 's' */ + { 0x32, 0x74 }, /* MONGOLIAN LETTER TA -> 't' */ + { 0x33, 0x64 }, /* MONGOLIAN LETTER DA -> 'd' */ + { 0x35, 0x6A }, /* MONGOLIAN LETTER JA -> 'j' */ + { 0x36, 0x79 }, /* MONGOLIAN LETTER YA -> 'y' */ + { 0x37, 0x72 }, /* MONGOLIAN LETTER RA -> 'r' */ + { 0x38, 0x77 }, /* MONGOLIAN LETTER WA -> 'w' */ + { 0x39, 0x66 }, /* MONGOLIAN LETTER FA -> 'f' */ + { 0x3A, 0x6B }, /* MONGOLIAN LETTER KA -> 'k' */ + { 0x3D, 0x7A }, /* MONGOLIAN LETTER ZA -> 'z' */ + { 0x3E, 0x68 }, /* MONGOLIAN LETTER HAA -> 'h' */ + { 0x43, 0x2D }, /* MONGOLIAN LETTER TODO LONG VOWEL SIGN -> '-' */ + { 0x44, 0x65 }, /* MONGOLIAN LETTER TODO E -> 'e' */ + { 0x45, 0x69 }, /* MONGOLIAN LETTER TODO I -> 'i' */ + { 0x46, 0x6F }, /* MONGOLIAN LETTER TODO O -> 'o' */ + { 0x47, 0x75 }, /* MONGOLIAN LETTER TODO U -> 'u' */ + { 0x48, 0x4F }, /* MONGOLIAN LETTER TODO OE -> 'O' */ + { 0x49, 0x55 }, /* MONGOLIAN LETTER TODO UE -> 'U' */ + { 0x4B, 0x62 }, /* MONGOLIAN LETTER TODO BA -> 'b' */ + { 0x4C, 0x70 }, /* MONGOLIAN LETTER TODO PA -> 'p' */ + { 0x4D, 0x71 }, /* MONGOLIAN LETTER TODO QA -> 'q' */ + { 0x4E, 0x67 }, /* MONGOLIAN LETTER TODO GA -> 'g' */ + { 0x4F, 0x6D }, /* MONGOLIAN LETTER TODO MA -> 'm' */ + { 0x50, 0x74 }, /* MONGOLIAN LETTER TODO TA -> 't' */ + { 0x51, 0x64 }, /* MONGOLIAN LETTER TODO DA -> 'd' */ + { 0x53, 0x6A }, /* MONGOLIAN LETTER TODO JA -> 'j' */ + { 0x55, 0x79 }, /* MONGOLIAN LETTER TODO YA -> 'y' */ + { 0x56, 0x77 }, /* MONGOLIAN LETTER TODO WA -> 'w' */ + { 0x57, 0x6B }, /* MONGOLIAN LETTER TODO KA -> 'k' */ + { 0x58, 0x67 }, /* MONGOLIAN LETTER TODO GAA -> 'g' */ + { 0x59, 0x68 }, /* MONGOLIAN LETTER TODO HAA -> 'h' */ + { 0x5D, 0x65 }, /* MONGOLIAN LETTER SIBE E -> 'e' */ + { 0x5E, 0x69 }, /* MONGOLIAN LETTER SIBE I -> 'i' */ + { 0x60, 0x55 }, /* MONGOLIAN LETTER SIBE UE -> 'U' */ + { 0x61, 0x75 }, /* MONGOLIAN LETTER SIBE U -> 'u' */ + { 0x63, 0x6B }, /* MONGOLIAN LETTER SIBE KA -> 'k' */ + { 0x64, 0x67 }, /* MONGOLIAN LETTER SIBE GA -> 'g' */ + { 0x65, 0x68 }, /* MONGOLIAN LETTER SIBE HA -> 'h' */ + { 0x66, 0x70 }, /* MONGOLIAN LETTER SIBE PA -> 'p' */ + { 0x68, 0x74 }, /* MONGOLIAN LETTER SIBE TA -> 't' */ + { 0x69, 0x64 }, /* MONGOLIAN LETTER SIBE DA -> 'd' */ + { 0x6A, 0x6A }, /* MONGOLIAN LETTER SIBE JA -> 'j' */ + { 0x6B, 0x66 }, /* MONGOLIAN LETTER SIBE FA -> 'f' */ + { 0x6C, 0x67 }, /* MONGOLIAN LETTER SIBE GAA -> 'g' */ + { 0x6D, 0x68 }, /* MONGOLIAN LETTER SIBE HAA -> 'h' */ + { 0x6F, 0x7A }, /* MONGOLIAN LETTER SIBE ZA -> 'z' */ + { 0x70, 0x72 }, /* MONGOLIAN LETTER SIBE RAA -> 'r' */ + { 0x73, 0x69 }, /* MONGOLIAN LETTER MANCHU I -> 'i' */ + { 0x74, 0x6B }, /* MONGOLIAN LETTER MANCHU KA -> 'k' */ + { 0x75, 0x72 }, /* MONGOLIAN LETTER MANCHU RA -> 'r' */ + { 0x76, 0x66 }, /* MONGOLIAN LETTER MANCHU FA -> 'f' */ + { 0x81, 0x48 }, /* MONGOLIAN LETTER ALI GALI VISARGA ONE -> 'H' */ + { 0x82, 0x58 }, /* MONGOLIAN LETTER ALI GALI DAMARU -> 'X' */ + { 0x83, 0x57 }, /* MONGOLIAN LETTER ALI GALI UBADAMA -> 'W' */ + { 0x84, 0x4D }, /* MONGOLIAN LETTER ALI GALI INVERTED UBADAMA -> 'M' */ + { 0x87, 0x61 }, /* MONGOLIAN LETTER ALI GALI A -> 'a' */ + { 0x88, 0x69 }, /* MONGOLIAN LETTER ALI GALI I -> 'i' */ + { 0x89, 0x6B }, /* MONGOLIAN LETTER ALI GALI KA -> 'k' */ + { 0x8B, 0x63 }, /* MONGOLIAN LETTER ALI GALI CA -> 'c' */ + { 0x90, 0x74 }, /* MONGOLIAN LETTER ALI GALI TA -> 't' */ + { 0x91, 0x64 }, /* MONGOLIAN LETTER ALI GALI DA -> 'd' */ + { 0x92, 0x70 }, /* MONGOLIAN LETTER ALI GALI PA -> 'p' */ + { 0x96, 0x7A }, /* MONGOLIAN LETTER ALI GALI ZA -> 'z' */ + { 0x97, 0x61 }, /* MONGOLIAN LETTER ALI GALI AH -> 'a' */ + { 0x98, 0x74 }, /* MONGOLIAN LETTER TODO ALI GALI TA -> 't' */ + { 0x9C, 0x63 }, /* MONGOLIAN LETTER MANCHU ALI GALI CA -> 'c' */ + { 0xA0, 0x74 }, /* MONGOLIAN LETTER MANCHU ALI GALI TA -> 't' */ + { 0xA5, 0x7A }, /* MONGOLIAN LETTER MANCHU ALI GALI ZA -> 'z' */ + { 0xA6, 0x75 }, /* MONGOLIAN LETTER ALI GALI HALF U -> 'u' */ + { 0xA7, 0x79 }, /* MONGOLIAN LETTER ALI GALI HALF YA -> 'y' */ + { 0xA9, 0x27 }, /* MONGOLIAN LETTER ALI GALI DAGALGA -> ''' */ + /* Entries for page 0x1D */ + { 0x00, 0x41 }, /* LATIN LETTER SMALL CAPITAL A -> 'A' */ + { 0x03, 0x42 }, /* LATIN LETTER SMALL CAPITAL BARRED B -> 'B' */ + { 0x04, 0x43 }, /* LATIN LETTER SMALL CAPITAL C -> 'C' */ + { 0x05, 0x44 }, /* LATIN LETTER SMALL CAPITAL D -> 'D' */ + { 0x06, 0x44 }, /* LATIN LETTER SMALL CAPITAL ETH -> 'D' */ + { 0x07, 0x45 }, /* LATIN LETTER SMALL CAPITAL E -> 'E' */ + { 0x08, 0x65 }, /* LATIN SMALL LETTER TURNED OPEN E -> 'e' */ + { 0x09, 0x69 }, /* LATIN SMALL LETTER TURNED I -> 'i' */ + { 0x0A, 0x4A }, /* LATIN LETTER SMALL CAPITAL J -> 'J' */ + { 0x0B, 0x4B }, /* LATIN LETTER SMALL CAPITAL K -> 'K' */ + { 0x0C, 0x4C }, /* LATIN LETTER SMALL CAPITAL L WITH STROKE -> 'L' */ + { 0x0D, 0x4D }, /* LATIN LETTER SMALL CAPITAL M -> 'M' */ + { 0x0E, 0x4E }, /* LATIN LETTER SMALL CAPITAL REVERSED N -> 'N' */ + { 0x0F, 0x4F }, /* LATIN LETTER SMALL CAPITAL O -> 'O' */ + { 0x11, 0x4F }, /* LATIN SMALL LETTER SIDEWAYS O -> 'O' */ + { 0x13, 0x4F }, /* LATIN SMALL LETTER SIDEWAYS O WITH STROKE -> 'O' */ + { 0x18, 0x50 }, /* LATIN LETTER SMALL CAPITAL P -> 'P' */ + { 0x19, 0x52 }, /* LATIN LETTER SMALL CAPITAL REVERSED R -> 'R' */ + { 0x1A, 0x52 }, /* LATIN LETTER SMALL CAPITAL TURNED R -> 'R' */ + { 0x1B, 0x54 }, /* LATIN LETTER SMALL CAPITAL T -> 'T' */ + { 0x1C, 0x55 }, /* LATIN LETTER SMALL CAPITAL U -> 'U' */ + { 0x1D, 0x75 }, /* LATIN SMALL LETTER SIDEWAYS U -> 'u' */ + { 0x1E, 0x75 }, /* LATIN SMALL LETTER SIDEWAYS DIAERESIZED U -> 'u' */ + { 0x1F, 0x6D }, /* LATIN SMALL LETTER SIDEWAYS TURNED M -> 'm' */ + { 0x20, 0x56 }, /* LATIN LETTER SMALL CAPITAL V -> 'V' */ + { 0x21, 0x57 }, /* LATIN LETTER SMALL CAPITAL W -> 'W' */ + { 0x22, 0x5A }, /* LATIN LETTER SMALL CAPITAL Z -> 'Z' */ + { 0x2C, 0x41 }, /* MODIFIER LETTER CAPITAL A -> 'A' */ + { 0x2E, 0x42 }, /* MODIFIER LETTER CAPITAL B -> 'B' */ + { 0x2F, 0x42 }, /* MODIFIER LETTER CAPITAL BARRED B -> 'B' */ + { 0x30, 0x44 }, /* MODIFIER LETTER CAPITAL D -> 'D' */ + { 0x31, 0x45 }, /* MODIFIER LETTER CAPITAL E -> 'E' */ + { 0x32, 0x45 }, /* MODIFIER LETTER CAPITAL REVERSED E -> 'E' */ + { 0x33, 0x47 }, /* MODIFIER LETTER CAPITAL G -> 'G' */ + { 0x34, 0x48 }, /* MODIFIER LETTER CAPITAL H -> 'H' */ + { 0x35, 0x49 }, /* MODIFIER LETTER CAPITAL I -> 'I' */ + { 0x36, 0x4A }, /* MODIFIER LETTER CAPITAL J -> 'J' */ + { 0x37, 0x4B }, /* MODIFIER LETTER CAPITAL K -> 'K' */ + { 0x38, 0x4C }, /* MODIFIER LETTER CAPITAL L -> 'L' */ + { 0x39, 0x4D }, /* MODIFIER LETTER CAPITAL M -> 'M' */ + { 0x3A, 0x4E }, /* MODIFIER LETTER CAPITAL N -> 'N' */ + { 0x3B, 0x4E }, /* MODIFIER LETTER CAPITAL REVERSED N -> 'N' */ + { 0x3C, 0x4F }, /* MODIFIER LETTER CAPITAL O -> 'O' */ + { 0x3E, 0x50 }, /* MODIFIER LETTER CAPITAL P -> 'P' */ + { 0x3F, 0x52 }, /* MODIFIER LETTER CAPITAL R -> 'R' */ + { 0x40, 0x54 }, /* MODIFIER LETTER CAPITAL T -> 'T' */ + { 0x41, 0x55 }, /* MODIFIER LETTER CAPITAL U -> 'U' */ + { 0x42, 0x57 }, /* MODIFIER LETTER CAPITAL W -> 'W' */ + { 0x43, 0x00 }, /* MODIFIER LETTER SMALL A -> ... */ + { 0x45, 0x61 }, /* MODIFIER LETTER SMALL ALPHA -> 'a' */ + { 0x47, 0x62 }, /* MODIFIER LETTER SMALL B -> 'b' */ + { 0x48, 0x64 }, /* MODIFIER LETTER SMALL D -> 'd' */ + { 0x49, 0x65 }, /* MODIFIER LETTER SMALL E -> 'e' */ + { 0x4B, 0x65 }, /* MODIFIER LETTER SMALL OPEN E -> 'e' */ + { 0x4C, 0x65 }, /* MODIFIER LETTER SMALL TURNED OPEN E -> 'e' */ + { 0x4D, 0x67 }, /* MODIFIER LETTER SMALL G -> 'g' */ + { 0x4E, 0x69 }, /* MODIFIER LETTER SMALL TURNED I -> 'i' */ + { 0x4F, 0x6B }, /* MODIFIER LETTER SMALL K -> 'k' */ + { 0x50, 0x6D }, /* MODIFIER LETTER SMALL M -> 'm' */ + { 0x52, 0x6F }, /* MODIFIER LETTER SMALL O -> 'o' */ + { 0x56, 0x70 }, /* MODIFIER LETTER SMALL P -> 'p' */ + { 0x57, 0x74 }, /* MODIFIER LETTER SMALL T -> 't' */ + { 0x58, 0x75 }, /* MODIFIER LETTER SMALL U -> 'u' */ + { 0x59, 0x75 }, /* MODIFIER LETTER SMALL SIDEWAYS U -> 'u' */ + { 0x5A, 0x6D }, /* MODIFIER LETTER SMALL TURNED M -> 'm' */ + { 0x5B, 0x76 }, /* MODIFIER LETTER SMALL V -> 'v' */ + { 0x5D, 0x62 }, /* MODIFIER LETTER SMALL BETA -> 'b' */ + { 0x5E, 0x67 }, /* MODIFIER LETTER SMALL GREEK GAMMA -> 'g' */ + { 0x5F, 0x64 }, /* MODIFIER LETTER SMALL DELTA -> 'd' */ + { 0x60, 0x66 }, /* MODIFIER LETTER SMALL GREEK PHI -> 'f' */ + { 0x62, 0x69 }, /* LATIN SUBSCRIPT SMALL LETTER I -> 'i' */ + { 0x63, 0x72 }, /* LATIN SUBSCRIPT SMALL LETTER R -> 'r' */ + { 0x64, 0x75 }, /* LATIN SUBSCRIPT SMALL LETTER U -> 'u' */ + { 0x65, 0x76 }, /* LATIN SUBSCRIPT SMALL LETTER V -> 'v' */ + { 0x66, 0x62 }, /* GREEK SUBSCRIPT SMALL LETTER BETA -> 'b' */ + { 0x67, 0x67 }, /* GREEK SUBSCRIPT SMALL LETTER GAMMA -> 'g' */ + { 0x68, 0x72 }, /* GREEK SUBSCRIPT SMALL LETTER RHO -> 'r' */ + { 0x69, 0x66 }, /* GREEK SUBSCRIPT SMALL LETTER PHI -> 'f' */ + { 0x6C, 0x62 }, /* LATIN SMALL LETTER B WITH MIDDLE TILDE -> 'b' */ + { 0x6D, 0x64 }, /* LATIN SMALL LETTER D WITH MIDDLE TILDE -> 'd' */ + { 0x6E, 0x66 }, /* LATIN SMALL LETTER F WITH MIDDLE TILDE -> 'f' */ + { 0x6F, 0x6D }, /* LATIN SMALL LETTER M WITH MIDDLE TILDE -> 'm' */ + { 0x70, 0x6E }, /* LATIN SMALL LETTER N WITH MIDDLE TILDE -> 'n' */ + { 0x71, 0x70 }, /* LATIN SMALL LETTER P WITH MIDDLE TILDE -> 'p' */ + { 0x72, 0x72 }, /* LATIN SMALL LETTER R WITH MIDDLE TILDE -> 'r' */ + { 0x73, 0x72 }, /* LATIN SMALL LETTER R WITH FISHHOOK AND MIDDLE TILDE -> 'r' */ + { 0x74, 0x73 }, /* LATIN SMALL LETTER S WITH MIDDLE TILDE -> 's' */ + { 0x75, 0x74 }, /* LATIN SMALL LETTER T WITH MIDDLE TILDE -> 't' */ + { 0x76, 0x7A }, /* LATIN SMALL LETTER Z WITH MIDDLE TILDE -> 'z' */ + { 0x77, 0x67 }, /* LATIN SMALL LETTER TURNED G -> 'g' */ + { 0x7D, 0x70 }, /* LATIN SMALL LETTER P WITH STROKE -> 'p' */ + { 0x80, 0x62 }, /* LATIN SMALL LETTER B WITH PALATAL HOOK -> 'b' */ + { 0x81, 0x64 }, /* LATIN SMALL LETTER D WITH PALATAL HOOK -> 'd' */ + { 0x82, 0x66 }, /* LATIN SMALL LETTER F WITH PALATAL HOOK -> 'f' */ + { 0x83, 0x67 }, /* LATIN SMALL LETTER G WITH PALATAL HOOK -> 'g' */ + { 0x84, 0x6B }, /* LATIN SMALL LETTER K WITH PALATAL HOOK -> 'k' */ + { 0x85, 0x6C }, /* LATIN SMALL LETTER L WITH PALATAL HOOK -> 'l' */ + { 0x86, 0x6D }, /* LATIN SMALL LETTER M WITH PALATAL HOOK -> 'm' */ + { 0x87, 0x6E }, /* LATIN SMALL LETTER N WITH PALATAL HOOK -> 'n' */ + { 0x88, 0x70 }, /* LATIN SMALL LETTER P WITH PALATAL HOOK -> 'p' */ + { 0x89, 0x72 }, /* LATIN SMALL LETTER R WITH PALATAL HOOK -> 'r' */ + { 0x8A, 0x73 }, /* LATIN SMALL LETTER S WITH PALATAL HOOK -> 's' */ + { 0x8C, 0x76 }, /* LATIN SMALL LETTER V WITH PALATAL HOOK -> 'v' */ + { 0x8D, 0x78 }, /* LATIN SMALL LETTER X WITH PALATAL HOOK -> 'x' */ + { 0x8E, 0x7A }, /* LATIN SMALL LETTER Z WITH PALATAL HOOK -> 'z' */ + /* Entries for page 0x1E */ + { 0x00, 0x41 }, /* LATIN CAPITAL LETTER A WITH RING BELOW -> 'A' */ + { 0x01, 0x61 }, /* LATIN SMALL LETTER A WITH RING BELOW -> 'a' */ + { 0x02, 0x42 }, /* LATIN CAPITAL LETTER B WITH DOT ABOVE -> 'B' */ + { 0x03, 0x62 }, /* LATIN SMALL LETTER B WITH DOT ABOVE -> 'b' */ + { 0x04, 0x42 }, /* LATIN CAPITAL LETTER B WITH DOT BELOW -> 'B' */ + { 0x05, 0x62 }, /* LATIN SMALL LETTER B WITH DOT BELOW -> 'b' */ + { 0x06, 0x42 }, /* LATIN CAPITAL LETTER B WITH LINE BELOW -> 'B' */ + { 0x07, 0x62 }, /* LATIN SMALL LETTER B WITH LINE BELOW -> 'b' */ + { 0x08, 0x43 }, /* LATIN CAPITAL LETTER C WITH CEDILLA AND ACUTE -> 'C' */ + { 0x09, 0x63 }, /* LATIN SMALL LETTER C WITH CEDILLA AND ACUTE -> 'c' */ + { 0x0A, 0x44 }, /* LATIN CAPITAL LETTER D WITH DOT ABOVE -> 'D' */ + { 0x0B, 0x64 }, /* LATIN SMALL LETTER D WITH DOT ABOVE -> 'd' */ + { 0x0C, 0x44 }, /* LATIN CAPITAL LETTER D WITH DOT BELOW -> 'D' */ + { 0x0D, 0x64 }, /* LATIN SMALL LETTER D WITH DOT BELOW -> 'd' */ + { 0x0E, 0x44 }, /* LATIN CAPITAL LETTER D WITH LINE BELOW -> 'D' */ + { 0x0F, 0x64 }, /* LATIN SMALL LETTER D WITH LINE BELOW -> 'd' */ + { 0x10, 0x44 }, /* LATIN CAPITAL LETTER D WITH CEDILLA -> 'D' */ + { 0x11, 0x64 }, /* LATIN SMALL LETTER D WITH CEDILLA -> 'd' */ + { 0x12, 0x44 }, /* LATIN CAPITAL LETTER D WITH CIRCUMFLEX BELOW -> 'D' */ + { 0x13, 0x64 }, /* LATIN SMALL LETTER D WITH CIRCUMFLEX BELOW -> 'd' */ + { 0x14, 0x45 }, /* LATIN CAPITAL LETTER E WITH MACRON AND GRAVE -> 'E' */ + { 0x15, 0x65 }, /* LATIN SMALL LETTER E WITH MACRON AND GRAVE -> 'e' */ + { 0x16, 0x45 }, /* LATIN CAPITAL LETTER E WITH MACRON AND ACUTE -> 'E' */ + { 0x17, 0x65 }, /* LATIN SMALL LETTER E WITH MACRON AND ACUTE -> 'e' */ + { 0x18, 0x45 }, /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX BELOW -> 'E' */ + { 0x19, 0x65 }, /* LATIN SMALL LETTER E WITH CIRCUMFLEX BELOW -> 'e' */ + { 0x1A, 0x45 }, /* LATIN CAPITAL LETTER E WITH TILDE BELOW -> 'E' */ + { 0x1B, 0x65 }, /* LATIN SMALL LETTER E WITH TILDE BELOW -> 'e' */ + { 0x1C, 0x45 }, /* LATIN CAPITAL LETTER E WITH CEDILLA AND BREVE -> 'E' */ + { 0x1D, 0x65 }, /* LATIN SMALL LETTER E WITH CEDILLA AND BREVE -> 'e' */ + { 0x1E, 0x46 }, /* LATIN CAPITAL LETTER F WITH DOT ABOVE -> 'F' */ + { 0x1F, 0x66 }, /* LATIN SMALL LETTER F WITH DOT ABOVE -> 'f' */ + { 0x20, 0x47 }, /* LATIN CAPITAL LETTER G WITH MACRON -> 'G' */ + { 0x21, 0x67 }, /* LATIN SMALL LETTER G WITH MACRON -> 'g' */ + { 0x22, 0x48 }, /* LATIN CAPITAL LETTER H WITH DOT ABOVE -> 'H' */ + { 0x23, 0x68 }, /* LATIN SMALL LETTER H WITH DOT ABOVE -> 'h' */ + { 0x24, 0x48 }, /* LATIN CAPITAL LETTER H WITH DOT BELOW -> 'H' */ + { 0x25, 0x68 }, /* LATIN SMALL LETTER H WITH DOT BELOW -> 'h' */ + { 0x26, 0x48 }, /* LATIN CAPITAL LETTER H WITH DIAERESIS -> 'H' */ + { 0x27, 0x68 }, /* LATIN SMALL LETTER H WITH DIAERESIS -> 'h' */ + { 0x28, 0x48 }, /* LATIN CAPITAL LETTER H WITH CEDILLA -> 'H' */ + { 0x29, 0x68 }, /* LATIN SMALL LETTER H WITH CEDILLA -> 'h' */ + { 0x2A, 0x48 }, /* LATIN CAPITAL LETTER H WITH BREVE BELOW -> 'H' */ + { 0x2B, 0x68 }, /* LATIN SMALL LETTER H WITH BREVE BELOW -> 'h' */ + { 0x2C, 0x49 }, /* LATIN CAPITAL LETTER I WITH TILDE BELOW -> 'I' */ + { 0x2D, 0x69 }, /* LATIN SMALL LETTER I WITH TILDE BELOW -> 'i' */ + { 0x2E, 0x49 }, /* LATIN CAPITAL LETTER I WITH DIAERESIS AND ACUTE -> 'I' */ + { 0x2F, 0x69 }, /* LATIN SMALL LETTER I WITH DIAERESIS AND ACUTE -> 'i' */ + { 0x30, 0x4B }, /* LATIN CAPITAL LETTER K WITH ACUTE -> 'K' */ + { 0x31, 0x6B }, /* LATIN SMALL LETTER K WITH ACUTE -> 'k' */ + { 0x32, 0x4B }, /* LATIN CAPITAL LETTER K WITH DOT BELOW -> 'K' */ + { 0x33, 0x6B }, /* LATIN SMALL LETTER K WITH DOT BELOW -> 'k' */ + { 0x34, 0x4B }, /* LATIN CAPITAL LETTER K WITH LINE BELOW -> 'K' */ + { 0x35, 0x6B }, /* LATIN SMALL LETTER K WITH LINE BELOW -> 'k' */ + { 0x36, 0x4C }, /* LATIN CAPITAL LETTER L WITH DOT BELOW -> 'L' */ + { 0x37, 0x6C }, /* LATIN SMALL LETTER L WITH DOT BELOW -> 'l' */ + { 0x38, 0x4C }, /* LATIN CAPITAL LETTER L WITH DOT BELOW AND MACRON -> 'L' */ + { 0x39, 0x6C }, /* LATIN SMALL LETTER L WITH DOT BELOW AND MACRON -> 'l' */ + { 0x3A, 0x4C }, /* LATIN CAPITAL LETTER L WITH LINE BELOW -> 'L' */ + { 0x3B, 0x6C }, /* LATIN SMALL LETTER L WITH LINE BELOW -> 'l' */ + { 0x3C, 0x4C }, /* LATIN CAPITAL LETTER L WITH CIRCUMFLEX BELOW -> 'L' */ + { 0x3D, 0x6C }, /* LATIN SMALL LETTER L WITH CIRCUMFLEX BELOW -> 'l' */ + { 0x3E, 0x4D }, /* LATIN CAPITAL LETTER M WITH ACUTE -> 'M' */ + { 0x3F, 0x6D }, /* LATIN SMALL LETTER M WITH ACUTE -> 'm' */ + { 0x40, 0x4D }, /* LATIN CAPITAL LETTER M WITH DOT ABOVE -> 'M' */ + { 0x41, 0x6D }, /* LATIN SMALL LETTER M WITH DOT ABOVE -> 'm' */ + { 0x42, 0x4D }, /* LATIN CAPITAL LETTER M WITH DOT BELOW -> 'M' */ + { 0x43, 0x6D }, /* LATIN SMALL LETTER M WITH DOT BELOW -> 'm' */ + { 0x44, 0x4E }, /* LATIN CAPITAL LETTER N WITH DOT ABOVE -> 'N' */ + { 0x45, 0x6E }, /* LATIN SMALL LETTER N WITH DOT ABOVE -> 'n' */ + { 0x46, 0x4E }, /* LATIN CAPITAL LETTER N WITH DOT BELOW -> 'N' */ + { 0x47, 0x6E }, /* LATIN SMALL LETTER N WITH DOT BELOW -> 'n' */ + { 0x48, 0x4E }, /* LATIN CAPITAL LETTER N WITH LINE BELOW -> 'N' */ + { 0x49, 0x6E }, /* LATIN SMALL LETTER N WITH LINE BELOW -> 'n' */ + { 0x4A, 0x4E }, /* LATIN CAPITAL LETTER N WITH CIRCUMFLEX BELOW -> 'N' */ + { 0x4B, 0x6E }, /* LATIN SMALL LETTER N WITH CIRCUMFLEX BELOW -> 'n' */ + { 0x4C, 0x4F }, /* LATIN CAPITAL LETTER O WITH TILDE AND ACUTE -> 'O' */ + { 0x4D, 0x6F }, /* LATIN SMALL LETTER O WITH TILDE AND ACUTE -> 'o' */ + { 0x4E, 0x4F }, /* LATIN CAPITAL LETTER O WITH TILDE AND DIAERESIS -> 'O' */ + { 0x4F, 0x6F }, /* LATIN SMALL LETTER O WITH TILDE AND DIAERESIS -> 'o' */ + { 0x50, 0x4F }, /* LATIN CAPITAL LETTER O WITH MACRON AND GRAVE -> 'O' */ + { 0x51, 0x6F }, /* LATIN SMALL LETTER O WITH MACRON AND GRAVE -> 'o' */ + { 0x52, 0x4F }, /* LATIN CAPITAL LETTER O WITH MACRON AND ACUTE -> 'O' */ + { 0x53, 0x6F }, /* LATIN SMALL LETTER O WITH MACRON AND ACUTE -> 'o' */ + { 0x54, 0x50 }, /* LATIN CAPITAL LETTER P WITH ACUTE -> 'P' */ + { 0x55, 0x70 }, /* LATIN SMALL LETTER P WITH ACUTE -> 'p' */ + { 0x56, 0x50 }, /* LATIN CAPITAL LETTER P WITH DOT ABOVE -> 'P' */ + { 0x57, 0x70 }, /* LATIN SMALL LETTER P WITH DOT ABOVE -> 'p' */ + { 0x58, 0x52 }, /* LATIN CAPITAL LETTER R WITH DOT ABOVE -> 'R' */ + { 0x59, 0x72 }, /* LATIN SMALL LETTER R WITH DOT ABOVE -> 'r' */ + { 0x5A, 0x52 }, /* LATIN CAPITAL LETTER R WITH DOT BELOW -> 'R' */ + { 0x5B, 0x72 }, /* LATIN SMALL LETTER R WITH DOT BELOW -> 'r' */ + { 0x5C, 0x52 }, /* LATIN CAPITAL LETTER R WITH DOT BELOW AND MACRON -> 'R' */ + { 0x5D, 0x72 }, /* LATIN SMALL LETTER R WITH DOT BELOW AND MACRON -> 'r' */ + { 0x5E, 0x52 }, /* LATIN CAPITAL LETTER R WITH LINE BELOW -> 'R' */ + { 0x5F, 0x72 }, /* LATIN SMALL LETTER R WITH LINE BELOW -> 'r' */ + { 0x60, 0x53 }, /* LATIN CAPITAL LETTER S WITH DOT ABOVE -> 'S' */ + { 0x61, 0x73 }, /* LATIN SMALL LETTER S WITH DOT ABOVE -> 's' */ + { 0x62, 0x53 }, /* LATIN CAPITAL LETTER S WITH DOT BELOW -> 'S' */ + { 0x63, 0x73 }, /* LATIN SMALL LETTER S WITH DOT BELOW -> 's' */ + { 0x64, 0x53 }, /* LATIN CAPITAL LETTER S WITH ACUTE AND DOT ABOVE -> 'S' */ + { 0x65, 0x73 }, /* LATIN SMALL LETTER S WITH ACUTE AND DOT ABOVE -> 's' */ + { 0x66, 0x53 }, /* LATIN CAPITAL LETTER S WITH CARON AND DOT ABOVE -> 'S' */ + { 0x67, 0x73 }, /* LATIN SMALL LETTER S WITH CARON AND DOT ABOVE -> 's' */ + { 0x68, 0x53 }, /* LATIN CAPITAL LETTER S WITH DOT BELOW AND DOT ABOVE -> 'S' */ + { 0x69, 0x73 }, /* LATIN SMALL LETTER S WITH DOT BELOW AND DOT ABOVE -> 's' */ + { 0x6A, 0x54 }, /* LATIN CAPITAL LETTER T WITH DOT ABOVE -> 'T' */ + { 0x6B, 0x74 }, /* LATIN SMALL LETTER T WITH DOT ABOVE -> 't' */ + { 0x6C, 0x54 }, /* LATIN CAPITAL LETTER T WITH DOT BELOW -> 'T' */ + { 0x6D, 0x74 }, /* LATIN SMALL LETTER T WITH DOT BELOW -> 't' */ + { 0x6E, 0x54 }, /* LATIN CAPITAL LETTER T WITH LINE BELOW -> 'T' */ + { 0x6F, 0x74 }, /* LATIN SMALL LETTER T WITH LINE BELOW -> 't' */ + { 0x70, 0x54 }, /* LATIN CAPITAL LETTER T WITH CIRCUMFLEX BELOW -> 'T' */ + { 0x71, 0x74 }, /* LATIN SMALL LETTER T WITH CIRCUMFLEX BELOW -> 't' */ + { 0x72, 0x55 }, /* LATIN CAPITAL LETTER U WITH DIAERESIS BELOW -> 'U' */ + { 0x73, 0x75 }, /* LATIN SMALL LETTER U WITH DIAERESIS BELOW -> 'u' */ + { 0x74, 0x55 }, /* LATIN CAPITAL LETTER U WITH TILDE BELOW -> 'U' */ + { 0x75, 0x75 }, /* LATIN SMALL LETTER U WITH TILDE BELOW -> 'u' */ + { 0x76, 0x55 }, /* LATIN CAPITAL LETTER U WITH CIRCUMFLEX BELOW -> 'U' */ + { 0x77, 0x75 }, /* LATIN SMALL LETTER U WITH CIRCUMFLEX BELOW -> 'u' */ + { 0x78, 0x55 }, /* LATIN CAPITAL LETTER U WITH TILDE AND ACUTE -> 'U' */ + { 0x79, 0x75 }, /* LATIN SMALL LETTER U WITH TILDE AND ACUTE -> 'u' */ + { 0x7A, 0x55 }, /* LATIN CAPITAL LETTER U WITH MACRON AND DIAERESIS -> 'U' */ + { 0x7B, 0x75 }, /* LATIN SMALL LETTER U WITH MACRON AND DIAERESIS -> 'u' */ + { 0x7C, 0x56 }, /* LATIN CAPITAL LETTER V WITH TILDE -> 'V' */ + { 0x7D, 0x76 }, /* LATIN SMALL LETTER V WITH TILDE -> 'v' */ + { 0x7E, 0x56 }, /* LATIN CAPITAL LETTER V WITH DOT BELOW -> 'V' */ + { 0x7F, 0x76 }, /* LATIN SMALL LETTER V WITH DOT BELOW -> 'v' */ + { 0x80, 0x57 }, /* LATIN CAPITAL LETTER W WITH GRAVE -> 'W' */ + { 0x81, 0x77 }, /* LATIN SMALL LETTER W WITH GRAVE -> 'w' */ + { 0x82, 0x57 }, /* LATIN CAPITAL LETTER W WITH ACUTE -> 'W' */ + { 0x83, 0x77 }, /* LATIN SMALL LETTER W WITH ACUTE -> 'w' */ + { 0x84, 0x57 }, /* LATIN CAPITAL LETTER W WITH DIAERESIS -> 'W' */ + { 0x85, 0x77 }, /* LATIN SMALL LETTER W WITH DIAERESIS -> 'w' */ + { 0x86, 0x57 }, /* LATIN CAPITAL LETTER W WITH DOT ABOVE -> 'W' */ + { 0x87, 0x77 }, /* LATIN SMALL LETTER W WITH DOT ABOVE -> 'w' */ + { 0x88, 0x57 }, /* LATIN CAPITAL LETTER W WITH DOT BELOW -> 'W' */ + { 0x89, 0x77 }, /* LATIN SMALL LETTER W WITH DOT BELOW -> 'w' */ + { 0x8A, 0x58 }, /* LATIN CAPITAL LETTER X WITH DOT ABOVE -> 'X' */ + { 0x8B, 0x78 }, /* LATIN SMALL LETTER X WITH DOT ABOVE -> 'x' */ + { 0x8C, 0x58 }, /* LATIN CAPITAL LETTER X WITH DIAERESIS -> 'X' */ + { 0x8D, 0x78 }, /* LATIN SMALL LETTER X WITH DIAERESIS -> 'x' */ + { 0x8E, 0x59 }, /* LATIN CAPITAL LETTER Y WITH DOT ABOVE -> 'Y' */ + { 0x8F, 0x79 }, /* LATIN SMALL LETTER Y WITH DOT ABOVE -> 'y' */ + { 0x90, 0x5A }, /* LATIN CAPITAL LETTER Z WITH CIRCUMFLEX -> 'Z' */ + { 0x91, 0x7A }, /* LATIN SMALL LETTER Z WITH CIRCUMFLEX -> 'z' */ + { 0x92, 0x5A }, /* LATIN CAPITAL LETTER Z WITH DOT BELOW -> 'Z' */ + { 0x93, 0x7A }, /* LATIN SMALL LETTER Z WITH DOT BELOW -> 'z' */ + { 0x94, 0x5A }, /* LATIN CAPITAL LETTER Z WITH LINE BELOW -> 'Z' */ + { 0x95, 0x7A }, /* LATIN SMALL LETTER Z WITH LINE BELOW -> 'z' */ + { 0x96, 0x68 }, /* LATIN SMALL LETTER H WITH LINE BELOW -> 'h' */ + { 0x97, 0x74 }, /* LATIN SMALL LETTER T WITH DIAERESIS -> 't' */ + { 0x98, 0x77 }, /* LATIN SMALL LETTER W WITH RING ABOVE -> 'w' */ + { 0x99, 0x79 }, /* LATIN SMALL LETTER Y WITH RING ABOVE -> 'y' */ + { 0x9A, 0x61 }, /* LATIN SMALL LETTER A WITH RIGHT HALF RING -> 'a' */ + { 0x9B, 0x53 }, /* LATIN SMALL LETTER LONG S WITH DOT ABOVE -> 'S' */ + { 0xA0, 0x41 }, /* LATIN CAPITAL LETTER A WITH DOT BELOW -> 'A' */ + { 0xA1, 0x61 }, /* LATIN SMALL LETTER A WITH DOT BELOW -> 'a' */ + { 0xA2, 0x41 }, /* LATIN CAPITAL LETTER A WITH HOOK ABOVE -> 'A' */ + { 0xA3, 0x61 }, /* LATIN SMALL LETTER A WITH HOOK ABOVE -> 'a' */ + { 0xA4, 0x41 }, /* LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND ACUTE -> 'A' */ + { 0xA5, 0x61 }, /* LATIN SMALL LETTER A WITH CIRCUMFLEX AND ACUTE -> 'a' */ + { 0xA6, 0x41 }, /* LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND GRAVE -> 'A' */ + { 0xA7, 0x61 }, /* LATIN SMALL LETTER A WITH CIRCUMFLEX AND GRAVE -> 'a' */ + { 0xA8, 0x41 }, /* LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE -> 'A' */ + { 0xA9, 0x61 }, /* LATIN SMALL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE -> 'a' */ + { 0xAA, 0x41 }, /* LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND TILDE -> 'A' */ + { 0xAB, 0x61 }, /* LATIN SMALL LETTER A WITH CIRCUMFLEX AND TILDE -> 'a' */ + { 0xAC, 0x41 }, /* LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND DOT BELOW -> 'A' */ + { 0xAD, 0x61 }, /* LATIN SMALL LETTER A WITH CIRCUMFLEX AND DOT BELOW -> 'a' */ + { 0xAE, 0x41 }, /* LATIN CAPITAL LETTER A WITH BREVE AND ACUTE -> 'A' */ + { 0xAF, 0x61 }, /* LATIN SMALL LETTER A WITH BREVE AND ACUTE -> 'a' */ + { 0xB0, 0x41 }, /* LATIN CAPITAL LETTER A WITH BREVE AND GRAVE -> 'A' */ + { 0xB1, 0x61 }, /* LATIN SMALL LETTER A WITH BREVE AND GRAVE -> 'a' */ + { 0xB2, 0x41 }, /* LATIN CAPITAL LETTER A WITH BREVE AND HOOK ABOVE -> 'A' */ + { 0xB3, 0x61 }, /* LATIN SMALL LETTER A WITH BREVE AND HOOK ABOVE -> 'a' */ + { 0xB4, 0x41 }, /* LATIN CAPITAL LETTER A WITH BREVE AND TILDE -> 'A' */ + { 0xB5, 0x61 }, /* LATIN SMALL LETTER A WITH BREVE AND TILDE -> 'a' */ + { 0xB6, 0x41 }, /* LATIN CAPITAL LETTER A WITH BREVE AND DOT BELOW -> 'A' */ + { 0xB7, 0x61 }, /* LATIN SMALL LETTER A WITH BREVE AND DOT BELOW -> 'a' */ + { 0xB8, 0x45 }, /* LATIN CAPITAL LETTER E WITH DOT BELOW -> 'E' */ + { 0xB9, 0x65 }, /* LATIN SMALL LETTER E WITH DOT BELOW -> 'e' */ + { 0xBA, 0x45 }, /* LATIN CAPITAL LETTER E WITH HOOK ABOVE -> 'E' */ + { 0xBB, 0x65 }, /* LATIN SMALL LETTER E WITH HOOK ABOVE -> 'e' */ + { 0xBC, 0x45 }, /* LATIN CAPITAL LETTER E WITH TILDE -> 'E' */ + { 0xBD, 0x65 }, /* LATIN SMALL LETTER E WITH TILDE -> 'e' */ + { 0xBE, 0x45 }, /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND ACUTE -> 'E' */ + { 0xBF, 0x65 }, /* LATIN SMALL LETTER E WITH CIRCUMFLEX AND ACUTE -> 'e' */ + { 0xC0, 0x45 }, /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND GRAVE -> 'E' */ + { 0xC1, 0x65 }, /* LATIN SMALL LETTER E WITH CIRCUMFLEX AND GRAVE -> 'e' */ + { 0xC2, 0x45 }, /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE -> 'E' */ + { 0xC3, 0x65 }, /* LATIN SMALL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE -> 'e' */ + { 0xC4, 0x45 }, /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND TILDE -> 'E' */ + { 0xC5, 0x65 }, /* LATIN SMALL LETTER E WITH CIRCUMFLEX AND TILDE -> 'e' */ + { 0xC6, 0x45 }, /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND DOT BELOW -> 'E' */ + { 0xC7, 0x65 }, /* LATIN SMALL LETTER E WITH CIRCUMFLEX AND DOT BELOW -> 'e' */ + { 0xC8, 0x49 }, /* LATIN CAPITAL LETTER I WITH HOOK ABOVE -> 'I' */ + { 0xC9, 0x69 }, /* LATIN SMALL LETTER I WITH HOOK ABOVE -> 'i' */ + { 0xCA, 0x49 }, /* LATIN CAPITAL LETTER I WITH DOT BELOW -> 'I' */ + { 0xCB, 0x69 }, /* LATIN SMALL LETTER I WITH DOT BELOW -> 'i' */ + { 0xCC, 0x4F }, /* LATIN CAPITAL LETTER O WITH DOT BELOW -> 'O' */ + { 0xCD, 0x6F }, /* LATIN SMALL LETTER O WITH DOT BELOW -> 'o' */ + { 0xCE, 0x4F }, /* LATIN CAPITAL LETTER O WITH HOOK ABOVE -> 'O' */ + { 0xCF, 0x6F }, /* LATIN SMALL LETTER O WITH HOOK ABOVE -> 'o' */ + { 0xD0, 0x4F }, /* LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND ACUTE -> 'O' */ + { 0xD1, 0x6F }, /* LATIN SMALL LETTER O WITH CIRCUMFLEX AND ACUTE -> 'o' */ + { 0xD2, 0x4F }, /* LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND GRAVE -> 'O' */ + { 0xD3, 0x6F }, /* LATIN SMALL LETTER O WITH CIRCUMFLEX AND GRAVE -> 'o' */ + { 0xD4, 0x4F }, /* LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE -> 'O' */ + { 0xD5, 0x6F }, /* LATIN SMALL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE -> 'o' */ + { 0xD6, 0x4F }, /* LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND TILDE -> 'O' */ + { 0xD7, 0x6F }, /* LATIN SMALL LETTER O WITH CIRCUMFLEX AND TILDE -> 'o' */ + { 0xD8, 0x4F }, /* LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND DOT BELOW -> 'O' */ + { 0xD9, 0x6F }, /* LATIN SMALL LETTER O WITH CIRCUMFLEX AND DOT BELOW -> 'o' */ + { 0xDA, 0x4F }, /* LATIN CAPITAL LETTER O WITH HORN AND ACUTE -> 'O' */ + { 0xDB, 0x6F }, /* LATIN SMALL LETTER O WITH HORN AND ACUTE -> 'o' */ + { 0xDC, 0x4F }, /* LATIN CAPITAL LETTER O WITH HORN AND GRAVE -> 'O' */ + { 0xDD, 0x6F }, /* LATIN SMALL LETTER O WITH HORN AND GRAVE -> 'o' */ + { 0xDE, 0x4F }, /* LATIN CAPITAL LETTER O WITH HORN AND HOOK ABOVE -> 'O' */ + { 0xDF, 0x6F }, /* LATIN SMALL LETTER O WITH HORN AND HOOK ABOVE -> 'o' */ + { 0xE0, 0x4F }, /* LATIN CAPITAL LETTER O WITH HORN AND TILDE -> 'O' */ + { 0xE1, 0x6F }, /* LATIN SMALL LETTER O WITH HORN AND TILDE -> 'o' */ + { 0xE2, 0x4F }, /* LATIN CAPITAL LETTER O WITH HORN AND DOT BELOW -> 'O' */ + { 0xE3, 0x6F }, /* LATIN SMALL LETTER O WITH HORN AND DOT BELOW -> 'o' */ + { 0xE4, 0x55 }, /* LATIN CAPITAL LETTER U WITH DOT BELOW -> 'U' */ + { 0xE5, 0x75 }, /* LATIN SMALL LETTER U WITH DOT BELOW -> 'u' */ + { 0xE6, 0x55 }, /* LATIN CAPITAL LETTER U WITH HOOK ABOVE -> 'U' */ + { 0xE7, 0x75 }, /* LATIN SMALL LETTER U WITH HOOK ABOVE -> 'u' */ + { 0xE8, 0x55 }, /* LATIN CAPITAL LETTER U WITH HORN AND ACUTE -> 'U' */ + { 0xE9, 0x75 }, /* LATIN SMALL LETTER U WITH HORN AND ACUTE -> 'u' */ + { 0xEA, 0x55 }, /* LATIN CAPITAL LETTER U WITH HORN AND GRAVE -> 'U' */ + { 0xEB, 0x75 }, /* LATIN SMALL LETTER U WITH HORN AND GRAVE -> 'u' */ + { 0xEC, 0x55 }, /* LATIN CAPITAL LETTER U WITH HORN AND HOOK ABOVE -> 'U' */ + { 0xED, 0x75 }, /* LATIN SMALL LETTER U WITH HORN AND HOOK ABOVE -> 'u' */ + { 0xEE, 0x55 }, /* LATIN CAPITAL LETTER U WITH HORN AND TILDE -> 'U' */ + { 0xEF, 0x75 }, /* LATIN SMALL LETTER U WITH HORN AND TILDE -> 'u' */ + { 0xF0, 0x55 }, /* LATIN CAPITAL LETTER U WITH HORN AND DOT BELOW -> 'U' */ + { 0xF1, 0x75 }, /* LATIN SMALL LETTER U WITH HORN AND DOT BELOW -> 'u' */ + { 0xF2, 0x59 }, /* LATIN CAPITAL LETTER Y WITH GRAVE -> 'Y' */ + { 0xF3, 0x79 }, /* LATIN SMALL LETTER Y WITH GRAVE -> 'y' */ + { 0xF4, 0x59 }, /* LATIN CAPITAL LETTER Y WITH DOT BELOW -> 'Y' */ + { 0xF5, 0x79 }, /* LATIN SMALL LETTER Y WITH DOT BELOW -> 'y' */ + { 0xF6, 0x59 }, /* LATIN CAPITAL LETTER Y WITH HOOK ABOVE -> 'Y' */ + { 0xF7, 0x79 }, /* LATIN SMALL LETTER Y WITH HOOK ABOVE -> 'y' */ + { 0xF8, 0x59 }, /* LATIN CAPITAL LETTER Y WITH TILDE -> 'Y' */ + { 0xF9, 0x79 }, /* LATIN SMALL LETTER Y WITH TILDE -> 'y' */ + /* Entries for page 0x1F */ + { 0x00, 0x00 }, /* GREEK SMALL LETTER ALPHA WITH PSILI -> ... */ + { 0x07, 0x61 }, /* GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI -> 'a' */ + { 0x08, 0x00 }, /* GREEK CAPITAL LETTER ALPHA WITH PSILI -> ... */ + { 0x0F, 0x41 }, /* GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI -> 'A' */ + { 0x10, 0x00 }, /* GREEK SMALL LETTER EPSILON WITH PSILI -> ... */ + { 0x15, 0x65 }, /* GREEK SMALL LETTER EPSILON WITH DASIA AND OXIA -> 'e' */ + { 0x18, 0x00 }, /* GREEK CAPITAL LETTER EPSILON WITH PSILI -> ... */ + { 0x1D, 0x45 }, /* GREEK CAPITAL LETTER EPSILON WITH DASIA AND OXIA -> 'E' */ + { 0x20, 0x00 }, /* GREEK SMALL LETTER ETA WITH PSILI -> ... */ + { 0x27, 0x65 }, /* GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI -> 'e' */ + { 0x28, 0x00 }, /* GREEK CAPITAL LETTER ETA WITH PSILI -> ... */ + { 0x2F, 0x45 }, /* GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI -> 'E' */ + { 0x30, 0x00 }, /* GREEK SMALL LETTER IOTA WITH PSILI -> ... */ + { 0x37, 0x69 }, /* GREEK SMALL LETTER IOTA WITH DASIA AND PERISPOMENI -> 'i' */ + { 0x38, 0x00 }, /* GREEK CAPITAL LETTER IOTA WITH PSILI -> ... */ + { 0x3F, 0x49 }, /* GREEK CAPITAL LETTER IOTA WITH DASIA AND PERISPOMENI -> 'I' */ + { 0x40, 0x00 }, /* GREEK SMALL LETTER OMICRON WITH PSILI -> ... */ + { 0x45, 0x6F }, /* GREEK SMALL LETTER OMICRON WITH DASIA AND OXIA -> 'o' */ + { 0x48, 0x00 }, /* GREEK CAPITAL LETTER OMICRON WITH PSILI -> ... */ + { 0x4D, 0x4F }, /* GREEK CAPITAL LETTER OMICRON WITH DASIA AND OXIA -> 'O' */ + { 0x50, 0x00 }, /* GREEK SMALL LETTER UPSILON WITH PSILI -> ... */ + { 0x57, 0x75 }, /* GREEK SMALL LETTER UPSILON WITH DASIA AND PERISPOMENI -> 'u' */ + { 0x59, 0x55 }, /* GREEK CAPITAL LETTER UPSILON WITH DASIA -> 'U' */ + { 0x5B, 0x55 }, /* GREEK CAPITAL LETTER UPSILON WITH DASIA AND VARIA -> 'U' */ + { 0x5D, 0x55 }, /* GREEK CAPITAL LETTER UPSILON WITH DASIA AND OXIA -> 'U' */ + { 0x5F, 0x55 }, /* GREEK CAPITAL LETTER UPSILON WITH DASIA AND PERISPOMENI -> 'U' */ + { 0x60, 0x00 }, /* GREEK SMALL LETTER OMEGA WITH PSILI -> ... */ + { 0x67, 0x6F }, /* GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI -> 'o' */ + { 0x68, 0x00 }, /* GREEK CAPITAL LETTER OMEGA WITH PSILI -> ... */ + { 0x6F, 0x4F }, /* GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI -> 'O' */ + { 0x70, 0x61 }, /* GREEK SMALL LETTER ALPHA WITH VARIA -> 'a' */ + { 0x71, 0x61 }, /* GREEK SMALL LETTER ALPHA WITH OXIA -> 'a' */ + { 0x72, 0x00 }, /* GREEK SMALL LETTER EPSILON WITH VARIA -> ... */ + { 0x75, 0x65 }, /* GREEK SMALL LETTER ETA WITH OXIA -> 'e' */ + { 0x76, 0x69 }, /* GREEK SMALL LETTER IOTA WITH VARIA -> 'i' */ + { 0x77, 0x69 }, /* GREEK SMALL LETTER IOTA WITH OXIA -> 'i' */ + { 0x78, 0x6F }, /* GREEK SMALL LETTER OMICRON WITH VARIA -> 'o' */ + { 0x79, 0x6F }, /* GREEK SMALL LETTER OMICRON WITH OXIA -> 'o' */ + { 0x7A, 0x75 }, /* GREEK SMALL LETTER UPSILON WITH VARIA -> 'u' */ + { 0x7B, 0x75 }, /* GREEK SMALL LETTER UPSILON WITH OXIA -> 'u' */ + { 0x7C, 0x6F }, /* GREEK SMALL LETTER OMEGA WITH VARIA -> 'o' */ + { 0x7D, 0x6F }, /* GREEK SMALL LETTER OMEGA WITH OXIA -> 'o' */ + { 0x80, 0x00 }, /* GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI -> ... */ + { 0x87, 0x61 }, /* GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI -> 'a' */ + { 0x88, 0x00 }, /* GREEK CAPITAL LETTER ALPHA WITH PSILI AND PROSGEGRAMMENI -> ... */ + { 0x8F, 0x41 }, /* GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI -> 'A' */ + { 0x90, 0x00 }, /* GREEK SMALL LETTER ETA WITH PSILI AND YPOGEGRAMMENI -> ... */ + { 0x97, 0x65 }, /* GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI -> 'e' */ + { 0x98, 0x00 }, /* GREEK CAPITAL LETTER ETA WITH PSILI AND PROSGEGRAMMENI -> ... */ + { 0x9F, 0x45 }, /* GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI -> 'E' */ + { 0xA0, 0x00 }, /* GREEK SMALL LETTER OMEGA WITH PSILI AND YPOGEGRAMMENI -> ... */ + { 0xA7, 0x6F }, /* GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI -> 'o' */ + { 0xA8, 0x00 }, /* GREEK CAPITAL LETTER OMEGA WITH PSILI AND PROSGEGRAMMENI -> ... */ + { 0xAF, 0x4F }, /* GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI -> 'O' */ + { 0xB0, 0x00 }, /* GREEK SMALL LETTER ALPHA WITH VRACHY -> ... */ + { 0xB4, 0x61 }, /* GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI -> 'a' */ + { 0xB6, 0x61 }, /* GREEK SMALL LETTER ALPHA WITH PERISPOMENI -> 'a' */ + { 0xB7, 0x61 }, /* GREEK SMALL LETTER ALPHA WITH PERISPOMENI AND YPOGEGRAMMENI -> 'a' */ + { 0xB8, 0x00 }, /* GREEK CAPITAL LETTER ALPHA WITH VRACHY -> ... */ + { 0xBC, 0x41 }, /* GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI -> 'A' */ + { 0xBD, 0x27 }, /* GREEK KORONIS -> ''' */ + { 0xBE, 0x69 }, /* GREEK PROSGEGRAMMENI -> 'i' */ + { 0xBF, 0x27 }, /* GREEK PSILI -> ''' */ + { 0xC0, 0x7E }, /* GREEK PERISPOMENI -> '~' */ + { 0xC2, 0x00 }, /* GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI -> ... */ + { 0xC4, 0x65 }, /* GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI -> 'e' */ + { 0xC6, 0x65 }, /* GREEK SMALL LETTER ETA WITH PERISPOMENI -> 'e' */ + { 0xC7, 0x65 }, /* GREEK SMALL LETTER ETA WITH PERISPOMENI AND YPOGEGRAMMENI -> 'e' */ + { 0xC8, 0x00 }, /* GREEK CAPITAL LETTER EPSILON WITH VARIA -> ... */ + { 0xCC, 0x45 }, /* GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI -> 'E' */ + { 0xD0, 0x00 }, /* GREEK SMALL LETTER IOTA WITH VRACHY -> ... */ + { 0xD3, 0x69 }, /* GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA -> 'i' */ + { 0xD6, 0x69 }, /* GREEK SMALL LETTER IOTA WITH PERISPOMENI -> 'i' */ + { 0xD7, 0x69 }, /* GREEK SMALL LETTER IOTA WITH DIALYTIKA AND PERISPOMENI -> 'i' */ + { 0xD8, 0x00 }, /* GREEK CAPITAL LETTER IOTA WITH VRACHY -> ... */ + { 0xDB, 0x49 }, /* GREEK CAPITAL LETTER IOTA WITH OXIA -> 'I' */ + { 0xE0, 0x00 }, /* GREEK SMALL LETTER UPSILON WITH VRACHY -> ... */ + { 0xE3, 0x75 }, /* GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND OXIA -> 'u' */ + { 0xE4, 0x52 }, /* GREEK SMALL LETTER RHO WITH PSILI -> 'R' */ + { 0xE5, 0x52 }, /* GREEK SMALL LETTER RHO WITH DASIA -> 'R' */ + { 0xE6, 0x75 }, /* GREEK SMALL LETTER UPSILON WITH PERISPOMENI -> 'u' */ + { 0xE7, 0x75 }, /* GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND PERISPOMENI -> 'u' */ + { 0xE8, 0x00 }, /* GREEK CAPITAL LETTER UPSILON WITH VRACHY -> ... */ + { 0xEB, 0x55 }, /* GREEK CAPITAL LETTER UPSILON WITH OXIA -> 'U' */ + { 0xEC, 0x52 }, /* GREEK CAPITAL LETTER RHO WITH DASIA -> 'R' */ + { 0xEF, 0x60 }, /* GREEK VARIA -> '`' */ + { 0xF2, 0x00 }, /* GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI -> ... */ + { 0xF4, 0x6F }, /* GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI -> 'o' */ + { 0xF6, 0x6F }, /* GREEK SMALL LETTER OMEGA WITH PERISPOMENI -> 'o' */ + { 0xF7, 0x6F }, /* GREEK SMALL LETTER OMEGA WITH PERISPOMENI AND YPOGEGRAMMENI -> 'o' */ + { 0xF8, 0x00 }, /* GREEK CAPITAL LETTER OMICRON WITH VARIA -> ... */ + { 0xFC, 0x4F }, /* GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI -> 'O' */ + { 0xFD, 0x27 }, /* GREEK OXIA -> ''' */ + { 0xFE, 0x60 }, /* GREEK DASIA -> '`' */ + /* Entries for page 0x20 */ + { 0x00, 0x00 }, /* EN QUAD -> ... */ + { 0x0B, 0x20 }, /* ZERO WIDTH SPACE -> ' ' */ + { 0x10, 0x00 }, /* HYPHEN -> ... */ + { 0x15, 0x2D }, /* HORIZONTAL BAR -> '-' */ + { 0x17, 0x5F }, /* DOUBLE LOW LINE -> '_' */ + { 0x18, 0x27 }, /* LEFT SINGLE QUOTATION MARK -> ''' */ + { 0x19, 0x27 }, /* RIGHT SINGLE QUOTATION MARK -> ''' */ + { 0x1A, 0x2C }, /* SINGLE LOW-9 QUOTATION MARK -> ',' */ + { 0x1B, 0x27 }, /* SINGLE HIGH-REVERSED-9 QUOTATION MARK -> ''' */ + { 0x1C, 0x00 }, /* LEFT DOUBLE QUOTATION MARK -> ... */ + { 0x1F, 0x22 }, /* DOUBLE HIGH-REVERSED-9 QUOTATION MARK -> '"' */ + { 0x20, 0x2B }, /* DAGGER -> '+' */ + { 0x22, 0x2A }, /* BULLET -> '*' */ + { 0x23, 0x3E }, /* TRIANGULAR BULLET -> '>' */ + { 0x24, 0x2E }, /* ONE DOT LEADER -> '.' */ + { 0x26, 0x2E }, /* HORIZONTAL ELLIPSIS -> '.' */ + { 0x27, 0x2E }, /* HYPHENATION POINT -> '.' */ + { 0x2F, 0x20 }, /* NARROW NO-BREAK SPACE -> ' ' */ + { 0x32, 0x27 }, /* PRIME -> ''' */ + { 0x33, 0x22 }, /* DOUBLE PRIME -> '"' */ + { 0x35, 0x60 }, /* REVERSED PRIME -> '`' */ + { 0x38, 0x5E }, /* CARET -> '^' */ + { 0x39, 0x3C }, /* SINGLE LEFT-POINTING ANGLE QUOTATION MARK -> '<' */ + { 0x3A, 0x3E }, /* SINGLE RIGHT-POINTING ANGLE QUOTATION MARK -> '>' */ + { 0x3B, 0x2A }, /* REFERENCE MARK -> '*' */ + { 0x3C, 0x21 }, /* DOUBLE EXCLAMATION MARK -> '!' */ + { 0x3D, 0x3F }, /* INTERROBANG -> '?' */ + { 0x3E, 0x2D }, /* OVERLINE -> '-' */ + { 0x3F, 0x5F }, /* UNDERTIE -> '_' */ + { 0x40, 0x2D }, /* CHARACTER TIE -> '-' */ + { 0x41, 0x5E }, /* CARET INSERTION POINT -> '^' */ + { 0x42, 0x2A }, /* ASTERISM -> '*' */ + { 0x43, 0x2D }, /* HYPHEN BULLET -> '-' */ + { 0x44, 0x2F }, /* FRACTION SLASH -> '/' */ + { 0x47, 0x3F }, /* DOUBLE QUESTION MARK -> '?' */ + { 0x48, 0x3F }, /* QUESTION EXCLAMATION MARK -> '?' */ + { 0x49, 0x21 }, /* EXCLAMATION QUESTION MARK -> '!' */ + { 0x4A, 0x26 }, /* TIRONIAN SIGN ET -> '&' */ + { 0x4B, 0x50 }, /* REVERSED PILCROW SIGN -> 'P' */ + { 0x4C, 0x3C }, /* BLACK LEFTWARDS BULLET -> '<' */ + { 0x4D, 0x3E }, /* BLACK RIGHTWARDS BULLET -> '>' */ + { 0x4E, 0x2A }, /* LOW ASTERISK -> '*' */ + { 0x4F, 0x3B }, /* REVERSED SEMICOLON -> ';' */ + { 0x51, 0x2A }, /* TWO ASTERISKS ALIGNED VERTICALLY -> '*' */ + { 0x52, 0x2D }, /* COMMERCIAL MINUS SIGN -> '-' */ + { 0x53, 0x7E }, /* SWUNG DASH -> '~' */ + { 0x55, 0x2A }, /* FLOWER PUNCTUATION MARK -> '*' */ + { 0x5B, 0x3A }, /* FOUR DOT MARK -> ':' */ + { 0x5F, 0x20 }, /* MEDIUM MATHEMATICAL SPACE -> ' ' */ + { 0x70, 0x30 }, /* SUPERSCRIPT ZERO -> '0' */ + { 0x71, 0x69 }, /* SUPERSCRIPT LATIN SMALL LETTER I -> 'i' */ + { 0x74, 0x34 }, /* SUPERSCRIPT FOUR -> '4' */ + { 0x75, 0x35 }, /* SUPERSCRIPT FIVE -> '5' */ + { 0x76, 0x36 }, /* SUPERSCRIPT SIX -> '6' */ + { 0x77, 0x37 }, /* SUPERSCRIPT SEVEN -> '7' */ + { 0x78, 0x38 }, /* SUPERSCRIPT EIGHT -> '8' */ + { 0x79, 0x39 }, /* SUPERSCRIPT NINE -> '9' */ + { 0x7A, 0x2B }, /* SUPERSCRIPT PLUS SIGN -> '+' */ + { 0x7B, 0x2D }, /* SUPERSCRIPT MINUS -> '-' */ + { 0x7C, 0x3D }, /* SUPERSCRIPT EQUALS SIGN -> '=' */ + { 0x7D, 0x28 }, /* SUPERSCRIPT LEFT PARENTHESIS -> '(' */ + { 0x7E, 0x29 }, /* SUPERSCRIPT RIGHT PARENTHESIS -> ')' */ + { 0x7F, 0x6E }, /* SUPERSCRIPT LATIN SMALL LETTER N -> 'n' */ + { 0x80, 0x30 }, /* SUBSCRIPT ZERO -> '0' */ + { 0x81, 0x31 }, /* SUBSCRIPT ONE -> '1' */ + { 0x82, 0x32 }, /* SUBSCRIPT TWO -> '2' */ + { 0x83, 0x33 }, /* SUBSCRIPT THREE -> '3' */ + { 0x84, 0x34 }, /* SUBSCRIPT FOUR -> '4' */ + { 0x85, 0x35 }, /* SUBSCRIPT FIVE -> '5' */ + { 0x86, 0x36 }, /* SUBSCRIPT SIX -> '6' */ + { 0x87, 0x37 }, /* SUBSCRIPT SEVEN -> '7' */ + { 0x88, 0x38 }, /* SUBSCRIPT EIGHT -> '8' */ + { 0x89, 0x39 }, /* SUBSCRIPT NINE -> '9' */ + { 0x8A, 0x2B }, /* SUBSCRIPT PLUS SIGN -> '+' */ + { 0x8B, 0x2D }, /* SUBSCRIPT MINUS -> '-' */ + { 0x8C, 0x3D }, /* SUBSCRIPT EQUALS SIGN -> '=' */ + { 0x8D, 0x28 }, /* SUBSCRIPT LEFT PARENTHESIS -> '(' */ + { 0x8E, 0x29 }, /* SUBSCRIPT RIGHT PARENTHESIS -> ')' */ + { 0x90, 0x61 }, /* LATIN SUBSCRIPT SMALL LETTER A -> 'a' */ + { 0x91, 0x65 }, /* LATIN SUBSCRIPT SMALL LETTER E -> 'e' */ + { 0x92, 0x6F }, /* LATIN SUBSCRIPT SMALL LETTER O -> 'o' */ + { 0x93, 0x78 }, /* LATIN SUBSCRIPT SMALL LETTER X -> 'x' */ + { 0x95, 0x68 }, /* LATIN SUBSCRIPT SMALL LETTER H -> 'h' */ + { 0x96, 0x6B }, /* LATIN SUBSCRIPT SMALL LETTER K -> 'k' */ + { 0x97, 0x6C }, /* LATIN SUBSCRIPT SMALL LETTER L -> 'l' */ + { 0x98, 0x6D }, /* LATIN SUBSCRIPT SMALL LETTER M -> 'm' */ + { 0x99, 0x6E }, /* LATIN SUBSCRIPT SMALL LETTER N -> 'n' */ + { 0x9A, 0x70 }, /* LATIN SUBSCRIPT SMALL LETTER P -> 'p' */ + { 0x9B, 0x73 }, /* LATIN SUBSCRIPT SMALL LETTER S -> 's' */ + { 0x9C, 0x74 }, /* LATIN SUBSCRIPT SMALL LETTER T -> 't' */ + { 0xA4, 0x4C }, /* LIRA SIGN -> 'L' */ + { 0xA6, 0x4E }, /* NAIRA SIGN -> 'N' */ + { 0xA9, 0x57 }, /* WON SIGN -> 'W' */ + { 0xAB, 0x44 }, /* DONG SIGN -> 'D' */ + { 0xAC, 0x45 }, /* EURO SIGN -> 'E' */ + { 0xAD, 0x4B }, /* KIP SIGN -> 'K' */ + { 0xAE, 0x54 }, /* TUGRIK SIGN -> 'T' */ + { 0xB1, 0x50 }, /* PESO SIGN -> 'P' */ + { 0xB2, 0x47 }, /* GUARANI SIGN -> 'G' */ + { 0xB3, 0x41 }, /* AUSTRAL SIGN -> 'A' */ + { 0xB6, 0x4C }, /* LIVRE TOURNOIS SIGN -> 'L' */ + { 0xB8, 0x54 }, /* TENGE SIGN -> 'T' */ + { 0xBA, 0x4C }, /* TURKISH LIRA SIGN -> 'L' */ + { 0xBB, 0x4D }, /* NORDIC MARK SIGN -> 'M' */ + { 0xBC, 0x6D }, /* MANAT SIGN -> 'm' */ + { 0xBD, 0x52 }, /* RUBLE SIGN -> 'R' */ + { 0xBE, 0x6C }, /* LARI SIGN -> 'l' */ + /* Entries for page 0x21 */ + { 0x02, 0x43 }, /* DOUBLE-STRUCK CAPITAL C -> 'C' */ + { 0x03, 0x43 }, /* DEGREE CELSIUS -> 'C' */ + { 0x09, 0x46 }, /* DEGREE FAHRENHEIT -> 'F' */ + { 0x0A, 0x67 }, /* SCRIPT SMALL G -> 'g' */ + { 0x0B, 0x00 }, /* SCRIPT CAPITAL H -> ... */ + { 0x0D, 0x48 }, /* DOUBLE-STRUCK CAPITAL H -> 'H' */ + { 0x0E, 0x68 }, /* PLANCK CONSTANT -> 'h' */ + { 0x10, 0x49 }, /* SCRIPT CAPITAL I -> 'I' */ + { 0x11, 0x49 }, /* BLACK-LETTER CAPITAL I -> 'I' */ + { 0x12, 0x4C }, /* SCRIPT CAPITAL L -> 'L' */ + { 0x13, 0x6C }, /* SCRIPT SMALL L -> 'l' */ + { 0x15, 0x4E }, /* DOUBLE-STRUCK CAPITAL N -> 'N' */ + { 0x19, 0x50 }, /* DOUBLE-STRUCK CAPITAL P -> 'P' */ + { 0x1A, 0x51 }, /* DOUBLE-STRUCK CAPITAL Q -> 'Q' */ + { 0x1B, 0x00 }, /* SCRIPT CAPITAL R -> ... */ + { 0x1D, 0x52 }, /* DOUBLE-STRUCK CAPITAL R -> 'R' */ + { 0x22, 0x54 }, /* TRADE MARK SIGN -> 'T' */ + { 0x24, 0x5A }, /* DOUBLE-STRUCK CAPITAL Z -> 'Z' */ + { 0x28, 0x5A }, /* BLACK-LETTER CAPITAL Z -> 'Z' */ + { 0x2A, 0x4B }, /* KELVIN SIGN -> 'K' */ + { 0x2B, 0x41 }, /* ANGSTROM SIGN -> 'A' */ + { 0x2C, 0x42 }, /* SCRIPT CAPITAL B -> 'B' */ + { 0x2D, 0x43 }, /* BLACK-LETTER CAPITAL C -> 'C' */ + { 0x2E, 0x65 }, /* ESTIMATED SYMBOL -> 'e' */ + { 0x2F, 0x65 }, /* SCRIPT SMALL E -> 'e' */ + { 0x30, 0x45 }, /* SCRIPT CAPITAL E -> 'E' */ + { 0x31, 0x46 }, /* SCRIPT CAPITAL F -> 'F' */ + { 0x32, 0x46 }, /* TURNED CAPITAL F -> 'F' */ + { 0x33, 0x4D }, /* SCRIPT CAPITAL M -> 'M' */ + { 0x34, 0x6F }, /* SCRIPT SMALL O -> 'o' */ + { 0x39, 0x69 }, /* INFORMATION SOURCE -> 'i' */ + { 0x45, 0x44 }, /* DOUBLE-STRUCK ITALIC CAPITAL D -> 'D' */ + { 0x46, 0x64 }, /* DOUBLE-STRUCK ITALIC SMALL D -> 'd' */ + { 0x47, 0x65 }, /* DOUBLE-STRUCK ITALIC SMALL E -> 'e' */ + { 0x48, 0x69 }, /* DOUBLE-STRUCK ITALIC SMALL I -> 'i' */ + { 0x49, 0x6A }, /* DOUBLE-STRUCK ITALIC SMALL J -> 'j' */ + { 0x4E, 0x46 }, /* TURNED SMALL F -> 'F' */ + { 0x60, 0x49 }, /* ROMAN NUMERAL ONE -> 'I' */ + { 0x64, 0x56 }, /* ROMAN NUMERAL FIVE -> 'V' */ + { 0x69, 0x58 }, /* ROMAN NUMERAL TEN -> 'X' */ + { 0x6C, 0x4C }, /* ROMAN NUMERAL FIFTY -> 'L' */ + { 0x6D, 0x43 }, /* ROMAN NUMERAL ONE HUNDRED -> 'C' */ + { 0x6E, 0x44 }, /* ROMAN NUMERAL FIVE HUNDRED -> 'D' */ + { 0x6F, 0x4D }, /* ROMAN NUMERAL ONE THOUSAND -> 'M' */ + { 0x70, 0x69 }, /* SMALL ROMAN NUMERAL ONE -> 'i' */ + { 0x74, 0x76 }, /* SMALL ROMAN NUMERAL FIVE -> 'v' */ + { 0x79, 0x78 }, /* SMALL ROMAN NUMERAL TEN -> 'x' */ + { 0x7C, 0x6C }, /* SMALL ROMAN NUMERAL FIFTY -> 'l' */ + { 0x7D, 0x63 }, /* SMALL ROMAN NUMERAL ONE HUNDRED -> 'c' */ + { 0x7E, 0x64 }, /* SMALL ROMAN NUMERAL FIVE HUNDRED -> 'd' */ + { 0x7F, 0x6D }, /* SMALL ROMAN NUMERAL ONE THOUSAND -> 'm' */ + { 0x83, 0x29 }, /* ROMAN NUMERAL REVERSED ONE HUNDRED -> ')' */ + { 0x90, 0x3C }, /* LEFTWARDS ARROW -> '<' */ + { 0x91, 0x5E }, /* UPWARDS ARROW -> '^' */ + { 0x92, 0x3E }, /* RIGHTWARDS ARROW -> '>' */ + { 0x93, 0x76 }, /* DOWNWARDS ARROW -> 'v' */ + { 0x94, 0x2D }, /* LEFT RIGHT ARROW -> '-' */ + { 0x95, 0x7C }, /* UP DOWN ARROW -> '|' */ + { 0x96, 0x5C }, /* NORTH WEST ARROW -> '\' */ + { 0x97, 0x2F }, /* NORTH EAST ARROW -> '/' */ + { 0x98, 0x5C }, /* SOUTH EAST ARROW -> '\' */ + { 0x99, 0x2F }, /* SOUTH WEST ARROW -> '/' */ + { 0x9A, 0x21 }, /* LEFTWARDS ARROW WITH STROKE -> '!' */ + { 0x9B, 0x21 }, /* RIGHTWARDS ARROW WITH STROKE -> '!' */ + { 0x9C, 0x7E }, /* LEFTWARDS WAVE ARROW -> '~' */ + { 0x9D, 0x7E }, /* RIGHTWARDS WAVE ARROW -> '~' */ + { 0x9E, 0x2D }, /* LEFTWARDS TWO HEADED ARROW -> '-' */ + { 0x9F, 0x7C }, /* UPWARDS TWO HEADED ARROW -> '|' */ + { 0xA0, 0x2D }, /* RIGHTWARDS TWO HEADED ARROW -> '-' */ + { 0xA1, 0x7C }, /* DOWNWARDS TWO HEADED ARROW -> '|' */ + { 0xA2, 0x00 }, /* LEFTWARDS ARROW WITH TAIL -> ... */ + { 0xA4, 0x2D }, /* LEFTWARDS ARROW FROM BAR -> '-' */ + { 0xA5, 0x7C }, /* UPWARDS ARROW FROM BAR -> '|' */ + { 0xA6, 0x2D }, /* RIGHTWARDS ARROW FROM BAR -> '-' */ + { 0xA7, 0x7C }, /* DOWNWARDS ARROW FROM BAR -> '|' */ + { 0xA8, 0x7C }, /* UP DOWN ARROW WITH BASE -> '|' */ + { 0xA9, 0x00 }, /* LEFTWARDS ARROW WITH HOOK -> ... */ + { 0xAD, 0x2D }, /* LEFT RIGHT WAVE ARROW -> '-' */ + { 0xAE, 0x21 }, /* LEFT RIGHT ARROW WITH STROKE -> '!' */ + { 0xAF, 0x00 }, /* DOWNWARDS ZIGZAG ARROW -> ... */ + { 0xB5, 0x7C }, /* DOWNWARDS ARROW WITH CORNER LEFTWARDS -> '|' */ + { 0xB6, 0x5E }, /* ANTICLOCKWISE TOP SEMICIRCLE ARROW -> '^' */ + { 0xB7, 0x56 }, /* CLOCKWISE TOP SEMICIRCLE ARROW -> 'V' */ + { 0xB8, 0x5C }, /* NORTH WEST ARROW TO LONG BAR -> '\' */ + { 0xB9, 0x3D }, /* LEFTWARDS ARROW TO BAR OVER RIGHTWARDS ARROW TO BAR -> '=' */ + { 0xBA, 0x56 }, /* ANTICLOCKWISE OPEN CIRCLE ARROW -> 'V' */ + { 0xBB, 0x5E }, /* CLOCKWISE OPEN CIRCLE ARROW -> '^' */ + { 0xBC, 0x2D }, /* LEFTWARDS HARPOON WITH BARB UPWARDS -> '-' */ + { 0xBD, 0x2D }, /* LEFTWARDS HARPOON WITH BARB DOWNWARDS -> '-' */ + { 0xBE, 0x7C }, /* UPWARDS HARPOON WITH BARB RIGHTWARDS -> '|' */ + { 0xBF, 0x7C }, /* UPWARDS HARPOON WITH BARB LEFTWARDS -> '|' */ + { 0xC0, 0x2D }, /* RIGHTWARDS HARPOON WITH BARB UPWARDS -> '-' */ + { 0xC1, 0x2D }, /* RIGHTWARDS HARPOON WITH BARB DOWNWARDS -> '-' */ + { 0xC2, 0x7C }, /* DOWNWARDS HARPOON WITH BARB RIGHTWARDS -> '|' */ + { 0xC3, 0x7C }, /* DOWNWARDS HARPOON WITH BARB LEFTWARDS -> '|' */ + { 0xC4, 0x3D }, /* RIGHTWARDS ARROW OVER LEFTWARDS ARROW -> '=' */ + { 0xC5, 0x7C }, /* UPWARDS ARROW LEFTWARDS OF DOWNWARDS ARROW -> '|' */ + { 0xC6, 0x3D }, /* LEFTWARDS ARROW OVER RIGHTWARDS ARROW -> '=' */ + { 0xC7, 0x3D }, /* LEFTWARDS PAIRED ARROWS -> '=' */ + { 0xC8, 0x7C }, /* UPWARDS PAIRED ARROWS -> '|' */ + { 0xC9, 0x3D }, /* RIGHTWARDS PAIRED ARROWS -> '=' */ + { 0xCA, 0x7C }, /* DOWNWARDS PAIRED ARROWS -> '|' */ + { 0xCB, 0x3D }, /* LEFTWARDS HARPOON OVER RIGHTWARDS HARPOON -> '=' */ + { 0xCC, 0x3D }, /* RIGHTWARDS HARPOON OVER LEFTWARDS HARPOON -> '=' */ + { 0xCD, 0x00 }, /* LEFTWARDS DOUBLE ARROW WITH STROKE -> ... */ + { 0xCF, 0x21 }, /* RIGHTWARDS DOUBLE ARROW WITH STROKE -> '!' */ + { 0xD0, 0x3C }, /* LEFTWARDS DOUBLE ARROW -> '<' */ + { 0xD1, 0x5E }, /* UPWARDS DOUBLE ARROW -> '^' */ + { 0xD2, 0x3E }, /* RIGHTWARDS DOUBLE ARROW -> '>' */ + { 0xD3, 0x76 }, /* DOWNWARDS DOUBLE ARROW -> 'v' */ + { 0xD4, 0x3D }, /* LEFT RIGHT DOUBLE ARROW -> '=' */ + { 0xD5, 0x7C }, /* UP DOWN DOUBLE ARROW -> '|' */ + { 0xD6, 0x5C }, /* NORTH WEST DOUBLE ARROW -> '\' */ + { 0xD7, 0x2F }, /* NORTH EAST DOUBLE ARROW -> '/' */ + { 0xD8, 0x5C }, /* SOUTH EAST DOUBLE ARROW -> '\' */ + { 0xD9, 0x2F }, /* SOUTH WEST DOUBLE ARROW -> '/' */ + { 0xDA, 0x3D }, /* LEFTWARDS TRIPLE ARROW -> '=' */ + { 0xDB, 0x3D }, /* RIGHTWARDS TRIPLE ARROW -> '=' */ + { 0xDC, 0x7E }, /* LEFTWARDS SQUIGGLE ARROW -> '~' */ + { 0xDD, 0x7E }, /* RIGHTWARDS SQUIGGLE ARROW -> '~' */ + { 0xDE, 0x7C }, /* UPWARDS ARROW WITH DOUBLE STROKE -> '|' */ + { 0xDF, 0x7C }, /* DOWNWARDS ARROW WITH DOUBLE STROKE -> '|' */ + { 0xE0, 0x2D }, /* LEFTWARDS DASHED ARROW -> '-' */ + { 0xE1, 0x7C }, /* UPWARDS DASHED ARROW -> '|' */ + { 0xE2, 0x2D }, /* RIGHTWARDS DASHED ARROW -> '-' */ + { 0xE3, 0x7C }, /* DOWNWARDS DASHED ARROW -> '|' */ + { 0xE4, 0x00 }, /* LEFTWARDS ARROW TO BAR -> ... */ + { 0xE6, 0x2D }, /* LEFTWARDS WHITE ARROW -> '-' */ + { 0xE7, 0x7C }, /* UPWARDS WHITE ARROW -> '|' */ + { 0xE8, 0x2D }, /* RIGHTWARDS WHITE ARROW -> '-' */ + { 0xE9, 0x00 }, /* DOWNWARDS WHITE ARROW -> ... */ + { 0xEF, 0x7C }, /* UPWARDS WHITE DOUBLE ARROW ON PEDESTAL -> '|' */ + { 0xF0, 0x2D }, /* RIGHTWARDS WHITE ARROW FROM WALL -> '-' */ + { 0xF1, 0x5C }, /* NORTH WEST ARROW TO CORNER -> '\' */ + { 0xF2, 0x5C }, /* SOUTH EAST ARROW TO CORNER -> '\' */ + { 0xF3, 0x7C }, /* UP DOWN WHITE ARROW -> '|' */ + /* Entries for page 0x22 */ + { 0x04, 0x21 }, /* THERE DOES NOT EXIST -> '!' */ + { 0x09, 0x21 }, /* NOT AN ELEMENT OF -> '!' */ + { 0x0C, 0x21 }, /* DOES NOT CONTAIN AS MEMBER -> '!' */ + { 0x12, 0x2D }, /* MINUS SIGN -> '-' */ + { 0x15, 0x2F }, /* DIVISION SLASH -> '/' */ + { 0x16, 0x5C }, /* SET MINUS -> '\' */ + { 0x17, 0x2A }, /* ASTERISK OPERATOR -> '*' */ + { 0x18, 0x6F }, /* RING OPERATOR -> 'o' */ + { 0x19, 0x2E }, /* BULLET OPERATOR -> '.' */ + { 0x23, 0x7C }, /* DIVIDES -> '|' */ + { 0x24, 0x21 }, /* DOES NOT DIVIDE -> '!' */ + { 0x26, 0x21 }, /* NOT PARALLEL TO -> '!' */ + { 0x36, 0x3A }, /* RATIO -> ':' */ + { 0x3C, 0x7E }, /* TILDE OPERATOR -> '~' */ + { 0x41, 0x23 }, /* NOT TILDE -> '#' */ + { 0x44, 0x23 }, /* NOT ASYMPTOTICALLY EQUAL TO -> '#' */ + { 0x49, 0x23 }, /* NOT ALMOST EQUAL TO -> '#' */ + { 0x60, 0x23 }, /* NOT EQUAL TO -> '#' */ + { 0x62, 0x23 }, /* NOT IDENTICAL TO -> '#' */ + { 0x64, 0x3C }, /* LESS-THAN OR EQUAL TO -> '<' */ + { 0x65, 0x3E }, /* GREATER-THAN OR EQUAL TO -> '>' */ + { 0x68, 0x23 }, /* LESS-THAN BUT NOT EQUAL TO -> '#' */ + { 0x69, 0x23 }, /* GREATER-THAN BUT NOT EQUAL TO -> '#' */ + { 0x6D, 0x23 }, /* NOT EQUIVALENT TO -> '#' */ + { 0x6E, 0x21 }, /* NOT LESS-THAN -> '!' */ + { 0x6F, 0x21 }, /* NOT GREATER-THAN -> '!' */ + { 0x80, 0x21 }, /* DOES NOT PRECEDE -> '!' */ + { 0x81, 0x21 }, /* DOES NOT SUCCEED -> '!' */ + { 0x84, 0x21 }, /* NOT A SUBSET OF -> '!' */ + { 0x85, 0x21 }, /* NOT A SUPERSET OF -> '!' */ + { 0x8A, 0x23 }, /* SUBSET OF WITH NOT EQUAL TO -> '#' */ + { 0x8B, 0x23 }, /* SUPERSET OF WITH NOT EQUAL TO -> '#' */ + { 0x9B, 0x2A }, /* CIRCLED ASTERISK OPERATOR -> '*' */ + { 0xC6, 0x2A }, /* STAR OPERATOR -> '*' */ + /* Entries for page 0x23 */ + { 0x03, 0x5E }, /* UP ARROWHEAD -> '^' */ + { 0x29, 0x3C }, /* LEFT-POINTING ANGLE BRACKET -> '<' */ + { 0x5F, 0x2A }, /* APL FUNCTIONAL SYMBOL CIRCLE STAR -> '*' */ + { 0x63, 0x2A }, /* APL FUNCTIONAL SYMBOL STAR DIAERESIS -> '*' */ + /* Entries for page 0x24 */ + { 0x60, 0x31 }, /* CIRCLED DIGIT ONE -> '1' */ + { 0x61, 0x32 }, /* CIRCLED DIGIT TWO -> '2' */ + { 0x62, 0x33 }, /* CIRCLED DIGIT THREE -> '3' */ + { 0x63, 0x34 }, /* CIRCLED DIGIT FOUR -> '4' */ + { 0x64, 0x35 }, /* CIRCLED DIGIT FIVE -> '5' */ + { 0x65, 0x36 }, /* CIRCLED DIGIT SIX -> '6' */ + { 0x66, 0x37 }, /* CIRCLED DIGIT SEVEN -> '7' */ + { 0x67, 0x38 }, /* CIRCLED DIGIT EIGHT -> '8' */ + { 0x68, 0x39 }, /* CIRCLED DIGIT NINE -> '9' */ + { 0xB6, 0x41 }, /* CIRCLED LATIN CAPITAL LETTER A -> 'A' */ + { 0xB7, 0x42 }, /* CIRCLED LATIN CAPITAL LETTER B -> 'B' */ + { 0xB8, 0x43 }, /* CIRCLED LATIN CAPITAL LETTER C -> 'C' */ + { 0xB9, 0x44 }, /* CIRCLED LATIN CAPITAL LETTER D -> 'D' */ + { 0xBA, 0x45 }, /* CIRCLED LATIN CAPITAL LETTER E -> 'E' */ + { 0xBB, 0x46 }, /* CIRCLED LATIN CAPITAL LETTER F -> 'F' */ + { 0xBC, 0x47 }, /* CIRCLED LATIN CAPITAL LETTER G -> 'G' */ + { 0xBD, 0x48 }, /* CIRCLED LATIN CAPITAL LETTER H -> 'H' */ + { 0xBE, 0x49 }, /* CIRCLED LATIN CAPITAL LETTER I -> 'I' */ + { 0xBF, 0x4A }, /* CIRCLED LATIN CAPITAL LETTER J -> 'J' */ + { 0xC0, 0x4B }, /* CIRCLED LATIN CAPITAL LETTER K -> 'K' */ + { 0xC1, 0x4C }, /* CIRCLED LATIN CAPITAL LETTER L -> 'L' */ + { 0xC2, 0x4D }, /* CIRCLED LATIN CAPITAL LETTER M -> 'M' */ + { 0xC3, 0x4E }, /* CIRCLED LATIN CAPITAL LETTER N -> 'N' */ + { 0xC4, 0x4F }, /* CIRCLED LATIN CAPITAL LETTER O -> 'O' */ + { 0xC5, 0x50 }, /* CIRCLED LATIN CAPITAL LETTER P -> 'P' */ + { 0xC6, 0x51 }, /* CIRCLED LATIN CAPITAL LETTER Q -> 'Q' */ + { 0xC7, 0x52 }, /* CIRCLED LATIN CAPITAL LETTER R -> 'R' */ + { 0xC8, 0x53 }, /* CIRCLED LATIN CAPITAL LETTER S -> 'S' */ + { 0xC9, 0x54 }, /* CIRCLED LATIN CAPITAL LETTER T -> 'T' */ + { 0xCA, 0x55 }, /* CIRCLED LATIN CAPITAL LETTER U -> 'U' */ + { 0xCB, 0x56 }, /* CIRCLED LATIN CAPITAL LETTER V -> 'V' */ + { 0xCC, 0x57 }, /* CIRCLED LATIN CAPITAL LETTER W -> 'W' */ + { 0xCD, 0x58 }, /* CIRCLED LATIN CAPITAL LETTER X -> 'X' */ + { 0xCE, 0x59 }, /* CIRCLED LATIN CAPITAL LETTER Y -> 'Y' */ + { 0xCF, 0x5A }, /* CIRCLED LATIN CAPITAL LETTER Z -> 'Z' */ + { 0xD0, 0x61 }, /* CIRCLED LATIN SMALL LETTER A -> 'a' */ + { 0xD1, 0x62 }, /* CIRCLED LATIN SMALL LETTER B -> 'b' */ + { 0xD2, 0x63 }, /* CIRCLED LATIN SMALL LETTER C -> 'c' */ + { 0xD3, 0x64 }, /* CIRCLED LATIN SMALL LETTER D -> 'd' */ + { 0xD4, 0x65 }, /* CIRCLED LATIN SMALL LETTER E -> 'e' */ + { 0xD5, 0x66 }, /* CIRCLED LATIN SMALL LETTER F -> 'f' */ + { 0xD6, 0x67 }, /* CIRCLED LATIN SMALL LETTER G -> 'g' */ + { 0xD7, 0x68 }, /* CIRCLED LATIN SMALL LETTER H -> 'h' */ + { 0xD8, 0x69 }, /* CIRCLED LATIN SMALL LETTER I -> 'i' */ + { 0xD9, 0x6A }, /* CIRCLED LATIN SMALL LETTER J -> 'j' */ + { 0xDA, 0x6B }, /* CIRCLED LATIN SMALL LETTER K -> 'k' */ + { 0xDB, 0x6C }, /* CIRCLED LATIN SMALL LETTER L -> 'l' */ + { 0xDC, 0x6D }, /* CIRCLED LATIN SMALL LETTER M -> 'm' */ + { 0xDD, 0x6E }, /* CIRCLED LATIN SMALL LETTER N -> 'n' */ + { 0xDE, 0x6F }, /* CIRCLED LATIN SMALL LETTER O -> 'o' */ + { 0xDF, 0x70 }, /* CIRCLED LATIN SMALL LETTER P -> 'p' */ + { 0xE0, 0x71 }, /* CIRCLED LATIN SMALL LETTER Q -> 'q' */ + { 0xE1, 0x72 }, /* CIRCLED LATIN SMALL LETTER R -> 'r' */ + { 0xE2, 0x73 }, /* CIRCLED LATIN SMALL LETTER S -> 's' */ + { 0xE3, 0x74 }, /* CIRCLED LATIN SMALL LETTER T -> 't' */ + { 0xE4, 0x75 }, /* CIRCLED LATIN SMALL LETTER U -> 'u' */ + { 0xE5, 0x76 }, /* CIRCLED LATIN SMALL LETTER V -> 'v' */ + { 0xE6, 0x77 }, /* CIRCLED LATIN SMALL LETTER W -> 'w' */ + { 0xE7, 0x78 }, /* CIRCLED LATIN SMALL LETTER X -> 'x' */ + { 0xE8, 0x79 }, /* CIRCLED LATIN SMALL LETTER Y -> 'y' */ + { 0xE9, 0x7A }, /* CIRCLED LATIN SMALL LETTER Z -> 'z' */ + { 0xEA, 0x30 }, /* CIRCLED DIGIT ZERO -> '0' */ + { 0xF5, 0x31 }, /* DOUBLE CIRCLED DIGIT ONE -> '1' */ + { 0xF6, 0x32 }, /* DOUBLE CIRCLED DIGIT TWO -> '2' */ + { 0xF7, 0x33 }, /* DOUBLE CIRCLED DIGIT THREE -> '3' */ + { 0xF8, 0x34 }, /* DOUBLE CIRCLED DIGIT FOUR -> '4' */ + { 0xF9, 0x35 }, /* DOUBLE CIRCLED DIGIT FIVE -> '5' */ + { 0xFA, 0x36 }, /* DOUBLE CIRCLED DIGIT SIX -> '6' */ + { 0xFB, 0x37 }, /* DOUBLE CIRCLED DIGIT SEVEN -> '7' */ + { 0xFC, 0x38 }, /* DOUBLE CIRCLED DIGIT EIGHT -> '8' */ + { 0xFD, 0x39 }, /* DOUBLE CIRCLED DIGIT NINE -> '9' */ + { 0xFF, 0x30 }, /* NEGATIVE CIRCLED DIGIT ZERO -> '0' */ + /* Entries for page 0x25 */ + { 0x00, 0x2D }, /* BOX DRAWINGS LIGHT HORIZONTAL -> '-' */ + { 0x01, 0x2D }, /* BOX DRAWINGS HEAVY HORIZONTAL -> '-' */ + { 0x02, 0x7C }, /* BOX DRAWINGS LIGHT VERTICAL -> '|' */ + { 0x03, 0x7C }, /* BOX DRAWINGS HEAVY VERTICAL -> '|' */ + { 0x04, 0x2D }, /* BOX DRAWINGS LIGHT TRIPLE DASH HORIZONTAL -> '-' */ + { 0x05, 0x2D }, /* BOX DRAWINGS HEAVY TRIPLE DASH HORIZONTAL -> '-' */ + { 0x06, 0x7C }, /* BOX DRAWINGS LIGHT TRIPLE DASH VERTICAL -> '|' */ + { 0x07, 0x7C }, /* BOX DRAWINGS HEAVY TRIPLE DASH VERTICAL -> '|' */ + { 0x08, 0x2D }, /* BOX DRAWINGS LIGHT QUADRUPLE DASH HORIZONTAL -> '-' */ + { 0x09, 0x2D }, /* BOX DRAWINGS HEAVY QUADRUPLE DASH HORIZONTAL -> '-' */ + { 0x0A, 0x7C }, /* BOX DRAWINGS LIGHT QUADRUPLE DASH VERTICAL -> '|' */ + { 0x0B, 0x7C }, /* BOX DRAWINGS HEAVY QUADRUPLE DASH VERTICAL -> '|' */ + { 0x0C, 0x00 }, /* BOX DRAWINGS LIGHT DOWN AND RIGHT -> ... */ + { 0x4B, 0x2B }, /* BOX DRAWINGS HEAVY VERTICAL AND HORIZONTAL -> '+' */ + { 0x4C, 0x2D }, /* BOX DRAWINGS LIGHT DOUBLE DASH HORIZONTAL -> '-' */ + { 0x4D, 0x2D }, /* BOX DRAWINGS HEAVY DOUBLE DASH HORIZONTAL -> '-' */ + { 0x4E, 0x7C }, /* BOX DRAWINGS LIGHT DOUBLE DASH VERTICAL -> '|' */ + { 0x4F, 0x7C }, /* BOX DRAWINGS HEAVY DOUBLE DASH VERTICAL -> '|' */ + { 0x50, 0x2D }, /* BOX DRAWINGS DOUBLE HORIZONTAL -> '-' */ + { 0x51, 0x7C }, /* BOX DRAWINGS DOUBLE VERTICAL -> '|' */ + { 0x52, 0x00 }, /* BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE -> ... */ + { 0x70, 0x2B }, /* BOX DRAWINGS LIGHT ARC UP AND RIGHT -> '+' */ + { 0x71, 0x2F }, /* BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT -> '/' */ + { 0x72, 0x5C }, /* BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT -> '\' */ + { 0x73, 0x58 }, /* BOX DRAWINGS LIGHT DIAGONAL CROSS -> 'X' */ + { 0x74, 0x2D }, /* BOX DRAWINGS LIGHT LEFT -> '-' */ + { 0x75, 0x7C }, /* BOX DRAWINGS LIGHT UP -> '|' */ + { 0x76, 0x2D }, /* BOX DRAWINGS LIGHT RIGHT -> '-' */ + { 0x77, 0x7C }, /* BOX DRAWINGS LIGHT DOWN -> '|' */ + { 0x78, 0x2D }, /* BOX DRAWINGS HEAVY LEFT -> '-' */ + { 0x79, 0x7C }, /* BOX DRAWINGS HEAVY UP -> '|' */ + { 0x7A, 0x2D }, /* BOX DRAWINGS HEAVY RIGHT -> '-' */ + { 0x7B, 0x7C }, /* BOX DRAWINGS HEAVY DOWN -> '|' */ + { 0x7C, 0x2D }, /* BOX DRAWINGS LIGHT LEFT AND HEAVY RIGHT -> '-' */ + { 0x7D, 0x7C }, /* BOX DRAWINGS LIGHT UP AND HEAVY DOWN -> '|' */ + { 0x7E, 0x2D }, /* BOX DRAWINGS HEAVY LEFT AND LIGHT RIGHT -> '-' */ + { 0x7F, 0x7C }, /* BOX DRAWINGS HEAVY UP AND LIGHT DOWN -> '|' */ + { 0x80, 0x00 }, /* UPPER HALF BLOCK -> ... */ + { 0x93, 0x23 }, /* DARK SHADE -> '#' */ + { 0x94, 0x2D }, /* UPPER ONE EIGHTH BLOCK -> '-' */ + { 0x95, 0x7C }, /* RIGHT ONE EIGHTH BLOCK -> '|' */ + { 0x96, 0x00 }, /* QUADRANT LOWER LEFT -> ... */ + { 0xB1, 0x23 }, /* WHITE PARALLELOGRAM -> '#' */ + { 0xB2, 0x00 }, /* BLACK UP-POINTING TRIANGLE -> ... */ + { 0xB5, 0x5E }, /* WHITE UP-POINTING SMALL TRIANGLE -> '^' */ + { 0xB6, 0x00 }, /* BLACK RIGHT-POINTING TRIANGLE -> ... */ + { 0xBB, 0x3E }, /* WHITE RIGHT-POINTING POINTER -> '>' */ + { 0xBC, 0x00 }, /* BLACK DOWN-POINTING TRIANGLE -> ... */ + { 0xBF, 0x56 }, /* WHITE DOWN-POINTING SMALL TRIANGLE -> 'V' */ + { 0xC0, 0x00 }, /* BLACK LEFT-POINTING TRIANGLE -> ... */ + { 0xC5, 0x3C }, /* WHITE LEFT-POINTING POINTER -> '<' */ + { 0xC6, 0x00 }, /* BLACK DIAMOND -> ... */ + { 0xE6, 0x2A }, /* WHITE BULLET -> '*' */ + { 0xE7, 0x00 }, /* SQUARE WITH LEFT HALF BLACK -> ... */ + { 0xEB, 0x23 }, /* WHITE SQUARE WITH VERTICAL BISECTING LINE -> '#' */ + { 0xEC, 0x00 }, /* WHITE UP-POINTING TRIANGLE WITH DOT -> ... */ + { 0xEE, 0x5E }, /* UP-POINTING TRIANGLE WITH RIGHT HALF BLACK -> '^' */ + { 0xEF, 0x4F }, /* LARGE CIRCLE -> 'O' */ + { 0xF0, 0x00 }, /* WHITE SQUARE WITH UPPER LEFT QUADRANT -> ... */ + { 0xF7, 0x23 }, /* WHITE CIRCLE WITH UPPER RIGHT QUADRANT -> '#' */ + /* Entries for page 0x26 */ + { 0x05, 0x2A }, /* BLACK STAR -> '*' */ + { 0x06, 0x2A }, /* WHITE STAR -> '*' */ + { 0x2A, 0x2A }, /* STAR AND CRESCENT -> '*' */ + { 0x6F, 0x23 }, /* MUSIC SHARP SIGN -> '#' */ + { 0x98, 0x2A }, /* FLOWER -> '*' */ + { 0x9D, 0x2A }, /* OUTLINED WHITE STAR -> '*' */ + /* Entries for page 0x27 */ + { 0x13, 0x76 }, /* CHECK MARK -> 'v' */ + { 0x14, 0x56 }, /* HEAVY CHECK MARK -> 'V' */ + { 0x15, 0x78 }, /* MULTIPLICATION X -> 'x' */ + { 0x16, 0x58 }, /* HEAVY MULTIPLICATION X -> 'X' */ + { 0x17, 0x78 }, /* BALLOT X -> 'x' */ + { 0x18, 0x58 }, /* HEAVY BALLOT X -> 'X' */ + { 0x21, 0x00 }, /* STAR OF DAVID -> ... */ + { 0x46, 0x2A }, /* HEAVY CHEVRON SNOWFLAKE -> '*' */ + { 0x49, 0x00 }, /* BALLOON-SPOKED ASTERISK -> ... */ + { 0x4B, 0x2A }, /* HEAVY EIGHT TEARDROP-SPOKED PROPELLER ASTERISK -> '*' */ + { 0x58, 0x7C }, /* LIGHT VERTICAL BAR -> '|' */ + { 0x5C, 0x27 }, /* HEAVY SINGLE COMMA QUOTATION MARK ORNAMENT -> ''' */ + { 0x5D, 0x22 }, /* HEAVY DOUBLE TURNED COMMA QUOTATION MARK ORNAMENT -> '"' */ + { 0x5E, 0x22 }, /* HEAVY DOUBLE COMMA QUOTATION MARK ORNAMENT -> '"' */ + { 0x5F, 0x2C }, /* HEAVY LOW SINGLE COMMA QUOTATION MARK ORNAMENT -> ',' */ + { 0x62, 0x21 }, /* HEAVY EXCLAMATION MARK ORNAMENT -> '!' */ + { 0xE6, 0x5B }, /* MATHEMATICAL LEFT WHITE SQUARE BRACKET -> '[' */ + { 0xE8, 0x3C }, /* MATHEMATICAL LEFT ANGLE BRACKET -> '<' */ + /* Entries for page 0x28 */ + { 0x00, 0x20 }, /* BRAILLE PATTERN BLANK -> ' ' */ + { 0x01, 0x61 }, /* BRAILLE PATTERN DOTS-1 -> 'a' */ + { 0x02, 0x31 }, /* BRAILLE PATTERN DOTS-2 -> '1' */ + { 0x03, 0x62 }, /* BRAILLE PATTERN DOTS-12 -> 'b' */ + { 0x04, 0x27 }, /* BRAILLE PATTERN DOTS-3 -> ''' */ + { 0x05, 0x6B }, /* BRAILLE PATTERN DOTS-13 -> 'k' */ + { 0x06, 0x32 }, /* BRAILLE PATTERN DOTS-23 -> '2' */ + { 0x07, 0x6C }, /* BRAILLE PATTERN DOTS-123 -> 'l' */ + { 0x08, 0x40 }, /* BRAILLE PATTERN DOTS-4 -> '@' */ + { 0x09, 0x63 }, /* BRAILLE PATTERN DOTS-14 -> 'c' */ + { 0x0A, 0x69 }, /* BRAILLE PATTERN DOTS-24 -> 'i' */ + { 0x0B, 0x66 }, /* BRAILLE PATTERN DOTS-124 -> 'f' */ + { 0x0C, 0x2F }, /* BRAILLE PATTERN DOTS-34 -> '/' */ + { 0x0D, 0x6D }, /* BRAILLE PATTERN DOTS-134 -> 'm' */ + { 0x0E, 0x73 }, /* BRAILLE PATTERN DOTS-234 -> 's' */ + { 0x0F, 0x70 }, /* BRAILLE PATTERN DOTS-1234 -> 'p' */ + { 0x10, 0x22 }, /* BRAILLE PATTERN DOTS-5 -> '"' */ + { 0x11, 0x65 }, /* BRAILLE PATTERN DOTS-15 -> 'e' */ + { 0x12, 0x33 }, /* BRAILLE PATTERN DOTS-25 -> '3' */ + { 0x13, 0x68 }, /* BRAILLE PATTERN DOTS-125 -> 'h' */ + { 0x14, 0x39 }, /* BRAILLE PATTERN DOTS-35 -> '9' */ + { 0x15, 0x6F }, /* BRAILLE PATTERN DOTS-135 -> 'o' */ + { 0x16, 0x36 }, /* BRAILLE PATTERN DOTS-235 -> '6' */ + { 0x17, 0x72 }, /* BRAILLE PATTERN DOTS-1235 -> 'r' */ + { 0x18, 0x5E }, /* BRAILLE PATTERN DOTS-45 -> '^' */ + { 0x19, 0x64 }, /* BRAILLE PATTERN DOTS-145 -> 'd' */ + { 0x1A, 0x6A }, /* BRAILLE PATTERN DOTS-245 -> 'j' */ + { 0x1B, 0x67 }, /* BRAILLE PATTERN DOTS-1245 -> 'g' */ + { 0x1C, 0x3E }, /* BRAILLE PATTERN DOTS-345 -> '>' */ + { 0x1D, 0x6E }, /* BRAILLE PATTERN DOTS-1345 -> 'n' */ + { 0x1E, 0x74 }, /* BRAILLE PATTERN DOTS-2345 -> 't' */ + { 0x1F, 0x71 }, /* BRAILLE PATTERN DOTS-12345 -> 'q' */ + { 0x20, 0x2C }, /* BRAILLE PATTERN DOTS-6 -> ',' */ + { 0x21, 0x2A }, /* BRAILLE PATTERN DOTS-16 -> '*' */ + { 0x22, 0x35 }, /* BRAILLE PATTERN DOTS-26 -> '5' */ + { 0x23, 0x3C }, /* BRAILLE PATTERN DOTS-126 -> '<' */ + { 0x24, 0x2D }, /* BRAILLE PATTERN DOTS-36 -> '-' */ + { 0x25, 0x75 }, /* BRAILLE PATTERN DOTS-136 -> 'u' */ + { 0x26, 0x38 }, /* BRAILLE PATTERN DOTS-236 -> '8' */ + { 0x27, 0x76 }, /* BRAILLE PATTERN DOTS-1236 -> 'v' */ + { 0x28, 0x2E }, /* BRAILLE PATTERN DOTS-46 -> '.' */ + { 0x29, 0x25 }, /* BRAILLE PATTERN DOTS-146 -> '%' */ + { 0x2A, 0x5B }, /* BRAILLE PATTERN DOTS-246 -> '[' */ + { 0x2B, 0x24 }, /* BRAILLE PATTERN DOTS-1246 -> '$' */ + { 0x2C, 0x2B }, /* BRAILLE PATTERN DOTS-346 -> '+' */ + { 0x2D, 0x78 }, /* BRAILLE PATTERN DOTS-1346 -> 'x' */ + { 0x2E, 0x21 }, /* BRAILLE PATTERN DOTS-2346 -> '!' */ + { 0x2F, 0x26 }, /* BRAILLE PATTERN DOTS-12346 -> '&' */ + { 0x30, 0x3B }, /* BRAILLE PATTERN DOTS-56 -> ';' */ + { 0x31, 0x3A }, /* BRAILLE PATTERN DOTS-156 -> ':' */ + { 0x32, 0x34 }, /* BRAILLE PATTERN DOTS-256 -> '4' */ + { 0x33, 0x5C }, /* BRAILLE PATTERN DOTS-1256 -> '\' */ + { 0x34, 0x30 }, /* BRAILLE PATTERN DOTS-356 -> '0' */ + { 0x35, 0x7A }, /* BRAILLE PATTERN DOTS-1356 -> 'z' */ + { 0x36, 0x37 }, /* BRAILLE PATTERN DOTS-2356 -> '7' */ + { 0x37, 0x28 }, /* BRAILLE PATTERN DOTS-12356 -> '(' */ + { 0x38, 0x5F }, /* BRAILLE PATTERN DOTS-456 -> '_' */ + { 0x39, 0x3F }, /* BRAILLE PATTERN DOTS-1456 -> '?' */ + { 0x3A, 0x77 }, /* BRAILLE PATTERN DOTS-2456 -> 'w' */ + { 0x3B, 0x5D }, /* BRAILLE PATTERN DOTS-12456 -> ']' */ + { 0x3C, 0x23 }, /* BRAILLE PATTERN DOTS-3456 -> '#' */ + { 0x3D, 0x79 }, /* BRAILLE PATTERN DOTS-13456 -> 'y' */ + { 0x3E, 0x29 }, /* BRAILLE PATTERN DOTS-23456 -> ')' */ + { 0x3F, 0x3D }, /* BRAILLE PATTERN DOTS-123456 -> '=' */ + /* Entries for page 0x29 */ + { 0x83, 0x7B }, /* LEFT WHITE CURLY BRACKET -> '{' */ + /* Entries for page 0x2C */ + { 0x60, 0x4C }, /* LATIN CAPITAL LETTER L WITH DOUBLE BAR -> 'L' */ + { 0x61, 0x6C }, /* LATIN SMALL LETTER L WITH DOUBLE BAR -> 'l' */ + { 0x62, 0x4C }, /* LATIN CAPITAL LETTER L WITH MIDDLE TILDE -> 'L' */ + { 0x63, 0x50 }, /* LATIN CAPITAL LETTER P WITH STROKE -> 'P' */ + { 0x64, 0x52 }, /* LATIN CAPITAL LETTER R WITH TAIL -> 'R' */ + { 0x65, 0x61 }, /* LATIN SMALL LETTER A WITH STROKE -> 'a' */ + { 0x66, 0x74 }, /* LATIN SMALL LETTER T WITH DIAGONAL STROKE -> 't' */ + { 0x67, 0x48 }, /* LATIN CAPITAL LETTER H WITH DESCENDER -> 'H' */ + { 0x68, 0x68 }, /* LATIN SMALL LETTER H WITH DESCENDER -> 'h' */ + { 0x69, 0x4B }, /* LATIN CAPITAL LETTER K WITH DESCENDER -> 'K' */ + { 0x6A, 0x6B }, /* LATIN SMALL LETTER K WITH DESCENDER -> 'k' */ + { 0x6B, 0x5A }, /* LATIN CAPITAL LETTER Z WITH DESCENDER -> 'Z' */ + { 0x6C, 0x7A }, /* LATIN SMALL LETTER Z WITH DESCENDER -> 'z' */ + { 0x6E, 0x4D }, /* LATIN CAPITAL LETTER M WITH HOOK -> 'M' */ + { 0x6F, 0x41 }, /* LATIN CAPITAL LETTER TURNED A -> 'A' */ + /* Entries for page 0x2E */ + { 0x00, 0x72 }, /* RIGHT ANGLE SUBSTITUTION MARKER -> 'r' */ + { 0x06, 0x54 }, /* RAISED INTERPOLATION MARKER -> 'T' */ + { 0x09, 0x73 }, /* LEFT TRANSPOSITION BRACKET -> 's' */ + { 0x0C, 0x5C }, /* LEFT RAISED OMISSION BRACKET -> '\' */ + { 0x0D, 0x2F }, /* RIGHT RAISED OMISSION BRACKET -> '/' */ + { 0x12, 0x3E }, /* HYPODIASTOLE -> '>' */ + { 0x13, 0x25 }, /* DOTTED OBELOS -> '%' */ + { 0x16, 0x3E }, /* DOTTED RIGHT-POINTING ANGLE -> '>' */ + { 0x17, 0x3D }, /* DOUBLE OBLIQUE HYPHEN -> '=' */ + { 0x19, 0x2F }, /* PALM BRANCH -> '/' */ + { 0x1A, 0x2D }, /* HYPHEN WITH DIAERESIS -> '-' */ + { 0x1B, 0x7E }, /* TILDE WITH RING ABOVE -> '~' */ + { 0x1C, 0x5C }, /* LEFT LOW PARAPHRASE BRACKET -> '\' */ + { 0x1D, 0x2F }, /* RIGHT LOW PARAPHRASE BRACKET -> '/' */ + { 0x1E, 0x7E }, /* TILDE WITH DOT ABOVE -> '~' */ + { 0x1F, 0x7E }, /* TILDE WITH DOT BELOW -> '~' */ + { 0x2E, 0x3F }, /* REVERSED QUESTION MARK -> '?' */ + { 0x2F, 0x27 }, /* VERTICAL TILDE -> ''' */ + { 0x30, 0x6F }, /* RING POINT -> 'o' */ + { 0x31, 0x2E }, /* WORD SEPARATOR MIDDLE DOT -> '.' */ + { 0x32, 0x2C }, /* TURNED COMMA -> ',' */ + { 0x33, 0x2E }, /* RAISED DOT -> '.' */ + { 0x34, 0x2C }, /* RAISED COMMA -> ',' */ + { 0x35, 0x3B }, /* TURNED SEMICOLON -> ';' */ + { 0x3C, 0x78 }, /* STENOGRAPHIC FULL STOP -> 'x' */ + { 0x3D, 0x7C }, /* VERTICAL SIX DOTS -> '|' */ + { 0x40, 0x3D }, /* DOUBLE HYPHEN -> '=' */ + { 0x41, 0x2C }, /* REVERSED COMMA -> ',' */ + { 0x42, 0x22 }, /* DOUBLE LOW-REVERSED-9 QUOTATION MARK -> '"' */ + /* Entries for page 0x30 */ + { 0x00, 0x20 }, /* IDEOGRAPHIC SPACE -> ' ' */ + { 0x03, 0x22 }, /* DITTO MARK -> '"' */ + { 0x05, 0x22 }, /* IDEOGRAPHIC ITERATION MARK -> '"' */ + { 0x06, 0x2F }, /* IDEOGRAPHIC CLOSING MARK -> '/' */ + { 0x07, 0x30 }, /* IDEOGRAPHIC NUMBER ZERO -> '0' */ + { 0x08, 0x3C }, /* LEFT ANGLE BRACKET -> '<' */ + { 0x0C, 0x5B }, /* LEFT CORNER BRACKET -> '[' */ + { 0x0E, 0x7B }, /* LEFT WHITE CORNER BRACKET -> '{' */ + { 0x12, 0x40 }, /* POSTAL MARK -> '@' */ + { 0x14, 0x5B }, /* LEFT TORTOISE SHELL BRACKET -> '[' */ + { 0x20, 0x40 }, /* POSTAL MARK FACE -> '@' */ + { 0x21, 0x31 }, /* HANGZHOU NUMERAL ONE -> '1' */ + { 0x22, 0x32 }, /* HANGZHOU NUMERAL TWO -> '2' */ + { 0x23, 0x33 }, /* HANGZHOU NUMERAL THREE -> '3' */ + { 0x24, 0x34 }, /* HANGZHOU NUMERAL FOUR -> '4' */ + { 0x25, 0x35 }, /* HANGZHOU NUMERAL FIVE -> '5' */ + { 0x26, 0x36 }, /* HANGZHOU NUMERAL SIX -> '6' */ + { 0x27, 0x37 }, /* HANGZHOU NUMERAL SEVEN -> '7' */ + { 0x28, 0x38 }, /* HANGZHOU NUMERAL EIGHT -> '8' */ + { 0x29, 0x39 }, /* HANGZHOU NUMERAL NINE -> '9' */ + { 0x30, 0x7E }, /* WAVY DASH -> '~' */ + { 0x31, 0x00 }, /* VERTICAL KANA REPEAT MARK -> ... */ + { 0x34, 0x2B }, /* VERTICAL KANA REPEAT WITH VOICED SOUND MARK UPPER HALF -> '+' */ + { 0x36, 0x40 }, /* CIRCLED POSTAL MARK -> '@' */ + { 0x41, 0x61 }, /* HIRAGANA LETTER SMALL A -> 'a' */ + { 0x42, 0x61 }, /* HIRAGANA LETTER A -> 'a' */ + { 0x43, 0x69 }, /* HIRAGANA LETTER SMALL I -> 'i' */ + { 0x44, 0x69 }, /* HIRAGANA LETTER I -> 'i' */ + { 0x45, 0x75 }, /* HIRAGANA LETTER SMALL U -> 'u' */ + { 0x46, 0x75 }, /* HIRAGANA LETTER U -> 'u' */ + { 0x47, 0x65 }, /* HIRAGANA LETTER SMALL E -> 'e' */ + { 0x48, 0x65 }, /* HIRAGANA LETTER E -> 'e' */ + { 0x49, 0x6F }, /* HIRAGANA LETTER SMALL O -> 'o' */ + { 0x4A, 0x6F }, /* HIRAGANA LETTER O -> 'o' */ + { 0x93, 0x6E }, /* HIRAGANA LETTER N -> 'n' */ + { 0x9D, 0x22 }, /* HIRAGANA ITERATION MARK -> '"' */ + { 0x9E, 0x22 }, /* HIRAGANA VOICED ITERATION MARK -> '"' */ + { 0xA0, 0x3D }, /* KATAKANA-HIRAGANA DOUBLE HYPHEN -> '=' */ + { 0xA1, 0x61 }, /* KATAKANA LETTER SMALL A -> 'a' */ + { 0xA2, 0x61 }, /* KATAKANA LETTER A -> 'a' */ + { 0xA3, 0x69 }, /* KATAKANA LETTER SMALL I -> 'i' */ + { 0xA4, 0x69 }, /* KATAKANA LETTER I -> 'i' */ + { 0xA5, 0x75 }, /* KATAKANA LETTER SMALL U -> 'u' */ + { 0xA6, 0x75 }, /* KATAKANA LETTER U -> 'u' */ + { 0xA7, 0x65 }, /* KATAKANA LETTER SMALL E -> 'e' */ + { 0xA8, 0x65 }, /* KATAKANA LETTER E -> 'e' */ + { 0xA9, 0x6F }, /* KATAKANA LETTER SMALL O -> 'o' */ + { 0xAA, 0x6F }, /* KATAKANA LETTER O -> 'o' */ + { 0xF3, 0x6E }, /* KATAKANA LETTER N -> 'n' */ + { 0xFB, 0x2A }, /* KATAKANA MIDDLE DOT -> '*' */ + { 0xFC, 0x2D }, /* KATAKANA-HIRAGANA PROLONGED SOUND MARK -> '-' */ + { 0xFD, 0x22 }, /* KATAKANA ITERATION MARK -> '"' */ + { 0xFE, 0x22 }, /* KATAKANA VOICED ITERATION MARK -> '"' */ + /* Entries for page 0x31 */ + { 0x05, 0x42 }, /* BOPOMOFO LETTER B -> 'B' */ + { 0x06, 0x50 }, /* BOPOMOFO LETTER P -> 'P' */ + { 0x07, 0x4D }, /* BOPOMOFO LETTER M -> 'M' */ + { 0x08, 0x46 }, /* BOPOMOFO LETTER F -> 'F' */ + { 0x09, 0x44 }, /* BOPOMOFO LETTER D -> 'D' */ + { 0x0A, 0x54 }, /* BOPOMOFO LETTER T -> 'T' */ + { 0x0B, 0x4E }, /* BOPOMOFO LETTER N -> 'N' */ + { 0x0C, 0x4C }, /* BOPOMOFO LETTER L -> 'L' */ + { 0x0D, 0x47 }, /* BOPOMOFO LETTER G -> 'G' */ + { 0x0E, 0x4B }, /* BOPOMOFO LETTER K -> 'K' */ + { 0x0F, 0x48 }, /* BOPOMOFO LETTER H -> 'H' */ + { 0x10, 0x4A }, /* BOPOMOFO LETTER J -> 'J' */ + { 0x11, 0x51 }, /* BOPOMOFO LETTER Q -> 'Q' */ + { 0x12, 0x58 }, /* BOPOMOFO LETTER X -> 'X' */ + { 0x16, 0x52 }, /* BOPOMOFO LETTER R -> 'R' */ + { 0x17, 0x5A }, /* BOPOMOFO LETTER Z -> 'Z' */ + { 0x18, 0x43 }, /* BOPOMOFO LETTER C -> 'C' */ + { 0x19, 0x53 }, /* BOPOMOFO LETTER S -> 'S' */ + { 0x1A, 0x41 }, /* BOPOMOFO LETTER A -> 'A' */ + { 0x1B, 0x4F }, /* BOPOMOFO LETTER O -> 'O' */ + { 0x1C, 0x45 }, /* BOPOMOFO LETTER E -> 'E' */ + { 0x27, 0x49 }, /* BOPOMOFO LETTER I -> 'I' */ + { 0x28, 0x55 }, /* BOPOMOFO LETTER U -> 'U' */ + { 0x2A, 0x56 }, /* BOPOMOFO LETTER V -> 'V' */ + { 0x31, 0x67 }, /* HANGUL LETTER KIYEOK -> 'g' */ + { 0x34, 0x6E }, /* HANGUL LETTER NIEUN -> 'n' */ + { 0x37, 0x64 }, /* HANGUL LETTER TIKEUT -> 'd' */ + { 0x39, 0x72 }, /* HANGUL LETTER RIEUL -> 'r' */ + { 0x41, 0x6D }, /* HANGUL LETTER MIEUM -> 'm' */ + { 0x42, 0x62 }, /* HANGUL LETTER PIEUP -> 'b' */ + { 0x45, 0x73 }, /* HANGUL LETTER SIOS -> 's' */ + { 0x48, 0x6A }, /* HANGUL LETTER CIEUC -> 'j' */ + { 0x4A, 0x63 }, /* HANGUL LETTER CHIEUCH -> 'c' */ + { 0x4B, 0x6B }, /* HANGUL LETTER KHIEUKH -> 'k' */ + { 0x4C, 0x74 }, /* HANGUL LETTER THIEUTH -> 't' */ + { 0x4D, 0x70 }, /* HANGUL LETTER PHIEUPH -> 'p' */ + { 0x4E, 0x68 }, /* HANGUL LETTER HIEUH -> 'h' */ + { 0x4F, 0x61 }, /* HANGUL LETTER A -> 'a' */ + { 0x54, 0x65 }, /* HANGUL LETTER E -> 'e' */ + { 0x57, 0x6F }, /* HANGUL LETTER O -> 'o' */ + { 0x5C, 0x75 }, /* HANGUL LETTER U -> 'u' */ + { 0x63, 0x69 }, /* HANGUL LETTER I -> 'i' */ + { 0x7F, 0x5A }, /* HANGUL LETTER PANSIOS -> 'Z' */ + { 0x81, 0x4E }, /* HANGUL LETTER YESIEUNG -> 'N' */ + { 0x86, 0x51 }, /* HANGUL LETTER YEORINHIEUH -> 'Q' */ + { 0x8D, 0x55 }, /* HANGUL LETTER ARAEA -> 'U' */ + { 0xB4, 0x50 }, /* BOPOMOFO FINAL LETTER P -> 'P' */ + { 0xB5, 0x54 }, /* BOPOMOFO FINAL LETTER T -> 'T' */ + { 0xB6, 0x4B }, /* BOPOMOFO FINAL LETTER K -> 'K' */ + { 0xB7, 0x48 }, /* BOPOMOFO FINAL LETTER H -> 'H' */ + /* Entries for page 0x32 */ + { 0xD0, 0x61 }, /* CIRCLED KATAKANA A -> 'a' */ + { 0xD1, 0x69 }, /* CIRCLED KATAKANA I -> 'i' */ + { 0xD2, 0x75 }, /* CIRCLED KATAKANA U -> 'u' */ + { 0xD3, 0x75 }, /* CIRCLED KATAKANA E -> 'u' */ + { 0xD4, 0x6F }, /* CIRCLED KATAKANA O -> 'o' */ + /* Entries for page 0xA0 */ + { 0x02, 0x69 }, /* YI SYLLABLE I -> 'i' */ + { 0x0A, 0x61 }, /* YI SYLLABLE A -> 'a' */ + { 0x11, 0x6F }, /* YI SYLLABLE O -> 'o' */ + { 0x14, 0x65 }, /* YI SYLLABLE E -> 'e' */ + /* Entries for page 0xC5 */ + { 0x44, 0x61 }, /* HANGUL SYLLABLE A -> 'a' */ + { 0xD0, 0x65 }, /* HANGUL SYLLABLE E -> 'e' */ + /* Entries for page 0xC6 */ + { 0x24, 0x6F }, /* HANGUL SYLLABLE O -> 'o' */ + { 0xB0, 0x75 }, /* HANGUL SYLLABLE U -> 'u' */ + /* Entries for page 0xC7 */ + { 0x74, 0x69 }, /* HANGUL SYLLABLE I -> 'i' */ + /* Entries for page 0xFB */ + { 0x1D, 0x69 }, /* HEBREW LETTER YOD WITH HIRIQ -> 'i' */ + { 0x20, 0x60 }, /* HEBREW LETTER ALTERNATIVE AYIN -> '`' */ + { 0x21, 0x41 }, /* HEBREW LETTER WIDE ALEF -> 'A' */ + { 0x22, 0x64 }, /* HEBREW LETTER WIDE DALET -> 'd' */ + { 0x23, 0x68 }, /* HEBREW LETTER WIDE HE -> 'h' */ + { 0x25, 0x6C }, /* HEBREW LETTER WIDE LAMED -> 'l' */ + { 0x26, 0x6D }, /* HEBREW LETTER WIDE FINAL MEM -> 'm' */ + { 0x27, 0x72 }, /* HEBREW LETTER WIDE RESH -> 'r' */ + { 0x28, 0x74 }, /* HEBREW LETTER WIDE TAV -> 't' */ + { 0x29, 0x2B }, /* HEBREW LETTER ALTERNATIVE PLUS SIGN -> '+' */ + { 0x2B, 0x53 }, /* HEBREW LETTER SHIN WITH SIN DOT -> 'S' */ + { 0x2D, 0x53 }, /* HEBREW LETTER SHIN WITH DAGESH AND SIN DOT -> 'S' */ + { 0x2E, 0x61 }, /* HEBREW LETTER ALEF WITH PATAH -> 'a' */ + { 0x2F, 0x61 }, /* HEBREW LETTER ALEF WITH QAMATS -> 'a' */ + { 0x30, 0x41 }, /* HEBREW LETTER ALEF WITH MAPIQ -> 'A' */ + { 0x31, 0x62 }, /* HEBREW LETTER BET WITH DAGESH -> 'b' */ + { 0x32, 0x67 }, /* HEBREW LETTER GIMEL WITH DAGESH -> 'g' */ + { 0x33, 0x64 }, /* HEBREW LETTER DALET WITH DAGESH -> 'd' */ + { 0x34, 0x68 }, /* HEBREW LETTER HE WITH MAPIQ -> 'h' */ + { 0x35, 0x76 }, /* HEBREW LETTER VAV WITH DAGESH -> 'v' */ + { 0x36, 0x7A }, /* HEBREW LETTER ZAYIN WITH DAGESH -> 'z' */ + { 0x38, 0x74 }, /* HEBREW LETTER TET WITH DAGESH -> 't' */ + { 0x39, 0x79 }, /* HEBREW LETTER YOD WITH DAGESH -> 'y' */ + { 0x3C, 0x6C }, /* HEBREW LETTER LAMED WITH DAGESH -> 'l' */ + { 0x3E, 0x6D }, /* HEBREW LETTER MEM WITH DAGESH -> 'm' */ + { 0x40, 0x6E }, /* HEBREW LETTER NUN WITH DAGESH -> 'n' */ + { 0x41, 0x73 }, /* HEBREW LETTER SAMEKH WITH DAGESH -> 's' */ + { 0x43, 0x70 }, /* HEBREW LETTER FINAL PE WITH DAGESH -> 'p' */ + { 0x44, 0x70 }, /* HEBREW LETTER PE WITH DAGESH -> 'p' */ + { 0x47, 0x6B }, /* HEBREW LETTER QOF WITH DAGESH -> 'k' */ + { 0x48, 0x72 }, /* HEBREW LETTER RESH WITH DAGESH -> 'r' */ + { 0x4A, 0x74 }, /* HEBREW LETTER TAV WITH DAGESH -> 't' */ + { 0x4B, 0x6F }, /* HEBREW LETTER VAV WITH HOLAM -> 'o' */ + { 0x4C, 0x76 }, /* HEBREW LETTER BET WITH RAFE -> 'v' */ + { 0x4E, 0x66 }, /* HEBREW LETTER PE WITH RAFE -> 'f' */ + /* Entries for page 0xFE */ + { 0x23, 0x7E }, /* COMBINING DOUBLE TILDE RIGHT HALF -> '~' */ + { 0x32, 0x2D }, /* PRESENTATION FORM FOR VERTICAL EN DASH -> '-' */ + { 0x33, 0x5F }, /* PRESENTATION FORM FOR VERTICAL LOW LINE -> '_' */ + { 0x34, 0x5F }, /* PRESENTATION FORM FOR VERTICAL WAVY LOW LINE -> '_' */ + { 0x35, 0x28 }, /* PRESENTATION FORM FOR VERTICAL LEFT PARENTHESIS -> '(' */ + { 0x37, 0x7B }, /* PRESENTATION FORM FOR VERTICAL LEFT CURLY BRACKET -> '{' */ + { 0x39, 0x5B }, /* PRESENTATION FORM FOR VERTICAL LEFT TORTOISE SHELL BRACKET -> '[' */ + { 0x3F, 0x3C }, /* PRESENTATION FORM FOR VERTICAL LEFT ANGLE BRACKET -> '<' */ + { 0x41, 0x5B }, /* PRESENTATION FORM FOR VERTICAL LEFT CORNER BRACKET -> '[' */ + { 0x43, 0x7B }, /* PRESENTATION FORM FOR VERTICAL LEFT WHITE CORNER BRACKET -> '{' */ + { 0x44, 0x7D }, /* PRESENTATION FORM FOR VERTICAL RIGHT WHITE CORNER BRACKET -> '}' */ + { 0x50, 0x2C }, /* SMALL COMMA -> ',' */ + { 0x51, 0x2C }, /* SMALL IDEOGRAPHIC COMMA -> ',' */ + { 0x52, 0x2E }, /* SMALL FULL STOP -> '.' */ + { 0x54, 0x3B }, /* SMALL SEMICOLON -> ';' */ + { 0x55, 0x3A }, /* SMALL COLON -> ':' */ + { 0x56, 0x3F }, /* SMALL QUESTION MARK -> '?' */ + { 0x57, 0x21 }, /* SMALL EXCLAMATION MARK -> '!' */ + { 0x58, 0x2D }, /* SMALL EM DASH -> '-' */ + { 0x59, 0x28 }, /* SMALL LEFT PARENTHESIS -> '(' */ + { 0x5A, 0x29 }, /* SMALL RIGHT PARENTHESIS -> ')' */ + { 0x5B, 0x7B }, /* SMALL LEFT CURLY BRACKET -> '{' */ + { 0x5C, 0x7D }, /* SMALL RIGHT CURLY BRACKET -> '}' */ + { 0x5D, 0x7B }, /* SMALL LEFT TORTOISE SHELL BRACKET -> '{' */ + { 0x5E, 0x7D }, /* SMALL RIGHT TORTOISE SHELL BRACKET -> '}' */ + { 0x5F, 0x23 }, /* SMALL NUMBER SIGN -> '#' */ + { 0x60, 0x26 }, /* SMALL AMPERSAND -> '&' */ + { 0x61, 0x2A }, /* SMALL ASTERISK -> '*' */ + { 0x62, 0x2B }, /* SMALL PLUS SIGN -> '+' */ + { 0x63, 0x2D }, /* SMALL HYPHEN-MINUS -> '-' */ + { 0x64, 0x3C }, /* SMALL LESS-THAN SIGN -> '<' */ + { 0x65, 0x3E }, /* SMALL GREATER-THAN SIGN -> '>' */ + { 0x66, 0x3D }, /* SMALL EQUALS SIGN -> '=' */ + { 0x68, 0x5C }, /* SMALL REVERSE SOLIDUS -> '\' */ + { 0x69, 0x24 }, /* SMALL DOLLAR SIGN -> '$' */ + { 0x6A, 0x25 }, /* SMALL PERCENT SIGN -> '%' */ + { 0x6B, 0x40 }, /* SMALL COMMERCIAL AT -> '@' */ + /* Entries for page 0xFF */ + { 0x61, 0x2E }, /* HALFWIDTH IDEOGRAPHIC FULL STOP -> '.' */ + { 0x62, 0x5B }, /* HALFWIDTH LEFT CORNER BRACKET -> '[' */ + { 0x63, 0x5D }, /* HALFWIDTH RIGHT CORNER BRACKET -> ']' */ + { 0x64, 0x2C }, /* HALFWIDTH IDEOGRAPHIC COMMA -> ',' */ + { 0x65, 0x2A }, /* HALFWIDTH KATAKANA MIDDLE DOT -> '*' */ + { 0x67, 0x61 }, /* HALFWIDTH KATAKANA LETTER SMALL A -> 'a' */ + { 0x68, 0x69 }, /* HALFWIDTH KATAKANA LETTER SMALL I -> 'i' */ + { 0x69, 0x75 }, /* HALFWIDTH KATAKANA LETTER SMALL U -> 'u' */ + { 0x6A, 0x65 }, /* HALFWIDTH KATAKANA LETTER SMALL E -> 'e' */ + { 0x6B, 0x6F }, /* HALFWIDTH KATAKANA LETTER SMALL O -> 'o' */ + { 0x70, 0x2B }, /* HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND MARK -> '+' */ + { 0x71, 0x61 }, /* HALFWIDTH KATAKANA LETTER A -> 'a' */ + { 0x72, 0x69 }, /* HALFWIDTH KATAKANA LETTER I -> 'i' */ + { 0x73, 0x75 }, /* HALFWIDTH KATAKANA LETTER U -> 'u' */ + { 0x74, 0x65 }, /* HALFWIDTH KATAKANA LETTER E -> 'e' */ + { 0x75, 0x6F }, /* HALFWIDTH KATAKANA LETTER O -> 'o' */ + { 0x9D, 0x6E }, /* HALFWIDTH KATAKANA LETTER N -> 'n' */ + { 0x9E, 0x3A }, /* HALFWIDTH KATAKANA VOICED SOUND MARK -> ':' */ + { 0x9F, 0x3B }, /* HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK -> ';' */ + { 0xA1, 0x67 }, /* HALFWIDTH HANGUL LETTER KIYEOK -> 'g' */ + { 0xA4, 0x6E }, /* HALFWIDTH HANGUL LETTER NIEUN -> 'n' */ + { 0xA7, 0x64 }, /* HALFWIDTH HANGUL LETTER TIKEUT -> 'd' */ + { 0xA9, 0x72 }, /* HALFWIDTH HANGUL LETTER RIEUL -> 'r' */ + { 0xB1, 0x6D }, /* HALFWIDTH HANGUL LETTER MIEUM -> 'm' */ + { 0xB2, 0x62 }, /* HALFWIDTH HANGUL LETTER PIEUP -> 'b' */ + { 0xB5, 0x73 }, /* HALFWIDTH HANGUL LETTER SIOS -> 's' */ + { 0xB8, 0x6A }, /* HALFWIDTH HANGUL LETTER CIEUC -> 'j' */ + { 0xBA, 0x63 }, /* HALFWIDTH HANGUL LETTER CHIEUCH -> 'c' */ + { 0xBB, 0x6B }, /* HALFWIDTH HANGUL LETTER KHIEUKH -> 'k' */ + { 0xBC, 0x74 }, /* HALFWIDTH HANGUL LETTER THIEUTH -> 't' */ + { 0xBD, 0x70 }, /* HALFWIDTH HANGUL LETTER PHIEUPH -> 'p' */ + { 0xBE, 0x68 }, /* HALFWIDTH HANGUL LETTER HIEUH -> 'h' */ + { 0xC2, 0x61 }, /* HALFWIDTH HANGUL LETTER A -> 'a' */ + { 0xC7, 0x65 }, /* HALFWIDTH HANGUL LETTER E -> 'e' */ + { 0xCC, 0x6F }, /* HALFWIDTH HANGUL LETTER O -> 'o' */ + { 0xD3, 0x75 }, /* HALFWIDTH HANGUL LETTER U -> 'u' */ + { 0xDC, 0x69 }, /* HALFWIDTH HANGUL LETTER I -> 'i' */ + { 0xE2, 0x21 }, /* FULLWIDTH NOT SIGN -> '!' */ + { 0xE3, 0x2D }, /* FULLWIDTH MACRON -> '-' */ + { 0xE4, 0x7C }, /* FULLWIDTH BROKEN BAR -> '|' */ + { 0xE8, 0x7C }, /* HALFWIDTH FORMS LIGHT VERTICAL -> '|' */ + { 0xE9, 0x3C }, /* HALFWIDTH LEFTWARDS ARROW -> '<' */ + { 0xEA, 0x5E }, /* HALFWIDTH UPWARDS ARROW -> '^' */ + { 0xEB, 0x3E }, /* HALFWIDTH RIGHTWARDS ARROW -> '>' */ + { 0xEC, 0x76 }, /* HALFWIDTH DOWNWARDS ARROW -> 'v' */ + { 0xED, 0x23 }, /* HALFWIDTH BLACK SQUARE -> '#' */ + { 0xEE, 0x4F }, /* HALFWIDTH WHITE CIRCLE -> 'O' */ + { 0xF9, 0x7B }, /* INTERLINEAR ANNOTATION ANCHOR -> '{' */ + { 0xFA, 0x7C }, /* INTERLINEAR ANNOTATION SEPARATOR -> '|' */ + { 0xFB, 0x7D }, /* INTERLINEAR ANNOTATION TERMINATOR -> '}' */ +}; + +#define UCS_PAGE_ENTRY_RANGE_MARKER 0 diff --git a/drivers/tty/vt/ucs_recompose_table.h_shipped b/drivers/tty/vt/ucs_recompose_table.h_shipped new file mode 100644 index 000000000000..bd91edde5d19 --- /dev/null +++ b/drivers/tty/vt/ucs_recompose_table.h_shipped @@ -0,0 +1,102 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * ucs_recompose_table.h - Unicode character recomposition + * + * Auto-generated by gen_ucs_recompose_table.py + * + * Unicode Version: 16.0.0 + * + * This file contains a table with most commonly used Latin, Greek, and + * Cyrillic recomposition pairs only (71 entries). To generate a table with + * all possible recomposition pairs from the Unicode BMP (1000 entries) + * instead, run: + * + * python gen_ucs_recompose_table.py --full + */ + +/* + * Table of most commonly used Latin, Greek, and Cyrillic recomposition pairs only + * Sorted by base character and then combining mark for binary search + */ +static const struct ucs_recomposition ucs_recomposition_table[] = { + { 0x0041, 0x0300, 0x00C0 }, /* LATIN CAPITAL LETTER A + COMBINING GRAVE ACCENT = LATIN CAPITAL LETTER A WITH GRAVE */ + { 0x0041, 0x0301, 0x00C1 }, /* LATIN CAPITAL LETTER A + COMBINING ACUTE ACCENT = LATIN CAPITAL LETTER A WITH ACUTE */ + { 0x0041, 0x0302, 0x00C2 }, /* LATIN CAPITAL LETTER A + COMBINING CIRCUMFLEX ACCENT = LATIN CAPITAL LETTER A WITH CIRCUMFLEX */ + { 0x0041, 0x0303, 0x00C3 }, /* LATIN CAPITAL LETTER A + COMBINING TILDE = LATIN CAPITAL LETTER A WITH TILDE */ + { 0x0041, 0x0308, 0x00C4 }, /* LATIN CAPITAL LETTER A + COMBINING DIAERESIS = LATIN CAPITAL LETTER A WITH DIAERESIS */ + { 0x0041, 0x030A, 0x00C5 }, /* LATIN CAPITAL LETTER A + COMBINING RING ABOVE = LATIN CAPITAL LETTER A WITH RING ABOVE */ + { 0x0043, 0x0327, 0x00C7 }, /* LATIN CAPITAL LETTER C + COMBINING CEDILLA = LATIN CAPITAL LETTER C WITH CEDILLA */ + { 0x0045, 0x0300, 0x00C8 }, /* LATIN CAPITAL LETTER E + COMBINING GRAVE ACCENT = LATIN CAPITAL LETTER E WITH GRAVE */ + { 0x0045, 0x0301, 0x00C9 }, /* LATIN CAPITAL LETTER E + COMBINING ACUTE ACCENT = LATIN CAPITAL LETTER E WITH ACUTE */ + { 0x0045, 0x0302, 0x00CA }, /* LATIN CAPITAL LETTER E + COMBINING CIRCUMFLEX ACCENT = LATIN CAPITAL LETTER E WITH CIRCUMFLEX */ + { 0x0045, 0x0308, 0x00CB }, /* LATIN CAPITAL LETTER E + COMBINING DIAERESIS = LATIN CAPITAL LETTER E WITH DIAERESIS */ + { 0x0049, 0x0300, 0x00CC }, /* LATIN CAPITAL LETTER I + COMBINING GRAVE ACCENT = LATIN CAPITAL LETTER I WITH GRAVE */ + { 0x0049, 0x0301, 0x00CD }, /* LATIN CAPITAL LETTER I + COMBINING ACUTE ACCENT = LATIN CAPITAL LETTER I WITH ACUTE */ + { 0x0049, 0x0302, 0x00CE }, /* LATIN CAPITAL LETTER I + COMBINING CIRCUMFLEX ACCENT = LATIN CAPITAL LETTER I WITH CIRCUMFLEX */ + { 0x0049, 0x0308, 0x00CF }, /* LATIN CAPITAL LETTER I + COMBINING DIAERESIS = LATIN CAPITAL LETTER I WITH DIAERESIS */ + { 0x004E, 0x0303, 0x00D1 }, /* LATIN CAPITAL LETTER N + COMBINING TILDE = LATIN CAPITAL LETTER N WITH TILDE */ + { 0x004F, 0x0300, 0x00D2 }, /* LATIN CAPITAL LETTER O + COMBINING GRAVE ACCENT = LATIN CAPITAL LETTER O WITH GRAVE */ + { 0x004F, 0x0301, 0x00D3 }, /* LATIN CAPITAL LETTER O + COMBINING ACUTE ACCENT = LATIN CAPITAL LETTER O WITH ACUTE */ + { 0x004F, 0x0302, 0x00D4 }, /* LATIN CAPITAL LETTER O + COMBINING CIRCUMFLEX ACCENT = LATIN CAPITAL LETTER O WITH CIRCUMFLEX */ + { 0x004F, 0x0303, 0x00D5 }, /* LATIN CAPITAL LETTER O + COMBINING TILDE = LATIN CAPITAL LETTER O WITH TILDE */ + { 0x004F, 0x0308, 0x00D6 }, /* LATIN CAPITAL LETTER O + COMBINING DIAERESIS = LATIN CAPITAL LETTER O WITH DIAERESIS */ + { 0x0055, 0x0300, 0x00D9 }, /* LATIN CAPITAL LETTER U + COMBINING GRAVE ACCENT = LATIN CAPITAL LETTER U WITH GRAVE */ + { 0x0055, 0x0301, 0x00DA }, /* LATIN CAPITAL LETTER U + COMBINING ACUTE ACCENT = LATIN CAPITAL LETTER U WITH ACUTE */ + { 0x0055, 0x0302, 0x00DB }, /* LATIN CAPITAL LETTER U + COMBINING CIRCUMFLEX ACCENT = LATIN CAPITAL LETTER U WITH CIRCUMFLEX */ + { 0x0055, 0x0308, 0x00DC }, /* LATIN CAPITAL LETTER U + COMBINING DIAERESIS = LATIN CAPITAL LETTER U WITH DIAERESIS */ + { 0x0059, 0x0301, 0x00DD }, /* LATIN CAPITAL LETTER Y + COMBINING ACUTE ACCENT = LATIN CAPITAL LETTER Y WITH ACUTE */ + { 0x0061, 0x0300, 0x00E0 }, /* LATIN SMALL LETTER A + COMBINING GRAVE ACCENT = LATIN SMALL LETTER A WITH GRAVE */ + { 0x0061, 0x0301, 0x00E1 }, /* LATIN SMALL LETTER A + COMBINING ACUTE ACCENT = LATIN SMALL LETTER A WITH ACUTE */ + { 0x0061, 0x0302, 0x00E2 }, /* LATIN SMALL LETTER A + COMBINING CIRCUMFLEX ACCENT = LATIN SMALL LETTER A WITH CIRCUMFLEX */ + { 0x0061, 0x0303, 0x00E3 }, /* LATIN SMALL LETTER A + COMBINING TILDE = LATIN SMALL LETTER A WITH TILDE */ + { 0x0061, 0x0308, 0x00E4 }, /* LATIN SMALL LETTER A + COMBINING DIAERESIS = LATIN SMALL LETTER A WITH DIAERESIS */ + { 0x0061, 0x030A, 0x00E5 }, /* LATIN SMALL LETTER A + COMBINING RING ABOVE = LATIN SMALL LETTER A WITH RING ABOVE */ + { 0x0063, 0x0327, 0x00E7 }, /* LATIN SMALL LETTER C + COMBINING CEDILLA = LATIN SMALL LETTER C WITH CEDILLA */ + { 0x0065, 0x0300, 0x00E8 }, /* LATIN SMALL LETTER E + COMBINING GRAVE ACCENT = LATIN SMALL LETTER E WITH GRAVE */ + { 0x0065, 0x0301, 0x00E9 }, /* LATIN SMALL LETTER E + COMBINING ACUTE ACCENT = LATIN SMALL LETTER E WITH ACUTE */ + { 0x0065, 0x0302, 0x00EA }, /* LATIN SMALL LETTER E + COMBINING CIRCUMFLEX ACCENT = LATIN SMALL LETTER E WITH CIRCUMFLEX */ + { 0x0065, 0x0308, 0x00EB }, /* LATIN SMALL LETTER E + COMBINING DIAERESIS = LATIN SMALL LETTER E WITH DIAERESIS */ + { 0x0069, 0x0300, 0x00EC }, /* LATIN SMALL LETTER I + COMBINING GRAVE ACCENT = LATIN SMALL LETTER I WITH GRAVE */ + { 0x0069, 0x0301, 0x00ED }, /* LATIN SMALL LETTER I + COMBINING ACUTE ACCENT = LATIN SMALL LETTER I WITH ACUTE */ + { 0x0069, 0x0302, 0x00EE }, /* LATIN SMALL LETTER I + COMBINING CIRCUMFLEX ACCENT = LATIN SMALL LETTER I WITH CIRCUMFLEX */ + { 0x0069, 0x0308, 0x00EF }, /* LATIN SMALL LETTER I + COMBINING DIAERESIS = LATIN SMALL LETTER I WITH DIAERESIS */ + { 0x006E, 0x0303, 0x00F1 }, /* LATIN SMALL LETTER N + COMBINING TILDE = LATIN SMALL LETTER N WITH TILDE */ + { 0x006F, 0x0300, 0x00F2 }, /* LATIN SMALL LETTER O + COMBINING GRAVE ACCENT = LATIN SMALL LETTER O WITH GRAVE */ + { 0x006F, 0x0301, 0x00F3 }, /* LATIN SMALL LETTER O + COMBINING ACUTE ACCENT = LATIN SMALL LETTER O WITH ACUTE */ + { 0x006F, 0x0302, 0x00F4 }, /* LATIN SMALL LETTER O + COMBINING CIRCUMFLEX ACCENT = LATIN SMALL LETTER O WITH CIRCUMFLEX */ + { 0x006F, 0x0303, 0x00F5 }, /* LATIN SMALL LETTER O + COMBINING TILDE = LATIN SMALL LETTER O WITH TILDE */ + { 0x006F, 0x0308, 0x00F6 }, /* LATIN SMALL LETTER O + COMBINING DIAERESIS = LATIN SMALL LETTER O WITH DIAERESIS */ + { 0x0075, 0x0300, 0x00F9 }, /* LATIN SMALL LETTER U + COMBINING GRAVE ACCENT = LATIN SMALL LETTER U WITH GRAVE */ + { 0x0075, 0x0301, 0x00FA }, /* LATIN SMALL LETTER U + COMBINING ACUTE ACCENT = LATIN SMALL LETTER U WITH ACUTE */ + { 0x0075, 0x0302, 0x00FB }, /* LATIN SMALL LETTER U + COMBINING CIRCUMFLEX ACCENT = LATIN SMALL LETTER U WITH CIRCUMFLEX */ + { 0x0075, 0x0308, 0x00FC }, /* LATIN SMALL LETTER U + COMBINING DIAERESIS = LATIN SMALL LETTER U WITH DIAERESIS */ + { 0x0079, 0x0301, 0x00FD }, /* LATIN SMALL LETTER Y + COMBINING ACUTE ACCENT = LATIN SMALL LETTER Y WITH ACUTE */ + { 0x0079, 0x0308, 0x00FF }, /* LATIN SMALL LETTER Y + COMBINING DIAERESIS = LATIN SMALL LETTER Y WITH DIAERESIS */ + { 0x0391, 0x0301, 0x0386 }, /* GREEK CAPITAL LETTER ALPHA + COMBINING ACUTE ACCENT = GREEK CAPITAL LETTER ALPHA WITH TONOS */ + { 0x0395, 0x0301, 0x0388 }, /* GREEK CAPITAL LETTER EPSILON + COMBINING ACUTE ACCENT = GREEK CAPITAL LETTER EPSILON WITH TONOS */ + { 0x0397, 0x0301, 0x0389 }, /* GREEK CAPITAL LETTER ETA + COMBINING ACUTE ACCENT = GREEK CAPITAL LETTER ETA WITH TONOS */ + { 0x0399, 0x0301, 0x038A }, /* GREEK CAPITAL LETTER IOTA + COMBINING ACUTE ACCENT = GREEK CAPITAL LETTER IOTA WITH TONOS */ + { 0x039F, 0x0301, 0x038C }, /* GREEK CAPITAL LETTER OMICRON + COMBINING ACUTE ACCENT = GREEK CAPITAL LETTER OMICRON WITH TONOS */ + { 0x03A5, 0x0301, 0x038E }, /* GREEK CAPITAL LETTER UPSILON + COMBINING ACUTE ACCENT = GREEK CAPITAL LETTER UPSILON WITH TONOS */ + { 0x03A9, 0x0301, 0x038F }, /* GREEK CAPITAL LETTER OMEGA + COMBINING ACUTE ACCENT = GREEK CAPITAL LETTER OMEGA WITH TONOS */ + { 0x03B1, 0x0301, 0x03AC }, /* GREEK SMALL LETTER ALPHA + COMBINING ACUTE ACCENT = GREEK SMALL LETTER ALPHA WITH TONOS */ + { 0x03B5, 0x0301, 0x03AD }, /* GREEK SMALL LETTER EPSILON + COMBINING ACUTE ACCENT = GREEK SMALL LETTER EPSILON WITH TONOS */ + { 0x03B7, 0x0301, 0x03AE }, /* GREEK SMALL LETTER ETA + COMBINING ACUTE ACCENT = GREEK SMALL LETTER ETA WITH TONOS */ + { 0x03B9, 0x0301, 0x03AF }, /* GREEK SMALL LETTER IOTA + COMBINING ACUTE ACCENT = GREEK SMALL LETTER IOTA WITH TONOS */ + { 0x03BF, 0x0301, 0x03CC }, /* GREEK SMALL LETTER OMICRON + COMBINING ACUTE ACCENT = GREEK SMALL LETTER OMICRON WITH TONOS */ + { 0x03C5, 0x0301, 0x03CD }, /* GREEK SMALL LETTER UPSILON + COMBINING ACUTE ACCENT = GREEK SMALL LETTER UPSILON WITH TONOS */ + { 0x03C9, 0x0301, 0x03CE }, /* GREEK SMALL LETTER OMEGA + COMBINING ACUTE ACCENT = GREEK SMALL LETTER OMEGA WITH TONOS */ + { 0x0418, 0x0306, 0x0419 }, /* CYRILLIC CAPITAL LETTER I + COMBINING BREVE = CYRILLIC CAPITAL LETTER SHORT I */ + { 0x0423, 0x0306, 0x040E }, /* CYRILLIC CAPITAL LETTER U + COMBINING BREVE = CYRILLIC CAPITAL LETTER SHORT U */ + { 0x0438, 0x0306, 0x0439 }, /* CYRILLIC SMALL LETTER I + COMBINING BREVE = CYRILLIC SMALL LETTER SHORT I */ + { 0x0443, 0x0306, 0x045E }, /* CYRILLIC SMALL LETTER U + COMBINING BREVE = CYRILLIC SMALL LETTER SHORT U */ +}; + +/* + * Boundary values for quick rejection + * These are calculated by analyzing the table during generation + */ +#define UCS_RECOMPOSE_MIN_BASE 0x0041 +#define UCS_RECOMPOSE_MAX_BASE 0x0443 +#define UCS_RECOMPOSE_MIN_MARK 0x0300 +#define UCS_RECOMPOSE_MAX_MARK 0x0327 diff --git a/drivers/tty/vt/ucs_width_table.h_shipped b/drivers/tty/vt/ucs_width_table.h_shipped new file mode 100644 index 000000000000..6fcb8f1d577d --- /dev/null +++ b/drivers/tty/vt/ucs_width_table.h_shipped @@ -0,0 +1,453 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * ucs_width_table.h - Unicode character width + * + * Auto-generated by gen_ucs_width_table.py + * + * Unicode Version: 16.0.0 + */ + +/* Zero-width character ranges (BMP - Basic Multilingual Plane, U+0000 to U+FFFF) */ +static const struct ucs_interval16 ucs_zero_width_bmp_ranges[] = { + { 0x00AD, 0x00AD }, /* SOFT HYPHEN */ + { 0x0300, 0x036F }, /* COMBINING GRAVE ACCENT - COMBINING LATIN SMALL LETTER X */ + { 0x0483, 0x0489 }, /* COMBINING CYRILLIC TITLO - COMBINING CYRILLIC MILLIONS SIGN */ + { 0x0591, 0x05BD }, /* HEBREW ACCENT ETNAHTA - HEBREW POINT METEG */ + { 0x05BF, 0x05BF }, /* HEBREW POINT RAFE */ + { 0x05C1, 0x05C2 }, /* HEBREW POINT SHIN DOT - HEBREW POINT SIN DOT */ + { 0x05C4, 0x05C5 }, /* HEBREW MARK UPPER DOT - HEBREW MARK LOWER DOT */ + { 0x05C7, 0x05C7 }, /* HEBREW POINT QAMATS QATAN */ + { 0x0600, 0x0605 }, /* ARABIC NUMBER SIGN - ARABIC NUMBER MARK ABOVE */ + { 0x0610, 0x061A }, /* ARABIC SIGN SALLALLAHOU ALAYHE WASSALLAM - ARABIC SMALL KASRA */ + { 0x061C, 0x061C }, /* ARABIC LETTER MARK */ + { 0x064B, 0x065F }, /* ARABIC FATHATAN - ARABIC WAVY HAMZA BELOW */ + { 0x0670, 0x0670 }, /* ARABIC LETTER SUPERSCRIPT ALEF */ + { 0x06D6, 0x06DD }, /* ARABIC SMALL HIGH LIGATURE SAD WITH LAM WITH ALEF MAKSURA - ARABIC END OF AYAH */ + { 0x06DF, 0x06E4 }, /* ARABIC SMALL HIGH ROUNDED ZERO - ARABIC SMALL HIGH MADDA */ + { 0x06E7, 0x06E8 }, /* ARABIC SMALL HIGH YEH - ARABIC SMALL HIGH NOON */ + { 0x06EA, 0x06ED }, /* ARABIC EMPTY CENTRE LOW STOP - ARABIC SMALL LOW MEEM */ + { 0x070F, 0x070F }, /* SYRIAC ABBREVIATION MARK */ + { 0x0711, 0x0711 }, /* SYRIAC LETTER SUPERSCRIPT ALAPH */ + { 0x0730, 0x074A }, /* SYRIAC PTHAHA ABOVE - SYRIAC BARREKH */ + { 0x07A6, 0x07B0 }, /* THAANA ABAFILI - THAANA SUKUN */ + { 0x07EB, 0x07F3 }, /* NKO COMBINING SHORT HIGH TONE - NKO COMBINING DOUBLE DOT ABOVE */ + { 0x07FD, 0x07FD }, /* NKO DANTAYALAN */ + { 0x0816, 0x0819 }, /* SAMARITAN MARK IN - SAMARITAN MARK DAGESH */ + { 0x081B, 0x0823 }, /* SAMARITAN MARK EPENTHETIC YUT - SAMARITAN VOWEL SIGN A */ + { 0x0825, 0x0827 }, /* SAMARITAN VOWEL SIGN SHORT A - SAMARITAN VOWEL SIGN U */ + { 0x0829, 0x082D }, /* SAMARITAN VOWEL SIGN LONG I - SAMARITAN MARK NEQUDAA */ + { 0x0859, 0x085B }, /* MANDAIC AFFRICATION MARK - MANDAIC GEMINATION MARK */ + { 0x0890, 0x0891 }, /* ARABIC POUND MARK ABOVE - ARABIC PIASTRE MARK ABOVE */ + { 0x0897, 0x089F }, /* ARABIC PEPET - ARABIC HALF MADDA OVER MADDA */ + { 0x08CA, 0x0903 }, /* ARABIC SMALL HIGH FARSI YEH - DEVANAGARI SIGN VISARGA */ + { 0x093A, 0x093C }, /* DEVANAGARI VOWEL SIGN OE - DEVANAGARI SIGN NUKTA */ + { 0x093E, 0x094F }, /* DEVANAGARI VOWEL SIGN AA - DEVANAGARI VOWEL SIGN AW */ + { 0x0951, 0x0957 }, /* DEVANAGARI STRESS SIGN UDATTA - DEVANAGARI VOWEL SIGN UUE */ + { 0x0962, 0x0963 }, /* DEVANAGARI VOWEL SIGN VOCALIC L - DEVANAGARI VOWEL SIGN VOCALIC LL */ + { 0x0981, 0x0983 }, /* BENGALI SIGN CANDRABINDU - BENGALI SIGN VISARGA */ + { 0x09BC, 0x09BC }, /* BENGALI SIGN NUKTA */ + { 0x09BE, 0x09C4 }, /* BENGALI VOWEL SIGN AA - BENGALI VOWEL SIGN VOCALIC RR */ + { 0x09C7, 0x09C8 }, /* BENGALI VOWEL SIGN E - BENGALI VOWEL SIGN AI */ + { 0x09CB, 0x09CD }, /* BENGALI VOWEL SIGN O - BENGALI SIGN VIRAMA */ + { 0x09D7, 0x09D7 }, /* BENGALI AU LENGTH MARK */ + { 0x09E2, 0x09E3 }, /* BENGALI VOWEL SIGN VOCALIC L - BENGALI VOWEL SIGN VOCALIC LL */ + { 0x09FE, 0x09FE }, /* BENGALI SANDHI MARK */ + { 0x0A01, 0x0A03 }, /* GURMUKHI SIGN ADAK BINDI - GURMUKHI SIGN VISARGA */ + { 0x0A3C, 0x0A3C }, /* GURMUKHI SIGN NUKTA */ + { 0x0A3E, 0x0A42 }, /* GURMUKHI VOWEL SIGN AA - GURMUKHI VOWEL SIGN UU */ + { 0x0A47, 0x0A48 }, /* GURMUKHI VOWEL SIGN EE - GURMUKHI VOWEL SIGN AI */ + { 0x0A4B, 0x0A4D }, /* GURMUKHI VOWEL SIGN OO - GURMUKHI SIGN VIRAMA */ + { 0x0A51, 0x0A51 }, /* GURMUKHI SIGN UDAAT */ + { 0x0A70, 0x0A71 }, /* GURMUKHI TIPPI - GURMUKHI ADDAK */ + { 0x0A75, 0x0A75 }, /* GURMUKHI SIGN YAKASH */ + { 0x0A81, 0x0A83 }, /* GUJARATI SIGN CANDRABINDU - GUJARATI SIGN VISARGA */ + { 0x0ABC, 0x0ABC }, /* GUJARATI SIGN NUKTA */ + { 0x0ABE, 0x0AC5 }, /* GUJARATI VOWEL SIGN AA - GUJARATI VOWEL SIGN CANDRA E */ + { 0x0AC7, 0x0AC9 }, /* GUJARATI VOWEL SIGN E - GUJARATI VOWEL SIGN CANDRA O */ + { 0x0ACB, 0x0ACD }, /* GUJARATI VOWEL SIGN O - GUJARATI SIGN VIRAMA */ + { 0x0AE2, 0x0AE3 }, /* GUJARATI VOWEL SIGN VOCALIC L - GUJARATI VOWEL SIGN VOCALIC LL */ + { 0x0AFA, 0x0AFF }, /* GUJARATI SIGN SUKUN - GUJARATI SIGN TWO-CIRCLE NUKTA ABOVE */ + { 0x0B01, 0x0B03 }, /* ORIYA SIGN CANDRABINDU - ORIYA SIGN VISARGA */ + { 0x0B3C, 0x0B3C }, /* ORIYA SIGN NUKTA */ + { 0x0B3E, 0x0B44 }, /* ORIYA VOWEL SIGN AA - ORIYA VOWEL SIGN VOCALIC RR */ + { 0x0B47, 0x0B48 }, /* ORIYA VOWEL SIGN E - ORIYA VOWEL SIGN AI */ + { 0x0B4B, 0x0B4D }, /* ORIYA VOWEL SIGN O - ORIYA SIGN VIRAMA */ + { 0x0B55, 0x0B57 }, /* ORIYA SIGN OVERLINE - ORIYA AU LENGTH MARK */ + { 0x0B62, 0x0B63 }, /* ORIYA VOWEL SIGN VOCALIC L - ORIYA VOWEL SIGN VOCALIC LL */ + { 0x0B82, 0x0B82 }, /* TAMIL SIGN ANUSVARA */ + { 0x0BBE, 0x0BC2 }, /* TAMIL VOWEL SIGN AA - TAMIL VOWEL SIGN UU */ + { 0x0BC6, 0x0BC8 }, /* TAMIL VOWEL SIGN E - TAMIL VOWEL SIGN AI */ + { 0x0BCA, 0x0BCD }, /* TAMIL VOWEL SIGN O - TAMIL SIGN VIRAMA */ + { 0x0BD7, 0x0BD7 }, /* TAMIL AU LENGTH MARK */ + { 0x0C00, 0x0C04 }, /* TELUGU SIGN COMBINING CANDRABINDU ABOVE - TELUGU SIGN COMBINING ANUSVARA ABOVE */ + { 0x0C3C, 0x0C3C }, /* TELUGU SIGN NUKTA */ + { 0x0C3E, 0x0C44 }, /* TELUGU VOWEL SIGN AA - TELUGU VOWEL SIGN VOCALIC RR */ + { 0x0C46, 0x0C48 }, /* TELUGU VOWEL SIGN E - TELUGU VOWEL SIGN AI */ + { 0x0C4A, 0x0C4D }, /* TELUGU VOWEL SIGN O - TELUGU SIGN VIRAMA */ + { 0x0C55, 0x0C56 }, /* TELUGU LENGTH MARK - TELUGU AI LENGTH MARK */ + { 0x0C62, 0x0C63 }, /* TELUGU VOWEL SIGN VOCALIC L - TELUGU VOWEL SIGN VOCALIC LL */ + { 0x0C81, 0x0C83 }, /* KANNADA SIGN CANDRABINDU - KANNADA SIGN VISARGA */ + { 0x0CBC, 0x0CBC }, /* KANNADA SIGN NUKTA */ + { 0x0CBE, 0x0CC4 }, /* KANNADA VOWEL SIGN AA - KANNADA VOWEL SIGN VOCALIC RR */ + { 0x0CC6, 0x0CC8 }, /* KANNADA VOWEL SIGN E - KANNADA VOWEL SIGN AI */ + { 0x0CCA, 0x0CCD }, /* KANNADA VOWEL SIGN O - KANNADA SIGN VIRAMA */ + { 0x0CD5, 0x0CD6 }, /* KANNADA LENGTH MARK - KANNADA AI LENGTH MARK */ + { 0x0CE2, 0x0CE3 }, /* KANNADA VOWEL SIGN VOCALIC L - KANNADA VOWEL SIGN VOCALIC LL */ + { 0x0CF3, 0x0CF3 }, /* KANNADA SIGN COMBINING ANUSVARA ABOVE RIGHT */ + { 0x0D00, 0x0D03 }, /* MALAYALAM SIGN COMBINING ANUSVARA ABOVE - MALAYALAM SIGN VISARGA */ + { 0x0D3B, 0x0D3C }, /* MALAYALAM SIGN VERTICAL BAR VIRAMA - MALAYALAM SIGN CIRCULAR VIRAMA */ + { 0x0D3E, 0x0D44 }, /* MALAYALAM VOWEL SIGN AA - MALAYALAM VOWEL SIGN VOCALIC RR */ + { 0x0D46, 0x0D48 }, /* MALAYALAM VOWEL SIGN E - MALAYALAM VOWEL SIGN AI */ + { 0x0D4A, 0x0D4D }, /* MALAYALAM VOWEL SIGN O - MALAYALAM SIGN VIRAMA */ + { 0x0D57, 0x0D57 }, /* MALAYALAM AU LENGTH MARK */ + { 0x0D62, 0x0D63 }, /* MALAYALAM VOWEL SIGN VOCALIC L - MALAYALAM VOWEL SIGN VOCALIC LL */ + { 0x0D81, 0x0D83 }, /* SINHALA SIGN CANDRABINDU - SINHALA SIGN VISARGAYA */ + { 0x0DCA, 0x0DCA }, /* SINHALA SIGN AL-LAKUNA */ + { 0x0DCF, 0x0DD4 }, /* SINHALA VOWEL SIGN AELA-PILLA - SINHALA VOWEL SIGN KETTI PAA-PILLA */ + { 0x0DD6, 0x0DD6 }, /* SINHALA VOWEL SIGN DIGA PAA-PILLA */ + { 0x0DD8, 0x0DDF }, /* SINHALA VOWEL SIGN GAETTA-PILLA - SINHALA VOWEL SIGN GAYANUKITTA */ + { 0x0DF2, 0x0DF3 }, /* SINHALA VOWEL SIGN DIGA GAETTA-PILLA - SINHALA VOWEL SIGN DIGA GAYANUKITTA */ + { 0x0E31, 0x0E31 }, /* THAI CHARACTER MAI HAN-AKAT */ + { 0x0E34, 0x0E3A }, /* THAI CHARACTER SARA I - THAI CHARACTER PHINTHU */ + { 0x0E47, 0x0E4E }, /* THAI CHARACTER MAITAIKHU - THAI CHARACTER YAMAKKAN */ + { 0x0EB1, 0x0EB1 }, /* LAO VOWEL SIGN MAI KAN */ + { 0x0EB4, 0x0EBC }, /* LAO VOWEL SIGN I - LAO SEMIVOWEL SIGN LO */ + { 0x0EC8, 0x0ECE }, /* LAO TONE MAI EK - LAO YAMAKKAN */ + { 0x0F18, 0x0F19 }, /* TIBETAN ASTROLOGICAL SIGN -KHYUD PA - TIBETAN ASTROLOGICAL SIGN SDONG TSHUGS */ + { 0x0F35, 0x0F35 }, /* TIBETAN MARK NGAS BZUNG NYI ZLA */ + { 0x0F37, 0x0F37 }, /* TIBETAN MARK NGAS BZUNG SGOR RTAGS */ + { 0x0F39, 0x0F39 }, /* TIBETAN MARK TSA -PHRU */ + { 0x0F3E, 0x0F3F }, /* TIBETAN SIGN YAR TSHES - TIBETAN SIGN MAR TSHES */ + { 0x0F71, 0x0F84 }, /* TIBETAN VOWEL SIGN AA - TIBETAN MARK HALANTA */ + { 0x0F86, 0x0F87 }, /* TIBETAN SIGN LCI RTAGS - TIBETAN SIGN YANG RTAGS */ + { 0x0F8D, 0x0F97 }, /* TIBETAN SUBJOINED SIGN LCE TSA CAN - TIBETAN SUBJOINED LETTER JA */ + { 0x0F99, 0x0FBC }, /* TIBETAN SUBJOINED LETTER NYA - TIBETAN SUBJOINED LETTER FIXED-FORM RA */ + { 0x0FC6, 0x0FC6 }, /* TIBETAN SYMBOL PADMA GDAN */ + { 0x102B, 0x103E }, /* MYANMAR VOWEL SIGN TALL AA - MYANMAR CONSONANT SIGN MEDIAL HA */ + { 0x1056, 0x1059 }, /* MYANMAR VOWEL SIGN VOCALIC R - MYANMAR VOWEL SIGN VOCALIC LL */ + { 0x105E, 0x1060 }, /* MYANMAR CONSONANT SIGN MON MEDIAL NA - MYANMAR CONSONANT SIGN MON MEDIAL LA */ + { 0x1062, 0x1064 }, /* MYANMAR VOWEL SIGN SGAW KAREN EU - MYANMAR TONE MARK SGAW KAREN KE PHO */ + { 0x1067, 0x106D }, /* MYANMAR VOWEL SIGN WESTERN PWO KAREN EU - MYANMAR SIGN WESTERN PWO KAREN TONE-5 */ + { 0x1071, 0x1074 }, /* MYANMAR VOWEL SIGN GEBA KAREN I - MYANMAR VOWEL SIGN KAYAH EE */ + { 0x1082, 0x108D }, /* MYANMAR CONSONANT SIGN SHAN MEDIAL WA - MYANMAR SIGN SHAN COUNCIL EMPHATIC TONE */ + { 0x108F, 0x108F }, /* MYANMAR SIGN RUMAI PALAUNG TONE-5 */ + { 0x109A, 0x109D }, /* MYANMAR SIGN KHAMTI TONE-1 - MYANMAR VOWEL SIGN AITON AI */ + { 0x135D, 0x135F }, /* ETHIOPIC COMBINING GEMINATION AND VOWEL LENGTH MARK - ETHIOPIC COMBINING GEMINATION MARK */ + { 0x1712, 0x1715 }, /* TAGALOG VOWEL SIGN I - TAGALOG SIGN PAMUDPOD */ + { 0x1732, 0x1734 }, /* HANUNOO VOWEL SIGN I - HANUNOO SIGN PAMUDPOD */ + { 0x1752, 0x1753 }, /* BUHID VOWEL SIGN I - BUHID VOWEL SIGN U */ + { 0x1772, 0x1773 }, /* TAGBANWA VOWEL SIGN I - TAGBANWA VOWEL SIGN U */ + { 0x17B4, 0x17D3 }, /* KHMER VOWEL INHERENT AQ - KHMER SIGN BATHAMASAT */ + { 0x17DD, 0x17DD }, /* KHMER SIGN ATTHACAN */ + { 0x180B, 0x180F }, /* MONGOLIAN FREE VARIATION SELECTOR ONE - MONGOLIAN FREE VARIATION SELECTOR FOUR */ + { 0x1885, 0x1886 }, /* MONGOLIAN LETTER ALI GALI BALUDA - MONGOLIAN LETTER ALI GALI THREE BALUDA */ + { 0x18A9, 0x18A9 }, /* MONGOLIAN LETTER ALI GALI DAGALGA */ + { 0x1920, 0x192B }, /* LIMBU VOWEL SIGN A - LIMBU SUBJOINED LETTER WA */ + { 0x1930, 0x193B }, /* LIMBU SMALL LETTER KA - LIMBU SIGN SA-I */ + { 0x1A17, 0x1A1B }, /* BUGINESE VOWEL SIGN I - BUGINESE VOWEL SIGN AE */ + { 0x1A55, 0x1A5E }, /* TAI THAM CONSONANT SIGN MEDIAL RA - TAI THAM CONSONANT SIGN SA */ + { 0x1A60, 0x1A7C }, /* TAI THAM SIGN SAKOT - TAI THAM SIGN KHUEN-LUE KARAN */ + { 0x1A7F, 0x1A7F }, /* TAI THAM COMBINING CRYPTOGRAMMIC DOT */ + { 0x1AB0, 0x1ACE }, /* COMBINING DOUBLED CIRCUMFLEX ACCENT - COMBINING LATIN SMALL LETTER INSULAR T */ + { 0x1B00, 0x1B04 }, /* BALINESE SIGN ULU RICEM - BALINESE SIGN BISAH */ + { 0x1B34, 0x1B44 }, /* BALINESE SIGN REREKAN - BALINESE ADEG ADEG */ + { 0x1B6B, 0x1B73 }, /* BALINESE MUSICAL SYMBOL COMBINING TEGEH - BALINESE MUSICAL SYMBOL COMBINING GONG */ + { 0x1B80, 0x1B82 }, /* SUNDANESE SIGN PANYECEK - SUNDANESE SIGN PANGWISAD */ + { 0x1BA1, 0x1BAD }, /* SUNDANESE CONSONANT SIGN PAMINGKAL - SUNDANESE CONSONANT SIGN PASANGAN WA */ + { 0x1BE6, 0x1BF3 }, /* BATAK SIGN TOMPI - BATAK PANONGONAN */ + { 0x1C24, 0x1C37 }, /* LEPCHA SUBJOINED LETTER YA - LEPCHA SIGN NUKTA */ + { 0x1CD0, 0x1CD2 }, /* VEDIC TONE KARSHANA - VEDIC TONE PRENKHA */ + { 0x1CD4, 0x1CE8 }, /* VEDIC SIGN YAJURVEDIC MIDLINE SVARITA - VEDIC SIGN VISARGA ANUDATTA WITH TAIL */ + { 0x1CED, 0x1CED }, /* VEDIC SIGN TIRYAK */ + { 0x1CF4, 0x1CF4 }, /* VEDIC TONE CANDRA ABOVE */ + { 0x1CF7, 0x1CF9 }, /* VEDIC SIGN ATIKRAMA - VEDIC TONE DOUBLE RING ABOVE */ + { 0x1DC0, 0x1DFF }, /* COMBINING DOTTED GRAVE ACCENT - COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW */ + { 0x200B, 0x200F }, /* ZERO WIDTH SPACE - RIGHT-TO-LEFT MARK */ + { 0x202A, 0x202E }, /* LEFT-TO-RIGHT EMBEDDING - RIGHT-TO-LEFT OVERRIDE */ + { 0x2060, 0x2064 }, /* WORD JOINER - INVISIBLE PLUS */ + { 0x2066, 0x206F }, /* LEFT-TO-RIGHT ISOLATE - NOMINAL DIGIT SHAPES */ + { 0x20D0, 0x20F0 }, /* COMBINING LEFT HARPOON ABOVE - COMBINING ASTERISK ABOVE */ + { 0x2640, 0x2640 }, /* FEMALE SIGN */ + { 0x2642, 0x2642 }, /* MALE SIGN */ + { 0x26A7, 0x26A7 }, /* MALE WITH STROKE AND MALE AND FEMALE SIGN */ + { 0x2CEF, 0x2CF1 }, /* COPTIC COMBINING NI ABOVE - COPTIC COMBINING SPIRITUS LENIS */ + { 0x2D7F, 0x2D7F }, /* TIFINAGH CONSONANT JOINER */ + { 0x2DE0, 0x2DFF }, /* COMBINING CYRILLIC LETTER BE - COMBINING CYRILLIC LETTER IOTIFIED BIG YUS */ + { 0x302A, 0x302F }, /* IDEOGRAPHIC LEVEL TONE MARK - HANGUL DOUBLE DOT TONE MARK */ + { 0x3099, 0x309A }, /* COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK - COMBINING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK */ + { 0xA66F, 0xA672 }, /* COMBINING CYRILLIC VZMET - COMBINING CYRILLIC THOUSAND MILLIONS SIGN */ + { 0xA674, 0xA67D }, /* COMBINING CYRILLIC LETTER UKRAINIAN IE - COMBINING CYRILLIC PAYEROK */ + { 0xA69E, 0xA69F }, /* COMBINING CYRILLIC LETTER EF - COMBINING CYRILLIC LETTER IOTIFIED E */ + { 0xA6F0, 0xA6F1 }, /* BAMUM COMBINING MARK KOQNDON - BAMUM COMBINING MARK TUKWENTIS */ + { 0xA802, 0xA802 }, /* SYLOTI NAGRI SIGN DVISVARA */ + { 0xA806, 0xA806 }, /* SYLOTI NAGRI SIGN HASANTA */ + { 0xA80B, 0xA80B }, /* SYLOTI NAGRI SIGN ANUSVARA */ + { 0xA823, 0xA827 }, /* SYLOTI NAGRI VOWEL SIGN A - SYLOTI NAGRI VOWEL SIGN OO */ + { 0xA82C, 0xA82C }, /* SYLOTI NAGRI SIGN ALTERNATE HASANTA */ + { 0xA880, 0xA881 }, /* SAURASHTRA SIGN ANUSVARA - SAURASHTRA SIGN VISARGA */ + { 0xA8B4, 0xA8C5 }, /* SAURASHTRA CONSONANT SIGN HAARU - SAURASHTRA SIGN CANDRABINDU */ + { 0xA8E0, 0xA8F1 }, /* COMBINING DEVANAGARI DIGIT ZERO - COMBINING DEVANAGARI SIGN AVAGRAHA */ + { 0xA8FF, 0xA8FF }, /* DEVANAGARI VOWEL SIGN AY */ + { 0xA926, 0xA92D }, /* KAYAH LI VOWEL UE - KAYAH LI TONE CALYA PLOPHU */ + { 0xA947, 0xA953 }, /* REJANG VOWEL SIGN I - REJANG VIRAMA */ + { 0xA980, 0xA983 }, /* JAVANESE SIGN PANYANGGA - JAVANESE SIGN WIGNYAN */ + { 0xA9B3, 0xA9C0 }, /* JAVANESE SIGN CECAK TELU - JAVANESE PANGKON */ + { 0xA9E5, 0xA9E5 }, /* MYANMAR SIGN SHAN SAW */ + { 0xAA29, 0xAA36 }, /* CHAM VOWEL SIGN AA - CHAM CONSONANT SIGN WA */ + { 0xAA43, 0xAA43 }, /* CHAM CONSONANT SIGN FINAL NG */ + { 0xAA4C, 0xAA4D }, /* CHAM CONSONANT SIGN FINAL M - CHAM CONSONANT SIGN FINAL H */ + { 0xAA7B, 0xAA7D }, /* MYANMAR SIGN PAO KAREN TONE - MYANMAR SIGN TAI LAING TONE-5 */ + { 0xAAB0, 0xAAB0 }, /* TAI VIET MAI KANG */ + { 0xAAB2, 0xAAB4 }, /* TAI VIET VOWEL I - TAI VIET VOWEL U */ + { 0xAAB7, 0xAAB8 }, /* TAI VIET MAI KHIT - TAI VIET VOWEL IA */ + { 0xAABE, 0xAABF }, /* TAI VIET VOWEL AM - TAI VIET TONE MAI EK */ + { 0xAAC1, 0xAAC1 }, /* TAI VIET TONE MAI THO */ + { 0xAAEB, 0xAAEF }, /* MEETEI MAYEK VOWEL SIGN II - MEETEI MAYEK VOWEL SIGN AAU */ + { 0xAAF5, 0xAAF6 }, /* MEETEI MAYEK VOWEL SIGN VISARGA - MEETEI MAYEK VIRAMA */ + { 0xABE3, 0xABEA }, /* MEETEI MAYEK VOWEL SIGN ONAP - MEETEI MAYEK VOWEL SIGN NUNG */ + { 0xABEC, 0xABED }, /* MEETEI MAYEK LUM IYEK - MEETEI MAYEK APUN IYEK */ + { 0xFB1E, 0xFB1E }, /* HEBREW POINT JUDEO-SPANISH VARIKA */ + { 0xFE00, 0xFE0F }, /* VARIATION SELECTOR-1 - VARIATION SELECTOR-16 */ + { 0xFE20, 0xFE2F }, /* COMBINING LIGATURE LEFT HALF - COMBINING CYRILLIC TITLO RIGHT HALF */ + { 0xFEFF, 0xFEFF }, /* ZERO WIDTH NO-BREAK SPACE */ + { 0xFFF9, 0xFFFB }, /* INTERLINEAR ANNOTATION ANCHOR - INTERLINEAR ANNOTATION TERMINATOR */ +}; + +/* Zero-width character ranges (non-BMP, U+10000 and above) */ +static const struct ucs_interval32 ucs_zero_width_non_bmp_ranges[] = { + { 0x101FD, 0x101FD }, /* PHAISTOS DISC SIGN COMBINING OBLIQUE STROKE */ + { 0x102E0, 0x102E0 }, /* COPTIC EPACT THOUSANDS MARK */ + { 0x10376, 0x1037A }, /* COMBINING OLD PERMIC LETTER AN - COMBINING OLD PERMIC LETTER SII */ + { 0x10A01, 0x10A03 }, /* KHAROSHTHI VOWEL SIGN I - KHAROSHTHI VOWEL SIGN VOCALIC R */ + { 0x10A05, 0x10A06 }, /* KHAROSHTHI VOWEL SIGN E - KHAROSHTHI VOWEL SIGN O */ + { 0x10A0C, 0x10A0F }, /* KHAROSHTHI VOWEL LENGTH MARK - KHAROSHTHI SIGN VISARGA */ + { 0x10A38, 0x10A3A }, /* KHAROSHTHI SIGN BAR ABOVE - KHAROSHTHI SIGN DOT BELOW */ + { 0x10A3F, 0x10A3F }, /* KHAROSHTHI VIRAMA */ + { 0x10AE5, 0x10AE6 }, /* MANICHAEAN ABBREVIATION MARK ABOVE - MANICHAEAN ABBREVIATION MARK BELOW */ + { 0x10D24, 0x10D27 }, /* HANIFI ROHINGYA SIGN HARBAHAY - HANIFI ROHINGYA SIGN TASSI */ + { 0x10D69, 0x10D6D }, /* GARAY VOWEL SIGN E - GARAY CONSONANT NASALIZATION MARK */ + { 0x10EAB, 0x10EAC }, /* YEZIDI COMBINING HAMZA MARK - YEZIDI COMBINING MADDA MARK */ + { 0x10EFC, 0x10EFF }, /* ARABIC COMBINING ALEF OVERLAY - ARABIC SMALL LOW WORD MADDA */ + { 0x10F46, 0x10F50 }, /* SOGDIAN COMBINING DOT BELOW - SOGDIAN COMBINING STROKE BELOW */ + { 0x10F82, 0x10F85 }, /* OLD UYGHUR COMBINING DOT ABOVE - OLD UYGHUR COMBINING TWO DOTS BELOW */ + { 0x11000, 0x11002 }, /* BRAHMI SIGN CANDRABINDU - BRAHMI SIGN VISARGA */ + { 0x11038, 0x11046 }, /* BRAHMI VOWEL SIGN AA - BRAHMI VIRAMA */ + { 0x11070, 0x11070 }, /* BRAHMI SIGN OLD TAMIL VIRAMA */ + { 0x11073, 0x11074 }, /* BRAHMI VOWEL SIGN OLD TAMIL SHORT E - BRAHMI VOWEL SIGN OLD TAMIL SHORT O */ + { 0x1107F, 0x11082 }, /* BRAHMI NUMBER JOINER - KAITHI SIGN VISARGA */ + { 0x110B0, 0x110BA }, /* KAITHI VOWEL SIGN AA - KAITHI SIGN NUKTA */ + { 0x110BD, 0x110BD }, /* KAITHI NUMBER SIGN */ + { 0x110C2, 0x110C2 }, /* KAITHI VOWEL SIGN VOCALIC R */ + { 0x110CD, 0x110CD }, /* KAITHI NUMBER SIGN ABOVE */ + { 0x11100, 0x11102 }, /* CHAKMA SIGN CANDRABINDU - CHAKMA SIGN VISARGA */ + { 0x11127, 0x11134 }, /* CHAKMA VOWEL SIGN A - CHAKMA MAAYYAA */ + { 0x11145, 0x11146 }, /* CHAKMA VOWEL SIGN AA - CHAKMA VOWEL SIGN EI */ + { 0x11173, 0x11173 }, /* MAHAJANI SIGN NUKTA */ + { 0x11180, 0x11182 }, /* SHARADA SIGN CANDRABINDU - SHARADA SIGN VISARGA */ + { 0x111B3, 0x111C0 }, /* SHARADA VOWEL SIGN AA - SHARADA SIGN VIRAMA */ + { 0x111C9, 0x111CC }, /* SHARADA SANDHI MARK - SHARADA EXTRA SHORT VOWEL MARK */ + { 0x111CE, 0x111CF }, /* SHARADA VOWEL SIGN PRISHTHAMATRA E - SHARADA SIGN INVERTED CANDRABINDU */ + { 0x1122C, 0x11237 }, /* KHOJKI VOWEL SIGN AA - KHOJKI SIGN SHADDA */ + { 0x1123E, 0x1123E }, /* KHOJKI SIGN SUKUN */ + { 0x11241, 0x11241 }, /* KHOJKI VOWEL SIGN VOCALIC R */ + { 0x112DF, 0x112EA }, /* KHUDAWADI SIGN ANUSVARA - KHUDAWADI SIGN VIRAMA */ + { 0x11300, 0x11303 }, /* GRANTHA SIGN COMBINING ANUSVARA ABOVE - GRANTHA SIGN VISARGA */ + { 0x1133B, 0x1133C }, /* COMBINING BINDU BELOW - GRANTHA SIGN NUKTA */ + { 0x1133E, 0x11344 }, /* GRANTHA VOWEL SIGN AA - GRANTHA VOWEL SIGN VOCALIC RR */ + { 0x11347, 0x11348 }, /* GRANTHA VOWEL SIGN EE - GRANTHA VOWEL SIGN AI */ + { 0x1134B, 0x1134D }, /* GRANTHA VOWEL SIGN OO - GRANTHA SIGN VIRAMA */ + { 0x11357, 0x11357 }, /* GRANTHA AU LENGTH MARK */ + { 0x11362, 0x11363 }, /* GRANTHA VOWEL SIGN VOCALIC L - GRANTHA VOWEL SIGN VOCALIC LL */ + { 0x11366, 0x1136C }, /* COMBINING GRANTHA DIGIT ZERO - COMBINING GRANTHA DIGIT SIX */ + { 0x11370, 0x11374 }, /* COMBINING GRANTHA LETTER A - COMBINING GRANTHA LETTER PA */ + { 0x113B8, 0x113C0 }, /* TULU-TIGALARI VOWEL SIGN AA - TULU-TIGALARI VOWEL SIGN VOCALIC LL */ + { 0x113C2, 0x113C2 }, /* TULU-TIGALARI VOWEL SIGN EE */ + { 0x113C5, 0x113C5 }, /* TULU-TIGALARI VOWEL SIGN AI */ + { 0x113C7, 0x113CA }, /* TULU-TIGALARI VOWEL SIGN OO - TULU-TIGALARI SIGN CANDRA ANUNASIKA */ + { 0x113CC, 0x113D0 }, /* TULU-TIGALARI SIGN ANUSVARA - TULU-TIGALARI CONJOINER */ + { 0x113D2, 0x113D2 }, /* TULU-TIGALARI GEMINATION MARK */ + { 0x113E1, 0x113E2 }, /* TULU-TIGALARI VEDIC TONE SVARITA - TULU-TIGALARI VEDIC TONE ANUDATTA */ + { 0x11435, 0x11446 }, /* NEWA VOWEL SIGN AA - NEWA SIGN NUKTA */ + { 0x1145E, 0x1145E }, /* NEWA SANDHI MARK */ + { 0x114B0, 0x114C3 }, /* TIRHUTA VOWEL SIGN AA - TIRHUTA SIGN NUKTA */ + { 0x115AF, 0x115B5 }, /* SIDDHAM VOWEL SIGN AA - SIDDHAM VOWEL SIGN VOCALIC RR */ + { 0x115B8, 0x115C0 }, /* SIDDHAM VOWEL SIGN E - SIDDHAM SIGN NUKTA */ + { 0x115DC, 0x115DD }, /* SIDDHAM VOWEL SIGN ALTERNATE U - SIDDHAM VOWEL SIGN ALTERNATE UU */ + { 0x11630, 0x11640 }, /* MODI VOWEL SIGN AA - MODI SIGN ARDHACANDRA */ + { 0x116AB, 0x116B7 }, /* TAKRI SIGN ANUSVARA - TAKRI SIGN NUKTA */ + { 0x1171D, 0x1172B }, /* AHOM CONSONANT SIGN MEDIAL LA - AHOM SIGN KILLER */ + { 0x1182C, 0x1183A }, /* DOGRA VOWEL SIGN AA - DOGRA SIGN NUKTA */ + { 0x11930, 0x11935 }, /* DIVES AKURU VOWEL SIGN AA - DIVES AKURU VOWEL SIGN E */ + { 0x11937, 0x11938 }, /* DIVES AKURU VOWEL SIGN AI - DIVES AKURU VOWEL SIGN O */ + { 0x1193B, 0x1193E }, /* DIVES AKURU SIGN ANUSVARA - DIVES AKURU VIRAMA */ + { 0x11940, 0x11940 }, /* DIVES AKURU MEDIAL YA */ + { 0x11942, 0x11943 }, /* DIVES AKURU MEDIAL RA - DIVES AKURU SIGN NUKTA */ + { 0x119D1, 0x119D7 }, /* NANDINAGARI VOWEL SIGN AA - NANDINAGARI VOWEL SIGN VOCALIC RR */ + { 0x119DA, 0x119E0 }, /* NANDINAGARI VOWEL SIGN E - NANDINAGARI SIGN VIRAMA */ + { 0x119E4, 0x119E4 }, /* NANDINAGARI VOWEL SIGN PRISHTHAMATRA E */ + { 0x11A01, 0x11A0A }, /* ZANABAZAR SQUARE VOWEL SIGN I - ZANABAZAR SQUARE VOWEL LENGTH MARK */ + { 0x11A33, 0x11A39 }, /* ZANABAZAR SQUARE FINAL CONSONANT MARK - ZANABAZAR SQUARE SIGN VISARGA */ + { 0x11A3B, 0x11A3E }, /* ZANABAZAR SQUARE CLUSTER-FINAL LETTER YA - ZANABAZAR SQUARE CLUSTER-FINAL LETTER VA */ + { 0x11A47, 0x11A47 }, /* ZANABAZAR SQUARE SUBJOINER */ + { 0x11A51, 0x11A5B }, /* SOYOMBO VOWEL SIGN I - SOYOMBO VOWEL LENGTH MARK */ + { 0x11A8A, 0x11A99 }, /* SOYOMBO FINAL CONSONANT SIGN G - SOYOMBO SUBJOINER */ + { 0x11C2F, 0x11C36 }, /* BHAIKSUKI VOWEL SIGN AA - BHAIKSUKI VOWEL SIGN VOCALIC L */ + { 0x11C38, 0x11C3F }, /* BHAIKSUKI VOWEL SIGN E - BHAIKSUKI SIGN VIRAMA */ + { 0x11C92, 0x11CA7 }, /* MARCHEN SUBJOINED LETTER KA - MARCHEN SUBJOINED LETTER ZA */ + { 0x11CA9, 0x11CB6 }, /* MARCHEN SUBJOINED LETTER YA - MARCHEN SIGN CANDRABINDU */ + { 0x11D31, 0x11D36 }, /* MASARAM GONDI VOWEL SIGN AA - MASARAM GONDI VOWEL SIGN VOCALIC R */ + { 0x11D3A, 0x11D3A }, /* MASARAM GONDI VOWEL SIGN E */ + { 0x11D3C, 0x11D3D }, /* MASARAM GONDI VOWEL SIGN AI - MASARAM GONDI VOWEL SIGN O */ + { 0x11D3F, 0x11D45 }, /* MASARAM GONDI VOWEL SIGN AU - MASARAM GONDI VIRAMA */ + { 0x11D47, 0x11D47 }, /* MASARAM GONDI RA-KARA */ + { 0x11D8A, 0x11D8E }, /* GUNJALA GONDI VOWEL SIGN AA - GUNJALA GONDI VOWEL SIGN UU */ + { 0x11D90, 0x11D91 }, /* GUNJALA GONDI VOWEL SIGN EE - GUNJALA GONDI VOWEL SIGN AI */ + { 0x11D93, 0x11D97 }, /* GUNJALA GONDI VOWEL SIGN OO - GUNJALA GONDI VIRAMA */ + { 0x11EF3, 0x11EF6 }, /* MAKASAR VOWEL SIGN I - MAKASAR VOWEL SIGN O */ + { 0x11F00, 0x11F01 }, /* KAWI SIGN CANDRABINDU - KAWI SIGN ANUSVARA */ + { 0x11F03, 0x11F03 }, /* KAWI SIGN VISARGA */ + { 0x11F34, 0x11F3A }, /* KAWI VOWEL SIGN AA - KAWI VOWEL SIGN VOCALIC R */ + { 0x11F3E, 0x11F42 }, /* KAWI VOWEL SIGN E - KAWI CONJOINER */ + { 0x11F5A, 0x11F5A }, /* KAWI SIGN NUKTA */ + { 0x13430, 0x13440 }, /* EGYPTIAN HIEROGLYPH VERTICAL JOINER - EGYPTIAN HIEROGLYPH MIRROR HORIZONTALLY */ + { 0x13447, 0x13455 }, /* EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT TOP START - EGYPTIAN HIEROGLYPH MODIFIER DAMAGED */ + { 0x1611E, 0x1612F }, /* GURUNG KHEMA VOWEL SIGN AA - GURUNG KHEMA SIGN THOLHOMA */ + { 0x16AF0, 0x16AF4 }, /* BASSA VAH COMBINING HIGH TONE - BASSA VAH COMBINING HIGH-LOW TONE */ + { 0x16B30, 0x16B36 }, /* PAHAWH HMONG MARK CIM TUB - PAHAWH HMONG MARK CIM TAUM */ + { 0x16F4F, 0x16F4F }, /* MIAO SIGN CONSONANT MODIFIER BAR */ + { 0x16F51, 0x16F87 }, /* MIAO SIGN ASPIRATION - MIAO VOWEL SIGN UI */ + { 0x16F8F, 0x16F92 }, /* MIAO TONE RIGHT - MIAO TONE BELOW */ + { 0x16FE4, 0x16FE4 }, /* KHITAN SMALL SCRIPT FILLER */ + { 0x16FF0, 0x16FF1 }, /* VIETNAMESE ALTERNATE READING MARK CA - VIETNAMESE ALTERNATE READING MARK NHAY */ + { 0x1BC9D, 0x1BC9E }, /* DUPLOYAN THICK LETTER SELECTOR - DUPLOYAN DOUBLE MARK */ + { 0x1BCA0, 0x1BCA3 }, /* SHORTHAND FORMAT LETTER OVERLAP - SHORTHAND FORMAT UP STEP */ + { 0x1CF00, 0x1CF2D }, /* ZNAMENNY COMBINING MARK GORAZDO NIZKO S KRYZHEM ON LEFT - ZNAMENNY COMBINING MARK KRYZH ON LEFT */ + { 0x1CF30, 0x1CF46 }, /* ZNAMENNY COMBINING TONAL RANGE MARK MRACHNO - ZNAMENNY PRIZNAK MODIFIER ROG */ + { 0x1D165, 0x1D169 }, /* MUSICAL SYMBOL COMBINING STEM - MUSICAL SYMBOL COMBINING TREMOLO-3 */ + { 0x1D16D, 0x1D182 }, /* MUSICAL SYMBOL COMBINING AUGMENTATION DOT - MUSICAL SYMBOL COMBINING LOURE */ + { 0x1D185, 0x1D18B }, /* MUSICAL SYMBOL COMBINING DOIT - MUSICAL SYMBOL COMBINING TRIPLE TONGUE */ + { 0x1D1AA, 0x1D1AD }, /* MUSICAL SYMBOL COMBINING DOWN BOW - MUSICAL SYMBOL COMBINING SNAP PIZZICATO */ + { 0x1D242, 0x1D244 }, /* COMBINING GREEK MUSICAL TRISEME - COMBINING GREEK MUSICAL PENTASEME */ + { 0x1DA00, 0x1DA36 }, /* SIGNWRITING HEAD RIM - SIGNWRITING AIR SUCKING IN */ + { 0x1DA3B, 0x1DA6C }, /* SIGNWRITING MOUTH CLOSED NEUTRAL - SIGNWRITING EXCITEMENT */ + { 0x1DA75, 0x1DA75 }, /* SIGNWRITING UPPER BODY TILTING FROM HIP JOINTS */ + { 0x1DA84, 0x1DA84 }, /* SIGNWRITING LOCATION HEAD NECK */ + { 0x1DA9B, 0x1DA9F }, /* SIGNWRITING FILL MODIFIER-2 - SIGNWRITING FILL MODIFIER-6 */ + { 0x1DAA1, 0x1DAAF }, /* SIGNWRITING ROTATION MODIFIER-2 - SIGNWRITING ROTATION MODIFIER-16 */ + { 0x1E000, 0x1E006 }, /* COMBINING GLAGOLITIC LETTER AZU - COMBINING GLAGOLITIC LETTER ZHIVETE */ + { 0x1E008, 0x1E018 }, /* COMBINING GLAGOLITIC LETTER ZEMLJA - COMBINING GLAGOLITIC LETTER HERU */ + { 0x1E01B, 0x1E021 }, /* COMBINING GLAGOLITIC LETTER SHTA - COMBINING GLAGOLITIC LETTER YATI */ + { 0x1E023, 0x1E024 }, /* COMBINING GLAGOLITIC LETTER YU - COMBINING GLAGOLITIC LETTER SMALL YUS */ + { 0x1E026, 0x1E02A }, /* COMBINING GLAGOLITIC LETTER YO - COMBINING GLAGOLITIC LETTER FITA */ + { 0x1E08F, 0x1E08F }, /* COMBINING CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I */ + { 0x1E130, 0x1E136 }, /* NYIAKENG PUACHUE HMONG TONE-B - NYIAKENG PUACHUE HMONG TONE-D */ + { 0x1E2AE, 0x1E2AE }, /* TOTO SIGN RISING TONE */ + { 0x1E2EC, 0x1E2EF }, /* WANCHO TONE TUP - WANCHO TONE KOINI */ + { 0x1E4EC, 0x1E4EF }, /* NAG MUNDARI SIGN MUHOR - NAG MUNDARI SIGN SUTUH */ + { 0x1E5EE, 0x1E5EF }, /* OL ONAL SIGN MU - OL ONAL SIGN IKIR */ + { 0x1E8D0, 0x1E8D6 }, /* MENDE KIKAKUI COMBINING NUMBER TEENS - MENDE KIKAKUI COMBINING NUMBER MILLIONS */ + { 0x1E944, 0x1E94A }, /* ADLAM ALIF LENGTHENER - ADLAM NUKTA */ + { 0x1F3FB, 0x1F3FF }, /* EMOJI MODIFIER FITZPATRICK TYPE-1-2 - EMOJI MODIFIER FITZPATRICK TYPE-6 */ + { 0x1F9B0, 0x1F9B3 }, /* EMOJI COMPONENT RED HAIR - EMOJI COMPONENT WHITE HAIR */ + { 0xE0001, 0xE0001 }, /* LANGUAGE TAG */ + { 0xE0020, 0xE007F }, /* TAG SPACE - CANCEL TAG */ + { 0xE0100, 0xE01EF }, /* VARIATION SELECTOR-17 - VARIATION SELECTOR-256 */ +}; + +/* Double-width character ranges (BMP - Basic Multilingual Plane, U+0000 to U+FFFF) */ +static const struct ucs_interval16 ucs_double_width_bmp_ranges[] = { + { 0x1100, 0x115F }, /* HANGUL CHOSEONG KIYEOK - HANGUL CHOSEONG FILLER */ + { 0x231A, 0x231B }, /* WATCH - HOURGLASS */ + { 0x2329, 0x232A }, /* LEFT-POINTING ANGLE BRACKET - RIGHT-POINTING ANGLE BRACKET */ + { 0x23E9, 0x23EC }, /* BLACK RIGHT-POINTING DOUBLE TRIANGLE - BLACK DOWN-POINTING DOUBLE TRIANGLE */ + { 0x23F0, 0x23F0 }, /* ALARM CLOCK */ + { 0x23F3, 0x23F3 }, /* HOURGLASS WITH FLOWING SAND */ + { 0x25FD, 0x25FE }, /* WHITE MEDIUM SMALL SQUARE - BLACK MEDIUM SMALL SQUARE */ + { 0x2614, 0x2615 }, /* UMBRELLA WITH RAIN DROPS - HOT BEVERAGE */ + { 0x2630, 0x2637 }, /* TRIGRAM FOR HEAVEN - TRIGRAM FOR EARTH */ + { 0x2648, 0x2653 }, /* ARIES - PISCES */ + { 0x267F, 0x267F }, /* WHEELCHAIR SYMBOL */ + { 0x268A, 0x268F }, /* MONOGRAM FOR YANG - DIGRAM FOR GREATER YIN */ + { 0x2693, 0x2693 }, /* ANCHOR */ + { 0x26A1, 0x26A1 }, /* HIGH VOLTAGE SIGN */ + { 0x26AA, 0x26AB }, /* MEDIUM WHITE CIRCLE - MEDIUM BLACK CIRCLE */ + { 0x26BD, 0x26BE }, /* SOCCER BALL - BASEBALL */ + { 0x26C4, 0x26C5 }, /* SNOWMAN WITHOUT SNOW - SUN BEHIND CLOUD */ + { 0x26CE, 0x26CE }, /* OPHIUCHUS */ + { 0x26D4, 0x26D4 }, /* NO ENTRY */ + { 0x26EA, 0x26EA }, /* CHURCH */ + { 0x26F2, 0x26F3 }, /* FOUNTAIN - FLAG IN HOLE */ + { 0x26F5, 0x26F5 }, /* SAILBOAT */ + { 0x26FA, 0x26FA }, /* TENT */ + { 0x26FD, 0x26FD }, /* FUEL PUMP */ + { 0x2705, 0x2705 }, /* WHITE HEAVY CHECK MARK */ + { 0x270A, 0x270B }, /* RAISED FIST - RAISED HAND */ + { 0x2728, 0x2728 }, /* SPARKLES */ + { 0x274C, 0x274C }, /* CROSS MARK */ + { 0x274E, 0x274E }, /* NEGATIVE SQUARED CROSS MARK */ + { 0x2753, 0x2755 }, /* BLACK QUESTION MARK ORNAMENT - WHITE EXCLAMATION MARK ORNAMENT */ + { 0x2757, 0x2757 }, /* HEAVY EXCLAMATION MARK SYMBOL */ + { 0x2795, 0x2797 }, /* HEAVY PLUS SIGN - HEAVY DIVISION SIGN */ + { 0x27B0, 0x27B0 }, /* CURLY LOOP */ + { 0x27BF, 0x27BF }, /* DOUBLE CURLY LOOP */ + { 0x2B1B, 0x2B1C }, /* BLACK LARGE SQUARE - WHITE LARGE SQUARE */ + { 0x2B50, 0x2B50 }, /* WHITE MEDIUM STAR */ + { 0x2B55, 0x2B55 }, /* HEAVY LARGE CIRCLE */ + { 0x2E80, 0x2E99 }, /* CJK RADICAL REPEAT - CJK RADICAL RAP */ + { 0x2E9B, 0x2EF3 }, /* CJK RADICAL CHOKE - CJK RADICAL C-SIMPLIFIED TURTLE */ + { 0x2F00, 0x2FD5 }, /* KANGXI RADICAL ONE - KANGXI RADICAL FLUTE */ + { 0x2FF0, 0x3029 }, /* IDEOGRAPHIC DESCRIPTION CHARACTER LEFT TO RIGHT - HANGZHOU NUMERAL NINE */ + { 0x3030, 0x303E }, /* WAVY DASH - IDEOGRAPHIC VARIATION INDICATOR */ + { 0x3041, 0x3096 }, /* HIRAGANA LETTER SMALL A - HIRAGANA LETTER SMALL KE */ + { 0x309B, 0x30FF }, /* KATAKANA-HIRAGANA VOICED SOUND MARK - KATAKANA DIGRAPH KOTO */ + { 0x3105, 0x312F }, /* BOPOMOFO LETTER B - BOPOMOFO LETTER NN */ + { 0x3131, 0x318E }, /* HANGUL LETTER KIYEOK - HANGUL LETTER ARAEAE */ + { 0x3190, 0x31E5 }, /* IDEOGRAPHIC ANNOTATION LINKING MARK - CJK STROKE SZP */ + { 0x31EF, 0x321E }, /* IDEOGRAPHIC DESCRIPTION CHARACTER SUBTRACTION - PARENTHESIZED KOREAN CHARACTER O HU */ + { 0x3220, 0x3247 }, /* PARENTHESIZED IDEOGRAPH ONE - CIRCLED IDEOGRAPH KOTO */ + { 0x3250, 0xA48C }, /* PARTNERSHIP SIGN - YI SYLLABLE YYR */ + { 0xA490, 0xA4C6 }, /* YI RADICAL QOT - YI RADICAL KE */ + { 0xA960, 0xA97C }, /* HANGUL CHOSEONG TIKEUT-MIEUM - HANGUL CHOSEONG SSANGYEORINHIEUH */ + { 0xAC00, 0xD7A3 }, /* HANGUL SYLLABLE GA - HANGUL SYLLABLE HIH */ + { 0xF900, 0xFAFF }, /* U+F900 - U+FAFF */ + { 0xFE10, 0xFE19 }, /* PRESENTATION FORM FOR VERTICAL COMMA - PRESENTATION FORM FOR VERTICAL HORIZONTAL ELLIPSIS */ + { 0xFE30, 0xFE52 }, /* PRESENTATION FORM FOR VERTICAL TWO DOT LEADER - SMALL FULL STOP */ + { 0xFE54, 0xFE66 }, /* SMALL SEMICOLON - SMALL EQUALS SIGN */ + { 0xFE68, 0xFE6B }, /* SMALL REVERSE SOLIDUS - SMALL COMMERCIAL AT */ + { 0xFF01, 0xFF60 }, /* FULLWIDTH EXCLAMATION MARK - FULLWIDTH RIGHT WHITE PARENTHESIS */ + { 0xFFE0, 0xFFE6 }, /* FULLWIDTH CENT SIGN - FULLWIDTH WON SIGN */ +}; + +/* Double-width character ranges (non-BMP, U+10000 and above) */ +static const struct ucs_interval32 ucs_double_width_non_bmp_ranges[] = { + { 0x16FE0, 0x16FE3 }, /* TANGUT ITERATION MARK - OLD CHINESE ITERATION MARK */ + { 0x17000, 0x187F7 }, /* U+17000 - U+187F7 */ + { 0x18800, 0x18CD5 }, /* TANGUT COMPONENT-001 - KHITAN SMALL SCRIPT CHARACTER-18CD5 */ + { 0x18CFF, 0x18D08 }, /* U+18CFF - U+18D08 */ + { 0x1AFF0, 0x1AFF3 }, /* KATAKANA LETTER MINNAN TONE-2 - KATAKANA LETTER MINNAN TONE-5 */ + { 0x1AFF5, 0x1AFFB }, /* KATAKANA LETTER MINNAN TONE-7 - KATAKANA LETTER MINNAN NASALIZED TONE-5 */ + { 0x1AFFD, 0x1AFFE }, /* KATAKANA LETTER MINNAN NASALIZED TONE-7 - KATAKANA LETTER MINNAN NASALIZED TONE-8 */ + { 0x1B000, 0x1B122 }, /* KATAKANA LETTER ARCHAIC E - KATAKANA LETTER ARCHAIC WU */ + { 0x1B132, 0x1B132 }, /* HIRAGANA LETTER SMALL KO */ + { 0x1B150, 0x1B152 }, /* HIRAGANA LETTER SMALL WI - HIRAGANA LETTER SMALL WO */ + { 0x1B155, 0x1B155 }, /* KATAKANA LETTER SMALL KO */ + { 0x1B164, 0x1B167 }, /* KATAKANA LETTER SMALL WI - KATAKANA LETTER SMALL N */ + { 0x1B170, 0x1B2FB }, /* NUSHU CHARACTER-1B170 - NUSHU CHARACTER-1B2FB */ + { 0x1D300, 0x1D356 }, /* MONOGRAM FOR EARTH - TETRAGRAM FOR FOSTERING */ + { 0x1D360, 0x1D376 }, /* COUNTING ROD UNIT DIGIT ONE - IDEOGRAPHIC TALLY MARK FIVE */ + { 0x1F000, 0x1F02F }, /* U+1F000 - U+1F02F */ + { 0x1F0A0, 0x1F0FF }, /* U+1F0A0 - U+1F0FF */ + { 0x1F18E, 0x1F18E }, /* NEGATIVE SQUARED AB */ + { 0x1F191, 0x1F19A }, /* SQUARED CL - SQUARED VS */ + { 0x1F200, 0x1F202 }, /* SQUARE HIRAGANA HOKA - SQUARED KATAKANA SA */ + { 0x1F210, 0x1F23B }, /* SQUARED CJK UNIFIED IDEOGRAPH-624B - SQUARED CJK UNIFIED IDEOGRAPH-914D */ + { 0x1F240, 0x1F248 }, /* TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-672C - TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-6557 */ + { 0x1F250, 0x1F251 }, /* CIRCLED IDEOGRAPH ADVANTAGE - CIRCLED IDEOGRAPH ACCEPT */ + { 0x1F260, 0x1F265 }, /* ROUNDED SYMBOL FOR FU - ROUNDED SYMBOL FOR CAI */ + { 0x1F300, 0x1F3FA }, /* CYCLONE - AMPHORA */ + { 0x1F400, 0x1F64F }, /* RAT - PERSON WITH FOLDED HANDS */ + { 0x1F680, 0x1F9AF }, /* ROCKET - PROBING CANE */ + { 0x1F9B4, 0x1FAFF }, /* U+1F9B4 - U+1FAFF */ + { 0x20000, 0x2FFFD }, /* U+20000 - U+2FFFD */ + { 0x30000, 0x3FFFD }, /* U+30000 - U+3FFFD */ +}; diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index f5642b3038e4..ed39d9cb4432 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -104,7 +104,6 @@ #include <linux/uaccess.h> #include <linux/kdb.h> #include <linux/ctype.h> -#include <linux/bsearch.h> #include <linux/gcd.h> #define MAX_NR_CON_DRIVER 16 @@ -444,6 +443,15 @@ static void vc_uniscr_scroll(struct vc_data *vc, unsigned int top, } } +static u32 vc_uniscr_getc(struct vc_data *vc, int relative_pos) +{ + int pos = vc->state.x + vc->vc_need_wrap + relative_pos; + + if (vc->vc_uni_lines && in_range(pos, 0, vc->vc_cols)) + return vc->vc_uni_lines[vc->state.y][pos]; + return 0; +} + static void vc_uniscr_copy_area(u32 **dst_lines, unsigned int dst_cols, unsigned int dst_rows, @@ -1862,6 +1870,14 @@ int mouse_reporting(void) return vc_cons[fg_console].d->vc_report_mouse; } +/* invoked via ioctl(TIOCLINUX) */ +static int get_bracketed_paste(struct tty_struct *tty) +{ + struct vc_data *vc = tty->driver_data; + + return vc->vc_bracketed_paste; +} + enum { CSI_DEC_hl_CURSOR_KEYS = 1, /* CKM: cursor keys send ^[Ox/^[[x */ CSI_DEC_hl_132_COLUMNS = 3, /* COLM: 80/132 mode switch */ @@ -1872,6 +1888,7 @@ enum { CSI_DEC_hl_MOUSE_X10 = 9, CSI_DEC_hl_SHOW_CURSOR = 25, /* TCEM */ CSI_DEC_hl_MOUSE_VT200 = 1000, + CSI_DEC_hl_BRACKETED_PASTE = 2004, }; /* console_lock is held */ @@ -1924,6 +1941,9 @@ static void csi_DEC_hl(struct vc_data *vc, bool on_off) case CSI_DEC_hl_MOUSE_VT200: vc->vc_report_mouse = on_off ? 2 : 0; break; + case CSI_DEC_hl_BRACKETED_PASTE: + vc->vc_bracketed_paste = on_off; + break; } } @@ -2149,6 +2169,7 @@ static void reset_terminal(struct vc_data *vc, int do_clear) vc->state.charset = 0; vc->vc_need_wrap = 0; vc->vc_report_mouse = 0; + vc->vc_bracketed_paste = 0; vc->vc_utf = default_utf8; vc->vc_utf_count = 0; @@ -2712,43 +2733,6 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, u8 c) } } -/* is_double_width() is based on the wcwidth() implementation by - * Markus Kuhn -- 2007-05-26 (Unicode 5.0) - * Latest version: https://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c - */ -struct interval { - uint32_t first; - uint32_t last; -}; - -static int ucs_cmp(const void *key, const void *elt) -{ - uint32_t ucs = *(uint32_t *)key; - struct interval e = *(struct interval *) elt; - - if (ucs > e.last) - return 1; - else if (ucs < e.first) - return -1; - return 0; -} - -static int is_double_width(uint32_t ucs) -{ - static const struct interval double_width[] = { - { 0x1100, 0x115F }, { 0x2329, 0x232A }, { 0x2E80, 0x303E }, - { 0x3040, 0xA4CF }, { 0xAC00, 0xD7A3 }, { 0xF900, 0xFAFF }, - { 0xFE10, 0xFE19 }, { 0xFE30, 0xFE6F }, { 0xFF00, 0xFF60 }, - { 0xFFE0, 0xFFE6 }, { 0x20000, 0x2FFFD }, { 0x30000, 0x3FFFD } - }; - if (ucs < double_width[0].first || - ucs > double_width[ARRAY_SIZE(double_width) - 1].last) - return 0; - - return bsearch(&ucs, double_width, ARRAY_SIZE(double_width), - sizeof(struct interval), ucs_cmp) != NULL; -} - struct vc_draw_region { unsigned long from, to; int x; @@ -2817,7 +2801,7 @@ static int vc_translate_unicode(struct vc_data *vc, int c, bool *rescan) if ((c & 0xc0) == 0x80) { /* Unexpected continuation byte? */ if (!vc->vc_utf_count) - return 0xfffd; + goto bad_sequence; vc->vc_utf_char = (vc->vc_utf_char << 6) | (c & 0x3f); vc->vc_npar++; @@ -2829,17 +2813,17 @@ static int vc_translate_unicode(struct vc_data *vc, int c, bool *rescan) /* Reject overlong sequences */ if (c <= utf8_length_changes[vc->vc_npar - 1] || c > utf8_length_changes[vc->vc_npar]) - return 0xfffd; + goto bad_sequence; return vc_sanitize_unicode(c); } /* Single ASCII byte or first byte of a sequence received */ if (vc->vc_utf_count) { - /* Continuation byte expected */ + /* A continuation byte was expected */ *rescan = true; vc->vc_utf_count = 0; - return 0xfffd; + goto bad_sequence; } /* Nothing to do if an ASCII byte was received */ @@ -2858,11 +2842,14 @@ static int vc_translate_unicode(struct vc_data *vc, int c, bool *rescan) vc->vc_utf_count = 3; vc->vc_utf_char = (c & 0x07); } else { - return 0xfffd; + goto bad_sequence; } need_more_bytes: return -1; + +bad_sequence: + return 0xfffd; } static int vc_translate(struct vc_data *vc, int *c, bool *rescan) @@ -2940,54 +2927,143 @@ static bool vc_is_control(struct vc_data *vc, int tc, int c) return false; } +static void vc_con_rewind(struct vc_data *vc) +{ + if (vc->state.x && !vc->vc_need_wrap) { + vc->vc_pos -= 2; + vc->state.x--; + } + vc->vc_need_wrap = 0; +} + +#define UCS_ZWS 0x200b /* Zero Width Space */ +#define UCS_VS16 0xfe0f /* Variation Selector 16 */ +#define UCS_REPLACEMENT 0xfffd /* Replacement Character */ + +static int vc_process_ucs(struct vc_data *vc, int *c, int *tc) +{ + u32 prev_c, curr_c = *c; + + if (ucs_is_double_width(curr_c)) { + /* + * The Unicode screen memory is allocated only when + * required. This is one such case as we need to remember + * which displayed characters are double-width. + */ + vc_uniscr_check(vc); + return 2; + } + + if (!ucs_is_zero_width(curr_c)) + return 1; + + /* From here curr_c is known to be zero-width. */ + + if (ucs_is_double_width(vc_uniscr_getc(vc, -2))) { + /* + * Let's merge this zero-width code point with the preceding + * double-width code point by replacing the existing + * zero-width space padding. To do so we rewind one column + * and pretend this has a width of 1. + * We give the legacy display the same initial space padding. + */ + vc_con_rewind(vc); + *tc = ' '; + return 1; + } + + /* From here the preceding character, if any, must be single-width. */ + prev_c = vc_uniscr_getc(vc, -1); + + if (curr_c == UCS_VS16 && prev_c != 0) { + /* + * VS16 (U+FE0F) is special. It typically turns the preceding + * single-width character into a double-width one. Let it + * have a width of 1 effectively making the combination with + * the preceding character double-width. + */ + *tc = ' '; + return 1; + } + + /* try recomposition */ + prev_c = ucs_recompose(prev_c, curr_c); + if (prev_c != 0) { + vc_con_rewind(vc); + *tc = *c = prev_c; + return 1; + } + + /* Otherwise zero-width code points are ignored. */ + return 0; +} + +static int vc_get_glyph(struct vc_data *vc, int tc) +{ + int glyph = conv_uni_to_pc(vc, tc); + u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; + + if (!(glyph & ~charmask)) + return glyph; + + if (glyph == -1) + return -1; /* nothing to display */ + + /* Glyph not found */ + if ((!vc->vc_utf || vc->vc_disp_ctrl || tc < 128) && !(tc & ~charmask)) { + /* + * In legacy mode use the glyph we get by a 1:1 mapping. + * This would make absolutely no sense with Unicode in mind, but do this for + * ASCII characters since a font may lack Unicode mapping info and we don't + * want to end up with having question marks only. + */ + return tc; + } + + /* + * The Unicode screen memory is allocated only when required. + * This is one such case: we're about to "cheat" with the displayed + * character meaning the simple screen buffer won't hold the original + * information, whereas the Unicode screen buffer always does. + */ + vc_uniscr_check(vc); + + /* Try getting a simpler fallback character. */ + tc = ucs_get_fallback(tc); + if (tc) + return vc_get_glyph(vc, tc); + + /* Display U+FFFD (Unicode Replacement Character). */ + return conv_uni_to_pc(vc, UCS_REPLACEMENT); +} + static int vc_con_write_normal(struct vc_data *vc, int tc, int c, struct vc_draw_region *draw) { int next_c; unsigned char vc_attr = vc->vc_attr; - u16 himask = vc->vc_hi_font_mask, charmask = himask ? 0x1ff : 0xff; + u16 himask = vc->vc_hi_font_mask; u8 width = 1; bool inverse = false; if (vc->vc_utf && !vc->vc_disp_ctrl) { - if (is_double_width(c)) - width = 2; + width = vc_process_ucs(vc, &c, &tc); + if (!width) + goto out; } /* Now try to find out how to display it */ - tc = conv_uni_to_pc(vc, tc); - if (tc & ~charmask) { - if (tc == -1 || tc == -2) - return -1; /* nothing to display */ - - /* Glyph not found */ - if ((!vc->vc_utf || vc->vc_disp_ctrl || c < 128) && - !(c & ~charmask)) { - /* - * In legacy mode use the glyph we get by a 1:1 - * mapping. - * This would make absolutely no sense with Unicode in - * mind, but do this for ASCII characters since a font - * may lack Unicode mapping info and we don't want to - * end up with having question marks only. - */ - tc = c; - } else { - /* - * Display U+FFFD. If it's not found, display an inverse - * question mark. - */ - tc = conv_uni_to_pc(vc, 0xfffd); - if (tc < 0) { - inverse = true; - tc = conv_uni_to_pc(vc, '?'); - if (tc < 0) - tc = '?'; - - vc_attr = vc_invert_attr(vc); - con_flush(vc, draw); - } - } + tc = vc_get_glyph(vc, tc); + if (tc == -1) + return -1; /* nothing to display */ + if (tc < 0) { + inverse = true; + tc = conv_uni_to_pc(vc, '?'); + if (tc < 0) + tc = '?'; + + vc_attr = vc_invert_attr(vc); + con_flush(vc, draw); } next_c = c; @@ -3028,8 +3104,14 @@ static int vc_con_write_normal(struct vc_data *vc, int tc, int c, tc = conv_uni_to_pc(vc, ' '); if (tc < 0) tc = ' '; - next_c = ' '; + /* + * Store a zero-width space in the Unicode screen given that + * the previous code point is semantically double width. + */ + next_c = UCS_ZWS; } + +out: notify_write(vc, c); if (inverse) @@ -3414,6 +3496,8 @@ int tioclinux(struct tty_struct *tty, unsigned long arg) break; case TIOCL_BLANKEDSCREEN: return console_blanked; + case TIOCL_GETBRACKETEDPASTE: + return get_bracketed_paste(tty); default: return -EINVAL; } diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c index 4b91072f3a4e..61342e06970a 100644 --- a/drivers/tty/vt/vt_ioctl.c +++ b/drivers/tty/vt/vt_ioctl.c @@ -951,6 +951,22 @@ int vt_ioctl(struct tty_struct *tty, (unsigned short __user *)arg); case VT_WAITEVENT: return vt_event_wait_ioctl((struct vt_event __user *)arg); + + case VT_GETCONSIZECSRPOS: + { + struct vt_consizecsrpos concsr; + + console_lock(); + concsr.con_cols = vc->vc_cols; + concsr.con_rows = vc->vc_rows; + concsr.csr_col = vc->state.x; + concsr.csr_row = vc->state.y; + console_unlock(); + if (copy_to_user(up, &concsr, sizeof(concsr))) + return -EFAULT; + return 0; + } + default: return -ENOIOCTLCMD; } @@ -1103,8 +1119,6 @@ long vt_compat_ioctl(struct tty_struct *tty, case VT_WAITACTIVE: case VT_RELDISP: case VT_DISALLOCATE: - case VT_RESIZE: - case VT_RESIZEX: return vt_ioctl(tty, cmd, arg); /* diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 76cedd30c274..4410e7d93b7d 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -1397,6 +1397,7 @@ static int ufshcd_clock_scaling_prepare(struct ufs_hba *hba, u64 timeout_us) * make sure that there are no outstanding requests when * clock scaling is in progress */ + mutex_lock(&hba->host->scan_mutex); blk_mq_quiesce_tagset(&hba->host->tag_set); mutex_lock(&hba->wb_mutex); down_write(&hba->clk_scaling_lock); @@ -1407,6 +1408,7 @@ static int ufshcd_clock_scaling_prepare(struct ufs_hba *hba, u64 timeout_us) up_write(&hba->clk_scaling_lock); mutex_unlock(&hba->wb_mutex); blk_mq_unquiesce_tagset(&hba->host->tag_set); + mutex_unlock(&hba->host->scan_mutex); goto out; } @@ -1428,6 +1430,7 @@ static void ufshcd_clock_scaling_unprepare(struct ufs_hba *hba, int err) mutex_unlock(&hba->wb_mutex); blk_mq_unquiesce_tagset(&hba->host->tag_set); + mutex_unlock(&hba->host->scan_mutex); ufshcd_release(hba); } diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c index 37887ec68412..18a978452001 100644 --- a/drivers/ufs/host/ufs-qcom.c +++ b/drivers/ufs/host/ufs-qcom.c @@ -122,7 +122,9 @@ static const struct { }; static void ufs_qcom_get_default_testbus_cfg(struct ufs_qcom_host *host); -static int ufs_qcom_set_core_clk_ctrl(struct ufs_hba *hba, unsigned long freq); +static unsigned long ufs_qcom_opp_freq_to_clk_freq(struct ufs_hba *hba, + unsigned long freq, char *name); +static int ufs_qcom_set_core_clk_ctrl(struct ufs_hba *hba, bool is_scale_up, unsigned long freq); static struct ufs_qcom_host *rcdev_to_ufs_host(struct reset_controller_dev *rcd) { @@ -506,10 +508,9 @@ static int ufs_qcom_power_up_sequence(struct ufs_hba *hba) if (ret) return ret; - if (phy->power_count) { + if (phy->power_count) phy_power_off(phy); - phy_exit(phy); - } + /* phy initialization - calibrate the phy */ ret = phy_init(phy); @@ -597,13 +598,14 @@ static int ufs_qcom_hce_enable_notify(struct ufs_hba *hba, * * @hba: host controller instance * @is_pre_scale_up: flag to check if pre scale up condition. + * @freq: target opp freq * Return: zero for success and non-zero in case of a failure. */ -static int ufs_qcom_cfg_timers(struct ufs_hba *hba, bool is_pre_scale_up) +static int ufs_qcom_cfg_timers(struct ufs_hba *hba, bool is_pre_scale_up, unsigned long freq) { struct ufs_qcom_host *host = ufshcd_get_variant(hba); struct ufs_clk_info *clki; - unsigned long core_clk_rate = 0; + unsigned long clk_freq = 0; u32 core_clk_cycles_per_us; /* @@ -615,22 +617,34 @@ static int ufs_qcom_cfg_timers(struct ufs_hba *hba, bool is_pre_scale_up) if (host->hw_ver.major < 4 && !ufshcd_is_intr_aggr_allowed(hba)) return 0; + if (hba->use_pm_opp && freq != ULONG_MAX) { + clk_freq = ufs_qcom_opp_freq_to_clk_freq(hba, freq, "core_clk"); + if (clk_freq) + goto cfg_timers; + } + list_for_each_entry(clki, &hba->clk_list_head, list) { if (!strcmp(clki->name, "core_clk")) { + if (freq == ULONG_MAX) { + clk_freq = clki->max_freq; + break; + } + if (is_pre_scale_up) - core_clk_rate = clki->max_freq; + clk_freq = clki->max_freq; else - core_clk_rate = clk_get_rate(clki->clk); + clk_freq = clk_get_rate(clki->clk); break; } } +cfg_timers: /* If frequency is smaller than 1MHz, set to 1MHz */ - if (core_clk_rate < DEFAULT_CLK_RATE_HZ) - core_clk_rate = DEFAULT_CLK_RATE_HZ; + if (clk_freq < DEFAULT_CLK_RATE_HZ) + clk_freq = DEFAULT_CLK_RATE_HZ; - core_clk_cycles_per_us = core_clk_rate / USEC_PER_SEC; + core_clk_cycles_per_us = clk_freq / USEC_PER_SEC; if (ufshcd_readl(hba, REG_UFS_SYS1CLK_1US) != core_clk_cycles_per_us) { ufshcd_writel(hba, core_clk_cycles_per_us, REG_UFS_SYS1CLK_1US); /* @@ -650,13 +664,13 @@ static int ufs_qcom_link_startup_notify(struct ufs_hba *hba, switch (status) { case PRE_CHANGE: - if (ufs_qcom_cfg_timers(hba, false)) { + if (ufs_qcom_cfg_timers(hba, false, ULONG_MAX)) { dev_err(hba->dev, "%s: ufs_qcom_cfg_timers() failed\n", __func__); return -EINVAL; } - err = ufs_qcom_set_core_clk_ctrl(hba, ULONG_MAX); + err = ufs_qcom_set_core_clk_ctrl(hba, true, ULONG_MAX); if (err) dev_err(hba->dev, "cfg core clk ctrl failed\n"); /* @@ -928,17 +942,6 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba, break; case POST_CHANGE: - if (ufs_qcom_cfg_timers(hba, false)) { - dev_err(hba->dev, "%s: ufs_qcom_cfg_timers() failed\n", - __func__); - /* - * we return error code at the end of the routine, - * but continue to configure UFS_PHY_TX_LANE_ENABLE - * and bus voting as usual - */ - ret = -EINVAL; - } - /* cache the power mode parameters to use internally */ memcpy(&host->dev_req_params, dev_req_params, sizeof(*dev_req_params)); @@ -1414,29 +1417,46 @@ static int ufs_qcom_set_clk_40ns_cycles(struct ufs_hba *hba, return ufshcd_dme_set(hba, UIC_ARG_MIB(PA_VS_CORE_CLK_40NS_CYCLES), reg); } -static int ufs_qcom_set_core_clk_ctrl(struct ufs_hba *hba, unsigned long freq) +static int ufs_qcom_set_core_clk_ctrl(struct ufs_hba *hba, bool is_scale_up, unsigned long freq) { struct ufs_qcom_host *host = ufshcd_get_variant(hba); struct list_head *head = &hba->clk_list_head; struct ufs_clk_info *clki; u32 cycles_in_1us = 0; u32 core_clk_ctrl_reg; + unsigned long clk_freq; int err; + if (hba->use_pm_opp && freq != ULONG_MAX) { + clk_freq = ufs_qcom_opp_freq_to_clk_freq(hba, freq, "core_clk_unipro"); + if (clk_freq) { + cycles_in_1us = ceil(clk_freq, HZ_PER_MHZ); + goto set_core_clk_ctrl; + } + } + list_for_each_entry(clki, head, list) { if (!IS_ERR_OR_NULL(clki->clk) && !strcmp(clki->name, "core_clk_unipro")) { - if (!clki->max_freq) + if (!clki->max_freq) { cycles_in_1us = 150; /* default for backwards compatibility */ - else if (freq == ULONG_MAX) + break; + } + + if (freq == ULONG_MAX) { cycles_in_1us = ceil(clki->max_freq, HZ_PER_MHZ); - else - cycles_in_1us = ceil(freq, HZ_PER_MHZ); + break; + } + if (is_scale_up) + cycles_in_1us = ceil(clki->max_freq, HZ_PER_MHZ); + else + cycles_in_1us = ceil(clk_get_rate(clki->clk), HZ_PER_MHZ); break; } } +set_core_clk_ctrl: err = ufshcd_dme_get(hba, UIC_ARG_MIB(DME_VS_CORE_CLK_CTRL), &core_clk_ctrl_reg); @@ -1473,13 +1493,13 @@ static int ufs_qcom_clk_scale_up_pre_change(struct ufs_hba *hba, unsigned long f { int ret; - ret = ufs_qcom_cfg_timers(hba, true); + ret = ufs_qcom_cfg_timers(hba, true, freq); if (ret) { dev_err(hba->dev, "%s ufs cfg timer failed\n", __func__); return ret; } /* set unipro core clock attributes and clear clock divider */ - return ufs_qcom_set_core_clk_ctrl(hba, freq); + return ufs_qcom_set_core_clk_ctrl(hba, true, freq); } static int ufs_qcom_clk_scale_up_post_change(struct ufs_hba *hba) @@ -1510,8 +1530,15 @@ static int ufs_qcom_clk_scale_down_pre_change(struct ufs_hba *hba) static int ufs_qcom_clk_scale_down_post_change(struct ufs_hba *hba, unsigned long freq) { + int ret; + + ret = ufs_qcom_cfg_timers(hba, false, freq); + if (ret) { + dev_err(hba->dev, "%s: ufs_qcom_cfg_timers() failed\n", __func__); + return ret; + } /* set unipro core clock attributes and clear clock divider */ - return ufs_qcom_set_core_clk_ctrl(hba, freq); + return ufs_qcom_set_core_clk_ctrl(hba, false, freq); } static int ufs_qcom_clk_scale_notify(struct ufs_hba *hba, bool scale_up, @@ -2092,11 +2119,53 @@ static int ufs_qcom_config_esi(struct ufs_hba *hba) return 0; } +static unsigned long ufs_qcom_opp_freq_to_clk_freq(struct ufs_hba *hba, + unsigned long freq, char *name) +{ + struct ufs_clk_info *clki; + struct dev_pm_opp *opp; + unsigned long clk_freq; + int idx = 0; + bool found = false; + + opp = dev_pm_opp_find_freq_exact_indexed(hba->dev, freq, 0, true); + if (IS_ERR(opp)) { + dev_err(hba->dev, "Failed to find OPP for exact frequency %lu\n", freq); + return 0; + } + + list_for_each_entry(clki, &hba->clk_list_head, list) { + if (!strcmp(clki->name, name)) { + found = true; + break; + } + + idx++; + } + + if (!found) { + dev_err(hba->dev, "Failed to find clock '%s' in clk list\n", name); + dev_pm_opp_put(opp); + return 0; + } + + clk_freq = dev_pm_opp_get_freq_indexed(opp, idx); + + dev_pm_opp_put(opp); + + return clk_freq; +} + static u32 ufs_qcom_freq_to_gear_speed(struct ufs_hba *hba, unsigned long freq) { - u32 gear = 0; + u32 gear = UFS_HS_DONT_CHANGE; + unsigned long unipro_freq; - switch (freq) { + if (!hba->use_pm_opp) + return gear; + + unipro_freq = ufs_qcom_opp_freq_to_clk_freq(hba, freq, "core_clk_unipro"); + switch (unipro_freq) { case 403000000: gear = UFS_HS_G5; break; @@ -2116,10 +2185,10 @@ static u32 ufs_qcom_freq_to_gear_speed(struct ufs_hba *hba, unsigned long freq) break; default: dev_err(hba->dev, "%s: Unsupported clock freq : %lu\n", __func__, freq); - break; + return UFS_HS_DONT_CHANGE; } - return gear; + return min_t(u32, gear, hba->max_pwr_info.info.gear_rx); } /* diff --git a/drivers/uio/uio_hv_generic.c b/drivers/uio/uio_hv_generic.c index aac67a4413ce..f19efad4d6f8 100644 --- a/drivers/uio/uio_hv_generic.c +++ b/drivers/uio/uio_hv_generic.c @@ -65,6 +65,16 @@ struct hv_uio_private_data { char send_name[32]; }; +static void set_event(struct vmbus_channel *channel, s32 irq_state) +{ + channel->inbound.ring_buffer->interrupt_mask = !irq_state; + if (!channel->offermsg.monitor_allocated && irq_state) { + /* MB is needed for host to see the interrupt mask first */ + virt_mb(); + vmbus_set_event(channel); + } +} + /* * This is the irqcontrol callback to be registered to uio_info. * It can be used to disable/enable interrupt from user space processes. @@ -79,12 +89,15 @@ hv_uio_irqcontrol(struct uio_info *info, s32 irq_state) { struct hv_uio_private_data *pdata = info->priv; struct hv_device *dev = pdata->device; + struct vmbus_channel *primary, *sc; - dev->channel->inbound.ring_buffer->interrupt_mask = !irq_state; - virt_mb(); + primary = dev->channel; + set_event(primary, irq_state); - if (!dev->channel->offermsg.monitor_allocated && irq_state) - vmbus_setevent(dev->channel); + mutex_lock(&vmbus_connection.channel_mutex); + list_for_each_entry(sc, &primary->sc_list, sc_list) + set_event(sc, irq_state); + mutex_unlock(&vmbus_connection.channel_mutex); return 0; } @@ -95,12 +108,19 @@ hv_uio_irqcontrol(struct uio_info *info, s32 irq_state) static void hv_uio_channel_cb(void *context) { struct vmbus_channel *chan = context; - struct hv_device *hv_dev = chan->device_obj; - struct hv_uio_private_data *pdata = hv_get_drvdata(hv_dev); + struct hv_device *hv_dev; + struct hv_uio_private_data *pdata; chan->inbound.ring_buffer->interrupt_mask = 1; virt_mb(); + /* + * The callback may come from a subchannel, in which case look + * for the hv device in the primary channel + */ + hv_dev = chan->primary_channel ? + chan->primary_channel->device_obj : chan->device_obj; + pdata = hv_get_drvdata(hv_dev); uio_event_notify(&pdata->info); } diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c index b7f940486414..a12ab90b3db7 100644 --- a/drivers/usb/atm/cxacru.c +++ b/drivers/usb/atm/cxacru.c @@ -582,7 +582,7 @@ struct cxacru_timer { static void cxacru_timeout_kill(struct timer_list *t) { - struct cxacru_timer *timer = from_timer(timer, t, timer); + struct cxacru_timer *timer = timer_container_of(timer, t, timer); usb_unlink_urb(timer->urb); } diff --git a/drivers/usb/atm/speedtch.c b/drivers/usb/atm/speedtch.c index 27e3d35ee7dd..773ac2725532 100644 --- a/drivers/usb/atm/speedtch.c +++ b/drivers/usb/atm/speedtch.c @@ -559,8 +559,9 @@ static void speedtch_check_status(struct work_struct *work) static void speedtch_status_poll(struct timer_list *t) { - struct speedtch_instance_data *instance = from_timer(instance, t, - status_check_timer); + struct speedtch_instance_data *instance = timer_container_of(instance, + t, + status_check_timer); schedule_work(&instance->status_check_work); @@ -573,8 +574,9 @@ static void speedtch_status_poll(struct timer_list *t) static void speedtch_resubmit_int(struct timer_list *t) { - struct speedtch_instance_data *instance = from_timer(instance, t, - resubmit_timer); + struct speedtch_instance_data *instance = timer_container_of(instance, + t, + resubmit_timer); struct urb *int_urb = instance->int_urb; int ret; diff --git a/drivers/usb/atm/usbatm.c b/drivers/usb/atm/usbatm.c index a6a05e85ef8c..5f3ad9a99d9e 100644 --- a/drivers/usb/atm/usbatm.c +++ b/drivers/usb/atm/usbatm.c @@ -993,7 +993,7 @@ static int usbatm_heavy_init(struct usbatm_data *instance) static void usbatm_tasklet_schedule(struct timer_list *t) { - struct usbatm_channel *channel = from_timer(channel, t, delay); + struct usbatm_channel *channel = timer_container_of(channel, t, delay); tasklet_schedule(&channel->tasklet); } diff --git a/drivers/usb/cdns3/cdns3-plat.c b/drivers/usb/cdns3/cdns3-plat.c index 59ec505e198a..735df88774e4 100644 --- a/drivers/usb/cdns3/cdns3-plat.c +++ b/drivers/usb/cdns3/cdns3-plat.c @@ -179,8 +179,6 @@ err_phy3_init: /** * cdns3_plat_remove() - unbind drd driver and clean up * @pdev: Pointer to Linux platform device - * - * Returns 0 on success otherwise negative errno */ static void cdns3_plat_remove(struct platform_device *pdev) { diff --git a/drivers/usb/cdns3/cdnsp-gadget.c b/drivers/usb/cdns3/cdnsp-gadget.c index 4824a10df07e..55f95f41b3b4 100644 --- a/drivers/usb/cdns3/cdnsp-gadget.c +++ b/drivers/usb/cdns3/cdnsp-gadget.c @@ -29,7 +29,8 @@ unsigned int cdnsp_port_speed(unsigned int port_status) { /*Detect gadget speed based on PORTSC register*/ - if (DEV_SUPERSPEEDPLUS(port_status)) + if (DEV_SUPERSPEEDPLUS(port_status) || + DEV_SSP_GEN1x2(port_status) || DEV_SSP_GEN2x2(port_status)) return USB_SPEED_SUPER_PLUS; else if (DEV_SUPERSPEED(port_status)) return USB_SPEED_SUPER; @@ -547,6 +548,7 @@ int cdnsp_wait_for_cmd_compl(struct cdnsp_device *pdev) dma_addr_t cmd_deq_dma; union cdnsp_trb *event; u32 cycle_state; + u32 retry = 10; int ret, val; u64 cmd_dma; u32 flags; @@ -578,8 +580,23 @@ int cdnsp_wait_for_cmd_compl(struct cdnsp_device *pdev) flags = le32_to_cpu(event->event_cmd.flags); /* Check the owner of the TRB. */ - if ((flags & TRB_CYCLE) != cycle_state) + if ((flags & TRB_CYCLE) != cycle_state) { + /* + * Give some extra time to get chance controller + * to finish command before returning error code. + * Checking CMD_RING_BUSY is not sufficient because + * this bit is cleared to '0' when the Command + * Descriptor has been executed by controller + * and not when command completion event has + * be added to event ring. + */ + if (retry--) { + udelay(20); + continue; + } + return -EINVAL; + } cmd_dma = le64_to_cpu(event->event_cmd.cmd_trb); diff --git a/drivers/usb/cdns3/cdnsp-gadget.h b/drivers/usb/cdns3/cdnsp-gadget.h index 12534be52f39..2afa3e558f85 100644 --- a/drivers/usb/cdns3/cdnsp-gadget.h +++ b/drivers/usb/cdns3/cdnsp-gadget.h @@ -285,11 +285,15 @@ struct cdnsp_port_regs { #define XDEV_HS (0x3 << 10) #define XDEV_SS (0x4 << 10) #define XDEV_SSP (0x5 << 10) +#define XDEV_SSP1x2 (0x6 << 10) +#define XDEV_SSP2x2 (0x7 << 10) #define DEV_UNDEFSPEED(p) (((p) & DEV_SPEED_MASK) == (0x0 << 10)) #define DEV_FULLSPEED(p) (((p) & DEV_SPEED_MASK) == XDEV_FS) #define DEV_HIGHSPEED(p) (((p) & DEV_SPEED_MASK) == XDEV_HS) #define DEV_SUPERSPEED(p) (((p) & DEV_SPEED_MASK) == XDEV_SS) #define DEV_SUPERSPEEDPLUS(p) (((p) & DEV_SPEED_MASK) == XDEV_SSP) +#define DEV_SSP_GEN1x2(p) (((p) & DEV_SPEED_MASK) == XDEV_SSP1x2) +#define DEV_SSP_GEN2x2(p) (((p) & DEV_SPEED_MASK) == XDEV_SSP2x2) #define DEV_SUPERSPEED_ANY(p) (((p) & DEV_SPEED_MASK) >= XDEV_SS) #define DEV_PORT_SPEED(p) (((p) >> 10) & 0x0f) /* Port Link State Write Strobe - set this when changing link state */ diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c index 4f8bfd242b59..780f4d151345 100644 --- a/drivers/usb/chipidea/ci_hdrc_imx.c +++ b/drivers/usb/chipidea/ci_hdrc_imx.c @@ -6,6 +6,7 @@ */ #include <linux/module.h> +#include <linux/irq.h> #include <linux/of.h> #include <linux/of_platform.h> #include <linux/platform_device.h> @@ -98,6 +99,7 @@ struct ci_hdrc_imx_data { struct clk *clk; struct clk *clk_wakeup; struct imx_usbmisc_data *usbmisc_data; + int wakeup_irq; bool supports_runtime_pm; bool override_phy_control; bool in_lpm; @@ -336,6 +338,16 @@ static int ci_hdrc_imx_notify_event(struct ci_hdrc *ci, unsigned int event) return ret; } +static irqreturn_t ci_wakeup_irq_handler(int irq, void *data) +{ + struct ci_hdrc_imx_data *imx_data = data; + + disable_irq_nosync(irq); + pm_runtime_resume(&imx_data->ci_pdev->dev); + + return IRQ_HANDLED; +} + static void ci_hdrc_imx_disable_regulator(void *arg) { struct ci_hdrc_imx_data *data = arg; @@ -494,6 +506,16 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) if (pdata.flags & CI_HDRC_SUPPORTS_RUNTIME_PM) data->supports_runtime_pm = true; + data->wakeup_irq = platform_get_irq_optional(pdev, 1); + if (data->wakeup_irq > 0) { + ret = devm_request_threaded_irq(dev, data->wakeup_irq, + NULL, ci_wakeup_irq_handler, + IRQF_ONESHOT | IRQF_NO_AUTOEN, + pdata.name, data); + if (ret) + goto err_clk; + } + ret = imx_usbmisc_init(data->usbmisc_data); if (ret) { dev_err(dev, "usbmisc init failed, ret=%d\n", ret); @@ -602,6 +624,10 @@ static int imx_controller_suspend(struct device *dev, } imx_disable_unprepare_clks(dev); + + if (data->wakeup_irq > 0) + enable_irq(data->wakeup_irq); + if (data->plat_data->flags & CI_HDRC_PMQOS) cpu_latency_qos_remove_request(&data->pm_qos_req); @@ -626,6 +652,10 @@ static int imx_controller_resume(struct device *dev, if (data->plat_data->flags & CI_HDRC_PMQOS) cpu_latency_qos_add_request(&data->pm_qos_req, 0); + if (data->wakeup_irq > 0 && + !irqd_irq_disabled(irq_get_irq_data(data->wakeup_irq))) + disable_irq_nosync(data->wakeup_irq); + ret = imx_prepare_enable_clks(dev); if (ret) return ret; @@ -661,6 +691,10 @@ static int ci_hdrc_imx_suspend(struct device *dev) return ret; pinctrl_pm_select_sleep_state(dev); + + if (data->wakeup_irq > 0 && device_may_wakeup(dev)) + enable_irq_wake(data->wakeup_irq); + return ret; } @@ -669,6 +703,9 @@ static int ci_hdrc_imx_resume(struct device *dev) struct ci_hdrc_imx_data *data = dev_get_drvdata(dev); int ret; + if (data->wakeup_irq > 0 && device_may_wakeup(dev)) + disable_irq_wake(data->wakeup_irq); + pinctrl_pm_select_default_state(dev); ret = imx_controller_resume(dev, PMSG_RESUME); if (!ret && data->supports_runtime_pm) { diff --git a/drivers/usb/chipidea/usbmisc_imx.c b/drivers/usb/chipidea/usbmisc_imx.c index 6243d8005f5d..118b9a68496b 100644 --- a/drivers/usb/chipidea/usbmisc_imx.c +++ b/drivers/usb/chipidea/usbmisc_imx.c @@ -139,6 +139,22 @@ #define MX6_USB_OTG_WAKEUP_BITS (MX6_BM_WAKEUP_ENABLE | MX6_BM_VBUS_WAKEUP | \ MX6_BM_ID_WAKEUP | MX6SX_BM_DPDM_WAKEUP_EN) +/* + * HSIO Block Control Register + */ + +#define BLKCTL_USB_WAKEUP_CTRL 0x0 +#define BLKCTL_OTG_WAKE_ENABLE BIT(31) +#define BLKCTL_OTG_VBUS_SESSVALID BIT(4) +#define BLKCTL_OTG_ID_WAKEUP_EN BIT(2) +#define BLKCTL_OTG_VBUS_WAKEUP_EN BIT(1) +#define BLKCTL_OTG_DPDM_WAKEUP_EN BIT(0) + +#define BLKCTL_WAKEUP_SOURCE (BLKCTL_OTG_WAKE_ENABLE | \ + BLKCTL_OTG_ID_WAKEUP_EN | \ + BLKCTL_OTG_VBUS_WAKEUP_EN | \ + BLKCTL_OTG_DPDM_WAKEUP_EN) + struct usbmisc_ops { /* It's called once when probe a usb device */ int (*init)(struct imx_usbmisc_data *data); @@ -159,6 +175,7 @@ struct usbmisc_ops { struct imx_usbmisc { void __iomem *base; + void __iomem *blkctl; spinlock_t lock; const struct usbmisc_ops *ops; }; @@ -1016,6 +1033,44 @@ static int usbmisc_imx6sx_power_lost_check(struct imx_usbmisc_data *data) return 0; } +static u32 usbmisc_blkctl_wakeup_setting(struct imx_usbmisc_data *data) +{ + u32 wakeup_setting = BLKCTL_WAKEUP_SOURCE; + + if (data->ext_id || data->available_role != USB_DR_MODE_OTG) + wakeup_setting &= ~BLKCTL_OTG_ID_WAKEUP_EN; + + if (data->ext_vbus || data->available_role == USB_DR_MODE_HOST) + wakeup_setting &= ~BLKCTL_OTG_VBUS_WAKEUP_EN; + + /* Select session valid as VBUS wakeup source */ + wakeup_setting |= BLKCTL_OTG_VBUS_SESSVALID; + + return wakeup_setting; +} + +static int usbmisc_imx95_set_wakeup(struct imx_usbmisc_data *data, bool enabled) +{ + struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev); + unsigned long flags; + u32 val; + + if (!usbmisc->blkctl) + return 0; + + spin_lock_irqsave(&usbmisc->lock, flags); + val = readl(usbmisc->blkctl + BLKCTL_USB_WAKEUP_CTRL); + val &= ~BLKCTL_WAKEUP_SOURCE; + + if (enabled) + val |= usbmisc_blkctl_wakeup_setting(data); + + writel(val, usbmisc->blkctl + BLKCTL_USB_WAKEUP_CTRL); + spin_unlock_irqrestore(&usbmisc->lock, flags); + + return 0; +} + static const struct usbmisc_ops imx25_usbmisc_ops = { .init = usbmisc_imx25_init, .post = usbmisc_imx25_post, @@ -1068,6 +1123,14 @@ static const struct usbmisc_ops imx7ulp_usbmisc_ops = { .power_lost_check = usbmisc_imx7d_power_lost_check, }; +static const struct usbmisc_ops imx95_usbmisc_ops = { + .init = usbmisc_imx7d_init, + .set_wakeup = usbmisc_imx95_set_wakeup, + .charger_detection = imx7d_charger_detection, + .power_lost_check = usbmisc_imx7d_power_lost_check, + .vbus_comparator_on = usbmisc_imx7d_vbus_comparator_on, +}; + static inline bool is_imx53_usbmisc(struct imx_usbmisc_data *data) { struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev); @@ -1289,6 +1352,10 @@ static const struct of_device_id usbmisc_imx_dt_ids[] = { .compatible = "fsl,imx8ulp-usbmisc", .data = &imx7ulp_usbmisc_ops, }, + { + .compatible = "fsl,imx95-usbmisc", + .data = &imx95_usbmisc_ops, + }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, usbmisc_imx_dt_ids); @@ -1296,6 +1363,7 @@ MODULE_DEVICE_TABLE(of, usbmisc_imx_dt_ids); static int usbmisc_imx_probe(struct platform_device *pdev) { struct imx_usbmisc *data; + struct resource *res; data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); if (!data) @@ -1307,6 +1375,15 @@ static int usbmisc_imx_probe(struct platform_device *pdev) if (IS_ERR(data->base)) return PTR_ERR(data->base); + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (res) { + data->blkctl = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(data->blkctl)) + return PTR_ERR(data->blkctl); + } else if (device_is_compatible(&pdev->dev, "fsl,imx95-usbmisc")) { + dev_warn(&pdev->dev, "wakeup setting is missing\n"); + } + data->ops = of_device_get_match_data(&pdev->dev); platform_set_drvdata(pdev, data); diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c index 16e7fa4d488d..ecd6d1f39e49 100644 --- a/drivers/usb/class/cdc-wdm.c +++ b/drivers/usb/class/cdc-wdm.c @@ -92,7 +92,6 @@ struct wdm_device { u16 wMaxCommand; u16 wMaxPacketSize; __le16 inum; - int reslength; int length; int read; int count; @@ -214,6 +213,11 @@ static void wdm_in_callback(struct urb *urb) if (desc->rerr == 0 && status != -EPIPE) desc->rerr = status; + if (length == 0) { + dev_dbg(&desc->intf->dev, "received ZLP\n"); + goto skip_zlp; + } + if (length + desc->length > desc->wMaxCommand) { /* The buffer would overflow */ set_bit(WDM_OVERFLOW, &desc->flags); @@ -222,18 +226,18 @@ static void wdm_in_callback(struct urb *urb) if (!test_bit(WDM_OVERFLOW, &desc->flags)) { memmove(desc->ubuf + desc->length, desc->inbuf, length); desc->length += length; - desc->reslength = length; } } skip_error: if (desc->rerr) { /* - * Since there was an error, userspace may decide to not read - * any data after poll'ing. + * If there was a ZLP or an error, userspace may decide to not + * read any data after poll'ing. * We should respond to further attempts from the device to send * data, so that we can get unstuck. */ +skip_zlp: schedule_work(&desc->service_outs_intr); } else { set_bit(WDM_READ, &desc->flags); @@ -585,15 +589,6 @@ retry: goto retry; } - if (!desc->reslength) { /* zero length read */ - dev_dbg(&desc->intf->dev, "zero length - clearing WDM_READ\n"); - clear_bit(WDM_READ, &desc->flags); - rv = service_outstanding_interrupt(desc); - spin_unlock_irq(&desc->iuspin); - if (rv < 0) - goto err; - goto retry; - } cntr = desc->length; spin_unlock_irq(&desc->iuspin); } @@ -1016,7 +1011,7 @@ static void service_interrupt_work(struct work_struct *work) spin_lock_irq(&desc->iuspin); service_outstanding_interrupt(desc); - if (!desc->resp_count) { + if (!desc->resp_count && (desc->length || desc->rerr)) { set_bit(WDM_READ, &desc->flags); wake_up(&desc->wait); } diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c index 740d2d2b19fb..75de29725a45 100644 --- a/drivers/usb/class/usbtmc.c +++ b/drivers/usb/class/usbtmc.c @@ -483,6 +483,7 @@ static int usbtmc_get_stb(struct usbtmc_file_data *file_data, __u8 *stb) u8 tag; int rv; long wait_rv; + unsigned long expire; dev_dbg(dev, "Enter ioctl_read_stb iin_ep_present: %d\n", data->iin_ep_present); @@ -512,10 +513,11 @@ static int usbtmc_get_stb(struct usbtmc_file_data *file_data, __u8 *stb) } if (data->iin_ep_present) { + expire = msecs_to_jiffies(file_data->timeout); wait_rv = wait_event_interruptible_timeout( data->waitq, atomic_read(&data->iin_data_valid) != 0, - file_data->timeout); + expire); if (wait_rv < 0) { dev_dbg(dev, "wait interrupted %ld\n", wait_rv); rv = wait_rv; @@ -563,14 +565,15 @@ static int usbtmc488_ioctl_read_stb(struct usbtmc_file_data *file_data, rv = usbtmc_get_stb(file_data, &stb); - if (rv > 0) { - srq_asserted = atomic_xchg(&file_data->srq_asserted, - srq_asserted); - if (srq_asserted) - stb |= 0x40; /* Set RQS bit */ + if (rv < 0) + return rv; + + srq_asserted = atomic_xchg(&file_data->srq_asserted, srq_asserted); + if (srq_asserted) + stb |= 0x40; /* Set RQS bit */ + + rv = put_user(stb, (__u8 __user *)arg); - rv = put_user(stb, (__u8 __user *)arg); - } return rv; } @@ -2199,7 +2202,7 @@ static long usbtmc_ioctl(struct file *file, unsigned int cmd, unsigned long arg) case USBTMC_IOCTL_GET_STB: retval = usbtmc_get_stb(file_data, &tmp_byte); - if (retval > 0) + if (!retval) retval = put_user(tmp_byte, (__u8 __user *)arg); break; diff --git a/drivers/usb/common/usb-conn-gpio.c b/drivers/usb/common/usb-conn-gpio.c index 1e36be2a28fd..421c3af38e06 100644 --- a/drivers/usb/common/usb-conn-gpio.c +++ b/drivers/usb/common/usb-conn-gpio.c @@ -21,6 +21,9 @@ #include <linux/regulator/consumer.h> #include <linux/string_choices.h> #include <linux/usb/role.h> +#include <linux/idr.h> + +static DEFINE_IDA(usb_conn_ida); #define USB_GPIO_DEB_MS 20 /* ms */ #define USB_GPIO_DEB_US ((USB_GPIO_DEB_MS) * 1000) /* us */ @@ -30,6 +33,7 @@ struct usb_conn_info { struct device *dev; + int conn_id; /* store the IDA-allocated ID */ struct usb_role_switch *role_sw; enum usb_role last_role; struct regulator *vbus; @@ -161,7 +165,17 @@ static int usb_conn_psy_register(struct usb_conn_info *info) .fwnode = dev_fwnode(dev), }; - desc->name = "usb-charger"; + info->conn_id = ida_alloc(&usb_conn_ida, GFP_KERNEL); + if (info->conn_id < 0) + return info->conn_id; + + desc->name = devm_kasprintf(dev, GFP_KERNEL, "usb-charger-%d", + info->conn_id); + if (!desc->name) { + ida_free(&usb_conn_ida, info->conn_id); + return -ENOMEM; + } + desc->properties = usb_charger_properties; desc->num_properties = ARRAY_SIZE(usb_charger_properties); desc->get_property = usb_charger_get_property; @@ -169,8 +183,10 @@ static int usb_conn_psy_register(struct usb_conn_info *info) cfg.drv_data = info; info->charger = devm_power_supply_register(dev, desc, &cfg); - if (IS_ERR(info->charger)) - dev_err(dev, "Unable to register charger\n"); + if (IS_ERR(info->charger)) { + dev_err(dev, "Unable to register charger %d\n", info->conn_id); + ida_free(&usb_conn_ida, info->conn_id); + } return PTR_ERR_OR_ZERO(info->charger); } @@ -278,6 +294,9 @@ static void usb_conn_remove(struct platform_device *pdev) cancel_delayed_work_sync(&info->dw_det); + if (info->charger) + ida_free(&usb_conn_ida, info->conn_id); + if (info->last_role == USB_ROLE_HOST && info->vbus) regulator_disable(info->vbus); diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index 13bd4ec4ea5f..fc0cfd94cbab 100644 --- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c @@ -307,7 +307,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, goto skip_to_next_endpoint_or_interface_descriptor; } - i = d->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; + i = usb_endpoint_num(d); if (i == 0) { dev_notice(ddev, "config %d interface %d altsetting %d has an " "invalid descriptor for endpoint zero, skipping\n", diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index a63c793bac21..c22de97432a0 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -775,7 +775,7 @@ EXPORT_SYMBOL_GPL(usb_hcd_poll_rh_status); /* timer callback */ static void rh_timer_func (struct timer_list *t) { - struct usb_hcd *_hcd = from_timer(_hcd, t, rh_timer); + struct usb_hcd *_hcd = timer_container_of(_hcd, t, rh_timer); usb_hcd_poll_rh_status(_hcd); } diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 0e1dd6ef60a7..770d1e91183c 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -697,7 +697,7 @@ static void hub_resubmit_irq_urb(struct usb_hub *hub) static void hub_retry_irq_urb(struct timer_list *t) { - struct usb_hub *hub = from_timer(hub, t, irq_urb_retry); + struct usb_hub *hub = timer_container_of(hub, t, irq_urb_retry); hub_resubmit_irq_urb(hub); } @@ -4160,7 +4160,7 @@ static int usb_set_device_initiated_lpm(struct usb_device *udev, "for unconfigured device.\n", __func__, str_enable_disable(enable), usb3_lpm_names[state]); - return 0; + return -EINVAL; } if (enable) { @@ -4234,9 +4234,9 @@ static int usb_set_lpm_timeout(struct usb_device *udev, } /* - * Don't allow device intiated U1/U2 if the system exit latency + one bus - * interval is greater than the minimum service interval of any active - * periodic endpoint. See USB 3.2 section 9.4.9 + * Don't allow device intiated U1/U2 if device isn't in the configured state, + * or the system exit latency + one bus interval is greater than the minimum + * service interval of any active periodic endpoint. See USB 3.2 section 9.4.9 */ static bool usb_device_may_initiate_lpm(struct usb_device *udev, enum usb3_link_state state) @@ -4244,7 +4244,7 @@ static bool usb_device_may_initiate_lpm(struct usb_device *udev, unsigned int sel; /* us */ int i, j; - if (!udev->lpm_devinit_allow) + if (!udev->lpm_devinit_allow || !udev->actconfig) return false; if (state == USB3_LPM_U1) @@ -4292,7 +4292,7 @@ static bool usb_device_may_initiate_lpm(struct usb_device *udev, * driver know about it. If that call fails, it should be harmless, and just * take up more slightly more bus bandwidth for unnecessary U1/U2 exit latency. */ -static void usb_enable_link_state(struct usb_hcd *hcd, struct usb_device *udev, +static int usb_enable_link_state(struct usb_hcd *hcd, struct usb_device *udev, enum usb3_link_state state) { int timeout; @@ -4301,7 +4301,7 @@ static void usb_enable_link_state(struct usb_hcd *hcd, struct usb_device *udev, /* Skip if the device BOS descriptor couldn't be read */ if (!udev->bos) - return; + return -EINVAL; u1_mel = udev->bos->ss_cap->bU1devExitLat; u2_mel = udev->bos->ss_cap->bU2DevExitLat; @@ -4312,7 +4312,7 @@ static void usb_enable_link_state(struct usb_hcd *hcd, struct usb_device *udev, */ if ((state == USB3_LPM_U1 && u1_mel == 0) || (state == USB3_LPM_U2 && u2_mel == 0)) - return; + return -EINVAL; /* We allow the host controller to set the U1/U2 timeout internally * first, so that it can change its schedule to account for the @@ -4323,13 +4323,13 @@ static void usb_enable_link_state(struct usb_hcd *hcd, struct usb_device *udev, /* xHCI host controller doesn't want to enable this LPM state. */ if (timeout == 0) - return; + return -EINVAL; if (timeout < 0) { dev_warn(&udev->dev, "Could not enable %s link state, " "xHCI error %i.\n", usb3_lpm_names[state], timeout); - return; + return timeout; } if (usb_set_lpm_timeout(udev, state, timeout)) { @@ -4338,29 +4338,15 @@ static void usb_enable_link_state(struct usb_hcd *hcd, struct usb_device *udev, * host know that this link state won't be enabled. */ hcd->driver->disable_usb3_lpm_timeout(hcd, udev, state); - return; - } - - /* Only a configured device will accept the Set Feature - * U1/U2_ENABLE - */ - if (udev->actconfig && - usb_device_may_initiate_lpm(udev, state)) { - if (usb_set_device_initiated_lpm(udev, state, true)) { - /* - * Request to enable device initiated U1/U2 failed, - * better to turn off lpm in this case. - */ - usb_set_lpm_timeout(udev, state, 0); - hcd->driver->disable_usb3_lpm_timeout(hcd, udev, state); - return; - } + return -EBUSY; } if (state == USB3_LPM_U1) udev->usb3_lpm_u1_enabled = 1; else if (state == USB3_LPM_U2) udev->usb3_lpm_u2_enabled = 1; + + return 0; } /* * Disable the hub-initiated U1/U2 idle timeouts, and disable device-initiated @@ -4393,8 +4379,6 @@ static int usb_disable_link_state(struct usb_hcd *hcd, struct usb_device *udev, if (usb_set_lpm_timeout(udev, state, 0)) return -EBUSY; - usb_set_device_initiated_lpm(udev, state, false); - if (hcd->driver->disable_usb3_lpm_timeout(hcd, udev, state)) dev_warn(&udev->dev, "Could not disable xHCI %s timeout, " "bus schedule bandwidth may be impacted.\n", @@ -4424,6 +4408,7 @@ static int usb_disable_link_state(struct usb_hcd *hcd, struct usb_device *udev, int usb_disable_lpm(struct usb_device *udev) { struct usb_hcd *hcd; + int err; if (!udev || !udev->parent || udev->speed < USB_SPEED_SUPER || @@ -4441,14 +4426,19 @@ int usb_disable_lpm(struct usb_device *udev) /* If LPM is enabled, attempt to disable it. */ if (usb_disable_link_state(hcd, udev, USB3_LPM_U1)) - goto enable_lpm; + goto disable_failed; if (usb_disable_link_state(hcd, udev, USB3_LPM_U2)) - goto enable_lpm; + goto disable_failed; + + err = usb_set_device_initiated_lpm(udev, USB3_LPM_U1, false); + if (!err) + usb_set_device_initiated_lpm(udev, USB3_LPM_U2, false); return 0; -enable_lpm: - usb_enable_lpm(udev); +disable_failed: + udev->lpm_disable_count--; + return -EBUSY; } EXPORT_SYMBOL_GPL(usb_disable_lpm); @@ -4509,10 +4499,24 @@ void usb_enable_lpm(struct usb_device *udev) port_dev = hub->ports[udev->portnum - 1]; if (port_dev->usb3_lpm_u1_permit) - usb_enable_link_state(hcd, udev, USB3_LPM_U1); + if (usb_enable_link_state(hcd, udev, USB3_LPM_U1)) + return; if (port_dev->usb3_lpm_u2_permit) - usb_enable_link_state(hcd, udev, USB3_LPM_U2); + if (usb_enable_link_state(hcd, udev, USB3_LPM_U2)) + return; + + /* + * Enable device initiated U1/U2 with a SetFeature(U1/U2_ENABLE) request + * if system exit latency is short enough and device is configured + */ + if (usb_device_may_initiate_lpm(udev, USB3_LPM_U1)) { + if (usb_set_device_initiated_lpm(udev, USB3_LPM_U1, true)) + return; + + if (usb_device_may_initiate_lpm(udev, USB3_LPM_U2)) + usb_set_device_initiated_lpm(udev, USB3_LPM_U2, true); + } } EXPORT_SYMBOL_GPL(usb_enable_lpm); @@ -6133,6 +6137,7 @@ static int usb_reset_and_verify_device(struct usb_device *udev) struct usb_hub *parent_hub; struct usb_hcd *hcd = bus_to_hcd(udev->bus); struct usb_device_descriptor descriptor; + struct usb_interface *intf; struct usb_host_bos *bos; int i, j, ret = 0; int port1 = udev->portnum; @@ -6190,6 +6195,18 @@ static int usb_reset_and_verify_device(struct usb_device *udev) if (!udev->actconfig) goto done; + /* + * Some devices can't handle setting default altsetting 0 with a + * Set-Interface request. Disable host-side endpoints of those + * interfaces here. Enable and reset them back after host has set + * its internal endpoint structures during usb_hcd_alloc_bandwith() + */ + for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) { + intf = udev->actconfig->interface[i]; + if (intf->cur_altsetting->desc.bAlternateSetting == 0) + usb_disable_interface(udev, intf, true); + } + mutex_lock(hcd->bandwidth_mutex); ret = usb_hcd_alloc_bandwidth(udev, udev->actconfig, NULL, NULL); if (ret < 0) { @@ -6221,12 +6238,11 @@ static int usb_reset_and_verify_device(struct usb_device *udev) */ for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) { struct usb_host_config *config = udev->actconfig; - struct usb_interface *intf = config->interface[i]; struct usb_interface_descriptor *desc; + intf = config->interface[i]; desc = &intf->cur_altsetting->desc; if (desc->bAlternateSetting == 0) { - usb_disable_interface(udev, intf, true); usb_enable_interface(udev, intf, true); ret = 0; } else { diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index 36d3df7d040c..53d68d20fb62 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -372,6 +372,9 @@ static const struct usb_device_id usb_quirk_list[] = { /* SanDisk Corp. SanDisk 3.2Gen1 */ { USB_DEVICE(0x0781, 0x55a3), .driver_info = USB_QUIRK_DELAY_INIT }, + /* SanDisk Extreme 55AE */ + { USB_DEVICE(0x0781, 0x55ae), .driver_info = USB_QUIRK_NO_LPM }, + /* Realforce 87U Keyboard */ { USB_DEVICE(0x0853, 0x011b), .driver_info = USB_QUIRK_NO_LPM }, diff --git a/drivers/usb/core/usb-acpi.c b/drivers/usb/core/usb-acpi.c index 935c0efea0b6..ea1ce8beb0cb 100644 --- a/drivers/usb/core/usb-acpi.c +++ b/drivers/usb/core/usb-acpi.c @@ -165,6 +165,8 @@ static int usb_acpi_add_usb4_devlink(struct usb_device *udev) return 0; hub = usb_hub_to_struct_hub(udev->parent); + if (!hub) + return 0; port_dev = hub->ports[udev->portnum - 1]; struct fwnode_handle *nhi_fwnode __free(fwnode_handle) = diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 0b4685aad2d5..118fa4c93a79 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -695,15 +695,16 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent, device_set_of_node_from_dev(&dev->dev, bus->sysdev); dev_set_name(&dev->dev, "usb%d", bus->busnum); } else { + int n; + /* match any labeling on the hubs; it's one-based */ if (parent->devpath[0] == '0') { - snprintf(dev->devpath, sizeof dev->devpath, - "%d", port1); + n = snprintf(dev->devpath, sizeof(dev->devpath), "%d", port1); /* Root ports are not counted in route string */ dev->route = 0; } else { - snprintf(dev->devpath, sizeof dev->devpath, - "%s.%d", parent->devpath, port1); + n = snprintf(dev->devpath, sizeof(dev->devpath), "%s.%d", + parent->devpath, port1); /* Route string assumes hubs have less than 16 ports */ if (port1 < 15) dev->route = parent->route + @@ -712,6 +713,11 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent, dev->route = parent->route + (15 << ((parent->level - 1)*4)); } + if (n >= sizeof(dev->devpath)) { + usb_put_hcd(bus_to_hcd(bus)); + usb_put_dev(dev); + return NULL; + } dev->dev.parent = &parent->dev; dev_set_name(&dev->dev, "%d-%s", bus->busnum, dev->devpath); diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index 300ea4969f0c..d5b622f78cf3 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -4049,7 +4049,7 @@ static int dwc2_hsotg_ep_enable(struct usb_ep *ep, return -EINVAL; } - ep_type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; + ep_type = usb_endpoint_type(desc); mps = usb_endpoint_maxp(desc); mc = usb_endpoint_maxp_mult(desc); @@ -4604,6 +4604,12 @@ static int dwc2_hsotg_udc_stop(struct usb_gadget *gadget) if (!hsotg) return -ENODEV; + /* Exit clock gating when driver is stopped. */ + if (hsotg->params.power_down == DWC2_POWER_DOWN_PARAM_NONE && + hsotg->bus_suspended && !hsotg->params.no_clock_gating) { + dwc2_gadget_exit_clock_gating(hsotg, 0); + } + /* all endpoints should be shutdown */ for (ep = 1; ep < hsotg->num_of_eps; ep++) { if (hsotg->eps_in[ep]) diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c index 60ef8092259a..30eb8506617c 100644 --- a/drivers/usb/dwc2/hcd.c +++ b/drivers/usb/dwc2/hcd.c @@ -3227,7 +3227,7 @@ host: static void dwc2_wakeup_detected(struct timer_list *t) { - struct dwc2_hsotg *hsotg = from_timer(hsotg, t, wkp_timer); + struct dwc2_hsotg *hsotg = timer_container_of(hsotg, t, wkp_timer); u32 hprt0; dev_dbg(hsotg->dev, "%s()\n", __func__); diff --git a/drivers/usb/dwc2/hcd_queue.c b/drivers/usb/dwc2/hcd_queue.c index b0098792dd22..904fe0632b34 100644 --- a/drivers/usb/dwc2/hcd_queue.c +++ b/drivers/usb/dwc2/hcd_queue.c @@ -1215,7 +1215,7 @@ static void dwc2_do_unreserve(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh) */ static void dwc2_unreserve_timer_fn(struct timer_list *t) { - struct dwc2_qh *qh = from_timer(qh, t, unreserve_timer); + struct dwc2_qh *qh = timer_container_of(qh, t, unreserve_timer); struct dwc2_hsotg *hsotg = qh->hsotg; unsigned long flags; diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile index 124eda2522d9..830e6c9e5fe0 100644 --- a/drivers/usb/dwc3/Makefile +++ b/drivers/usb/dwc3/Makefile @@ -52,6 +52,7 @@ obj-$(CONFIG_USB_DWC3_MESON_G12A) += dwc3-meson-g12a.o obj-$(CONFIG_USB_DWC3_OF_SIMPLE) += dwc3-of-simple.o obj-$(CONFIG_USB_DWC3_ST) += dwc3-st.o obj-$(CONFIG_USB_DWC3_QCOM) += dwc3-qcom.o +obj-$(CONFIG_USB_DWC3_QCOM) += dwc3-qcom-legacy.o obj-$(CONFIG_USB_DWC3_IMX8MP) += dwc3-imx8mp.o obj-$(CONFIG_USB_DWC3_XILINX) += dwc3-xilinx.o obj-$(CONFIG_USB_DWC3_OCTEON) += dwc3-octeon.o diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 66a08b527165..2bc775a747f2 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -26,6 +26,7 @@ #include <linux/of_graph.h> #include <linux/acpi.h> #include <linux/pinctrl/consumer.h> +#include <linux/pinctrl/devinfo.h> #include <linux/reset.h> #include <linux/bitfield.h> @@ -36,6 +37,7 @@ #include "core.h" #include "gadget.h" +#include "glue.h" #include "io.h" #include "debug.h" @@ -1699,6 +1701,7 @@ static void dwc3_get_properties(struct dwc3 *dwc) u8 tx_thr_num_pkt_prd = 0; u8 tx_max_burst_prd = 0; u8 tx_fifo_resize_max_num; + u16 num_hc_interrupters; /* default to highest possible threshold */ lpm_nyet_threshold = 0xf; @@ -1719,6 +1722,9 @@ static void dwc3_get_properties(struct dwc3 *dwc) */ tx_fifo_resize_max_num = 6; + /* default to a single XHCI interrupter */ + num_hc_interrupters = 1; + dwc->maximum_speed = usb_get_maximum_speed(dev); dwc->max_ssp_rate = usb_get_maximum_ssp_rate(dev); dwc->dr_mode = usb_get_dr_mode(dev); @@ -1765,6 +1771,12 @@ static void dwc3_get_properties(struct dwc3 *dwc) &tx_thr_num_pkt_prd); device_property_read_u8(dev, "snps,tx-max-burst-prd", &tx_max_burst_prd); + device_property_read_u16(dev, "num-hc-interrupters", + &num_hc_interrupters); + /* DWC3 core allowed to have a max of 8 interrupters */ + if (num_hc_interrupters > 8) + num_hc_interrupters = 8; + dwc->do_fifo_resize = device_property_read_bool(dev, "tx-fifo-resize"); if (dwc->do_fifo_resize) @@ -1851,6 +1863,8 @@ static void dwc3_get_properties(struct dwc3 *dwc) dwc->tx_max_burst_prd = tx_max_burst_prd; dwc->tx_fifo_resize_max_num = tx_fifo_resize_max_num; + + dwc->num_hc_interrupters = num_hc_interrupters; } /* check whether the core supports IMOD */ @@ -2148,27 +2162,16 @@ static struct power_supply *dwc3_get_usb_power_supply(struct dwc3 *dwc) return usb_psy; } -static int dwc3_probe(struct platform_device *pdev) +int dwc3_core_probe(const struct dwc3_probe_data *data) { - struct device *dev = &pdev->dev; - struct resource *res, dwc_res; + struct dwc3 *dwc = data->dwc; + struct device *dev = dwc->dev; + struct resource dwc_res; unsigned int hw_mode; void __iomem *regs; - struct dwc3 *dwc; + struct resource *res = data->res; int ret; - dwc = devm_kzalloc(dev, sizeof(*dwc), GFP_KERNEL); - if (!dwc) - return -ENOMEM; - - dwc->dev = dev; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(dev, "missing memory resource\n"); - return -ENODEV; - } - dwc->xhci_resources[0].start = res->start; dwc->xhci_resources[0].end = dwc->xhci_resources[0].start + DWC3_XHCI_REGS_END; @@ -2208,15 +2211,17 @@ static int dwc3_probe(struct platform_device *pdev) if (IS_ERR(dwc->usb_psy)) return dev_err_probe(dev, PTR_ERR(dwc->usb_psy), "couldn't get usb power supply\n"); - dwc->reset = devm_reset_control_array_get_optional_shared(dev); - if (IS_ERR(dwc->reset)) { - ret = PTR_ERR(dwc->reset); - goto err_put_psy; - } + if (!data->ignore_clocks_and_resets) { + dwc->reset = devm_reset_control_array_get_optional_shared(dev); + if (IS_ERR(dwc->reset)) { + ret = PTR_ERR(dwc->reset); + goto err_put_psy; + } - ret = dwc3_get_clocks(dwc); - if (ret) - goto err_put_psy; + ret = dwc3_get_clocks(dwc); + if (ret) + goto err_put_psy; + } ret = reset_control_deassert(dwc->reset); if (ret) @@ -2232,7 +2237,7 @@ static int dwc3_probe(struct platform_device *pdev) goto err_disable_clks; } - platform_set_drvdata(pdev, dwc); + dev_set_drvdata(dev, dwc); dwc3_cache_hwparams(dwc); if (!dwc->sysdev_is_parent && @@ -2327,12 +2332,35 @@ err_put_psy: return ret; } +EXPORT_SYMBOL_GPL(dwc3_core_probe); -static void dwc3_remove(struct platform_device *pdev) +static int dwc3_probe(struct platform_device *pdev) { - struct dwc3 *dwc = platform_get_drvdata(pdev); + struct dwc3_probe_data probe_data = {}; + struct resource *res; + struct dwc3 *dwc; - pm_runtime_get_sync(&pdev->dev); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "missing memory resource\n"); + return -ENODEV; + } + + dwc = devm_kzalloc(&pdev->dev, sizeof(*dwc), GFP_KERNEL); + if (!dwc) + return -ENOMEM; + + dwc->dev = &pdev->dev; + + probe_data.dwc = dwc; + probe_data.res = res; + + return dwc3_core_probe(&probe_data); +} + +void dwc3_core_remove(struct dwc3 *dwc) +{ + pm_runtime_get_sync(dwc->dev); dwc3_core_exit_mode(dwc); dwc3_debugfs_exit(dwc); @@ -2340,22 +2368,28 @@ static void dwc3_remove(struct platform_device *pdev) dwc3_core_exit(dwc); dwc3_ulpi_exit(dwc); - pm_runtime_allow(&pdev->dev); - pm_runtime_disable(&pdev->dev); - pm_runtime_dont_use_autosuspend(&pdev->dev); - pm_runtime_put_noidle(&pdev->dev); + pm_runtime_allow(dwc->dev); + pm_runtime_disable(dwc->dev); + pm_runtime_dont_use_autosuspend(dwc->dev); + pm_runtime_put_noidle(dwc->dev); /* * HACK: Clear the driver data, which is currently accessed by parent * glue drivers, before allowing the parent to suspend. */ - platform_set_drvdata(pdev, NULL); - pm_runtime_set_suspended(&pdev->dev); + dev_set_drvdata(dwc->dev, NULL); + pm_runtime_set_suspended(dwc->dev); dwc3_free_event_buffers(dwc); if (dwc->usb_psy) power_supply_put(dwc->usb_psy); } +EXPORT_SYMBOL_GPL(dwc3_core_remove); + +static void dwc3_remove(struct platform_device *pdev) +{ + dwc3_core_remove(platform_get_drvdata(pdev)); +} #ifdef CONFIG_PM static int dwc3_core_init_for_resume(struct dwc3 *dwc) @@ -2544,9 +2578,8 @@ static int dwc3_runtime_checks(struct dwc3 *dwc) return 0; } -static int dwc3_runtime_suspend(struct device *dev) +int dwc3_runtime_suspend(struct dwc3 *dwc) { - struct dwc3 *dwc = dev_get_drvdata(dev); int ret; if (dwc3_runtime_checks(dwc)) @@ -2558,10 +2591,11 @@ static int dwc3_runtime_suspend(struct device *dev) return 0; } +EXPORT_SYMBOL_GPL(dwc3_runtime_suspend); -static int dwc3_runtime_resume(struct device *dev) +int dwc3_runtime_resume(struct dwc3 *dwc) { - struct dwc3 *dwc = dev_get_drvdata(dev); + struct device *dev = dwc->dev; int ret; ret = dwc3_resume_common(dwc, PMSG_AUTO_RESUME); @@ -2571,7 +2605,7 @@ static int dwc3_runtime_resume(struct device *dev) switch (dwc->current_dr_role) { case DWC3_GCTL_PRTCAP_DEVICE: if (dwc->pending_events) { - pm_runtime_put(dwc->dev); + pm_runtime_put(dev); dwc->pending_events = false; enable_irq(dwc->irq_gadget); } @@ -2586,10 +2620,11 @@ static int dwc3_runtime_resume(struct device *dev) return 0; } +EXPORT_SYMBOL_GPL(dwc3_runtime_resume); -static int dwc3_runtime_idle(struct device *dev) +int dwc3_runtime_idle(struct dwc3 *dwc) { - struct dwc3 *dwc = dev_get_drvdata(dev); + struct device *dev = dwc->dev; switch (dwc->current_dr_role) { case DWC3_GCTL_PRTCAP_DEVICE: @@ -2607,12 +2642,28 @@ static int dwc3_runtime_idle(struct device *dev) return 0; } +EXPORT_SYMBOL_GPL(dwc3_runtime_idle); + +static int dwc3_plat_runtime_suspend(struct device *dev) +{ + return dwc3_runtime_suspend(dev_get_drvdata(dev)); +} + +static int dwc3_plat_runtime_resume(struct device *dev) +{ + return dwc3_runtime_resume(dev_get_drvdata(dev)); +} + +static int dwc3_plat_runtime_idle(struct device *dev) +{ + return dwc3_runtime_idle(dev_get_drvdata(dev)); +} #endif /* CONFIG_PM */ #ifdef CONFIG_PM_SLEEP -static int dwc3_suspend(struct device *dev) +int dwc3_pm_suspend(struct dwc3 *dwc) { - struct dwc3 *dwc = dev_get_drvdata(dev); + struct device *dev = dwc->dev; int ret; ret = dwc3_suspend_common(dwc, PMSG_SUSPEND); @@ -2623,10 +2674,11 @@ static int dwc3_suspend(struct device *dev) return 0; } +EXPORT_SYMBOL_GPL(dwc3_pm_suspend); -static int dwc3_resume(struct device *dev) +int dwc3_pm_resume(struct dwc3 *dwc) { - struct dwc3 *dwc = dev_get_drvdata(dev); + struct device *dev = dwc->dev; int ret = 0; pinctrl_pm_select_default_state(dev); @@ -2645,10 +2697,10 @@ out: return ret; } +EXPORT_SYMBOL_GPL(dwc3_pm_resume); -static void dwc3_complete(struct device *dev) +void dwc3_pm_complete(struct dwc3 *dwc) { - struct dwc3 *dwc = dev_get_drvdata(dev); u32 reg; if (dwc->current_dr_role == DWC3_GCTL_PRTCAP_HOST && @@ -2658,21 +2710,60 @@ static void dwc3_complete(struct device *dev) dwc3_writel(dwc->regs, DWC3_GUCTL3, reg); } } +EXPORT_SYMBOL_GPL(dwc3_pm_complete); + +int dwc3_pm_prepare(struct dwc3 *dwc) +{ + struct device *dev = dwc->dev; + + /* + * Indicate to the PM core that it may safely leave the device in + * runtime suspend if runtime-suspended already in device mode. + */ + if (dwc->current_dr_role == DWC3_GCTL_PRTCAP_DEVICE && + pm_runtime_suspended(dev) && + !dev_pinctrl(dev)) + return 1; + + return 0; +} +EXPORT_SYMBOL_GPL(dwc3_pm_prepare); + +static int dwc3_plat_suspend(struct device *dev) +{ + return dwc3_pm_suspend(dev_get_drvdata(dev)); +} + +static int dwc3_plat_resume(struct device *dev) +{ + return dwc3_pm_resume(dev_get_drvdata(dev)); +} + +static void dwc3_plat_complete(struct device *dev) +{ + dwc3_pm_complete(dev_get_drvdata(dev)); +} + +static int dwc3_plat_prepare(struct device *dev) +{ + return dwc3_pm_prepare(dev_get_drvdata(dev)); +} #else -#define dwc3_complete NULL +#define dwc3_plat_complete NULL +#define dwc3_plat_prepare NULL #endif /* CONFIG_PM_SLEEP */ static const struct dev_pm_ops dwc3_dev_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(dwc3_suspend, dwc3_resume) - .complete = dwc3_complete, - + SET_SYSTEM_SLEEP_PM_OPS(dwc3_plat_suspend, dwc3_plat_resume) + .complete = dwc3_plat_complete, + .prepare = dwc3_plat_prepare, /* * Runtime suspend halts the controller on disconnection. It relies on * platforms with custom connection notification to start the controller * again. */ - SET_RUNTIME_PM_OPS(dwc3_runtime_suspend, dwc3_runtime_resume, - dwc3_runtime_idle) + SET_RUNTIME_PM_OPS(dwc3_plat_runtime_suspend, dwc3_plat_runtime_resume, + dwc3_plat_runtime_idle) }; #ifdef CONFIG_OF diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 27eae4cf223d..d5b985fa12f4 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -1083,6 +1083,7 @@ struct dwc3_scratchpad_array { * @tx_max_burst_prd: max periodic ESS transmit burst size * @tx_fifo_resize_max_num: max number of fifos allocated during txfifo resize * @clear_stall_protocol: endpoint number that requires a delayed status phase + * @num_hc_interrupters: number of host controller interrupters * @hsphy_interface: "utmi" or "ulpi" * @connected: true when we're connected to a host, false otherwise * @softconnect: true when gadget connect is called, false when disconnect runs @@ -1333,6 +1334,7 @@ struct dwc3 { u8 tx_max_burst_prd; u8 tx_fifo_resize_max_num; u8 clear_stall_protocol; + u16 num_hc_interrupters; const char *hsphy_interface; diff --git a/drivers/usb/dwc3/dwc3-exynos.c b/drivers/usb/dwc3/dwc3-exynos.c index de686b9e6404..e934f94e8fd8 100644 --- a/drivers/usb/dwc3/dwc3-exynos.c +++ b/drivers/usb/dwc3/dwc3-exynos.c @@ -145,6 +145,12 @@ static void dwc3_exynos_remove(struct platform_device *pdev) regulator_disable(exynos->vdd10); } +static const struct dwc3_exynos_driverdata exynos2200_drvdata = { + .clk_names = { "link_aclk" }, + .num_clks = 1, + .suspend_clk_idx = -1, +}; + static const struct dwc3_exynos_driverdata exynos5250_drvdata = { .clk_names = { "usbdrd30" }, .num_clks = 1, @@ -181,8 +187,17 @@ static const struct dwc3_exynos_driverdata gs101_drvdata = { .suspend_clk_idx = 1, }; +static const struct dwc3_exynos_driverdata exynosautov920_drvdata = { + .clk_names = { "ref", "susp_clk"}, + .num_clks = 2, + .suspend_clk_idx = 1, +}; + static const struct of_device_id exynos_dwc3_match[] = { { + .compatible = "samsung,exynos2200-dwusb3", + .data = &exynos2200_drvdata, + }, { .compatible = "samsung,exynos5250-dwusb3", .data = &exynos5250_drvdata, }, { @@ -198,6 +213,9 @@ static const struct of_device_id exynos_dwc3_match[] = { .compatible = "samsung,exynos850-dwusb3", .data = &exynos850_drvdata, }, { + .compatible = "samsung,exynosautov920-dwusb3", + .data = &exynosautov920_drvdata, + }, { .compatible = "google,gs101-dwusb3", .data = &gs101_drvdata, }, { diff --git a/drivers/usb/dwc3/dwc3-qcom-legacy.c b/drivers/usb/dwc3/dwc3-qcom-legacy.c new file mode 100644 index 000000000000..d3fad0fcfdac --- /dev/null +++ b/drivers/usb/dwc3/dwc3-qcom-legacy.c @@ -0,0 +1,935 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * Inspired by dwc3-of-simple.c + */ + +#include <linux/cleanup.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/clk.h> +#include <linux/irq.h> +#include <linux/of_clk.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/extcon.h> +#include <linux/interconnect.h> +#include <linux/of_platform.h> +#include <linux/platform_device.h> +#include <linux/phy/phy.h> +#include <linux/usb/of.h> +#include <linux/reset.h> +#include <linux/iopoll.h> +#include <linux/usb/hcd.h> +#include <linux/usb.h> +#include "core.h" + +/* USB QSCRATCH Hardware registers */ +#define QSCRATCH_HS_PHY_CTRL 0x10 +#define UTMI_OTG_VBUS_VALID BIT(20) +#define SW_SESSVLD_SEL BIT(28) + +#define QSCRATCH_SS_PHY_CTRL 0x30 +#define LANE0_PWR_PRESENT BIT(24) + +#define QSCRATCH_GENERAL_CFG 0x08 +#define PIPE_UTMI_CLK_SEL BIT(0) +#define PIPE3_PHYSTATUS_SW BIT(3) +#define PIPE_UTMI_CLK_DIS BIT(8) + +#define PWR_EVNT_LPM_IN_L2_MASK BIT(4) +#define PWR_EVNT_LPM_OUT_L2_MASK BIT(5) + +#define SDM845_QSCRATCH_BASE_OFFSET 0xf8800 +#define SDM845_QSCRATCH_SIZE 0x400 +#define SDM845_DWC3_CORE_SIZE 0xcd00 + +/* Interconnect path bandwidths in MBps */ +#define USB_MEMORY_AVG_HS_BW MBps_to_icc(240) +#define USB_MEMORY_PEAK_HS_BW MBps_to_icc(700) +#define USB_MEMORY_AVG_SS_BW MBps_to_icc(1000) +#define USB_MEMORY_PEAK_SS_BW MBps_to_icc(2500) +#define APPS_USB_AVG_BW 0 +#define APPS_USB_PEAK_BW MBps_to_icc(40) + +/* Qualcomm SoCs with multiport support has up to 4 ports */ +#define DWC3_QCOM_MAX_PORTS 4 + +static const u32 pwr_evnt_irq_stat_reg[DWC3_QCOM_MAX_PORTS] = { + 0x58, + 0x1dc, + 0x228, + 0x238, +}; + +struct dwc3_qcom_port { + int qusb2_phy_irq; + int dp_hs_phy_irq; + int dm_hs_phy_irq; + int ss_phy_irq; + enum usb_device_speed usb2_speed; +}; + +struct dwc3_qcom { + struct device *dev; + void __iomem *qscratch_base; + struct platform_device *dwc3; + struct clk **clks; + int num_clocks; + struct reset_control *resets; + struct dwc3_qcom_port ports[DWC3_QCOM_MAX_PORTS]; + u8 num_ports; + + struct extcon_dev *edev; + struct extcon_dev *host_edev; + struct notifier_block vbus_nb; + struct notifier_block host_nb; + + enum usb_dr_mode mode; + bool is_suspended; + bool pm_suspended; + struct icc_path *icc_path_ddr; + struct icc_path *icc_path_apps; +}; + +static inline void dwc3_qcom_setbits(void __iomem *base, u32 offset, u32 val) +{ + u32 reg; + + reg = readl(base + offset); + reg |= val; + writel(reg, base + offset); + + /* ensure that above write is through */ + readl(base + offset); +} + +static inline void dwc3_qcom_clrbits(void __iomem *base, u32 offset, u32 val) +{ + u32 reg; + + reg = readl(base + offset); + reg &= ~val; + writel(reg, base + offset); + + /* ensure that above write is through */ + readl(base + offset); +} + +static void dwc3_qcom_vbus_override_enable(struct dwc3_qcom *qcom, bool enable) +{ + if (enable) { + dwc3_qcom_setbits(qcom->qscratch_base, QSCRATCH_SS_PHY_CTRL, + LANE0_PWR_PRESENT); + dwc3_qcom_setbits(qcom->qscratch_base, QSCRATCH_HS_PHY_CTRL, + UTMI_OTG_VBUS_VALID | SW_SESSVLD_SEL); + } else { + dwc3_qcom_clrbits(qcom->qscratch_base, QSCRATCH_SS_PHY_CTRL, + LANE0_PWR_PRESENT); + dwc3_qcom_clrbits(qcom->qscratch_base, QSCRATCH_HS_PHY_CTRL, + UTMI_OTG_VBUS_VALID | SW_SESSVLD_SEL); + } +} + +static int dwc3_qcom_vbus_notifier(struct notifier_block *nb, + unsigned long event, void *ptr) +{ + struct dwc3_qcom *qcom = container_of(nb, struct dwc3_qcom, vbus_nb); + + /* enable vbus override for device mode */ + dwc3_qcom_vbus_override_enable(qcom, event); + qcom->mode = event ? USB_DR_MODE_PERIPHERAL : USB_DR_MODE_HOST; + + return NOTIFY_DONE; +} + +static int dwc3_qcom_host_notifier(struct notifier_block *nb, + unsigned long event, void *ptr) +{ + struct dwc3_qcom *qcom = container_of(nb, struct dwc3_qcom, host_nb); + + /* disable vbus override in host mode */ + dwc3_qcom_vbus_override_enable(qcom, !event); + qcom->mode = event ? USB_DR_MODE_HOST : USB_DR_MODE_PERIPHERAL; + + return NOTIFY_DONE; +} + +static int dwc3_qcom_register_extcon(struct dwc3_qcom *qcom) +{ + struct device *dev = qcom->dev; + struct extcon_dev *host_edev; + int ret; + + if (!of_property_present(dev->of_node, "extcon")) + return 0; + + qcom->edev = extcon_get_edev_by_phandle(dev, 0); + if (IS_ERR(qcom->edev)) + return dev_err_probe(dev, PTR_ERR(qcom->edev), + "Failed to get extcon\n"); + + qcom->vbus_nb.notifier_call = dwc3_qcom_vbus_notifier; + + qcom->host_edev = extcon_get_edev_by_phandle(dev, 1); + if (IS_ERR(qcom->host_edev)) + qcom->host_edev = NULL; + + ret = devm_extcon_register_notifier(dev, qcom->edev, EXTCON_USB, + &qcom->vbus_nb); + if (ret < 0) { + dev_err(dev, "VBUS notifier register failed\n"); + return ret; + } + + if (qcom->host_edev) + host_edev = qcom->host_edev; + else + host_edev = qcom->edev; + + qcom->host_nb.notifier_call = dwc3_qcom_host_notifier; + ret = devm_extcon_register_notifier(dev, host_edev, EXTCON_USB_HOST, + &qcom->host_nb); + if (ret < 0) { + dev_err(dev, "Host notifier register failed\n"); + return ret; + } + + /* Update initial VBUS override based on extcon state */ + if (extcon_get_state(qcom->edev, EXTCON_USB) || + !extcon_get_state(host_edev, EXTCON_USB_HOST)) + dwc3_qcom_vbus_notifier(&qcom->vbus_nb, true, qcom->edev); + else + dwc3_qcom_vbus_notifier(&qcom->vbus_nb, false, qcom->edev); + + return 0; +} + +static int dwc3_qcom_interconnect_enable(struct dwc3_qcom *qcom) +{ + int ret; + + ret = icc_enable(qcom->icc_path_ddr); + if (ret) + return ret; + + ret = icc_enable(qcom->icc_path_apps); + if (ret) + icc_disable(qcom->icc_path_ddr); + + return ret; +} + +static int dwc3_qcom_interconnect_disable(struct dwc3_qcom *qcom) +{ + int ret; + + ret = icc_disable(qcom->icc_path_ddr); + if (ret) + return ret; + + ret = icc_disable(qcom->icc_path_apps); + if (ret) + icc_enable(qcom->icc_path_ddr); + + return ret; +} + +/** + * dwc3_qcom_interconnect_init() - Get interconnect path handles + * and set bandwidth. + * @qcom: Pointer to the concerned usb core. + * + */ +static int dwc3_qcom_interconnect_init(struct dwc3_qcom *qcom) +{ + enum usb_device_speed max_speed; + struct device *dev = qcom->dev; + int ret; + + qcom->icc_path_ddr = of_icc_get(dev, "usb-ddr"); + if (IS_ERR(qcom->icc_path_ddr)) { + return dev_err_probe(dev, PTR_ERR(qcom->icc_path_ddr), + "failed to get usb-ddr path\n"); + } + + qcom->icc_path_apps = of_icc_get(dev, "apps-usb"); + if (IS_ERR(qcom->icc_path_apps)) { + ret = dev_err_probe(dev, PTR_ERR(qcom->icc_path_apps), + "failed to get apps-usb path\n"); + goto put_path_ddr; + } + + max_speed = usb_get_maximum_speed(&qcom->dwc3->dev); + if (max_speed >= USB_SPEED_SUPER || max_speed == USB_SPEED_UNKNOWN) { + ret = icc_set_bw(qcom->icc_path_ddr, + USB_MEMORY_AVG_SS_BW, USB_MEMORY_PEAK_SS_BW); + } else { + ret = icc_set_bw(qcom->icc_path_ddr, + USB_MEMORY_AVG_HS_BW, USB_MEMORY_PEAK_HS_BW); + } + if (ret) { + dev_err(dev, "failed to set bandwidth for usb-ddr path: %d\n", ret); + goto put_path_apps; + } + + ret = icc_set_bw(qcom->icc_path_apps, APPS_USB_AVG_BW, APPS_USB_PEAK_BW); + if (ret) { + dev_err(dev, "failed to set bandwidth for apps-usb path: %d\n", ret); + goto put_path_apps; + } + + return 0; + +put_path_apps: + icc_put(qcom->icc_path_apps); +put_path_ddr: + icc_put(qcom->icc_path_ddr); + return ret; +} + +/** + * dwc3_qcom_interconnect_exit() - Release interconnect path handles + * @qcom: Pointer to the concerned usb core. + * + * This function is used to release interconnect path handle. + */ +static void dwc3_qcom_interconnect_exit(struct dwc3_qcom *qcom) +{ + icc_put(qcom->icc_path_ddr); + icc_put(qcom->icc_path_apps); +} + +/* Only usable in contexts where the role can not change. */ +static bool dwc3_qcom_is_host(struct dwc3_qcom *qcom) +{ + struct dwc3 *dwc; + + /* + * FIXME: Fix this layering violation. + */ + dwc = platform_get_drvdata(qcom->dwc3); + + /* Core driver may not have probed yet. */ + if (!dwc) + return false; + + return dwc->xhci; +} + +static enum usb_device_speed dwc3_qcom_read_usb2_speed(struct dwc3_qcom *qcom, int port_index) +{ + struct dwc3 *dwc = platform_get_drvdata(qcom->dwc3); + struct usb_device *udev; + struct usb_hcd __maybe_unused *hcd; + + /* + * FIXME: Fix this layering violation. + */ + hcd = platform_get_drvdata(dwc->xhci); + +#ifdef CONFIG_USB + udev = usb_hub_find_child(hcd->self.root_hub, port_index + 1); +#else + udev = NULL; +#endif + if (!udev) + return USB_SPEED_UNKNOWN; + + return udev->speed; +} + +static void dwc3_qcom_enable_wakeup_irq(int irq, unsigned int polarity) +{ + if (!irq) + return; + + if (polarity) + irq_set_irq_type(irq, polarity); + + enable_irq(irq); + enable_irq_wake(irq); +} + +static void dwc3_qcom_disable_wakeup_irq(int irq) +{ + if (!irq) + return; + + disable_irq_wake(irq); + disable_irq_nosync(irq); +} + +static void dwc3_qcom_disable_port_interrupts(struct dwc3_qcom_port *port) +{ + dwc3_qcom_disable_wakeup_irq(port->qusb2_phy_irq); + + if (port->usb2_speed == USB_SPEED_LOW) { + dwc3_qcom_disable_wakeup_irq(port->dm_hs_phy_irq); + } else if ((port->usb2_speed == USB_SPEED_HIGH) || + (port->usb2_speed == USB_SPEED_FULL)) { + dwc3_qcom_disable_wakeup_irq(port->dp_hs_phy_irq); + } else { + dwc3_qcom_disable_wakeup_irq(port->dp_hs_phy_irq); + dwc3_qcom_disable_wakeup_irq(port->dm_hs_phy_irq); + } + + dwc3_qcom_disable_wakeup_irq(port->ss_phy_irq); +} + +static void dwc3_qcom_enable_port_interrupts(struct dwc3_qcom_port *port) +{ + dwc3_qcom_enable_wakeup_irq(port->qusb2_phy_irq, 0); + + /* + * Configure DP/DM line interrupts based on the USB2 device attached to + * the root hub port. When HS/FS device is connected, configure the DP line + * as falling edge to detect both disconnect and remote wakeup scenarios. When + * LS device is connected, configure DM line as falling edge to detect both + * disconnect and remote wakeup. When no device is connected, configure both + * DP and DM lines as rising edge to detect HS/HS/LS device connect scenario. + */ + + if (port->usb2_speed == USB_SPEED_LOW) { + dwc3_qcom_enable_wakeup_irq(port->dm_hs_phy_irq, + IRQ_TYPE_EDGE_FALLING); + } else if ((port->usb2_speed == USB_SPEED_HIGH) || + (port->usb2_speed == USB_SPEED_FULL)) { + dwc3_qcom_enable_wakeup_irq(port->dp_hs_phy_irq, + IRQ_TYPE_EDGE_FALLING); + } else { + dwc3_qcom_enable_wakeup_irq(port->dp_hs_phy_irq, + IRQ_TYPE_EDGE_RISING); + dwc3_qcom_enable_wakeup_irq(port->dm_hs_phy_irq, + IRQ_TYPE_EDGE_RISING); + } + + dwc3_qcom_enable_wakeup_irq(port->ss_phy_irq, 0); +} + +static void dwc3_qcom_disable_interrupts(struct dwc3_qcom *qcom) +{ + int i; + + for (i = 0; i < qcom->num_ports; i++) + dwc3_qcom_disable_port_interrupts(&qcom->ports[i]); +} + +static void dwc3_qcom_enable_interrupts(struct dwc3_qcom *qcom) +{ + int i; + + for (i = 0; i < qcom->num_ports; i++) + dwc3_qcom_enable_port_interrupts(&qcom->ports[i]); +} + +static int dwc3_qcom_suspend(struct dwc3_qcom *qcom, bool wakeup) +{ + u32 val; + int i, ret; + + if (qcom->is_suspended) + return 0; + + for (i = 0; i < qcom->num_ports; i++) { + val = readl(qcom->qscratch_base + pwr_evnt_irq_stat_reg[i]); + if (!(val & PWR_EVNT_LPM_IN_L2_MASK)) + dev_err(qcom->dev, "port-%d HS-PHY not in L2\n", i + 1); + } + + for (i = qcom->num_clocks - 1; i >= 0; i--) + clk_disable_unprepare(qcom->clks[i]); + + ret = dwc3_qcom_interconnect_disable(qcom); + if (ret) + dev_warn(qcom->dev, "failed to disable interconnect: %d\n", ret); + + /* + * The role is stable during suspend as role switching is done from a + * freezable workqueue. + */ + if (dwc3_qcom_is_host(qcom) && wakeup) { + for (i = 0; i < qcom->num_ports; i++) + qcom->ports[i].usb2_speed = dwc3_qcom_read_usb2_speed(qcom, i); + dwc3_qcom_enable_interrupts(qcom); + } + + qcom->is_suspended = true; + + return 0; +} + +static int dwc3_qcom_resume(struct dwc3_qcom *qcom, bool wakeup) +{ + int ret; + int i; + + if (!qcom->is_suspended) + return 0; + + if (dwc3_qcom_is_host(qcom) && wakeup) + dwc3_qcom_disable_interrupts(qcom); + + for (i = 0; i < qcom->num_clocks; i++) { + ret = clk_prepare_enable(qcom->clks[i]); + if (ret < 0) { + while (--i >= 0) + clk_disable_unprepare(qcom->clks[i]); + return ret; + } + } + + ret = dwc3_qcom_interconnect_enable(qcom); + if (ret) + dev_warn(qcom->dev, "failed to enable interconnect: %d\n", ret); + + /* Clear existing events from PHY related to L2 in/out */ + for (i = 0; i < qcom->num_ports; i++) { + dwc3_qcom_setbits(qcom->qscratch_base, + pwr_evnt_irq_stat_reg[i], + PWR_EVNT_LPM_IN_L2_MASK | PWR_EVNT_LPM_OUT_L2_MASK); + } + + qcom->is_suspended = false; + + return 0; +} + +static irqreturn_t qcom_dwc3_resume_irq(int irq, void *data) +{ + struct dwc3_qcom *qcom = data; + struct dwc3 *dwc = platform_get_drvdata(qcom->dwc3); + + /* If pm_suspended then let pm_resume take care of resuming h/w */ + if (qcom->pm_suspended) + return IRQ_HANDLED; + + /* + * This is safe as role switching is done from a freezable workqueue + * and the wakeup interrupts are disabled as part of resume. + */ + if (dwc3_qcom_is_host(qcom)) + pm_runtime_resume(&dwc->xhci->dev); + + return IRQ_HANDLED; +} + +static void dwc3_qcom_select_utmi_clk(struct dwc3_qcom *qcom) +{ + /* Configure dwc3 to use UTMI clock as PIPE clock not present */ + dwc3_qcom_setbits(qcom->qscratch_base, QSCRATCH_GENERAL_CFG, + PIPE_UTMI_CLK_DIS); + + usleep_range(100, 1000); + + dwc3_qcom_setbits(qcom->qscratch_base, QSCRATCH_GENERAL_CFG, + PIPE_UTMI_CLK_SEL | PIPE3_PHYSTATUS_SW); + + usleep_range(100, 1000); + + dwc3_qcom_clrbits(qcom->qscratch_base, QSCRATCH_GENERAL_CFG, + PIPE_UTMI_CLK_DIS); +} + +static int dwc3_qcom_request_irq(struct dwc3_qcom *qcom, int irq, + const char *name) +{ + int ret; + + /* Keep wakeup interrupts disabled until suspend */ + ret = devm_request_threaded_irq(qcom->dev, irq, NULL, + qcom_dwc3_resume_irq, + IRQF_ONESHOT | IRQF_NO_AUTOEN, + name, qcom); + if (ret) + dev_err(qcom->dev, "failed to request irq %s: %d\n", name, ret); + + return ret; +} + +static int dwc3_qcom_setup_port_irq(struct platform_device *pdev, int port_index, bool is_multiport) +{ + struct dwc3_qcom *qcom = platform_get_drvdata(pdev); + const char *irq_name; + int irq; + int ret; + + if (is_multiport) + irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "dp_hs_phy_%d", port_index + 1); + else + irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "dp_hs_phy_irq"); + if (!irq_name) + return -ENOMEM; + + irq = platform_get_irq_byname_optional(pdev, irq_name); + if (irq > 0) { + ret = dwc3_qcom_request_irq(qcom, irq, irq_name); + if (ret) + return ret; + qcom->ports[port_index].dp_hs_phy_irq = irq; + } + + if (is_multiport) + irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "dm_hs_phy_%d", port_index + 1); + else + irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "dm_hs_phy_irq"); + if (!irq_name) + return -ENOMEM; + + irq = platform_get_irq_byname_optional(pdev, irq_name); + if (irq > 0) { + ret = dwc3_qcom_request_irq(qcom, irq, irq_name); + if (ret) + return ret; + qcom->ports[port_index].dm_hs_phy_irq = irq; + } + + if (is_multiport) + irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "ss_phy_%d", port_index + 1); + else + irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "ss_phy_irq"); + if (!irq_name) + return -ENOMEM; + + irq = platform_get_irq_byname_optional(pdev, irq_name); + if (irq > 0) { + ret = dwc3_qcom_request_irq(qcom, irq, irq_name); + if (ret) + return ret; + qcom->ports[port_index].ss_phy_irq = irq; + } + + if (is_multiport) + return 0; + + irq = platform_get_irq_byname_optional(pdev, "qusb2_phy"); + if (irq > 0) { + ret = dwc3_qcom_request_irq(qcom, irq, "qusb2_phy"); + if (ret) + return ret; + qcom->ports[port_index].qusb2_phy_irq = irq; + } + + return 0; +} + +static int dwc3_qcom_find_num_ports(struct platform_device *pdev) +{ + char irq_name[14]; + int port_num; + int irq; + + irq = platform_get_irq_byname_optional(pdev, "dp_hs_phy_1"); + if (irq <= 0) + return 1; + + for (port_num = 2; port_num <= DWC3_QCOM_MAX_PORTS; port_num++) { + sprintf(irq_name, "dp_hs_phy_%d", port_num); + + irq = platform_get_irq_byname_optional(pdev, irq_name); + if (irq <= 0) + return port_num - 1; + } + + return DWC3_QCOM_MAX_PORTS; +} + +static int dwc3_qcom_setup_irq(struct platform_device *pdev) +{ + struct dwc3_qcom *qcom = platform_get_drvdata(pdev); + bool is_multiport; + int ret; + int i; + + qcom->num_ports = dwc3_qcom_find_num_ports(pdev); + is_multiport = (qcom->num_ports > 1); + + for (i = 0; i < qcom->num_ports; i++) { + ret = dwc3_qcom_setup_port_irq(pdev, i, is_multiport); + if (ret) + return ret; + } + + return 0; +} + +static int dwc3_qcom_clk_init(struct dwc3_qcom *qcom, int count) +{ + struct device *dev = qcom->dev; + struct device_node *np = dev->of_node; + int i; + + if (!np || !count) + return 0; + + if (count < 0) + return count; + + qcom->num_clocks = count; + + qcom->clks = devm_kcalloc(dev, qcom->num_clocks, + sizeof(struct clk *), GFP_KERNEL); + if (!qcom->clks) + return -ENOMEM; + + for (i = 0; i < qcom->num_clocks; i++) { + struct clk *clk; + int ret; + + clk = of_clk_get(np, i); + if (IS_ERR(clk)) { + while (--i >= 0) + clk_put(qcom->clks[i]); + return PTR_ERR(clk); + } + + ret = clk_prepare_enable(clk); + if (ret < 0) { + while (--i >= 0) { + clk_disable_unprepare(qcom->clks[i]); + clk_put(qcom->clks[i]); + } + clk_put(clk); + + return ret; + } + + qcom->clks[i] = clk; + } + + return 0; +} + +static int dwc3_qcom_of_register_core(struct platform_device *pdev) +{ + struct dwc3_qcom *qcom = platform_get_drvdata(pdev); + struct device_node *np = pdev->dev.of_node; + struct device *dev = &pdev->dev; + int ret; + + struct device_node *dwc3_np __free(device_node) = of_get_compatible_child(np, + "snps,dwc3"); + if (!dwc3_np) { + dev_err(dev, "failed to find dwc3 core child\n"); + return -ENODEV; + } + + ret = of_platform_populate(np, NULL, NULL, dev); + if (ret) { + dev_err(dev, "failed to register dwc3 core - %d\n", ret); + return ret; + } + + qcom->dwc3 = of_find_device_by_node(dwc3_np); + if (!qcom->dwc3) { + ret = -ENODEV; + dev_err(dev, "failed to get dwc3 platform device\n"); + of_platform_depopulate(dev); + } + + return ret; +} + +static int dwc3_qcom_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct device *dev = &pdev->dev; + struct dwc3_qcom *qcom; + int ret, i; + bool ignore_pipe_clk; + bool wakeup_source; + + qcom = devm_kzalloc(&pdev->dev, sizeof(*qcom), GFP_KERNEL); + if (!qcom) + return -ENOMEM; + + platform_set_drvdata(pdev, qcom); + qcom->dev = &pdev->dev; + + qcom->resets = devm_reset_control_array_get_optional_exclusive(dev); + if (IS_ERR(qcom->resets)) { + return dev_err_probe(&pdev->dev, PTR_ERR(qcom->resets), + "failed to get resets\n"); + } + + ret = reset_control_assert(qcom->resets); + if (ret) { + dev_err(&pdev->dev, "failed to assert resets, err=%d\n", ret); + return ret; + } + + usleep_range(10, 1000); + + ret = reset_control_deassert(qcom->resets); + if (ret) { + dev_err(&pdev->dev, "failed to deassert resets, err=%d\n", ret); + goto reset_assert; + } + + ret = dwc3_qcom_clk_init(qcom, of_clk_get_parent_count(np)); + if (ret) { + dev_err_probe(dev, ret, "failed to get clocks\n"); + goto reset_assert; + } + + qcom->qscratch_base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(qcom->qscratch_base)) { + ret = PTR_ERR(qcom->qscratch_base); + goto clk_disable; + } + + ret = dwc3_qcom_setup_irq(pdev); + if (ret) { + dev_err(dev, "failed to setup IRQs, err=%d\n", ret); + goto clk_disable; + } + + /* + * Disable pipe_clk requirement if specified. Used when dwc3 + * operates without SSPHY and only HS/FS/LS modes are supported. + */ + ignore_pipe_clk = device_property_read_bool(dev, + "qcom,select-utmi-as-pipe-clk"); + if (ignore_pipe_clk) + dwc3_qcom_select_utmi_clk(qcom); + + ret = dwc3_qcom_of_register_core(pdev); + if (ret) { + dev_err(dev, "failed to register DWC3 Core, err=%d\n", ret); + goto clk_disable; + } + + ret = dwc3_qcom_interconnect_init(qcom); + if (ret) + goto depopulate; + + qcom->mode = usb_get_dr_mode(&qcom->dwc3->dev); + + /* enable vbus override for device mode */ + if (qcom->mode != USB_DR_MODE_HOST) + dwc3_qcom_vbus_override_enable(qcom, true); + + /* register extcon to override sw_vbus on Vbus change later */ + ret = dwc3_qcom_register_extcon(qcom); + if (ret) + goto interconnect_exit; + + wakeup_source = of_property_read_bool(dev->of_node, "wakeup-source"); + device_init_wakeup(&pdev->dev, wakeup_source); + device_init_wakeup(&qcom->dwc3->dev, wakeup_source); + + qcom->is_suspended = false; + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + pm_runtime_forbid(dev); + + return 0; + +interconnect_exit: + dwc3_qcom_interconnect_exit(qcom); +depopulate: + of_platform_depopulate(&pdev->dev); + platform_device_put(qcom->dwc3); +clk_disable: + for (i = qcom->num_clocks - 1; i >= 0; i--) { + clk_disable_unprepare(qcom->clks[i]); + clk_put(qcom->clks[i]); + } +reset_assert: + reset_control_assert(qcom->resets); + + return ret; +} + +static void dwc3_qcom_remove(struct platform_device *pdev) +{ + struct dwc3_qcom *qcom = platform_get_drvdata(pdev); + struct device *dev = &pdev->dev; + int i; + + of_platform_depopulate(&pdev->dev); + platform_device_put(qcom->dwc3); + + for (i = qcom->num_clocks - 1; i >= 0; i--) { + clk_disable_unprepare(qcom->clks[i]); + clk_put(qcom->clks[i]); + } + qcom->num_clocks = 0; + + dwc3_qcom_interconnect_exit(qcom); + reset_control_assert(qcom->resets); + + pm_runtime_allow(dev); + pm_runtime_disable(dev); +} + +static int __maybe_unused dwc3_qcom_pm_suspend(struct device *dev) +{ + struct dwc3_qcom *qcom = dev_get_drvdata(dev); + bool wakeup = device_may_wakeup(dev); + int ret; + + ret = dwc3_qcom_suspend(qcom, wakeup); + if (ret) + return ret; + + qcom->pm_suspended = true; + + return 0; +} + +static int __maybe_unused dwc3_qcom_pm_resume(struct device *dev) +{ + struct dwc3_qcom *qcom = dev_get_drvdata(dev); + bool wakeup = device_may_wakeup(dev); + int ret; + + ret = dwc3_qcom_resume(qcom, wakeup); + if (ret) + return ret; + + qcom->pm_suspended = false; + + return 0; +} + +static int __maybe_unused dwc3_qcom_runtime_suspend(struct device *dev) +{ + struct dwc3_qcom *qcom = dev_get_drvdata(dev); + + return dwc3_qcom_suspend(qcom, true); +} + +static int __maybe_unused dwc3_qcom_runtime_resume(struct device *dev) +{ + struct dwc3_qcom *qcom = dev_get_drvdata(dev); + + return dwc3_qcom_resume(qcom, true); +} + +static const struct dev_pm_ops dwc3_qcom_dev_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(dwc3_qcom_pm_suspend, dwc3_qcom_pm_resume) + SET_RUNTIME_PM_OPS(dwc3_qcom_runtime_suspend, dwc3_qcom_runtime_resume, + NULL) +}; + +static const struct of_device_id dwc3_qcom_of_match[] = { + { .compatible = "qcom,dwc3" }, + { } +}; +MODULE_DEVICE_TABLE(of, dwc3_qcom_of_match); + +static struct platform_driver dwc3_qcom_driver = { + .probe = dwc3_qcom_probe, + .remove = dwc3_qcom_remove, + .driver = { + .name = "dwc3-qcom-legacy", + .pm = &dwc3_qcom_dev_pm_ops, + .of_match_table = dwc3_qcom_of_match, + }, +}; + +module_platform_driver(dwc3_qcom_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("DesignWare DWC3 QCOM legacy glue Driver"); diff --git a/drivers/usb/dwc3/dwc3-qcom.c b/drivers/usb/dwc3/dwc3-qcom.c index 58683bb672e9..7334de85ad10 100644 --- a/drivers/usb/dwc3/dwc3-qcom.c +++ b/drivers/usb/dwc3/dwc3-qcom.c @@ -4,7 +4,6 @@ * Inspired by dwc3-of-simple.c */ -#include <linux/cleanup.h> #include <linux/io.h> #include <linux/of.h> #include <linux/clk.h> @@ -14,7 +13,6 @@ #include <linux/kernel.h> #include <linux/extcon.h> #include <linux/interconnect.h> -#include <linux/of_platform.h> #include <linux/platform_device.h> #include <linux/phy/phy.h> #include <linux/usb/of.h> @@ -23,6 +21,7 @@ #include <linux/usb/hcd.h> #include <linux/usb.h> #include "core.h" +#include "glue.h" /* USB QSCRATCH Hardware registers */ #define QSCRATCH_HS_PHY_CTRL 0x10 @@ -73,8 +72,8 @@ struct dwc3_qcom_port { struct dwc3_qcom { struct device *dev; void __iomem *qscratch_base; - struct platform_device *dwc3; - struct clk **clks; + struct dwc3 dwc; + struct clk_bulk_data *clks; int num_clocks; struct reset_control *resets; struct dwc3_qcom_port ports[DWC3_QCOM_MAX_PORTS]; @@ -92,6 +91,8 @@ struct dwc3_qcom { struct icc_path *icc_path_apps; }; +#define to_dwc3_qcom(d) container_of((d), struct dwc3_qcom, dwc) + static inline void dwc3_qcom_setbits(void __iomem *base, u32 offset, u32 val) { u32 reg; @@ -116,6 +117,11 @@ static inline void dwc3_qcom_clrbits(void __iomem *base, u32 offset, u32 val) readl(base + offset); } +/* + * TODO: Make the in-core role switching code invoke dwc3_qcom_vbus_override_enable(), + * validate that the in-core extcon support is functional, and drop extcon + * handling from the glue + */ static void dwc3_qcom_vbus_override_enable(struct dwc3_qcom *qcom, bool enable) { if (enable) { @@ -260,7 +266,7 @@ static int dwc3_qcom_interconnect_init(struct dwc3_qcom *qcom) goto put_path_ddr; } - max_speed = usb_get_maximum_speed(&qcom->dwc3->dev); + max_speed = usb_get_maximum_speed(qcom->dwc.dev); if (max_speed >= USB_SPEED_SUPER || max_speed == USB_SPEED_UNKNOWN) { ret = icc_set_bw(qcom->icc_path_ddr, USB_MEMORY_AVG_SS_BW, USB_MEMORY_PEAK_SS_BW); @@ -303,25 +309,14 @@ static void dwc3_qcom_interconnect_exit(struct dwc3_qcom *qcom) /* Only usable in contexts where the role can not change. */ static bool dwc3_qcom_is_host(struct dwc3_qcom *qcom) { - struct dwc3 *dwc; - - /* - * FIXME: Fix this layering violation. - */ - dwc = platform_get_drvdata(qcom->dwc3); - - /* Core driver may not have probed yet. */ - if (!dwc) - return false; - - return dwc->xhci; + return qcom->dwc.xhci; } static enum usb_device_speed dwc3_qcom_read_usb2_speed(struct dwc3_qcom *qcom, int port_index) { - struct dwc3 *dwc = platform_get_drvdata(qcom->dwc3); struct usb_device *udev; struct usb_hcd __maybe_unused *hcd; + struct dwc3 *dwc = &qcom->dwc; /* * FIXME: Fix this layering violation. @@ -436,9 +431,7 @@ static int dwc3_qcom_suspend(struct dwc3_qcom *qcom, bool wakeup) if (!(val & PWR_EVNT_LPM_IN_L2_MASK)) dev_err(qcom->dev, "port-%d HS-PHY not in L2\n", i + 1); } - - for (i = qcom->num_clocks - 1; i >= 0; i--) - clk_disable_unprepare(qcom->clks[i]); + clk_bulk_disable_unprepare(qcom->num_clocks, qcom->clks); ret = dwc3_qcom_interconnect_disable(qcom); if (ret) @@ -470,14 +463,9 @@ static int dwc3_qcom_resume(struct dwc3_qcom *qcom, bool wakeup) if (dwc3_qcom_is_host(qcom) && wakeup) dwc3_qcom_disable_interrupts(qcom); - for (i = 0; i < qcom->num_clocks; i++) { - ret = clk_prepare_enable(qcom->clks[i]); - if (ret < 0) { - while (--i >= 0) - clk_disable_unprepare(qcom->clks[i]); - return ret; - } - } + ret = clk_bulk_prepare_enable(qcom->num_clocks, qcom->clks); + if (ret < 0) + return ret; ret = dwc3_qcom_interconnect_enable(qcom); if (ret) @@ -498,7 +486,7 @@ static int dwc3_qcom_resume(struct dwc3_qcom *qcom, bool wakeup) static irqreturn_t qcom_dwc3_resume_irq(int irq, void *data) { struct dwc3_qcom *qcom = data; - struct dwc3 *dwc = platform_get_drvdata(qcom->dwc3); + struct dwc3 *dwc = &qcom->dwc; /* If pm_suspended then let pm_resume take care of resuming h/w */ if (qcom->pm_suspended) @@ -547,9 +535,10 @@ static int dwc3_qcom_request_irq(struct dwc3_qcom *qcom, int irq, return ret; } -static int dwc3_qcom_setup_port_irq(struct platform_device *pdev, int port_index, bool is_multiport) +static int dwc3_qcom_setup_port_irq(struct dwc3_qcom *qcom, + struct platform_device *pdev, + int port_index, bool is_multiport) { - struct dwc3_qcom *qcom = platform_get_drvdata(pdev); const char *irq_name; int irq; int ret; @@ -634,9 +623,8 @@ static int dwc3_qcom_find_num_ports(struct platform_device *pdev) return DWC3_QCOM_MAX_PORTS; } -static int dwc3_qcom_setup_irq(struct platform_device *pdev) +static int dwc3_qcom_setup_irq(struct dwc3_qcom *qcom, struct platform_device *pdev) { - struct dwc3_qcom *qcom = platform_get_drvdata(pdev); bool is_multiport; int ret; int i; @@ -645,7 +633,7 @@ static int dwc3_qcom_setup_irq(struct platform_device *pdev) is_multiport = (qcom->num_ports > 1); for (i = 0; i < qcom->num_ports; i++) { - ret = dwc3_qcom_setup_port_irq(pdev, i, is_multiport); + ret = dwc3_qcom_setup_port_irq(qcom, pdev, i, is_multiport); if (ret) return ret; } @@ -653,89 +641,14 @@ static int dwc3_qcom_setup_irq(struct platform_device *pdev) return 0; } -static int dwc3_qcom_clk_init(struct dwc3_qcom *qcom, int count) -{ - struct device *dev = qcom->dev; - struct device_node *np = dev->of_node; - int i; - - if (!np || !count) - return 0; - - if (count < 0) - return count; - - qcom->num_clocks = count; - - qcom->clks = devm_kcalloc(dev, qcom->num_clocks, - sizeof(struct clk *), GFP_KERNEL); - if (!qcom->clks) - return -ENOMEM; - - for (i = 0; i < qcom->num_clocks; i++) { - struct clk *clk; - int ret; - - clk = of_clk_get(np, i); - if (IS_ERR(clk)) { - while (--i >= 0) - clk_put(qcom->clks[i]); - return PTR_ERR(clk); - } - - ret = clk_prepare_enable(clk); - if (ret < 0) { - while (--i >= 0) { - clk_disable_unprepare(qcom->clks[i]); - clk_put(qcom->clks[i]); - } - clk_put(clk); - - return ret; - } - - qcom->clks[i] = clk; - } - - return 0; -} - -static int dwc3_qcom_of_register_core(struct platform_device *pdev) -{ - struct dwc3_qcom *qcom = platform_get_drvdata(pdev); - struct device_node *np = pdev->dev.of_node; - struct device *dev = &pdev->dev; - int ret; - - struct device_node *dwc3_np __free(device_node) = of_get_compatible_child(np, - "snps,dwc3"); - if (!dwc3_np) { - dev_err(dev, "failed to find dwc3 core child\n"); - return -ENODEV; - } - - ret = of_platform_populate(np, NULL, NULL, dev); - if (ret) { - dev_err(dev, "failed to register dwc3 core - %d\n", ret); - return ret; - } - - qcom->dwc3 = of_find_device_by_node(dwc3_np); - if (!qcom->dwc3) { - ret = -ENODEV; - dev_err(dev, "failed to get dwc3 platform device\n"); - of_platform_depopulate(dev); - } - - return ret; -} - static int dwc3_qcom_probe(struct platform_device *pdev) { - struct device_node *np = pdev->dev.of_node; + struct dwc3_probe_data probe_data = {}; struct device *dev = &pdev->dev; struct dwc3_qcom *qcom; - int ret, i; + struct resource res; + struct resource *r; + int ret; bool ignore_pipe_clk; bool wakeup_source; @@ -743,7 +656,6 @@ static int dwc3_qcom_probe(struct platform_device *pdev) if (!qcom) return -ENOMEM; - platform_set_drvdata(pdev, qcom); qcom->dev = &pdev->dev; qcom->resets = devm_reset_control_array_get_optional_exclusive(dev); @@ -752,6 +664,11 @@ static int dwc3_qcom_probe(struct platform_device *pdev) "failed to get resets\n"); } + ret = devm_clk_bulk_get_all(&pdev->dev, &qcom->clks); + if (ret < 0) + return dev_err_probe(dev, ret, "failed to get clocks\n"); + qcom->num_clocks = ret; + ret = reset_control_assert(qcom->resets); if (ret) { dev_err(&pdev->dev, "failed to assert resets, err=%d\n", ret); @@ -766,19 +683,26 @@ static int dwc3_qcom_probe(struct platform_device *pdev) goto reset_assert; } - ret = dwc3_qcom_clk_init(qcom, of_clk_get_parent_count(np)); - if (ret) { - dev_err_probe(dev, ret, "failed to get clocks\n"); + ret = clk_bulk_prepare_enable(qcom->num_clocks, qcom->clks); + if (ret < 0) goto reset_assert; + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!r) { + ret = -EINVAL; + goto clk_disable; } + res = *r; + res.end = res.start + SDM845_QSCRATCH_BASE_OFFSET; - qcom->qscratch_base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(qcom->qscratch_base)) { - ret = PTR_ERR(qcom->qscratch_base); + qcom->qscratch_base = devm_ioremap(dev, res.end, SDM845_QSCRATCH_SIZE); + if (!qcom->qscratch_base) { + dev_err(dev, "failed to map qscratch region\n"); + ret = -ENOMEM; goto clk_disable; } - ret = dwc3_qcom_setup_irq(pdev); + ret = dwc3_qcom_setup_irq(qcom, pdev); if (ret) { dev_err(dev, "failed to setup IRQs, err=%d\n", ret); goto clk_disable; @@ -793,17 +717,21 @@ static int dwc3_qcom_probe(struct platform_device *pdev) if (ignore_pipe_clk) dwc3_qcom_select_utmi_clk(qcom); - ret = dwc3_qcom_of_register_core(pdev); - if (ret) { - dev_err(dev, "failed to register DWC3 Core, err=%d\n", ret); + qcom->dwc.dev = dev; + probe_data.dwc = &qcom->dwc; + probe_data.res = &res; + probe_data.ignore_clocks_and_resets = true; + ret = dwc3_core_probe(&probe_data); + if (ret) { + ret = dev_err_probe(dev, ret, "failed to register DWC3 Core\n"); goto clk_disable; } ret = dwc3_qcom_interconnect_init(qcom); if (ret) - goto depopulate; + goto remove_core; - qcom->mode = usb_get_dr_mode(&qcom->dwc3->dev); + qcom->mode = usb_get_dr_mode(dev); /* enable vbus override for device mode */ if (qcom->mode != USB_DR_MODE_HOST) @@ -816,25 +744,17 @@ static int dwc3_qcom_probe(struct platform_device *pdev) wakeup_source = of_property_read_bool(dev->of_node, "wakeup-source"); device_init_wakeup(&pdev->dev, wakeup_source); - device_init_wakeup(&qcom->dwc3->dev, wakeup_source); qcom->is_suspended = false; - pm_runtime_set_active(dev); - pm_runtime_enable(dev); - pm_runtime_forbid(dev); return 0; interconnect_exit: dwc3_qcom_interconnect_exit(qcom); -depopulate: - of_platform_depopulate(&pdev->dev); - platform_device_put(qcom->dwc3); +remove_core: + dwc3_core_remove(&qcom->dwc); clk_disable: - for (i = qcom->num_clocks - 1; i >= 0; i--) { - clk_disable_unprepare(qcom->clks[i]); - clk_put(qcom->clks[i]); - } + clk_bulk_disable_unprepare(qcom->num_clocks, qcom->clks); reset_assert: reset_control_assert(qcom->resets); @@ -843,32 +763,28 @@ reset_assert: static void dwc3_qcom_remove(struct platform_device *pdev) { - struct dwc3_qcom *qcom = platform_get_drvdata(pdev); - struct device *dev = &pdev->dev; - int i; + struct dwc3 *dwc = platform_get_drvdata(pdev); + struct dwc3_qcom *qcom = to_dwc3_qcom(dwc); - of_platform_depopulate(&pdev->dev); - platform_device_put(qcom->dwc3); + dwc3_core_remove(&qcom->dwc); - for (i = qcom->num_clocks - 1; i >= 0; i--) { - clk_disable_unprepare(qcom->clks[i]); - clk_put(qcom->clks[i]); - } - qcom->num_clocks = 0; + clk_bulk_disable_unprepare(qcom->num_clocks, qcom->clks); dwc3_qcom_interconnect_exit(qcom); reset_control_assert(qcom->resets); - - pm_runtime_allow(dev); - pm_runtime_disable(dev); } -static int __maybe_unused dwc3_qcom_pm_suspend(struct device *dev) +static int dwc3_qcom_pm_suspend(struct device *dev) { - struct dwc3_qcom *qcom = dev_get_drvdata(dev); + struct dwc3 *dwc = dev_get_drvdata(dev); + struct dwc3_qcom *qcom = to_dwc3_qcom(dwc); bool wakeup = device_may_wakeup(dev); int ret; + ret = dwc3_pm_suspend(&qcom->dwc); + if (ret) + return ret; + ret = dwc3_qcom_suspend(qcom, wakeup); if (ret) return ret; @@ -878,9 +794,10 @@ static int __maybe_unused dwc3_qcom_pm_suspend(struct device *dev) return 0; } -static int __maybe_unused dwc3_qcom_pm_resume(struct device *dev) +static int dwc3_qcom_pm_resume(struct device *dev) { - struct dwc3_qcom *qcom = dev_get_drvdata(dev); + struct dwc3 *dwc = dev_get_drvdata(dev); + struct dwc3_qcom *qcom = to_dwc3_qcom(dwc); bool wakeup = device_may_wakeup(dev); int ret; @@ -890,31 +807,68 @@ static int __maybe_unused dwc3_qcom_pm_resume(struct device *dev) qcom->pm_suspended = false; + ret = dwc3_pm_resume(&qcom->dwc); + if (ret) + return ret; + return 0; } -static int __maybe_unused dwc3_qcom_runtime_suspend(struct device *dev) +static void dwc3_qcom_complete(struct device *dev) { - struct dwc3_qcom *qcom = dev_get_drvdata(dev); + struct dwc3 *dwc = dev_get_drvdata(dev); + + dwc3_pm_complete(dwc); +} + +static int dwc3_qcom_prepare(struct device *dev) +{ + struct dwc3 *dwc = dev_get_drvdata(dev); + + return dwc3_pm_prepare(dwc); +} + +static int dwc3_qcom_runtime_suspend(struct device *dev) +{ + struct dwc3 *dwc = dev_get_drvdata(dev); + struct dwc3_qcom *qcom = to_dwc3_qcom(dwc); + int ret; + + ret = dwc3_runtime_suspend(&qcom->dwc); + if (ret) + return ret; return dwc3_qcom_suspend(qcom, true); } -static int __maybe_unused dwc3_qcom_runtime_resume(struct device *dev) +static int dwc3_qcom_runtime_resume(struct device *dev) { - struct dwc3_qcom *qcom = dev_get_drvdata(dev); + struct dwc3 *dwc = dev_get_drvdata(dev); + struct dwc3_qcom *qcom = to_dwc3_qcom(dwc); + int ret; - return dwc3_qcom_resume(qcom, true); + ret = dwc3_qcom_resume(qcom, true); + if (ret) + return ret; + + return dwc3_runtime_resume(&qcom->dwc); +} + +static int dwc3_qcom_runtime_idle(struct device *dev) +{ + return dwc3_runtime_idle(dev_get_drvdata(dev)); } static const struct dev_pm_ops dwc3_qcom_dev_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(dwc3_qcom_pm_suspend, dwc3_qcom_pm_resume) - SET_RUNTIME_PM_OPS(dwc3_qcom_runtime_suspend, dwc3_qcom_runtime_resume, - NULL) + SYSTEM_SLEEP_PM_OPS(dwc3_qcom_pm_suspend, dwc3_qcom_pm_resume) + RUNTIME_PM_OPS(dwc3_qcom_runtime_suspend, dwc3_qcom_runtime_resume, + dwc3_qcom_runtime_idle) + .complete = pm_sleep_ptr(dwc3_qcom_complete), + .prepare = pm_sleep_ptr(dwc3_qcom_prepare), }; static const struct of_device_id dwc3_qcom_of_match[] = { - { .compatible = "qcom,dwc3" }, + { .compatible = "qcom,snps-dwc3" }, { } }; MODULE_DEVICE_TABLE(of, dwc3_qcom_of_match); @@ -924,7 +878,7 @@ static struct platform_driver dwc3_qcom_driver = { .remove = dwc3_qcom_remove, .driver = { .name = "dwc3-qcom", - .pm = &dwc3_qcom_dev_pm_ops, + .pm = pm_ptr(&dwc3_qcom_dev_pm_ops), .of_match_table = dwc3_qcom_of_match, }, }; diff --git a/drivers/usb/dwc3/glue.h b/drivers/usb/dwc3/glue.h new file mode 100644 index 000000000000..2efd00e763be --- /dev/null +++ b/drivers/usb/dwc3/glue.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * glue.h - DesignWare USB3 DRD glue header + */ + +#ifndef __DRIVERS_USB_DWC3_GLUE_H +#define __DRIVERS_USB_DWC3_GLUE_H + +#include <linux/types.h> +#include "core.h" + +/** + * dwc3_probe_data: Initialization parameters passed to dwc3_core_probe() + * @dwc: Reference to dwc3 context structure + * @res: resource for the DWC3 core mmio region + * @ignore_clocks_and_resets: clocks and resets defined for the device should + * be ignored by the DWC3 core, as they are managed by the glue + */ +struct dwc3_probe_data { + struct dwc3 *dwc; + struct resource *res; + bool ignore_clocks_and_resets; +}; + +int dwc3_core_probe(const struct dwc3_probe_data *data); +void dwc3_core_remove(struct dwc3 *dwc); + +int dwc3_runtime_suspend(struct dwc3 *dwc); +int dwc3_runtime_resume(struct dwc3 *dwc); +int dwc3_runtime_idle(struct dwc3 *dwc); +int dwc3_pm_suspend(struct dwc3 *dwc); +int dwc3_pm_resume(struct dwc3 *dwc); +void dwc3_pm_complete(struct dwc3 *dwc); +int dwc3_pm_prepare(struct dwc3 *dwc); + +#endif diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c index b48e108fc8fe..1c513bf8002e 100644 --- a/drivers/usb/dwc3/host.c +++ b/drivers/usb/dwc3/host.c @@ -182,6 +182,9 @@ int dwc3_host_init(struct dwc3 *dwc) if (DWC3_VER_IS_WITHIN(DWC3, ANY, 300A)) props[prop_idx++] = PROPERTY_ENTRY_BOOL("quirk-broken-port-ped"); + props[prop_idx++] = PROPERTY_ENTRY_U16("num-hc-interrupters", + dwc->num_hc_interrupters); + if (prop_idx) { ret = device_create_managed_software_node(&xhci->dev, props, NULL); if (ret) { diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c index ed5a92c474e5..30016b805bfd 100644 --- a/drivers/usb/gadget/epautoconf.c +++ b/drivers/usb/gadget/epautoconf.c @@ -158,7 +158,7 @@ struct usb_ep *usb_ep_autoconfig( if (!ep) return NULL; - type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; + type = usb_endpoint_type(desc); /* report (variable) full speed bulk maxpacket */ if (type == USB_ENDPOINT_XFER_BULK) { diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c index c7a05f842745..97a62b926415 100644 --- a/drivers/usb/gadget/function/f_hid.c +++ b/drivers/usb/gadget/function/f_hid.c @@ -62,6 +62,9 @@ struct f_hidg { unsigned short report_desc_length; char *report_desc; unsigned short report_length; + unsigned char interval; + bool interval_user_set; + /* * use_out_ep - if true, the OUT Endpoint (interrupt out method) * will be used to receive reports from the host @@ -75,6 +78,7 @@ struct f_hidg { /* recv report */ spinlock_t read_spinlock; wait_queue_head_t read_queue; + bool disabled; /* recv report - interrupt out only (use_out_ep == 1) */ struct list_head completed_out_req; unsigned int qlen; @@ -156,10 +160,7 @@ static struct usb_endpoint_descriptor hidg_ss_in_ep_desc = { .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_INT, /*.wMaxPacketSize = DYNAMIC */ - .bInterval = 4, /* FIXME: Add this field in the - * HID gadget configuration? - * (struct hidg_func_descriptor) - */ + /*.bInterval = DYNAMIC */ }; static struct usb_ss_ep_comp_descriptor hidg_ss_in_comp_desc = { @@ -177,10 +178,7 @@ static struct usb_endpoint_descriptor hidg_ss_out_ep_desc = { .bEndpointAddress = USB_DIR_OUT, .bmAttributes = USB_ENDPOINT_XFER_INT, /*.wMaxPacketSize = DYNAMIC */ - .bInterval = 4, /* FIXME: Add this field in the - * HID gadget configuration? - * (struct hidg_func_descriptor) - */ + /*.bInterval = DYNAMIC */ }; static struct usb_ss_ep_comp_descriptor hidg_ss_out_comp_desc = { @@ -218,10 +216,7 @@ static struct usb_endpoint_descriptor hidg_hs_in_ep_desc = { .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_INT, /*.wMaxPacketSize = DYNAMIC */ - .bInterval = 4, /* FIXME: Add this field in the - * HID gadget configuration? - * (struct hidg_func_descriptor) - */ + /* .bInterval = DYNAMIC */ }; static struct usb_endpoint_descriptor hidg_hs_out_ep_desc = { @@ -230,10 +225,7 @@ static struct usb_endpoint_descriptor hidg_hs_out_ep_desc = { .bEndpointAddress = USB_DIR_OUT, .bmAttributes = USB_ENDPOINT_XFER_INT, /*.wMaxPacketSize = DYNAMIC */ - .bInterval = 4, /* FIXME: Add this field in the - * HID gadget configuration? - * (struct hidg_func_descriptor) - */ + /*.bInterval = DYNAMIC */ }; static struct usb_descriptor_header *hidg_hs_descriptors_intout[] = { @@ -259,10 +251,7 @@ static struct usb_endpoint_descriptor hidg_fs_in_ep_desc = { .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_INT, /*.wMaxPacketSize = DYNAMIC */ - .bInterval = 10, /* FIXME: Add this field in the - * HID gadget configuration? - * (struct hidg_func_descriptor) - */ + /*.bInterval = DYNAMIC */ }; static struct usb_endpoint_descriptor hidg_fs_out_ep_desc = { @@ -271,10 +260,7 @@ static struct usb_endpoint_descriptor hidg_fs_out_ep_desc = { .bEndpointAddress = USB_DIR_OUT, .bmAttributes = USB_ENDPOINT_XFER_INT, /*.wMaxPacketSize = DYNAMIC */ - .bInterval = 10, /* FIXME: Add this field in the - * HID gadget configuration? - * (struct hidg_func_descriptor) - */ + /*.bInterval = DYNAMIC */ }; static struct usb_descriptor_header *hidg_fs_descriptors_intout[] = { @@ -329,7 +315,7 @@ static ssize_t f_hidg_intout_read(struct file *file, char __user *buffer, spin_lock_irqsave(&hidg->read_spinlock, flags); -#define READ_COND_INTOUT (!list_empty(&hidg->completed_out_req)) +#define READ_COND_INTOUT (!list_empty(&hidg->completed_out_req) || hidg->disabled) /* wait for at least one buffer to complete */ while (!READ_COND_INTOUT) { @@ -343,6 +329,11 @@ static ssize_t f_hidg_intout_read(struct file *file, char __user *buffer, spin_lock_irqsave(&hidg->read_spinlock, flags); } + if (hidg->disabled) { + spin_unlock_irqrestore(&hidg->read_spinlock, flags); + return -ESHUTDOWN; + } + /* pick the first one */ list = list_first_entry(&hidg->completed_out_req, struct f_hidg_req_list, list); @@ -387,7 +378,7 @@ static ssize_t f_hidg_intout_read(struct file *file, char __user *buffer, return count; } -#define READ_COND_SSREPORT (hidg->set_report_buf != NULL) +#define READ_COND_SSREPORT (hidg->set_report_buf != NULL || hidg->disabled) static ssize_t f_hidg_ssreport_read(struct file *file, char __user *buffer, size_t count, loff_t *ptr) @@ -1012,6 +1003,11 @@ static void hidg_disable(struct usb_function *f) } spin_unlock_irqrestore(&hidg->get_report_spinlock, flags); + spin_lock_irqsave(&hidg->read_spinlock, flags); + hidg->disabled = true; + spin_unlock_irqrestore(&hidg->read_spinlock, flags); + wake_up(&hidg->read_queue); + spin_lock_irqsave(&hidg->write_spinlock, flags); if (!hidg->write_pending) { free_ep_req(hidg->in_ep, hidg->req); @@ -1097,6 +1093,10 @@ static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt) } } + spin_lock_irqsave(&hidg->read_spinlock, flags); + hidg->disabled = false; + spin_unlock_irqrestore(&hidg->read_spinlock, flags); + if (hidg->in_ep != NULL) { spin_lock_irqsave(&hidg->write_spinlock, flags); hidg->req = req_in; @@ -1202,6 +1202,16 @@ static int hidg_bind(struct usb_configuration *c, struct usb_function *f) hidg_hs_in_ep_desc.wMaxPacketSize = cpu_to_le16(hidg->report_length); hidg_fs_in_ep_desc.wMaxPacketSize = cpu_to_le16(hidg->report_length); hidg_ss_out_ep_desc.wMaxPacketSize = cpu_to_le16(hidg->report_length); + + /* IN endpoints: FS default=10ms, HS default=4µ-frame; user override if set */ + if (!hidg->interval_user_set) { + hidg_fs_in_ep_desc.bInterval = 10; + hidg_hs_in_ep_desc.bInterval = 4; + } else { + hidg_fs_in_ep_desc.bInterval = hidg->interval; + hidg_hs_in_ep_desc.bInterval = hidg->interval; + } + hidg_ss_out_comp_desc.wBytesPerInterval = cpu_to_le16(hidg->report_length); hidg_hs_out_ep_desc.wMaxPacketSize = cpu_to_le16(hidg->report_length); @@ -1224,19 +1234,27 @@ static int hidg_bind(struct usb_configuration *c, struct usb_function *f) hidg_ss_out_ep_desc.bEndpointAddress = hidg_fs_out_ep_desc.bEndpointAddress; - if (hidg->use_out_ep) + if (hidg->use_out_ep) { + /* OUT endpoints: same defaults (FS=10, HS=4) unless user set */ + if (!hidg->interval_user_set) { + hidg_fs_out_ep_desc.bInterval = 10; + hidg_hs_out_ep_desc.bInterval = 4; + } else { + hidg_fs_out_ep_desc.bInterval = hidg->interval; + hidg_hs_out_ep_desc.bInterval = hidg->interval; + } status = usb_assign_descriptors(f, - hidg_fs_descriptors_intout, - hidg_hs_descriptors_intout, - hidg_ss_descriptors_intout, - hidg_ss_descriptors_intout); - else + hidg_fs_descriptors_intout, + hidg_hs_descriptors_intout, + hidg_ss_descriptors_intout, + hidg_ss_descriptors_intout); + } else { status = usb_assign_descriptors(f, hidg_fs_descriptors_ssreport, hidg_hs_descriptors_ssreport, hidg_ss_descriptors_ssreport, hidg_ss_descriptors_ssreport); - + } if (status) goto fail; @@ -1408,6 +1426,53 @@ end: CONFIGFS_ATTR(f_hid_opts_, report_desc); +static ssize_t f_hid_opts_interval_show(struct config_item *item, char *page) +{ + struct f_hid_opts *opts = to_f_hid_opts(item); + int result; + + mutex_lock(&opts->lock); + result = sprintf(page, "%d\n", opts->interval); + mutex_unlock(&opts->lock); + + return result; +} + +static ssize_t f_hid_opts_interval_store(struct config_item *item, + const char *page, size_t len) +{ + struct f_hid_opts *opts = to_f_hid_opts(item); + int ret; + unsigned int tmp; + + mutex_lock(&opts->lock); + if (opts->refcnt) { + ret = -EBUSY; + goto end; + } + + /* parse into a wider type first */ + ret = kstrtouint(page, 0, &tmp); + if (ret) + goto end; + + /* range-check against unsigned char max */ + if (tmp > 255) { + ret = -EINVAL; + goto end; + } + + opts->interval = (unsigned char)tmp; + opts->interval_user_set = true; + ret = len; + +end: + mutex_unlock(&opts->lock); + return ret; +} + +CONFIGFS_ATTR(f_hid_opts_, interval); + static ssize_t f_hid_opts_dev_show(struct config_item *item, char *page) { struct f_hid_opts *opts = to_f_hid_opts(item); @@ -1422,6 +1487,7 @@ static struct configfs_attribute *hid_attrs[] = { &f_hid_opts_attr_protocol, &f_hid_opts_attr_no_out_endpoint, &f_hid_opts_attr_report_length, + &f_hid_opts_attr_interval, &f_hid_opts_attr_report_desc, &f_hid_opts_attr_dev, NULL, @@ -1468,6 +1534,10 @@ static struct usb_function_instance *hidg_alloc_inst(void) if (!opts) return ERR_PTR(-ENOMEM); mutex_init(&opts->lock); + + opts->interval = 4; + opts->interval_user_set = false; + opts->func_inst.free_func_inst = hidg_free_inst; ret = &opts->func_inst; @@ -1546,6 +1616,8 @@ static struct usb_function *hidg_alloc(struct usb_function_instance *fi) hidg->bInterfaceProtocol = opts->protocol; hidg->report_length = opts->report_length; hidg->report_desc_length = opts->report_desc_length; + hidg->interval = opts->interval; + hidg->interval_user_set = opts->interval_user_set; if (opts->report_desc) { hidg->report_desc = kmemdup(opts->report_desc, opts->report_desc_length, diff --git a/drivers/usb/gadget/function/f_mass_storage.h b/drivers/usb/gadget/function/f_mass_storage.h index 3b8c4ce2a40a..82ecd3fedb3a 100644 --- a/drivers/usb/gadget/function/f_mass_storage.h +++ b/drivers/usb/gadget/function/f_mass_storage.h @@ -110,7 +110,7 @@ struct fsg_config { }; static inline struct fsg_opts * -fsg_opts_from_func_inst(const struct usb_function_instance *fi) +fsg_opts_from_func_inst(struct usb_function_instance *fi) { return container_of(fi, struct fsg_opts, func_inst); } diff --git a/drivers/usb/gadget/function/f_serial.c b/drivers/usb/gadget/function/f_serial.c index 8f7e7a2b2ff2..0f266bc067f5 100644 --- a/drivers/usb/gadget/function/f_serial.c +++ b/drivers/usb/gadget/function/f_serial.c @@ -364,6 +364,12 @@ static void gser_suspend(struct usb_function *f) gserial_suspend(&gser->port); } +static int gser_get_status(struct usb_function *f) +{ + return (f->func_wakeup_armed ? USB_INTRF_STAT_FUNC_RW : 0) | + USB_INTRF_STAT_FUNC_RW_CAP; +} + static struct usb_function *gser_alloc(struct usb_function_instance *fi) { struct f_gser *gser; @@ -387,6 +393,7 @@ static struct usb_function *gser_alloc(struct usb_function_instance *fi) gser->port.func.free_func = gser_free; gser->port.func.resume = gser_resume; gser->port.func.suspend = gser_suspend; + gser->port.func.get_status = gser_get_status; return &gser->port.func; } diff --git a/drivers/usb/gadget/function/f_tcm.c b/drivers/usb/gadget/function/f_tcm.c index 5a2e1237f85c..6e8804f04baa 100644 --- a/drivers/usb/gadget/function/f_tcm.c +++ b/drivers/usb/gadget/function/f_tcm.c @@ -1641,14 +1641,14 @@ static struct se_portal_group *usbg_make_tpg(struct se_wwn *wwn, struct usbg_tport *tport = container_of(wwn, struct usbg_tport, tport_wwn); struct usbg_tpg *tpg; - unsigned long tpgt; + u16 tpgt; int ret; struct f_tcm_opts *opts; unsigned i; if (strstr(name, "tpgt_") != name) return ERR_PTR(-EINVAL); - if (kstrtoul(name + 5, 0, &tpgt) || tpgt > UINT_MAX) + if (kstrtou16(name + 5, 0, &tpgt)) return ERR_PTR(-EINVAL); ret = -ENODEV; mutex_lock(&tpg_instances_lock); diff --git a/drivers/usb/gadget/function/u_hid.h b/drivers/usb/gadget/function/u_hid.h index 84bb70292855..a9ed9720caee 100644 --- a/drivers/usb/gadget/function/u_hid.h +++ b/drivers/usb/gadget/function/u_hid.h @@ -25,6 +25,8 @@ struct f_hid_opts { unsigned short report_desc_length; unsigned char *report_desc; bool report_desc_alloc; + unsigned char interval; + bool interval_user_set; /* * Protect the data form concurrent access by read/write diff --git a/drivers/usb/gadget/function/u_serial.c b/drivers/usb/gadget/function/u_serial.c index 36fff45e8c9b..ab544f6824be 100644 --- a/drivers/usb/gadget/function/u_serial.c +++ b/drivers/usb/gadget/function/u_serial.c @@ -592,6 +592,17 @@ static int gs_start_io(struct gs_port *port) return status; } +static int gserial_wakeup_host(struct gserial *gser) +{ + struct usb_function *func = &gser->func; + struct usb_gadget *gadget = func->config->cdev->gadget; + + if (func->func_suspended) + return usb_func_wakeup(func); + else + return usb_gadget_wakeup(gadget); +} + /*-------------------------------------------------------------------------*/ /* TTY Driver */ @@ -746,6 +757,8 @@ static ssize_t gs_write(struct tty_struct *tty, const u8 *buf, size_t count) { struct gs_port *port = tty->driver_data; unsigned long flags; + int ret = 0; + struct gserial *gser = port->port_usb; pr_vdebug("gs_write: ttyGS%d (%p) writing %zu bytes\n", port->port_num, tty, count); @@ -753,6 +766,17 @@ static ssize_t gs_write(struct tty_struct *tty, const u8 *buf, size_t count) spin_lock_irqsave(&port->port_lock, flags); if (count) count = kfifo_in(&port->port_write_buf, buf, count); + + if (port->suspended) { + spin_unlock_irqrestore(&port->port_lock, flags); + ret = gserial_wakeup_host(gser); + if (ret) { + pr_debug("ttyGS%d: Remote wakeup failed:%d\n", port->port_num, ret); + return count; + } + spin_lock_irqsave(&port->port_lock, flags); + } + /* treat count == 0 as flush_chars() */ if (port->port_usb) gs_start_tx(port); @@ -781,10 +805,22 @@ static void gs_flush_chars(struct tty_struct *tty) { struct gs_port *port = tty->driver_data; unsigned long flags; + int ret = 0; + struct gserial *gser = port->port_usb; pr_vdebug("gs_flush_chars: (%d,%p)\n", port->port_num, tty); spin_lock_irqsave(&port->port_lock, flags); + if (port->suspended) { + spin_unlock_irqrestore(&port->port_lock, flags); + ret = gserial_wakeup_host(gser); + if (ret) { + pr_debug("ttyGS%d: Remote wakeup failed:%d\n", port->port_num, ret); + return; + } + spin_lock_irqsave(&port->port_lock, flags); + } + if (port->port_usb) gs_start_tx(port); spin_unlock_irqrestore(&port->port_lock, flags); @@ -1464,6 +1500,20 @@ void gserial_suspend(struct gserial *gser) return; } + if (port->write_busy || port->write_started) { + /* Wakeup to host if there are ongoing transfers */ + spin_unlock_irqrestore(&serial_port_lock, flags); + if (!gserial_wakeup_host(gser)) + return; + + /* Check if port is valid after acquiring lock back */ + spin_lock_irqsave(&serial_port_lock, flags); + if (!port) { + spin_unlock_irqrestore(&serial_port_lock, flags); + return; + } + } + spin_lock(&port->port_lock); spin_unlock(&serial_port_lock); port->suspended = true; diff --git a/drivers/usb/gadget/function/uvc_configfs.h b/drivers/usb/gadget/function/uvc_configfs.h index 2f78cd4f396f..9391614135e9 100644 --- a/drivers/usb/gadget/function/uvc_configfs.h +++ b/drivers/usb/gadget/function/uvc_configfs.h @@ -74,10 +74,12 @@ static inline struct uvcg_format *to_uvcg_format(struct config_item *item) struct uvcg_streaming_header { struct config_item item; - struct uvc_input_header_descriptor desc; unsigned linked; struct list_head formats; unsigned num_fmt; + + /* Must be last --ends in a flexible-array member. */ + struct uvc_input_header_descriptor desc; }; static inline struct uvcg_streaming_header *to_uvcg_streaming_header(struct config_item *item) diff --git a/drivers/usb/gadget/legacy/g_ffs.c b/drivers/usb/gadget/legacy/g_ffs.c index a9544fea8723..578556422ea3 100644 --- a/drivers/usb/gadget/legacy/g_ffs.c +++ b/drivers/usb/gadget/legacy/g_ffs.c @@ -188,7 +188,7 @@ static int __init gfs_init(void) /* * Allocate in one chunk for easier maintenance */ - f_ffs[0] = kcalloc(func_num * N_CONF, sizeof(*f_ffs), GFP_KERNEL); + f_ffs[0] = kcalloc(func_num * N_CONF, sizeof(*f_ffs[0]), GFP_KERNEL); if (!f_ffs[0]) { ret = -ENOMEM; goto no_func; diff --git a/drivers/usb/gadget/legacy/inode.c b/drivers/usb/gadget/legacy/inode.c index b6a30d88a800..fcce84a726f2 100644 --- a/drivers/usb/gadget/legacy/inode.c +++ b/drivers/usb/gadget/legacy/inode.c @@ -1615,7 +1615,7 @@ static int activate_ep_files (struct dev_data *dev) mutex_init(&data->lock); init_waitqueue_head (&data->wait); - strncpy (data->name, ep->name, sizeof (data->name) - 1); + strscpy(data->name, ep->name); refcount_set (&data->count, 1); data->dev = dev; get_dev (dev); diff --git a/drivers/usb/gadget/udc/Kconfig b/drivers/usb/gadget/udc/Kconfig index aae1787320d4..26460340fbc9 100644 --- a/drivers/usb/gadget/udc/Kconfig +++ b/drivers/usb/gadget/udc/Kconfig @@ -102,12 +102,6 @@ config USB_FSL_USB2 dynamically linked module called "fsl_usb2_udc" and force all gadget drivers to also be dynamically linked. -config USB_FUSB300 - tristate "Faraday FUSB300 USB Peripheral Controller" - depends on !PHYS_ADDR_T_64BIT && HAS_DMA - help - Faraday usb device controller FUSB300 driver - config USB_GR_UDC tristate "Aeroflex Gaisler GRUSBDC USB Peripheral Controller Driver" depends on HAS_DMA @@ -228,21 +222,6 @@ config USB_PXA27X dynamically linked module called "pxa27x_udc" and force all gadget drivers to also be dynamically linked. -config USB_MV_UDC - tristate "Marvell USB2.0 Device Controller" - depends on HAS_DMA - help - Marvell Socs (including PXA and MMP series) include a high speed - USB2.0 OTG controller, which can be configured as high speed or - full speed USB peripheral. - -config USB_MV_U3D - depends on HAS_DMA - tristate "MARVELL PXA2128 USB 3.0 controller" - help - MARVELL PXA2128 Processor series include a super speed USB3.0 device - controller, which support super speed USB peripheral. - config USB_SNP_CORE depends on (USB_AMD5536UDC || USB_SNP_UDC_PLAT) depends on HAS_DMA @@ -326,29 +305,6 @@ config USB_FSL_QE Set CONFIG_USB_GADGET to "m" to build this driver as a dynamically linked module called "fsl_qe_udc". -config USB_NET2272 - depends on HAS_IOMEM - tristate "PLX NET2272" - help - PLX NET2272 is a USB peripheral controller which supports - both full and high speed USB 2.0 data transfers. - - It has three configurable endpoints, as well as endpoint zero - (for control transfer). - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "net2272" and force all - gadget drivers to also be dynamically linked. - -config USB_NET2272_DMA - bool "Support external DMA controller" - depends on USB_NET2272 && HAS_DMA - help - The NET2272 part can optionally support an external DMA - controller, but your board has to have support in the - driver itself. - - If unsure, say "N" here. The driver works fine in PIO mode. - config USB_NET2280 tristate "NetChip NET228x / PLX USB3x8x" depends on USB_PCI diff --git a/drivers/usb/gadget/udc/Makefile b/drivers/usb/gadget/udc/Makefile index b52f93e9c61d..1b9b1a4f9c57 100644 --- a/drivers/usb/gadget/udc/Makefile +++ b/drivers/usb/gadget/udc/Makefile @@ -9,7 +9,6 @@ udc-core-y := core.o trace.o # obj-$(CONFIG_USB_GADGET) += udc-core.o obj-$(CONFIG_USB_DUMMY_HCD) += dummy_hcd.o -obj-$(CONFIG_USB_NET2272) += net2272.o obj-$(CONFIG_USB_NET2280) += net2280.o obj-$(CONFIG_USB_SNP_CORE) += snps_udc_core.o obj-$(CONFIG_USB_AMD5536UDC) += amd5536udc_pci.o @@ -31,10 +30,6 @@ obj-$(CONFIG_USB_RENESAS_USBF) += renesas_usbf.o obj-$(CONFIG_USB_FSL_QE) += fsl_qe_udc.o obj-$(CONFIG_USB_LPC32XX) += lpc32xx_udc.o obj-$(CONFIG_USB_EG20T) += pch_udc.o -obj-$(CONFIG_USB_MV_UDC) += mv_udc.o -mv_udc-y := mv_udc_core.o -obj-$(CONFIG_USB_FUSB300) += fusb300_udc.o -obj-$(CONFIG_USB_MV_U3D) += mv_u3d_core.o obj-$(CONFIG_USB_GR_UDC) += gr_udc.o obj-$(CONFIG_USB_GADGET_XILINX) += udc-xilinx.o obj-$(CONFIG_USB_SNP_UDC_PLAT) += snps_udc_plat.o diff --git a/drivers/usb/gadget/udc/at91_udc.c b/drivers/usb/gadget/udc/at91_udc.c index aa4c61094dc6..42b94d858e37 100644 --- a/drivers/usb/gadget/udc/at91_udc.c +++ b/drivers/usb/gadget/udc/at91_udc.c @@ -1541,7 +1541,7 @@ static void at91_vbus_timer_work(struct work_struct *work) static void at91_vbus_timer(struct timer_list *t) { - struct at91_udc *udc = from_timer(udc, t, vbus_timer); + struct at91_udc *udc = timer_container_of(udc, t, vbus_timer); /* * If we are polling vbus it is likely that the gpio is on an diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c index 4b3d5075621a..d709e24c1fd4 100644 --- a/drivers/usb/gadget/udc/core.c +++ b/drivers/usb/gadget/udc/core.c @@ -1570,7 +1570,7 @@ static int gadget_match_driver(struct device *dev, const struct device_driver *d { struct usb_gadget *gadget = dev_to_usb_gadget(dev); struct usb_udc *udc = gadget->udc; - struct usb_gadget_driver *driver = container_of(drv, + const struct usb_gadget_driver *driver = container_of(drv, struct usb_gadget_driver, driver); /* If the driver specifies a udc_name, it must match the UDC's name */ diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c index 4f1b5db51dda..27c9699365ab 100644 --- a/drivers/usb/gadget/udc/dummy_hcd.c +++ b/drivers/usb/gadget/udc/dummy_hcd.c @@ -1787,7 +1787,8 @@ static int handle_control_request(struct dummy_hcd *dum_hcd, struct urb *urb, */ static enum hrtimer_restart dummy_timer(struct hrtimer *t) { - struct dummy_hcd *dum_hcd = from_timer(dum_hcd, t, timer); + struct dummy_hcd *dum_hcd = timer_container_of(dum_hcd, t, + timer); struct dummy *dum = dum_hcd->dum; struct urbp *urbp, *tmp; unsigned long flags; diff --git a/drivers/usb/gadget/udc/fusb300_udc.c b/drivers/usb/gadget/udc/fusb300_udc.c deleted file mode 100644 index 5e94a99b3e53..000000000000 --- a/drivers/usb/gadget/udc/fusb300_udc.c +++ /dev/null @@ -1,1516 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Fusb300 UDC (USB gadget) - * - * Copyright (C) 2010 Faraday Technology Corp. - * - * Author : Yuan-hsin Chen <yhchen@faraday-tech.com> - */ -#include <linux/dma-mapping.h> -#include <linux/err.h> -#include <linux/interrupt.h> -#include <linux/io.h> -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/usb/ch9.h> -#include <linux/usb/gadget.h> - -#include "fusb300_udc.h" - -MODULE_DESCRIPTION("FUSB300 USB gadget driver"); -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Yuan-Hsin Chen, Feng-Hsin Chiang <john453@faraday-tech.com>"); -MODULE_ALIAS("platform:fusb300_udc"); - -#define DRIVER_VERSION "20 October 2010" - -static const char udc_name[] = "fusb300_udc"; -static const char * const fusb300_ep_name[] = { - "ep0", "ep1", "ep2", "ep3", "ep4", "ep5", "ep6", "ep7", "ep8", "ep9", - "ep10", "ep11", "ep12", "ep13", "ep14", "ep15" -}; - -static void done(struct fusb300_ep *ep, struct fusb300_request *req, - int status); - -static void fusb300_enable_bit(struct fusb300 *fusb300, u32 offset, - u32 value) -{ - u32 reg = ioread32(fusb300->reg + offset); - - reg |= value; - iowrite32(reg, fusb300->reg + offset); -} - -static void fusb300_disable_bit(struct fusb300 *fusb300, u32 offset, - u32 value) -{ - u32 reg = ioread32(fusb300->reg + offset); - - reg &= ~value; - iowrite32(reg, fusb300->reg + offset); -} - - -static void fusb300_ep_setting(struct fusb300_ep *ep, - struct fusb300_ep_info info) -{ - ep->epnum = info.epnum; - ep->type = info.type; -} - -static int fusb300_ep_release(struct fusb300_ep *ep) -{ - if (!ep->epnum) - return 0; - ep->epnum = 0; - ep->stall = 0; - ep->wedged = 0; - return 0; -} - -static void fusb300_set_fifo_entry(struct fusb300 *fusb300, - u32 ep) -{ - u32 val = ioread32(fusb300->reg + FUSB300_OFFSET_EPSET1(ep)); - - val &= ~FUSB300_EPSET1_FIFOENTRY_MSK; - val |= FUSB300_EPSET1_FIFOENTRY(FUSB300_FIFO_ENTRY_NUM); - iowrite32(val, fusb300->reg + FUSB300_OFFSET_EPSET1(ep)); -} - -static void fusb300_set_start_entry(struct fusb300 *fusb300, - u8 ep) -{ - u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPSET1(ep)); - u32 start_entry = fusb300->fifo_entry_num * FUSB300_FIFO_ENTRY_NUM; - - reg &= ~FUSB300_EPSET1_START_ENTRY_MSK ; - reg |= FUSB300_EPSET1_START_ENTRY(start_entry); - iowrite32(reg, fusb300->reg + FUSB300_OFFSET_EPSET1(ep)); - if (fusb300->fifo_entry_num == FUSB300_MAX_FIFO_ENTRY) { - fusb300->fifo_entry_num = 0; - fusb300->addrofs = 0; - pr_err("fifo entry is over the maximum number!\n"); - } else - fusb300->fifo_entry_num++; -} - -/* set fusb300_set_start_entry first before fusb300_set_epaddrofs */ -static void fusb300_set_epaddrofs(struct fusb300 *fusb300, - struct fusb300_ep_info info) -{ - u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPSET2(info.epnum)); - - reg &= ~FUSB300_EPSET2_ADDROFS_MSK; - reg |= FUSB300_EPSET2_ADDROFS(fusb300->addrofs); - iowrite32(reg, fusb300->reg + FUSB300_OFFSET_EPSET2(info.epnum)); - fusb300->addrofs += (info.maxpacket + 7) / 8 * FUSB300_FIFO_ENTRY_NUM; -} - -static void ep_fifo_setting(struct fusb300 *fusb300, - struct fusb300_ep_info info) -{ - fusb300_set_fifo_entry(fusb300, info.epnum); - fusb300_set_start_entry(fusb300, info.epnum); - fusb300_set_epaddrofs(fusb300, info); -} - -static void fusb300_set_eptype(struct fusb300 *fusb300, - struct fusb300_ep_info info) -{ - u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPSET1(info.epnum)); - - reg &= ~FUSB300_EPSET1_TYPE_MSK; - reg |= FUSB300_EPSET1_TYPE(info.type); - iowrite32(reg, fusb300->reg + FUSB300_OFFSET_EPSET1(info.epnum)); -} - -static void fusb300_set_epdir(struct fusb300 *fusb300, - struct fusb300_ep_info info) -{ - u32 reg; - - if (!info.dir_in) - return; - reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPSET1(info.epnum)); - reg &= ~FUSB300_EPSET1_DIR_MSK; - reg |= FUSB300_EPSET1_DIRIN; - iowrite32(reg, fusb300->reg + FUSB300_OFFSET_EPSET1(info.epnum)); -} - -static void fusb300_set_ep_active(struct fusb300 *fusb300, - u8 ep) -{ - u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPSET1(ep)); - - reg |= FUSB300_EPSET1_ACTEN; - iowrite32(reg, fusb300->reg + FUSB300_OFFSET_EPSET1(ep)); -} - -static void fusb300_set_epmps(struct fusb300 *fusb300, - struct fusb300_ep_info info) -{ - u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPSET2(info.epnum)); - - reg &= ~FUSB300_EPSET2_MPS_MSK; - reg |= FUSB300_EPSET2_MPS(info.maxpacket); - iowrite32(reg, fusb300->reg + FUSB300_OFFSET_EPSET2(info.epnum)); -} - -static void fusb300_set_interval(struct fusb300 *fusb300, - struct fusb300_ep_info info) -{ - u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPSET1(info.epnum)); - - reg &= ~FUSB300_EPSET1_INTERVAL(0x7); - reg |= FUSB300_EPSET1_INTERVAL(info.interval); - iowrite32(reg, fusb300->reg + FUSB300_OFFSET_EPSET1(info.epnum)); -} - -static void fusb300_set_bwnum(struct fusb300 *fusb300, - struct fusb300_ep_info info) -{ - u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPSET1(info.epnum)); - - reg &= ~FUSB300_EPSET1_BWNUM(0x3); - reg |= FUSB300_EPSET1_BWNUM(info.bw_num); - iowrite32(reg, fusb300->reg + FUSB300_OFFSET_EPSET1(info.epnum)); -} - -static void set_ep_reg(struct fusb300 *fusb300, - struct fusb300_ep_info info) -{ - fusb300_set_eptype(fusb300, info); - fusb300_set_epdir(fusb300, info); - fusb300_set_epmps(fusb300, info); - - if (info.interval) - fusb300_set_interval(fusb300, info); - - if (info.bw_num) - fusb300_set_bwnum(fusb300, info); - - fusb300_set_ep_active(fusb300, info.epnum); -} - -static int config_ep(struct fusb300_ep *ep, - const struct usb_endpoint_descriptor *desc) -{ - struct fusb300 *fusb300 = ep->fusb300; - struct fusb300_ep_info info; - - ep->ep.desc = desc; - - info.interval = 0; - info.addrofs = 0; - info.bw_num = 0; - - info.type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; - info.dir_in = (desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) ? 1 : 0; - info.maxpacket = usb_endpoint_maxp(desc); - info.epnum = desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; - - if ((info.type == USB_ENDPOINT_XFER_INT) || - (info.type == USB_ENDPOINT_XFER_ISOC)) { - info.interval = desc->bInterval; - if (info.type == USB_ENDPOINT_XFER_ISOC) - info.bw_num = usb_endpoint_maxp_mult(desc); - } - - ep_fifo_setting(fusb300, info); - - set_ep_reg(fusb300, info); - - fusb300_ep_setting(ep, info); - - fusb300->ep[info.epnum] = ep; - - return 0; -} - -static int fusb300_enable(struct usb_ep *_ep, - const struct usb_endpoint_descriptor *desc) -{ - struct fusb300_ep *ep; - - ep = container_of(_ep, struct fusb300_ep, ep); - - if (ep->fusb300->reenum) { - ep->fusb300->fifo_entry_num = 0; - ep->fusb300->addrofs = 0; - ep->fusb300->reenum = 0; - } - - return config_ep(ep, desc); -} - -static int fusb300_disable(struct usb_ep *_ep) -{ - struct fusb300_ep *ep; - struct fusb300_request *req; - unsigned long flags; - - ep = container_of(_ep, struct fusb300_ep, ep); - - BUG_ON(!ep); - - while (!list_empty(&ep->queue)) { - req = list_entry(ep->queue.next, struct fusb300_request, queue); - spin_lock_irqsave(&ep->fusb300->lock, flags); - done(ep, req, -ECONNRESET); - spin_unlock_irqrestore(&ep->fusb300->lock, flags); - } - - return fusb300_ep_release(ep); -} - -static struct usb_request *fusb300_alloc_request(struct usb_ep *_ep, - gfp_t gfp_flags) -{ - struct fusb300_request *req; - - req = kzalloc(sizeof(struct fusb300_request), gfp_flags); - if (!req) - return NULL; - INIT_LIST_HEAD(&req->queue); - - return &req->req; -} - -static void fusb300_free_request(struct usb_ep *_ep, struct usb_request *_req) -{ - struct fusb300_request *req; - - req = container_of(_req, struct fusb300_request, req); - kfree(req); -} - -static int enable_fifo_int(struct fusb300_ep *ep) -{ - struct fusb300 *fusb300 = ep->fusb300; - - if (ep->epnum) { - fusb300_enable_bit(fusb300, FUSB300_OFFSET_IGER0, - FUSB300_IGER0_EEPn_FIFO_INT(ep->epnum)); - } else { - pr_err("can't enable_fifo_int ep0\n"); - return -EINVAL; - } - - return 0; -} - -static int disable_fifo_int(struct fusb300_ep *ep) -{ - struct fusb300 *fusb300 = ep->fusb300; - - if (ep->epnum) { - fusb300_disable_bit(fusb300, FUSB300_OFFSET_IGER0, - FUSB300_IGER0_EEPn_FIFO_INT(ep->epnum)); - } else { - pr_err("can't disable_fifo_int ep0\n"); - return -EINVAL; - } - - return 0; -} - -static void fusb300_set_cxlen(struct fusb300 *fusb300, u32 length) -{ - u32 reg; - - reg = ioread32(fusb300->reg + FUSB300_OFFSET_CSR); - reg &= ~FUSB300_CSR_LEN_MSK; - reg |= FUSB300_CSR_LEN(length); - iowrite32(reg, fusb300->reg + FUSB300_OFFSET_CSR); -} - -/* write data to cx fifo */ -static void fusb300_wrcxf(struct fusb300_ep *ep, - struct fusb300_request *req) -{ - int i = 0; - u8 *tmp; - u32 data; - struct fusb300 *fusb300 = ep->fusb300; - u32 length = req->req.length - req->req.actual; - - tmp = req->req.buf + req->req.actual; - - if (length > SS_CTL_MAX_PACKET_SIZE) { - fusb300_set_cxlen(fusb300, SS_CTL_MAX_PACKET_SIZE); - for (i = (SS_CTL_MAX_PACKET_SIZE >> 2); i > 0; i--) { - data = *tmp | *(tmp + 1) << 8 | *(tmp + 2) << 16 | - *(tmp + 3) << 24; - iowrite32(data, fusb300->reg + FUSB300_OFFSET_CXPORT); - tmp += 4; - } - req->req.actual += SS_CTL_MAX_PACKET_SIZE; - } else { /* length is less than max packet size */ - fusb300_set_cxlen(fusb300, length); - for (i = length >> 2; i > 0; i--) { - data = *tmp | *(tmp + 1) << 8 | *(tmp + 2) << 16 | - *(tmp + 3) << 24; - printk(KERN_DEBUG " 0x%x\n", data); - iowrite32(data, fusb300->reg + FUSB300_OFFSET_CXPORT); - tmp = tmp + 4; - } - switch (length % 4) { - case 1: - data = *tmp; - printk(KERN_DEBUG " 0x%x\n", data); - iowrite32(data, fusb300->reg + FUSB300_OFFSET_CXPORT); - break; - case 2: - data = *tmp | *(tmp + 1) << 8; - printk(KERN_DEBUG " 0x%x\n", data); - iowrite32(data, fusb300->reg + FUSB300_OFFSET_CXPORT); - break; - case 3: - data = *tmp | *(tmp + 1) << 8 | *(tmp + 2) << 16; - printk(KERN_DEBUG " 0x%x\n", data); - iowrite32(data, fusb300->reg + FUSB300_OFFSET_CXPORT); - break; - default: - break; - } - req->req.actual += length; - } -} - -static void fusb300_set_epnstall(struct fusb300 *fusb300, u8 ep) -{ - fusb300_enable_bit(fusb300, FUSB300_OFFSET_EPSET0(ep), - FUSB300_EPSET0_STL); -} - -static void fusb300_clear_epnstall(struct fusb300 *fusb300, u8 ep) -{ - u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPSET0(ep)); - - if (reg & FUSB300_EPSET0_STL) { - printk(KERN_DEBUG "EP%d stall... Clear!!\n", ep); - reg |= FUSB300_EPSET0_STL_CLR; - iowrite32(reg, fusb300->reg + FUSB300_OFFSET_EPSET0(ep)); - } -} - -static void ep0_queue(struct fusb300_ep *ep, struct fusb300_request *req) -{ - if (ep->fusb300->ep0_dir) { /* if IN */ - if (req->req.length) { - fusb300_wrcxf(ep, req); - } else - printk(KERN_DEBUG "%s : req->req.length = 0x%x\n", - __func__, req->req.length); - if ((req->req.length == req->req.actual) || - (req->req.actual < ep->ep.maxpacket)) - done(ep, req, 0); - } else { /* OUT */ - if (!req->req.length) - done(ep, req, 0); - else - fusb300_enable_bit(ep->fusb300, FUSB300_OFFSET_IGER1, - FUSB300_IGER1_CX_OUT_INT); - } -} - -static int fusb300_queue(struct usb_ep *_ep, struct usb_request *_req, - gfp_t gfp_flags) -{ - struct fusb300_ep *ep; - struct fusb300_request *req; - unsigned long flags; - int request = 0; - - ep = container_of(_ep, struct fusb300_ep, ep); - req = container_of(_req, struct fusb300_request, req); - - if (ep->fusb300->gadget.speed == USB_SPEED_UNKNOWN) - return -ESHUTDOWN; - - spin_lock_irqsave(&ep->fusb300->lock, flags); - - if (list_empty(&ep->queue)) - request = 1; - - list_add_tail(&req->queue, &ep->queue); - - req->req.actual = 0; - req->req.status = -EINPROGRESS; - - if (ep->ep.desc == NULL) /* ep0 */ - ep0_queue(ep, req); - else if (request && !ep->stall) - enable_fifo_int(ep); - - spin_unlock_irqrestore(&ep->fusb300->lock, flags); - - return 0; -} - -static int fusb300_dequeue(struct usb_ep *_ep, struct usb_request *_req) -{ - struct fusb300_ep *ep; - struct fusb300_request *req; - unsigned long flags; - - ep = container_of(_ep, struct fusb300_ep, ep); - req = container_of(_req, struct fusb300_request, req); - - spin_lock_irqsave(&ep->fusb300->lock, flags); - if (!list_empty(&ep->queue)) - done(ep, req, -ECONNRESET); - spin_unlock_irqrestore(&ep->fusb300->lock, flags); - - return 0; -} - -static int fusb300_set_halt_and_wedge(struct usb_ep *_ep, int value, int wedge) -{ - struct fusb300_ep *ep; - struct fusb300 *fusb300; - unsigned long flags; - int ret = 0; - - ep = container_of(_ep, struct fusb300_ep, ep); - - fusb300 = ep->fusb300; - - spin_lock_irqsave(&ep->fusb300->lock, flags); - - if (!list_empty(&ep->queue)) { - ret = -EAGAIN; - goto out; - } - - if (value) { - fusb300_set_epnstall(fusb300, ep->epnum); - ep->stall = 1; - if (wedge) - ep->wedged = 1; - } else { - fusb300_clear_epnstall(fusb300, ep->epnum); - ep->stall = 0; - ep->wedged = 0; - } - -out: - spin_unlock_irqrestore(&ep->fusb300->lock, flags); - return ret; -} - -static int fusb300_set_halt(struct usb_ep *_ep, int value) -{ - return fusb300_set_halt_and_wedge(_ep, value, 0); -} - -static int fusb300_set_wedge(struct usb_ep *_ep) -{ - return fusb300_set_halt_and_wedge(_ep, 1, 1); -} - -static void fusb300_fifo_flush(struct usb_ep *_ep) -{ -} - -static const struct usb_ep_ops fusb300_ep_ops = { - .enable = fusb300_enable, - .disable = fusb300_disable, - - .alloc_request = fusb300_alloc_request, - .free_request = fusb300_free_request, - - .queue = fusb300_queue, - .dequeue = fusb300_dequeue, - - .set_halt = fusb300_set_halt, - .fifo_flush = fusb300_fifo_flush, - .set_wedge = fusb300_set_wedge, -}; - -/*****************************************************************************/ -static void fusb300_clear_int(struct fusb300 *fusb300, u32 offset, - u32 value) -{ - iowrite32(value, fusb300->reg + offset); -} - -static void fusb300_reset(void) -{ -} - -static void fusb300_set_cxstall(struct fusb300 *fusb300) -{ - fusb300_enable_bit(fusb300, FUSB300_OFFSET_CSR, - FUSB300_CSR_STL); -} - -static void fusb300_set_cxdone(struct fusb300 *fusb300) -{ - fusb300_enable_bit(fusb300, FUSB300_OFFSET_CSR, - FUSB300_CSR_DONE); -} - -/* read data from cx fifo */ -static void fusb300_rdcxf(struct fusb300 *fusb300, - u8 *buffer, u32 length) -{ - int i = 0; - u8 *tmp; - u32 data; - - tmp = buffer; - - for (i = (length >> 2); i > 0; i--) { - data = ioread32(fusb300->reg + FUSB300_OFFSET_CXPORT); - printk(KERN_DEBUG " 0x%x\n", data); - *tmp = data & 0xFF; - *(tmp + 1) = (data >> 8) & 0xFF; - *(tmp + 2) = (data >> 16) & 0xFF; - *(tmp + 3) = (data >> 24) & 0xFF; - tmp = tmp + 4; - } - - switch (length % 4) { - case 1: - data = ioread32(fusb300->reg + FUSB300_OFFSET_CXPORT); - printk(KERN_DEBUG " 0x%x\n", data); - *tmp = data & 0xFF; - break; - case 2: - data = ioread32(fusb300->reg + FUSB300_OFFSET_CXPORT); - printk(KERN_DEBUG " 0x%x\n", data); - *tmp = data & 0xFF; - *(tmp + 1) = (data >> 8) & 0xFF; - break; - case 3: - data = ioread32(fusb300->reg + FUSB300_OFFSET_CXPORT); - printk(KERN_DEBUG " 0x%x\n", data); - *tmp = data & 0xFF; - *(tmp + 1) = (data >> 8) & 0xFF; - *(tmp + 2) = (data >> 16) & 0xFF; - break; - default: - break; - } -} - -static void fusb300_rdfifo(struct fusb300_ep *ep, - struct fusb300_request *req, - u32 length) -{ - int i = 0; - u8 *tmp; - u32 data, reg; - struct fusb300 *fusb300 = ep->fusb300; - - tmp = req->req.buf + req->req.actual; - req->req.actual += length; - - if (req->req.actual > req->req.length) - printk(KERN_DEBUG "req->req.actual > req->req.length\n"); - - for (i = (length >> 2); i > 0; i--) { - data = ioread32(fusb300->reg + - FUSB300_OFFSET_EPPORT(ep->epnum)); - *tmp = data & 0xFF; - *(tmp + 1) = (data >> 8) & 0xFF; - *(tmp + 2) = (data >> 16) & 0xFF; - *(tmp + 3) = (data >> 24) & 0xFF; - tmp = tmp + 4; - } - - switch (length % 4) { - case 1: - data = ioread32(fusb300->reg + - FUSB300_OFFSET_EPPORT(ep->epnum)); - *tmp = data & 0xFF; - break; - case 2: - data = ioread32(fusb300->reg + - FUSB300_OFFSET_EPPORT(ep->epnum)); - *tmp = data & 0xFF; - *(tmp + 1) = (data >> 8) & 0xFF; - break; - case 3: - data = ioread32(fusb300->reg + - FUSB300_OFFSET_EPPORT(ep->epnum)); - *tmp = data & 0xFF; - *(tmp + 1) = (data >> 8) & 0xFF; - *(tmp + 2) = (data >> 16) & 0xFF; - break; - default: - break; - } - - do { - reg = ioread32(fusb300->reg + FUSB300_OFFSET_IGR1); - reg &= FUSB300_IGR1_SYNF0_EMPTY_INT; - if (i) - printk(KERN_INFO "sync fifo is not empty!\n"); - i++; - } while (!reg); -} - -static u8 fusb300_get_epnstall(struct fusb300 *fusb300, u8 ep) -{ - u8 value; - u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPSET0(ep)); - - value = reg & FUSB300_EPSET0_STL; - - return value; -} - -static u8 fusb300_get_cxstall(struct fusb300 *fusb300) -{ - u8 value; - u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_CSR); - - value = (reg & FUSB300_CSR_STL) >> 1; - - return value; -} - -static void request_error(struct fusb300 *fusb300) -{ - fusb300_set_cxstall(fusb300); - printk(KERN_DEBUG "request error!!\n"); -} - -static void get_status(struct fusb300 *fusb300, struct usb_ctrlrequest *ctrl) -__releases(fusb300->lock) -__acquires(fusb300->lock) -{ - u8 ep; - u16 status = 0; - u16 w_index = ctrl->wIndex; - - switch (ctrl->bRequestType & USB_RECIP_MASK) { - case USB_RECIP_DEVICE: - status = 1 << USB_DEVICE_SELF_POWERED; - break; - case USB_RECIP_INTERFACE: - status = 0; - break; - case USB_RECIP_ENDPOINT: - ep = w_index & USB_ENDPOINT_NUMBER_MASK; - if (ep) { - if (fusb300_get_epnstall(fusb300, ep)) - status = 1 << USB_ENDPOINT_HALT; - } else { - if (fusb300_get_cxstall(fusb300)) - status = 0; - } - break; - - default: - request_error(fusb300); - return; /* exit */ - } - - fusb300->ep0_data = cpu_to_le16(status); - fusb300->ep0_req->buf = &fusb300->ep0_data; - fusb300->ep0_req->length = 2; - - spin_unlock(&fusb300->lock); - fusb300_queue(fusb300->gadget.ep0, fusb300->ep0_req, GFP_KERNEL); - spin_lock(&fusb300->lock); -} - -static void set_feature(struct fusb300 *fusb300, struct usb_ctrlrequest *ctrl) -{ - u8 ep; - - switch (ctrl->bRequestType & USB_RECIP_MASK) { - case USB_RECIP_DEVICE: - fusb300_set_cxdone(fusb300); - break; - case USB_RECIP_INTERFACE: - fusb300_set_cxdone(fusb300); - break; - case USB_RECIP_ENDPOINT: { - u16 w_index = le16_to_cpu(ctrl->wIndex); - - ep = w_index & USB_ENDPOINT_NUMBER_MASK; - if (ep) - fusb300_set_epnstall(fusb300, ep); - else - fusb300_set_cxstall(fusb300); - fusb300_set_cxdone(fusb300); - } - break; - default: - request_error(fusb300); - break; - } -} - -static void fusb300_clear_seqnum(struct fusb300 *fusb300, u8 ep) -{ - fusb300_enable_bit(fusb300, FUSB300_OFFSET_EPSET0(ep), - FUSB300_EPSET0_CLRSEQNUM); -} - -static void clear_feature(struct fusb300 *fusb300, struct usb_ctrlrequest *ctrl) -{ - struct fusb300_ep *ep = - fusb300->ep[ctrl->wIndex & USB_ENDPOINT_NUMBER_MASK]; - - switch (ctrl->bRequestType & USB_RECIP_MASK) { - case USB_RECIP_DEVICE: - fusb300_set_cxdone(fusb300); - break; - case USB_RECIP_INTERFACE: - fusb300_set_cxdone(fusb300); - break; - case USB_RECIP_ENDPOINT: - if (ctrl->wIndex & USB_ENDPOINT_NUMBER_MASK) { - if (ep->wedged) { - fusb300_set_cxdone(fusb300); - break; - } - if (ep->stall) { - ep->stall = 0; - fusb300_clear_seqnum(fusb300, ep->epnum); - fusb300_clear_epnstall(fusb300, ep->epnum); - if (!list_empty(&ep->queue)) - enable_fifo_int(ep); - } - } - fusb300_set_cxdone(fusb300); - break; - default: - request_error(fusb300); - break; - } -} - -static void fusb300_set_dev_addr(struct fusb300 *fusb300, u16 addr) -{ - u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_DAR); - - reg &= ~FUSB300_DAR_DRVADDR_MSK; - reg |= FUSB300_DAR_DRVADDR(addr); - - iowrite32(reg, fusb300->reg + FUSB300_OFFSET_DAR); -} - -static void set_address(struct fusb300 *fusb300, struct usb_ctrlrequest *ctrl) -{ - if (ctrl->wValue >= 0x0100) - request_error(fusb300); - else { - fusb300_set_dev_addr(fusb300, ctrl->wValue); - fusb300_set_cxdone(fusb300); - } -} - -#define UVC_COPY_DESCRIPTORS(mem, src) \ - do { \ - const struct usb_descriptor_header * const *__src; \ - for (__src = src; *__src; ++__src) { \ - memcpy(mem, *__src, (*__src)->bLength); \ - mem += (*__src)->bLength; \ - } \ - } while (0) - -static int setup_packet(struct fusb300 *fusb300, struct usb_ctrlrequest *ctrl) -{ - u8 *p = (u8 *)ctrl; - u8 ret = 0; - u8 i = 0; - - fusb300_rdcxf(fusb300, p, 8); - fusb300->ep0_dir = ctrl->bRequestType & USB_DIR_IN; - fusb300->ep0_length = ctrl->wLength; - - /* check request */ - if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) { - switch (ctrl->bRequest) { - case USB_REQ_GET_STATUS: - get_status(fusb300, ctrl); - break; - case USB_REQ_CLEAR_FEATURE: - clear_feature(fusb300, ctrl); - break; - case USB_REQ_SET_FEATURE: - set_feature(fusb300, ctrl); - break; - case USB_REQ_SET_ADDRESS: - set_address(fusb300, ctrl); - break; - case USB_REQ_SET_CONFIGURATION: - fusb300_enable_bit(fusb300, FUSB300_OFFSET_DAR, - FUSB300_DAR_SETCONFG); - /* clear sequence number */ - for (i = 1; i <= FUSB300_MAX_NUM_EP; i++) - fusb300_clear_seqnum(fusb300, i); - fusb300->reenum = 1; - ret = 1; - break; - default: - ret = 1; - break; - } - } else - ret = 1; - - return ret; -} - -static void done(struct fusb300_ep *ep, struct fusb300_request *req, - int status) -{ - list_del_init(&req->queue); - - /* don't modify queue heads during completion callback */ - if (ep->fusb300->gadget.speed == USB_SPEED_UNKNOWN) - req->req.status = -ESHUTDOWN; - else - req->req.status = status; - - spin_unlock(&ep->fusb300->lock); - usb_gadget_giveback_request(&ep->ep, &req->req); - spin_lock(&ep->fusb300->lock); - - if (ep->epnum) { - disable_fifo_int(ep); - if (!list_empty(&ep->queue)) - enable_fifo_int(ep); - } else - fusb300_set_cxdone(ep->fusb300); -} - -static void fusb300_fill_idma_prdtbl(struct fusb300_ep *ep, dma_addr_t d, - u32 len) -{ - u32 value; - u32 reg; - - /* wait SW owner */ - do { - reg = ioread32(ep->fusb300->reg + - FUSB300_OFFSET_EPPRD_W0(ep->epnum)); - reg &= FUSB300_EPPRD0_H; - } while (reg); - - iowrite32(d, ep->fusb300->reg + FUSB300_OFFSET_EPPRD_W1(ep->epnum)); - - value = FUSB300_EPPRD0_BTC(len) | FUSB300_EPPRD0_H | - FUSB300_EPPRD0_F | FUSB300_EPPRD0_L | FUSB300_EPPRD0_I; - iowrite32(value, ep->fusb300->reg + FUSB300_OFFSET_EPPRD_W0(ep->epnum)); - - iowrite32(0x0, ep->fusb300->reg + FUSB300_OFFSET_EPPRD_W2(ep->epnum)); - - fusb300_enable_bit(ep->fusb300, FUSB300_OFFSET_EPPRDRDY, - FUSB300_EPPRDR_EP_PRD_RDY(ep->epnum)); -} - -static void fusb300_wait_idma_finished(struct fusb300_ep *ep) -{ - u32 reg; - - do { - reg = ioread32(ep->fusb300->reg + FUSB300_OFFSET_IGR1); - if ((reg & FUSB300_IGR1_VBUS_CHG_INT) || - (reg & FUSB300_IGR1_WARM_RST_INT) || - (reg & FUSB300_IGR1_HOT_RST_INT) || - (reg & FUSB300_IGR1_USBRST_INT) - ) - goto IDMA_RESET; - reg = ioread32(ep->fusb300->reg + FUSB300_OFFSET_IGR0); - reg &= FUSB300_IGR0_EPn_PRD_INT(ep->epnum); - } while (!reg); - - fusb300_clear_int(ep->fusb300, FUSB300_OFFSET_IGR0, - FUSB300_IGR0_EPn_PRD_INT(ep->epnum)); - return; - -IDMA_RESET: - reg = ioread32(ep->fusb300->reg + FUSB300_OFFSET_IGER0); - reg &= ~FUSB300_IGER0_EEPn_PRD_INT(ep->epnum); - iowrite32(reg, ep->fusb300->reg + FUSB300_OFFSET_IGER0); -} - -static void fusb300_set_idma(struct fusb300_ep *ep, - struct fusb300_request *req) -{ - int ret; - - ret = usb_gadget_map_request(&ep->fusb300->gadget, - &req->req, DMA_TO_DEVICE); - if (ret) - return; - - fusb300_enable_bit(ep->fusb300, FUSB300_OFFSET_IGER0, - FUSB300_IGER0_EEPn_PRD_INT(ep->epnum)); - - fusb300_fill_idma_prdtbl(ep, req->req.dma, req->req.length); - /* check idma is done */ - fusb300_wait_idma_finished(ep); - - usb_gadget_unmap_request(&ep->fusb300->gadget, - &req->req, DMA_TO_DEVICE); -} - -static void in_ep_fifo_handler(struct fusb300_ep *ep) -{ - struct fusb300_request *req = list_entry(ep->queue.next, - struct fusb300_request, queue); - - if (req->req.length) - fusb300_set_idma(ep, req); - done(ep, req, 0); -} - -static void out_ep_fifo_handler(struct fusb300_ep *ep) -{ - struct fusb300 *fusb300 = ep->fusb300; - struct fusb300_request *req = list_entry(ep->queue.next, - struct fusb300_request, queue); - u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPFFR(ep->epnum)); - u32 length = reg & FUSB300_FFR_BYCNT; - - fusb300_rdfifo(ep, req, length); - - /* finish out transfer */ - if ((req->req.length == req->req.actual) || (length < ep->ep.maxpacket)) - done(ep, req, 0); -} - -static void check_device_mode(struct fusb300 *fusb300) -{ - u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_GCR); - - switch (reg & FUSB300_GCR_DEVEN_MSK) { - case FUSB300_GCR_DEVEN_SS: - fusb300->gadget.speed = USB_SPEED_SUPER; - break; - case FUSB300_GCR_DEVEN_HS: - fusb300->gadget.speed = USB_SPEED_HIGH; - break; - case FUSB300_GCR_DEVEN_FS: - fusb300->gadget.speed = USB_SPEED_FULL; - break; - default: - fusb300->gadget.speed = USB_SPEED_UNKNOWN; - break; - } - printk(KERN_INFO "dev_mode = %d\n", (reg & FUSB300_GCR_DEVEN_MSK)); -} - - -static void fusb300_ep0out(struct fusb300 *fusb300) -{ - struct fusb300_ep *ep = fusb300->ep[0]; - u32 reg; - - if (!list_empty(&ep->queue)) { - struct fusb300_request *req; - - req = list_first_entry(&ep->queue, - struct fusb300_request, queue); - if (req->req.length) - fusb300_rdcxf(ep->fusb300, req->req.buf, - req->req.length); - done(ep, req, 0); - reg = ioread32(fusb300->reg + FUSB300_OFFSET_IGER1); - reg &= ~FUSB300_IGER1_CX_OUT_INT; - iowrite32(reg, fusb300->reg + FUSB300_OFFSET_IGER1); - } else - pr_err("%s : empty queue\n", __func__); -} - -static void fusb300_ep0in(struct fusb300 *fusb300) -{ - struct fusb300_request *req; - struct fusb300_ep *ep = fusb300->ep[0]; - - if ((!list_empty(&ep->queue)) && (fusb300->ep0_dir)) { - req = list_entry(ep->queue.next, - struct fusb300_request, queue); - if (req->req.length) - fusb300_wrcxf(ep, req); - if ((req->req.length - req->req.actual) < ep->ep.maxpacket) - done(ep, req, 0); - } else - fusb300_set_cxdone(fusb300); -} - -static void fusb300_grp2_handler(void) -{ -} - -static void fusb300_grp3_handler(void) -{ -} - -static void fusb300_grp4_handler(void) -{ -} - -static void fusb300_grp5_handler(void) -{ -} - -static irqreturn_t fusb300_irq(int irq, void *_fusb300) -{ - struct fusb300 *fusb300 = _fusb300; - u32 int_grp1 = ioread32(fusb300->reg + FUSB300_OFFSET_IGR1); - u32 int_grp1_en = ioread32(fusb300->reg + FUSB300_OFFSET_IGER1); - u32 int_grp0 = ioread32(fusb300->reg + FUSB300_OFFSET_IGR0); - u32 int_grp0_en = ioread32(fusb300->reg + FUSB300_OFFSET_IGER0); - struct usb_ctrlrequest ctrl; - u8 in; - u32 reg; - int i; - - spin_lock(&fusb300->lock); - - int_grp1 &= int_grp1_en; - int_grp0 &= int_grp0_en; - - if (int_grp1 & FUSB300_IGR1_WARM_RST_INT) { - fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, - FUSB300_IGR1_WARM_RST_INT); - printk(KERN_INFO"fusb300_warmreset\n"); - fusb300_reset(); - } - - if (int_grp1 & FUSB300_IGR1_HOT_RST_INT) { - fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, - FUSB300_IGR1_HOT_RST_INT); - printk(KERN_INFO"fusb300_hotreset\n"); - fusb300_reset(); - } - - if (int_grp1 & FUSB300_IGR1_USBRST_INT) { - fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, - FUSB300_IGR1_USBRST_INT); - fusb300_reset(); - } - /* COMABT_INT has a highest priority */ - - if (int_grp1 & FUSB300_IGR1_CX_COMABT_INT) { - fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, - FUSB300_IGR1_CX_COMABT_INT); - printk(KERN_INFO"fusb300_ep0abt\n"); - } - - if (int_grp1 & FUSB300_IGR1_VBUS_CHG_INT) { - fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, - FUSB300_IGR1_VBUS_CHG_INT); - printk(KERN_INFO"fusb300_vbus_change\n"); - } - - if (int_grp1 & FUSB300_IGR1_U3_EXIT_FAIL_INT) { - fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, - FUSB300_IGR1_U3_EXIT_FAIL_INT); - } - - if (int_grp1 & FUSB300_IGR1_U2_EXIT_FAIL_INT) { - fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, - FUSB300_IGR1_U2_EXIT_FAIL_INT); - } - - if (int_grp1 & FUSB300_IGR1_U1_EXIT_FAIL_INT) { - fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, - FUSB300_IGR1_U1_EXIT_FAIL_INT); - } - - if (int_grp1 & FUSB300_IGR1_U2_ENTRY_FAIL_INT) { - fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, - FUSB300_IGR1_U2_ENTRY_FAIL_INT); - } - - if (int_grp1 & FUSB300_IGR1_U1_ENTRY_FAIL_INT) { - fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, - FUSB300_IGR1_U1_ENTRY_FAIL_INT); - } - - if (int_grp1 & FUSB300_IGR1_U3_EXIT_INT) { - fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, - FUSB300_IGR1_U3_EXIT_INT); - printk(KERN_INFO "FUSB300_IGR1_U3_EXIT_INT\n"); - } - - if (int_grp1 & FUSB300_IGR1_U2_EXIT_INT) { - fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, - FUSB300_IGR1_U2_EXIT_INT); - printk(KERN_INFO "FUSB300_IGR1_U2_EXIT_INT\n"); - } - - if (int_grp1 & FUSB300_IGR1_U1_EXIT_INT) { - fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, - FUSB300_IGR1_U1_EXIT_INT); - printk(KERN_INFO "FUSB300_IGR1_U1_EXIT_INT\n"); - } - - if (int_grp1 & FUSB300_IGR1_U3_ENTRY_INT) { - fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, - FUSB300_IGR1_U3_ENTRY_INT); - printk(KERN_INFO "FUSB300_IGR1_U3_ENTRY_INT\n"); - fusb300_enable_bit(fusb300, FUSB300_OFFSET_SSCR1, - FUSB300_SSCR1_GO_U3_DONE); - } - - if (int_grp1 & FUSB300_IGR1_U2_ENTRY_INT) { - fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, - FUSB300_IGR1_U2_ENTRY_INT); - printk(KERN_INFO "FUSB300_IGR1_U2_ENTRY_INT\n"); - } - - if (int_grp1 & FUSB300_IGR1_U1_ENTRY_INT) { - fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, - FUSB300_IGR1_U1_ENTRY_INT); - printk(KERN_INFO "FUSB300_IGR1_U1_ENTRY_INT\n"); - } - - if (int_grp1 & FUSB300_IGR1_RESM_INT) { - fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, - FUSB300_IGR1_RESM_INT); - printk(KERN_INFO "fusb300_resume\n"); - } - - if (int_grp1 & FUSB300_IGR1_SUSP_INT) { - fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, - FUSB300_IGR1_SUSP_INT); - printk(KERN_INFO "fusb300_suspend\n"); - } - - if (int_grp1 & FUSB300_IGR1_HS_LPM_INT) { - fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, - FUSB300_IGR1_HS_LPM_INT); - printk(KERN_INFO "fusb300_HS_LPM_INT\n"); - } - - if (int_grp1 & FUSB300_IGR1_DEV_MODE_CHG_INT) { - fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, - FUSB300_IGR1_DEV_MODE_CHG_INT); - check_device_mode(fusb300); - } - - if (int_grp1 & FUSB300_IGR1_CX_COMFAIL_INT) { - fusb300_set_cxstall(fusb300); - printk(KERN_INFO "fusb300_ep0fail\n"); - } - - if (int_grp1 & FUSB300_IGR1_CX_SETUP_INT) { - printk(KERN_INFO "fusb300_ep0setup\n"); - if (setup_packet(fusb300, &ctrl)) { - spin_unlock(&fusb300->lock); - if (fusb300->driver->setup(&fusb300->gadget, &ctrl) < 0) - fusb300_set_cxstall(fusb300); - spin_lock(&fusb300->lock); - } - } - - if (int_grp1 & FUSB300_IGR1_CX_CMDEND_INT) - printk(KERN_INFO "fusb300_cmdend\n"); - - - if (int_grp1 & FUSB300_IGR1_CX_OUT_INT) { - printk(KERN_INFO "fusb300_cxout\n"); - fusb300_ep0out(fusb300); - } - - if (int_grp1 & FUSB300_IGR1_CX_IN_INT) { - printk(KERN_INFO "fusb300_cxin\n"); - fusb300_ep0in(fusb300); - } - - if (int_grp1 & FUSB300_IGR1_INTGRP5) - fusb300_grp5_handler(); - - if (int_grp1 & FUSB300_IGR1_INTGRP4) - fusb300_grp4_handler(); - - if (int_grp1 & FUSB300_IGR1_INTGRP3) - fusb300_grp3_handler(); - - if (int_grp1 & FUSB300_IGR1_INTGRP2) - fusb300_grp2_handler(); - - if (int_grp0) { - for (i = 1; i < FUSB300_MAX_NUM_EP; i++) { - if (int_grp0 & FUSB300_IGR0_EPn_FIFO_INT(i)) { - reg = ioread32(fusb300->reg + - FUSB300_OFFSET_EPSET1(i)); - in = (reg & FUSB300_EPSET1_DIRIN) ? 1 : 0; - if (in) - in_ep_fifo_handler(fusb300->ep[i]); - else - out_ep_fifo_handler(fusb300->ep[i]); - } - } - } - - spin_unlock(&fusb300->lock); - - return IRQ_HANDLED; -} - -static void fusb300_set_u2_timeout(struct fusb300 *fusb300, - u32 time) -{ - u32 reg; - - reg = ioread32(fusb300->reg + FUSB300_OFFSET_TT); - reg &= ~0xff; - reg |= FUSB300_SSCR2_U2TIMEOUT(time); - - iowrite32(reg, fusb300->reg + FUSB300_OFFSET_TT); -} - -static void fusb300_set_u1_timeout(struct fusb300 *fusb300, - u32 time) -{ - u32 reg; - - reg = ioread32(fusb300->reg + FUSB300_OFFSET_TT); - reg &= ~(0xff << 8); - reg |= FUSB300_SSCR2_U1TIMEOUT(time); - - iowrite32(reg, fusb300->reg + FUSB300_OFFSET_TT); -} - -static void init_controller(struct fusb300 *fusb300) -{ - u32 reg; - u32 mask = 0; - u32 val = 0; - - /* split on */ - mask = val = FUSB300_AHBBCR_S0_SPLIT_ON | FUSB300_AHBBCR_S1_SPLIT_ON; - reg = ioread32(fusb300->reg + FUSB300_OFFSET_AHBCR); - reg &= ~mask; - reg |= val; - iowrite32(reg, fusb300->reg + FUSB300_OFFSET_AHBCR); - - /* enable high-speed LPM */ - mask = val = FUSB300_HSCR_HS_LPM_PERMIT; - reg = ioread32(fusb300->reg + FUSB300_OFFSET_HSCR); - reg &= ~mask; - reg |= val; - iowrite32(reg, fusb300->reg + FUSB300_OFFSET_HSCR); - - /*set u1 u2 timer*/ - fusb300_set_u2_timeout(fusb300, 0xff); - fusb300_set_u1_timeout(fusb300, 0xff); - - /* enable all grp1 interrupt */ - iowrite32(0xcfffff9f, fusb300->reg + FUSB300_OFFSET_IGER1); -} -/*------------------------------------------------------------------------*/ -static int fusb300_udc_start(struct usb_gadget *g, - struct usb_gadget_driver *driver) -{ - struct fusb300 *fusb300 = to_fusb300(g); - - /* hook up the driver */ - fusb300->driver = driver; - - return 0; -} - -static int fusb300_udc_stop(struct usb_gadget *g) -{ - struct fusb300 *fusb300 = to_fusb300(g); - - init_controller(fusb300); - fusb300->driver = NULL; - - return 0; -} -/*--------------------------------------------------------------------------*/ - -static int fusb300_udc_pullup(struct usb_gadget *_gadget, int is_active) -{ - return 0; -} - -static const struct usb_gadget_ops fusb300_gadget_ops = { - .pullup = fusb300_udc_pullup, - .udc_start = fusb300_udc_start, - .udc_stop = fusb300_udc_stop, -}; - -static void fusb300_remove(struct platform_device *pdev) -{ - struct fusb300 *fusb300 = platform_get_drvdata(pdev); - int i; - - usb_del_gadget_udc(&fusb300->gadget); - iounmap(fusb300->reg); - free_irq(platform_get_irq(pdev, 0), fusb300); - free_irq(platform_get_irq(pdev, 1), fusb300); - - fusb300_free_request(&fusb300->ep[0]->ep, fusb300->ep0_req); - for (i = 0; i < FUSB300_MAX_NUM_EP; i++) - kfree(fusb300->ep[i]); - kfree(fusb300); -} - -static int fusb300_probe(struct platform_device *pdev) -{ - struct resource *res, *ires, *ires1; - void __iomem *reg = NULL; - struct fusb300 *fusb300 = NULL; - struct fusb300_ep *_ep[FUSB300_MAX_NUM_EP]; - int ret = 0; - int i; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - ret = -ENODEV; - pr_err("platform_get_resource error.\n"); - goto clean_up; - } - - ires = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!ires) { - ret = -ENODEV; - dev_err(&pdev->dev, - "platform_get_resource IORESOURCE_IRQ error.\n"); - goto clean_up; - } - - ires1 = platform_get_resource(pdev, IORESOURCE_IRQ, 1); - if (!ires1) { - ret = -ENODEV; - dev_err(&pdev->dev, - "platform_get_resource IORESOURCE_IRQ 1 error.\n"); - goto clean_up; - } - - reg = ioremap(res->start, resource_size(res)); - if (reg == NULL) { - ret = -ENOMEM; - pr_err("ioremap error.\n"); - goto clean_up; - } - - /* initialize udc */ - fusb300 = kzalloc(sizeof(struct fusb300), GFP_KERNEL); - if (fusb300 == NULL) { - ret = -ENOMEM; - goto clean_up; - } - - for (i = 0; i < FUSB300_MAX_NUM_EP; i++) { - _ep[i] = kzalloc(sizeof(struct fusb300_ep), GFP_KERNEL); - if (_ep[i] == NULL) { - ret = -ENOMEM; - goto clean_up; - } - fusb300->ep[i] = _ep[i]; - } - - spin_lock_init(&fusb300->lock); - - platform_set_drvdata(pdev, fusb300); - - fusb300->gadget.ops = &fusb300_gadget_ops; - - fusb300->gadget.max_speed = USB_SPEED_HIGH; - fusb300->gadget.name = udc_name; - fusb300->reg = reg; - - ret = request_irq(ires->start, fusb300_irq, IRQF_SHARED, - udc_name, fusb300); - if (ret < 0) { - pr_err("request_irq error (%d)\n", ret); - goto clean_up; - } - - ret = request_irq(ires1->start, fusb300_irq, - IRQF_SHARED, udc_name, fusb300); - if (ret < 0) { - pr_err("request_irq1 error (%d)\n", ret); - goto err_request_irq1; - } - - INIT_LIST_HEAD(&fusb300->gadget.ep_list); - - for (i = 0; i < FUSB300_MAX_NUM_EP ; i++) { - struct fusb300_ep *ep = fusb300->ep[i]; - - if (i != 0) { - INIT_LIST_HEAD(&fusb300->ep[i]->ep.ep_list); - list_add_tail(&fusb300->ep[i]->ep.ep_list, - &fusb300->gadget.ep_list); - } - ep->fusb300 = fusb300; - INIT_LIST_HEAD(&ep->queue); - ep->ep.name = fusb300_ep_name[i]; - ep->ep.ops = &fusb300_ep_ops; - usb_ep_set_maxpacket_limit(&ep->ep, HS_BULK_MAX_PACKET_SIZE); - - if (i == 0) { - ep->ep.caps.type_control = true; - } else { - ep->ep.caps.type_iso = true; - ep->ep.caps.type_bulk = true; - ep->ep.caps.type_int = true; - } - - ep->ep.caps.dir_in = true; - ep->ep.caps.dir_out = true; - } - usb_ep_set_maxpacket_limit(&fusb300->ep[0]->ep, HS_CTL_MAX_PACKET_SIZE); - fusb300->ep[0]->epnum = 0; - fusb300->gadget.ep0 = &fusb300->ep[0]->ep; - INIT_LIST_HEAD(&fusb300->gadget.ep0->ep_list); - - fusb300->ep0_req = fusb300_alloc_request(&fusb300->ep[0]->ep, - GFP_KERNEL); - if (fusb300->ep0_req == NULL) { - ret = -ENOMEM; - goto err_alloc_request; - } - - init_controller(fusb300); - ret = usb_add_gadget_udc(&pdev->dev, &fusb300->gadget); - if (ret) - goto err_add_udc; - - dev_info(&pdev->dev, "version %s\n", DRIVER_VERSION); - - return 0; - -err_add_udc: - fusb300_free_request(&fusb300->ep[0]->ep, fusb300->ep0_req); - -err_alloc_request: - free_irq(ires1->start, fusb300); - -err_request_irq1: - free_irq(ires->start, fusb300); - -clean_up: - if (fusb300) { - if (fusb300->ep0_req) - fusb300_free_request(&fusb300->ep[0]->ep, - fusb300->ep0_req); - for (i = 0; i < FUSB300_MAX_NUM_EP; i++) - kfree(fusb300->ep[i]); - kfree(fusb300); - } - if (reg) - iounmap(reg); - - return ret; -} - -static struct platform_driver fusb300_driver = { - .probe = fusb300_probe, - .remove = fusb300_remove, - .driver = { - .name = udc_name, - }, -}; - -module_platform_driver(fusb300_driver); diff --git a/drivers/usb/gadget/udc/fusb300_udc.h b/drivers/usb/gadget/udc/fusb300_udc.h deleted file mode 100644 index eb3d6d379ba7..000000000000 --- a/drivers/usb/gadget/udc/fusb300_udc.h +++ /dev/null @@ -1,675 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Fusb300 UDC (USB gadget) - * - * Copyright (C) 2010 Faraday Technology Corp. - * - * Author : Yuan-hsin Chen <yhchen@faraday-tech.com> - */ - - -#ifndef __FUSB300_UDC_H__ -#define __FUSB300_UDC_H__ - -#include <linux/kernel.h> - -#define FUSB300_OFFSET_GCR 0x00 -#define FUSB300_OFFSET_GTM 0x04 -#define FUSB300_OFFSET_DAR 0x08 -#define FUSB300_OFFSET_CSR 0x0C -#define FUSB300_OFFSET_CXPORT 0x10 -#define FUSB300_OFFSET_EPSET0(n) (0x20 + (n - 1) * 0x30) -#define FUSB300_OFFSET_EPSET1(n) (0x24 + (n - 1) * 0x30) -#define FUSB300_OFFSET_EPSET2(n) (0x28 + (n - 1) * 0x30) -#define FUSB300_OFFSET_EPFFR(n) (0x2c + (n - 1) * 0x30) -#define FUSB300_OFFSET_EPSTRID(n) (0x40 + (n - 1) * 0x30) -#define FUSB300_OFFSET_HSPTM 0x300 -#define FUSB300_OFFSET_HSCR 0x304 -#define FUSB300_OFFSET_SSCR0 0x308 -#define FUSB300_OFFSET_SSCR1 0x30C -#define FUSB300_OFFSET_TT 0x310 -#define FUSB300_OFFSET_DEVNOTF 0x314 -#define FUSB300_OFFSET_DNC1 0x318 -#define FUSB300_OFFSET_CS 0x31C -#define FUSB300_OFFSET_SOF 0x324 -#define FUSB300_OFFSET_EFCS 0x328 -#define FUSB300_OFFSET_IGR0 0x400 -#define FUSB300_OFFSET_IGR1 0x404 -#define FUSB300_OFFSET_IGR2 0x408 -#define FUSB300_OFFSET_IGR3 0x40C -#define FUSB300_OFFSET_IGR4 0x410 -#define FUSB300_OFFSET_IGR5 0x414 -#define FUSB300_OFFSET_IGER0 0x420 -#define FUSB300_OFFSET_IGER1 0x424 -#define FUSB300_OFFSET_IGER2 0x428 -#define FUSB300_OFFSET_IGER3 0x42C -#define FUSB300_OFFSET_IGER4 0x430 -#define FUSB300_OFFSET_IGER5 0x434 -#define FUSB300_OFFSET_DMAHMER 0x500 -#define FUSB300_OFFSET_EPPRDRDY 0x504 -#define FUSB300_OFFSET_DMAEPMR 0x508 -#define FUSB300_OFFSET_DMAENR 0x50C -#define FUSB300_OFFSET_DMAAPR 0x510 -#define FUSB300_OFFSET_AHBCR 0x514 -#define FUSB300_OFFSET_EPPRD_W0(n) (0x520 + (n - 1) * 0x10) -#define FUSB300_OFFSET_EPPRD_W1(n) (0x524 + (n - 1) * 0x10) -#define FUSB300_OFFSET_EPPRD_W2(n) (0x528 + (n - 1) * 0x10) -#define FUSB300_OFFSET_EPRD_PTR(n) (0x52C + (n - 1) * 0x10) -#define FUSB300_OFFSET_BUFDBG_START 0x800 -#define FUSB300_OFFSET_BUFDBG_END 0xBFC -#define FUSB300_OFFSET_EPPORT(n) (0x1010 + (n - 1) * 0x10) - -/* - * * Global Control Register (offset = 000H) - * */ -#define FUSB300_GCR_SF_RST (1 << 8) -#define FUSB300_GCR_VBUS_STATUS (1 << 7) -#define FUSB300_GCR_FORCE_HS_SUSP (1 << 6) -#define FUSB300_GCR_SYNC_FIFO1_CLR (1 << 5) -#define FUSB300_GCR_SYNC_FIFO0_CLR (1 << 4) -#define FUSB300_GCR_FIFOCLR (1 << 3) -#define FUSB300_GCR_GLINTEN (1 << 2) -#define FUSB300_GCR_DEVEN_FS 0x3 -#define FUSB300_GCR_DEVEN_HS 0x2 -#define FUSB300_GCR_DEVEN_SS 0x1 -#define FUSB300_GCR_DEVDIS 0x0 -#define FUSB300_GCR_DEVEN_MSK 0x3 - - -/* - * *Global Test Mode (offset = 004H) - * */ -#define FUSB300_GTM_TST_DIS_SOFGEN (1 << 16) -#define FUSB300_GTM_TST_CUR_EP_ENTRY(n) ((n & 0xF) << 12) -#define FUSB300_GTM_TST_EP_ENTRY(n) ((n & 0xF) << 8) -#define FUSB300_GTM_TST_EP_NUM(n) ((n & 0xF) << 4) -#define FUSB300_GTM_TST_FIFO_DEG (1 << 1) -#define FUSB300_GTM_TSTMODE (1 << 0) - -/* - * * Device Address Register (offset = 008H) - * */ -#define FUSB300_DAR_SETCONFG (1 << 7) -#define FUSB300_DAR_DRVADDR(x) (x & 0x7F) -#define FUSB300_DAR_DRVADDR_MSK 0x7F - -/* - * *Control Transfer Configuration and Status Register - * (CX_Config_Status, offset = 00CH) - * */ -#define FUSB300_CSR_LEN(x) ((x & 0xFFFF) << 8) -#define FUSB300_CSR_LEN_MSK (0xFFFF << 8) -#define FUSB300_CSR_EMP (1 << 4) -#define FUSB300_CSR_FUL (1 << 3) -#define FUSB300_CSR_CLR (1 << 2) -#define FUSB300_CSR_STL (1 << 1) -#define FUSB300_CSR_DONE (1 << 0) - -/* - * * EPn Setting 0 (EPn_SET0, offset = 020H+(n-1)*30H, n=1~15 ) - * */ -#define FUSB300_EPSET0_STL_CLR (1 << 3) -#define FUSB300_EPSET0_CLRSEQNUM (1 << 2) -#define FUSB300_EPSET0_STL (1 << 0) - -/* - * * EPn Setting 1 (EPn_SET1, offset = 024H+(n-1)*30H, n=1~15) - * */ -#define FUSB300_EPSET1_START_ENTRY(x) ((x & 0xFF) << 24) -#define FUSB300_EPSET1_START_ENTRY_MSK (0xFF << 24) -#define FUSB300_EPSET1_FIFOENTRY(x) ((x & 0x1F) << 12) -#define FUSB300_EPSET1_FIFOENTRY_MSK (0x1f << 12) -#define FUSB300_EPSET1_INTERVAL(x) ((x & 0x7) << 6) -#define FUSB300_EPSET1_BWNUM(x) ((x & 0x3) << 4) -#define FUSB300_EPSET1_TYPEISO (1 << 2) -#define FUSB300_EPSET1_TYPEBLK (2 << 2) -#define FUSB300_EPSET1_TYPEINT (3 << 2) -#define FUSB300_EPSET1_TYPE(x) ((x & 0x3) << 2) -#define FUSB300_EPSET1_TYPE_MSK (0x3 << 2) -#define FUSB300_EPSET1_DIROUT (0 << 1) -#define FUSB300_EPSET1_DIRIN (1 << 1) -#define FUSB300_EPSET1_DIR(x) ((x & 0x1) << 1) -#define FUSB300_EPSET1_DIRIN (1 << 1) -#define FUSB300_EPSET1_DIR_MSK ((0x1) << 1) -#define FUSB300_EPSET1_ACTDIS 0 -#define FUSB300_EPSET1_ACTEN 1 - -/* - * *EPn Setting 2 (EPn_SET2, offset = 028H+(n-1)*30H, n=1~15) - * */ -#define FUSB300_EPSET2_ADDROFS(x) ((x & 0x7FFF) << 16) -#define FUSB300_EPSET2_ADDROFS_MSK (0x7fff << 16) -#define FUSB300_EPSET2_MPS(x) (x & 0x7FF) -#define FUSB300_EPSET2_MPS_MSK 0x7FF - -/* - * * EPn FIFO Register (offset = 2cH+(n-1)*30H) - * */ -#define FUSB300_FFR_RST (1 << 31) -#define FUSB300_FF_FUL (1 << 30) -#define FUSB300_FF_EMPTY (1 << 29) -#define FUSB300_FFR_BYCNT 0x1FFFF - -/* - * *EPn Stream ID (EPn_STR_ID, offset = 040H+(n-1)*30H, n=1~15) - * */ -#define FUSB300_STRID_STREN (1 << 16) -#define FUSB300_STRID_STRID(x) (x & 0xFFFF) - -/* - * *HS PHY Test Mode (offset = 300H) - * */ -#define FUSB300_HSPTM_TSTPKDONE (1 << 4) -#define FUSB300_HSPTM_TSTPKT (1 << 3) -#define FUSB300_HSPTM_TSTSET0NAK (1 << 2) -#define FUSB300_HSPTM_TSTKSTA (1 << 1) -#define FUSB300_HSPTM_TSTJSTA (1 << 0) - -/* - * *HS Control Register (offset = 304H) - * */ -#define FUSB300_HSCR_HS_LPM_PERMIT (1 << 8) -#define FUSB300_HSCR_HS_LPM_RMWKUP (1 << 7) -#define FUSB300_HSCR_CAP_LPM_RMWKUP (1 << 6) -#define FUSB300_HSCR_HS_GOSUSP (1 << 5) -#define FUSB300_HSCR_HS_GORMWKU (1 << 4) -#define FUSB300_HSCR_CAP_RMWKUP (1 << 3) -#define FUSB300_HSCR_IDLECNT_0MS 0 -#define FUSB300_HSCR_IDLECNT_1MS 1 -#define FUSB300_HSCR_IDLECNT_2MS 2 -#define FUSB300_HSCR_IDLECNT_3MS 3 -#define FUSB300_HSCR_IDLECNT_4MS 4 -#define FUSB300_HSCR_IDLECNT_5MS 5 -#define FUSB300_HSCR_IDLECNT_6MS 6 -#define FUSB300_HSCR_IDLECNT_7MS 7 - -/* - * * SS Controller Register 0 (offset = 308H) - * */ -#define FUSB300_SSCR0_MAX_INTERVAL(x) ((x & 0x7) << 4) -#define FUSB300_SSCR0_U2_FUN_EN (1 << 1) -#define FUSB300_SSCR0_U1_FUN_EN (1 << 0) - -/* - * * SS Controller Register 1 (offset = 30CH) - * */ -#define FUSB300_SSCR1_GO_U3_DONE (1 << 8) -#define FUSB300_SSCR1_TXDEEMPH_LEVEL (1 << 7) -#define FUSB300_SSCR1_DIS_SCRMB (1 << 6) -#define FUSB300_SSCR1_FORCE_RECOVERY (1 << 5) -#define FUSB300_SSCR1_U3_WAKEUP_EN (1 << 4) -#define FUSB300_SSCR1_U2_EXIT_EN (1 << 3) -#define FUSB300_SSCR1_U1_EXIT_EN (1 << 2) -#define FUSB300_SSCR1_U2_ENTRY_EN (1 << 1) -#define FUSB300_SSCR1_U1_ENTRY_EN (1 << 0) - -/* - * *SS Controller Register 2 (offset = 310H) - * */ -#define FUSB300_SSCR2_SS_TX_SWING (1 << 25) -#define FUSB300_SSCR2_FORCE_LINKPM_ACCEPT (1 << 24) -#define FUSB300_SSCR2_U2_INACT_TIMEOUT(x) ((x & 0xFF) << 16) -#define FUSB300_SSCR2_U1TIMEOUT(x) ((x & 0xFF) << 8) -#define FUSB300_SSCR2_U2TIMEOUT(x) (x & 0xFF) - -/* - * *SS Device Notification Control (DEV_NOTF, offset = 314H) - * */ -#define FUSB300_DEVNOTF_CONTEXT0(x) ((x & 0xFFFFFF) << 8) -#define FUSB300_DEVNOTF_TYPE_DIS 0 -#define FUSB300_DEVNOTF_TYPE_FUNCWAKE 1 -#define FUSB300_DEVNOTF_TYPE_LTM 2 -#define FUSB300_DEVNOTF_TYPE_BUSINT_ADJMSG 3 - -/* - * *BFM Arbiter Priority Register (BFM_ARB offset = 31CH) - * */ -#define FUSB300_BFMARB_ARB_M1 (1 << 3) -#define FUSB300_BFMARB_ARB_M0 (1 << 2) -#define FUSB300_BFMARB_ARB_S1 (1 << 1) -#define FUSB300_BFMARB_ARB_S0 1 - -/* - * *Vendor Specific IO Control Register (offset = 320H) - * */ -#define FUSB300_VSIC_VCTLOAD_N (1 << 8) -#define FUSB300_VSIC_VCTL(x) (x & 0x3F) - -/* - * *SOF Mask Timer (offset = 324H) - * */ -#define FUSB300_SOF_MASK_TIMER_HS 0x044c -#define FUSB300_SOF_MASK_TIMER_FS 0x2710 - -/* - * *Error Flag and Control Status (offset = 328H) - * */ -#define FUSB300_EFCS_PM_STATE_U3 3 -#define FUSB300_EFCS_PM_STATE_U2 2 -#define FUSB300_EFCS_PM_STATE_U1 1 -#define FUSB300_EFCS_PM_STATE_U0 0 - -/* - * *Interrupt Group 0 Register (offset = 400H) - * */ -#define FUSB300_IGR0_EP15_PRD_INT (1 << 31) -#define FUSB300_IGR0_EP14_PRD_INT (1 << 30) -#define FUSB300_IGR0_EP13_PRD_INT (1 << 29) -#define FUSB300_IGR0_EP12_PRD_INT (1 << 28) -#define FUSB300_IGR0_EP11_PRD_INT (1 << 27) -#define FUSB300_IGR0_EP10_PRD_INT (1 << 26) -#define FUSB300_IGR0_EP9_PRD_INT (1 << 25) -#define FUSB300_IGR0_EP8_PRD_INT (1 << 24) -#define FUSB300_IGR0_EP7_PRD_INT (1 << 23) -#define FUSB300_IGR0_EP6_PRD_INT (1 << 22) -#define FUSB300_IGR0_EP5_PRD_INT (1 << 21) -#define FUSB300_IGR0_EP4_PRD_INT (1 << 20) -#define FUSB300_IGR0_EP3_PRD_INT (1 << 19) -#define FUSB300_IGR0_EP2_PRD_INT (1 << 18) -#define FUSB300_IGR0_EP1_PRD_INT (1 << 17) -#define FUSB300_IGR0_EPn_PRD_INT(n) (1 << (n + 16)) - -#define FUSB300_IGR0_EP15_FIFO_INT (1 << 15) -#define FUSB300_IGR0_EP14_FIFO_INT (1 << 14) -#define FUSB300_IGR0_EP13_FIFO_INT (1 << 13) -#define FUSB300_IGR0_EP12_FIFO_INT (1 << 12) -#define FUSB300_IGR0_EP11_FIFO_INT (1 << 11) -#define FUSB300_IGR0_EP10_FIFO_INT (1 << 10) -#define FUSB300_IGR0_EP9_FIFO_INT (1 << 9) -#define FUSB300_IGR0_EP8_FIFO_INT (1 << 8) -#define FUSB300_IGR0_EP7_FIFO_INT (1 << 7) -#define FUSB300_IGR0_EP6_FIFO_INT (1 << 6) -#define FUSB300_IGR0_EP5_FIFO_INT (1 << 5) -#define FUSB300_IGR0_EP4_FIFO_INT (1 << 4) -#define FUSB300_IGR0_EP3_FIFO_INT (1 << 3) -#define FUSB300_IGR0_EP2_FIFO_INT (1 << 2) -#define FUSB300_IGR0_EP1_FIFO_INT (1 << 1) -#define FUSB300_IGR0_EPn_FIFO_INT(n) (1 << n) - -/* - * *Interrupt Group 1 Register (offset = 404H) - * */ -#define FUSB300_IGR1_INTGRP5 (1 << 31) -#define FUSB300_IGR1_VBUS_CHG_INT (1 << 30) -#define FUSB300_IGR1_SYNF1_EMPTY_INT (1 << 29) -#define FUSB300_IGR1_SYNF0_EMPTY_INT (1 << 28) -#define FUSB300_IGR1_U3_EXIT_FAIL_INT (1 << 27) -#define FUSB300_IGR1_U2_EXIT_FAIL_INT (1 << 26) -#define FUSB300_IGR1_U1_EXIT_FAIL_INT (1 << 25) -#define FUSB300_IGR1_U2_ENTRY_FAIL_INT (1 << 24) -#define FUSB300_IGR1_U1_ENTRY_FAIL_INT (1 << 23) -#define FUSB300_IGR1_U3_EXIT_INT (1 << 22) -#define FUSB300_IGR1_U2_EXIT_INT (1 << 21) -#define FUSB300_IGR1_U1_EXIT_INT (1 << 20) -#define FUSB300_IGR1_U3_ENTRY_INT (1 << 19) -#define FUSB300_IGR1_U2_ENTRY_INT (1 << 18) -#define FUSB300_IGR1_U1_ENTRY_INT (1 << 17) -#define FUSB300_IGR1_HOT_RST_INT (1 << 16) -#define FUSB300_IGR1_WARM_RST_INT (1 << 15) -#define FUSB300_IGR1_RESM_INT (1 << 14) -#define FUSB300_IGR1_SUSP_INT (1 << 13) -#define FUSB300_IGR1_HS_LPM_INT (1 << 12) -#define FUSB300_IGR1_USBRST_INT (1 << 11) -#define FUSB300_IGR1_DEV_MODE_CHG_INT (1 << 9) -#define FUSB300_IGR1_CX_COMABT_INT (1 << 8) -#define FUSB300_IGR1_CX_COMFAIL_INT (1 << 7) -#define FUSB300_IGR1_CX_CMDEND_INT (1 << 6) -#define FUSB300_IGR1_CX_OUT_INT (1 << 5) -#define FUSB300_IGR1_CX_IN_INT (1 << 4) -#define FUSB300_IGR1_CX_SETUP_INT (1 << 3) -#define FUSB300_IGR1_INTGRP4 (1 << 2) -#define FUSB300_IGR1_INTGRP3 (1 << 1) -#define FUSB300_IGR1_INTGRP2 (1 << 0) - -/* - * *Interrupt Group 2 Register (offset = 408H) - * */ -#define FUSB300_IGR2_EP6_STR_ACCEPT_INT (1 << 29) -#define FUSB300_IGR2_EP6_STR_RESUME_INT (1 << 28) -#define FUSB300_IGR2_EP6_STR_REQ_INT (1 << 27) -#define FUSB300_IGR2_EP6_STR_NOTRDY_INT (1 << 26) -#define FUSB300_IGR2_EP6_STR_PRIME_INT (1 << 25) -#define FUSB300_IGR2_EP5_STR_ACCEPT_INT (1 << 24) -#define FUSB300_IGR2_EP5_STR_RESUME_INT (1 << 23) -#define FUSB300_IGR2_EP5_STR_REQ_INT (1 << 22) -#define FUSB300_IGR2_EP5_STR_NOTRDY_INT (1 << 21) -#define FUSB300_IGR2_EP5_STR_PRIME_INT (1 << 20) -#define FUSB300_IGR2_EP4_STR_ACCEPT_INT (1 << 19) -#define FUSB300_IGR2_EP4_STR_RESUME_INT (1 << 18) -#define FUSB300_IGR2_EP4_STR_REQ_INT (1 << 17) -#define FUSB300_IGR2_EP4_STR_NOTRDY_INT (1 << 16) -#define FUSB300_IGR2_EP4_STR_PRIME_INT (1 << 15) -#define FUSB300_IGR2_EP3_STR_ACCEPT_INT (1 << 14) -#define FUSB300_IGR2_EP3_STR_RESUME_INT (1 << 13) -#define FUSB300_IGR2_EP3_STR_REQ_INT (1 << 12) -#define FUSB300_IGR2_EP3_STR_NOTRDY_INT (1 << 11) -#define FUSB300_IGR2_EP3_STR_PRIME_INT (1 << 10) -#define FUSB300_IGR2_EP2_STR_ACCEPT_INT (1 << 9) -#define FUSB300_IGR2_EP2_STR_RESUME_INT (1 << 8) -#define FUSB300_IGR2_EP2_STR_REQ_INT (1 << 7) -#define FUSB300_IGR2_EP2_STR_NOTRDY_INT (1 << 6) -#define FUSB300_IGR2_EP2_STR_PRIME_INT (1 << 5) -#define FUSB300_IGR2_EP1_STR_ACCEPT_INT (1 << 4) -#define FUSB300_IGR2_EP1_STR_RESUME_INT (1 << 3) -#define FUSB300_IGR2_EP1_STR_REQ_INT (1 << 2) -#define FUSB300_IGR2_EP1_STR_NOTRDY_INT (1 << 1) -#define FUSB300_IGR2_EP1_STR_PRIME_INT (1 << 0) - -#define FUSB300_IGR2_EP_STR_ACCEPT_INT(n) (1 << (5 * n - 1)) -#define FUSB300_IGR2_EP_STR_RESUME_INT(n) (1 << (5 * n - 2)) -#define FUSB300_IGR2_EP_STR_REQ_INT(n) (1 << (5 * n - 3)) -#define FUSB300_IGR2_EP_STR_NOTRDY_INT(n) (1 << (5 * n - 4)) -#define FUSB300_IGR2_EP_STR_PRIME_INT(n) (1 << (5 * n - 5)) - -/* - * *Interrupt Group 3 Register (offset = 40CH) - * */ -#define FUSB300_IGR3_EP12_STR_ACCEPT_INT (1 << 29) -#define FUSB300_IGR3_EP12_STR_RESUME_INT (1 << 28) -#define FUSB300_IGR3_EP12_STR_REQ_INT (1 << 27) -#define FUSB300_IGR3_EP12_STR_NOTRDY_INT (1 << 26) -#define FUSB300_IGR3_EP12_STR_PRIME_INT (1 << 25) -#define FUSB300_IGR3_EP11_STR_ACCEPT_INT (1 << 24) -#define FUSB300_IGR3_EP11_STR_RESUME_INT (1 << 23) -#define FUSB300_IGR3_EP11_STR_REQ_INT (1 << 22) -#define FUSB300_IGR3_EP11_STR_NOTRDY_INT (1 << 21) -#define FUSB300_IGR3_EP11_STR_PRIME_INT (1 << 20) -#define FUSB300_IGR3_EP10_STR_ACCEPT_INT (1 << 19) -#define FUSB300_IGR3_EP10_STR_RESUME_INT (1 << 18) -#define FUSB300_IGR3_EP10_STR_REQ_INT (1 << 17) -#define FUSB300_IGR3_EP10_STR_NOTRDY_INT (1 << 16) -#define FUSB300_IGR3_EP10_STR_PRIME_INT (1 << 15) -#define FUSB300_IGR3_EP9_STR_ACCEPT_INT (1 << 14) -#define FUSB300_IGR3_EP9_STR_RESUME_INT (1 << 13) -#define FUSB300_IGR3_EP9_STR_REQ_INT (1 << 12) -#define FUSB300_IGR3_EP9_STR_NOTRDY_INT (1 << 11) -#define FUSB300_IGR3_EP9_STR_PRIME_INT (1 << 10) -#define FUSB300_IGR3_EP8_STR_ACCEPT_INT (1 << 9) -#define FUSB300_IGR3_EP8_STR_RESUME_INT (1 << 8) -#define FUSB300_IGR3_EP8_STR_REQ_INT (1 << 7) -#define FUSB300_IGR3_EP8_STR_NOTRDY_INT (1 << 6) -#define FUSB300_IGR3_EP8_STR_PRIME_INT (1 << 5) -#define FUSB300_IGR3_EP7_STR_ACCEPT_INT (1 << 4) -#define FUSB300_IGR3_EP7_STR_RESUME_INT (1 << 3) -#define FUSB300_IGR3_EP7_STR_REQ_INT (1 << 2) -#define FUSB300_IGR3_EP7_STR_NOTRDY_INT (1 << 1) -#define FUSB300_IGR3_EP7_STR_PRIME_INT (1 << 0) - -#define FUSB300_IGR3_EP_STR_ACCEPT_INT(n) (1 << (5 * (n - 6) - 1)) -#define FUSB300_IGR3_EP_STR_RESUME_INT(n) (1 << (5 * (n - 6) - 2)) -#define FUSB300_IGR3_EP_STR_REQ_INT(n) (1 << (5 * (n - 6) - 3)) -#define FUSB300_IGR3_EP_STR_NOTRDY_INT(n) (1 << (5 * (n - 6) - 4)) -#define FUSB300_IGR3_EP_STR_PRIME_INT(n) (1 << (5 * (n - 6) - 5)) - -/* - * *Interrupt Group 4 Register (offset = 410H) - * */ -#define FUSB300_IGR4_EP15_RX0_INT (1 << 31) -#define FUSB300_IGR4_EP14_RX0_INT (1 << 30) -#define FUSB300_IGR4_EP13_RX0_INT (1 << 29) -#define FUSB300_IGR4_EP12_RX0_INT (1 << 28) -#define FUSB300_IGR4_EP11_RX0_INT (1 << 27) -#define FUSB300_IGR4_EP10_RX0_INT (1 << 26) -#define FUSB300_IGR4_EP9_RX0_INT (1 << 25) -#define FUSB300_IGR4_EP8_RX0_INT (1 << 24) -#define FUSB300_IGR4_EP7_RX0_INT (1 << 23) -#define FUSB300_IGR4_EP6_RX0_INT (1 << 22) -#define FUSB300_IGR4_EP5_RX0_INT (1 << 21) -#define FUSB300_IGR4_EP4_RX0_INT (1 << 20) -#define FUSB300_IGR4_EP3_RX0_INT (1 << 19) -#define FUSB300_IGR4_EP2_RX0_INT (1 << 18) -#define FUSB300_IGR4_EP1_RX0_INT (1 << 17) -#define FUSB300_IGR4_EP_RX0_INT(x) (1 << (x + 16)) -#define FUSB300_IGR4_EP15_STR_ACCEPT_INT (1 << 14) -#define FUSB300_IGR4_EP15_STR_RESUME_INT (1 << 13) -#define FUSB300_IGR4_EP15_STR_REQ_INT (1 << 12) -#define FUSB300_IGR4_EP15_STR_NOTRDY_INT (1 << 11) -#define FUSB300_IGR4_EP15_STR_PRIME_INT (1 << 10) -#define FUSB300_IGR4_EP14_STR_ACCEPT_INT (1 << 9) -#define FUSB300_IGR4_EP14_STR_RESUME_INT (1 << 8) -#define FUSB300_IGR4_EP14_STR_REQ_INT (1 << 7) -#define FUSB300_IGR4_EP14_STR_NOTRDY_INT (1 << 6) -#define FUSB300_IGR4_EP14_STR_PRIME_INT (1 << 5) -#define FUSB300_IGR4_EP13_STR_ACCEPT_INT (1 << 4) -#define FUSB300_IGR4_EP13_STR_RESUME_INT (1 << 3) -#define FUSB300_IGR4_EP13_STR_REQ_INT (1 << 2) -#define FUSB300_IGR4_EP13_STR_NOTRDY_INT (1 << 1) -#define FUSB300_IGR4_EP13_STR_PRIME_INT (1 << 0) - -#define FUSB300_IGR4_EP_STR_ACCEPT_INT(n) (1 << (5 * (n - 12) - 1)) -#define FUSB300_IGR4_EP_STR_RESUME_INT(n) (1 << (5 * (n - 12) - 2)) -#define FUSB300_IGR4_EP_STR_REQ_INT(n) (1 << (5 * (n - 12) - 3)) -#define FUSB300_IGR4_EP_STR_NOTRDY_INT(n) (1 << (5 * (n - 12) - 4)) -#define FUSB300_IGR4_EP_STR_PRIME_INT(n) (1 << (5 * (n - 12) - 5)) - -/* - * *Interrupt Group 5 Register (offset = 414H) - * */ -#define FUSB300_IGR5_EP_STL_INT(n) (1 << n) - -/* - * *Interrupt Enable Group 0 Register (offset = 420H) - * */ -#define FUSB300_IGER0_EEP15_PRD_INT (1 << 31) -#define FUSB300_IGER0_EEP14_PRD_INT (1 << 30) -#define FUSB300_IGER0_EEP13_PRD_INT (1 << 29) -#define FUSB300_IGER0_EEP12_PRD_INT (1 << 28) -#define FUSB300_IGER0_EEP11_PRD_INT (1 << 27) -#define FUSB300_IGER0_EEP10_PRD_INT (1 << 26) -#define FUSB300_IGER0_EEP9_PRD_INT (1 << 25) -#define FUSB300_IGER0_EP8_PRD_INT (1 << 24) -#define FUSB300_IGER0_EEP7_PRD_INT (1 << 23) -#define FUSB300_IGER0_EEP6_PRD_INT (1 << 22) -#define FUSB300_IGER0_EEP5_PRD_INT (1 << 21) -#define FUSB300_IGER0_EEP4_PRD_INT (1 << 20) -#define FUSB300_IGER0_EEP3_PRD_INT (1 << 19) -#define FUSB300_IGER0_EEP2_PRD_INT (1 << 18) -#define FUSB300_IGER0_EEP1_PRD_INT (1 << 17) -#define FUSB300_IGER0_EEPn_PRD_INT(n) (1 << (n + 16)) - -#define FUSB300_IGER0_EEP15_FIFO_INT (1 << 15) -#define FUSB300_IGER0_EEP14_FIFO_INT (1 << 14) -#define FUSB300_IGER0_EEP13_FIFO_INT (1 << 13) -#define FUSB300_IGER0_EEP12_FIFO_INT (1 << 12) -#define FUSB300_IGER0_EEP11_FIFO_INT (1 << 11) -#define FUSB300_IGER0_EEP10_FIFO_INT (1 << 10) -#define FUSB300_IGER0_EEP9_FIFO_INT (1 << 9) -#define FUSB300_IGER0_EEP8_FIFO_INT (1 << 8) -#define FUSB300_IGER0_EEP7_FIFO_INT (1 << 7) -#define FUSB300_IGER0_EEP6_FIFO_INT (1 << 6) -#define FUSB300_IGER0_EEP5_FIFO_INT (1 << 5) -#define FUSB300_IGER0_EEP4_FIFO_INT (1 << 4) -#define FUSB300_IGER0_EEP3_FIFO_INT (1 << 3) -#define FUSB300_IGER0_EEP2_FIFO_INT (1 << 2) -#define FUSB300_IGER0_EEP1_FIFO_INT (1 << 1) -#define FUSB300_IGER0_EEPn_FIFO_INT(n) (1 << n) - -/* - * *Interrupt Enable Group 1 Register (offset = 424H) - * */ -#define FUSB300_IGER1_EINT_GRP5 (1 << 31) -#define FUSB300_IGER1_VBUS_CHG_INT (1 << 30) -#define FUSB300_IGER1_SYNF1_EMPTY_INT (1 << 29) -#define FUSB300_IGER1_SYNF0_EMPTY_INT (1 << 28) -#define FUSB300_IGER1_U3_EXIT_FAIL_INT (1 << 27) -#define FUSB300_IGER1_U2_EXIT_FAIL_INT (1 << 26) -#define FUSB300_IGER1_U1_EXIT_FAIL_INT (1 << 25) -#define FUSB300_IGER1_U2_ENTRY_FAIL_INT (1 << 24) -#define FUSB300_IGER1_U1_ENTRY_FAIL_INT (1 << 23) -#define FUSB300_IGER1_U3_EXIT_INT (1 << 22) -#define FUSB300_IGER1_U2_EXIT_INT (1 << 21) -#define FUSB300_IGER1_U1_EXIT_INT (1 << 20) -#define FUSB300_IGER1_U3_ENTRY_INT (1 << 19) -#define FUSB300_IGER1_U2_ENTRY_INT (1 << 18) -#define FUSB300_IGER1_U1_ENTRY_INT (1 << 17) -#define FUSB300_IGER1_HOT_RST_INT (1 << 16) -#define FUSB300_IGER1_WARM_RST_INT (1 << 15) -#define FUSB300_IGER1_RESM_INT (1 << 14) -#define FUSB300_IGER1_SUSP_INT (1 << 13) -#define FUSB300_IGER1_LPM_INT (1 << 12) -#define FUSB300_IGER1_HS_RST_INT (1 << 11) -#define FUSB300_IGER1_EDEV_MODE_CHG_INT (1 << 9) -#define FUSB300_IGER1_CX_COMABT_INT (1 << 8) -#define FUSB300_IGER1_CX_COMFAIL_INT (1 << 7) -#define FUSB300_IGER1_CX_CMDEND_INT (1 << 6) -#define FUSB300_IGER1_CX_OUT_INT (1 << 5) -#define FUSB300_IGER1_CX_IN_INT (1 << 4) -#define FUSB300_IGER1_CX_SETUP_INT (1 << 3) -#define FUSB300_IGER1_INTGRP4 (1 << 2) -#define FUSB300_IGER1_INTGRP3 (1 << 1) -#define FUSB300_IGER1_INTGRP2 (1 << 0) - -/* - * *Interrupt Enable Group 2 Register (offset = 428H) - * */ -#define FUSB300_IGER2_EEP_STR_ACCEPT_INT(n) (1 << (5 * n - 1)) -#define FUSB300_IGER2_EEP_STR_RESUME_INT(n) (1 << (5 * n - 2)) -#define FUSB300_IGER2_EEP_STR_REQ_INT(n) (1 << (5 * n - 3)) -#define FUSB300_IGER2_EEP_STR_NOTRDY_INT(n) (1 << (5 * n - 4)) -#define FUSB300_IGER2_EEP_STR_PRIME_INT(n) (1 << (5 * n - 5)) - -/* - * *Interrupt Enable Group 3 Register (offset = 42CH) - * */ - -#define FUSB300_IGER3_EEP_STR_ACCEPT_INT(n) (1 << (5 * (n - 6) - 1)) -#define FUSB300_IGER3_EEP_STR_RESUME_INT(n) (1 << (5 * (n - 6) - 2)) -#define FUSB300_IGER3_EEP_STR_REQ_INT(n) (1 << (5 * (n - 6) - 3)) -#define FUSB300_IGER3_EEP_STR_NOTRDY_INT(n) (1 << (5 * (n - 6) - 4)) -#define FUSB300_IGER3_EEP_STR_PRIME_INT(n) (1 << (5 * (n - 6) - 5)) - -/* - * *Interrupt Enable Group 4 Register (offset = 430H) - * */ - -#define FUSB300_IGER4_EEP_RX0_INT(n) (1 << (n + 16)) -#define FUSB300_IGER4_EEP_STR_ACCEPT_INT(n) (1 << (5 * (n - 6) - 1)) -#define FUSB300_IGER4_EEP_STR_RESUME_INT(n) (1 << (5 * (n - 6) - 2)) -#define FUSB300_IGER4_EEP_STR_REQ_INT(n) (1 << (5 * (n - 6) - 3)) -#define FUSB300_IGER4_EEP_STR_NOTRDY_INT(n) (1 << (5 * (n - 6) - 4)) -#define FUSB300_IGER4_EEP_STR_PRIME_INT(n) (1 << (5 * (n - 6) - 5)) - -/* EP PRD Ready (EP_PRD_RDY, offset = 504H) */ - -#define FUSB300_EPPRDR_EP15_PRD_RDY (1 << 15) -#define FUSB300_EPPRDR_EP14_PRD_RDY (1 << 14) -#define FUSB300_EPPRDR_EP13_PRD_RDY (1 << 13) -#define FUSB300_EPPRDR_EP12_PRD_RDY (1 << 12) -#define FUSB300_EPPRDR_EP11_PRD_RDY (1 << 11) -#define FUSB300_EPPRDR_EP10_PRD_RDY (1 << 10) -#define FUSB300_EPPRDR_EP9_PRD_RDY (1 << 9) -#define FUSB300_EPPRDR_EP8_PRD_RDY (1 << 8) -#define FUSB300_EPPRDR_EP7_PRD_RDY (1 << 7) -#define FUSB300_EPPRDR_EP6_PRD_RDY (1 << 6) -#define FUSB300_EPPRDR_EP5_PRD_RDY (1 << 5) -#define FUSB300_EPPRDR_EP4_PRD_RDY (1 << 4) -#define FUSB300_EPPRDR_EP3_PRD_RDY (1 << 3) -#define FUSB300_EPPRDR_EP2_PRD_RDY (1 << 2) -#define FUSB300_EPPRDR_EP1_PRD_RDY (1 << 1) -#define FUSB300_EPPRDR_EP_PRD_RDY(n) (1 << n) - -/* AHB Bus Control Register (offset = 514H) */ -#define FUSB300_AHBBCR_S1_SPLIT_ON (1 << 17) -#define FUSB300_AHBBCR_S0_SPLIT_ON (1 << 16) -#define FUSB300_AHBBCR_S1_1entry (0 << 12) -#define FUSB300_AHBBCR_S1_4entry (3 << 12) -#define FUSB300_AHBBCR_S1_8entry (5 << 12) -#define FUSB300_AHBBCR_S1_16entry (7 << 12) -#define FUSB300_AHBBCR_S0_1entry (0 << 8) -#define FUSB300_AHBBCR_S0_4entry (3 << 8) -#define FUSB300_AHBBCR_S0_8entry (5 << 8) -#define FUSB300_AHBBCR_S0_16entry (7 << 8) -#define FUSB300_AHBBCR_M1_BURST_SINGLE (0 << 4) -#define FUSB300_AHBBCR_M1_BURST_INCR (1 << 4) -#define FUSB300_AHBBCR_M1_BURST_INCR4 (3 << 4) -#define FUSB300_AHBBCR_M1_BURST_INCR8 (5 << 4) -#define FUSB300_AHBBCR_M1_BURST_INCR16 (7 << 4) -#define FUSB300_AHBBCR_M0_BURST_SINGLE 0 -#define FUSB300_AHBBCR_M0_BURST_INCR 1 -#define FUSB300_AHBBCR_M0_BURST_INCR4 3 -#define FUSB300_AHBBCR_M0_BURST_INCR8 5 -#define FUSB300_AHBBCR_M0_BURST_INCR16 7 -#define FUSB300_IGER5_EEP_STL_INT(n) (1 << n) - -/* WORD 0 Data Structure of PRD Table */ -#define FUSB300_EPPRD0_M (1 << 30) -#define FUSB300_EPPRD0_O (1 << 29) -/* The finished prd */ -#define FUSB300_EPPRD0_F (1 << 28) -#define FUSB300_EPPRD0_I (1 << 27) -#define FUSB300_EPPRD0_A (1 << 26) -/* To decide HW point to first prd at next time */ -#define FUSB300_EPPRD0_L (1 << 25) -#define FUSB300_EPPRD0_H (1 << 24) -#define FUSB300_EPPRD0_BTC(n) (n & 0xFFFFFF) - -/*----------------------------------------------------------------------*/ -#define FUSB300_MAX_NUM_EP 16 - -#define FUSB300_FIFO_ENTRY_NUM 8 -#define FUSB300_MAX_FIFO_ENTRY 8 - -#define SS_CTL_MAX_PACKET_SIZE 0x200 -#define SS_BULK_MAX_PACKET_SIZE 0x400 -#define SS_INT_MAX_PACKET_SIZE 0x400 -#define SS_ISO_MAX_PACKET_SIZE 0x400 - -#define HS_BULK_MAX_PACKET_SIZE 0x200 -#define HS_CTL_MAX_PACKET_SIZE 0x40 -#define HS_INT_MAX_PACKET_SIZE 0x400 -#define HS_ISO_MAX_PACKET_SIZE 0x400 - -struct fusb300_ep_info { - u8 epnum; - u8 type; - u8 interval; - u8 dir_in; - u16 maxpacket; - u16 addrofs; - u16 bw_num; -}; - -struct fusb300_request { - - struct usb_request req; - struct list_head queue; -}; - - -struct fusb300_ep { - struct usb_ep ep; - struct fusb300 *fusb300; - - struct list_head queue; - unsigned stall:1; - unsigned wedged:1; - unsigned use_dma:1; - - unsigned char epnum; - unsigned char type; -}; - -struct fusb300 { - spinlock_t lock; - void __iomem *reg; - - unsigned long irq_trigger; - - struct usb_gadget gadget; - struct usb_gadget_driver *driver; - - struct fusb300_ep *ep[FUSB300_MAX_NUM_EP]; - - struct usb_request *ep0_req; /* for internal request */ - __le16 ep0_data; - u32 ep0_length; /* for internal request */ - u8 ep0_dir; /* 0/0x80 out/in */ - - u8 fifo_entry_num; /* next start fifo entry */ - u32 addrofs; /* next fifo address offset */ - u8 reenum; /* if re-enumeration */ -}; - -#define to_fusb300(g) (container_of((g), struct fusb300, gadget)) - -#endif diff --git a/drivers/usb/gadget/udc/lpc32xx_udc.c b/drivers/usb/gadget/udc/lpc32xx_udc.c index 89d6daf2bda7..1a7d3c4f652f 100644 --- a/drivers/usb/gadget/udc/lpc32xx_udc.c +++ b/drivers/usb/gadget/udc/lpc32xx_udc.c @@ -1629,7 +1629,7 @@ static int lpc32xx_ep_enable(struct usb_ep *_ep, return -ESHUTDOWN; } - tmp = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; + tmp = usb_endpoint_type(desc); switch (tmp) { case USB_ENDPOINT_XFER_CONTROL: return -EINVAL; diff --git a/drivers/usb/gadget/udc/m66592-udc.c b/drivers/usb/gadget/udc/m66592-udc.c index a938b2af0944..715791737499 100644 --- a/drivers/usb/gadget/udc/m66592-udc.c +++ b/drivers/usb/gadget/udc/m66592-udc.c @@ -1261,7 +1261,7 @@ static irqreturn_t m66592_irq(int irq, void *_m66592) static void m66592_timer(struct timer_list *t) { - struct m66592 *m66592 = from_timer(m66592, t, timer); + struct m66592 *m66592 = timer_container_of(m66592, t, timer); unsigned long flags; u16 tmp; diff --git a/drivers/usb/gadget/udc/mv_u3d.h b/drivers/usb/gadget/udc/mv_u3d.h deleted file mode 100644 index 66b84f792f64..000000000000 --- a/drivers/usb/gadget/udc/mv_u3d.h +++ /dev/null @@ -1,317 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (C) 2011 Marvell International Ltd. All rights reserved. - */ - -#ifndef __MV_U3D_H -#define __MV_U3D_H - -#define MV_U3D_EP_CONTEXT_ALIGNMENT 32 -#define MV_U3D_TRB_ALIGNMENT 16 -#define MV_U3D_DMA_BOUNDARY 4096 -#define MV_U3D_EP0_MAX_PKT_SIZE 512 - -/* ep0 transfer state */ -#define MV_U3D_WAIT_FOR_SETUP 0 -#define MV_U3D_DATA_STATE_XMIT 1 -#define MV_U3D_DATA_STATE_NEED_ZLP 2 -#define MV_U3D_WAIT_FOR_OUT_STATUS 3 -#define MV_U3D_DATA_STATE_RECV 4 -#define MV_U3D_STATUS_STAGE 5 - -#define MV_U3D_EP_MAX_LENGTH_TRANSFER 0x10000 - -/* USB3 Interrupt Status */ -#define MV_U3D_USBINT_SETUP 0x00000001 -#define MV_U3D_USBINT_RX_COMPLETE 0x00000002 -#define MV_U3D_USBINT_TX_COMPLETE 0x00000004 -#define MV_U3D_USBINT_UNDER_RUN 0x00000008 -#define MV_U3D_USBINT_RXDESC_ERR 0x00000010 -#define MV_U3D_USBINT_TXDESC_ERR 0x00000020 -#define MV_U3D_USBINT_RX_TRB_COMPLETE 0x00000040 -#define MV_U3D_USBINT_TX_TRB_COMPLETE 0x00000080 -#define MV_U3D_USBINT_VBUS_VALID 0x00010000 -#define MV_U3D_USBINT_STORAGE_CMD_FULL 0x00020000 -#define MV_U3D_USBINT_LINK_CHG 0x01000000 - -/* USB3 Interrupt Enable */ -#define MV_U3D_INTR_ENABLE_SETUP 0x00000001 -#define MV_U3D_INTR_ENABLE_RX_COMPLETE 0x00000002 -#define MV_U3D_INTR_ENABLE_TX_COMPLETE 0x00000004 -#define MV_U3D_INTR_ENABLE_UNDER_RUN 0x00000008 -#define MV_U3D_INTR_ENABLE_RXDESC_ERR 0x00000010 -#define MV_U3D_INTR_ENABLE_TXDESC_ERR 0x00000020 -#define MV_U3D_INTR_ENABLE_RX_TRB_COMPLETE 0x00000040 -#define MV_U3D_INTR_ENABLE_TX_TRB_COMPLETE 0x00000080 -#define MV_U3D_INTR_ENABLE_RX_BUFFER_ERR 0x00000100 -#define MV_U3D_INTR_ENABLE_VBUS_VALID 0x00010000 -#define MV_U3D_INTR_ENABLE_STORAGE_CMD_FULL 0x00020000 -#define MV_U3D_INTR_ENABLE_LINK_CHG 0x01000000 -#define MV_U3D_INTR_ENABLE_PRIME_STATUS 0x02000000 - -/* USB3 Link Change */ -#define MV_U3D_LINK_CHANGE_LINK_UP 0x00000001 -#define MV_U3D_LINK_CHANGE_SUSPEND 0x00000002 -#define MV_U3D_LINK_CHANGE_RESUME 0x00000004 -#define MV_U3D_LINK_CHANGE_WRESET 0x00000008 -#define MV_U3D_LINK_CHANGE_HRESET 0x00000010 -#define MV_U3D_LINK_CHANGE_VBUS_INVALID 0x00000020 -#define MV_U3D_LINK_CHANGE_INACT 0x00000040 -#define MV_U3D_LINK_CHANGE_DISABLE_AFTER_U0 0x00000080 -#define MV_U3D_LINK_CHANGE_U1 0x00000100 -#define MV_U3D_LINK_CHANGE_U2 0x00000200 -#define MV_U3D_LINK_CHANGE_U3 0x00000400 - -/* bridge setting */ -#define MV_U3D_BRIDGE_SETTING_VBUS_VALID (1 << 16) - -/* Command Register Bit Masks */ -#define MV_U3D_CMD_RUN_STOP 0x00000001 -#define MV_U3D_CMD_CTRL_RESET 0x00000002 - -/* ep control register */ -#define MV_U3D_EPXCR_EP_TYPE_CONTROL 0 -#define MV_U3D_EPXCR_EP_TYPE_ISOC 1 -#define MV_U3D_EPXCR_EP_TYPE_BULK 2 -#define MV_U3D_EPXCR_EP_TYPE_INT 3 -#define MV_U3D_EPXCR_EP_ENABLE_SHIFT 4 -#define MV_U3D_EPXCR_MAX_BURST_SIZE_SHIFT 12 -#define MV_U3D_EPXCR_MAX_PACKET_SIZE_SHIFT 16 -#define MV_U3D_USB_BULK_BURST_OUT 6 -#define MV_U3D_USB_BULK_BURST_IN 14 - -#define MV_U3D_EPXCR_EP_FLUSH (1 << 7) -#define MV_U3D_EPXCR_EP_HALT (1 << 1) -#define MV_U3D_EPXCR_EP_INIT (1) - -/* TX/RX Status Register */ -#define MV_U3D_XFERSTATUS_COMPLETE_SHIFT 24 -#define MV_U3D_COMPLETE_INVALID 0 -#define MV_U3D_COMPLETE_SUCCESS 1 -#define MV_U3D_COMPLETE_BUFF_ERR 2 -#define MV_U3D_COMPLETE_SHORT_PACKET 3 -#define MV_U3D_COMPLETE_TRB_ERR 5 -#define MV_U3D_XFERSTATUS_TRB_LENGTH_MASK (0xFFFFFF) - -#define MV_U3D_USB_LINK_BYPASS_VBUS 0x8 - -#define MV_U3D_LTSSM_PHY_INIT_DONE 0x80000000 -#define MV_U3D_LTSSM_NEVER_GO_COMPLIANCE 0x40000000 - -#define MV_U3D_USB3_OP_REGS_OFFSET 0x100 -#define MV_U3D_USB3_PHY_OFFSET 0xB800 - -#define DCS_ENABLE 0x1 - -/* timeout */ -#define MV_U3D_RESET_TIMEOUT 10000 -#define MV_U3D_FLUSH_TIMEOUT 100000 -#define MV_U3D_OWN_TIMEOUT 10000 -#define LOOPS_USEC_SHIFT 4 -#define LOOPS_USEC (1 << LOOPS_USEC_SHIFT) -#define LOOPS(timeout) ((timeout) >> LOOPS_USEC_SHIFT) - -/* ep direction */ -#define MV_U3D_EP_DIR_IN 1 -#define MV_U3D_EP_DIR_OUT 0 -#define mv_u3d_ep_dir(ep) (((ep)->ep_num == 0) ? \ - ((ep)->u3d->ep0_dir) : ((ep)->direction)) - -/* usb capability registers */ -struct mv_u3d_cap_regs { - u32 rsvd[5]; - u32 dboff; /* doorbell register offset */ - u32 rtsoff; /* runtime register offset */ - u32 vuoff; /* vendor unique register offset */ -}; - -/* operation registers */ -struct mv_u3d_op_regs { - u32 usbcmd; /* Command register */ - u32 rsvd1[11]; - u32 dcbaapl; /* Device Context Base Address low register */ - u32 dcbaaph; /* Device Context Base Address high register */ - u32 rsvd2[243]; - u32 portsc; /* port status and control register*/ - u32 portlinkinfo; /* port link info register*/ - u32 rsvd3[9917]; - u32 doorbell; /* doorbell register */ -}; - -/* control endpoint enable registers */ -struct epxcr { - u32 epxoutcr0; /* ep out control 0 register */ - u32 epxoutcr1; /* ep out control 1 register */ - u32 epxincr0; /* ep in control 0 register */ - u32 epxincr1; /* ep in control 1 register */ -}; - -/* transfer status registers */ -struct xferstatus { - u32 curdeqlo; /* current TRB pointer low */ - u32 curdeqhi; /* current TRB pointer high */ - u32 statuslo; /* transfer status low */ - u32 statushi; /* transfer status high */ -}; - -/* vendor unique control registers */ -struct mv_u3d_vuc_regs { - u32 ctrlepenable; /* control endpoint enable register */ - u32 setuplock; /* setup lock register */ - u32 endcomplete; /* endpoint transfer complete register */ - u32 intrcause; /* interrupt cause register */ - u32 intrenable; /* interrupt enable register */ - u32 trbcomplete; /* TRB complete register */ - u32 linkchange; /* link change register */ - u32 rsvd1[5]; - u32 trbunderrun; /* TRB underrun register */ - u32 rsvd2[43]; - u32 bridgesetting; /* bridge setting register */ - u32 rsvd3[7]; - struct xferstatus txst[16]; /* TX status register */ - struct xferstatus rxst[16]; /* RX status register */ - u32 ltssm; /* LTSSM control register */ - u32 pipe; /* PIPE control register */ - u32 linkcr0; /* link control 0 register */ - u32 linkcr1; /* link control 1 register */ - u32 rsvd6[60]; - u32 mib0; /* MIB0 counter register */ - u32 usblink; /* usb link control register */ - u32 ltssmstate; /* LTSSM state register */ - u32 linkerrorcause; /* link error cause register */ - u32 rsvd7[60]; - u32 devaddrtiebrkr; /* device address and tie breaker */ - u32 itpinfo0; /* ITP info 0 register */ - u32 itpinfo1; /* ITP info 1 register */ - u32 rsvd8[61]; - struct epxcr epcr[16]; /* ep control register */ - u32 rsvd9[64]; - u32 phyaddr; /* PHY address register */ - u32 phydata; /* PHY data register */ -}; - -/* Endpoint context structure */ -struct mv_u3d_ep_context { - u32 rsvd0; - u32 rsvd1; - u32 trb_addr_lo; /* TRB address low 32 bit */ - u32 trb_addr_hi; /* TRB address high 32 bit */ - u32 rsvd2; - u32 rsvd3; - struct usb_ctrlrequest setup_buffer; /* setup data buffer */ -}; - -/* TRB control data structure */ -struct mv_u3d_trb_ctrl { - u32 own:1; /* owner of TRB */ - u32 rsvd1:3; - u32 chain:1; /* associate this TRB with the - next TRB on the Ring */ - u32 ioc:1; /* interrupt on complete */ - u32 rsvd2:4; - u32 type:6; /* TRB type */ -#define TYPE_NORMAL 1 -#define TYPE_DATA 3 -#define TYPE_LINK 6 - u32 dir:1; /* Working at data stage of control endpoint - operation. 0 is OUT and 1 is IN. */ - u32 rsvd3:15; -}; - -/* TRB data structure - * For multiple TRB, all the TRBs' physical address should be continuous. - */ -struct mv_u3d_trb_hw { - u32 buf_addr_lo; /* data buffer address low 32 bit */ - u32 buf_addr_hi; /* data buffer address high 32 bit */ - u32 trb_len; /* transfer length */ - struct mv_u3d_trb_ctrl ctrl; /* TRB control data */ -}; - -/* TRB structure */ -struct mv_u3d_trb { - struct mv_u3d_trb_hw *trb_hw; /* point to the trb_hw structure */ - dma_addr_t trb_dma; /* dma address for this trb_hw */ - struct list_head trb_list; /* trb list */ -}; - -/* device data structure */ -struct mv_u3d { - struct usb_gadget gadget; - struct usb_gadget_driver *driver; - spinlock_t lock; /* device lock */ - struct completion *done; - struct device *dev; - int irq; - - /* usb controller registers */ - struct mv_u3d_cap_regs __iomem *cap_regs; - struct mv_u3d_op_regs __iomem *op_regs; - struct mv_u3d_vuc_regs __iomem *vuc_regs; - void __iomem *phy_regs; - - unsigned int max_eps; - struct mv_u3d_ep_context *ep_context; - size_t ep_context_size; - dma_addr_t ep_context_dma; - - struct dma_pool *trb_pool; /* for TRB data structure */ - struct mv_u3d_ep *eps; - - struct mv_u3d_req *status_req; /* ep0 status request */ - struct usb_ctrlrequest local_setup_buff; /* store setup data*/ - - unsigned int resume_state; /* USB state to resume */ - unsigned int usb_state; /* USB current state */ - unsigned int ep0_state; /* Endpoint zero state */ - unsigned int ep0_dir; - - unsigned int dev_addr; /* device address */ - - unsigned int errors; - - unsigned softconnect:1; - unsigned vbus_active:1; /* vbus is active or not */ - unsigned remote_wakeup:1; /* support remote wakeup */ - unsigned clock_gating:1; /* clock gating or not */ - unsigned active:1; /* udc is active or not */ - unsigned vbus_valid_detect:1; /* udc vbus detection */ - - struct mv_usb_addon_irq *vbus; - unsigned int power; - - struct clk *clk; -}; - -/* endpoint data structure */ -struct mv_u3d_ep { - struct usb_ep ep; - struct mv_u3d *u3d; - struct list_head queue; /* ep request queued hardware */ - struct list_head req_list; /* list of ep request */ - struct mv_u3d_ep_context *ep_context; /* ep context */ - u32 direction; - char name[14]; - u32 processing; /* there is ep request - queued on haredware */ - spinlock_t req_lock; /* ep lock */ - unsigned wedge:1; - unsigned enabled:1; - unsigned ep_type:2; - unsigned ep_num:8; -}; - -/* request data structure */ -struct mv_u3d_req { - struct usb_request req; - struct mv_u3d_ep *ep; - struct list_head queue; /* ep requst queued on hardware */ - struct list_head list; /* ep request list */ - struct list_head trb_list; /* trb list of a request */ - - struct mv_u3d_trb *trb_head; /* point to first trb of a request */ - unsigned trb_count; /* TRB number in the chain */ - unsigned chain; /* TRB chain or not */ -}; - -#endif diff --git a/drivers/usb/gadget/udc/mv_u3d_core.c b/drivers/usb/gadget/udc/mv_u3d_core.c deleted file mode 100644 index 062f43e146aa..000000000000 --- a/drivers/usb/gadget/udc/mv_u3d_core.c +++ /dev/null @@ -1,2062 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (C) 2011 Marvell International Ltd. All rights reserved. - */ - -#include <linux/module.h> -#include <linux/dma-mapping.h> -#include <linux/dmapool.h> -#include <linux/kernel.h> -#include <linux/delay.h> -#include <linux/ioport.h> -#include <linux/sched.h> -#include <linux/slab.h> -#include <linux/errno.h> -#include <linux/timer.h> -#include <linux/list.h> -#include <linux/notifier.h> -#include <linux/interrupt.h> -#include <linux/moduleparam.h> -#include <linux/device.h> -#include <linux/usb/ch9.h> -#include <linux/usb/gadget.h> -#include <linux/pm.h> -#include <linux/io.h> -#include <linux/irq.h> -#include <linux/platform_device.h> -#include <linux/platform_data/mv_usb.h> -#include <linux/clk.h> - -#include "mv_u3d.h" - -#define DRIVER_DESC "Marvell PXA USB3.0 Device Controller driver" - -static const char driver_name[] = "mv_u3d"; - -static void mv_u3d_nuke(struct mv_u3d_ep *ep, int status); -static void mv_u3d_stop_activity(struct mv_u3d *u3d, - struct usb_gadget_driver *driver); - -/* for endpoint 0 operations */ -static const struct usb_endpoint_descriptor mv_u3d_ep0_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = 0, - .bmAttributes = USB_ENDPOINT_XFER_CONTROL, - .wMaxPacketSize = MV_U3D_EP0_MAX_PKT_SIZE, -}; - -static void mv_u3d_ep0_reset(struct mv_u3d *u3d) -{ - struct mv_u3d_ep *ep; - u32 epxcr; - int i; - - for (i = 0; i < 2; i++) { - ep = &u3d->eps[i]; - ep->u3d = u3d; - - /* ep0 ep context, ep0 in and out share the same ep context */ - ep->ep_context = &u3d->ep_context[1]; - } - - /* reset ep state machine */ - /* reset ep0 out */ - epxcr = ioread32(&u3d->vuc_regs->epcr[0].epxoutcr0); - epxcr |= MV_U3D_EPXCR_EP_INIT; - iowrite32(epxcr, &u3d->vuc_regs->epcr[0].epxoutcr0); - udelay(5); - epxcr &= ~MV_U3D_EPXCR_EP_INIT; - iowrite32(epxcr, &u3d->vuc_regs->epcr[0].epxoutcr0); - - epxcr = ((MV_U3D_EP0_MAX_PKT_SIZE - << MV_U3D_EPXCR_MAX_PACKET_SIZE_SHIFT) - | (1 << MV_U3D_EPXCR_MAX_BURST_SIZE_SHIFT) - | (1 << MV_U3D_EPXCR_EP_ENABLE_SHIFT) - | MV_U3D_EPXCR_EP_TYPE_CONTROL); - iowrite32(epxcr, &u3d->vuc_regs->epcr[0].epxoutcr1); - - /* reset ep0 in */ - epxcr = ioread32(&u3d->vuc_regs->epcr[0].epxincr0); - epxcr |= MV_U3D_EPXCR_EP_INIT; - iowrite32(epxcr, &u3d->vuc_regs->epcr[0].epxincr0); - udelay(5); - epxcr &= ~MV_U3D_EPXCR_EP_INIT; - iowrite32(epxcr, &u3d->vuc_regs->epcr[0].epxincr0); - - epxcr = ((MV_U3D_EP0_MAX_PKT_SIZE - << MV_U3D_EPXCR_MAX_PACKET_SIZE_SHIFT) - | (1 << MV_U3D_EPXCR_MAX_BURST_SIZE_SHIFT) - | (1 << MV_U3D_EPXCR_EP_ENABLE_SHIFT) - | MV_U3D_EPXCR_EP_TYPE_CONTROL); - iowrite32(epxcr, &u3d->vuc_regs->epcr[0].epxincr1); -} - -static void mv_u3d_ep0_stall(struct mv_u3d *u3d) -{ - u32 tmp; - dev_dbg(u3d->dev, "%s\n", __func__); - - /* set TX and RX to stall */ - tmp = ioread32(&u3d->vuc_regs->epcr[0].epxoutcr0); - tmp |= MV_U3D_EPXCR_EP_HALT; - iowrite32(tmp, &u3d->vuc_regs->epcr[0].epxoutcr0); - - tmp = ioread32(&u3d->vuc_regs->epcr[0].epxincr0); - tmp |= MV_U3D_EPXCR_EP_HALT; - iowrite32(tmp, &u3d->vuc_regs->epcr[0].epxincr0); - - /* update ep0 state */ - u3d->ep0_state = MV_U3D_WAIT_FOR_SETUP; - u3d->ep0_dir = MV_U3D_EP_DIR_OUT; -} - -static int mv_u3d_process_ep_req(struct mv_u3d *u3d, int index, - struct mv_u3d_req *curr_req) -{ - struct mv_u3d_trb *curr_trb; - int actual, remaining_length = 0; - int direction, ep_num; - int retval = 0; - u32 tmp, status, length; - - direction = index % 2; - ep_num = index / 2; - - actual = curr_req->req.length; - - while (!list_empty(&curr_req->trb_list)) { - curr_trb = list_entry(curr_req->trb_list.next, - struct mv_u3d_trb, trb_list); - if (!curr_trb->trb_hw->ctrl.own) { - dev_err(u3d->dev, "%s, TRB own error!\n", - u3d->eps[index].name); - return 1; - } - - curr_trb->trb_hw->ctrl.own = 0; - if (direction == MV_U3D_EP_DIR_OUT) - tmp = ioread32(&u3d->vuc_regs->rxst[ep_num].statuslo); - else - tmp = ioread32(&u3d->vuc_regs->txst[ep_num].statuslo); - - status = tmp >> MV_U3D_XFERSTATUS_COMPLETE_SHIFT; - length = tmp & MV_U3D_XFERSTATUS_TRB_LENGTH_MASK; - - if (status == MV_U3D_COMPLETE_SUCCESS || - (status == MV_U3D_COMPLETE_SHORT_PACKET && - direction == MV_U3D_EP_DIR_OUT)) { - remaining_length += length; - actual -= remaining_length; - } else { - dev_err(u3d->dev, - "complete_tr error: ep=%d %s: error = 0x%x\n", - index >> 1, direction ? "SEND" : "RECV", - status); - retval = -EPROTO; - } - - list_del_init(&curr_trb->trb_list); - } - if (retval) - return retval; - - curr_req->req.actual = actual; - return 0; -} - -/* - * mv_u3d_done() - retire a request; caller blocked irqs - * @status : request status to be set, only works when - * request is still in progress. - */ -static -void mv_u3d_done(struct mv_u3d_ep *ep, struct mv_u3d_req *req, int status) - __releases(&ep->udc->lock) - __acquires(&ep->udc->lock) -{ - struct mv_u3d *u3d = (struct mv_u3d *)ep->u3d; - - dev_dbg(u3d->dev, "mv_u3d_done: remove req->queue\n"); - /* Removed the req from ep queue */ - list_del_init(&req->queue); - - /* req.status should be set as -EINPROGRESS in ep_queue() */ - if (req->req.status == -EINPROGRESS) - req->req.status = status; - else - status = req->req.status; - - /* Free trb for the request */ - if (!req->chain) - dma_pool_free(u3d->trb_pool, - req->trb_head->trb_hw, req->trb_head->trb_dma); - else { - dma_unmap_single(ep->u3d->gadget.dev.parent, - (dma_addr_t)req->trb_head->trb_dma, - req->trb_count * sizeof(struct mv_u3d_trb_hw), - DMA_BIDIRECTIONAL); - kfree(req->trb_head->trb_hw); - } - kfree(req->trb_head); - - usb_gadget_unmap_request(&u3d->gadget, &req->req, mv_u3d_ep_dir(ep)); - - if (status && (status != -ESHUTDOWN)) { - dev_dbg(u3d->dev, "complete %s req %p stat %d len %u/%u", - ep->ep.name, &req->req, status, - req->req.actual, req->req.length); - } - - spin_unlock(&ep->u3d->lock); - - usb_gadget_giveback_request(&ep->ep, &req->req); - - spin_lock(&ep->u3d->lock); -} - -static int mv_u3d_queue_trb(struct mv_u3d_ep *ep, struct mv_u3d_req *req) -{ - u32 tmp, direction; - struct mv_u3d *u3d; - struct mv_u3d_ep_context *ep_context; - int retval = 0; - - u3d = ep->u3d; - direction = mv_u3d_ep_dir(ep); - - /* ep0 in and out share the same ep context slot 1*/ - if (ep->ep_num == 0) - ep_context = &(u3d->ep_context[1]); - else - ep_context = &(u3d->ep_context[ep->ep_num * 2 + direction]); - - /* check if the pipe is empty or not */ - if (!list_empty(&ep->queue)) { - dev_err(u3d->dev, "add trb to non-empty queue!\n"); - retval = -ENOMEM; - WARN_ON(1); - } else { - ep_context->rsvd0 = cpu_to_le32(1); - ep_context->rsvd1 = 0; - - /* Configure the trb address and set the DCS bit. - * Both DCS bit and own bit in trb should be set. - */ - ep_context->trb_addr_lo = - cpu_to_le32(req->trb_head->trb_dma | DCS_ENABLE); - ep_context->trb_addr_hi = 0; - - /* Ensure that updates to the EP Context will - * occure before Ring Bell. - */ - wmb(); - - /* ring bell the ep */ - if (ep->ep_num == 0) - tmp = 0x1; - else - tmp = ep->ep_num * 2 - + ((direction == MV_U3D_EP_DIR_OUT) ? 0 : 1); - - iowrite32(tmp, &u3d->op_regs->doorbell); - } - return retval; -} - -static struct mv_u3d_trb *mv_u3d_build_trb_one(struct mv_u3d_req *req, - unsigned *length, dma_addr_t *dma) -{ - u32 temp; - unsigned int direction; - struct mv_u3d_trb *trb; - struct mv_u3d_trb_hw *trb_hw; - struct mv_u3d *u3d; - - /* how big will this transfer be? */ - *length = req->req.length - req->req.actual; - BUG_ON(*length > (unsigned)MV_U3D_EP_MAX_LENGTH_TRANSFER); - - u3d = req->ep->u3d; - - trb = kzalloc(sizeof(*trb), GFP_ATOMIC); - if (!trb) - return NULL; - - /* - * Be careful that no _GFP_HIGHMEM is set, - * or we can not use dma_to_virt - * cannot use GFP_KERNEL in spin lock - */ - trb_hw = dma_pool_alloc(u3d->trb_pool, GFP_ATOMIC, dma); - if (!trb_hw) { - kfree(trb); - dev_err(u3d->dev, - "%s, dma_pool_alloc fail\n", __func__); - return NULL; - } - trb->trb_dma = *dma; - trb->trb_hw = trb_hw; - - /* initialize buffer page pointers */ - temp = (u32)(req->req.dma + req->req.actual); - - trb_hw->buf_addr_lo = cpu_to_le32(temp); - trb_hw->buf_addr_hi = 0; - trb_hw->trb_len = cpu_to_le32(*length); - trb_hw->ctrl.own = 1; - - if (req->ep->ep_num == 0) - trb_hw->ctrl.type = TYPE_DATA; - else - trb_hw->ctrl.type = TYPE_NORMAL; - - req->req.actual += *length; - - direction = mv_u3d_ep_dir(req->ep); - if (direction == MV_U3D_EP_DIR_IN) - trb_hw->ctrl.dir = 1; - else - trb_hw->ctrl.dir = 0; - - /* Enable interrupt for the last trb of a request */ - if (!req->req.no_interrupt) - trb_hw->ctrl.ioc = 1; - - trb_hw->ctrl.chain = 0; - - wmb(); - return trb; -} - -static int mv_u3d_build_trb_chain(struct mv_u3d_req *req, unsigned *length, - struct mv_u3d_trb *trb, int *is_last) -{ - u32 temp; - unsigned int direction; - struct mv_u3d *u3d; - - /* how big will this transfer be? */ - *length = min(req->req.length - req->req.actual, - (unsigned)MV_U3D_EP_MAX_LENGTH_TRANSFER); - - u3d = req->ep->u3d; - - trb->trb_dma = 0; - - /* initialize buffer page pointers */ - temp = (u32)(req->req.dma + req->req.actual); - - trb->trb_hw->buf_addr_lo = cpu_to_le32(temp); - trb->trb_hw->buf_addr_hi = 0; - trb->trb_hw->trb_len = cpu_to_le32(*length); - trb->trb_hw->ctrl.own = 1; - - if (req->ep->ep_num == 0) - trb->trb_hw->ctrl.type = TYPE_DATA; - else - trb->trb_hw->ctrl.type = TYPE_NORMAL; - - req->req.actual += *length; - - direction = mv_u3d_ep_dir(req->ep); - if (direction == MV_U3D_EP_DIR_IN) - trb->trb_hw->ctrl.dir = 1; - else - trb->trb_hw->ctrl.dir = 0; - - /* zlp is needed if req->req.zero is set */ - if (req->req.zero) { - if (*length == 0 || (*length % req->ep->ep.maxpacket) != 0) - *is_last = 1; - else - *is_last = 0; - } else if (req->req.length == req->req.actual) - *is_last = 1; - else - *is_last = 0; - - /* Enable interrupt for the last trb of a request */ - if (*is_last && !req->req.no_interrupt) - trb->trb_hw->ctrl.ioc = 1; - - if (*is_last) - trb->trb_hw->ctrl.chain = 0; - else { - trb->trb_hw->ctrl.chain = 1; - dev_dbg(u3d->dev, "chain trb\n"); - } - - wmb(); - - return 0; -} - -/* generate TRB linked list for a request - * usb controller only supports continous trb chain, - * that trb structure physical address should be continous. - */ -static int mv_u3d_req_to_trb(struct mv_u3d_req *req) -{ - unsigned count; - int is_last; - struct mv_u3d_trb *trb; - struct mv_u3d_trb_hw *trb_hw; - struct mv_u3d *u3d; - dma_addr_t dma; - unsigned length; - unsigned trb_num; - - u3d = req->ep->u3d; - - INIT_LIST_HEAD(&req->trb_list); - - length = req->req.length - req->req.actual; - /* normally the request transfer length is less than 16KB. - * we use buil_trb_one() to optimize it. - */ - if (length <= (unsigned)MV_U3D_EP_MAX_LENGTH_TRANSFER) { - trb = mv_u3d_build_trb_one(req, &count, &dma); - list_add_tail(&trb->trb_list, &req->trb_list); - req->trb_head = trb; - req->trb_count = 1; - req->chain = 0; - } else { - trb_num = length / MV_U3D_EP_MAX_LENGTH_TRANSFER; - if (length % MV_U3D_EP_MAX_LENGTH_TRANSFER) - trb_num++; - - trb = kcalloc(trb_num, sizeof(*trb), GFP_ATOMIC); - if (!trb) - return -ENOMEM; - - trb_hw = kcalloc(trb_num, sizeof(*trb_hw), GFP_ATOMIC); - if (!trb_hw) { - kfree(trb); - return -ENOMEM; - } - - do { - trb->trb_hw = trb_hw; - if (mv_u3d_build_trb_chain(req, &count, - trb, &is_last)) { - dev_err(u3d->dev, - "%s, mv_u3d_build_trb_chain fail\n", - __func__); - return -EIO; - } - - list_add_tail(&trb->trb_list, &req->trb_list); - req->trb_count++; - trb++; - trb_hw++; - } while (!is_last); - - req->trb_head = list_entry(req->trb_list.next, - struct mv_u3d_trb, trb_list); - req->trb_head->trb_dma = dma_map_single(u3d->gadget.dev.parent, - req->trb_head->trb_hw, - trb_num * sizeof(*trb_hw), - DMA_BIDIRECTIONAL); - if (dma_mapping_error(u3d->gadget.dev.parent, - req->trb_head->trb_dma)) { - kfree(req->trb_head->trb_hw); - kfree(req->trb_head); - return -EFAULT; - } - - req->chain = 1; - } - - return 0; -} - -static int -mv_u3d_start_queue(struct mv_u3d_ep *ep) -{ - struct mv_u3d *u3d = ep->u3d; - struct mv_u3d_req *req; - int ret; - - if (!list_empty(&ep->req_list) && !ep->processing) - req = list_entry(ep->req_list.next, struct mv_u3d_req, list); - else - return 0; - - ep->processing = 1; - - /* set up dma mapping */ - ret = usb_gadget_map_request(&u3d->gadget, &req->req, - mv_u3d_ep_dir(ep)); - if (ret) - goto break_processing; - - req->req.status = -EINPROGRESS; - req->req.actual = 0; - req->trb_count = 0; - - /* build trbs */ - ret = mv_u3d_req_to_trb(req); - if (ret) { - dev_err(u3d->dev, "%s, mv_u3d_req_to_trb fail\n", __func__); - goto break_processing; - } - - /* and push them to device queue */ - ret = mv_u3d_queue_trb(ep, req); - if (ret) - goto break_processing; - - /* irq handler advances the queue */ - list_add_tail(&req->queue, &ep->queue); - - return 0; - -break_processing: - ep->processing = 0; - return ret; -} - -static int mv_u3d_ep_enable(struct usb_ep *_ep, - const struct usb_endpoint_descriptor *desc) -{ - struct mv_u3d *u3d; - struct mv_u3d_ep *ep; - u16 max = 0; - unsigned maxburst = 0; - u32 epxcr, direction; - - if (!_ep || !desc || desc->bDescriptorType != USB_DT_ENDPOINT) - return -EINVAL; - - ep = container_of(_ep, struct mv_u3d_ep, ep); - u3d = ep->u3d; - - if (!u3d->driver || u3d->gadget.speed == USB_SPEED_UNKNOWN) - return -ESHUTDOWN; - - direction = mv_u3d_ep_dir(ep); - max = le16_to_cpu(desc->wMaxPacketSize); - - if (!_ep->maxburst) - _ep->maxburst = 1; - maxburst = _ep->maxburst; - - /* Set the max burst size */ - switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { - case USB_ENDPOINT_XFER_BULK: - if (maxburst > 16) { - dev_dbg(u3d->dev, - "max burst should not be greater " - "than 16 on bulk ep\n"); - maxburst = 1; - _ep->maxburst = maxburst; - } - dev_dbg(u3d->dev, - "maxburst: %d on bulk %s\n", maxburst, ep->name); - break; - case USB_ENDPOINT_XFER_CONTROL: - /* control transfer only supports maxburst as one */ - maxburst = 1; - _ep->maxburst = maxburst; - break; - case USB_ENDPOINT_XFER_INT: - if (maxburst != 1) { - dev_dbg(u3d->dev, - "max burst should be 1 on int ep " - "if transfer size is not 1024\n"); - maxburst = 1; - _ep->maxburst = maxburst; - } - break; - case USB_ENDPOINT_XFER_ISOC: - if (maxburst != 1) { - dev_dbg(u3d->dev, - "max burst should be 1 on isoc ep " - "if transfer size is not 1024\n"); - maxburst = 1; - _ep->maxburst = maxburst; - } - break; - default: - goto en_done; - } - - ep->ep.maxpacket = max; - ep->ep.desc = desc; - ep->enabled = 1; - - /* Enable the endpoint for Rx or Tx and set the endpoint type */ - if (direction == MV_U3D_EP_DIR_OUT) { - epxcr = ioread32(&u3d->vuc_regs->epcr[ep->ep_num].epxoutcr0); - epxcr |= MV_U3D_EPXCR_EP_INIT; - iowrite32(epxcr, &u3d->vuc_regs->epcr[ep->ep_num].epxoutcr0); - udelay(5); - epxcr &= ~MV_U3D_EPXCR_EP_INIT; - iowrite32(epxcr, &u3d->vuc_regs->epcr[ep->ep_num].epxoutcr0); - - epxcr = ((max << MV_U3D_EPXCR_MAX_PACKET_SIZE_SHIFT) - | ((maxburst - 1) << MV_U3D_EPXCR_MAX_BURST_SIZE_SHIFT) - | (1 << MV_U3D_EPXCR_EP_ENABLE_SHIFT) - | (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)); - iowrite32(epxcr, &u3d->vuc_regs->epcr[ep->ep_num].epxoutcr1); - } else { - epxcr = ioread32(&u3d->vuc_regs->epcr[ep->ep_num].epxincr0); - epxcr |= MV_U3D_EPXCR_EP_INIT; - iowrite32(epxcr, &u3d->vuc_regs->epcr[ep->ep_num].epxincr0); - udelay(5); - epxcr &= ~MV_U3D_EPXCR_EP_INIT; - iowrite32(epxcr, &u3d->vuc_regs->epcr[ep->ep_num].epxincr0); - - epxcr = ((max << MV_U3D_EPXCR_MAX_PACKET_SIZE_SHIFT) - | ((maxburst - 1) << MV_U3D_EPXCR_MAX_BURST_SIZE_SHIFT) - | (1 << MV_U3D_EPXCR_EP_ENABLE_SHIFT) - | (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)); - iowrite32(epxcr, &u3d->vuc_regs->epcr[ep->ep_num].epxincr1); - } - - return 0; -en_done: - return -EINVAL; -} - -static int mv_u3d_ep_disable(struct usb_ep *_ep) -{ - struct mv_u3d *u3d; - struct mv_u3d_ep *ep; - u32 epxcr, direction; - unsigned long flags; - - if (!_ep) - return -EINVAL; - - ep = container_of(_ep, struct mv_u3d_ep, ep); - if (!ep->ep.desc) - return -EINVAL; - - u3d = ep->u3d; - - direction = mv_u3d_ep_dir(ep); - - /* nuke all pending requests (does flush) */ - spin_lock_irqsave(&u3d->lock, flags); - mv_u3d_nuke(ep, -ESHUTDOWN); - spin_unlock_irqrestore(&u3d->lock, flags); - - /* Disable the endpoint for Rx or Tx and reset the endpoint type */ - if (direction == MV_U3D_EP_DIR_OUT) { - epxcr = ioread32(&u3d->vuc_regs->epcr[ep->ep_num].epxoutcr1); - epxcr &= ~((1 << MV_U3D_EPXCR_EP_ENABLE_SHIFT) - | USB_ENDPOINT_XFERTYPE_MASK); - iowrite32(epxcr, &u3d->vuc_regs->epcr[ep->ep_num].epxoutcr1); - } else { - epxcr = ioread32(&u3d->vuc_regs->epcr[ep->ep_num].epxincr1); - epxcr &= ~((1 << MV_U3D_EPXCR_EP_ENABLE_SHIFT) - | USB_ENDPOINT_XFERTYPE_MASK); - iowrite32(epxcr, &u3d->vuc_regs->epcr[ep->ep_num].epxincr1); - } - - ep->enabled = 0; - - ep->ep.desc = NULL; - return 0; -} - -static struct usb_request * -mv_u3d_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags) -{ - struct mv_u3d_req *req; - - req = kzalloc(sizeof *req, gfp_flags); - if (!req) - return NULL; - - INIT_LIST_HEAD(&req->queue); - - return &req->req; -} - -static void mv_u3d_free_request(struct usb_ep *_ep, struct usb_request *_req) -{ - struct mv_u3d_req *req = container_of(_req, struct mv_u3d_req, req); - - kfree(req); -} - -static void mv_u3d_ep_fifo_flush(struct usb_ep *_ep) -{ - struct mv_u3d *u3d; - u32 direction; - struct mv_u3d_ep *ep = container_of(_ep, struct mv_u3d_ep, ep); - unsigned int loops; - u32 tmp; - - /* if endpoint is not enabled, cannot flush endpoint */ - if (!ep->enabled) - return; - - u3d = ep->u3d; - direction = mv_u3d_ep_dir(ep); - - /* ep0 need clear bit after flushing fifo. */ - if (!ep->ep_num) { - if (direction == MV_U3D_EP_DIR_OUT) { - tmp = ioread32(&u3d->vuc_regs->epcr[0].epxoutcr0); - tmp |= MV_U3D_EPXCR_EP_FLUSH; - iowrite32(tmp, &u3d->vuc_regs->epcr[0].epxoutcr0); - udelay(10); - tmp &= ~MV_U3D_EPXCR_EP_FLUSH; - iowrite32(tmp, &u3d->vuc_regs->epcr[0].epxoutcr0); - } else { - tmp = ioread32(&u3d->vuc_regs->epcr[0].epxincr0); - tmp |= MV_U3D_EPXCR_EP_FLUSH; - iowrite32(tmp, &u3d->vuc_regs->epcr[0].epxincr0); - udelay(10); - tmp &= ~MV_U3D_EPXCR_EP_FLUSH; - iowrite32(tmp, &u3d->vuc_regs->epcr[0].epxincr0); - } - return; - } - - if (direction == MV_U3D_EP_DIR_OUT) { - tmp = ioread32(&u3d->vuc_regs->epcr[ep->ep_num].epxoutcr0); - tmp |= MV_U3D_EPXCR_EP_FLUSH; - iowrite32(tmp, &u3d->vuc_regs->epcr[ep->ep_num].epxoutcr0); - - /* Wait until flushing completed */ - loops = LOOPS(MV_U3D_FLUSH_TIMEOUT); - while (ioread32(&u3d->vuc_regs->epcr[ep->ep_num].epxoutcr0) & - MV_U3D_EPXCR_EP_FLUSH) { - /* - * EP_FLUSH bit should be cleared to indicate this - * operation is complete - */ - if (loops == 0) { - dev_dbg(u3d->dev, - "EP FLUSH TIMEOUT for ep%d%s\n", ep->ep_num, - direction ? "in" : "out"); - return; - } - loops--; - udelay(LOOPS_USEC); - } - } else { /* EP_DIR_IN */ - tmp = ioread32(&u3d->vuc_regs->epcr[ep->ep_num].epxincr0); - tmp |= MV_U3D_EPXCR_EP_FLUSH; - iowrite32(tmp, &u3d->vuc_regs->epcr[ep->ep_num].epxincr0); - - /* Wait until flushing completed */ - loops = LOOPS(MV_U3D_FLUSH_TIMEOUT); - while (ioread32(&u3d->vuc_regs->epcr[ep->ep_num].epxincr0) & - MV_U3D_EPXCR_EP_FLUSH) { - /* - * EP_FLUSH bit should be cleared to indicate this - * operation is complete - */ - if (loops == 0) { - dev_dbg(u3d->dev, - "EP FLUSH TIMEOUT for ep%d%s\n", ep->ep_num, - direction ? "in" : "out"); - return; - } - loops--; - udelay(LOOPS_USEC); - } - } -} - -/* queues (submits) an I/O request to an endpoint */ -static int -mv_u3d_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) -{ - struct mv_u3d_ep *ep; - struct mv_u3d_req *req; - struct mv_u3d *u3d; - unsigned long flags; - int is_first_req = 0; - - if (unlikely(!_ep || !_req)) - return -EINVAL; - - ep = container_of(_ep, struct mv_u3d_ep, ep); - u3d = ep->u3d; - - req = container_of(_req, struct mv_u3d_req, req); - - if (!ep->ep_num - && u3d->ep0_state == MV_U3D_STATUS_STAGE - && !_req->length) { - dev_dbg(u3d->dev, "ep0 status stage\n"); - u3d->ep0_state = MV_U3D_WAIT_FOR_SETUP; - return 0; - } - - dev_dbg(u3d->dev, "%s: %s, req: 0x%p\n", - __func__, _ep->name, req); - - /* catch various bogus parameters */ - if (!req->req.complete || !req->req.buf - || !list_empty(&req->queue)) { - dev_err(u3d->dev, - "%s, bad params, _req: 0x%p," - "req->req.complete: 0x%p, req->req.buf: 0x%p," - "list_empty: 0x%x\n", - __func__, _req, - req->req.complete, req->req.buf, - list_empty(&req->queue)); - return -EINVAL; - } - if (unlikely(!ep->ep.desc)) { - dev_err(u3d->dev, "%s, bad ep\n", __func__); - return -EINVAL; - } - if (ep->ep.desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) { - if (req->req.length > ep->ep.maxpacket) - return -EMSGSIZE; - } - - if (!u3d->driver || u3d->gadget.speed == USB_SPEED_UNKNOWN) { - dev_err(u3d->dev, - "bad params of driver/speed\n"); - return -ESHUTDOWN; - } - - req->ep = ep; - - /* Software list handles usb request. */ - spin_lock_irqsave(&ep->req_lock, flags); - is_first_req = list_empty(&ep->req_list); - list_add_tail(&req->list, &ep->req_list); - spin_unlock_irqrestore(&ep->req_lock, flags); - if (!is_first_req) { - dev_dbg(u3d->dev, "list is not empty\n"); - return 0; - } - - dev_dbg(u3d->dev, "call mv_u3d_start_queue from usb_ep_queue\n"); - spin_lock_irqsave(&u3d->lock, flags); - mv_u3d_start_queue(ep); - spin_unlock_irqrestore(&u3d->lock, flags); - return 0; -} - -/* dequeues (cancels, unlinks) an I/O request from an endpoint */ -static int mv_u3d_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) -{ - struct mv_u3d_ep *ep; - struct mv_u3d_req *req = NULL, *iter; - struct mv_u3d *u3d; - struct mv_u3d_ep_context *ep_context; - struct mv_u3d_req *next_req; - - unsigned long flags; - int ret = 0; - - if (!_ep || !_req) - return -EINVAL; - - ep = container_of(_ep, struct mv_u3d_ep, ep); - u3d = ep->u3d; - - spin_lock_irqsave(&ep->u3d->lock, flags); - - /* make sure it's actually queued on this endpoint */ - list_for_each_entry(iter, &ep->queue, queue) { - if (&iter->req != _req) - continue; - req = iter; - break; - } - if (!req) { - ret = -EINVAL; - goto out; - } - - /* The request is in progress, or completed but not dequeued */ - if (ep->queue.next == &req->queue) { - _req->status = -ECONNRESET; - mv_u3d_ep_fifo_flush(_ep); - - /* The request isn't the last request in this ep queue */ - if (req->queue.next != &ep->queue) { - dev_dbg(u3d->dev, - "it is the last request in this ep queue\n"); - ep_context = ep->ep_context; - next_req = list_entry(req->queue.next, - struct mv_u3d_req, queue); - - /* Point first TRB of next request to the EP context. */ - iowrite32((unsigned long) next_req->trb_head, - &ep_context->trb_addr_lo); - } else { - struct mv_u3d_ep_context *ep_context; - ep_context = ep->ep_context; - ep_context->trb_addr_lo = 0; - ep_context->trb_addr_hi = 0; - } - - } else - WARN_ON(1); - - mv_u3d_done(ep, req, -ECONNRESET); - - /* remove the req from the ep req list */ - if (!list_empty(&ep->req_list)) { - struct mv_u3d_req *curr_req; - curr_req = list_entry(ep->req_list.next, - struct mv_u3d_req, list); - if (curr_req == req) { - list_del_init(&req->list); - ep->processing = 0; - } - } - -out: - spin_unlock_irqrestore(&ep->u3d->lock, flags); - return ret; -} - -static void -mv_u3d_ep_set_stall(struct mv_u3d *u3d, u8 ep_num, u8 direction, int stall) -{ - u32 tmp; - struct mv_u3d_ep *ep = u3d->eps; - - dev_dbg(u3d->dev, "%s\n", __func__); - if (direction == MV_U3D_EP_DIR_OUT) { - tmp = ioread32(&u3d->vuc_regs->epcr[ep->ep_num].epxoutcr0); - if (stall) - tmp |= MV_U3D_EPXCR_EP_HALT; - else - tmp &= ~MV_U3D_EPXCR_EP_HALT; - iowrite32(tmp, &u3d->vuc_regs->epcr[ep->ep_num].epxoutcr0); - } else { - tmp = ioread32(&u3d->vuc_regs->epcr[ep->ep_num].epxincr0); - if (stall) - tmp |= MV_U3D_EPXCR_EP_HALT; - else - tmp &= ~MV_U3D_EPXCR_EP_HALT; - iowrite32(tmp, &u3d->vuc_regs->epcr[ep->ep_num].epxincr0); - } -} - -static int mv_u3d_ep_set_halt_wedge(struct usb_ep *_ep, int halt, int wedge) -{ - struct mv_u3d_ep *ep; - unsigned long flags; - int status = 0; - struct mv_u3d *u3d; - - ep = container_of(_ep, struct mv_u3d_ep, ep); - u3d = ep->u3d; - if (!ep->ep.desc) { - status = -EINVAL; - goto out; - } - - if (ep->ep.desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) { - status = -EOPNOTSUPP; - goto out; - } - - /* - * Attempt to halt IN ep will fail if any transfer requests - * are still queue - */ - if (halt && (mv_u3d_ep_dir(ep) == MV_U3D_EP_DIR_IN) - && !list_empty(&ep->queue)) { - status = -EAGAIN; - goto out; - } - - spin_lock_irqsave(&ep->u3d->lock, flags); - mv_u3d_ep_set_stall(u3d, ep->ep_num, mv_u3d_ep_dir(ep), halt); - if (halt && wedge) - ep->wedge = 1; - else if (!halt) - ep->wedge = 0; - spin_unlock_irqrestore(&ep->u3d->lock, flags); - - if (ep->ep_num == 0) - u3d->ep0_dir = MV_U3D_EP_DIR_OUT; -out: - return status; -} - -static int mv_u3d_ep_set_halt(struct usb_ep *_ep, int halt) -{ - return mv_u3d_ep_set_halt_wedge(_ep, halt, 0); -} - -static int mv_u3d_ep_set_wedge(struct usb_ep *_ep) -{ - return mv_u3d_ep_set_halt_wedge(_ep, 1, 1); -} - -static const struct usb_ep_ops mv_u3d_ep_ops = { - .enable = mv_u3d_ep_enable, - .disable = mv_u3d_ep_disable, - - .alloc_request = mv_u3d_alloc_request, - .free_request = mv_u3d_free_request, - - .queue = mv_u3d_ep_queue, - .dequeue = mv_u3d_ep_dequeue, - - .set_wedge = mv_u3d_ep_set_wedge, - .set_halt = mv_u3d_ep_set_halt, - .fifo_flush = mv_u3d_ep_fifo_flush, -}; - -static void mv_u3d_controller_stop(struct mv_u3d *u3d) -{ - u32 tmp; - - if (!u3d->clock_gating && u3d->vbus_valid_detect) - iowrite32(MV_U3D_INTR_ENABLE_VBUS_VALID, - &u3d->vuc_regs->intrenable); - else - iowrite32(0, &u3d->vuc_regs->intrenable); - iowrite32(~0x0, &u3d->vuc_regs->endcomplete); - iowrite32(~0x0, &u3d->vuc_regs->trbunderrun); - iowrite32(~0x0, &u3d->vuc_regs->trbcomplete); - iowrite32(~0x0, &u3d->vuc_regs->linkchange); - iowrite32(0x1, &u3d->vuc_regs->setuplock); - - /* Reset the RUN bit in the command register to stop USB */ - tmp = ioread32(&u3d->op_regs->usbcmd); - tmp &= ~MV_U3D_CMD_RUN_STOP; - iowrite32(tmp, &u3d->op_regs->usbcmd); - dev_dbg(u3d->dev, "after u3d_stop, USBCMD 0x%x\n", - ioread32(&u3d->op_regs->usbcmd)); -} - -static void mv_u3d_controller_start(struct mv_u3d *u3d) -{ - u32 usbintr; - u32 temp; - - /* enable link LTSSM state machine */ - temp = ioread32(&u3d->vuc_regs->ltssm); - temp |= MV_U3D_LTSSM_PHY_INIT_DONE; - iowrite32(temp, &u3d->vuc_regs->ltssm); - - /* Enable interrupts */ - usbintr = MV_U3D_INTR_ENABLE_LINK_CHG | MV_U3D_INTR_ENABLE_TXDESC_ERR | - MV_U3D_INTR_ENABLE_RXDESC_ERR | MV_U3D_INTR_ENABLE_TX_COMPLETE | - MV_U3D_INTR_ENABLE_RX_COMPLETE | MV_U3D_INTR_ENABLE_SETUP | - (u3d->vbus_valid_detect ? MV_U3D_INTR_ENABLE_VBUS_VALID : 0); - iowrite32(usbintr, &u3d->vuc_regs->intrenable); - - /* Enable ctrl ep */ - iowrite32(0x1, &u3d->vuc_regs->ctrlepenable); - - /* Set the Run bit in the command register */ - iowrite32(MV_U3D_CMD_RUN_STOP, &u3d->op_regs->usbcmd); - dev_dbg(u3d->dev, "after u3d_start, USBCMD 0x%x\n", - ioread32(&u3d->op_regs->usbcmd)); -} - -static int mv_u3d_controller_reset(struct mv_u3d *u3d) -{ - unsigned int loops; - u32 tmp; - - /* Stop the controller */ - tmp = ioread32(&u3d->op_regs->usbcmd); - tmp &= ~MV_U3D_CMD_RUN_STOP; - iowrite32(tmp, &u3d->op_regs->usbcmd); - - /* Reset the controller to get default values */ - iowrite32(MV_U3D_CMD_CTRL_RESET, &u3d->op_regs->usbcmd); - - /* wait for reset to complete */ - loops = LOOPS(MV_U3D_RESET_TIMEOUT); - while (ioread32(&u3d->op_regs->usbcmd) & MV_U3D_CMD_CTRL_RESET) { - if (loops == 0) { - dev_err(u3d->dev, - "Wait for RESET completed TIMEOUT\n"); - return -ETIMEDOUT; - } - loops--; - udelay(LOOPS_USEC); - } - - /* Configure the Endpoint Context Address */ - iowrite32(u3d->ep_context_dma, &u3d->op_regs->dcbaapl); - iowrite32(0, &u3d->op_regs->dcbaaph); - - return 0; -} - -static int mv_u3d_enable(struct mv_u3d *u3d) -{ - struct mv_usb_platform_data *pdata = dev_get_platdata(u3d->dev); - int retval; - - if (u3d->active) - return 0; - - if (!u3d->clock_gating) { - u3d->active = 1; - return 0; - } - - dev_dbg(u3d->dev, "enable u3d\n"); - clk_enable(u3d->clk); - if (pdata->phy_init) { - retval = pdata->phy_init(u3d->phy_regs); - if (retval) { - dev_err(u3d->dev, - "init phy error %d\n", retval); - clk_disable(u3d->clk); - return retval; - } - } - u3d->active = 1; - - return 0; -} - -static void mv_u3d_disable(struct mv_u3d *u3d) -{ - struct mv_usb_platform_data *pdata = dev_get_platdata(u3d->dev); - if (u3d->clock_gating && u3d->active) { - dev_dbg(u3d->dev, "disable u3d\n"); - if (pdata->phy_deinit) - pdata->phy_deinit(u3d->phy_regs); - clk_disable(u3d->clk); - u3d->active = 0; - } -} - -static int mv_u3d_vbus_session(struct usb_gadget *gadget, int is_active) -{ - struct mv_u3d *u3d; - unsigned long flags; - int retval = 0; - - u3d = container_of(gadget, struct mv_u3d, gadget); - - spin_lock_irqsave(&u3d->lock, flags); - - u3d->vbus_active = (is_active != 0); - dev_dbg(u3d->dev, "%s: softconnect %d, vbus_active %d\n", - __func__, u3d->softconnect, u3d->vbus_active); - /* - * 1. external VBUS detect: we can disable/enable clock on demand. - * 2. UDC VBUS detect: we have to enable clock all the time. - * 3. No VBUS detect: we have to enable clock all the time. - */ - if (u3d->driver && u3d->softconnect && u3d->vbus_active) { - retval = mv_u3d_enable(u3d); - if (retval == 0) { - /* - * after clock is disabled, we lost all the register - * context. We have to re-init registers - */ - mv_u3d_controller_reset(u3d); - mv_u3d_ep0_reset(u3d); - mv_u3d_controller_start(u3d); - } - } else if (u3d->driver && u3d->softconnect) { - if (!u3d->active) - goto out; - - /* stop all the transfer in queue*/ - mv_u3d_stop_activity(u3d, u3d->driver); - mv_u3d_controller_stop(u3d); - mv_u3d_disable(u3d); - } - -out: - spin_unlock_irqrestore(&u3d->lock, flags); - return retval; -} - -/* constrain controller's VBUS power usage - * This call is used by gadget drivers during SET_CONFIGURATION calls, - * reporting how much power the device may consume. For example, this - * could affect how quickly batteries are recharged. - * - * Returns zero on success, else negative errno. - */ -static int mv_u3d_vbus_draw(struct usb_gadget *gadget, unsigned mA) -{ - struct mv_u3d *u3d = container_of(gadget, struct mv_u3d, gadget); - - u3d->power = mA; - - return 0; -} - -static int mv_u3d_pullup(struct usb_gadget *gadget, int is_on) -{ - struct mv_u3d *u3d = container_of(gadget, struct mv_u3d, gadget); - unsigned long flags; - int retval = 0; - - spin_lock_irqsave(&u3d->lock, flags); - - dev_dbg(u3d->dev, "%s: softconnect %d, vbus_active %d\n", - __func__, u3d->softconnect, u3d->vbus_active); - u3d->softconnect = (is_on != 0); - if (u3d->driver && u3d->softconnect && u3d->vbus_active) { - retval = mv_u3d_enable(u3d); - if (retval == 0) { - /* - * after clock is disabled, we lost all the register - * context. We have to re-init registers - */ - mv_u3d_controller_reset(u3d); - mv_u3d_ep0_reset(u3d); - mv_u3d_controller_start(u3d); - } - } else if (u3d->driver && u3d->vbus_active) { - /* stop all the transfer in queue*/ - mv_u3d_stop_activity(u3d, u3d->driver); - mv_u3d_controller_stop(u3d); - mv_u3d_disable(u3d); - } - - spin_unlock_irqrestore(&u3d->lock, flags); - - return retval; -} - -static int mv_u3d_start(struct usb_gadget *g, - struct usb_gadget_driver *driver) -{ - struct mv_u3d *u3d = container_of(g, struct mv_u3d, gadget); - struct mv_usb_platform_data *pdata = dev_get_platdata(u3d->dev); - unsigned long flags; - - if (u3d->driver) - return -EBUSY; - - spin_lock_irqsave(&u3d->lock, flags); - - if (!u3d->clock_gating) { - clk_enable(u3d->clk); - if (pdata->phy_init) - pdata->phy_init(u3d->phy_regs); - } - - /* hook up the driver ... */ - u3d->driver = driver; - - u3d->ep0_dir = USB_DIR_OUT; - - spin_unlock_irqrestore(&u3d->lock, flags); - - u3d->vbus_valid_detect = 1; - - return 0; -} - -static int mv_u3d_stop(struct usb_gadget *g) -{ - struct mv_u3d *u3d = container_of(g, struct mv_u3d, gadget); - struct mv_usb_platform_data *pdata = dev_get_platdata(u3d->dev); - unsigned long flags; - - u3d->vbus_valid_detect = 0; - spin_lock_irqsave(&u3d->lock, flags); - - /* enable clock to access controller register */ - clk_enable(u3d->clk); - if (pdata->phy_init) - pdata->phy_init(u3d->phy_regs); - - mv_u3d_controller_stop(u3d); - /* stop all usb activities */ - u3d->gadget.speed = USB_SPEED_UNKNOWN; - mv_u3d_stop_activity(u3d, NULL); - mv_u3d_disable(u3d); - - if (pdata->phy_deinit) - pdata->phy_deinit(u3d->phy_regs); - clk_disable(u3d->clk); - - spin_unlock_irqrestore(&u3d->lock, flags); - - u3d->driver = NULL; - - return 0; -} - -/* device controller usb_gadget_ops structure */ -static const struct usb_gadget_ops mv_u3d_ops = { - /* notify controller that VBUS is powered or not */ - .vbus_session = mv_u3d_vbus_session, - - /* constrain controller's VBUS power usage */ - .vbus_draw = mv_u3d_vbus_draw, - - .pullup = mv_u3d_pullup, - .udc_start = mv_u3d_start, - .udc_stop = mv_u3d_stop, -}; - -static int mv_u3d_eps_init(struct mv_u3d *u3d) -{ - struct mv_u3d_ep *ep; - char name[14]; - int i; - - /* initialize ep0, ep0 in/out use eps[1] */ - ep = &u3d->eps[1]; - ep->u3d = u3d; - strscpy(ep->name, "ep0"); - ep->ep.name = ep->name; - ep->ep.ops = &mv_u3d_ep_ops; - ep->wedge = 0; - usb_ep_set_maxpacket_limit(&ep->ep, MV_U3D_EP0_MAX_PKT_SIZE); - ep->ep.caps.type_control = true; - ep->ep.caps.dir_in = true; - ep->ep.caps.dir_out = true; - ep->ep_num = 0; - ep->ep.desc = &mv_u3d_ep0_desc; - INIT_LIST_HEAD(&ep->queue); - INIT_LIST_HEAD(&ep->req_list); - ep->ep_type = USB_ENDPOINT_XFER_CONTROL; - - /* add ep0 ep_context */ - ep->ep_context = &u3d->ep_context[1]; - - /* initialize other endpoints */ - for (i = 2; i < u3d->max_eps * 2; i++) { - ep = &u3d->eps[i]; - if (i & 1) { - snprintf(name, sizeof(name), "ep%din", i >> 1); - ep->direction = MV_U3D_EP_DIR_IN; - ep->ep.caps.dir_in = true; - } else { - snprintf(name, sizeof(name), "ep%dout", i >> 1); - ep->direction = MV_U3D_EP_DIR_OUT; - ep->ep.caps.dir_out = true; - } - ep->u3d = u3d; - strscpy(ep->name, name); - ep->ep.name = ep->name; - - ep->ep.caps.type_iso = true; - ep->ep.caps.type_bulk = true; - ep->ep.caps.type_int = true; - - ep->ep.ops = &mv_u3d_ep_ops; - usb_ep_set_maxpacket_limit(&ep->ep, (unsigned short) ~0); - ep->ep_num = i / 2; - - INIT_LIST_HEAD(&ep->queue); - list_add_tail(&ep->ep.ep_list, &u3d->gadget.ep_list); - - INIT_LIST_HEAD(&ep->req_list); - spin_lock_init(&ep->req_lock); - ep->ep_context = &u3d->ep_context[i]; - } - - return 0; -} - -/* delete all endpoint requests, called with spinlock held */ -static void mv_u3d_nuke(struct mv_u3d_ep *ep, int status) -{ - /* endpoint fifo flush */ - mv_u3d_ep_fifo_flush(&ep->ep); - - while (!list_empty(&ep->queue)) { - struct mv_u3d_req *req = NULL; - req = list_entry(ep->queue.next, struct mv_u3d_req, queue); - mv_u3d_done(ep, req, status); - } -} - -/* stop all USB activities */ -static -void mv_u3d_stop_activity(struct mv_u3d *u3d, struct usb_gadget_driver *driver) -{ - struct mv_u3d_ep *ep; - - mv_u3d_nuke(&u3d->eps[1], -ESHUTDOWN); - - list_for_each_entry(ep, &u3d->gadget.ep_list, ep.ep_list) { - mv_u3d_nuke(ep, -ESHUTDOWN); - } - - /* report disconnect; the driver is already quiesced */ - if (driver) { - spin_unlock(&u3d->lock); - driver->disconnect(&u3d->gadget); - spin_lock(&u3d->lock); - } -} - -static void mv_u3d_irq_process_error(struct mv_u3d *u3d) -{ - /* Increment the error count */ - u3d->errors++; - dev_err(u3d->dev, "%s\n", __func__); -} - -static void mv_u3d_irq_process_link_change(struct mv_u3d *u3d) -{ - u32 linkchange; - - linkchange = ioread32(&u3d->vuc_regs->linkchange); - iowrite32(linkchange, &u3d->vuc_regs->linkchange); - - dev_dbg(u3d->dev, "linkchange: 0x%x\n", linkchange); - - if (linkchange & MV_U3D_LINK_CHANGE_LINK_UP) { - dev_dbg(u3d->dev, "link up: ltssm state: 0x%x\n", - ioread32(&u3d->vuc_regs->ltssmstate)); - - u3d->usb_state = USB_STATE_DEFAULT; - u3d->ep0_dir = MV_U3D_EP_DIR_OUT; - u3d->ep0_state = MV_U3D_WAIT_FOR_SETUP; - - /* set speed */ - u3d->gadget.speed = USB_SPEED_SUPER; - } - - if (linkchange & MV_U3D_LINK_CHANGE_SUSPEND) { - dev_dbg(u3d->dev, "link suspend\n"); - u3d->resume_state = u3d->usb_state; - u3d->usb_state = USB_STATE_SUSPENDED; - } - - if (linkchange & MV_U3D_LINK_CHANGE_RESUME) { - dev_dbg(u3d->dev, "link resume\n"); - u3d->usb_state = u3d->resume_state; - u3d->resume_state = 0; - } - - if (linkchange & MV_U3D_LINK_CHANGE_WRESET) { - dev_dbg(u3d->dev, "warm reset\n"); - u3d->usb_state = USB_STATE_POWERED; - } - - if (linkchange & MV_U3D_LINK_CHANGE_HRESET) { - dev_dbg(u3d->dev, "hot reset\n"); - u3d->usb_state = USB_STATE_DEFAULT; - } - - if (linkchange & MV_U3D_LINK_CHANGE_INACT) - dev_dbg(u3d->dev, "inactive\n"); - - if (linkchange & MV_U3D_LINK_CHANGE_DISABLE_AFTER_U0) - dev_dbg(u3d->dev, "ss.disabled\n"); - - if (linkchange & MV_U3D_LINK_CHANGE_VBUS_INVALID) { - dev_dbg(u3d->dev, "vbus invalid\n"); - u3d->usb_state = USB_STATE_ATTACHED; - u3d->vbus_valid_detect = 1; - /* if external vbus detect is not supported, - * we handle it here. - */ - if (!u3d->vbus) { - spin_unlock(&u3d->lock); - mv_u3d_vbus_session(&u3d->gadget, 0); - spin_lock(&u3d->lock); - } - } -} - -static void mv_u3d_ch9setaddress(struct mv_u3d *u3d, - struct usb_ctrlrequest *setup) -{ - u32 tmp; - - if (u3d->usb_state != USB_STATE_DEFAULT) { - dev_err(u3d->dev, - "%s, cannot setaddr in this state (%d)\n", - __func__, u3d->usb_state); - goto err; - } - - u3d->dev_addr = (u8)setup->wValue; - - dev_dbg(u3d->dev, "%s: 0x%x\n", __func__, u3d->dev_addr); - - if (u3d->dev_addr > 127) { - dev_err(u3d->dev, - "%s, u3d address is wrong (out of range)\n", __func__); - u3d->dev_addr = 0; - goto err; - } - - /* update usb state */ - u3d->usb_state = USB_STATE_ADDRESS; - - /* set the new address */ - tmp = ioread32(&u3d->vuc_regs->devaddrtiebrkr); - tmp &= ~0x7F; - tmp |= (u32)u3d->dev_addr; - iowrite32(tmp, &u3d->vuc_regs->devaddrtiebrkr); - - return; -err: - mv_u3d_ep0_stall(u3d); -} - -static int mv_u3d_is_set_configuration(struct usb_ctrlrequest *setup) -{ - if ((setup->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) - if (setup->bRequest == USB_REQ_SET_CONFIGURATION) - return 1; - - return 0; -} - -static void mv_u3d_handle_setup_packet(struct mv_u3d *u3d, u8 ep_num, - struct usb_ctrlrequest *setup) - __releases(&u3c->lock) - __acquires(&u3c->lock) -{ - bool delegate = false; - - mv_u3d_nuke(&u3d->eps[ep_num * 2 + MV_U3D_EP_DIR_IN], -ESHUTDOWN); - - dev_dbg(u3d->dev, "SETUP %02x.%02x v%04x i%04x l%04x\n", - setup->bRequestType, setup->bRequest, - setup->wValue, setup->wIndex, setup->wLength); - - /* We process some stardard setup requests here */ - if ((setup->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) { - switch (setup->bRequest) { - case USB_REQ_GET_STATUS: - delegate = true; - break; - - case USB_REQ_SET_ADDRESS: - mv_u3d_ch9setaddress(u3d, setup); - break; - - case USB_REQ_CLEAR_FEATURE: - delegate = true; - break; - - case USB_REQ_SET_FEATURE: - delegate = true; - break; - - default: - delegate = true; - } - } else - delegate = true; - - /* delegate USB standard requests to the gadget driver */ - if (delegate) { - /* USB requests handled by gadget */ - if (setup->wLength) { - /* DATA phase from gadget, STATUS phase from u3d */ - u3d->ep0_dir = (setup->bRequestType & USB_DIR_IN) - ? MV_U3D_EP_DIR_IN : MV_U3D_EP_DIR_OUT; - spin_unlock(&u3d->lock); - if (u3d->driver->setup(&u3d->gadget, - &u3d->local_setup_buff) < 0) { - dev_err(u3d->dev, "setup error!\n"); - mv_u3d_ep0_stall(u3d); - } - spin_lock(&u3d->lock); - } else { - /* no DATA phase, STATUS phase from gadget */ - u3d->ep0_dir = MV_U3D_EP_DIR_IN; - u3d->ep0_state = MV_U3D_STATUS_STAGE; - spin_unlock(&u3d->lock); - if (u3d->driver->setup(&u3d->gadget, - &u3d->local_setup_buff) < 0) - mv_u3d_ep0_stall(u3d); - spin_lock(&u3d->lock); - } - - if (mv_u3d_is_set_configuration(setup)) { - dev_dbg(u3d->dev, "u3d configured\n"); - u3d->usb_state = USB_STATE_CONFIGURED; - } - } -} - -static void mv_u3d_get_setup_data(struct mv_u3d *u3d, u8 ep_num, u8 *buffer_ptr) -{ - struct mv_u3d_ep_context *epcontext; - - epcontext = &u3d->ep_context[ep_num * 2 + MV_U3D_EP_DIR_IN]; - - /* Copy the setup packet to local buffer */ - memcpy(buffer_ptr, (u8 *) &epcontext->setup_buffer, 8); -} - -static void mv_u3d_irq_process_setup(struct mv_u3d *u3d) -{ - u32 tmp, i; - /* Process all Setup packet received interrupts */ - tmp = ioread32(&u3d->vuc_regs->setuplock); - if (tmp) { - for (i = 0; i < u3d->max_eps; i++) { - if (tmp & (1 << i)) { - mv_u3d_get_setup_data(u3d, i, - (u8 *)(&u3d->local_setup_buff)); - mv_u3d_handle_setup_packet(u3d, i, - &u3d->local_setup_buff); - } - } - } - - iowrite32(tmp, &u3d->vuc_regs->setuplock); -} - -static void mv_u3d_irq_process_tr_complete(struct mv_u3d *u3d) -{ - u32 tmp, bit_pos; - int i, ep_num = 0, direction = 0; - struct mv_u3d_ep *curr_ep; - struct mv_u3d_req *curr_req, *temp_req; - int status; - - tmp = ioread32(&u3d->vuc_regs->endcomplete); - - dev_dbg(u3d->dev, "tr_complete: ep: 0x%x\n", tmp); - if (!tmp) - return; - iowrite32(tmp, &u3d->vuc_regs->endcomplete); - - for (i = 0; i < u3d->max_eps * 2; i++) { - ep_num = i >> 1; - direction = i % 2; - - bit_pos = 1 << (ep_num + 16 * direction); - - if (!(bit_pos & tmp)) - continue; - - if (i == 0) - curr_ep = &u3d->eps[1]; - else - curr_ep = &u3d->eps[i]; - - /* remove req out of ep request list after completion */ - dev_dbg(u3d->dev, "tr comp: check req_list\n"); - spin_lock(&curr_ep->req_lock); - if (!list_empty(&curr_ep->req_list)) { - struct mv_u3d_req *req; - req = list_entry(curr_ep->req_list.next, - struct mv_u3d_req, list); - list_del_init(&req->list); - curr_ep->processing = 0; - } - spin_unlock(&curr_ep->req_lock); - - /* process the req queue until an uncomplete request */ - list_for_each_entry_safe(curr_req, temp_req, - &curr_ep->queue, queue) { - status = mv_u3d_process_ep_req(u3d, i, curr_req); - if (status) - break; - /* write back status to req */ - curr_req->req.status = status; - - /* ep0 request completion */ - if (ep_num == 0) { - mv_u3d_done(curr_ep, curr_req, 0); - break; - } else { - mv_u3d_done(curr_ep, curr_req, status); - } - } - - dev_dbg(u3d->dev, "call mv_u3d_start_queue from ep complete\n"); - mv_u3d_start_queue(curr_ep); - } -} - -static irqreturn_t mv_u3d_irq(int irq, void *dev) -{ - struct mv_u3d *u3d = (struct mv_u3d *)dev; - u32 status, intr; - u32 bridgesetting; - u32 trbunderrun; - - spin_lock(&u3d->lock); - - status = ioread32(&u3d->vuc_regs->intrcause); - intr = ioread32(&u3d->vuc_regs->intrenable); - status &= intr; - - if (status == 0) { - spin_unlock(&u3d->lock); - dev_err(u3d->dev, "irq error!\n"); - return IRQ_NONE; - } - - if (status & MV_U3D_USBINT_VBUS_VALID) { - bridgesetting = ioread32(&u3d->vuc_regs->bridgesetting); - if (bridgesetting & MV_U3D_BRIDGE_SETTING_VBUS_VALID) { - /* write vbus valid bit of bridge setting to clear */ - bridgesetting = MV_U3D_BRIDGE_SETTING_VBUS_VALID; - iowrite32(bridgesetting, &u3d->vuc_regs->bridgesetting); - dev_dbg(u3d->dev, "vbus valid\n"); - - u3d->usb_state = USB_STATE_POWERED; - u3d->vbus_valid_detect = 0; - /* if external vbus detect is not supported, - * we handle it here. - */ - if (!u3d->vbus) { - spin_unlock(&u3d->lock); - mv_u3d_vbus_session(&u3d->gadget, 1); - spin_lock(&u3d->lock); - } - } else - dev_err(u3d->dev, "vbus bit is not set\n"); - } - - /* RX data is already in the 16KB FIFO.*/ - if (status & MV_U3D_USBINT_UNDER_RUN) { - trbunderrun = ioread32(&u3d->vuc_regs->trbunderrun); - dev_err(u3d->dev, "under run, ep%d\n", trbunderrun); - iowrite32(trbunderrun, &u3d->vuc_regs->trbunderrun); - mv_u3d_irq_process_error(u3d); - } - - if (status & (MV_U3D_USBINT_RXDESC_ERR | MV_U3D_USBINT_TXDESC_ERR)) { - /* write one to clear */ - iowrite32(status & (MV_U3D_USBINT_RXDESC_ERR - | MV_U3D_USBINT_TXDESC_ERR), - &u3d->vuc_regs->intrcause); - dev_err(u3d->dev, "desc err 0x%x\n", status); - mv_u3d_irq_process_error(u3d); - } - - if (status & MV_U3D_USBINT_LINK_CHG) - mv_u3d_irq_process_link_change(u3d); - - if (status & MV_U3D_USBINT_TX_COMPLETE) - mv_u3d_irq_process_tr_complete(u3d); - - if (status & MV_U3D_USBINT_RX_COMPLETE) - mv_u3d_irq_process_tr_complete(u3d); - - if (status & MV_U3D_USBINT_SETUP) - mv_u3d_irq_process_setup(u3d); - - spin_unlock(&u3d->lock); - return IRQ_HANDLED; -} - -static void mv_u3d_remove(struct platform_device *dev) -{ - struct mv_u3d *u3d = platform_get_drvdata(dev); - - BUG_ON(u3d == NULL); - - usb_del_gadget_udc(&u3d->gadget); - - /* free memory allocated in probe */ - dma_pool_destroy(u3d->trb_pool); - - if (u3d->ep_context) - dma_free_coherent(&dev->dev, u3d->ep_context_size, - u3d->ep_context, u3d->ep_context_dma); - - kfree(u3d->eps); - - if (u3d->irq) - free_irq(u3d->irq, u3d); - - if (u3d->cap_regs) - iounmap(u3d->cap_regs); - u3d->cap_regs = NULL; - - kfree(u3d->status_req); - - clk_put(u3d->clk); - - kfree(u3d); -} - -static int mv_u3d_probe(struct platform_device *dev) -{ - struct mv_u3d *u3d; - struct mv_usb_platform_data *pdata = dev_get_platdata(&dev->dev); - int retval = 0; - struct resource *r; - size_t size; - - if (!dev_get_platdata(&dev->dev)) { - dev_err(&dev->dev, "missing platform_data\n"); - retval = -ENODEV; - goto err_pdata; - } - - u3d = kzalloc(sizeof(*u3d), GFP_KERNEL); - if (!u3d) { - retval = -ENOMEM; - goto err_alloc_private; - } - - spin_lock_init(&u3d->lock); - - platform_set_drvdata(dev, u3d); - - u3d->dev = &dev->dev; - u3d->vbus = pdata->vbus; - - u3d->clk = clk_get(&dev->dev, NULL); - if (IS_ERR(u3d->clk)) { - retval = PTR_ERR(u3d->clk); - goto err_get_clk; - } - - r = platform_get_resource_byname(dev, IORESOURCE_MEM, "capregs"); - if (!r) { - dev_err(&dev->dev, "no I/O memory resource defined\n"); - retval = -ENODEV; - goto err_get_cap_regs; - } - - u3d->cap_regs = (struct mv_u3d_cap_regs __iomem *) - ioremap(r->start, resource_size(r)); - if (!u3d->cap_regs) { - dev_err(&dev->dev, "failed to map I/O memory\n"); - retval = -EBUSY; - goto err_map_cap_regs; - } else { - dev_dbg(&dev->dev, "cap_regs address: 0x%lx/0x%lx\n", - (unsigned long) r->start, - (unsigned long) u3d->cap_regs); - } - - /* we will access controller register, so enable the u3d controller */ - retval = clk_enable(u3d->clk); - if (retval) { - dev_err(&dev->dev, "clk_enable error %d\n", retval); - goto err_u3d_enable; - } - - if (pdata->phy_init) { - retval = pdata->phy_init(u3d->phy_regs); - if (retval) { - dev_err(&dev->dev, "init phy error %d\n", retval); - clk_disable(u3d->clk); - goto err_phy_init; - } - } - - u3d->op_regs = (struct mv_u3d_op_regs __iomem *)(u3d->cap_regs - + MV_U3D_USB3_OP_REGS_OFFSET); - - u3d->vuc_regs = (struct mv_u3d_vuc_regs __iomem *)(u3d->cap_regs - + ioread32(&u3d->cap_regs->vuoff)); - - u3d->max_eps = 16; - - /* - * some platform will use usb to download image, it may not disconnect - * usb gadget before loading kernel. So first stop u3d here. - */ - mv_u3d_controller_stop(u3d); - iowrite32(0xFFFFFFFF, &u3d->vuc_regs->intrcause); - - if (pdata->phy_deinit) - pdata->phy_deinit(u3d->phy_regs); - clk_disable(u3d->clk); - - size = u3d->max_eps * sizeof(struct mv_u3d_ep_context) * 2; - size = (size + MV_U3D_EP_CONTEXT_ALIGNMENT - 1) - & ~(MV_U3D_EP_CONTEXT_ALIGNMENT - 1); - u3d->ep_context = dma_alloc_coherent(&dev->dev, size, - &u3d->ep_context_dma, GFP_KERNEL); - if (!u3d->ep_context) { - dev_err(&dev->dev, "allocate ep context memory failed\n"); - retval = -ENOMEM; - goto err_alloc_ep_context; - } - u3d->ep_context_size = size; - - /* create TRB dma_pool resource */ - u3d->trb_pool = dma_pool_create("u3d_trb", - &dev->dev, - sizeof(struct mv_u3d_trb_hw), - MV_U3D_TRB_ALIGNMENT, - MV_U3D_DMA_BOUNDARY); - - if (!u3d->trb_pool) { - retval = -ENOMEM; - goto err_alloc_trb_pool; - } - - size = u3d->max_eps * sizeof(struct mv_u3d_ep) * 2; - u3d->eps = kzalloc(size, GFP_KERNEL); - if (!u3d->eps) { - retval = -ENOMEM; - goto err_alloc_eps; - } - - /* initialize ep0 status request structure */ - u3d->status_req = kzalloc(sizeof(struct mv_u3d_req) + 8, GFP_KERNEL); - if (!u3d->status_req) { - retval = -ENOMEM; - goto err_alloc_status_req; - } - INIT_LIST_HEAD(&u3d->status_req->queue); - - /* allocate a small amount of memory to get valid address */ - u3d->status_req->req.buf = (char *)u3d->status_req - + sizeof(struct mv_u3d_req); - u3d->status_req->req.dma = virt_to_phys(u3d->status_req->req.buf); - - u3d->resume_state = USB_STATE_NOTATTACHED; - u3d->usb_state = USB_STATE_ATTACHED; - u3d->ep0_dir = MV_U3D_EP_DIR_OUT; - u3d->remote_wakeup = 0; - - r = platform_get_resource(dev, IORESOURCE_IRQ, 0); - if (!r) { - dev_err(&dev->dev, "no IRQ resource defined\n"); - retval = -ENODEV; - goto err_get_irq; - } - u3d->irq = r->start; - - /* initialize gadget structure */ - u3d->gadget.ops = &mv_u3d_ops; /* usb_gadget_ops */ - u3d->gadget.ep0 = &u3d->eps[1].ep; /* gadget ep0 */ - INIT_LIST_HEAD(&u3d->gadget.ep_list); /* ep_list */ - u3d->gadget.speed = USB_SPEED_UNKNOWN; /* speed */ - - /* the "gadget" abstracts/virtualizes the controller */ - u3d->gadget.name = driver_name; /* gadget name */ - - mv_u3d_eps_init(u3d); - - if (request_irq(u3d->irq, mv_u3d_irq, - IRQF_SHARED, driver_name, u3d)) { - u3d->irq = 0; - dev_err(&dev->dev, "Request irq %d for u3d failed\n", - u3d->irq); - retval = -ENODEV; - goto err_request_irq; - } - - /* external vbus detection */ - if (u3d->vbus) { - u3d->clock_gating = 1; - dev_err(&dev->dev, "external vbus detection\n"); - } - - if (!u3d->clock_gating) - u3d->vbus_active = 1; - - /* enable usb3 controller vbus detection */ - u3d->vbus_valid_detect = 1; - - retval = usb_add_gadget_udc(&dev->dev, &u3d->gadget); - if (retval) - goto err_unregister; - - dev_dbg(&dev->dev, "successful probe usb3 device %s clock gating.\n", - u3d->clock_gating ? "with" : "without"); - - return 0; - -err_unregister: - free_irq(u3d->irq, u3d); -err_get_irq: -err_request_irq: - kfree(u3d->status_req); -err_alloc_status_req: - kfree(u3d->eps); -err_alloc_eps: - dma_pool_destroy(u3d->trb_pool); -err_alloc_trb_pool: - dma_free_coherent(&dev->dev, u3d->ep_context_size, - u3d->ep_context, u3d->ep_context_dma); -err_alloc_ep_context: -err_phy_init: -err_u3d_enable: - iounmap(u3d->cap_regs); -err_map_cap_regs: -err_get_cap_regs: - clk_put(u3d->clk); -err_get_clk: - kfree(u3d); -err_alloc_private: -err_pdata: - return retval; -} - -#ifdef CONFIG_PM_SLEEP -static int mv_u3d_suspend(struct device *dev) -{ - struct mv_u3d *u3d = dev_get_drvdata(dev); - - /* - * only cable is unplugged, usb can suspend. - * So do not care about clock_gating == 1, it is handled by - * vbus session. - */ - if (!u3d->clock_gating) { - mv_u3d_controller_stop(u3d); - - spin_lock_irq(&u3d->lock); - /* stop all usb activities */ - mv_u3d_stop_activity(u3d, u3d->driver); - spin_unlock_irq(&u3d->lock); - - mv_u3d_disable(u3d); - } - - return 0; -} - -static int mv_u3d_resume(struct device *dev) -{ - struct mv_u3d *u3d = dev_get_drvdata(dev); - int retval; - - if (!u3d->clock_gating) { - retval = mv_u3d_enable(u3d); - if (retval) - return retval; - - if (u3d->driver && u3d->softconnect) { - mv_u3d_controller_reset(u3d); - mv_u3d_ep0_reset(u3d); - mv_u3d_controller_start(u3d); - } - } - - return 0; -} -#endif - -static SIMPLE_DEV_PM_OPS(mv_u3d_pm_ops, mv_u3d_suspend, mv_u3d_resume); - -static void mv_u3d_shutdown(struct platform_device *dev) -{ - struct mv_u3d *u3d = platform_get_drvdata(dev); - u32 tmp; - - tmp = ioread32(&u3d->op_regs->usbcmd); - tmp &= ~MV_U3D_CMD_RUN_STOP; - iowrite32(tmp, &u3d->op_regs->usbcmd); -} - -static struct platform_driver mv_u3d_driver = { - .probe = mv_u3d_probe, - .remove = mv_u3d_remove, - .shutdown = mv_u3d_shutdown, - .driver = { - .name = "mv-u3d", - .pm = &mv_u3d_pm_ops, - }, -}; - -module_platform_driver(mv_u3d_driver); -MODULE_ALIAS("platform:mv-u3d"); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_AUTHOR("Yu Xu <yuxu@marvell.com>"); -MODULE_LICENSE("GPL"); diff --git a/drivers/usb/gadget/udc/mv_udc.h b/drivers/usb/gadget/udc/mv_udc.h deleted file mode 100644 index b3f759c0962c..000000000000 --- a/drivers/usb/gadget/udc/mv_udc.h +++ /dev/null @@ -1,309 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (C) 2011 Marvell International Ltd. All rights reserved. - */ - -#ifndef __MV_UDC_H -#define __MV_UDC_H - -#define VUSBHS_MAX_PORTS 8 - -#define DQH_ALIGNMENT 2048 -#define DTD_ALIGNMENT 64 -#define DMA_BOUNDARY 4096 - -#define EP_DIR_IN 1 -#define EP_DIR_OUT 0 - -#define DMA_ADDR_INVALID (~(dma_addr_t)0) - -#define EP0_MAX_PKT_SIZE 64 -/* ep0 transfer state */ -#define WAIT_FOR_SETUP 0 -#define DATA_STATE_XMIT 1 -#define DATA_STATE_NEED_ZLP 2 -#define WAIT_FOR_OUT_STATUS 3 -#define DATA_STATE_RECV 4 - -#define CAPLENGTH_MASK (0xff) -#define DCCPARAMS_DEN_MASK (0x1f) - -#define HCSPARAMS_PPC (0x10) - -/* Frame Index Register Bit Masks */ -#define USB_FRINDEX_MASKS 0x3fff - -/* Command Register Bit Masks */ -#define USBCMD_RUN_STOP (0x00000001) -#define USBCMD_CTRL_RESET (0x00000002) -#define USBCMD_SETUP_TRIPWIRE_SET (0x00002000) -#define USBCMD_SETUP_TRIPWIRE_CLEAR (~USBCMD_SETUP_TRIPWIRE_SET) - -#define USBCMD_ATDTW_TRIPWIRE_SET (0x00004000) -#define USBCMD_ATDTW_TRIPWIRE_CLEAR (~USBCMD_ATDTW_TRIPWIRE_SET) - -/* bit 15,3,2 are for frame list size */ -#define USBCMD_FRAME_SIZE_1024 (0x00000000) /* 000 */ -#define USBCMD_FRAME_SIZE_512 (0x00000004) /* 001 */ -#define USBCMD_FRAME_SIZE_256 (0x00000008) /* 010 */ -#define USBCMD_FRAME_SIZE_128 (0x0000000C) /* 011 */ -#define USBCMD_FRAME_SIZE_64 (0x00008000) /* 100 */ -#define USBCMD_FRAME_SIZE_32 (0x00008004) /* 101 */ -#define USBCMD_FRAME_SIZE_16 (0x00008008) /* 110 */ -#define USBCMD_FRAME_SIZE_8 (0x0000800C) /* 111 */ - -#define EPCTRL_TX_ALL_MASK (0xFFFF0000) -#define EPCTRL_RX_ALL_MASK (0x0000FFFF) - -#define EPCTRL_TX_DATA_TOGGLE_RST (0x00400000) -#define EPCTRL_TX_EP_STALL (0x00010000) -#define EPCTRL_RX_EP_STALL (0x00000001) -#define EPCTRL_RX_DATA_TOGGLE_RST (0x00000040) -#define EPCTRL_RX_ENABLE (0x00000080) -#define EPCTRL_TX_ENABLE (0x00800000) -#define EPCTRL_CONTROL (0x00000000) -#define EPCTRL_ISOCHRONOUS (0x00040000) -#define EPCTRL_BULK (0x00080000) -#define EPCTRL_INT (0x000C0000) -#define EPCTRL_TX_TYPE (0x000C0000) -#define EPCTRL_RX_TYPE (0x0000000C) -#define EPCTRL_DATA_TOGGLE_INHIBIT (0x00000020) -#define EPCTRL_TX_EP_TYPE_SHIFT (18) -#define EPCTRL_RX_EP_TYPE_SHIFT (2) - -#define EPCOMPLETE_MAX_ENDPOINTS (16) - -/* endpoint list address bit masks */ -#define USB_EP_LIST_ADDRESS_MASK 0xfffff800 - -#define PORTSCX_W1C_BITS 0x2a -#define PORTSCX_PORT_RESET 0x00000100 -#define PORTSCX_PORT_POWER 0x00001000 -#define PORTSCX_FORCE_FULL_SPEED_CONNECT 0x01000000 -#define PORTSCX_PAR_XCVR_SELECT 0xC0000000 -#define PORTSCX_PORT_FORCE_RESUME 0x00000040 -#define PORTSCX_PORT_SUSPEND 0x00000080 -#define PORTSCX_PORT_SPEED_FULL 0x00000000 -#define PORTSCX_PORT_SPEED_LOW 0x04000000 -#define PORTSCX_PORT_SPEED_HIGH 0x08000000 -#define PORTSCX_PORT_SPEED_MASK 0x0C000000 - -/* USB MODE Register Bit Masks */ -#define USBMODE_CTRL_MODE_IDLE 0x00000000 -#define USBMODE_CTRL_MODE_DEVICE 0x00000002 -#define USBMODE_CTRL_MODE_HOST 0x00000003 -#define USBMODE_CTRL_MODE_RSV 0x00000001 -#define USBMODE_SETUP_LOCK_OFF 0x00000008 -#define USBMODE_STREAM_DISABLE 0x00000010 - -/* USB STS Register Bit Masks */ -#define USBSTS_INT 0x00000001 -#define USBSTS_ERR 0x00000002 -#define USBSTS_PORT_CHANGE 0x00000004 -#define USBSTS_FRM_LST_ROLL 0x00000008 -#define USBSTS_SYS_ERR 0x00000010 -#define USBSTS_IAA 0x00000020 -#define USBSTS_RESET 0x00000040 -#define USBSTS_SOF 0x00000080 -#define USBSTS_SUSPEND 0x00000100 -#define USBSTS_HC_HALTED 0x00001000 -#define USBSTS_RCL 0x00002000 -#define USBSTS_PERIODIC_SCHEDULE 0x00004000 -#define USBSTS_ASYNC_SCHEDULE 0x00008000 - - -/* Interrupt Enable Register Bit Masks */ -#define USBINTR_INT_EN (0x00000001) -#define USBINTR_ERR_INT_EN (0x00000002) -#define USBINTR_PORT_CHANGE_DETECT_EN (0x00000004) - -#define USBINTR_ASYNC_ADV_AAE (0x00000020) -#define USBINTR_ASYNC_ADV_AAE_ENABLE (0x00000020) -#define USBINTR_ASYNC_ADV_AAE_DISABLE (0xFFFFFFDF) - -#define USBINTR_RESET_EN (0x00000040) -#define USBINTR_SOF_UFRAME_EN (0x00000080) -#define USBINTR_DEVICE_SUSPEND (0x00000100) - -#define USB_DEVICE_ADDRESS_MASK (0xfe000000) -#define USB_DEVICE_ADDRESS_BIT_SHIFT (25) - -struct mv_cap_regs { - u32 caplength_hciversion; - u32 hcsparams; /* HC structural parameters */ - u32 hccparams; /* HC Capability Parameters*/ - u32 reserved[5]; - u32 dciversion; /* DC version number and reserved 16 bits */ - u32 dccparams; /* DC Capability Parameters */ -}; - -struct mv_op_regs { - u32 usbcmd; /* Command register */ - u32 usbsts; /* Status register */ - u32 usbintr; /* Interrupt enable */ - u32 frindex; /* Frame index */ - u32 reserved1[1]; - u32 deviceaddr; /* Device Address */ - u32 eplistaddr; /* Endpoint List Address */ - u32 ttctrl; /* HOST TT status and control */ - u32 burstsize; /* Programmable Burst Size */ - u32 txfilltuning; /* Host Transmit Pre-Buffer Packet Tuning */ - u32 reserved[4]; - u32 epnak; /* Endpoint NAK */ - u32 epnaken; /* Endpoint NAK Enable */ - u32 configflag; /* Configured Flag register */ - u32 portsc[VUSBHS_MAX_PORTS]; /* Port Status/Control x, x = 1..8 */ - u32 otgsc; - u32 usbmode; /* USB Host/Device mode */ - u32 epsetupstat; /* Endpoint Setup Status */ - u32 epprime; /* Endpoint Initialize */ - u32 epflush; /* Endpoint De-initialize */ - u32 epstatus; /* Endpoint Status */ - u32 epcomplete; /* Endpoint Interrupt On Complete */ - u32 epctrlx[16]; /* Endpoint Control, where x = 0.. 15 */ - u32 mcr; /* Mux Control */ - u32 isr; /* Interrupt Status */ - u32 ier; /* Interrupt Enable */ -}; - -struct mv_udc { - struct usb_gadget gadget; - struct usb_gadget_driver *driver; - spinlock_t lock; - struct completion *done; - struct platform_device *dev; - int irq; - - struct mv_cap_regs __iomem *cap_regs; - struct mv_op_regs __iomem *op_regs; - void __iomem *phy_regs; - unsigned int max_eps; - struct mv_dqh *ep_dqh; - size_t ep_dqh_size; - dma_addr_t ep_dqh_dma; - - struct dma_pool *dtd_pool; - struct mv_ep *eps; - - struct mv_dtd *dtd_head; - struct mv_dtd *dtd_tail; - unsigned int dtd_entries; - - struct mv_req *status_req; - struct usb_ctrlrequest local_setup_buff; - - unsigned int resume_state; /* USB state to resume */ - unsigned int usb_state; /* USB current state */ - unsigned int ep0_state; /* Endpoint zero state */ - unsigned int ep0_dir; - - unsigned int dev_addr; - unsigned int test_mode; - - int errors; - unsigned softconnect:1, - vbus_active:1, - remote_wakeup:1, - softconnected:1, - force_fs:1, - clock_gating:1, - active:1, - stopped:1; /* stop bit is setted */ - - struct work_struct vbus_work; - struct workqueue_struct *qwork; - - struct usb_phy *transceiver; - - struct mv_usb_platform_data *pdata; - - /* some SOC has mutiple clock sources for USB*/ - struct clk *clk; -}; - -/* endpoint data structure */ -struct mv_ep { - struct usb_ep ep; - struct mv_udc *udc; - struct list_head queue; - struct mv_dqh *dqh; - u32 direction; - char name[14]; - unsigned stopped:1, - wedge:1, - ep_type:2, - ep_num:8; -}; - -/* request data structure */ -struct mv_req { - struct usb_request req; - struct mv_dtd *dtd, *head, *tail; - struct mv_ep *ep; - struct list_head queue; - unsigned int test_mode; - unsigned dtd_count; - unsigned mapped:1; -}; - -#define EP_QUEUE_HEAD_MULT_POS 30 -#define EP_QUEUE_HEAD_ZLT_SEL 0x20000000 -#define EP_QUEUE_HEAD_MAX_PKT_LEN_POS 16 -#define EP_QUEUE_HEAD_MAX_PKT_LEN(ep_info) (((ep_info)>>16)&0x07ff) -#define EP_QUEUE_HEAD_IOS 0x00008000 -#define EP_QUEUE_HEAD_NEXT_TERMINATE 0x00000001 -#define EP_QUEUE_HEAD_IOC 0x00008000 -#define EP_QUEUE_HEAD_MULTO 0x00000C00 -#define EP_QUEUE_HEAD_STATUS_HALT 0x00000040 -#define EP_QUEUE_HEAD_STATUS_ACTIVE 0x00000080 -#define EP_QUEUE_CURRENT_OFFSET_MASK 0x00000FFF -#define EP_QUEUE_HEAD_NEXT_POINTER_MASK 0xFFFFFFE0 -#define EP_QUEUE_FRINDEX_MASK 0x000007FF -#define EP_MAX_LENGTH_TRANSFER 0x4000 - -struct mv_dqh { - /* Bits 16..26 Bit 15 is Interrupt On Setup */ - u32 max_packet_length; - u32 curr_dtd_ptr; /* Current dTD Pointer */ - u32 next_dtd_ptr; /* Next dTD Pointer */ - /* Total bytes (16..30), IOC (15), INT (8), STS (0-7) */ - u32 size_ioc_int_sts; - u32 buff_ptr0; /* Buffer pointer Page 0 (12-31) */ - u32 buff_ptr1; /* Buffer pointer Page 1 (12-31) */ - u32 buff_ptr2; /* Buffer pointer Page 2 (12-31) */ - u32 buff_ptr3; /* Buffer pointer Page 3 (12-31) */ - u32 buff_ptr4; /* Buffer pointer Page 4 (12-31) */ - u32 reserved1; - /* 8 bytes of setup data that follows the Setup PID */ - u8 setup_buffer[8]; - u32 reserved2[4]; -}; - - -#define DTD_NEXT_TERMINATE (0x00000001) -#define DTD_IOC (0x00008000) -#define DTD_STATUS_ACTIVE (0x00000080) -#define DTD_STATUS_HALTED (0x00000040) -#define DTD_STATUS_DATA_BUFF_ERR (0x00000020) -#define DTD_STATUS_TRANSACTION_ERR (0x00000008) -#define DTD_RESERVED_FIELDS (0x00007F00) -#define DTD_ERROR_MASK (0x68) -#define DTD_ADDR_MASK (0xFFFFFFE0) -#define DTD_PACKET_SIZE 0x7FFF0000 -#define DTD_LENGTH_BIT_POS (16) - -struct mv_dtd { - u32 dtd_next; - u32 size_ioc_sts; - u32 buff_ptr0; /* Buffer pointer Page 0 */ - u32 buff_ptr1; /* Buffer pointer Page 1 */ - u32 buff_ptr2; /* Buffer pointer Page 2 */ - u32 buff_ptr3; /* Buffer pointer Page 3 */ - u32 buff_ptr4; /* Buffer pointer Page 4 */ - u32 scratch_ptr; - /* 32 bytes */ - dma_addr_t td_dma; /* dma address for this td */ - struct mv_dtd *next_dtd_virt; -}; - -#endif diff --git a/drivers/usb/gadget/udc/mv_udc_core.c b/drivers/usb/gadget/udc/mv_udc_core.c deleted file mode 100644 index ff103e6b3048..000000000000 --- a/drivers/usb/gadget/udc/mv_udc_core.c +++ /dev/null @@ -1,2426 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (C) 2011 Marvell International Ltd. All rights reserved. - * Author: Chao Xie <chao.xie@marvell.com> - * Neil Zhang <zhangwm@marvell.com> - */ - -#include <linux/module.h> -#include <linux/pci.h> -#include <linux/dma-mapping.h> -#include <linux/dmapool.h> -#include <linux/kernel.h> -#include <linux/delay.h> -#include <linux/ioport.h> -#include <linux/sched.h> -#include <linux/slab.h> -#include <linux/errno.h> -#include <linux/err.h> -#include <linux/timer.h> -#include <linux/list.h> -#include <linux/interrupt.h> -#include <linux/moduleparam.h> -#include <linux/device.h> -#include <linux/usb/ch9.h> -#include <linux/usb/gadget.h> -#include <linux/usb/otg.h> -#include <linux/pm.h> -#include <linux/io.h> -#include <linux/irq.h> -#include <linux/platform_device.h> -#include <linux/clk.h> -#include <linux/platform_data/mv_usb.h> -#include <linux/unaligned.h> - -#include "mv_udc.h" - -#define DRIVER_DESC "Marvell PXA USB Device Controller driver" - -#define ep_dir(ep) (((ep)->ep_num == 0) ? \ - ((ep)->udc->ep0_dir) : ((ep)->direction)) - -/* timeout value -- usec */ -#define RESET_TIMEOUT 10000 -#define FLUSH_TIMEOUT 10000 -#define EPSTATUS_TIMEOUT 10000 -#define PRIME_TIMEOUT 10000 -#define READSAFE_TIMEOUT 1000 - -#define LOOPS_USEC_SHIFT 1 -#define LOOPS_USEC (1 << LOOPS_USEC_SHIFT) -#define LOOPS(timeout) ((timeout) >> LOOPS_USEC_SHIFT) - -static DECLARE_COMPLETION(release_done); - -static const char driver_name[] = "mv_udc"; - -static void nuke(struct mv_ep *ep, int status); -static void stop_activity(struct mv_udc *udc, struct usb_gadget_driver *driver); - -/* for endpoint 0 operations */ -static const struct usb_endpoint_descriptor mv_ep0_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = 0, - .bmAttributes = USB_ENDPOINT_XFER_CONTROL, - .wMaxPacketSize = EP0_MAX_PKT_SIZE, -}; - -static void ep0_reset(struct mv_udc *udc) -{ - struct mv_ep *ep; - u32 epctrlx; - int i = 0; - - /* ep0 in and out */ - for (i = 0; i < 2; i++) { - ep = &udc->eps[i]; - ep->udc = udc; - - /* ep0 dQH */ - ep->dqh = &udc->ep_dqh[i]; - - /* configure ep0 endpoint capabilities in dQH */ - ep->dqh->max_packet_length = - (EP0_MAX_PKT_SIZE << EP_QUEUE_HEAD_MAX_PKT_LEN_POS) - | EP_QUEUE_HEAD_IOS; - - ep->dqh->next_dtd_ptr = EP_QUEUE_HEAD_NEXT_TERMINATE; - - epctrlx = readl(&udc->op_regs->epctrlx[0]); - if (i) { /* TX */ - epctrlx |= EPCTRL_TX_ENABLE - | (USB_ENDPOINT_XFER_CONTROL - << EPCTRL_TX_EP_TYPE_SHIFT); - - } else { /* RX */ - epctrlx |= EPCTRL_RX_ENABLE - | (USB_ENDPOINT_XFER_CONTROL - << EPCTRL_RX_EP_TYPE_SHIFT); - } - - writel(epctrlx, &udc->op_regs->epctrlx[0]); - } -} - -/* protocol ep0 stall, will automatically be cleared on new transaction */ -static void ep0_stall(struct mv_udc *udc) -{ - u32 epctrlx; - - /* set TX and RX to stall */ - epctrlx = readl(&udc->op_regs->epctrlx[0]); - epctrlx |= EPCTRL_RX_EP_STALL | EPCTRL_TX_EP_STALL; - writel(epctrlx, &udc->op_regs->epctrlx[0]); - - /* update ep0 state */ - udc->ep0_state = WAIT_FOR_SETUP; - udc->ep0_dir = EP_DIR_OUT; -} - -static int process_ep_req(struct mv_udc *udc, int index, - struct mv_req *curr_req) -{ - struct mv_dtd *curr_dtd; - struct mv_dqh *curr_dqh; - int actual, remaining_length; - int i, direction; - int retval = 0; - u32 errors; - u32 bit_pos; - - curr_dqh = &udc->ep_dqh[index]; - direction = index % 2; - - curr_dtd = curr_req->head; - actual = curr_req->req.length; - - for (i = 0; i < curr_req->dtd_count; i++) { - if (curr_dtd->size_ioc_sts & DTD_STATUS_ACTIVE) { - dev_dbg(&udc->dev->dev, "%s, dTD not completed\n", - udc->eps[index].name); - return 1; - } - - errors = curr_dtd->size_ioc_sts & DTD_ERROR_MASK; - if (!errors) { - remaining_length = - (curr_dtd->size_ioc_sts & DTD_PACKET_SIZE) - >> DTD_LENGTH_BIT_POS; - actual -= remaining_length; - - if (remaining_length) { - if (direction) { - dev_dbg(&udc->dev->dev, - "TX dTD remains data\n"); - retval = -EPROTO; - break; - } else - break; - } - } else { - dev_info(&udc->dev->dev, - "complete_tr error: ep=%d %s: error = 0x%x\n", - index >> 1, direction ? "SEND" : "RECV", - errors); - if (errors & DTD_STATUS_HALTED) { - /* Clear the errors and Halt condition */ - curr_dqh->size_ioc_int_sts &= ~errors; - retval = -EPIPE; - } else if (errors & DTD_STATUS_DATA_BUFF_ERR) { - retval = -EPROTO; - } else if (errors & DTD_STATUS_TRANSACTION_ERR) { - retval = -EILSEQ; - } - } - if (i != curr_req->dtd_count - 1) - curr_dtd = (struct mv_dtd *)curr_dtd->next_dtd_virt; - } - if (retval) - return retval; - - if (direction == EP_DIR_OUT) - bit_pos = 1 << curr_req->ep->ep_num; - else - bit_pos = 1 << (16 + curr_req->ep->ep_num); - - while (curr_dqh->curr_dtd_ptr == curr_dtd->td_dma) { - if (curr_dtd->dtd_next == EP_QUEUE_HEAD_NEXT_TERMINATE) { - while (readl(&udc->op_regs->epstatus) & bit_pos) - udelay(1); - break; - } - udelay(1); - } - - curr_req->req.actual = actual; - - return 0; -} - -/* - * done() - retire a request; caller blocked irqs - * @status : request status to be set, only works when - * request is still in progress. - */ -static void done(struct mv_ep *ep, struct mv_req *req, int status) - __releases(&ep->udc->lock) - __acquires(&ep->udc->lock) -{ - struct mv_udc *udc = NULL; - unsigned char stopped = ep->stopped; - struct mv_dtd *curr_td, *next_td; - int j; - - udc = (struct mv_udc *)ep->udc; - /* Removed the req from fsl_ep->queue */ - list_del_init(&req->queue); - - /* req.status should be set as -EINPROGRESS in ep_queue() */ - if (req->req.status == -EINPROGRESS) - req->req.status = status; - else - status = req->req.status; - - /* Free dtd for the request */ - next_td = req->head; - for (j = 0; j < req->dtd_count; j++) { - curr_td = next_td; - if (j != req->dtd_count - 1) - next_td = curr_td->next_dtd_virt; - dma_pool_free(udc->dtd_pool, curr_td, curr_td->td_dma); - } - - usb_gadget_unmap_request(&udc->gadget, &req->req, ep_dir(ep)); - - if (status && (status != -ESHUTDOWN)) - dev_info(&udc->dev->dev, "complete %s req %p stat %d len %u/%u", - ep->ep.name, &req->req, status, - req->req.actual, req->req.length); - - ep->stopped = 1; - - spin_unlock(&ep->udc->lock); - - usb_gadget_giveback_request(&ep->ep, &req->req); - - spin_lock(&ep->udc->lock); - ep->stopped = stopped; -} - -static int queue_dtd(struct mv_ep *ep, struct mv_req *req) -{ - struct mv_udc *udc; - struct mv_dqh *dqh; - u32 bit_pos, direction; - u32 usbcmd, epstatus; - unsigned int loops; - int retval = 0; - - udc = ep->udc; - direction = ep_dir(ep); - dqh = &(udc->ep_dqh[ep->ep_num * 2 + direction]); - bit_pos = 1 << (((direction == EP_DIR_OUT) ? 0 : 16) + ep->ep_num); - - /* check if the pipe is empty */ - if (!(list_empty(&ep->queue))) { - struct mv_req *lastreq; - lastreq = list_entry(ep->queue.prev, struct mv_req, queue); - lastreq->tail->dtd_next = - req->head->td_dma & EP_QUEUE_HEAD_NEXT_POINTER_MASK; - - wmb(); - - if (readl(&udc->op_regs->epprime) & bit_pos) - goto done; - - loops = LOOPS(READSAFE_TIMEOUT); - while (1) { - /* start with setting the semaphores */ - usbcmd = readl(&udc->op_regs->usbcmd); - usbcmd |= USBCMD_ATDTW_TRIPWIRE_SET; - writel(usbcmd, &udc->op_regs->usbcmd); - - /* read the endpoint status */ - epstatus = readl(&udc->op_regs->epstatus) & bit_pos; - - /* - * Reread the ATDTW semaphore bit to check if it is - * cleared. When hardware see a hazard, it will clear - * the bit or else we remain set to 1 and we can - * proceed with priming of endpoint if not already - * primed. - */ - if (readl(&udc->op_regs->usbcmd) - & USBCMD_ATDTW_TRIPWIRE_SET) - break; - - loops--; - if (loops == 0) { - dev_err(&udc->dev->dev, - "Timeout for ATDTW_TRIPWIRE...\n"); - retval = -ETIME; - goto done; - } - udelay(LOOPS_USEC); - } - - /* Clear the semaphore */ - usbcmd = readl(&udc->op_regs->usbcmd); - usbcmd &= USBCMD_ATDTW_TRIPWIRE_CLEAR; - writel(usbcmd, &udc->op_regs->usbcmd); - - if (epstatus) - goto done; - } - - /* Write dQH next pointer and terminate bit to 0 */ - dqh->next_dtd_ptr = req->head->td_dma - & EP_QUEUE_HEAD_NEXT_POINTER_MASK; - - /* clear active and halt bit, in case set from a previous error */ - dqh->size_ioc_int_sts &= ~(DTD_STATUS_ACTIVE | DTD_STATUS_HALTED); - - /* Ensure that updates to the QH will occur before priming. */ - wmb(); - - /* Prime the Endpoint */ - writel(bit_pos, &udc->op_regs->epprime); - -done: - return retval; -} - -static struct mv_dtd *build_dtd(struct mv_req *req, unsigned *length, - dma_addr_t *dma, int *is_last) -{ - struct mv_dtd *dtd; - struct mv_udc *udc; - struct mv_dqh *dqh; - u32 temp, mult = 0; - - /* how big will this transfer be? */ - if (usb_endpoint_xfer_isoc(req->ep->ep.desc)) { - dqh = req->ep->dqh; - mult = (dqh->max_packet_length >> EP_QUEUE_HEAD_MULT_POS) - & 0x3; - *length = min(req->req.length - req->req.actual, - (unsigned)(mult * req->ep->ep.maxpacket)); - } else - *length = min(req->req.length - req->req.actual, - (unsigned)EP_MAX_LENGTH_TRANSFER); - - udc = req->ep->udc; - - /* - * Be careful that no _GFP_HIGHMEM is set, - * or we can not use dma_to_virt - */ - dtd = dma_pool_alloc(udc->dtd_pool, GFP_ATOMIC, dma); - if (dtd == NULL) - return dtd; - - dtd->td_dma = *dma; - /* initialize buffer page pointers */ - temp = (u32)(req->req.dma + req->req.actual); - dtd->buff_ptr0 = cpu_to_le32(temp); - temp &= ~0xFFF; - dtd->buff_ptr1 = cpu_to_le32(temp + 0x1000); - dtd->buff_ptr2 = cpu_to_le32(temp + 0x2000); - dtd->buff_ptr3 = cpu_to_le32(temp + 0x3000); - dtd->buff_ptr4 = cpu_to_le32(temp + 0x4000); - - req->req.actual += *length; - - /* zlp is needed if req->req.zero is set */ - if (req->req.zero) { - if (*length == 0 || (*length % req->ep->ep.maxpacket) != 0) - *is_last = 1; - else - *is_last = 0; - } else if (req->req.length == req->req.actual) - *is_last = 1; - else - *is_last = 0; - - /* Fill in the transfer size; set active bit */ - temp = ((*length << DTD_LENGTH_BIT_POS) | DTD_STATUS_ACTIVE); - - /* Enable interrupt for the last dtd of a request */ - if (*is_last && !req->req.no_interrupt) - temp |= DTD_IOC; - - temp |= mult << 10; - - dtd->size_ioc_sts = temp; - - mb(); - - return dtd; -} - -/* generate dTD linked list for a request */ -static int req_to_dtd(struct mv_req *req) -{ - unsigned count; - int is_last, is_first = 1; - struct mv_dtd *dtd, *last_dtd = NULL; - dma_addr_t dma; - - do { - dtd = build_dtd(req, &count, &dma, &is_last); - if (dtd == NULL) - return -ENOMEM; - - if (is_first) { - is_first = 0; - req->head = dtd; - } else { - last_dtd->dtd_next = dma; - last_dtd->next_dtd_virt = dtd; - } - last_dtd = dtd; - req->dtd_count++; - } while (!is_last); - - /* set terminate bit to 1 for the last dTD */ - dtd->dtd_next = DTD_NEXT_TERMINATE; - - req->tail = dtd; - - return 0; -} - -static int mv_ep_enable(struct usb_ep *_ep, - const struct usb_endpoint_descriptor *desc) -{ - struct mv_udc *udc; - struct mv_ep *ep; - struct mv_dqh *dqh; - u16 max = 0; - u32 bit_pos, epctrlx, direction; - const unsigned char zlt = 1; - unsigned char ios, mult; - unsigned long flags; - - ep = container_of(_ep, struct mv_ep, ep); - udc = ep->udc; - - if (!_ep || !desc - || desc->bDescriptorType != USB_DT_ENDPOINT) - return -EINVAL; - - if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN) - return -ESHUTDOWN; - - direction = ep_dir(ep); - max = usb_endpoint_maxp(desc); - - /* - * disable HW zero length termination select - * driver handles zero length packet through req->req.zero - */ - bit_pos = 1 << ((direction == EP_DIR_OUT ? 0 : 16) + ep->ep_num); - - /* Check if the Endpoint is Primed */ - if ((readl(&udc->op_regs->epprime) & bit_pos) - || (readl(&udc->op_regs->epstatus) & bit_pos)) { - dev_info(&udc->dev->dev, - "ep=%d %s: Init ERROR: ENDPTPRIME=0x%x," - " ENDPTSTATUS=0x%x, bit_pos=0x%x\n", - (unsigned)ep->ep_num, direction ? "SEND" : "RECV", - (unsigned)readl(&udc->op_regs->epprime), - (unsigned)readl(&udc->op_regs->epstatus), - (unsigned)bit_pos); - goto en_done; - } - - /* Set the max packet length, interrupt on Setup and Mult fields */ - ios = 0; - mult = 0; - switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { - case USB_ENDPOINT_XFER_BULK: - case USB_ENDPOINT_XFER_INT: - break; - case USB_ENDPOINT_XFER_CONTROL: - ios = 1; - break; - case USB_ENDPOINT_XFER_ISOC: - /* Calculate transactions needed for high bandwidth iso */ - mult = usb_endpoint_maxp_mult(desc); - /* 3 transactions at most */ - if (mult > 3) - goto en_done; - break; - default: - goto en_done; - } - - spin_lock_irqsave(&udc->lock, flags); - /* Get the endpoint queue head address */ - dqh = ep->dqh; - dqh->max_packet_length = (max << EP_QUEUE_HEAD_MAX_PKT_LEN_POS) - | (mult << EP_QUEUE_HEAD_MULT_POS) - | (zlt ? EP_QUEUE_HEAD_ZLT_SEL : 0) - | (ios ? EP_QUEUE_HEAD_IOS : 0); - dqh->next_dtd_ptr = 1; - dqh->size_ioc_int_sts = 0; - - ep->ep.maxpacket = max; - ep->ep.desc = desc; - ep->stopped = 0; - - /* Enable the endpoint for Rx or Tx and set the endpoint type */ - epctrlx = readl(&udc->op_regs->epctrlx[ep->ep_num]); - if (direction == EP_DIR_IN) { - epctrlx &= ~EPCTRL_TX_ALL_MASK; - epctrlx |= EPCTRL_TX_ENABLE | EPCTRL_TX_DATA_TOGGLE_RST - | ((desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) - << EPCTRL_TX_EP_TYPE_SHIFT); - } else { - epctrlx &= ~EPCTRL_RX_ALL_MASK; - epctrlx |= EPCTRL_RX_ENABLE | EPCTRL_RX_DATA_TOGGLE_RST - | ((desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) - << EPCTRL_RX_EP_TYPE_SHIFT); - } - writel(epctrlx, &udc->op_regs->epctrlx[ep->ep_num]); - - /* - * Implement Guideline (GL# USB-7) The unused endpoint type must - * be programmed to bulk. - */ - epctrlx = readl(&udc->op_regs->epctrlx[ep->ep_num]); - if ((epctrlx & EPCTRL_RX_ENABLE) == 0) { - epctrlx |= (USB_ENDPOINT_XFER_BULK - << EPCTRL_RX_EP_TYPE_SHIFT); - writel(epctrlx, &udc->op_regs->epctrlx[ep->ep_num]); - } - - epctrlx = readl(&udc->op_regs->epctrlx[ep->ep_num]); - if ((epctrlx & EPCTRL_TX_ENABLE) == 0) { - epctrlx |= (USB_ENDPOINT_XFER_BULK - << EPCTRL_TX_EP_TYPE_SHIFT); - writel(epctrlx, &udc->op_regs->epctrlx[ep->ep_num]); - } - - spin_unlock_irqrestore(&udc->lock, flags); - - return 0; -en_done: - return -EINVAL; -} - -static int mv_ep_disable(struct usb_ep *_ep) -{ - struct mv_udc *udc; - struct mv_ep *ep; - struct mv_dqh *dqh; - u32 epctrlx, direction; - unsigned long flags; - - ep = container_of(_ep, struct mv_ep, ep); - if ((_ep == NULL) || !ep->ep.desc) - return -EINVAL; - - udc = ep->udc; - - /* Get the endpoint queue head address */ - dqh = ep->dqh; - - spin_lock_irqsave(&udc->lock, flags); - - direction = ep_dir(ep); - - /* Reset the max packet length and the interrupt on Setup */ - dqh->max_packet_length = 0; - - /* Disable the endpoint for Rx or Tx and reset the endpoint type */ - epctrlx = readl(&udc->op_regs->epctrlx[ep->ep_num]); - epctrlx &= ~((direction == EP_DIR_IN) - ? (EPCTRL_TX_ENABLE | EPCTRL_TX_TYPE) - : (EPCTRL_RX_ENABLE | EPCTRL_RX_TYPE)); - writel(epctrlx, &udc->op_regs->epctrlx[ep->ep_num]); - - /* nuke all pending requests (does flush) */ - nuke(ep, -ESHUTDOWN); - - ep->ep.desc = NULL; - ep->stopped = 1; - - spin_unlock_irqrestore(&udc->lock, flags); - - return 0; -} - -static struct usb_request * -mv_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags) -{ - struct mv_req *req; - - req = kzalloc(sizeof *req, gfp_flags); - if (!req) - return NULL; - - req->req.dma = DMA_ADDR_INVALID; - INIT_LIST_HEAD(&req->queue); - - return &req->req; -} - -static void mv_free_request(struct usb_ep *_ep, struct usb_request *_req) -{ - struct mv_req *req = NULL; - - req = container_of(_req, struct mv_req, req); - - if (_req) - kfree(req); -} - -static void mv_ep_fifo_flush(struct usb_ep *_ep) -{ - struct mv_udc *udc; - u32 bit_pos, direction; - struct mv_ep *ep; - unsigned int loops; - - if (!_ep) - return; - - ep = container_of(_ep, struct mv_ep, ep); - if (!ep->ep.desc) - return; - - udc = ep->udc; - direction = ep_dir(ep); - - if (ep->ep_num == 0) - bit_pos = (1 << 16) | 1; - else if (direction == EP_DIR_OUT) - bit_pos = 1 << ep->ep_num; - else - bit_pos = 1 << (16 + ep->ep_num); - - loops = LOOPS(EPSTATUS_TIMEOUT); - do { - unsigned int inter_loops; - - if (loops == 0) { - dev_err(&udc->dev->dev, - "TIMEOUT for ENDPTSTATUS=0x%x, bit_pos=0x%x\n", - (unsigned)readl(&udc->op_regs->epstatus), - (unsigned)bit_pos); - return; - } - /* Write 1 to the Flush register */ - writel(bit_pos, &udc->op_regs->epflush); - - /* Wait until flushing completed */ - inter_loops = LOOPS(FLUSH_TIMEOUT); - while (readl(&udc->op_regs->epflush)) { - /* - * ENDPTFLUSH bit should be cleared to indicate this - * operation is complete - */ - if (inter_loops == 0) { - dev_err(&udc->dev->dev, - "TIMEOUT for ENDPTFLUSH=0x%x," - "bit_pos=0x%x\n", - (unsigned)readl(&udc->op_regs->epflush), - (unsigned)bit_pos); - return; - } - inter_loops--; - udelay(LOOPS_USEC); - } - loops--; - } while (readl(&udc->op_regs->epstatus) & bit_pos); -} - -/* queues (submits) an I/O request to an endpoint */ -static int -mv_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) -{ - struct mv_ep *ep = container_of(_ep, struct mv_ep, ep); - struct mv_req *req = container_of(_req, struct mv_req, req); - struct mv_udc *udc = ep->udc; - unsigned long flags; - int retval; - - /* catch various bogus parameters */ - if (!_req || !req->req.complete || !req->req.buf - || !list_empty(&req->queue)) { - dev_err(&udc->dev->dev, "%s, bad params", __func__); - return -EINVAL; - } - if (unlikely(!_ep || !ep->ep.desc)) { - dev_err(&udc->dev->dev, "%s, bad ep", __func__); - return -EINVAL; - } - - udc = ep->udc; - if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN) - return -ESHUTDOWN; - - req->ep = ep; - - /* map virtual address to hardware */ - retval = usb_gadget_map_request(&udc->gadget, _req, ep_dir(ep)); - if (retval) - return retval; - - req->req.status = -EINPROGRESS; - req->req.actual = 0; - req->dtd_count = 0; - - spin_lock_irqsave(&udc->lock, flags); - - /* build dtds and push them to device queue */ - if (!req_to_dtd(req)) { - retval = queue_dtd(ep, req); - if (retval) { - spin_unlock_irqrestore(&udc->lock, flags); - dev_err(&udc->dev->dev, "Failed to queue dtd\n"); - goto err_unmap_dma; - } - } else { - spin_unlock_irqrestore(&udc->lock, flags); - dev_err(&udc->dev->dev, "Failed to dma_pool_alloc\n"); - retval = -ENOMEM; - goto err_unmap_dma; - } - - /* Update ep0 state */ - if (ep->ep_num == 0) - udc->ep0_state = DATA_STATE_XMIT; - - /* irq handler advances the queue */ - list_add_tail(&req->queue, &ep->queue); - spin_unlock_irqrestore(&udc->lock, flags); - - return 0; - -err_unmap_dma: - usb_gadget_unmap_request(&udc->gadget, _req, ep_dir(ep)); - - return retval; -} - -static void mv_prime_ep(struct mv_ep *ep, struct mv_req *req) -{ - struct mv_dqh *dqh = ep->dqh; - u32 bit_pos; - - /* Write dQH next pointer and terminate bit to 0 */ - dqh->next_dtd_ptr = req->head->td_dma - & EP_QUEUE_HEAD_NEXT_POINTER_MASK; - - /* clear active and halt bit, in case set from a previous error */ - dqh->size_ioc_int_sts &= ~(DTD_STATUS_ACTIVE | DTD_STATUS_HALTED); - - /* Ensure that updates to the QH will occure before priming. */ - wmb(); - - bit_pos = 1 << (((ep_dir(ep) == EP_DIR_OUT) ? 0 : 16) + ep->ep_num); - - /* Prime the Endpoint */ - writel(bit_pos, &ep->udc->op_regs->epprime); -} - -/* dequeues (cancels, unlinks) an I/O request from an endpoint */ -static int mv_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) -{ - struct mv_ep *ep = container_of(_ep, struct mv_ep, ep); - struct mv_req *req = NULL, *iter; - struct mv_udc *udc = ep->udc; - unsigned long flags; - int stopped, ret = 0; - u32 epctrlx; - - if (!_ep || !_req) - return -EINVAL; - - spin_lock_irqsave(&ep->udc->lock, flags); - stopped = ep->stopped; - - /* Stop the ep before we deal with the queue */ - ep->stopped = 1; - epctrlx = readl(&udc->op_regs->epctrlx[ep->ep_num]); - if (ep_dir(ep) == EP_DIR_IN) - epctrlx &= ~EPCTRL_TX_ENABLE; - else - epctrlx &= ~EPCTRL_RX_ENABLE; - writel(epctrlx, &udc->op_regs->epctrlx[ep->ep_num]); - - /* make sure it's actually queued on this endpoint */ - list_for_each_entry(iter, &ep->queue, queue) { - if (&iter->req != _req) - continue; - req = iter; - break; - } - if (!req) { - ret = -EINVAL; - goto out; - } - - /* The request is in progress, or completed but not dequeued */ - if (ep->queue.next == &req->queue) { - _req->status = -ECONNRESET; - mv_ep_fifo_flush(_ep); /* flush current transfer */ - - /* The request isn't the last request in this ep queue */ - if (req->queue.next != &ep->queue) { - struct mv_req *next_req; - - next_req = list_entry(req->queue.next, - struct mv_req, queue); - - /* Point the QH to the first TD of next request */ - mv_prime_ep(ep, next_req); - } else { - struct mv_dqh *qh; - - qh = ep->dqh; - qh->next_dtd_ptr = 1; - qh->size_ioc_int_sts = 0; - } - - /* The request hasn't been processed, patch up the TD chain */ - } else { - struct mv_req *prev_req; - - prev_req = list_entry(req->queue.prev, struct mv_req, queue); - writel(readl(&req->tail->dtd_next), - &prev_req->tail->dtd_next); - - } - - done(ep, req, -ECONNRESET); - - /* Enable EP */ -out: - epctrlx = readl(&udc->op_regs->epctrlx[ep->ep_num]); - if (ep_dir(ep) == EP_DIR_IN) - epctrlx |= EPCTRL_TX_ENABLE; - else - epctrlx |= EPCTRL_RX_ENABLE; - writel(epctrlx, &udc->op_regs->epctrlx[ep->ep_num]); - ep->stopped = stopped; - - spin_unlock_irqrestore(&ep->udc->lock, flags); - return ret; -} - -static void ep_set_stall(struct mv_udc *udc, u8 ep_num, u8 direction, int stall) -{ - u32 epctrlx; - - epctrlx = readl(&udc->op_regs->epctrlx[ep_num]); - - if (stall) { - if (direction == EP_DIR_IN) - epctrlx |= EPCTRL_TX_EP_STALL; - else - epctrlx |= EPCTRL_RX_EP_STALL; - } else { - if (direction == EP_DIR_IN) { - epctrlx &= ~EPCTRL_TX_EP_STALL; - epctrlx |= EPCTRL_TX_DATA_TOGGLE_RST; - } else { - epctrlx &= ~EPCTRL_RX_EP_STALL; - epctrlx |= EPCTRL_RX_DATA_TOGGLE_RST; - } - } - writel(epctrlx, &udc->op_regs->epctrlx[ep_num]); -} - -static int ep_is_stall(struct mv_udc *udc, u8 ep_num, u8 direction) -{ - u32 epctrlx; - - epctrlx = readl(&udc->op_regs->epctrlx[ep_num]); - - if (direction == EP_DIR_OUT) - return (epctrlx & EPCTRL_RX_EP_STALL) ? 1 : 0; - else - return (epctrlx & EPCTRL_TX_EP_STALL) ? 1 : 0; -} - -static int mv_ep_set_halt_wedge(struct usb_ep *_ep, int halt, int wedge) -{ - struct mv_ep *ep; - unsigned long flags; - int status = 0; - struct mv_udc *udc; - - ep = container_of(_ep, struct mv_ep, ep); - udc = ep->udc; - if (!_ep || !ep->ep.desc) { - status = -EINVAL; - goto out; - } - - if (ep->ep.desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) { - status = -EOPNOTSUPP; - goto out; - } - - /* - * Attempt to halt IN ep will fail if any transfer requests - * are still queue - */ - if (halt && (ep_dir(ep) == EP_DIR_IN) && !list_empty(&ep->queue)) { - status = -EAGAIN; - goto out; - } - - spin_lock_irqsave(&ep->udc->lock, flags); - ep_set_stall(udc, ep->ep_num, ep_dir(ep), halt); - if (halt && wedge) - ep->wedge = 1; - else if (!halt) - ep->wedge = 0; - spin_unlock_irqrestore(&ep->udc->lock, flags); - - if (ep->ep_num == 0) { - udc->ep0_state = WAIT_FOR_SETUP; - udc->ep0_dir = EP_DIR_OUT; - } -out: - return status; -} - -static int mv_ep_set_halt(struct usb_ep *_ep, int halt) -{ - return mv_ep_set_halt_wedge(_ep, halt, 0); -} - -static int mv_ep_set_wedge(struct usb_ep *_ep) -{ - return mv_ep_set_halt_wedge(_ep, 1, 1); -} - -static const struct usb_ep_ops mv_ep_ops = { - .enable = mv_ep_enable, - .disable = mv_ep_disable, - - .alloc_request = mv_alloc_request, - .free_request = mv_free_request, - - .queue = mv_ep_queue, - .dequeue = mv_ep_dequeue, - - .set_wedge = mv_ep_set_wedge, - .set_halt = mv_ep_set_halt, - .fifo_flush = mv_ep_fifo_flush, /* flush fifo */ -}; - -static int udc_clock_enable(struct mv_udc *udc) -{ - return clk_prepare_enable(udc->clk); -} - -static void udc_clock_disable(struct mv_udc *udc) -{ - clk_disable_unprepare(udc->clk); -} - -static void udc_stop(struct mv_udc *udc) -{ - u32 tmp; - - /* Disable interrupts */ - tmp = readl(&udc->op_regs->usbintr); - tmp &= ~(USBINTR_INT_EN | USBINTR_ERR_INT_EN | - USBINTR_PORT_CHANGE_DETECT_EN | USBINTR_RESET_EN); - writel(tmp, &udc->op_regs->usbintr); - - udc->stopped = 1; - - /* Reset the Run the bit in the command register to stop VUSB */ - tmp = readl(&udc->op_regs->usbcmd); - tmp &= ~USBCMD_RUN_STOP; - writel(tmp, &udc->op_regs->usbcmd); -} - -static void udc_start(struct mv_udc *udc) -{ - u32 usbintr; - - usbintr = USBINTR_INT_EN | USBINTR_ERR_INT_EN - | USBINTR_PORT_CHANGE_DETECT_EN - | USBINTR_RESET_EN | USBINTR_DEVICE_SUSPEND; - /* Enable interrupts */ - writel(usbintr, &udc->op_regs->usbintr); - - udc->stopped = 0; - - /* Set the Run bit in the command register */ - writel(USBCMD_RUN_STOP, &udc->op_regs->usbcmd); -} - -static int udc_reset(struct mv_udc *udc) -{ - unsigned int loops; - u32 tmp, portsc; - - /* Stop the controller */ - tmp = readl(&udc->op_regs->usbcmd); - tmp &= ~USBCMD_RUN_STOP; - writel(tmp, &udc->op_regs->usbcmd); - - /* Reset the controller to get default values */ - writel(USBCMD_CTRL_RESET, &udc->op_regs->usbcmd); - - /* wait for reset to complete */ - loops = LOOPS(RESET_TIMEOUT); - while (readl(&udc->op_regs->usbcmd) & USBCMD_CTRL_RESET) { - if (loops == 0) { - dev_err(&udc->dev->dev, - "Wait for RESET completed TIMEOUT\n"); - return -ETIMEDOUT; - } - loops--; - udelay(LOOPS_USEC); - } - - /* set controller to device mode */ - tmp = readl(&udc->op_regs->usbmode); - tmp |= USBMODE_CTRL_MODE_DEVICE; - - /* turn setup lockout off, require setup tripwire in usbcmd */ - tmp |= USBMODE_SETUP_LOCK_OFF; - - writel(tmp, &udc->op_regs->usbmode); - - writel(0x0, &udc->op_regs->epsetupstat); - - /* Configure the Endpoint List Address */ - writel(udc->ep_dqh_dma & USB_EP_LIST_ADDRESS_MASK, - &udc->op_regs->eplistaddr); - - portsc = readl(&udc->op_regs->portsc[0]); - if (readl(&udc->cap_regs->hcsparams) & HCSPARAMS_PPC) - portsc &= (~PORTSCX_W1C_BITS | ~PORTSCX_PORT_POWER); - - if (udc->force_fs) - portsc |= PORTSCX_FORCE_FULL_SPEED_CONNECT; - else - portsc &= (~PORTSCX_FORCE_FULL_SPEED_CONNECT); - - writel(portsc, &udc->op_regs->portsc[0]); - - tmp = readl(&udc->op_regs->epctrlx[0]); - tmp &= ~(EPCTRL_TX_EP_STALL | EPCTRL_RX_EP_STALL); - writel(tmp, &udc->op_regs->epctrlx[0]); - - return 0; -} - -static int mv_udc_enable_internal(struct mv_udc *udc) -{ - int retval; - - if (udc->active) - return 0; - - dev_dbg(&udc->dev->dev, "enable udc\n"); - retval = udc_clock_enable(udc); - if (retval) - return retval; - - if (udc->pdata->phy_init) { - retval = udc->pdata->phy_init(udc->phy_regs); - if (retval) { - dev_err(&udc->dev->dev, - "init phy error %d\n", retval); - udc_clock_disable(udc); - return retval; - } - } - udc->active = 1; - - return 0; -} - -static int mv_udc_enable(struct mv_udc *udc) -{ - if (udc->clock_gating) - return mv_udc_enable_internal(udc); - - return 0; -} - -static void mv_udc_disable_internal(struct mv_udc *udc) -{ - if (udc->active) { - dev_dbg(&udc->dev->dev, "disable udc\n"); - if (udc->pdata->phy_deinit) - udc->pdata->phy_deinit(udc->phy_regs); - udc_clock_disable(udc); - udc->active = 0; - } -} - -static void mv_udc_disable(struct mv_udc *udc) -{ - if (udc->clock_gating) - mv_udc_disable_internal(udc); -} - -static int mv_udc_get_frame(struct usb_gadget *gadget) -{ - struct mv_udc *udc; - u16 retval; - - if (!gadget) - return -ENODEV; - - udc = container_of(gadget, struct mv_udc, gadget); - - retval = readl(&udc->op_regs->frindex) & USB_FRINDEX_MASKS; - - return retval; -} - -/* Tries to wake up the host connected to this gadget */ -static int mv_udc_wakeup(struct usb_gadget *gadget) -{ - struct mv_udc *udc = container_of(gadget, struct mv_udc, gadget); - u32 portsc; - - /* Remote wakeup feature not enabled by host */ - if (!udc->remote_wakeup) - return -ENOTSUPP; - - portsc = readl(&udc->op_regs->portsc); - /* not suspended? */ - if (!(portsc & PORTSCX_PORT_SUSPEND)) - return 0; - /* trigger force resume */ - portsc |= PORTSCX_PORT_FORCE_RESUME; - writel(portsc, &udc->op_regs->portsc[0]); - return 0; -} - -static int mv_udc_vbus_session(struct usb_gadget *gadget, int is_active) -{ - struct mv_udc *udc; - unsigned long flags; - int retval = 0; - - udc = container_of(gadget, struct mv_udc, gadget); - spin_lock_irqsave(&udc->lock, flags); - - udc->vbus_active = (is_active != 0); - - dev_dbg(&udc->dev->dev, "%s: softconnect %d, vbus_active %d\n", - __func__, udc->softconnect, udc->vbus_active); - - if (udc->driver && udc->softconnect && udc->vbus_active) { - retval = mv_udc_enable(udc); - if (retval == 0) { - /* Clock is disabled, need re-init registers */ - udc_reset(udc); - ep0_reset(udc); - udc_start(udc); - } - } else if (udc->driver && udc->softconnect) { - if (!udc->active) - goto out; - - /* stop all the transfer in queue*/ - stop_activity(udc, udc->driver); - udc_stop(udc); - mv_udc_disable(udc); - } - -out: - spin_unlock_irqrestore(&udc->lock, flags); - return retval; -} - -static int mv_udc_pullup(struct usb_gadget *gadget, int is_on) -{ - struct mv_udc *udc; - unsigned long flags; - int retval = 0; - - udc = container_of(gadget, struct mv_udc, gadget); - spin_lock_irqsave(&udc->lock, flags); - - udc->softconnect = (is_on != 0); - - dev_dbg(&udc->dev->dev, "%s: softconnect %d, vbus_active %d\n", - __func__, udc->softconnect, udc->vbus_active); - - if (udc->driver && udc->softconnect && udc->vbus_active) { - retval = mv_udc_enable(udc); - if (retval == 0) { - /* Clock is disabled, need re-init registers */ - udc_reset(udc); - ep0_reset(udc); - udc_start(udc); - } - } else if (udc->driver && udc->vbus_active) { - /* stop all the transfer in queue*/ - stop_activity(udc, udc->driver); - udc_stop(udc); - mv_udc_disable(udc); - } - - spin_unlock_irqrestore(&udc->lock, flags); - return retval; -} - -static int mv_udc_start(struct usb_gadget *, struct usb_gadget_driver *); -static int mv_udc_stop(struct usb_gadget *); -/* device controller usb_gadget_ops structure */ -static const struct usb_gadget_ops mv_ops = { - - /* returns the current frame number */ - .get_frame = mv_udc_get_frame, - - /* tries to wake up the host connected to this gadget */ - .wakeup = mv_udc_wakeup, - - /* notify controller that VBUS is powered or not */ - .vbus_session = mv_udc_vbus_session, - - /* D+ pullup, software-controlled connect/disconnect to USB host */ - .pullup = mv_udc_pullup, - .udc_start = mv_udc_start, - .udc_stop = mv_udc_stop, -}; - -static int eps_init(struct mv_udc *udc) -{ - struct mv_ep *ep; - char name[14]; - int i; - - /* initialize ep0 */ - ep = &udc->eps[0]; - ep->udc = udc; - strncpy(ep->name, "ep0", sizeof(ep->name)); - ep->ep.name = ep->name; - ep->ep.ops = &mv_ep_ops; - ep->wedge = 0; - ep->stopped = 0; - usb_ep_set_maxpacket_limit(&ep->ep, EP0_MAX_PKT_SIZE); - ep->ep.caps.type_control = true; - ep->ep.caps.dir_in = true; - ep->ep.caps.dir_out = true; - ep->ep_num = 0; - ep->ep.desc = &mv_ep0_desc; - INIT_LIST_HEAD(&ep->queue); - - ep->ep_type = USB_ENDPOINT_XFER_CONTROL; - - /* initialize other endpoints */ - for (i = 2; i < udc->max_eps * 2; i++) { - ep = &udc->eps[i]; - if (i % 2) { - snprintf(name, sizeof(name), "ep%din", i / 2); - ep->direction = EP_DIR_IN; - ep->ep.caps.dir_in = true; - } else { - snprintf(name, sizeof(name), "ep%dout", i / 2); - ep->direction = EP_DIR_OUT; - ep->ep.caps.dir_out = true; - } - ep->udc = udc; - strncpy(ep->name, name, sizeof(ep->name)); - ep->ep.name = ep->name; - - ep->ep.caps.type_iso = true; - ep->ep.caps.type_bulk = true; - ep->ep.caps.type_int = true; - - ep->ep.ops = &mv_ep_ops; - ep->stopped = 0; - usb_ep_set_maxpacket_limit(&ep->ep, (unsigned short) ~0); - ep->ep_num = i / 2; - - INIT_LIST_HEAD(&ep->queue); - list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list); - - ep->dqh = &udc->ep_dqh[i]; - } - - return 0; -} - -/* delete all endpoint requests, called with spinlock held */ -static void nuke(struct mv_ep *ep, int status) -{ - /* called with spinlock held */ - ep->stopped = 1; - - /* endpoint fifo flush */ - mv_ep_fifo_flush(&ep->ep); - - while (!list_empty(&ep->queue)) { - struct mv_req *req = NULL; - req = list_entry(ep->queue.next, struct mv_req, queue); - done(ep, req, status); - } -} - -static void gadget_reset(struct mv_udc *udc, struct usb_gadget_driver *driver) -{ - struct mv_ep *ep; - - nuke(&udc->eps[0], -ESHUTDOWN); - - list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) { - nuke(ep, -ESHUTDOWN); - } - - /* report reset; the driver is already quiesced */ - if (driver) { - spin_unlock(&udc->lock); - usb_gadget_udc_reset(&udc->gadget, driver); - spin_lock(&udc->lock); - } -} -/* stop all USB activities */ -static void stop_activity(struct mv_udc *udc, struct usb_gadget_driver *driver) -{ - struct mv_ep *ep; - - nuke(&udc->eps[0], -ESHUTDOWN); - - list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) { - nuke(ep, -ESHUTDOWN); - } - - /* report disconnect; the driver is already quiesced */ - if (driver) { - spin_unlock(&udc->lock); - driver->disconnect(&udc->gadget); - spin_lock(&udc->lock); - } -} - -static int mv_udc_start(struct usb_gadget *gadget, - struct usb_gadget_driver *driver) -{ - struct mv_udc *udc; - int retval = 0; - unsigned long flags; - - udc = container_of(gadget, struct mv_udc, gadget); - - if (udc->driver) - return -EBUSY; - - spin_lock_irqsave(&udc->lock, flags); - - /* hook up the driver ... */ - udc->driver = driver; - - udc->usb_state = USB_STATE_ATTACHED; - udc->ep0_state = WAIT_FOR_SETUP; - udc->ep0_dir = EP_DIR_OUT; - - spin_unlock_irqrestore(&udc->lock, flags); - - if (udc->transceiver) { - retval = otg_set_peripheral(udc->transceiver->otg, - &udc->gadget); - if (retval) { - dev_err(&udc->dev->dev, - "unable to register peripheral to otg\n"); - udc->driver = NULL; - return retval; - } - } - - /* When boot with cable attached, there will be no vbus irq occurred */ - if (udc->qwork) - queue_work(udc->qwork, &udc->vbus_work); - - return 0; -} - -static int mv_udc_stop(struct usb_gadget *gadget) -{ - struct mv_udc *udc; - unsigned long flags; - - udc = container_of(gadget, struct mv_udc, gadget); - - spin_lock_irqsave(&udc->lock, flags); - - mv_udc_enable(udc); - udc_stop(udc); - - /* stop all usb activities */ - udc->gadget.speed = USB_SPEED_UNKNOWN; - stop_activity(udc, NULL); - mv_udc_disable(udc); - - spin_unlock_irqrestore(&udc->lock, flags); - - /* unbind gadget driver */ - udc->driver = NULL; - - return 0; -} - -static void mv_set_ptc(struct mv_udc *udc, u32 mode) -{ - u32 portsc; - - portsc = readl(&udc->op_regs->portsc[0]); - portsc |= mode << 16; - writel(portsc, &udc->op_regs->portsc[0]); -} - -static void prime_status_complete(struct usb_ep *ep, struct usb_request *_req) -{ - struct mv_ep *mvep = container_of(ep, struct mv_ep, ep); - struct mv_req *req = container_of(_req, struct mv_req, req); - struct mv_udc *udc; - unsigned long flags; - - udc = mvep->udc; - - dev_info(&udc->dev->dev, "switch to test mode %d\n", req->test_mode); - - spin_lock_irqsave(&udc->lock, flags); - if (req->test_mode) { - mv_set_ptc(udc, req->test_mode); - req->test_mode = 0; - } - spin_unlock_irqrestore(&udc->lock, flags); -} - -static int -udc_prime_status(struct mv_udc *udc, u8 direction, u16 status, bool empty) -{ - int retval = 0; - struct mv_req *req; - struct mv_ep *ep; - - ep = &udc->eps[0]; - udc->ep0_dir = direction; - udc->ep0_state = WAIT_FOR_OUT_STATUS; - - req = udc->status_req; - - /* fill in the request structure */ - if (empty == false) { - *((u16 *) req->req.buf) = cpu_to_le16(status); - req->req.length = 2; - } else - req->req.length = 0; - - req->ep = ep; - req->req.status = -EINPROGRESS; - req->req.actual = 0; - if (udc->test_mode) { - req->req.complete = prime_status_complete; - req->test_mode = udc->test_mode; - udc->test_mode = 0; - } else - req->req.complete = NULL; - req->dtd_count = 0; - - if (req->req.dma == DMA_ADDR_INVALID) { - req->req.dma = dma_map_single(ep->udc->gadget.dev.parent, - req->req.buf, req->req.length, - ep_dir(ep) ? DMA_TO_DEVICE : DMA_FROM_DEVICE); - req->mapped = 1; - } - - /* prime the data phase */ - if (!req_to_dtd(req)) { - retval = queue_dtd(ep, req); - if (retval) { - dev_err(&udc->dev->dev, - "Failed to queue dtd when prime status\n"); - goto out; - } - } else{ /* no mem */ - retval = -ENOMEM; - dev_err(&udc->dev->dev, - "Failed to dma_pool_alloc when prime status\n"); - goto out; - } - - list_add_tail(&req->queue, &ep->queue); - - return 0; -out: - usb_gadget_unmap_request(&udc->gadget, &req->req, ep_dir(ep)); - - return retval; -} - -static void mv_udc_testmode(struct mv_udc *udc, u16 index) -{ - if (index <= USB_TEST_FORCE_ENABLE) { - udc->test_mode = index; - if (udc_prime_status(udc, EP_DIR_IN, 0, true)) - ep0_stall(udc); - } else - dev_err(&udc->dev->dev, - "This test mode(%d) is not supported\n", index); -} - -static void ch9setaddress(struct mv_udc *udc, struct usb_ctrlrequest *setup) -{ - udc->dev_addr = (u8)setup->wValue; - - /* update usb state */ - udc->usb_state = USB_STATE_ADDRESS; - - if (udc_prime_status(udc, EP_DIR_IN, 0, true)) - ep0_stall(udc); -} - -static void ch9getstatus(struct mv_udc *udc, u8 ep_num, - struct usb_ctrlrequest *setup) -{ - u16 status = 0; - int retval; - - if ((setup->bRequestType & (USB_DIR_IN | USB_TYPE_MASK)) - != (USB_DIR_IN | USB_TYPE_STANDARD)) - return; - - if ((setup->bRequestType & USB_RECIP_MASK) == USB_RECIP_DEVICE) { - status = 1 << USB_DEVICE_SELF_POWERED; - status |= udc->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP; - } else if ((setup->bRequestType & USB_RECIP_MASK) - == USB_RECIP_INTERFACE) { - /* get interface status */ - status = 0; - } else if ((setup->bRequestType & USB_RECIP_MASK) - == USB_RECIP_ENDPOINT) { - u8 ep_num, direction; - - ep_num = setup->wIndex & USB_ENDPOINT_NUMBER_MASK; - direction = (setup->wIndex & USB_ENDPOINT_DIR_MASK) - ? EP_DIR_IN : EP_DIR_OUT; - status = ep_is_stall(udc, ep_num, direction) - << USB_ENDPOINT_HALT; - } - - retval = udc_prime_status(udc, EP_DIR_IN, status, false); - if (retval) - ep0_stall(udc); - else - udc->ep0_state = DATA_STATE_XMIT; -} - -static void ch9clearfeature(struct mv_udc *udc, struct usb_ctrlrequest *setup) -{ - u8 ep_num; - u8 direction; - struct mv_ep *ep; - - if ((setup->bRequestType & (USB_TYPE_MASK | USB_RECIP_MASK)) - == ((USB_TYPE_STANDARD | USB_RECIP_DEVICE))) { - switch (setup->wValue) { - case USB_DEVICE_REMOTE_WAKEUP: - udc->remote_wakeup = 0; - break; - default: - goto out; - } - } else if ((setup->bRequestType & (USB_TYPE_MASK | USB_RECIP_MASK)) - == ((USB_TYPE_STANDARD | USB_RECIP_ENDPOINT))) { - switch (setup->wValue) { - case USB_ENDPOINT_HALT: - ep_num = setup->wIndex & USB_ENDPOINT_NUMBER_MASK; - direction = (setup->wIndex & USB_ENDPOINT_DIR_MASK) - ? EP_DIR_IN : EP_DIR_OUT; - if (setup->wValue != 0 || setup->wLength != 0 - || ep_num > udc->max_eps) - goto out; - ep = &udc->eps[ep_num * 2 + direction]; - if (ep->wedge == 1) - break; - spin_unlock(&udc->lock); - ep_set_stall(udc, ep_num, direction, 0); - spin_lock(&udc->lock); - break; - default: - goto out; - } - } else - goto out; - - if (udc_prime_status(udc, EP_DIR_IN, 0, true)) - ep0_stall(udc); -out: - return; -} - -static void ch9setfeature(struct mv_udc *udc, struct usb_ctrlrequest *setup) -{ - u8 ep_num; - u8 direction; - - if ((setup->bRequestType & (USB_TYPE_MASK | USB_RECIP_MASK)) - == ((USB_TYPE_STANDARD | USB_RECIP_DEVICE))) { - switch (setup->wValue) { - case USB_DEVICE_REMOTE_WAKEUP: - udc->remote_wakeup = 1; - break; - case USB_DEVICE_TEST_MODE: - if (setup->wIndex & 0xFF - || udc->gadget.speed != USB_SPEED_HIGH) - ep0_stall(udc); - - if (udc->usb_state != USB_STATE_CONFIGURED - && udc->usb_state != USB_STATE_ADDRESS - && udc->usb_state != USB_STATE_DEFAULT) - ep0_stall(udc); - - mv_udc_testmode(udc, (setup->wIndex >> 8)); - goto out; - default: - goto out; - } - } else if ((setup->bRequestType & (USB_TYPE_MASK | USB_RECIP_MASK)) - == ((USB_TYPE_STANDARD | USB_RECIP_ENDPOINT))) { - switch (setup->wValue) { - case USB_ENDPOINT_HALT: - ep_num = setup->wIndex & USB_ENDPOINT_NUMBER_MASK; - direction = (setup->wIndex & USB_ENDPOINT_DIR_MASK) - ? EP_DIR_IN : EP_DIR_OUT; - if (setup->wValue != 0 || setup->wLength != 0 - || ep_num > udc->max_eps) - goto out; - spin_unlock(&udc->lock); - ep_set_stall(udc, ep_num, direction, 1); - spin_lock(&udc->lock); - break; - default: - goto out; - } - } else - goto out; - - if (udc_prime_status(udc, EP_DIR_IN, 0, true)) - ep0_stall(udc); -out: - return; -} - -static void handle_setup_packet(struct mv_udc *udc, u8 ep_num, - struct usb_ctrlrequest *setup) - __releases(&ep->udc->lock) - __acquires(&ep->udc->lock) -{ - bool delegate = false; - - nuke(&udc->eps[ep_num * 2 + EP_DIR_OUT], -ESHUTDOWN); - - dev_dbg(&udc->dev->dev, "SETUP %02x.%02x v%04x i%04x l%04x\n", - setup->bRequestType, setup->bRequest, - setup->wValue, setup->wIndex, setup->wLength); - /* We process some standard setup requests here */ - if ((setup->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) { - switch (setup->bRequest) { - case USB_REQ_GET_STATUS: - ch9getstatus(udc, ep_num, setup); - break; - - case USB_REQ_SET_ADDRESS: - ch9setaddress(udc, setup); - break; - - case USB_REQ_CLEAR_FEATURE: - ch9clearfeature(udc, setup); - break; - - case USB_REQ_SET_FEATURE: - ch9setfeature(udc, setup); - break; - - default: - delegate = true; - } - } else - delegate = true; - - /* delegate USB standard requests to the gadget driver */ - if (delegate == true) { - /* USB requests handled by gadget */ - if (setup->wLength) { - /* DATA phase from gadget, STATUS phase from udc */ - udc->ep0_dir = (setup->bRequestType & USB_DIR_IN) - ? EP_DIR_IN : EP_DIR_OUT; - spin_unlock(&udc->lock); - if (udc->driver->setup(&udc->gadget, - &udc->local_setup_buff) < 0) - ep0_stall(udc); - spin_lock(&udc->lock); - udc->ep0_state = (setup->bRequestType & USB_DIR_IN) - ? DATA_STATE_XMIT : DATA_STATE_RECV; - } else { - /* no DATA phase, IN STATUS phase from gadget */ - udc->ep0_dir = EP_DIR_IN; - spin_unlock(&udc->lock); - if (udc->driver->setup(&udc->gadget, - &udc->local_setup_buff) < 0) - ep0_stall(udc); - spin_lock(&udc->lock); - udc->ep0_state = WAIT_FOR_OUT_STATUS; - } - } -} - -/* complete DATA or STATUS phase of ep0 prime status phase if needed */ -static void ep0_req_complete(struct mv_udc *udc, - struct mv_ep *ep0, struct mv_req *req) -{ - u32 new_addr; - - if (udc->usb_state == USB_STATE_ADDRESS) { - /* set the new address */ - new_addr = (u32)udc->dev_addr; - writel(new_addr << USB_DEVICE_ADDRESS_BIT_SHIFT, - &udc->op_regs->deviceaddr); - } - - done(ep0, req, 0); - - switch (udc->ep0_state) { - case DATA_STATE_XMIT: - /* receive status phase */ - if (udc_prime_status(udc, EP_DIR_OUT, 0, true)) - ep0_stall(udc); - break; - case DATA_STATE_RECV: - /* send status phase */ - if (udc_prime_status(udc, EP_DIR_IN, 0 , true)) - ep0_stall(udc); - break; - case WAIT_FOR_OUT_STATUS: - udc->ep0_state = WAIT_FOR_SETUP; - break; - case WAIT_FOR_SETUP: - dev_err(&udc->dev->dev, "unexpect ep0 packets\n"); - break; - default: - ep0_stall(udc); - break; - } -} - -static void get_setup_data(struct mv_udc *udc, u8 ep_num, u8 *buffer_ptr) -{ - u32 temp; - struct mv_dqh *dqh; - - dqh = &udc->ep_dqh[ep_num * 2 + EP_DIR_OUT]; - - /* Clear bit in ENDPTSETUPSTAT */ - writel((1 << ep_num), &udc->op_regs->epsetupstat); - - /* while a hazard exists when setup package arrives */ - do { - /* Set Setup Tripwire */ - temp = readl(&udc->op_regs->usbcmd); - writel(temp | USBCMD_SETUP_TRIPWIRE_SET, &udc->op_regs->usbcmd); - - /* Copy the setup packet to local buffer */ - memcpy(buffer_ptr, (u8 *) dqh->setup_buffer, 8); - } while (!(readl(&udc->op_regs->usbcmd) & USBCMD_SETUP_TRIPWIRE_SET)); - - /* Clear Setup Tripwire */ - temp = readl(&udc->op_regs->usbcmd); - writel(temp & ~USBCMD_SETUP_TRIPWIRE_SET, &udc->op_regs->usbcmd); -} - -static void irq_process_tr_complete(struct mv_udc *udc) -{ - u32 tmp, bit_pos; - int i, ep_num = 0, direction = 0; - struct mv_ep *curr_ep; - struct mv_req *curr_req, *temp_req; - int status; - - /* - * We use separate loops for ENDPTSETUPSTAT and ENDPTCOMPLETE - * because the setup packets are to be read ASAP - */ - - /* Process all Setup packet received interrupts */ - tmp = readl(&udc->op_regs->epsetupstat); - - if (tmp) { - for (i = 0; i < udc->max_eps; i++) { - if (tmp & (1 << i)) { - get_setup_data(udc, i, - (u8 *)(&udc->local_setup_buff)); - handle_setup_packet(udc, i, - &udc->local_setup_buff); - } - } - } - - /* Don't clear the endpoint setup status register here. - * It is cleared as a setup packet is read out of the buffer - */ - - /* Process non-setup transaction complete interrupts */ - tmp = readl(&udc->op_regs->epcomplete); - - if (!tmp) - return; - - writel(tmp, &udc->op_regs->epcomplete); - - for (i = 0; i < udc->max_eps * 2; i++) { - ep_num = i >> 1; - direction = i % 2; - - bit_pos = 1 << (ep_num + 16 * direction); - - if (!(bit_pos & tmp)) - continue; - - if (i == 1) - curr_ep = &udc->eps[0]; - else - curr_ep = &udc->eps[i]; - /* process the req queue until an uncomplete request */ - list_for_each_entry_safe(curr_req, temp_req, - &curr_ep->queue, queue) { - status = process_ep_req(udc, i, curr_req); - if (status) - break; - - /* write back status to req */ - curr_req->req.status = status; - - /* ep0 request completion */ - if (ep_num == 0) { - ep0_req_complete(udc, curr_ep, curr_req); - break; - } else { - done(curr_ep, curr_req, status); - } - } - } -} - -static void irq_process_reset(struct mv_udc *udc) -{ - u32 tmp; - unsigned int loops; - - udc->ep0_dir = EP_DIR_OUT; - udc->ep0_state = WAIT_FOR_SETUP; - udc->remote_wakeup = 0; /* default to 0 on reset */ - - /* The address bits are past bit 25-31. Set the address */ - tmp = readl(&udc->op_regs->deviceaddr); - tmp &= ~(USB_DEVICE_ADDRESS_MASK); - writel(tmp, &udc->op_regs->deviceaddr); - - /* Clear all the setup token semaphores */ - tmp = readl(&udc->op_regs->epsetupstat); - writel(tmp, &udc->op_regs->epsetupstat); - - /* Clear all the endpoint complete status bits */ - tmp = readl(&udc->op_regs->epcomplete); - writel(tmp, &udc->op_regs->epcomplete); - - /* wait until all endptprime bits cleared */ - loops = LOOPS(PRIME_TIMEOUT); - while (readl(&udc->op_regs->epprime) & 0xFFFFFFFF) { - if (loops == 0) { - dev_err(&udc->dev->dev, - "Timeout for ENDPTPRIME = 0x%x\n", - readl(&udc->op_regs->epprime)); - break; - } - loops--; - udelay(LOOPS_USEC); - } - - /* Write 1s to the Flush register */ - writel((u32)~0, &udc->op_regs->epflush); - - if (readl(&udc->op_regs->portsc[0]) & PORTSCX_PORT_RESET) { - dev_info(&udc->dev->dev, "usb bus reset\n"); - udc->usb_state = USB_STATE_DEFAULT; - /* reset all the queues, stop all USB activities */ - gadget_reset(udc, udc->driver); - } else { - dev_info(&udc->dev->dev, "USB reset portsc 0x%x\n", - readl(&udc->op_regs->portsc)); - - /* - * re-initialize - * controller reset - */ - udc_reset(udc); - - /* reset all the queues, stop all USB activities */ - stop_activity(udc, udc->driver); - - /* reset ep0 dQH and endptctrl */ - ep0_reset(udc); - - /* enable interrupt and set controller to run state */ - udc_start(udc); - - udc->usb_state = USB_STATE_ATTACHED; - } -} - -static void handle_bus_resume(struct mv_udc *udc) -{ - udc->usb_state = udc->resume_state; - udc->resume_state = 0; - - /* report resume to the driver */ - if (udc->driver) { - if (udc->driver->resume) { - spin_unlock(&udc->lock); - udc->driver->resume(&udc->gadget); - spin_lock(&udc->lock); - } - } -} - -static void irq_process_suspend(struct mv_udc *udc) -{ - udc->resume_state = udc->usb_state; - udc->usb_state = USB_STATE_SUSPENDED; - - if (udc->driver->suspend) { - spin_unlock(&udc->lock); - udc->driver->suspend(&udc->gadget); - spin_lock(&udc->lock); - } -} - -static void irq_process_port_change(struct mv_udc *udc) -{ - u32 portsc; - - portsc = readl(&udc->op_regs->portsc[0]); - if (!(portsc & PORTSCX_PORT_RESET)) { - /* Get the speed */ - u32 speed = portsc & PORTSCX_PORT_SPEED_MASK; - switch (speed) { - case PORTSCX_PORT_SPEED_HIGH: - udc->gadget.speed = USB_SPEED_HIGH; - break; - case PORTSCX_PORT_SPEED_FULL: - udc->gadget.speed = USB_SPEED_FULL; - break; - case PORTSCX_PORT_SPEED_LOW: - udc->gadget.speed = USB_SPEED_LOW; - break; - default: - udc->gadget.speed = USB_SPEED_UNKNOWN; - break; - } - } - - if (portsc & PORTSCX_PORT_SUSPEND) { - udc->resume_state = udc->usb_state; - udc->usb_state = USB_STATE_SUSPENDED; - if (udc->driver->suspend) { - spin_unlock(&udc->lock); - udc->driver->suspend(&udc->gadget); - spin_lock(&udc->lock); - } - } - - if (!(portsc & PORTSCX_PORT_SUSPEND) - && udc->usb_state == USB_STATE_SUSPENDED) { - handle_bus_resume(udc); - } - - if (!udc->resume_state) - udc->usb_state = USB_STATE_DEFAULT; -} - -static void irq_process_error(struct mv_udc *udc) -{ - /* Increment the error count */ - udc->errors++; -} - -static irqreturn_t mv_udc_irq(int irq, void *dev) -{ - struct mv_udc *udc = (struct mv_udc *)dev; - u32 status, intr; - - /* Disable ISR when stopped bit is set */ - if (udc->stopped) - return IRQ_NONE; - - spin_lock(&udc->lock); - - status = readl(&udc->op_regs->usbsts); - intr = readl(&udc->op_regs->usbintr); - status &= intr; - - if (status == 0) { - spin_unlock(&udc->lock); - return IRQ_NONE; - } - - /* Clear all the interrupts occurred */ - writel(status, &udc->op_regs->usbsts); - - if (status & USBSTS_ERR) - irq_process_error(udc); - - if (status & USBSTS_RESET) - irq_process_reset(udc); - - if (status & USBSTS_PORT_CHANGE) - irq_process_port_change(udc); - - if (status & USBSTS_INT) - irq_process_tr_complete(udc); - - if (status & USBSTS_SUSPEND) - irq_process_suspend(udc); - - spin_unlock(&udc->lock); - - return IRQ_HANDLED; -} - -static irqreturn_t mv_udc_vbus_irq(int irq, void *dev) -{ - struct mv_udc *udc = (struct mv_udc *)dev; - - /* polling VBUS and init phy may cause too much time*/ - if (udc->qwork) - queue_work(udc->qwork, &udc->vbus_work); - - return IRQ_HANDLED; -} - -static void mv_udc_vbus_work(struct work_struct *work) -{ - struct mv_udc *udc; - unsigned int vbus; - - udc = container_of(work, struct mv_udc, vbus_work); - if (!udc->pdata->vbus) - return; - - vbus = udc->pdata->vbus->poll(); - dev_info(&udc->dev->dev, "vbus is %d\n", vbus); - - if (vbus == VBUS_HIGH) - mv_udc_vbus_session(&udc->gadget, 1); - else if (vbus == VBUS_LOW) - mv_udc_vbus_session(&udc->gadget, 0); -} - -/* release device structure */ -static void gadget_release(struct device *_dev) -{ - struct mv_udc *udc; - - udc = dev_get_drvdata(_dev); - - complete(udc->done); -} - -static void mv_udc_remove(struct platform_device *pdev) -{ - struct mv_udc *udc; - - udc = platform_get_drvdata(pdev); - - usb_del_gadget_udc(&udc->gadget); - - if (udc->qwork) - destroy_workqueue(udc->qwork); - - /* free memory allocated in probe */ - dma_pool_destroy(udc->dtd_pool); - - if (udc->ep_dqh) - dma_free_coherent(&pdev->dev, udc->ep_dqh_size, - udc->ep_dqh, udc->ep_dqh_dma); - - mv_udc_disable(udc); - - /* free dev, wait for the release() finished */ - wait_for_completion(udc->done); -} - -static int mv_udc_probe(struct platform_device *pdev) -{ - struct mv_usb_platform_data *pdata = dev_get_platdata(&pdev->dev); - struct mv_udc *udc; - int retval = 0; - struct resource *r; - size_t size; - - if (pdata == NULL) { - dev_err(&pdev->dev, "missing platform_data\n"); - return -ENODEV; - } - - udc = devm_kzalloc(&pdev->dev, sizeof(*udc), GFP_KERNEL); - if (udc == NULL) - return -ENOMEM; - - udc->done = &release_done; - udc->pdata = dev_get_platdata(&pdev->dev); - spin_lock_init(&udc->lock); - - udc->dev = pdev; - - if (pdata->mode == MV_USB_MODE_OTG) { - udc->transceiver = devm_usb_get_phy(&pdev->dev, - USB_PHY_TYPE_USB2); - if (IS_ERR(udc->transceiver)) { - retval = PTR_ERR(udc->transceiver); - - if (retval == -ENXIO) - return retval; - - udc->transceiver = NULL; - return -EPROBE_DEFER; - } - } - - /* udc only have one sysclk. */ - udc->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(udc->clk)) - return PTR_ERR(udc->clk); - - r = platform_get_resource_byname(udc->dev, IORESOURCE_MEM, "capregs"); - if (r == NULL) { - dev_err(&pdev->dev, "no I/O memory resource defined\n"); - return -ENODEV; - } - - udc->cap_regs = (struct mv_cap_regs __iomem *) - devm_ioremap(&pdev->dev, r->start, resource_size(r)); - if (udc->cap_regs == NULL) { - dev_err(&pdev->dev, "failed to map I/O memory\n"); - return -EBUSY; - } - - r = platform_get_resource_byname(udc->dev, IORESOURCE_MEM, "phyregs"); - if (r == NULL) { - dev_err(&pdev->dev, "no phy I/O memory resource defined\n"); - return -ENODEV; - } - - udc->phy_regs = devm_ioremap(&pdev->dev, r->start, resource_size(r)); - if (udc->phy_regs == NULL) { - dev_err(&pdev->dev, "failed to map phy I/O memory\n"); - return -EBUSY; - } - - /* we will acces controller register, so enable the clk */ - retval = mv_udc_enable_internal(udc); - if (retval) - return retval; - - udc->op_regs = - (struct mv_op_regs __iomem *)((unsigned long)udc->cap_regs - + (readl(&udc->cap_regs->caplength_hciversion) - & CAPLENGTH_MASK)); - udc->max_eps = readl(&udc->cap_regs->dccparams) & DCCPARAMS_DEN_MASK; - - /* - * some platform will use usb to download image, it may not disconnect - * usb gadget before loading kernel. So first stop udc here. - */ - udc_stop(udc); - writel(0xFFFFFFFF, &udc->op_regs->usbsts); - - size = udc->max_eps * sizeof(struct mv_dqh) *2; - size = (size + DQH_ALIGNMENT - 1) & ~(DQH_ALIGNMENT - 1); - udc->ep_dqh = dma_alloc_coherent(&pdev->dev, size, - &udc->ep_dqh_dma, GFP_KERNEL); - - if (udc->ep_dqh == NULL) { - dev_err(&pdev->dev, "allocate dQH memory failed\n"); - retval = -ENOMEM; - goto err_disable_clock; - } - udc->ep_dqh_size = size; - - /* create dTD dma_pool resource */ - udc->dtd_pool = dma_pool_create("mv_dtd", - &pdev->dev, - sizeof(struct mv_dtd), - DTD_ALIGNMENT, - DMA_BOUNDARY); - - if (!udc->dtd_pool) { - retval = -ENOMEM; - goto err_free_dma; - } - - size = udc->max_eps * sizeof(struct mv_ep) *2; - udc->eps = devm_kzalloc(&pdev->dev, size, GFP_KERNEL); - if (udc->eps == NULL) { - retval = -ENOMEM; - goto err_destroy_dma; - } - - /* initialize ep0 status request structure */ - udc->status_req = devm_kzalloc(&pdev->dev, sizeof(struct mv_req), - GFP_KERNEL); - if (!udc->status_req) { - retval = -ENOMEM; - goto err_destroy_dma; - } - INIT_LIST_HEAD(&udc->status_req->queue); - - /* allocate a small amount of memory to get valid address */ - udc->status_req->req.buf = devm_kzalloc(&pdev->dev, 8, GFP_KERNEL); - if (!udc->status_req->req.buf) { - retval = -ENOMEM; - goto err_destroy_dma; - } - udc->status_req->req.dma = DMA_ADDR_INVALID; - - udc->resume_state = USB_STATE_NOTATTACHED; - udc->usb_state = USB_STATE_POWERED; - udc->ep0_dir = EP_DIR_OUT; - udc->remote_wakeup = 0; - - r = platform_get_resource(udc->dev, IORESOURCE_IRQ, 0); - if (r == NULL) { - dev_err(&pdev->dev, "no IRQ resource defined\n"); - retval = -ENODEV; - goto err_destroy_dma; - } - udc->irq = r->start; - if (devm_request_irq(&pdev->dev, udc->irq, mv_udc_irq, - IRQF_SHARED, driver_name, udc)) { - dev_err(&pdev->dev, "Request irq %d for UDC failed\n", - udc->irq); - retval = -ENODEV; - goto err_destroy_dma; - } - - /* initialize gadget structure */ - udc->gadget.ops = &mv_ops; /* usb_gadget_ops */ - udc->gadget.ep0 = &udc->eps[0].ep; /* gadget ep0 */ - INIT_LIST_HEAD(&udc->gadget.ep_list); /* ep_list */ - udc->gadget.speed = USB_SPEED_UNKNOWN; /* speed */ - udc->gadget.max_speed = USB_SPEED_HIGH; /* support dual speed */ - - /* the "gadget" abstracts/virtualizes the controller */ - udc->gadget.name = driver_name; /* gadget name */ - - eps_init(udc); - - /* VBUS detect: we can disable/enable clock on demand.*/ - if (udc->transceiver) - udc->clock_gating = 1; - else if (pdata->vbus) { - udc->clock_gating = 1; - retval = devm_request_threaded_irq(&pdev->dev, - pdata->vbus->irq, NULL, - mv_udc_vbus_irq, IRQF_ONESHOT, "vbus", udc); - if (retval) { - dev_info(&pdev->dev, - "Can not request irq for VBUS, " - "disable clock gating\n"); - udc->clock_gating = 0; - } - - udc->qwork = create_singlethread_workqueue("mv_udc_queue"); - if (!udc->qwork) { - dev_err(&pdev->dev, "cannot create workqueue\n"); - retval = -ENOMEM; - goto err_destroy_dma; - } - - INIT_WORK(&udc->vbus_work, mv_udc_vbus_work); - } - - /* - * When clock gating is supported, we can disable clk and phy. - * If not, it means that VBUS detection is not supported, we - * have to enable vbus active all the time to let controller work. - */ - if (udc->clock_gating) - mv_udc_disable_internal(udc); - else - udc->vbus_active = 1; - - retval = usb_add_gadget_udc_release(&pdev->dev, &udc->gadget, - gadget_release); - if (retval) - goto err_create_workqueue; - - platform_set_drvdata(pdev, udc); - dev_info(&pdev->dev, "successful probe UDC device %s clock gating.\n", - udc->clock_gating ? "with" : "without"); - - return 0; - -err_create_workqueue: - if (udc->qwork) - destroy_workqueue(udc->qwork); -err_destroy_dma: - dma_pool_destroy(udc->dtd_pool); -err_free_dma: - dma_free_coherent(&pdev->dev, udc->ep_dqh_size, - udc->ep_dqh, udc->ep_dqh_dma); -err_disable_clock: - mv_udc_disable_internal(udc); - - return retval; -} - -#ifdef CONFIG_PM -static int mv_udc_suspend(struct device *dev) -{ - struct mv_udc *udc; - - udc = dev_get_drvdata(dev); - - /* if OTG is enabled, the following will be done in OTG driver*/ - if (udc->transceiver) - return 0; - - if (udc->pdata->vbus && udc->pdata->vbus->poll) - if (udc->pdata->vbus->poll() == VBUS_HIGH) { - dev_info(&udc->dev->dev, "USB cable is connected!\n"); - return -EAGAIN; - } - - /* - * only cable is unplugged, udc can suspend. - * So do not care about clock_gating == 1. - */ - if (!udc->clock_gating) { - udc_stop(udc); - - spin_lock_irq(&udc->lock); - /* stop all usb activities */ - stop_activity(udc, udc->driver); - spin_unlock_irq(&udc->lock); - - mv_udc_disable_internal(udc); - } - - return 0; -} - -static int mv_udc_resume(struct device *dev) -{ - struct mv_udc *udc; - int retval; - - udc = dev_get_drvdata(dev); - - /* if OTG is enabled, the following will be done in OTG driver*/ - if (udc->transceiver) - return 0; - - if (!udc->clock_gating) { - retval = mv_udc_enable_internal(udc); - if (retval) - return retval; - - if (udc->driver && udc->softconnect) { - udc_reset(udc); - ep0_reset(udc); - udc_start(udc); - } - } - - return 0; -} - -static const struct dev_pm_ops mv_udc_pm_ops = { - .suspend = mv_udc_suspend, - .resume = mv_udc_resume, -}; -#endif - -static void mv_udc_shutdown(struct platform_device *pdev) -{ - struct mv_udc *udc; - u32 mode; - - udc = platform_get_drvdata(pdev); - /* reset controller mode to IDLE */ - mv_udc_enable(udc); - mode = readl(&udc->op_regs->usbmode); - mode &= ~3; - writel(mode, &udc->op_regs->usbmode); - mv_udc_disable(udc); -} - -static struct platform_driver udc_driver = { - .probe = mv_udc_probe, - .remove = mv_udc_remove, - .shutdown = mv_udc_shutdown, - .driver = { - .name = "mv-udc", -#ifdef CONFIG_PM - .pm = &mv_udc_pm_ops, -#endif - }, -}; - -module_platform_driver(udc_driver); -MODULE_ALIAS("platform:mv-udc"); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_AUTHOR("Chao Xie <chao.xie@marvell.com>"); -MODULE_LICENSE("GPL"); diff --git a/drivers/usb/gadget/udc/net2272.c b/drivers/usb/gadget/udc/net2272.c deleted file mode 100644 index 7ecddbf5c90d..000000000000 --- a/drivers/usb/gadget/udc/net2272.c +++ /dev/null @@ -1,2723 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Driver for PLX NET2272 USB device controller - * - * Copyright (C) 2005-2006 PLX Technology, Inc. - * Copyright (C) 2006-2011 Analog Devices, Inc. - */ - -#include <linux/delay.h> -#include <linux/device.h> -#include <linux/errno.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/io.h> -#include <linux/ioport.h> -#include <linux/kernel.h> -#include <linux/list.h> -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/pci.h> -#include <linux/platform_device.h> -#include <linux/prefetch.h> -#include <linux/sched.h> -#include <linux/slab.h> -#include <linux/timer.h> -#include <linux/usb.h> -#include <linux/usb/ch9.h> -#include <linux/usb/gadget.h> - -#include <asm/byteorder.h> -#include <linux/unaligned.h> - -#include "net2272.h" - -#define DRIVER_DESC "PLX NET2272 USB Peripheral Controller" - -static const char driver_name[] = "net2272"; -static const char driver_vers[] = "2006 October 17/mainline"; -static const char driver_desc[] = DRIVER_DESC; - -static const char ep0name[] = "ep0"; -static const char * const ep_name[] = { - ep0name, - "ep-a", "ep-b", "ep-c", -}; - -#ifdef CONFIG_USB_NET2272_DMA -/* - * use_dma: the NET2272 can use an external DMA controller. - * Note that since there is no generic DMA api, some functions, - * notably request_dma, start_dma, and cancel_dma will need to be - * modified for your platform's particular dma controller. - * - * If use_dma is disabled, pio will be used instead. - */ -static bool use_dma = false; -module_param(use_dma, bool, 0644); - -/* - * dma_ep: selects the endpoint for use with dma (1=ep-a, 2=ep-b) - * The NET2272 can only use dma for a single endpoint at a time. - * At some point this could be modified to allow either endpoint - * to take control of dma as it becomes available. - * - * Note that DMA should not be used on OUT endpoints unless it can - * be guaranteed that no short packets will arrive on an IN endpoint - * while the DMA operation is pending. Otherwise the OUT DMA will - * terminate prematurely (See NET2272 Errata 630-0213-0101) - */ -static ushort dma_ep = 1; -module_param(dma_ep, ushort, 0644); - -/* - * dma_mode: net2272 dma mode setting (see LOCCTL1 definition): - * mode 0 == Slow DREQ mode - * mode 1 == Fast DREQ mode - * mode 2 == Burst mode - */ -static ushort dma_mode = 2; -module_param(dma_mode, ushort, 0644); -#else -#define use_dma 0 -#define dma_ep 1 -#define dma_mode 2 -#endif - -/* - * fifo_mode: net2272 buffer configuration: - * mode 0 == ep-{a,b,c} 512db each - * mode 1 == ep-a 1k, ep-{b,c} 512db - * mode 2 == ep-a 1k, ep-b 1k, ep-c 512db - * mode 3 == ep-a 1k, ep-b disabled, ep-c 512db - */ -static ushort fifo_mode; -module_param(fifo_mode, ushort, 0644); - -/* - * enable_suspend: When enabled, the driver will respond to - * USB suspend requests by powering down the NET2272. Otherwise, - * USB suspend requests will be ignored. This is acceptable for - * self-powered devices. For bus powered devices set this to 1. - */ -static ushort enable_suspend; -module_param(enable_suspend, ushort, 0644); - -static void assert_out_naking(struct net2272_ep *ep, const char *where) -{ - u8 tmp; - -#ifndef DEBUG - return; -#endif - - tmp = net2272_ep_read(ep, EP_STAT0); - if ((tmp & (1 << NAK_OUT_PACKETS)) == 0) { - dev_dbg(ep->dev->dev, "%s %s %02x !NAK\n", - ep->ep.name, where, tmp); - net2272_ep_write(ep, EP_RSPSET, 1 << ALT_NAK_OUT_PACKETS); - } -} -#define ASSERT_OUT_NAKING(ep) assert_out_naking(ep, __func__) - -static void stop_out_naking(struct net2272_ep *ep) -{ - u8 tmp = net2272_ep_read(ep, EP_STAT0); - - if ((tmp & (1 << NAK_OUT_PACKETS)) != 0) - net2272_ep_write(ep, EP_RSPCLR, 1 << ALT_NAK_OUT_PACKETS); -} - -#define PIPEDIR(bAddress) (usb_pipein(bAddress) ? "in" : "out") - -static char *type_string(u8 bmAttributes) -{ - switch ((bmAttributes) & USB_ENDPOINT_XFERTYPE_MASK) { - case USB_ENDPOINT_XFER_BULK: return "bulk"; - case USB_ENDPOINT_XFER_ISOC: return "iso"; - case USB_ENDPOINT_XFER_INT: return "intr"; - default: return "control"; - } -} - -static char *buf_state_string(unsigned state) -{ - switch (state) { - case BUFF_FREE: return "free"; - case BUFF_VALID: return "valid"; - case BUFF_LCL: return "local"; - case BUFF_USB: return "usb"; - default: return "unknown"; - } -} - -static char *dma_mode_string(void) -{ - if (!use_dma) - return "PIO"; - switch (dma_mode) { - case 0: return "SLOW DREQ"; - case 1: return "FAST DREQ"; - case 2: return "BURST"; - default: return "invalid"; - } -} - -static void net2272_dequeue_all(struct net2272_ep *); -static int net2272_kick_dma(struct net2272_ep *, struct net2272_request *); -static int net2272_fifo_status(struct usb_ep *); - -static const struct usb_ep_ops net2272_ep_ops; - -/*---------------------------------------------------------------------------*/ - -static int -net2272_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) -{ - struct net2272 *dev; - struct net2272_ep *ep; - u32 max; - u8 tmp; - unsigned long flags; - - ep = container_of(_ep, struct net2272_ep, ep); - if (!_ep || !desc || ep->desc || _ep->name == ep0name - || desc->bDescriptorType != USB_DT_ENDPOINT) - return -EINVAL; - dev = ep->dev; - if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) - return -ESHUTDOWN; - - max = usb_endpoint_maxp(desc); - - spin_lock_irqsave(&dev->lock, flags); - _ep->maxpacket = max; - ep->desc = desc; - - /* net2272_ep_reset() has already been called */ - ep->stopped = 0; - ep->wedged = 0; - - /* set speed-dependent max packet */ - net2272_ep_write(ep, EP_MAXPKT0, max & 0xff); - net2272_ep_write(ep, EP_MAXPKT1, (max & 0xff00) >> 8); - - /* set type, direction, address; reset fifo counters */ - net2272_ep_write(ep, EP_STAT1, 1 << BUFFER_FLUSH); - tmp = usb_endpoint_type(desc); - if (usb_endpoint_xfer_bulk(desc)) { - /* catch some particularly blatant driver bugs */ - if ((dev->gadget.speed == USB_SPEED_HIGH && max != 512) || - (dev->gadget.speed == USB_SPEED_FULL && max > 64)) { - spin_unlock_irqrestore(&dev->lock, flags); - return -ERANGE; - } - } - ep->is_iso = usb_endpoint_xfer_isoc(desc) ? 1 : 0; - tmp <<= ENDPOINT_TYPE; - tmp |= ((desc->bEndpointAddress & 0x0f) << ENDPOINT_NUMBER); - tmp |= usb_endpoint_dir_in(desc) << ENDPOINT_DIRECTION; - tmp |= (1 << ENDPOINT_ENABLE); - - /* for OUT transfers, block the rx fifo until a read is posted */ - ep->is_in = usb_endpoint_dir_in(desc); - if (!ep->is_in) - net2272_ep_write(ep, EP_RSPSET, 1 << ALT_NAK_OUT_PACKETS); - - net2272_ep_write(ep, EP_CFG, tmp); - - /* enable irqs */ - tmp = (1 << ep->num) | net2272_read(dev, IRQENB0); - net2272_write(dev, IRQENB0, tmp); - - tmp = (1 << DATA_PACKET_RECEIVED_INTERRUPT_ENABLE) - | (1 << DATA_PACKET_TRANSMITTED_INTERRUPT_ENABLE) - | net2272_ep_read(ep, EP_IRQENB); - net2272_ep_write(ep, EP_IRQENB, tmp); - - tmp = desc->bEndpointAddress; - dev_dbg(dev->dev, "enabled %s (ep%d%s-%s) max %04x cfg %02x\n", - _ep->name, tmp & 0x0f, PIPEDIR(tmp), - type_string(desc->bmAttributes), max, - net2272_ep_read(ep, EP_CFG)); - - spin_unlock_irqrestore(&dev->lock, flags); - return 0; -} - -static void net2272_ep_reset(struct net2272_ep *ep) -{ - u8 tmp; - - ep->desc = NULL; - INIT_LIST_HEAD(&ep->queue); - - usb_ep_set_maxpacket_limit(&ep->ep, ~0); - ep->ep.ops = &net2272_ep_ops; - - /* disable irqs, endpoint */ - net2272_ep_write(ep, EP_IRQENB, 0); - - /* init to our chosen defaults, notably so that we NAK OUT - * packets until the driver queues a read. - */ - tmp = (1 << NAK_OUT_PACKETS_MODE) | (1 << ALT_NAK_OUT_PACKETS); - net2272_ep_write(ep, EP_RSPSET, tmp); - - tmp = (1 << INTERRUPT_MODE) | (1 << HIDE_STATUS_PHASE); - if (ep->num != 0) - tmp |= (1 << ENDPOINT_TOGGLE) | (1 << ENDPOINT_HALT); - - net2272_ep_write(ep, EP_RSPCLR, tmp); - - /* scrub most status bits, and flush any fifo state */ - net2272_ep_write(ep, EP_STAT0, - (1 << DATA_IN_TOKEN_INTERRUPT) - | (1 << DATA_OUT_TOKEN_INTERRUPT) - | (1 << DATA_PACKET_TRANSMITTED_INTERRUPT) - | (1 << DATA_PACKET_RECEIVED_INTERRUPT) - | (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT)); - - net2272_ep_write(ep, EP_STAT1, - (1 << TIMEOUT) - | (1 << USB_OUT_ACK_SENT) - | (1 << USB_OUT_NAK_SENT) - | (1 << USB_IN_ACK_RCVD) - | (1 << USB_IN_NAK_SENT) - | (1 << USB_STALL_SENT) - | (1 << LOCAL_OUT_ZLP) - | (1 << BUFFER_FLUSH)); - - /* fifo size is handled separately */ -} - -static int net2272_disable(struct usb_ep *_ep) -{ - struct net2272_ep *ep; - unsigned long flags; - - ep = container_of(_ep, struct net2272_ep, ep); - if (!_ep || !ep->desc || _ep->name == ep0name) - return -EINVAL; - - spin_lock_irqsave(&ep->dev->lock, flags); - net2272_dequeue_all(ep); - net2272_ep_reset(ep); - - dev_vdbg(ep->dev->dev, "disabled %s\n", _ep->name); - - spin_unlock_irqrestore(&ep->dev->lock, flags); - return 0; -} - -/*---------------------------------------------------------------------------*/ - -static struct usb_request * -net2272_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags) -{ - struct net2272_request *req; - - if (!_ep) - return NULL; - - req = kzalloc(sizeof(*req), gfp_flags); - if (!req) - return NULL; - - INIT_LIST_HEAD(&req->queue); - - return &req->req; -} - -static void -net2272_free_request(struct usb_ep *_ep, struct usb_request *_req) -{ - struct net2272_request *req; - - if (!_ep || !_req) - return; - - req = container_of(_req, struct net2272_request, req); - WARN_ON(!list_empty(&req->queue)); - kfree(req); -} - -static void -net2272_done(struct net2272_ep *ep, struct net2272_request *req, int status) -{ - struct net2272 *dev; - unsigned stopped = ep->stopped; - - if (ep->num == 0) { - if (ep->dev->protocol_stall) { - ep->stopped = 1; - set_halt(ep); - } - allow_status(ep); - } - - list_del_init(&req->queue); - - if (req->req.status == -EINPROGRESS) - req->req.status = status; - else - status = req->req.status; - - dev = ep->dev; - if (use_dma && ep->dma) - usb_gadget_unmap_request(&dev->gadget, &req->req, - ep->is_in); - - if (status && status != -ESHUTDOWN) - dev_vdbg(dev->dev, "complete %s req %p stat %d len %u/%u buf %p\n", - ep->ep.name, &req->req, status, - req->req.actual, req->req.length, req->req.buf); - - /* don't modify queue heads during completion callback */ - ep->stopped = 1; - spin_unlock(&dev->lock); - usb_gadget_giveback_request(&ep->ep, &req->req); - spin_lock(&dev->lock); - ep->stopped = stopped; -} - -static int -net2272_write_packet(struct net2272_ep *ep, u8 *buf, - struct net2272_request *req, unsigned max) -{ - u16 __iomem *ep_data = net2272_reg_addr(ep->dev, EP_DATA); - u16 *bufp; - unsigned length, count; - u8 tmp; - - length = min(req->req.length - req->req.actual, max); - req->req.actual += length; - - dev_vdbg(ep->dev->dev, "write packet %s req %p max %u len %u avail %u\n", - ep->ep.name, req, max, length, - (net2272_ep_read(ep, EP_AVAIL1) << 8) | net2272_ep_read(ep, EP_AVAIL0)); - - count = length; - bufp = (u16 *)buf; - - while (likely(count >= 2)) { - /* no byte-swap required; chip endian set during init */ - writew(*bufp++, ep_data); - count -= 2; - } - buf = (u8 *)bufp; - - /* write final byte by placing the NET2272 into 8-bit mode */ - if (unlikely(count)) { - tmp = net2272_read(ep->dev, LOCCTL); - net2272_write(ep->dev, LOCCTL, tmp & ~(1 << DATA_WIDTH)); - writeb(*buf, ep_data); - net2272_write(ep->dev, LOCCTL, tmp); - } - return length; -} - -/* returns: 0: still running, 1: completed, negative: errno */ -static int -net2272_write_fifo(struct net2272_ep *ep, struct net2272_request *req) -{ - u8 *buf; - unsigned count, max; - int status; - - dev_vdbg(ep->dev->dev, "write_fifo %s actual %d len %d\n", - ep->ep.name, req->req.actual, req->req.length); - - /* - * Keep loading the endpoint until the final packet is loaded, - * or the endpoint buffer is full. - */ - top: - /* - * Clear interrupt status - * - Packet Transmitted interrupt will become set again when the - * host successfully takes another packet - */ - net2272_ep_write(ep, EP_STAT0, (1 << DATA_PACKET_TRANSMITTED_INTERRUPT)); - while (!(net2272_ep_read(ep, EP_STAT0) & (1 << BUFFER_FULL))) { - buf = req->req.buf + req->req.actual; - prefetch(buf); - - /* force pagesel */ - net2272_ep_read(ep, EP_STAT0); - - max = (net2272_ep_read(ep, EP_AVAIL1) << 8) | - (net2272_ep_read(ep, EP_AVAIL0)); - - if (max < ep->ep.maxpacket) - max = (net2272_ep_read(ep, EP_AVAIL1) << 8) - | (net2272_ep_read(ep, EP_AVAIL0)); - - count = net2272_write_packet(ep, buf, req, max); - /* see if we are done */ - if (req->req.length == req->req.actual) { - /* validate short or zlp packet */ - if (count < ep->ep.maxpacket) - set_fifo_bytecount(ep, 0); - net2272_done(ep, req, 0); - - if (!list_empty(&ep->queue)) { - req = list_entry(ep->queue.next, - struct net2272_request, - queue); - status = net2272_kick_dma(ep, req); - - if (status < 0) - if ((net2272_ep_read(ep, EP_STAT0) - & (1 << BUFFER_EMPTY))) - goto top; - } - return 1; - } - net2272_ep_write(ep, EP_STAT0, (1 << DATA_PACKET_TRANSMITTED_INTERRUPT)); - } - return 0; -} - -static void -net2272_out_flush(struct net2272_ep *ep) -{ - ASSERT_OUT_NAKING(ep); - - net2272_ep_write(ep, EP_STAT0, (1 << DATA_OUT_TOKEN_INTERRUPT) - | (1 << DATA_PACKET_RECEIVED_INTERRUPT)); - net2272_ep_write(ep, EP_STAT1, 1 << BUFFER_FLUSH); -} - -static int -net2272_read_packet(struct net2272_ep *ep, u8 *buf, - struct net2272_request *req, unsigned avail) -{ - u16 __iomem *ep_data = net2272_reg_addr(ep->dev, EP_DATA); - unsigned is_short; - u16 *bufp; - - req->req.actual += avail; - - dev_vdbg(ep->dev->dev, "read packet %s req %p len %u avail %u\n", - ep->ep.name, req, avail, - (net2272_ep_read(ep, EP_AVAIL1) << 8) | net2272_ep_read(ep, EP_AVAIL0)); - - is_short = (avail < ep->ep.maxpacket); - - if (unlikely(avail == 0)) { - /* remove any zlp from the buffer */ - (void)readw(ep_data); - return is_short; - } - - /* Ensure we get the final byte */ - if (unlikely(avail % 2)) - avail++; - bufp = (u16 *)buf; - - do { - *bufp++ = readw(ep_data); - avail -= 2; - } while (avail); - - /* - * To avoid false endpoint available race condition must read - * ep stat0 twice in the case of a short transfer - */ - if (net2272_ep_read(ep, EP_STAT0) & (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT)) - net2272_ep_read(ep, EP_STAT0); - - return is_short; -} - -static int -net2272_read_fifo(struct net2272_ep *ep, struct net2272_request *req) -{ - u8 *buf; - unsigned is_short; - int count; - int tmp; - int cleanup = 0; - - dev_vdbg(ep->dev->dev, "read_fifo %s actual %d len %d\n", - ep->ep.name, req->req.actual, req->req.length); - - top: - do { - buf = req->req.buf + req->req.actual; - prefetchw(buf); - - count = (net2272_ep_read(ep, EP_AVAIL1) << 8) - | net2272_ep_read(ep, EP_AVAIL0); - - net2272_ep_write(ep, EP_STAT0, - (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT) | - (1 << DATA_PACKET_RECEIVED_INTERRUPT)); - - tmp = req->req.length - req->req.actual; - - if (count > tmp) { - if ((tmp % ep->ep.maxpacket) != 0) { - dev_err(ep->dev->dev, - "%s out fifo %d bytes, expected %d\n", - ep->ep.name, count, tmp); - cleanup = 1; - } - count = (tmp > 0) ? tmp : 0; - } - - is_short = net2272_read_packet(ep, buf, req, count); - - /* completion */ - if (unlikely(cleanup || is_short || - req->req.actual == req->req.length)) { - - if (cleanup) { - net2272_out_flush(ep); - net2272_done(ep, req, -EOVERFLOW); - } else - net2272_done(ep, req, 0); - - /* re-initialize endpoint transfer registers - * otherwise they may result in erroneous pre-validation - * for subsequent control reads - */ - if (unlikely(ep->num == 0)) { - net2272_ep_write(ep, EP_TRANSFER2, 0); - net2272_ep_write(ep, EP_TRANSFER1, 0); - net2272_ep_write(ep, EP_TRANSFER0, 0); - } - - if (!list_empty(&ep->queue)) { - int status; - - req = list_entry(ep->queue.next, - struct net2272_request, queue); - status = net2272_kick_dma(ep, req); - if ((status < 0) && - !(net2272_ep_read(ep, EP_STAT0) & (1 << BUFFER_EMPTY))) - goto top; - } - return 1; - } - } while (!(net2272_ep_read(ep, EP_STAT0) & (1 << BUFFER_EMPTY))); - - return 0; -} - -static void -net2272_pio_advance(struct net2272_ep *ep) -{ - struct net2272_request *req; - - if (unlikely(list_empty(&ep->queue))) - return; - - req = list_entry(ep->queue.next, struct net2272_request, queue); - (ep->is_in ? net2272_write_fifo : net2272_read_fifo)(ep, req); -} - -/* returns 0 on success, else negative errno */ -static int -net2272_request_dma(struct net2272 *dev, unsigned ep, u32 buf, - unsigned len, unsigned dir) -{ - dev_vdbg(dev->dev, "request_dma ep %d buf %08x len %d dir %d\n", - ep, buf, len, dir); - - /* The NET2272 only supports a single dma channel */ - if (dev->dma_busy) - return -EBUSY; - /* - * EP_TRANSFER (used to determine the number of bytes received - * in an OUT transfer) is 24 bits wide; don't ask for more than that. - */ - if ((dir == 1) && (len > 0x1000000)) - return -EINVAL; - - dev->dma_busy = 1; - - /* initialize platform's dma */ -#ifdef CONFIG_USB_PCI - /* NET2272 addr, buffer addr, length, etc. */ - switch (dev->dev_id) { - case PCI_DEVICE_ID_RDK1: - /* Setup PLX 9054 DMA mode */ - writel((1 << LOCAL_BUS_WIDTH) | - (1 << TA_READY_INPUT_ENABLE) | - (0 << LOCAL_BURST_ENABLE) | - (1 << DONE_INTERRUPT_ENABLE) | - (1 << LOCAL_ADDRESSING_MODE) | - (1 << DEMAND_MODE) | - (1 << DMA_EOT_ENABLE) | - (1 << FAST_SLOW_TERMINATE_MODE_SELECT) | - (1 << DMA_CHANNEL_INTERRUPT_SELECT), - dev->rdk1.plx9054_base_addr + DMAMODE0); - - writel(0x100000, dev->rdk1.plx9054_base_addr + DMALADR0); - writel(buf, dev->rdk1.plx9054_base_addr + DMAPADR0); - writel(len, dev->rdk1.plx9054_base_addr + DMASIZ0); - writel((dir << DIRECTION_OF_TRANSFER) | - (1 << INTERRUPT_AFTER_TERMINAL_COUNT), - dev->rdk1.plx9054_base_addr + DMADPR0); - writel((1 << LOCAL_DMA_CHANNEL_0_INTERRUPT_ENABLE) | - readl(dev->rdk1.plx9054_base_addr + INTCSR), - dev->rdk1.plx9054_base_addr + INTCSR); - - break; - } -#endif - - net2272_write(dev, DMAREQ, - (0 << DMA_BUFFER_VALID) | - (1 << DMA_REQUEST_ENABLE) | - (1 << DMA_CONTROL_DACK) | - (dev->dma_eot_polarity << EOT_POLARITY) | - (dev->dma_dack_polarity << DACK_POLARITY) | - (dev->dma_dreq_polarity << DREQ_POLARITY) | - ((ep >> 1) << DMA_ENDPOINT_SELECT)); - - (void) net2272_read(dev, SCRATCH); - - return 0; -} - -static void -net2272_start_dma(struct net2272 *dev) -{ - /* start platform's dma controller */ -#ifdef CONFIG_USB_PCI - switch (dev->dev_id) { - case PCI_DEVICE_ID_RDK1: - writeb((1 << CHANNEL_ENABLE) | (1 << CHANNEL_START), - dev->rdk1.plx9054_base_addr + DMACSR0); - break; - } -#endif -} - -/* returns 0 on success, else negative errno */ -static int -net2272_kick_dma(struct net2272_ep *ep, struct net2272_request *req) -{ - unsigned size; - u8 tmp; - - if (!use_dma || (ep->num < 1) || (ep->num > 2) || !ep->dma) - return -EINVAL; - - /* don't use dma for odd-length transfers - * otherwise, we'd need to deal with the last byte with pio - */ - if (req->req.length & 1) - return -EINVAL; - - dev_vdbg(ep->dev->dev, "kick_dma %s req %p dma %08llx\n", - ep->ep.name, req, (unsigned long long) req->req.dma); - - net2272_ep_write(ep, EP_RSPSET, 1 << ALT_NAK_OUT_PACKETS); - - /* The NET2272 can only use DMA on one endpoint at a time */ - if (ep->dev->dma_busy) - return -EBUSY; - - /* Make sure we only DMA an even number of bytes (we'll use - * pio to complete the transfer) - */ - size = req->req.length; - size &= ~1; - - /* device-to-host transfer */ - if (ep->is_in) { - /* initialize platform's dma controller */ - if (net2272_request_dma(ep->dev, ep->num, req->req.dma, size, 0)) - /* unable to obtain DMA channel; return error and use pio mode */ - return -EBUSY; - req->req.actual += size; - - /* host-to-device transfer */ - } else { - tmp = net2272_ep_read(ep, EP_STAT0); - - /* initialize platform's dma controller */ - if (net2272_request_dma(ep->dev, ep->num, req->req.dma, size, 1)) - /* unable to obtain DMA channel; return error and use pio mode */ - return -EBUSY; - - if (!(tmp & (1 << BUFFER_EMPTY))) - ep->not_empty = 1; - else - ep->not_empty = 0; - - - /* allow the endpoint's buffer to fill */ - net2272_ep_write(ep, EP_RSPCLR, 1 << ALT_NAK_OUT_PACKETS); - - /* this transfer completed and data's already in the fifo - * return error so pio gets used. - */ - if (tmp & (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT)) { - - /* deassert dreq */ - net2272_write(ep->dev, DMAREQ, - (0 << DMA_BUFFER_VALID) | - (0 << DMA_REQUEST_ENABLE) | - (1 << DMA_CONTROL_DACK) | - (ep->dev->dma_eot_polarity << EOT_POLARITY) | - (ep->dev->dma_dack_polarity << DACK_POLARITY) | - (ep->dev->dma_dreq_polarity << DREQ_POLARITY) | - ((ep->num >> 1) << DMA_ENDPOINT_SELECT)); - - return -EBUSY; - } - } - - /* Don't use per-packet interrupts: use dma interrupts only */ - net2272_ep_write(ep, EP_IRQENB, 0); - - net2272_start_dma(ep->dev); - - return 0; -} - -static void net2272_cancel_dma(struct net2272 *dev) -{ -#ifdef CONFIG_USB_PCI - switch (dev->dev_id) { - case PCI_DEVICE_ID_RDK1: - writeb(0, dev->rdk1.plx9054_base_addr + DMACSR0); - writeb(1 << CHANNEL_ABORT, dev->rdk1.plx9054_base_addr + DMACSR0); - while (!(readb(dev->rdk1.plx9054_base_addr + DMACSR0) & - (1 << CHANNEL_DONE))) - continue; /* wait for dma to stabalize */ - - /* dma abort generates an interrupt */ - writeb(1 << CHANNEL_CLEAR_INTERRUPT, - dev->rdk1.plx9054_base_addr + DMACSR0); - break; - } -#endif - - dev->dma_busy = 0; -} - -/*---------------------------------------------------------------------------*/ - -static int -net2272_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) -{ - struct net2272_request *req; - struct net2272_ep *ep; - struct net2272 *dev; - unsigned long flags; - int status = -1; - u8 s; - - req = container_of(_req, struct net2272_request, req); - if (!_req || !_req->complete || !_req->buf - || !list_empty(&req->queue)) - return -EINVAL; - ep = container_of(_ep, struct net2272_ep, ep); - if (!_ep || (!ep->desc && ep->num != 0)) - return -EINVAL; - dev = ep->dev; - if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) - return -ESHUTDOWN; - - /* set up dma mapping in case the caller didn't */ - if (use_dma && ep->dma) { - status = usb_gadget_map_request(&dev->gadget, _req, - ep->is_in); - if (status) - return status; - } - - dev_vdbg(dev->dev, "%s queue req %p, len %d buf %p dma %08llx %s\n", - _ep->name, _req, _req->length, _req->buf, - (unsigned long long) _req->dma, _req->zero ? "zero" : "!zero"); - - spin_lock_irqsave(&dev->lock, flags); - - _req->status = -EINPROGRESS; - _req->actual = 0; - - /* kickstart this i/o queue? */ - if (list_empty(&ep->queue) && !ep->stopped) { - /* maybe there's no control data, just status ack */ - if (ep->num == 0 && _req->length == 0) { - net2272_done(ep, req, 0); - dev_vdbg(dev->dev, "%s status ack\n", ep->ep.name); - goto done; - } - - /* Return zlp, don't let it block subsequent packets */ - s = net2272_ep_read(ep, EP_STAT0); - if (s & (1 << BUFFER_EMPTY)) { - /* Buffer is empty check for a blocking zlp, handle it */ - if ((s & (1 << NAK_OUT_PACKETS)) && - net2272_ep_read(ep, EP_STAT1) & (1 << LOCAL_OUT_ZLP)) { - dev_dbg(dev->dev, "WARNING: returning ZLP short packet termination!\n"); - /* - * Request is going to terminate with a short packet ... - * hope the client is ready for it! - */ - status = net2272_read_fifo(ep, req); - /* clear short packet naking */ - net2272_ep_write(ep, EP_STAT0, (1 << NAK_OUT_PACKETS)); - goto done; - } - } - - /* try dma first */ - status = net2272_kick_dma(ep, req); - - if (status < 0) { - /* dma failed (most likely in use by another endpoint) - * fallback to pio - */ - status = 0; - - if (ep->is_in) - status = net2272_write_fifo(ep, req); - else { - s = net2272_ep_read(ep, EP_STAT0); - if ((s & (1 << BUFFER_EMPTY)) == 0) - status = net2272_read_fifo(ep, req); - } - - if (unlikely(status != 0)) { - if (status > 0) - status = 0; - req = NULL; - } - } - } - if (likely(req)) - list_add_tail(&req->queue, &ep->queue); - - if (likely(!list_empty(&ep->queue))) - net2272_ep_write(ep, EP_RSPCLR, 1 << ALT_NAK_OUT_PACKETS); - done: - spin_unlock_irqrestore(&dev->lock, flags); - - return 0; -} - -/* dequeue ALL requests */ -static void -net2272_dequeue_all(struct net2272_ep *ep) -{ - struct net2272_request *req; - - /* called with spinlock held */ - ep->stopped = 1; - - while (!list_empty(&ep->queue)) { - req = list_entry(ep->queue.next, - struct net2272_request, - queue); - net2272_done(ep, req, -ESHUTDOWN); - } -} - -/* dequeue JUST ONE request */ -static int -net2272_dequeue(struct usb_ep *_ep, struct usb_request *_req) -{ - struct net2272_ep *ep; - struct net2272_request *req = NULL, *iter; - unsigned long flags; - int stopped; - - ep = container_of(_ep, struct net2272_ep, ep); - if (!_ep || (!ep->desc && ep->num != 0) || !_req) - return -EINVAL; - - spin_lock_irqsave(&ep->dev->lock, flags); - stopped = ep->stopped; - ep->stopped = 1; - - /* make sure it's still queued on this endpoint */ - list_for_each_entry(iter, &ep->queue, queue) { - if (&iter->req != _req) - continue; - req = iter; - break; - } - if (!req) { - ep->stopped = stopped; - spin_unlock_irqrestore(&ep->dev->lock, flags); - return -EINVAL; - } - - /* queue head may be partially complete */ - if (ep->queue.next == &req->queue) { - dev_dbg(ep->dev->dev, "unlink (%s) pio\n", _ep->name); - net2272_done(ep, req, -ECONNRESET); - } - ep->stopped = stopped; - - spin_unlock_irqrestore(&ep->dev->lock, flags); - return 0; -} - -/*---------------------------------------------------------------------------*/ - -static int -net2272_set_halt_and_wedge(struct usb_ep *_ep, int value, int wedged) -{ - struct net2272_ep *ep; - unsigned long flags; - int ret = 0; - - ep = container_of(_ep, struct net2272_ep, ep); - if (!_ep || (!ep->desc && ep->num != 0)) - return -EINVAL; - if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN) - return -ESHUTDOWN; - if (ep->desc /* not ep0 */ && usb_endpoint_xfer_isoc(ep->desc)) - return -EINVAL; - - spin_lock_irqsave(&ep->dev->lock, flags); - if (!list_empty(&ep->queue)) - ret = -EAGAIN; - else if (ep->is_in && value && net2272_fifo_status(_ep) != 0) - ret = -EAGAIN; - else { - dev_vdbg(ep->dev->dev, "%s %s %s\n", _ep->name, - value ? "set" : "clear", - wedged ? "wedge" : "halt"); - /* set/clear */ - if (value) { - if (ep->num == 0) - ep->dev->protocol_stall = 1; - else - set_halt(ep); - if (wedged) - ep->wedged = 1; - } else { - clear_halt(ep); - ep->wedged = 0; - } - } - spin_unlock_irqrestore(&ep->dev->lock, flags); - - return ret; -} - -static int -net2272_set_halt(struct usb_ep *_ep, int value) -{ - return net2272_set_halt_and_wedge(_ep, value, 0); -} - -static int -net2272_set_wedge(struct usb_ep *_ep) -{ - if (!_ep || _ep->name == ep0name) - return -EINVAL; - return net2272_set_halt_and_wedge(_ep, 1, 1); -} - -static int -net2272_fifo_status(struct usb_ep *_ep) -{ - struct net2272_ep *ep; - u16 avail; - - ep = container_of(_ep, struct net2272_ep, ep); - if (!_ep || (!ep->desc && ep->num != 0)) - return -ENODEV; - if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN) - return -ESHUTDOWN; - - avail = net2272_ep_read(ep, EP_AVAIL1) << 8; - avail |= net2272_ep_read(ep, EP_AVAIL0); - if (avail > ep->fifo_size) - return -EOVERFLOW; - if (ep->is_in) - avail = ep->fifo_size - avail; - return avail; -} - -static void -net2272_fifo_flush(struct usb_ep *_ep) -{ - struct net2272_ep *ep; - - ep = container_of(_ep, struct net2272_ep, ep); - if (!_ep || (!ep->desc && ep->num != 0)) - return; - if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN) - return; - - net2272_ep_write(ep, EP_STAT1, 1 << BUFFER_FLUSH); -} - -static const struct usb_ep_ops net2272_ep_ops = { - .enable = net2272_enable, - .disable = net2272_disable, - - .alloc_request = net2272_alloc_request, - .free_request = net2272_free_request, - - .queue = net2272_queue, - .dequeue = net2272_dequeue, - - .set_halt = net2272_set_halt, - .set_wedge = net2272_set_wedge, - .fifo_status = net2272_fifo_status, - .fifo_flush = net2272_fifo_flush, -}; - -/*---------------------------------------------------------------------------*/ - -static int -net2272_get_frame(struct usb_gadget *_gadget) -{ - struct net2272 *dev; - unsigned long flags; - u16 ret; - - if (!_gadget) - return -ENODEV; - dev = container_of(_gadget, struct net2272, gadget); - spin_lock_irqsave(&dev->lock, flags); - - ret = net2272_read(dev, FRAME1) << 8; - ret |= net2272_read(dev, FRAME0); - - spin_unlock_irqrestore(&dev->lock, flags); - return ret; -} - -static int -net2272_wakeup(struct usb_gadget *_gadget) -{ - struct net2272 *dev; - u8 tmp; - unsigned long flags; - - if (!_gadget) - return 0; - dev = container_of(_gadget, struct net2272, gadget); - - spin_lock_irqsave(&dev->lock, flags); - tmp = net2272_read(dev, USBCTL0); - if (tmp & (1 << IO_WAKEUP_ENABLE)) - net2272_write(dev, USBCTL1, (1 << GENERATE_RESUME)); - - spin_unlock_irqrestore(&dev->lock, flags); - - return 0; -} - -static int -net2272_set_selfpowered(struct usb_gadget *_gadget, int value) -{ - if (!_gadget) - return -ENODEV; - - _gadget->is_selfpowered = (value != 0); - - return 0; -} - -static int -net2272_pullup(struct usb_gadget *_gadget, int is_on) -{ - struct net2272 *dev; - u8 tmp; - unsigned long flags; - - if (!_gadget) - return -ENODEV; - dev = container_of(_gadget, struct net2272, gadget); - - spin_lock_irqsave(&dev->lock, flags); - tmp = net2272_read(dev, USBCTL0); - dev->softconnect = (is_on != 0); - if (is_on) - tmp |= (1 << USB_DETECT_ENABLE); - else - tmp &= ~(1 << USB_DETECT_ENABLE); - net2272_write(dev, USBCTL0, tmp); - spin_unlock_irqrestore(&dev->lock, flags); - - return 0; -} - -static int net2272_start(struct usb_gadget *_gadget, - struct usb_gadget_driver *driver); -static int net2272_stop(struct usb_gadget *_gadget); -static void net2272_async_callbacks(struct usb_gadget *_gadget, bool enable); - -static const struct usb_gadget_ops net2272_ops = { - .get_frame = net2272_get_frame, - .wakeup = net2272_wakeup, - .set_selfpowered = net2272_set_selfpowered, - .pullup = net2272_pullup, - .udc_start = net2272_start, - .udc_stop = net2272_stop, - .udc_async_callbacks = net2272_async_callbacks, -}; - -/*---------------------------------------------------------------------------*/ - -static ssize_t -registers_show(struct device *_dev, struct device_attribute *attr, char *buf) -{ - struct net2272 *dev; - char *next; - unsigned size, t; - unsigned long flags; - u8 t1, t2; - int i; - const char *s; - - dev = dev_get_drvdata(_dev); - next = buf; - size = PAGE_SIZE; - spin_lock_irqsave(&dev->lock, flags); - - /* Main Control Registers */ - t = scnprintf(next, size, "%s version %s," - "chiprev %02x, locctl %02x\n" - "irqenb0 %02x irqenb1 %02x " - "irqstat0 %02x irqstat1 %02x\n", - driver_name, driver_vers, dev->chiprev, - net2272_read(dev, LOCCTL), - net2272_read(dev, IRQENB0), - net2272_read(dev, IRQENB1), - net2272_read(dev, IRQSTAT0), - net2272_read(dev, IRQSTAT1)); - size -= t; - next += t; - - /* DMA */ - t1 = net2272_read(dev, DMAREQ); - t = scnprintf(next, size, "\ndmareq %02x: %s %s%s%s%s\n", - t1, ep_name[(t1 & 0x01) + 1], - t1 & (1 << DMA_CONTROL_DACK) ? "dack " : "", - t1 & (1 << DMA_REQUEST_ENABLE) ? "reqenb " : "", - t1 & (1 << DMA_REQUEST) ? "req " : "", - t1 & (1 << DMA_BUFFER_VALID) ? "valid " : ""); - size -= t; - next += t; - - /* USB Control Registers */ - t1 = net2272_read(dev, USBCTL1); - if (t1 & (1 << VBUS_PIN)) { - if (t1 & (1 << USB_HIGH_SPEED)) - s = "high speed"; - else if (dev->gadget.speed == USB_SPEED_UNKNOWN) - s = "powered"; - else - s = "full speed"; - } else - s = "not attached"; - t = scnprintf(next, size, - "usbctl0 %02x usbctl1 %02x addr 0x%02x (%s)\n", - net2272_read(dev, USBCTL0), t1, - net2272_read(dev, OURADDR), s); - size -= t; - next += t; - - /* Endpoint Registers */ - for (i = 0; i < 4; ++i) { - struct net2272_ep *ep; - - ep = &dev->ep[i]; - if (i && !ep->desc) - continue; - - t1 = net2272_ep_read(ep, EP_CFG); - t2 = net2272_ep_read(ep, EP_RSPSET); - t = scnprintf(next, size, - "\n%s\tcfg %02x rsp (%02x) %s%s%s%s%s%s%s%s" - "irqenb %02x\n", - ep->ep.name, t1, t2, - (t2 & (1 << ALT_NAK_OUT_PACKETS)) ? "NAK " : "", - (t2 & (1 << HIDE_STATUS_PHASE)) ? "hide " : "", - (t2 & (1 << AUTOVALIDATE)) ? "auto " : "", - (t2 & (1 << INTERRUPT_MODE)) ? "interrupt " : "", - (t2 & (1 << CONTROL_STATUS_PHASE_HANDSHAKE)) ? "status " : "", - (t2 & (1 << NAK_OUT_PACKETS_MODE)) ? "NAKmode " : "", - (t2 & (1 << ENDPOINT_TOGGLE)) ? "DATA1 " : "DATA0 ", - (t2 & (1 << ENDPOINT_HALT)) ? "HALT " : "", - net2272_ep_read(ep, EP_IRQENB)); - size -= t; - next += t; - - t = scnprintf(next, size, - "\tstat0 %02x stat1 %02x avail %04x " - "(ep%d%s-%s)%s\n", - net2272_ep_read(ep, EP_STAT0), - net2272_ep_read(ep, EP_STAT1), - (net2272_ep_read(ep, EP_AVAIL1) << 8) | net2272_ep_read(ep, EP_AVAIL0), - t1 & 0x0f, - ep->is_in ? "in" : "out", - type_string(t1 >> 5), - ep->stopped ? "*" : ""); - size -= t; - next += t; - - t = scnprintf(next, size, - "\tep_transfer %06x\n", - ((net2272_ep_read(ep, EP_TRANSFER2) & 0xff) << 16) | - ((net2272_ep_read(ep, EP_TRANSFER1) & 0xff) << 8) | - ((net2272_ep_read(ep, EP_TRANSFER0) & 0xff))); - size -= t; - next += t; - - t1 = net2272_ep_read(ep, EP_BUFF_STATES) & 0x03; - t2 = (net2272_ep_read(ep, EP_BUFF_STATES) >> 2) & 0x03; - t = scnprintf(next, size, - "\tbuf-a %s buf-b %s\n", - buf_state_string(t1), - buf_state_string(t2)); - size -= t; - next += t; - } - - spin_unlock_irqrestore(&dev->lock, flags); - - return PAGE_SIZE - size; -} -static DEVICE_ATTR_RO(registers); - -/*---------------------------------------------------------------------------*/ - -static void -net2272_set_fifo_mode(struct net2272 *dev, int mode) -{ - u8 tmp; - - tmp = net2272_read(dev, LOCCTL) & 0x3f; - tmp |= (mode << 6); - net2272_write(dev, LOCCTL, tmp); - - INIT_LIST_HEAD(&dev->gadget.ep_list); - - /* always ep-a, ep-c ... maybe not ep-b */ - list_add_tail(&dev->ep[1].ep.ep_list, &dev->gadget.ep_list); - - switch (mode) { - case 0: - list_add_tail(&dev->ep[2].ep.ep_list, &dev->gadget.ep_list); - dev->ep[1].fifo_size = dev->ep[2].fifo_size = 512; - break; - case 1: - list_add_tail(&dev->ep[2].ep.ep_list, &dev->gadget.ep_list); - dev->ep[1].fifo_size = 1024; - dev->ep[2].fifo_size = 512; - break; - case 2: - list_add_tail(&dev->ep[2].ep.ep_list, &dev->gadget.ep_list); - dev->ep[1].fifo_size = dev->ep[2].fifo_size = 1024; - break; - case 3: - dev->ep[1].fifo_size = 1024; - break; - } - - /* ep-c is always 2 512 byte buffers */ - list_add_tail(&dev->ep[3].ep.ep_list, &dev->gadget.ep_list); - dev->ep[3].fifo_size = 512; -} - -/*---------------------------------------------------------------------------*/ - -static void -net2272_usb_reset(struct net2272 *dev) -{ - dev->gadget.speed = USB_SPEED_UNKNOWN; - - net2272_cancel_dma(dev); - - net2272_write(dev, IRQENB0, 0); - net2272_write(dev, IRQENB1, 0); - - /* clear irq state */ - net2272_write(dev, IRQSTAT0, 0xff); - net2272_write(dev, IRQSTAT1, ~(1 << SUSPEND_REQUEST_INTERRUPT)); - - net2272_write(dev, DMAREQ, - (0 << DMA_BUFFER_VALID) | - (0 << DMA_REQUEST_ENABLE) | - (1 << DMA_CONTROL_DACK) | - (dev->dma_eot_polarity << EOT_POLARITY) | - (dev->dma_dack_polarity << DACK_POLARITY) | - (dev->dma_dreq_polarity << DREQ_POLARITY) | - ((dma_ep >> 1) << DMA_ENDPOINT_SELECT)); - - net2272_cancel_dma(dev); - net2272_set_fifo_mode(dev, (fifo_mode <= 3) ? fifo_mode : 0); - - /* Set the NET2272 ep fifo data width to 16-bit mode and for correct byte swapping - * note that the higher level gadget drivers are expected to convert data to little endian. - * Enable byte swap for your local bus/cpu if needed by setting BYTE_SWAP in LOCCTL here - */ - net2272_write(dev, LOCCTL, net2272_read(dev, LOCCTL) | (1 << DATA_WIDTH)); - net2272_write(dev, LOCCTL1, (dma_mode << DMA_MODE)); -} - -static void -net2272_usb_reinit(struct net2272 *dev) -{ - int i; - - /* basic endpoint init */ - for (i = 0; i < 4; ++i) { - struct net2272_ep *ep = &dev->ep[i]; - - ep->ep.name = ep_name[i]; - ep->dev = dev; - ep->num = i; - ep->not_empty = 0; - - if (use_dma && ep->num == dma_ep) - ep->dma = 1; - - if (i > 0 && i <= 3) - ep->fifo_size = 512; - else - ep->fifo_size = 64; - net2272_ep_reset(ep); - - if (i == 0) { - ep->ep.caps.type_control = true; - } else { - ep->ep.caps.type_iso = true; - ep->ep.caps.type_bulk = true; - ep->ep.caps.type_int = true; - } - - ep->ep.caps.dir_in = true; - ep->ep.caps.dir_out = true; - } - usb_ep_set_maxpacket_limit(&dev->ep[0].ep, 64); - - dev->gadget.ep0 = &dev->ep[0].ep; - dev->ep[0].stopped = 0; - INIT_LIST_HEAD(&dev->gadget.ep0->ep_list); -} - -static void -net2272_ep0_start(struct net2272 *dev) -{ - struct net2272_ep *ep0 = &dev->ep[0]; - - net2272_ep_write(ep0, EP_RSPSET, - (1 << NAK_OUT_PACKETS_MODE) | - (1 << ALT_NAK_OUT_PACKETS)); - net2272_ep_write(ep0, EP_RSPCLR, - (1 << HIDE_STATUS_PHASE) | - (1 << CONTROL_STATUS_PHASE_HANDSHAKE)); - net2272_write(dev, USBCTL0, - (dev->softconnect << USB_DETECT_ENABLE) | - (1 << USB_ROOT_PORT_WAKEUP_ENABLE) | - (1 << IO_WAKEUP_ENABLE)); - net2272_write(dev, IRQENB0, - (1 << SETUP_PACKET_INTERRUPT_ENABLE) | - (1 << ENDPOINT_0_INTERRUPT_ENABLE) | - (1 << DMA_DONE_INTERRUPT_ENABLE)); - net2272_write(dev, IRQENB1, - (1 << VBUS_INTERRUPT_ENABLE) | - (1 << ROOT_PORT_RESET_INTERRUPT_ENABLE) | - (1 << SUSPEND_REQUEST_CHANGE_INTERRUPT_ENABLE)); -} - -/* when a driver is successfully registered, it will receive - * control requests including set_configuration(), which enables - * non-control requests. then usb traffic follows until a - * disconnect is reported. then a host may connect again, or - * the driver might get unbound. - */ -static int net2272_start(struct usb_gadget *_gadget, - struct usb_gadget_driver *driver) -{ - struct net2272 *dev; - unsigned i; - - if (!driver || !driver->setup || - driver->max_speed != USB_SPEED_HIGH) - return -EINVAL; - - dev = container_of(_gadget, struct net2272, gadget); - - for (i = 0; i < 4; ++i) - dev->ep[i].irqs = 0; - /* hook up the driver ... */ - dev->softconnect = 1; - dev->driver = driver; - - /* ... then enable host detection and ep0; and we're ready - * for set_configuration as well as eventual disconnect. - */ - net2272_ep0_start(dev); - - return 0; -} - -static void -stop_activity(struct net2272 *dev, struct usb_gadget_driver *driver) -{ - int i; - - /* don't disconnect if it's not connected */ - if (dev->gadget.speed == USB_SPEED_UNKNOWN) - driver = NULL; - - /* stop hardware; prevent new request submissions; - * and kill any outstanding requests. - */ - net2272_usb_reset(dev); - for (i = 0; i < 4; ++i) - net2272_dequeue_all(&dev->ep[i]); - - /* report disconnect; the driver is already quiesced */ - if (dev->async_callbacks && driver) { - spin_unlock(&dev->lock); - driver->disconnect(&dev->gadget); - spin_lock(&dev->lock); - } - - net2272_usb_reinit(dev); -} - -static int net2272_stop(struct usb_gadget *_gadget) -{ - struct net2272 *dev; - unsigned long flags; - - dev = container_of(_gadget, struct net2272, gadget); - - spin_lock_irqsave(&dev->lock, flags); - stop_activity(dev, NULL); - spin_unlock_irqrestore(&dev->lock, flags); - - dev->driver = NULL; - - return 0; -} - -static void net2272_async_callbacks(struct usb_gadget *_gadget, bool enable) -{ - struct net2272 *dev = container_of(_gadget, struct net2272, gadget); - - spin_lock_irq(&dev->lock); - dev->async_callbacks = enable; - spin_unlock_irq(&dev->lock); -} - -/*---------------------------------------------------------------------------*/ -/* handle ep-a/ep-b dma completions */ -static void -net2272_handle_dma(struct net2272_ep *ep) -{ - struct net2272_request *req; - unsigned len; - int status; - - if (!list_empty(&ep->queue)) - req = list_entry(ep->queue.next, - struct net2272_request, queue); - else - req = NULL; - - dev_vdbg(ep->dev->dev, "handle_dma %s req %p\n", ep->ep.name, req); - - /* Ensure DREQ is de-asserted */ - net2272_write(ep->dev, DMAREQ, - (0 << DMA_BUFFER_VALID) - | (0 << DMA_REQUEST_ENABLE) - | (1 << DMA_CONTROL_DACK) - | (ep->dev->dma_eot_polarity << EOT_POLARITY) - | (ep->dev->dma_dack_polarity << DACK_POLARITY) - | (ep->dev->dma_dreq_polarity << DREQ_POLARITY) - | (ep->dma << DMA_ENDPOINT_SELECT)); - - ep->dev->dma_busy = 0; - - net2272_ep_write(ep, EP_IRQENB, - (1 << DATA_PACKET_RECEIVED_INTERRUPT_ENABLE) - | (1 << DATA_PACKET_TRANSMITTED_INTERRUPT_ENABLE) - | net2272_ep_read(ep, EP_IRQENB)); - - /* device-to-host transfer completed */ - if (ep->is_in) { - /* validate a short packet or zlp if necessary */ - if ((req->req.length % ep->ep.maxpacket != 0) || - req->req.zero) - set_fifo_bytecount(ep, 0); - - net2272_done(ep, req, 0); - if (!list_empty(&ep->queue)) { - req = list_entry(ep->queue.next, - struct net2272_request, queue); - status = net2272_kick_dma(ep, req); - if (status < 0) - net2272_pio_advance(ep); - } - - /* host-to-device transfer completed */ - } else { - /* terminated with a short packet? */ - if (net2272_read(ep->dev, IRQSTAT0) & - (1 << DMA_DONE_INTERRUPT)) { - /* abort system dma */ - net2272_cancel_dma(ep->dev); - } - - /* EP_TRANSFER will contain the number of bytes - * actually received. - * NOTE: There is no overflow detection on EP_TRANSFER: - * We can't deal with transfers larger than 2^24 bytes! - */ - len = (net2272_ep_read(ep, EP_TRANSFER2) << 16) - | (net2272_ep_read(ep, EP_TRANSFER1) << 8) - | (net2272_ep_read(ep, EP_TRANSFER0)); - - if (ep->not_empty) - len += 4; - - req->req.actual += len; - - /* get any remaining data */ - net2272_pio_advance(ep); - } -} - -/*---------------------------------------------------------------------------*/ - -static void -net2272_handle_ep(struct net2272_ep *ep) -{ - struct net2272_request *req; - u8 stat0, stat1; - - if (!list_empty(&ep->queue)) - req = list_entry(ep->queue.next, - struct net2272_request, queue); - else - req = NULL; - - /* ack all, and handle what we care about */ - stat0 = net2272_ep_read(ep, EP_STAT0); - stat1 = net2272_ep_read(ep, EP_STAT1); - ep->irqs++; - - dev_vdbg(ep->dev->dev, "%s ack ep_stat0 %02x, ep_stat1 %02x, req %p\n", - ep->ep.name, stat0, stat1, req ? &req->req : NULL); - - net2272_ep_write(ep, EP_STAT0, stat0 & - ~((1 << NAK_OUT_PACKETS) - | (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT))); - net2272_ep_write(ep, EP_STAT1, stat1); - - /* data packet(s) received (in the fifo, OUT) - * direction must be validated, otherwise control read status phase - * could be interpreted as a valid packet - */ - if (!ep->is_in && (stat0 & (1 << DATA_PACKET_RECEIVED_INTERRUPT))) - net2272_pio_advance(ep); - /* data packet(s) transmitted (IN) */ - else if (stat0 & (1 << DATA_PACKET_TRANSMITTED_INTERRUPT)) - net2272_pio_advance(ep); -} - -static struct net2272_ep * -net2272_get_ep_by_addr(struct net2272 *dev, u16 wIndex) -{ - struct net2272_ep *ep; - - if ((wIndex & USB_ENDPOINT_NUMBER_MASK) == 0) - return &dev->ep[0]; - - list_for_each_entry(ep, &dev->gadget.ep_list, ep.ep_list) { - u8 bEndpointAddress; - - if (!ep->desc) - continue; - bEndpointAddress = ep->desc->bEndpointAddress; - if ((wIndex ^ bEndpointAddress) & USB_DIR_IN) - continue; - if ((wIndex & 0x0f) == (bEndpointAddress & 0x0f)) - return ep; - } - return NULL; -} - -/* - * USB Test Packet: - * JKJKJKJK * 9 - * JJKKJJKK * 8 - * JJJJKKKK * 8 - * JJJJJJJKKKKKKK * 8 - * JJJJJJJK * 8 - * {JKKKKKKK * 10}, JK - */ -static const u8 net2272_test_packet[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, - 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, - 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0x7F, 0xBF, 0xDF, 0xEF, 0xF7, 0xFB, 0xFD, - 0xFC, 0x7E, 0xBF, 0xDF, 0xEF, 0xF7, 0xFD, 0x7E -}; - -static void -net2272_set_test_mode(struct net2272 *dev, int mode) -{ - int i; - - /* Disable all net2272 interrupts: - * Nothing but a power cycle should stop the test. - */ - net2272_write(dev, IRQENB0, 0x00); - net2272_write(dev, IRQENB1, 0x00); - - /* Force tranceiver to high-speed */ - net2272_write(dev, XCVRDIAG, 1 << FORCE_HIGH_SPEED); - - net2272_write(dev, PAGESEL, 0); - net2272_write(dev, EP_STAT0, 1 << DATA_PACKET_TRANSMITTED_INTERRUPT); - net2272_write(dev, EP_RSPCLR, - (1 << CONTROL_STATUS_PHASE_HANDSHAKE) - | (1 << HIDE_STATUS_PHASE)); - net2272_write(dev, EP_CFG, 1 << ENDPOINT_DIRECTION); - net2272_write(dev, EP_STAT1, 1 << BUFFER_FLUSH); - - /* wait for status phase to complete */ - while (!(net2272_read(dev, EP_STAT0) & - (1 << DATA_PACKET_TRANSMITTED_INTERRUPT))) - ; - - /* Enable test mode */ - net2272_write(dev, USBTEST, mode); - - /* load test packet */ - if (mode == USB_TEST_PACKET) { - /* switch to 8 bit mode */ - net2272_write(dev, LOCCTL, net2272_read(dev, LOCCTL) & - ~(1 << DATA_WIDTH)); - - for (i = 0; i < sizeof(net2272_test_packet); ++i) - net2272_write(dev, EP_DATA, net2272_test_packet[i]); - - /* Validate test packet */ - net2272_write(dev, EP_TRANSFER0, 0); - } -} - -static void -net2272_handle_stat0_irqs(struct net2272 *dev, u8 stat) -{ - struct net2272_ep *ep; - u8 num, scratch; - - /* starting a control request? */ - if (unlikely(stat & (1 << SETUP_PACKET_INTERRUPT))) { - union { - u8 raw[8]; - struct usb_ctrlrequest r; - } u; - int tmp = 0; - struct net2272_request *req; - - if (dev->gadget.speed == USB_SPEED_UNKNOWN) { - if (net2272_read(dev, USBCTL1) & (1 << USB_HIGH_SPEED)) - dev->gadget.speed = USB_SPEED_HIGH; - else - dev->gadget.speed = USB_SPEED_FULL; - dev_dbg(dev->dev, "%s\n", - usb_speed_string(dev->gadget.speed)); - } - - ep = &dev->ep[0]; - ep->irqs++; - - /* make sure any leftover interrupt state is cleared */ - stat &= ~(1 << ENDPOINT_0_INTERRUPT); - while (!list_empty(&ep->queue)) { - req = list_entry(ep->queue.next, - struct net2272_request, queue); - net2272_done(ep, req, - (req->req.actual == req->req.length) ? 0 : -EPROTO); - } - ep->stopped = 0; - dev->protocol_stall = 0; - net2272_ep_write(ep, EP_STAT0, - (1 << DATA_IN_TOKEN_INTERRUPT) - | (1 << DATA_OUT_TOKEN_INTERRUPT) - | (1 << DATA_PACKET_TRANSMITTED_INTERRUPT) - | (1 << DATA_PACKET_RECEIVED_INTERRUPT) - | (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT)); - net2272_ep_write(ep, EP_STAT1, - (1 << TIMEOUT) - | (1 << USB_OUT_ACK_SENT) - | (1 << USB_OUT_NAK_SENT) - | (1 << USB_IN_ACK_RCVD) - | (1 << USB_IN_NAK_SENT) - | (1 << USB_STALL_SENT) - | (1 << LOCAL_OUT_ZLP)); - - /* - * Ensure Control Read pre-validation setting is beyond maximum size - * - Control Writes can leave non-zero values in EP_TRANSFER. If - * an EP0 transfer following the Control Write is a Control Read, - * the NET2272 sees the non-zero EP_TRANSFER as an unexpected - * pre-validation count. - * - Setting EP_TRANSFER beyond the maximum EP0 transfer size ensures - * the pre-validation count cannot cause an unexpected validatation - */ - net2272_write(dev, PAGESEL, 0); - net2272_write(dev, EP_TRANSFER2, 0xff); - net2272_write(dev, EP_TRANSFER1, 0xff); - net2272_write(dev, EP_TRANSFER0, 0xff); - - u.raw[0] = net2272_read(dev, SETUP0); - u.raw[1] = net2272_read(dev, SETUP1); - u.raw[2] = net2272_read(dev, SETUP2); - u.raw[3] = net2272_read(dev, SETUP3); - u.raw[4] = net2272_read(dev, SETUP4); - u.raw[5] = net2272_read(dev, SETUP5); - u.raw[6] = net2272_read(dev, SETUP6); - u.raw[7] = net2272_read(dev, SETUP7); - /* - * If you have a big endian cpu make sure le16_to_cpus - * performs the proper byte swapping here... - */ - le16_to_cpus(&u.r.wValue); - le16_to_cpus(&u.r.wIndex); - le16_to_cpus(&u.r.wLength); - - /* ack the irq */ - net2272_write(dev, IRQSTAT0, 1 << SETUP_PACKET_INTERRUPT); - stat ^= (1 << SETUP_PACKET_INTERRUPT); - - /* watch control traffic at the token level, and force - * synchronization before letting the status phase happen. - */ - ep->is_in = (u.r.bRequestType & USB_DIR_IN) != 0; - if (ep->is_in) { - scratch = (1 << DATA_PACKET_TRANSMITTED_INTERRUPT_ENABLE) - | (1 << DATA_OUT_TOKEN_INTERRUPT_ENABLE) - | (1 << DATA_IN_TOKEN_INTERRUPT_ENABLE); - stop_out_naking(ep); - } else - scratch = (1 << DATA_PACKET_RECEIVED_INTERRUPT_ENABLE) - | (1 << DATA_OUT_TOKEN_INTERRUPT_ENABLE) - | (1 << DATA_IN_TOKEN_INTERRUPT_ENABLE); - net2272_ep_write(ep, EP_IRQENB, scratch); - - if ((u.r.bRequestType & USB_TYPE_MASK) != USB_TYPE_STANDARD) - goto delegate; - switch (u.r.bRequest) { - case USB_REQ_GET_STATUS: { - struct net2272_ep *e; - u16 status = 0; - - switch (u.r.bRequestType & USB_RECIP_MASK) { - case USB_RECIP_ENDPOINT: - e = net2272_get_ep_by_addr(dev, u.r.wIndex); - if (!e || u.r.wLength > 2) - goto do_stall; - if (net2272_ep_read(e, EP_RSPSET) & (1 << ENDPOINT_HALT)) - status = cpu_to_le16(1); - else - status = cpu_to_le16(0); - - /* don't bother with a request object! */ - net2272_ep_write(&dev->ep[0], EP_IRQENB, 0); - writew(status, net2272_reg_addr(dev, EP_DATA)); - set_fifo_bytecount(&dev->ep[0], 0); - allow_status(ep); - dev_vdbg(dev->dev, "%s stat %02x\n", - ep->ep.name, status); - goto next_endpoints; - case USB_RECIP_DEVICE: - if (u.r.wLength > 2) - goto do_stall; - if (dev->gadget.is_selfpowered) - status = (1 << USB_DEVICE_SELF_POWERED); - - /* don't bother with a request object! */ - net2272_ep_write(&dev->ep[0], EP_IRQENB, 0); - writew(status, net2272_reg_addr(dev, EP_DATA)); - set_fifo_bytecount(&dev->ep[0], 0); - allow_status(ep); - dev_vdbg(dev->dev, "device stat %02x\n", status); - goto next_endpoints; - case USB_RECIP_INTERFACE: - if (u.r.wLength > 2) - goto do_stall; - - /* don't bother with a request object! */ - net2272_ep_write(&dev->ep[0], EP_IRQENB, 0); - writew(status, net2272_reg_addr(dev, EP_DATA)); - set_fifo_bytecount(&dev->ep[0], 0); - allow_status(ep); - dev_vdbg(dev->dev, "interface status %02x\n", status); - goto next_endpoints; - } - - break; - } - case USB_REQ_CLEAR_FEATURE: { - struct net2272_ep *e; - - if (u.r.bRequestType != USB_RECIP_ENDPOINT) - goto delegate; - if (u.r.wValue != USB_ENDPOINT_HALT || - u.r.wLength != 0) - goto do_stall; - e = net2272_get_ep_by_addr(dev, u.r.wIndex); - if (!e) - goto do_stall; - if (e->wedged) { - dev_vdbg(dev->dev, "%s wedged, halt not cleared\n", - ep->ep.name); - } else { - dev_vdbg(dev->dev, "%s clear halt\n", ep->ep.name); - clear_halt(e); - } - allow_status(ep); - goto next_endpoints; - } - case USB_REQ_SET_FEATURE: { - struct net2272_ep *e; - - if (u.r.bRequestType == USB_RECIP_DEVICE) { - if (u.r.wIndex != NORMAL_OPERATION) - net2272_set_test_mode(dev, (u.r.wIndex >> 8)); - allow_status(ep); - dev_vdbg(dev->dev, "test mode: %d\n", u.r.wIndex); - goto next_endpoints; - } else if (u.r.bRequestType != USB_RECIP_ENDPOINT) - goto delegate; - if (u.r.wValue != USB_ENDPOINT_HALT || - u.r.wLength != 0) - goto do_stall; - e = net2272_get_ep_by_addr(dev, u.r.wIndex); - if (!e) - goto do_stall; - set_halt(e); - allow_status(ep); - dev_vdbg(dev->dev, "%s set halt\n", ep->ep.name); - goto next_endpoints; - } - case USB_REQ_SET_ADDRESS: { - net2272_write(dev, OURADDR, u.r.wValue & 0xff); - allow_status(ep); - break; - } - default: - delegate: - dev_vdbg(dev->dev, "setup %02x.%02x v%04x i%04x " - "ep_cfg %08x\n", - u.r.bRequestType, u.r.bRequest, - u.r.wValue, u.r.wIndex, - net2272_ep_read(ep, EP_CFG)); - if (dev->async_callbacks) { - spin_unlock(&dev->lock); - tmp = dev->driver->setup(&dev->gadget, &u.r); - spin_lock(&dev->lock); - } - } - - /* stall ep0 on error */ - if (tmp < 0) { - do_stall: - dev_vdbg(dev->dev, "req %02x.%02x protocol STALL; stat %d\n", - u.r.bRequestType, u.r.bRequest, tmp); - dev->protocol_stall = 1; - } - /* endpoint dma irq? */ - } else if (stat & (1 << DMA_DONE_INTERRUPT)) { - net2272_cancel_dma(dev); - net2272_write(dev, IRQSTAT0, 1 << DMA_DONE_INTERRUPT); - stat &= ~(1 << DMA_DONE_INTERRUPT); - num = (net2272_read(dev, DMAREQ) & (1 << DMA_ENDPOINT_SELECT)) - ? 2 : 1; - - ep = &dev->ep[num]; - net2272_handle_dma(ep); - } - - next_endpoints: - /* endpoint data irq? */ - scratch = stat & 0x0f; - stat &= ~0x0f; - for (num = 0; scratch; num++) { - u8 t; - - /* does this endpoint's FIFO and queue need tending? */ - t = 1 << num; - if ((scratch & t) == 0) - continue; - scratch ^= t; - - ep = &dev->ep[num]; - net2272_handle_ep(ep); - } - - /* some interrupts we can just ignore */ - stat &= ~(1 << SOF_INTERRUPT); - - if (stat) - dev_dbg(dev->dev, "unhandled irqstat0 %02x\n", stat); -} - -static void -net2272_handle_stat1_irqs(struct net2272 *dev, u8 stat) -{ - u8 tmp, mask; - - /* after disconnect there's nothing else to do! */ - tmp = (1 << VBUS_INTERRUPT) | (1 << ROOT_PORT_RESET_INTERRUPT); - mask = (1 << USB_HIGH_SPEED) | (1 << USB_FULL_SPEED); - - if (stat & tmp) { - bool reset = false; - bool disconnect = false; - - /* - * Ignore disconnects and resets if the speed hasn't been set. - * VBUS can bounce and there's always an initial reset. - */ - net2272_write(dev, IRQSTAT1, tmp); - if (dev->gadget.speed != USB_SPEED_UNKNOWN) { - if ((stat & (1 << VBUS_INTERRUPT)) && - (net2272_read(dev, USBCTL1) & - (1 << VBUS_PIN)) == 0) { - disconnect = true; - dev_dbg(dev->dev, "disconnect %s\n", - dev->driver->driver.name); - } else if ((stat & (1 << ROOT_PORT_RESET_INTERRUPT)) && - (net2272_read(dev, USBCTL1) & mask) - == 0) { - reset = true; - dev_dbg(dev->dev, "reset %s\n", - dev->driver->driver.name); - } - - if (disconnect || reset) { - stop_activity(dev, dev->driver); - net2272_ep0_start(dev); - if (dev->async_callbacks) { - 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; - } - } - stat &= ~tmp; - - if (!stat) - return; - } - - tmp = (1 << SUSPEND_REQUEST_CHANGE_INTERRUPT); - if (stat & tmp) { - net2272_write(dev, IRQSTAT1, tmp); - if (stat & (1 << SUSPEND_REQUEST_INTERRUPT)) { - if (dev->async_callbacks && dev->driver->suspend) - dev->driver->suspend(&dev->gadget); - if (!enable_suspend) { - stat &= ~(1 << SUSPEND_REQUEST_INTERRUPT); - dev_dbg(dev->dev, "Suspend disabled, ignoring\n"); - } - } else { - if (dev->async_callbacks && dev->driver->resume) - dev->driver->resume(&dev->gadget); - } - stat &= ~tmp; - } - - /* clear any other status/irqs */ - if (stat) - net2272_write(dev, IRQSTAT1, stat); - - /* some status we can just ignore */ - stat &= ~((1 << CONTROL_STATUS_INTERRUPT) - | (1 << SUSPEND_REQUEST_INTERRUPT) - | (1 << RESUME_INTERRUPT)); - if (!stat) - return; - else - dev_dbg(dev->dev, "unhandled irqstat1 %02x\n", stat); -} - -static irqreturn_t net2272_irq(int irq, void *_dev) -{ - struct net2272 *dev = _dev; -#if defined(PLX_PCI_RDK) || defined(PLX_PCI_RDK2) - u32 intcsr; -#endif -#if defined(PLX_PCI_RDK) - u8 dmareq; -#endif - spin_lock(&dev->lock); -#if defined(PLX_PCI_RDK) - intcsr = readl(dev->rdk1.plx9054_base_addr + INTCSR); - - if ((intcsr & LOCAL_INTERRUPT_TEST) == LOCAL_INTERRUPT_TEST) { - writel(intcsr & ~(1 << PCI_INTERRUPT_ENABLE), - dev->rdk1.plx9054_base_addr + INTCSR); - net2272_handle_stat1_irqs(dev, net2272_read(dev, IRQSTAT1)); - net2272_handle_stat0_irqs(dev, net2272_read(dev, IRQSTAT0)); - intcsr = readl(dev->rdk1.plx9054_base_addr + INTCSR); - writel(intcsr | (1 << PCI_INTERRUPT_ENABLE), - dev->rdk1.plx9054_base_addr + INTCSR); - } - if ((intcsr & DMA_CHANNEL_0_TEST) == DMA_CHANNEL_0_TEST) { - writeb((1 << CHANNEL_CLEAR_INTERRUPT | (0 << CHANNEL_ENABLE)), - dev->rdk1.plx9054_base_addr + DMACSR0); - - dmareq = net2272_read(dev, DMAREQ); - if (dmareq & 0x01) - net2272_handle_dma(&dev->ep[2]); - else - net2272_handle_dma(&dev->ep[1]); - } -#endif -#if defined(PLX_PCI_RDK2) - /* see if PCI int for us by checking irqstat */ - intcsr = readl(dev->rdk2.fpga_base_addr + RDK2_IRQSTAT); - if (!(intcsr & (1 << NET2272_PCI_IRQ))) { - spin_unlock(&dev->lock); - return IRQ_NONE; - } - /* check dma interrupts */ -#endif - /* Platform/device interrupt handler */ -#if !defined(PLX_PCI_RDK) - net2272_handle_stat1_irqs(dev, net2272_read(dev, IRQSTAT1)); - net2272_handle_stat0_irqs(dev, net2272_read(dev, IRQSTAT0)); -#endif - spin_unlock(&dev->lock); - - return IRQ_HANDLED; -} - -static int net2272_present(struct net2272 *dev) -{ - /* - * Quick test to see if CPU can communicate properly with the NET2272. - * Verifies connection using writes and reads to write/read and - * read-only registers. - * - * This routine is strongly recommended especially during early bring-up - * of new hardware, however for designs that do not apply Power On System - * Tests (POST) it may discarded (or perhaps minimized). - */ - unsigned int ii; - u8 val, refval; - - /* Verify NET2272 write/read SCRATCH register can write and read */ - refval = net2272_read(dev, SCRATCH); - for (ii = 0; ii < 0x100; ii += 7) { - net2272_write(dev, SCRATCH, ii); - val = net2272_read(dev, SCRATCH); - if (val != ii) { - dev_dbg(dev->dev, - "%s: write/read SCRATCH register test failed: " - "wrote:0x%2.2x, read:0x%2.2x\n", - __func__, ii, val); - return -EINVAL; - } - } - /* To be nice, we write the original SCRATCH value back: */ - net2272_write(dev, SCRATCH, refval); - - /* Verify NET2272 CHIPREV register is read-only: */ - refval = net2272_read(dev, CHIPREV_2272); - for (ii = 0; ii < 0x100; ii += 7) { - net2272_write(dev, CHIPREV_2272, ii); - val = net2272_read(dev, CHIPREV_2272); - if (val != refval) { - dev_dbg(dev->dev, - "%s: write/read CHIPREV register test failed: " - "wrote 0x%2.2x, read:0x%2.2x expected:0x%2.2x\n", - __func__, ii, val, refval); - return -EINVAL; - } - } - - /* - * Verify NET2272's "NET2270 legacy revision" register - * - NET2272 has two revision registers. The NET2270 legacy revision - * register should read the same value, regardless of the NET2272 - * silicon revision. The legacy register applies to NET2270 - * firmware being applied to the NET2272. - */ - val = net2272_read(dev, CHIPREV_LEGACY); - if (val != NET2270_LEGACY_REV) { - /* - * Unexpected legacy revision value - * - Perhaps the chip is a NET2270? - */ - dev_dbg(dev->dev, - "%s: WARNING: UNEXPECTED NET2272 LEGACY REGISTER VALUE:\n" - " - CHIPREV_LEGACY: expected 0x%2.2x, got:0x%2.2x. (Not NET2272?)\n", - __func__, NET2270_LEGACY_REV, val); - return -EINVAL; - } - - /* - * Verify NET2272 silicon revision - * - This revision register is appropriate for the silicon version - * of the NET2272 - */ - val = net2272_read(dev, CHIPREV_2272); - switch (val) { - case CHIPREV_NET2272_R1: - /* - * NET2272 Rev 1 has DMA related errata: - * - Newer silicon (Rev 1A or better) required - */ - dev_dbg(dev->dev, - "%s: Rev 1 detected: newer silicon recommended for DMA support\n", - __func__); - break; - case CHIPREV_NET2272_R1A: - break; - default: - /* NET2272 silicon version *may* not work with this firmware */ - dev_dbg(dev->dev, - "%s: unexpected silicon revision register value: " - " CHIPREV_2272: 0x%2.2x\n", - __func__, val); - /* - * Return Success, even though the chip rev is not an expected value - * - Older, pre-built firmware can attempt to operate on newer silicon - * - Often, new silicon is perfectly compatible - */ - } - - /* Success: NET2272 checks out OK */ - return 0; -} - -static void -net2272_gadget_release(struct device *_dev) -{ - struct net2272 *dev = container_of(_dev, struct net2272, gadget.dev); - - kfree(dev); -} - -/*---------------------------------------------------------------------------*/ - -static void -net2272_remove(struct net2272 *dev) -{ - if (dev->added) - usb_del_gadget(&dev->gadget); - free_irq(dev->irq, dev); - iounmap(dev->base_addr); - device_remove_file(dev->dev, &dev_attr_registers); - - dev_info(dev->dev, "unbind\n"); -} - -static struct net2272 *net2272_probe_init(struct device *dev, unsigned int irq) -{ - struct net2272 *ret; - - if (!irq) { - dev_dbg(dev, "No IRQ!\n"); - return ERR_PTR(-ENODEV); - } - - /* alloc, and start init */ - ret = kzalloc(sizeof(*ret), GFP_KERNEL); - if (!ret) - return ERR_PTR(-ENOMEM); - - spin_lock_init(&ret->lock); - ret->irq = irq; - ret->dev = dev; - ret->gadget.ops = &net2272_ops; - ret->gadget.max_speed = USB_SPEED_HIGH; - - /* the "gadget" abstracts/virtualizes the controller */ - ret->gadget.name = driver_name; - usb_initialize_gadget(dev, &ret->gadget, net2272_gadget_release); - - return ret; -} - -static int -net2272_probe_fin(struct net2272 *dev, unsigned int irqflags) -{ - int ret; - - /* See if there... */ - if (net2272_present(dev)) { - dev_warn(dev->dev, "2272 not found!\n"); - ret = -ENODEV; - goto err; - } - - net2272_usb_reset(dev); - net2272_usb_reinit(dev); - - ret = request_irq(dev->irq, net2272_irq, irqflags, driver_name, dev); - if (ret) { - dev_err(dev->dev, "request interrupt %i failed\n", dev->irq); - goto err; - } - - dev->chiprev = net2272_read(dev, CHIPREV_2272); - - /* done */ - dev_info(dev->dev, "%s\n", driver_desc); - dev_info(dev->dev, "irq %i, mem %p, chip rev %04x, dma %s\n", - dev->irq, dev->base_addr, dev->chiprev, - dma_mode_string()); - dev_info(dev->dev, "version: %s\n", driver_vers); - - ret = device_create_file(dev->dev, &dev_attr_registers); - if (ret) - goto err_irq; - - ret = usb_add_gadget(&dev->gadget); - if (ret) - goto err_add_udc; - dev->added = 1; - - return 0; - -err_add_udc: - device_remove_file(dev->dev, &dev_attr_registers); - err_irq: - free_irq(dev->irq, dev); - err: - return ret; -} - -#ifdef CONFIG_USB_PCI - -/* - * wrap this driver around the specified device, but - * don't respond over USB until a gadget driver binds to us - */ - -static int -net2272_rdk1_probe(struct pci_dev *pdev, struct net2272 *dev) -{ - unsigned long resource, len, tmp; - void __iomem *mem_mapped_addr[4]; - int ret, i; - - /* - * BAR 0 holds PLX 9054 config registers - * BAR 1 is i/o memory; unused here - * BAR 2 holds EPLD config registers - * BAR 3 holds NET2272 registers - */ - - /* Find and map all address spaces */ - for (i = 0; i < 4; ++i) { - if (i == 1) - continue; /* BAR1 unused */ - - resource = pci_resource_start(pdev, i); - len = pci_resource_len(pdev, i); - - if (!request_mem_region(resource, len, driver_name)) { - dev_dbg(dev->dev, "controller already in use\n"); - ret = -EBUSY; - goto err; - } - - mem_mapped_addr[i] = ioremap(resource, len); - if (mem_mapped_addr[i] == NULL) { - release_mem_region(resource, len); - dev_dbg(dev->dev, "can't map memory\n"); - ret = -EFAULT; - goto err; - } - } - - dev->rdk1.plx9054_base_addr = mem_mapped_addr[0]; - dev->rdk1.epld_base_addr = mem_mapped_addr[2]; - dev->base_addr = mem_mapped_addr[3]; - - /* Set PLX 9054 bus width (16 bits) */ - tmp = readl(dev->rdk1.plx9054_base_addr + LBRD1); - writel((tmp & ~(3 << MEMORY_SPACE_LOCAL_BUS_WIDTH)) | W16_BIT, - dev->rdk1.plx9054_base_addr + LBRD1); - - /* Enable PLX 9054 Interrupts */ - writel(readl(dev->rdk1.plx9054_base_addr + INTCSR) | - (1 << PCI_INTERRUPT_ENABLE) | - (1 << LOCAL_INTERRUPT_INPUT_ENABLE), - dev->rdk1.plx9054_base_addr + INTCSR); - - writeb((1 << CHANNEL_CLEAR_INTERRUPT | (0 << CHANNEL_ENABLE)), - dev->rdk1.plx9054_base_addr + DMACSR0); - - /* reset */ - writeb((1 << EPLD_DMA_ENABLE) | - (1 << DMA_CTL_DACK) | - (1 << DMA_TIMEOUT_ENABLE) | - (1 << USER) | - (0 << MPX_MODE) | - (1 << BUSWIDTH) | - (1 << NET2272_RESET), - dev->base_addr + EPLD_IO_CONTROL_REGISTER); - - mb(); - writeb(readb(dev->base_addr + EPLD_IO_CONTROL_REGISTER) & - ~(1 << NET2272_RESET), - dev->base_addr + EPLD_IO_CONTROL_REGISTER); - udelay(200); - - return 0; - - err: - while (--i >= 0) { - if (i == 1) - continue; /* BAR1 unused */ - iounmap(mem_mapped_addr[i]); - release_mem_region(pci_resource_start(pdev, i), - pci_resource_len(pdev, i)); - } - - return ret; -} - -static int -net2272_rdk2_probe(struct pci_dev *pdev, struct net2272 *dev) -{ - unsigned long resource, len; - void __iomem *mem_mapped_addr[2]; - int ret, i; - - /* - * BAR 0 holds FGPA config registers - * BAR 1 holds NET2272 registers - */ - - /* Find and map all address spaces, bar2-3 unused in rdk 2 */ - for (i = 0; i < 2; ++i) { - resource = pci_resource_start(pdev, i); - len = pci_resource_len(pdev, i); - - if (!request_mem_region(resource, len, driver_name)) { - dev_dbg(dev->dev, "controller already in use\n"); - ret = -EBUSY; - goto err; - } - - mem_mapped_addr[i] = ioremap(resource, len); - if (mem_mapped_addr[i] == NULL) { - release_mem_region(resource, len); - dev_dbg(dev->dev, "can't map memory\n"); - ret = -EFAULT; - goto err; - } - } - - dev->rdk2.fpga_base_addr = mem_mapped_addr[0]; - dev->base_addr = mem_mapped_addr[1]; - - mb(); - /* Set 2272 bus width (16 bits) and reset */ - writel((1 << CHIP_RESET), dev->rdk2.fpga_base_addr + RDK2_LOCCTLRDK); - udelay(200); - writel((1 << BUS_WIDTH), dev->rdk2.fpga_base_addr + RDK2_LOCCTLRDK); - /* Print fpga version number */ - dev_info(dev->dev, "RDK2 FPGA version %08x\n", - readl(dev->rdk2.fpga_base_addr + RDK2_FPGAREV)); - /* Enable FPGA Interrupts */ - writel((1 << NET2272_PCI_IRQ), dev->rdk2.fpga_base_addr + RDK2_IRQENB); - - return 0; - - err: - while (--i >= 0) { - iounmap(mem_mapped_addr[i]); - release_mem_region(pci_resource_start(pdev, i), - pci_resource_len(pdev, i)); - } - - return ret; -} - -static int -net2272_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) -{ - struct net2272 *dev; - int ret; - - dev = net2272_probe_init(&pdev->dev, pdev->irq); - if (IS_ERR(dev)) - return PTR_ERR(dev); - dev->dev_id = pdev->device; - - if (pci_enable_device(pdev) < 0) { - ret = -ENODEV; - goto err_put; - } - - pci_set_master(pdev); - - switch (pdev->device) { - case PCI_DEVICE_ID_RDK1: ret = net2272_rdk1_probe(pdev, dev); break; - case PCI_DEVICE_ID_RDK2: ret = net2272_rdk2_probe(pdev, dev); break; - default: BUG(); - } - if (ret) - goto err_pci; - - ret = net2272_probe_fin(dev, 0); - if (ret) - goto err_pci; - - pci_set_drvdata(pdev, dev); - - return 0; - - err_pci: - pci_disable_device(pdev); - err_put: - usb_put_gadget(&dev->gadget); - - return ret; -} - -static void -net2272_rdk1_remove(struct pci_dev *pdev, struct net2272 *dev) -{ - int i; - - /* disable PLX 9054 interrupts */ - writel(readl(dev->rdk1.plx9054_base_addr + INTCSR) & - ~(1 << PCI_INTERRUPT_ENABLE), - dev->rdk1.plx9054_base_addr + INTCSR); - - /* clean up resources allocated during probe() */ - iounmap(dev->rdk1.plx9054_base_addr); - iounmap(dev->rdk1.epld_base_addr); - - for (i = 0; i < 4; ++i) { - if (i == 1) - continue; /* BAR1 unused */ - release_mem_region(pci_resource_start(pdev, i), - pci_resource_len(pdev, i)); - } -} - -static void -net2272_rdk2_remove(struct pci_dev *pdev, struct net2272 *dev) -{ - int i; - - /* disable fpga interrupts - writel(readl(dev->rdk1.plx9054_base_addr + INTCSR) & - ~(1 << PCI_INTERRUPT_ENABLE), - dev->rdk1.plx9054_base_addr + INTCSR); - */ - - /* clean up resources allocated during probe() */ - iounmap(dev->rdk2.fpga_base_addr); - - for (i = 0; i < 2; ++i) - release_mem_region(pci_resource_start(pdev, i), - pci_resource_len(pdev, i)); -} - -static void -net2272_pci_remove(struct pci_dev *pdev) -{ - struct net2272 *dev = pci_get_drvdata(pdev); - - net2272_remove(dev); - - switch (pdev->device) { - case PCI_DEVICE_ID_RDK1: net2272_rdk1_remove(pdev, dev); break; - case PCI_DEVICE_ID_RDK2: net2272_rdk2_remove(pdev, dev); break; - default: BUG(); - } - - pci_disable_device(pdev); - - usb_put_gadget(&dev->gadget); -} - -/* Table of matching PCI IDs */ -static struct pci_device_id pci_ids[] = { - { /* RDK 1 card */ - .class = ((PCI_CLASS_BRIDGE_OTHER << 8) | 0xfe), - .class_mask = 0, - .vendor = PCI_VENDOR_ID_PLX, - .device = PCI_DEVICE_ID_RDK1, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, - { /* RDK 2 card */ - .class = ((PCI_CLASS_BRIDGE_OTHER << 8) | 0xfe), - .class_mask = 0, - .vendor = PCI_VENDOR_ID_PLX, - .device = PCI_DEVICE_ID_RDK2, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, - { } -}; -MODULE_DEVICE_TABLE(pci, pci_ids); - -static struct pci_driver net2272_pci_driver = { - .name = driver_name, - .id_table = pci_ids, - - .probe = net2272_pci_probe, - .remove = net2272_pci_remove, -}; - -static int net2272_pci_register(void) -{ - return pci_register_driver(&net2272_pci_driver); -} - -static void net2272_pci_unregister(void) -{ - pci_unregister_driver(&net2272_pci_driver); -} - -#else -static inline int net2272_pci_register(void) { return 0; } -static inline void net2272_pci_unregister(void) { } -#endif - -/*---------------------------------------------------------------------------*/ - -static int -net2272_plat_probe(struct platform_device *pdev) -{ - struct net2272 *dev; - int ret; - unsigned int irqflags; - resource_size_t base, len; - struct resource *iomem, *iomem_bus, *irq_res; - - irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - iomem_bus = platform_get_resource(pdev, IORESOURCE_BUS, 0); - if (!irq_res || !iomem) { - dev_err(&pdev->dev, "must provide irq/base addr"); - return -EINVAL; - } - - dev = net2272_probe_init(&pdev->dev, irq_res->start); - if (IS_ERR(dev)) - return PTR_ERR(dev); - - irqflags = 0; - if (irq_res->flags & IORESOURCE_IRQ_HIGHEDGE) - irqflags |= IRQF_TRIGGER_RISING; - if (irq_res->flags & IORESOURCE_IRQ_LOWEDGE) - irqflags |= IRQF_TRIGGER_FALLING; - if (irq_res->flags & IORESOURCE_IRQ_HIGHLEVEL) - irqflags |= IRQF_TRIGGER_HIGH; - if (irq_res->flags & IORESOURCE_IRQ_LOWLEVEL) - irqflags |= IRQF_TRIGGER_LOW; - - base = iomem->start; - len = resource_size(iomem); - if (iomem_bus) - dev->base_shift = iomem_bus->start; - - if (!request_mem_region(base, len, driver_name)) { - dev_dbg(dev->dev, "get request memory region!\n"); - ret = -EBUSY; - goto err; - } - dev->base_addr = ioremap(base, len); - if (!dev->base_addr) { - dev_dbg(dev->dev, "can't map memory\n"); - ret = -EFAULT; - goto err_req; - } - - ret = net2272_probe_fin(dev, irqflags); - if (ret) - goto err_io; - - platform_set_drvdata(pdev, dev); - dev_info(&pdev->dev, "running in 16-bit, %sbyte swap local bus mode\n", - (net2272_read(dev, LOCCTL) & (1 << BYTE_SWAP)) ? "" : "no "); - - return 0; - - err_io: - iounmap(dev->base_addr); - err_req: - release_mem_region(base, len); - err: - usb_put_gadget(&dev->gadget); - - return ret; -} - -static void -net2272_plat_remove(struct platform_device *pdev) -{ - struct net2272 *dev = platform_get_drvdata(pdev); - - net2272_remove(dev); - - release_mem_region(pdev->resource[0].start, - resource_size(&pdev->resource[0])); - - usb_put_gadget(&dev->gadget); -} - -static struct platform_driver net2272_plat_driver = { - .probe = net2272_plat_probe, - .remove = net2272_plat_remove, - .driver = { - .name = driver_name, - }, - /* FIXME .suspend, .resume */ -}; -MODULE_ALIAS("platform:net2272"); - -static int __init net2272_init(void) -{ - int ret; - - ret = net2272_pci_register(); - if (ret) - return ret; - ret = platform_driver_register(&net2272_plat_driver); - if (ret) - goto err_pci; - return ret; - -err_pci: - net2272_pci_unregister(); - return ret; -} -module_init(net2272_init); - -static void __exit net2272_cleanup(void) -{ - net2272_pci_unregister(); - platform_driver_unregister(&net2272_plat_driver); -} -module_exit(net2272_cleanup); - -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_AUTHOR("PLX Technology, Inc."); -MODULE_LICENSE("GPL"); diff --git a/drivers/usb/gadget/udc/net2272.h b/drivers/usb/gadget/udc/net2272.h deleted file mode 100644 index a9994f737588..000000000000 --- a/drivers/usb/gadget/udc/net2272.h +++ /dev/null @@ -1,584 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * PLX NET2272 high/full speed USB device controller - * - * Copyright (C) 2005-2006 PLX Technology, Inc. - * Copyright (C) 2006-2011 Analog Devices, Inc. - */ - -#ifndef __NET2272_H__ -#define __NET2272_H__ - -/* Main Registers */ -#define REGADDRPTR 0x00 -#define REGDATA 0x01 -#define IRQSTAT0 0x02 -#define ENDPOINT_0_INTERRUPT 0 -#define ENDPOINT_A_INTERRUPT 1 -#define ENDPOINT_B_INTERRUPT 2 -#define ENDPOINT_C_INTERRUPT 3 -#define VIRTUALIZED_ENDPOINT_INTERRUPT 4 -#define SETUP_PACKET_INTERRUPT 5 -#define DMA_DONE_INTERRUPT 6 -#define SOF_INTERRUPT 7 -#define IRQSTAT1 0x03 -#define CONTROL_STATUS_INTERRUPT 1 -#define VBUS_INTERRUPT 2 -#define SUSPEND_REQUEST_INTERRUPT 3 -#define SUSPEND_REQUEST_CHANGE_INTERRUPT 4 -#define RESUME_INTERRUPT 5 -#define ROOT_PORT_RESET_INTERRUPT 6 -#define RESET_STATUS 7 -#define PAGESEL 0x04 -#define DMAREQ 0x1c -#define DMA_ENDPOINT_SELECT 0 -#define DREQ_POLARITY 1 -#define DACK_POLARITY 2 -#define EOT_POLARITY 3 -#define DMA_CONTROL_DACK 4 -#define DMA_REQUEST_ENABLE 5 -#define DMA_REQUEST 6 -#define DMA_BUFFER_VALID 7 -#define SCRATCH 0x1d -#define IRQENB0 0x20 -#define ENDPOINT_0_INTERRUPT_ENABLE 0 -#define ENDPOINT_A_INTERRUPT_ENABLE 1 -#define ENDPOINT_B_INTERRUPT_ENABLE 2 -#define ENDPOINT_C_INTERRUPT_ENABLE 3 -#define VIRTUALIZED_ENDPOINT_INTERRUPT_ENABLE 4 -#define SETUP_PACKET_INTERRUPT_ENABLE 5 -#define DMA_DONE_INTERRUPT_ENABLE 6 -#define SOF_INTERRUPT_ENABLE 7 -#define IRQENB1 0x21 -#define VBUS_INTERRUPT_ENABLE 2 -#define SUSPEND_REQUEST_INTERRUPT_ENABLE 3 -#define SUSPEND_REQUEST_CHANGE_INTERRUPT_ENABLE 4 -#define RESUME_INTERRUPT_ENABLE 5 -#define ROOT_PORT_RESET_INTERRUPT_ENABLE 6 -#define LOCCTL 0x22 -#define DATA_WIDTH 0 -#define LOCAL_CLOCK_OUTPUT 1 -#define LOCAL_CLOCK_OUTPUT_OFF 0 -#define LOCAL_CLOCK_OUTPUT_3_75MHZ 1 -#define LOCAL_CLOCK_OUTPUT_7_5MHZ 2 -#define LOCAL_CLOCK_OUTPUT_15MHZ 3 -#define LOCAL_CLOCK_OUTPUT_30MHZ 4 -#define LOCAL_CLOCK_OUTPUT_60MHZ 5 -#define DMA_SPLIT_BUS_MODE 4 -#define BYTE_SWAP 5 -#define BUFFER_CONFIGURATION 6 -#define BUFFER_CONFIGURATION_EPA512_EPB512 0 -#define BUFFER_CONFIGURATION_EPA1024_EPB512 1 -#define BUFFER_CONFIGURATION_EPA1024_EPB1024 2 -#define BUFFER_CONFIGURATION_EPA1024DB 3 -#define CHIPREV_LEGACY 0x23 -#define NET2270_LEGACY_REV 0x40 -#define LOCCTL1 0x24 -#define DMA_MODE 0 -#define SLOW_DREQ 0 -#define FAST_DREQ 1 -#define BURST_MODE 2 -#define DMA_DACK_ENABLE 2 -#define CHIPREV_2272 0x25 -#define CHIPREV_NET2272_R1 0x10 -#define CHIPREV_NET2272_R1A 0x11 -/* USB Registers */ -#define USBCTL0 0x18 -#define IO_WAKEUP_ENABLE 1 -#define USB_DETECT_ENABLE 3 -#define USB_ROOT_PORT_WAKEUP_ENABLE 5 -#define USBCTL1 0x19 -#define VBUS_PIN 0 -#define USB_FULL_SPEED 1 -#define USB_HIGH_SPEED 2 -#define GENERATE_RESUME 3 -#define VIRTUAL_ENDPOINT_ENABLE 4 -#define FRAME0 0x1a -#define FRAME1 0x1b -#define OURADDR 0x30 -#define FORCE_IMMEDIATE 7 -#define USBDIAG 0x31 -#define FORCE_TRANSMIT_CRC_ERROR 0 -#define PREVENT_TRANSMIT_BIT_STUFF 1 -#define FORCE_RECEIVE_ERROR 2 -#define FAST_TIMES 4 -#define USBTEST 0x32 -#define TEST_MODE_SELECT 0 -#define NORMAL_OPERATION 0 -#define XCVRDIAG 0x33 -#define FORCE_FULL_SPEED 2 -#define FORCE_HIGH_SPEED 3 -#define OPMODE 4 -#define NORMAL_OPERATION 0 -#define NON_DRIVING 1 -#define DISABLE_BITSTUFF_AND_NRZI_ENCODE 2 -#define LINESTATE 6 -#define SE0_STATE 0 -#define J_STATE 1 -#define K_STATE 2 -#define SE1_STATE 3 -#define VIRTOUT0 0x34 -#define VIRTOUT1 0x35 -#define VIRTIN0 0x36 -#define VIRTIN1 0x37 -#define SETUP0 0x40 -#define SETUP1 0x41 -#define SETUP2 0x42 -#define SETUP3 0x43 -#define SETUP4 0x44 -#define SETUP5 0x45 -#define SETUP6 0x46 -#define SETUP7 0x47 -/* Endpoint Registers (Paged via PAGESEL) */ -#define EP_DATA 0x05 -#define EP_STAT0 0x06 -#define DATA_IN_TOKEN_INTERRUPT 0 -#define DATA_OUT_TOKEN_INTERRUPT 1 -#define DATA_PACKET_TRANSMITTED_INTERRUPT 2 -#define DATA_PACKET_RECEIVED_INTERRUPT 3 -#define SHORT_PACKET_TRANSFERRED_INTERRUPT 4 -#define NAK_OUT_PACKETS 5 -#define BUFFER_EMPTY 6 -#define BUFFER_FULL 7 -#define EP_STAT1 0x07 -#define TIMEOUT 0 -#define USB_OUT_ACK_SENT 1 -#define USB_OUT_NAK_SENT 2 -#define USB_IN_ACK_RCVD 3 -#define USB_IN_NAK_SENT 4 -#define USB_STALL_SENT 5 -#define LOCAL_OUT_ZLP 6 -#define BUFFER_FLUSH 7 -#define EP_TRANSFER0 0x08 -#define EP_TRANSFER1 0x09 -#define EP_TRANSFER2 0x0a -#define EP_IRQENB 0x0b -#define DATA_IN_TOKEN_INTERRUPT_ENABLE 0 -#define DATA_OUT_TOKEN_INTERRUPT_ENABLE 1 -#define DATA_PACKET_TRANSMITTED_INTERRUPT_ENABLE 2 -#define DATA_PACKET_RECEIVED_INTERRUPT_ENABLE 3 -#define SHORT_PACKET_TRANSFERRED_INTERRUPT_ENABLE 4 -#define EP_AVAIL0 0x0c -#define EP_AVAIL1 0x0d -#define EP_RSPCLR 0x0e -#define EP_RSPSET 0x0f -#define ENDPOINT_HALT 0 -#define ENDPOINT_TOGGLE 1 -#define NAK_OUT_PACKETS_MODE 2 -#define CONTROL_STATUS_PHASE_HANDSHAKE 3 -#define INTERRUPT_MODE 4 -#define AUTOVALIDATE 5 -#define HIDE_STATUS_PHASE 6 -#define ALT_NAK_OUT_PACKETS 7 -#define EP_MAXPKT0 0x28 -#define EP_MAXPKT1 0x29 -#define ADDITIONAL_TRANSACTION_OPPORTUNITIES 3 -#define NONE_ADDITIONAL_TRANSACTION 0 -#define ONE_ADDITIONAL_TRANSACTION 1 -#define TWO_ADDITIONAL_TRANSACTION 2 -#define EP_CFG 0x2a -#define ENDPOINT_NUMBER 0 -#define ENDPOINT_DIRECTION 4 -#define ENDPOINT_TYPE 5 -#define ENDPOINT_ENABLE 7 -#define EP_HBW 0x2b -#define HIGH_BANDWIDTH_OUT_TRANSACTION_PID 0 -#define DATA0_PID 0 -#define DATA1_PID 1 -#define DATA2_PID 2 -#define MDATA_PID 3 -#define EP_BUFF_STATES 0x2c -#define BUFFER_A_STATE 0 -#define BUFFER_B_STATE 2 -#define BUFF_FREE 0 -#define BUFF_VALID 1 -#define BUFF_LCL 2 -#define BUFF_USB 3 - -/*---------------------------------------------------------------------------*/ - -#define PCI_DEVICE_ID_RDK1 0x9054 - -/* PCI-RDK EPLD Registers */ -#define RDK_EPLD_IO_REGISTER1 0x00000000 -#define RDK_EPLD_USB_RESET 0 -#define RDK_EPLD_USB_POWERDOWN 1 -#define RDK_EPLD_USB_WAKEUP 2 -#define RDK_EPLD_USB_EOT 3 -#define RDK_EPLD_DPPULL 4 -#define RDK_EPLD_IO_REGISTER2 0x00000004 -#define RDK_EPLD_BUSWIDTH 0 -#define RDK_EPLD_USER 2 -#define RDK_EPLD_RESET_INTERRUPT_ENABLE 3 -#define RDK_EPLD_DMA_TIMEOUT_ENABLE 4 -#define RDK_EPLD_STATUS_REGISTER 0x00000008 -#define RDK_EPLD_USB_LRESET 0 -#define RDK_EPLD_REVISION_REGISTER 0x0000000c - -/* PCI-RDK PLX 9054 Registers */ -#define INTCSR 0x68 -#define PCI_INTERRUPT_ENABLE 8 -#define LOCAL_INTERRUPT_INPUT_ENABLE 11 -#define LOCAL_INPUT_INTERRUPT_ACTIVE 15 -#define LOCAL_DMA_CHANNEL_0_INTERRUPT_ENABLE 18 -#define LOCAL_DMA_CHANNEL_1_INTERRUPT_ENABLE 19 -#define DMA_CHANNEL_0_INTERRUPT_ACTIVE 21 -#define DMA_CHANNEL_1_INTERRUPT_ACTIVE 22 -#define CNTRL 0x6C -#define RELOAD_CONFIGURATION_REGISTERS 29 -#define PCI_ADAPTER_SOFTWARE_RESET 30 -#define DMAMODE0 0x80 -#define LOCAL_BUS_WIDTH 0 -#define INTERNAL_WAIT_STATES 2 -#define TA_READY_INPUT_ENABLE 6 -#define LOCAL_BURST_ENABLE 8 -#define SCATTER_GATHER_MODE 9 -#define DONE_INTERRUPT_ENABLE 10 -#define LOCAL_ADDRESSING_MODE 11 -#define DEMAND_MODE 12 -#define DMA_EOT_ENABLE 14 -#define FAST_SLOW_TERMINATE_MODE_SELECT 15 -#define DMA_CHANNEL_INTERRUPT_SELECT 17 -#define DMAPADR0 0x84 -#define DMALADR0 0x88 -#define DMASIZ0 0x8c -#define DMADPR0 0x90 -#define DESCRIPTOR_LOCATION 0 -#define END_OF_CHAIN 1 -#define INTERRUPT_AFTER_TERMINAL_COUNT 2 -#define DIRECTION_OF_TRANSFER 3 -#define DMACSR0 0xa8 -#define CHANNEL_ENABLE 0 -#define CHANNEL_START 1 -#define CHANNEL_ABORT 2 -#define CHANNEL_CLEAR_INTERRUPT 3 -#define CHANNEL_DONE 4 -#define DMATHR 0xb0 -#define LBRD1 0xf8 -#define MEMORY_SPACE_LOCAL_BUS_WIDTH 0 -#define W8_BIT 0 -#define W16_BIT 1 - -/* Special OR'ing of INTCSR bits */ -#define LOCAL_INTERRUPT_TEST \ - ((1 << LOCAL_INPUT_INTERRUPT_ACTIVE) | \ - (1 << LOCAL_INTERRUPT_INPUT_ENABLE)) - -#define DMA_CHANNEL_0_TEST \ - ((1 << DMA_CHANNEL_0_INTERRUPT_ACTIVE) | \ - (1 << LOCAL_DMA_CHANNEL_0_INTERRUPT_ENABLE)) - -#define DMA_CHANNEL_1_TEST \ - ((1 << DMA_CHANNEL_1_INTERRUPT_ACTIVE) | \ - (1 << LOCAL_DMA_CHANNEL_1_INTERRUPT_ENABLE)) - -/* EPLD Registers */ -#define RDK_EPLD_IO_REGISTER1 0x00000000 -#define RDK_EPLD_USB_RESET 0 -#define RDK_EPLD_USB_POWERDOWN 1 -#define RDK_EPLD_USB_WAKEUP 2 -#define RDK_EPLD_USB_EOT 3 -#define RDK_EPLD_DPPULL 4 -#define RDK_EPLD_IO_REGISTER2 0x00000004 -#define RDK_EPLD_BUSWIDTH 0 -#define RDK_EPLD_USER 2 -#define RDK_EPLD_RESET_INTERRUPT_ENABLE 3 -#define RDK_EPLD_DMA_TIMEOUT_ENABLE 4 -#define RDK_EPLD_STATUS_REGISTER 0x00000008 -#define RDK_EPLD_USB_LRESET 0 -#define RDK_EPLD_REVISION_REGISTER 0x0000000c - -#define EPLD_IO_CONTROL_REGISTER 0x400 -#define NET2272_RESET 0 -#define BUSWIDTH 1 -#define MPX_MODE 3 -#define USER 4 -#define DMA_TIMEOUT_ENABLE 5 -#define DMA_CTL_DACK 6 -#define EPLD_DMA_ENABLE 7 -#define EPLD_DMA_CONTROL_REGISTER 0x800 -#define SPLIT_DMA_MODE 0 -#define SPLIT_DMA_DIRECTION 1 -#define SPLIT_DMA_ENABLE 2 -#define SPLIT_DMA_INTERRUPT_ENABLE 3 -#define SPLIT_DMA_INTERRUPT 4 -#define EPLD_DMA_MODE 5 -#define EPLD_DMA_CONTROLLER_ENABLE 7 -#define SPLIT_DMA_ADDRESS_LOW 0xc00 -#define SPLIT_DMA_ADDRESS_HIGH 0x1000 -#define SPLIT_DMA_BYTE_COUNT_LOW 0x1400 -#define SPLIT_DMA_BYTE_COUNT_HIGH 0x1800 -#define EPLD_REVISION_REGISTER 0x1c00 -#define SPLIT_DMA_RAM 0x4000 -#define DMA_RAM_SIZE 0x1000 - -/*---------------------------------------------------------------------------*/ - -#define PCI_DEVICE_ID_RDK2 0x3272 - -/* PCI-RDK version 2 registers */ - -/* Main Control Registers */ - -#define RDK2_IRQENB 0x00 -#define RDK2_IRQSTAT 0x04 -#define PB7 23 -#define PB6 22 -#define PB5 21 -#define PB4 20 -#define PB3 19 -#define PB2 18 -#define PB1 17 -#define PB0 16 -#define GP3 23 -#define GP2 23 -#define GP1 23 -#define GP0 23 -#define DMA_RETRY_ABORT 6 -#define DMA_PAUSE_DONE 5 -#define DMA_ABORT_DONE 4 -#define DMA_OUT_FIFO_TRANSFER_DONE 3 -#define DMA_LOCAL_DONE 2 -#define DMA_PCI_DONE 1 -#define NET2272_PCI_IRQ 0 - -#define RDK2_LOCCTLRDK 0x08 -#define CHIP_RESET 3 -#define SPLIT_DMA 2 -#define MULTIPLEX_MODE 1 -#define BUS_WIDTH 0 - -#define RDK2_GPIOCTL 0x10 -#define GP3_OUT_ENABLE 7 -#define GP2_OUT_ENABLE 6 -#define GP1_OUT_ENABLE 5 -#define GP0_OUT_ENABLE 4 -#define GP3_DATA 3 -#define GP2_DATA 2 -#define GP1_DATA 1 -#define GP0_DATA 0 - -#define RDK2_LEDSW 0x14 -#define LED3 27 -#define LED2 26 -#define LED1 25 -#define LED0 24 -#define PBUTTON 16 -#define DIPSW 0 - -#define RDK2_DIAG 0x18 -#define RDK2_FAST_TIMES 2 -#define FORCE_PCI_SERR 1 -#define FORCE_PCI_INT 0 -#define RDK2_FPGAREV 0x1C - -/* Dma Control registers */ -#define RDK2_DMACTL 0x80 -#define ADDR_HOLD 24 -#define RETRY_COUNT 16 /* 23:16 */ -#define FIFO_THRESHOLD 11 /* 15:11 */ -#define MEM_WRITE_INVALIDATE 10 -#define READ_MULTIPLE 9 -#define READ_LINE 8 -#define RDK2_DMA_MODE 6 /* 7:6 */ -#define CONTROL_DACK 5 -#define EOT_ENABLE 4 -#define EOT_POLARITY 3 -#define DACK_POLARITY 2 -#define DREQ_POLARITY 1 -#define DMA_ENABLE 0 - -#define RDK2_DMASTAT 0x84 -#define GATHER_COUNT 12 /* 14:12 */ -#define FIFO_COUNT 6 /* 11:6 */ -#define FIFO_FLUSH 5 -#define FIFO_TRANSFER 4 -#define PAUSE_DONE 3 -#define ABORT_DONE 2 -#define DMA_ABORT 1 -#define DMA_START 0 - -#define RDK2_DMAPCICOUNT 0x88 -#define DMA_DIRECTION 31 -#define DMA_PCI_BYTE_COUNT 0 /* 0:23 */ - -#define RDK2_DMALOCCOUNT 0x8C /* 0:23 dma local byte count */ - -#define RDK2_DMAADDR 0x90 /* 2:31 PCI bus starting address */ - -/*---------------------------------------------------------------------------*/ - -#define REG_INDEXED_THRESHOLD (1 << 5) - -/* DRIVER DATA STRUCTURES and UTILITIES */ -struct net2272_ep { - struct usb_ep ep; - struct net2272 *dev; - unsigned long irqs; - - /* analogous to a host-side qh */ - struct list_head queue; - const struct usb_endpoint_descriptor *desc; - unsigned num:8, - fifo_size:12, - stopped:1, - wedged:1, - is_in:1, - is_iso:1, - dma:1, - not_empty:1; -}; - -struct net2272 { - /* each device provides one gadget, several endpoints */ - struct usb_gadget gadget; - struct device *dev; - unsigned short dev_id; - - spinlock_t lock; - struct net2272_ep ep[4]; - struct usb_gadget_driver *driver; - unsigned protocol_stall:1, - softconnect:1, - wakeup:1, - added:1, - async_callbacks:1, - dma_eot_polarity:1, - dma_dack_polarity:1, - dma_dreq_polarity:1, - dma_busy:1; - u16 chiprev; - u8 pagesel; - - unsigned int irq; - unsigned short fifo_mode; - - unsigned int base_shift; - u16 __iomem *base_addr; - union { -#ifdef CONFIG_USB_PCI - struct { - void __iomem *plx9054_base_addr; - void __iomem *epld_base_addr; - } rdk1; - struct { - /* Bar0, Bar1 is base_addr both mem-mapped */ - void __iomem *fpga_base_addr; - } rdk2; -#endif - }; -}; - -static void __iomem * -net2272_reg_addr(struct net2272 *dev, unsigned int reg) -{ - return dev->base_addr + (reg << dev->base_shift); -} - -static void -net2272_write(struct net2272 *dev, unsigned int reg, u8 value) -{ - if (reg >= REG_INDEXED_THRESHOLD) { - /* - * Indexed register; use REGADDRPTR/REGDATA - * - Save and restore REGADDRPTR. This prevents REGADDRPTR from - * changes between other code sections, but it is time consuming. - * - Performance tips: either do not save and restore REGADDRPTR (if it - * is safe) or do save/restore operations only in critical sections. - u8 tmp = readb(dev->base_addr + REGADDRPTR); - */ - writeb((u8)reg, net2272_reg_addr(dev, REGADDRPTR)); - writeb(value, net2272_reg_addr(dev, REGDATA)); - /* writeb(tmp, net2272_reg_addr(dev, REGADDRPTR)); */ - } else - writeb(value, net2272_reg_addr(dev, reg)); -} - -static u8 -net2272_read(struct net2272 *dev, unsigned int reg) -{ - u8 ret; - - if (reg >= REG_INDEXED_THRESHOLD) { - /* - * Indexed register; use REGADDRPTR/REGDATA - * - Save and restore REGADDRPTR. This prevents REGADDRPTR from - * changes between other code sections, but it is time consuming. - * - Performance tips: either do not save and restore REGADDRPTR (if it - * is safe) or do save/restore operations only in critical sections. - u8 tmp = readb(dev->base_addr + REGADDRPTR); - */ - writeb((u8)reg, net2272_reg_addr(dev, REGADDRPTR)); - ret = readb(net2272_reg_addr(dev, REGDATA)); - /* writeb(tmp, net2272_reg_addr(dev, REGADDRPTR)); */ - } else - ret = readb(net2272_reg_addr(dev, reg)); - - return ret; -} - -static void -net2272_ep_write(struct net2272_ep *ep, unsigned int reg, u8 value) -{ - struct net2272 *dev = ep->dev; - - if (dev->pagesel != ep->num) { - net2272_write(dev, PAGESEL, ep->num); - dev->pagesel = ep->num; - } - net2272_write(dev, reg, value); -} - -static u8 -net2272_ep_read(struct net2272_ep *ep, unsigned int reg) -{ - struct net2272 *dev = ep->dev; - - if (dev->pagesel != ep->num) { - net2272_write(dev, PAGESEL, ep->num); - dev->pagesel = ep->num; - } - return net2272_read(dev, reg); -} - -static void allow_status(struct net2272_ep *ep) -{ - /* ep0 only */ - net2272_ep_write(ep, EP_RSPCLR, - (1 << CONTROL_STATUS_PHASE_HANDSHAKE) | - (1 << ALT_NAK_OUT_PACKETS) | - (1 << NAK_OUT_PACKETS_MODE)); - ep->stopped = 1; -} - -static void set_halt(struct net2272_ep *ep) -{ - /* ep0 and bulk/intr endpoints */ - net2272_ep_write(ep, EP_RSPCLR, 1 << CONTROL_STATUS_PHASE_HANDSHAKE); - net2272_ep_write(ep, EP_RSPSET, 1 << ENDPOINT_HALT); -} - -static void clear_halt(struct net2272_ep *ep) -{ - /* ep0 and bulk/intr endpoints */ - net2272_ep_write(ep, EP_RSPCLR, - (1 << ENDPOINT_HALT) | (1 << ENDPOINT_TOGGLE)); -} - -/* count (<= 4) bytes in the next fifo write will be valid */ -static void set_fifo_bytecount(struct net2272_ep *ep, unsigned count) -{ - /* net2272_ep_write will truncate to u8 for us */ - net2272_ep_write(ep, EP_TRANSFER2, count >> 16); - net2272_ep_write(ep, EP_TRANSFER1, count >> 8); - net2272_ep_write(ep, EP_TRANSFER0, count); -} - -struct net2272_request { - struct usb_request req; - struct list_head queue; - unsigned mapped:1, - valid:1; -}; - -#endif diff --git a/drivers/usb/gadget/udc/omap_udc.c b/drivers/usb/gadget/udc/omap_udc.c index c93ea210c17c..062bf2b57d2e 100644 --- a/drivers/usb/gadget/udc/omap_udc.c +++ b/drivers/usb/gadget/udc/omap_udc.c @@ -1860,7 +1860,7 @@ static irqreturn_t omap_udc_irq(int irq, void *_udc) static void pio_out_timer(struct timer_list *t) { - struct omap_ep *ep = from_timer(ep, t, timer); + struct omap_ep *ep = timer_container_of(ep, t, timer); unsigned long flags; u16 stat_flg; diff --git a/drivers/usb/gadget/udc/pxa25x_udc.c b/drivers/usb/gadget/udc/pxa25x_udc.c index 24eb1ae78e45..f5d09a91e554 100644 --- a/drivers/usb/gadget/udc/pxa25x_udc.c +++ b/drivers/usb/gadget/udc/pxa25x_udc.c @@ -1574,7 +1574,7 @@ static inline void clear_ep_state (struct pxa25x_udc *dev) static void udc_watchdog(struct timer_list *t) { - struct pxa25x_udc *dev = from_timer(dev, t, timer); + struct pxa25x_udc *dev = timer_container_of(dev, t, timer); local_irq_disable(); if (dev->ep0state == EP0_STALL diff --git a/drivers/usb/gadget/udc/r8a66597-udc.c b/drivers/usb/gadget/udc/r8a66597-udc.c index 6c1d15b2250c..e5c2630e3711 100644 --- a/drivers/usb/gadget/udc/r8a66597-udc.c +++ b/drivers/usb/gadget/udc/r8a66597-udc.c @@ -1516,7 +1516,7 @@ static irqreturn_t r8a66597_irq(int irq, void *_r8a66597) static void r8a66597_timer(struct timer_list *t) { - struct r8a66597 *r8a66597 = from_timer(r8a66597, t, timer); + struct r8a66597 *r8a66597 = timer_container_of(r8a66597, t, timer); unsigned long flags; u16 tmp; diff --git a/drivers/usb/gadget/udc/renesas_usb3.c b/drivers/usb/gadget/udc/renesas_usb3.c index 89b304cf6d03..3e4d56457597 100644 --- a/drivers/usb/gadget/udc/renesas_usb3.c +++ b/drivers/usb/gadget/udc/renesas_usb3.c @@ -2397,8 +2397,7 @@ static int renesas_usb3_stop(struct usb_gadget *gadget) rzv2m_usb3drd_reset(usb3_to_dev(usb3)->parent, false); renesas_usb3_stop_controller(usb3); - if (usb3->phy) - phy_exit(usb3->phy); + phy_exit(usb3->phy); pm_runtime_put(usb3_to_dev(usb3)); @@ -2984,8 +2983,7 @@ static int renesas_usb3_suspend(struct device *dev) return 0; renesas_usb3_stop_controller(usb3); - if (usb3->phy) - phy_exit(usb3->phy); + phy_exit(usb3->phy); pm_runtime_put(dev); return 0; diff --git a/drivers/usb/gadget/udc/udc-xilinx.c b/drivers/usb/gadget/udc/udc-xilinx.c index ae2aeb271897..fa94cc065274 100644 --- a/drivers/usb/gadget/udc/udc-xilinx.c +++ b/drivers/usb/gadget/udc/udc-xilinx.c @@ -2178,8 +2178,6 @@ fail: /** * xudc_remove - Releases the resources allocated during the initialization. * @pdev: pointer to the platform device structure. - * - * Return: 0 always */ static void xudc_remove(struct platform_device *pdev) { diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index d011d6c753ed..109100cc77a3 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -104,6 +104,15 @@ config USB_XHCI_RZV2M Say 'Y' to enable the support for the xHCI host controller found in Renesas RZ/V2M SoC. +config USB_XHCI_SIDEBAND + bool "xHCI support for sideband" + help + Say 'Y' to enable the support for the xHCI sideband capability. + Provide a mechanism for a sideband datapath for payload associated + with audio class endpoints. This allows for an audio DSP to use + xHCI USB endpoints directly, allowing CPU to sleep while playing + audio. + config USB_XHCI_TEGRA tristate "xHCI support for NVIDIA Tegra SoCs" depends on PHY_TEGRA_XUSB @@ -225,7 +234,7 @@ config USB_EHCI_HCD_OMAP tristate "EHCI support for OMAP3 and later chips" depends on ARCH_OMAP || COMPILE_TEST depends on NOP_USB_XCEIV - default y + default ARCH_OMAP help Enables support for the on-chip EHCI controller on OMAP3 and later chips. diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index be4e5245c52f..4df946c05ba0 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -32,6 +32,10 @@ endif xhci-rcar-hcd-y += xhci-rcar.o xhci-rcar-hcd-$(CONFIG_USB_XHCI_RZV2M) += xhci-rzv2m.o +ifneq ($(CONFIG_USB_XHCI_SIDEBAND),) + xhci-hcd-y += xhci-sideband.o +endif + obj-$(CONFIG_USB_PCI) += pci-quirks.o obj-$(CONFIG_USB_EHCI_HCD) += ehci-hcd.o diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c index 26f13278d4d6..6ed2fa5418a4 100644 --- a/drivers/usb/host/ehci-fsl.c +++ b/drivers/usb/host/ehci-fsl.c @@ -410,15 +410,13 @@ static int ehci_fsl_setup(struct usb_hcd *hcd) return retval; } -struct ehci_fsl { - struct ehci_hcd ehci; - -#ifdef CONFIG_PM +struct ehci_fsl_priv { /* Saved USB PHY settings, need to restore after deep sleep. */ u32 usb_ctrl; -#endif }; +#define hcd_to_ehci_fsl_priv(h) ((struct ehci_fsl_priv *) hcd_to_ehci(h)->priv) + #ifdef CONFIG_PM #ifdef CONFIG_PPC_MPC512x @@ -566,17 +564,10 @@ static inline int ehci_fsl_mpc512x_drv_resume(struct device *dev) } #endif /* CONFIG_PPC_MPC512x */ -static struct ehci_fsl *hcd_to_ehci_fsl(struct usb_hcd *hcd) -{ - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - - return container_of(ehci, struct ehci_fsl, ehci); -} - static int ehci_fsl_drv_suspend(struct device *dev) { struct usb_hcd *hcd = dev_get_drvdata(dev); - struct ehci_fsl *ehci_fsl = hcd_to_ehci_fsl(hcd); + struct ehci_fsl_priv *priv = hcd_to_ehci_fsl_priv(hcd); void __iomem *non_ehci = hcd->regs; if (of_device_is_compatible(dev->parent->of_node, @@ -589,14 +580,14 @@ static int ehci_fsl_drv_suspend(struct device *dev) if (!fsl_deep_sleep()) return 0; - ehci_fsl->usb_ctrl = ioread32be(non_ehci + FSL_SOC_USB_CTRL); + priv->usb_ctrl = ioread32be(non_ehci + FSL_SOC_USB_CTRL); return 0; } static int ehci_fsl_drv_resume(struct device *dev) { struct usb_hcd *hcd = dev_get_drvdata(dev); - struct ehci_fsl *ehci_fsl = hcd_to_ehci_fsl(hcd); + struct ehci_fsl_priv *priv = hcd_to_ehci_fsl_priv(hcd); struct ehci_hcd *ehci = hcd_to_ehci(hcd); void __iomem *non_ehci = hcd->regs; @@ -612,7 +603,7 @@ static int ehci_fsl_drv_resume(struct device *dev) usb_root_hub_lost_power(hcd->self.root_hub); /* Restore USB PHY settings and enable the controller. */ - iowrite32be(ehci_fsl->usb_ctrl, non_ehci + FSL_SOC_USB_CTRL); + iowrite32be(priv->usb_ctrl, non_ehci + FSL_SOC_USB_CTRL); ehci_reset(ehci); ehci_fsl_reinit(ehci); @@ -671,7 +662,7 @@ static int ehci_start_port_reset(struct usb_hcd *hcd, unsigned port) #endif /* CONFIG_USB_OTG */ static const struct ehci_driver_overrides ehci_fsl_overrides __initconst = { - .extra_priv_size = sizeof(struct ehci_fsl), + .extra_priv_size = sizeof(struct ehci_fsl_priv), .reset = ehci_fsl_setup, }; diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c index 150d2542cef0..6aab45c8525c 100644 --- a/drivers/usb/host/ehci-platform.c +++ b/drivers/usb/host/ehci-platform.c @@ -198,7 +198,8 @@ static void quirk_poll_work(struct work_struct *work) static void quirk_poll_timer(struct timer_list *t) { - struct ehci_platform_priv *priv = from_timer(priv, t, poll_timer); + struct ehci_platform_priv *priv = timer_container_of(priv, t, + poll_timer); struct ehci_hcd *ehci = container_of((void *)priv, struct ehci_hcd, priv); diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index c7784bf8101d..9c7f3008646e 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -746,7 +746,8 @@ static int ohci_start(struct usb_hcd *hcd) */ static void io_watchdog_func(struct timer_list *t) { - struct ohci_hcd *ohci = from_timer(ohci, t, io_watchdog); + struct ohci_hcd *ohci = timer_container_of(ohci, t, + io_watchdog); bool takeback_all_pending = false; u32 status; u32 head; diff --git a/drivers/usb/host/oxu210hp-hcd.c b/drivers/usb/host/oxu210hp-hcd.c index d75b1b9b4db0..6b7c73eff081 100644 --- a/drivers/usb/host/oxu210hp-hcd.c +++ b/drivers/usb/host/oxu210hp-hcd.c @@ -2955,7 +2955,7 @@ static irqreturn_t oxu_irq(struct usb_hcd *hcd) static void oxu_watchdog(struct timer_list *t) { - struct oxu_hcd *oxu = from_timer(oxu, t, watchdog); + struct oxu_hcd *oxu = timer_container_of(oxu, t, watchdog); unsigned long flags; spin_lock_irqsave(&oxu->lock, flags); diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c index 67e472116d11..d21a03cf5c17 100644 --- a/drivers/usb/host/r8a66597-hcd.c +++ b/drivers/usb/host/r8a66597-hcd.c @@ -1720,7 +1720,8 @@ static void r8a66597_root_hub_control(struct r8a66597 *r8a66597, int port) static void r8a66597_interval_timer(struct timer_list *t) { - struct r8a66597_timers *timers = from_timer(timers, t, interval); + struct r8a66597_timers *timers = timer_container_of(timers, t, + interval); struct r8a66597 *r8a66597 = timers->r8a66597; unsigned long flags; u16 pipenum; @@ -1744,7 +1745,7 @@ static void r8a66597_interval_timer(struct timer_list *t) static void r8a66597_td_timer(struct timer_list *t) { - struct r8a66597_timers *timers = from_timer(timers, t, td); + struct r8a66597_timers *timers = timer_container_of(timers, t, td); struct r8a66597 *r8a66597 = timers->r8a66597; unsigned long flags; u16 pipenum; @@ -1798,7 +1799,7 @@ static void r8a66597_td_timer(struct timer_list *t) static void r8a66597_timer(struct timer_list *t) { - struct r8a66597 *r8a66597 = from_timer(r8a66597, t, rh_timer); + struct r8a66597 *r8a66597 = timer_container_of(r8a66597, t, rh_timer); unsigned long flags; int port; diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c index 718b1b7fe366..ea3cab99c5d4 100644 --- a/drivers/usb/host/sl811-hcd.c +++ b/drivers/usb/host/sl811-hcd.c @@ -1124,7 +1124,7 @@ sl811h_hub_descriptor ( static void sl811h_timer(struct timer_list *t) { - struct sl811 *sl811 = from_timer(sl811, t, timer); + struct sl811 *sl811 = timer_container_of(sl811, t, timer); unsigned long flags; u8 irqstat; u8 signaling = sl811->ctrl1 & SL11H_CTL1MASK_FORCE; diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c index 45a8256a665f..9480d4ff0111 100644 --- a/drivers/usb/host/uhci-q.c +++ b/drivers/usb/host/uhci-q.c @@ -91,7 +91,7 @@ static void uhci_urbp_wants_fsbr(struct uhci_hcd *uhci, struct urb_priv *urbp) static void uhci_fsbr_timeout(struct timer_list *t) { - struct uhci_hcd *uhci = from_timer(uhci, t, fsbr_timer); + struct uhci_hcd *uhci = timer_container_of(uhci, t, fsbr_timer); unsigned long flags; spin_lock_irqsave(&uhci->lock, flags); diff --git a/drivers/usb/host/xen-hcd.c b/drivers/usb/host/xen-hcd.c index 05943f2213e4..1c2a95fe41e5 100644 --- a/drivers/usb/host/xen-hcd.c +++ b/drivers/usb/host/xen-hcd.c @@ -1258,7 +1258,7 @@ static void xenhcd_disconnect(struct xenbus_device *dev) static void xenhcd_watchdog(struct timer_list *timer) { - struct xenhcd_info *info = from_timer(info, timer, watchdog); + struct xenhcd_info *info = timer_container_of(info, timer, watchdog); unsigned long flags; spin_lock_irqsave(&info->lock, flags); diff --git a/drivers/usb/host/xhci-caps.h b/drivers/usb/host/xhci-caps.h index f6b9a00a0ab9..4b8ff4815644 100644 --- a/drivers/usb/host/xhci-caps.h +++ b/drivers/usb/host/xhci-caps.h @@ -62,8 +62,8 @@ #define CTX_SIZE(_hcc) (HCC_64BYTE_CONTEXT(_hcc) ? 64 : 32) -/* db_off bitmask - bits 0:1 reserved */ -#define DBOFF_MASK (~0x3) +/* db_off bitmask - bits 31:2 Doorbell Array Offset */ +#define DBOFF_MASK (0xfffffffc) /* run_regs_off bitmask - bits 0:4 reserved */ #define RTSOFF_MASK (~0x1f) diff --git a/drivers/usb/host/xhci-debugfs.c b/drivers/usb/host/xhci-debugfs.c index 1f5ef174abea..c6d44977193f 100644 --- a/drivers/usb/host/xhci-debugfs.c +++ b/drivers/usb/host/xhci-debugfs.c @@ -631,6 +631,112 @@ static void xhci_debugfs_create_ports(struct xhci_hcd *xhci, } } +static int xhci_port_bw_show(struct xhci_hcd *xhci, u8 dev_speed, + struct seq_file *s) +{ + unsigned int num_ports; + unsigned int i; + int ret; + struct xhci_container_ctx *ctx; + struct usb_hcd *hcd = xhci_to_hcd(xhci); + struct device *dev = hcd->self.controller; + + ret = pm_runtime_get_sync(dev); + if (ret < 0) + return ret; + + num_ports = HCS_MAX_PORTS(xhci->hcs_params1); + + ctx = xhci_alloc_port_bw_ctx(xhci, 0); + if (!ctx) { + pm_runtime_put_sync(dev); + return -ENOMEM; + } + + /* get roothub port bandwidth */ + ret = xhci_get_port_bandwidth(xhci, ctx, dev_speed); + if (ret) + goto err_out; + + /* print all roothub ports available bandwidth + * refer to xhci rev1_2 protocol 6.2.6 , byte 0 is reserved + */ + for (i = 1; i < num_ports+1; i++) + seq_printf(s, "port[%d] available bw: %d%%.\n", i, + ctx->bytes[i]); +err_out: + pm_runtime_put_sync(dev); + xhci_free_port_bw_ctx(xhci, ctx); + return ret; +} + +static int xhci_ss_bw_show(struct seq_file *s, void *unused) +{ + int ret; + struct xhci_hcd *xhci = (struct xhci_hcd *)s->private; + + ret = xhci_port_bw_show(xhci, USB_SPEED_SUPER, s); + return ret; +} + +static int xhci_hs_bw_show(struct seq_file *s, void *unused) +{ + int ret; + struct xhci_hcd *xhci = (struct xhci_hcd *)s->private; + + ret = xhci_port_bw_show(xhci, USB_SPEED_HIGH, s); + return ret; +} + +static int xhci_fs_bw_show(struct seq_file *s, void *unused) +{ + int ret; + struct xhci_hcd *xhci = (struct xhci_hcd *)s->private; + + ret = xhci_port_bw_show(xhci, USB_SPEED_FULL, s); + return ret; +} + +static struct xhci_file_map bw_context_files[] = { + {"SS_BW", xhci_ss_bw_show, }, + {"HS_BW", xhci_hs_bw_show, }, + {"FS_BW", xhci_fs_bw_show, }, +}; + +static int bw_context_open(struct inode *inode, struct file *file) +{ + int i; + struct xhci_file_map *f_map; + const char *file_name = file_dentry(file)->d_iname; + + for (i = 0; i < ARRAY_SIZE(bw_context_files); i++) { + f_map = &bw_context_files[i]; + + if (strcmp(f_map->name, file_name) == 0) + break; + } + + return single_open(file, f_map->show, inode->i_private); +} + +static const struct file_operations bw_fops = { + .open = bw_context_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static void xhci_debugfs_create_bandwidth(struct xhci_hcd *xhci, + struct dentry *parent) +{ + parent = debugfs_create_dir("port_bandwidth", parent); + + xhci_debugfs_create_files(xhci, bw_context_files, + ARRAY_SIZE(bw_context_files), + xhci, + parent, &bw_fops); +} + void xhci_debugfs_init(struct xhci_hcd *xhci) { struct device *dev = xhci_to_hcd(xhci)->self.controller; @@ -681,6 +787,8 @@ void xhci_debugfs_init(struct xhci_hcd *xhci) xhci->debugfs_slots = debugfs_create_dir("devices", xhci->debugfs_root); xhci_debugfs_create_ports(xhci, xhci->debugfs_root); + + xhci_debugfs_create_bandwidth(xhci, xhci->debugfs_root); } void xhci_debugfs_exit(struct xhci_hcd *xhci) diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index 486347776cb2..92bb84f8132a 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -1907,7 +1907,7 @@ int xhci_bus_resume(struct usb_hcd *hcd) * prevent port event interrupts from interfering * with usb2 port resume process */ - xhci_disable_interrupter(xhci->interrupters[0]); + xhci_disable_interrupter(xhci, xhci->interrupters[0]); disabled_irq = true; } } diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index d698095fc88d..bd745a0f2f78 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -484,6 +484,35 @@ void xhci_free_container_ctx(struct xhci_hcd *xhci, kfree(ctx); } +struct xhci_container_ctx *xhci_alloc_port_bw_ctx(struct xhci_hcd *xhci, + gfp_t flags) +{ + struct xhci_container_ctx *ctx; + struct device *dev = xhci_to_hcd(xhci)->self.sysdev; + + ctx = kzalloc_node(sizeof(*ctx), flags, dev_to_node(dev)); + if (!ctx) + return NULL; + + ctx->size = GET_PORT_BW_ARRAY_SIZE; + + ctx->bytes = dma_pool_zalloc(xhci->port_bw_pool, flags, &ctx->dma); + if (!ctx->bytes) { + kfree(ctx); + return NULL; + } + return ctx; +} + +void xhci_free_port_bw_ctx(struct xhci_hcd *xhci, + struct xhci_container_ctx *ctx) +{ + if (!ctx) + return; + dma_pool_free(xhci->port_bw_pool, ctx->bytes, ctx->dma); + kfree(ctx); +} + struct xhci_input_control_ctx *xhci_get_input_control_ctx( struct xhci_container_ctx *ctx) { @@ -1802,10 +1831,10 @@ xhci_remove_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir) */ if (ir->ir_set) { tmp = readl(&ir->ir_set->erst_size); - tmp &= ERST_SIZE_MASK; + tmp &= ~ERST_SIZE_MASK; writel(tmp, &ir->ir_set->erst_size); - xhci_write_64(xhci, ERST_EHB, &ir->ir_set->erst_dequeue); + xhci_update_erst_dequeue(xhci, ir, true); } } @@ -1848,6 +1877,11 @@ void xhci_remove_secondary_interrupter(struct usb_hcd *hcd, struct xhci_interrup return; } + /* + * Cleanup secondary interrupter to ensure there are no pending events. + * This also updates event ring dequeue pointer back to the start. + */ + xhci_skip_sec_intr_events(xhci, ir->event_ring, ir); intr_num = ir->intr_num; xhci_remove_interrupter(xhci, ir); @@ -1907,6 +1941,11 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Freed small stream array pool"); + dma_pool_destroy(xhci->port_bw_pool); + xhci->port_bw_pool = NULL; + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "Freed xhci port bw array pool"); + dma_pool_destroy(xhci->medium_streams_pool); xhci->medium_streams_pool = NULL; xhci_dbg_trace(xhci, trace_xhci_dbg_init, @@ -2282,37 +2321,25 @@ xhci_alloc_interrupter(struct xhci_hcd *xhci, unsigned int segs, gfp_t flags) return ir; } -static int -xhci_add_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir, - unsigned int intr_num) +void xhci_add_interrupter(struct xhci_hcd *xhci, unsigned int intr_num) { + struct xhci_interrupter *ir; u64 erst_base; u32 erst_size; - if (intr_num >= xhci->max_interrupters) { - xhci_warn(xhci, "Can't add interrupter %d, max interrupters %d\n", - intr_num, xhci->max_interrupters); - return -EINVAL; - } - - if (xhci->interrupters[intr_num]) { - xhci_warn(xhci, "Interrupter %d\n already set up", intr_num); - return -EINVAL; - } - - xhci->interrupters[intr_num] = ir; + ir = xhci->interrupters[intr_num]; ir->intr_num = intr_num; ir->ir_set = &xhci->run_regs->ir_set[intr_num]; /* set ERST count with the number of entries in the segment table */ erst_size = readl(&ir->ir_set->erst_size); - erst_size &= ERST_SIZE_MASK; + erst_size &= ~ERST_SIZE_MASK; erst_size |= ir->event_ring->num_segs; writel(erst_size, &ir->ir_set->erst_size); erst_base = xhci_read_64(xhci, &ir->ir_set->erst_base); - erst_base &= ERST_BASE_RSVDP; - erst_base |= ir->erst.erst_dma_addr & ~ERST_BASE_RSVDP; + erst_base &= ~ERST_BASE_ADDRESS_MASK; + erst_base |= ir->erst.erst_dma_addr & ERST_BASE_ADDRESS_MASK; if (xhci->quirks & XHCI_WRITE_64_HI_LO) hi_lo_writeq(erst_base, &ir->ir_set->erst_base); else @@ -2320,20 +2347,19 @@ xhci_add_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir, /* Set the event ring dequeue address of this interrupter */ xhci_set_hc_event_deq(xhci, ir); - - return 0; } struct xhci_interrupter * xhci_create_secondary_interrupter(struct usb_hcd *hcd, unsigned int segs, - u32 imod_interval) + u32 imod_interval, unsigned int intr_num) { struct xhci_hcd *xhci = hcd_to_xhci(hcd); struct xhci_interrupter *ir; unsigned int i; int err = -ENOSPC; - if (!xhci->interrupters || xhci->max_interrupters <= 1) + if (!xhci->interrupters || xhci->max_interrupters <= 1 || + intr_num >= xhci->max_interrupters) return NULL; ir = xhci_alloc_interrupter(xhci, segs, GFP_KERNEL); @@ -2341,15 +2367,23 @@ xhci_create_secondary_interrupter(struct usb_hcd *hcd, unsigned int segs, return NULL; spin_lock_irq(&xhci->lock); - - /* Find available secondary interrupter, interrupter 0 is reserved for primary */ - for (i = 1; i < xhci->max_interrupters; i++) { - if (xhci->interrupters[i] == NULL) { - err = xhci_add_interrupter(xhci, ir, i); - break; + if (!intr_num) { + /* Find available secondary interrupter, interrupter 0 is reserved for primary */ + for (i = 1; i < xhci->max_interrupters; i++) { + if (!xhci->interrupters[i]) { + xhci->interrupters[i] = ir; + xhci_add_interrupter(xhci, i); + err = 0; + break; + } + } + } else { + if (!xhci->interrupters[intr_num]) { + xhci->interrupters[intr_num] = ir; + xhci_add_interrupter(xhci, intr_num); + err = 0; } } - spin_unlock_irq(&xhci->lock); if (err) { @@ -2359,78 +2393,32 @@ xhci_create_secondary_interrupter(struct usb_hcd *hcd, unsigned int segs, return NULL; } - err = xhci_set_interrupter_moderation(ir, imod_interval); - if (err) - xhci_warn(xhci, "Failed to set interrupter %d moderation to %uns\n", - i, imod_interval); + xhci_set_interrupter_moderation(ir, imod_interval); xhci_dbg(xhci, "Add secondary interrupter %d, max interrupters %d\n", - i, xhci->max_interrupters); + ir->intr_num, xhci->max_interrupters); return ir; } EXPORT_SYMBOL_GPL(xhci_create_secondary_interrupter); -static void xhci_hcd_page_size(struct xhci_hcd *xhci) -{ - u32 page_size; - - page_size = readl(&xhci->op_regs->page_size) & XHCI_PAGE_SIZE_MASK; - if (!is_power_of_2(page_size)) { - xhci_warn(xhci, "Invalid page size register = 0x%x\n", page_size); - /* Fallback to 4K page size, since that's common */ - page_size = 1; - } - - xhci->page_size = page_size << 12; - xhci_dbg_trace(xhci, trace_xhci_dbg_init, "HCD page size set to %iK", - xhci->page_size >> 10); -} - int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) { - struct xhci_interrupter *ir; struct device *dev = xhci_to_hcd(xhci)->self.sysdev; dma_addr_t dma; - unsigned int val, val2; - u64 val_64; - u32 temp; - int i; - - INIT_LIST_HEAD(&xhci->cmd_list); - - /* init command timeout work */ - INIT_DELAYED_WORK(&xhci->cmd_timer, xhci_handle_command_timeout); - init_completion(&xhci->cmd_ring_stop_completion); - - xhci_hcd_page_size(xhci); - - /* - * Program the Number of Device Slots Enabled field in the CONFIG - * register with the max value of slots the HC can handle. - */ - val = HCS_MAX_SLOTS(readl(&xhci->cap_regs->hcs_params1)); - xhci_dbg_trace(xhci, trace_xhci_dbg_init, - "// xHC can handle at most %d device slots.", val); - val2 = readl(&xhci->op_regs->config_reg); - val |= (val2 & ~HCS_SLOTS_MASK); - xhci_dbg_trace(xhci, trace_xhci_dbg_init, - "// Setting Max device slots reg = 0x%x.", val); - writel(val, &xhci->op_regs->config_reg); /* * xHCI section 5.4.6 - Device Context array must be * "physically contiguous and 64-byte (cache line) aligned". */ - xhci->dcbaa = dma_alloc_coherent(dev, sizeof(*xhci->dcbaa), &dma, - flags); + xhci->dcbaa = dma_alloc_coherent(dev, sizeof(*xhci->dcbaa), &dma, flags); if (!xhci->dcbaa) goto fail; + xhci->dcbaa->dma = dma; xhci_dbg_trace(xhci, trace_xhci_dbg_init, - "// Device context base array address = 0x%pad (DMA), %p (virt)", - &xhci->dcbaa->dma, xhci->dcbaa); - xhci_write_64(xhci, dma, &xhci->op_regs->dcbaa_ptr); + "Device context base array address = 0x%pad (DMA), %p (virt)", + &xhci->dcbaa->dma, xhci->dcbaa); /* * Initialize the ring segment pool. The ring must be a contiguous @@ -2446,92 +2434,77 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) else xhci->segment_pool = dma_pool_create("xHCI ring segments", dev, TRB_SEGMENT_SIZE, TRB_SEGMENT_SIZE, xhci->page_size); + if (!xhci->segment_pool) + goto fail; /* See Table 46 and Note on Figure 55 */ - xhci->device_pool = dma_pool_create("xHCI input/output contexts", dev, - 2112, 64, xhci->page_size); - if (!xhci->segment_pool || !xhci->device_pool) + xhci->device_pool = dma_pool_create("xHCI input/output contexts", dev, 2112, 64, + xhci->page_size); + if (!xhci->device_pool) goto fail; - /* Linear stream context arrays don't have any boundary restrictions, + /* + * Linear stream context arrays don't have any boundary restrictions, * and only need to be 16-byte aligned. */ - xhci->small_streams_pool = - dma_pool_create("xHCI 256 byte stream ctx arrays", - dev, SMALL_STREAM_ARRAY_SIZE, 16, 0); - xhci->medium_streams_pool = - dma_pool_create("xHCI 1KB stream ctx arrays", - dev, MEDIUM_STREAM_ARRAY_SIZE, 16, 0); - /* Any stream context array bigger than MEDIUM_STREAM_ARRAY_SIZE - * will be allocated with dma_alloc_coherent() + xhci->small_streams_pool = dma_pool_create("xHCI 256 byte stream ctx arrays", + dev, SMALL_STREAM_ARRAY_SIZE, 16, 0); + if (!xhci->small_streams_pool) + goto fail; + + /* + * Any stream context array bigger than MEDIUM_STREAM_ARRAY_SIZE will be + * allocated with dma_alloc_coherent(). */ - if (!xhci->small_streams_pool || !xhci->medium_streams_pool) + xhci->medium_streams_pool = dma_pool_create("xHCI 1KB stream ctx arrays", + dev, MEDIUM_STREAM_ARRAY_SIZE, 16, 0); + if (!xhci->medium_streams_pool) + goto fail; + + /* + * refer to xhci rev1_2 protocol 5.3.3 max ports is 255. + * refer to xhci rev1_2 protocol 6.4.3.14 port bandwidth buffer need + * to be 16-byte aligned. + */ + xhci->port_bw_pool = dma_pool_create("xHCI 256 port bw ctx arrays", + dev, GET_PORT_BW_ARRAY_SIZE, 16, 0); + if (!xhci->port_bw_pool) goto fail; /* Set up the command ring to have one segments for now. */ xhci->cmd_ring = xhci_ring_alloc(xhci, 1, TYPE_COMMAND, 0, flags); if (!xhci->cmd_ring) goto fail; - xhci_dbg_trace(xhci, trace_xhci_dbg_init, - "Allocated command ring at %p", xhci->cmd_ring); - xhci_dbg_trace(xhci, trace_xhci_dbg_init, "First segment DMA is 0x%pad", - &xhci->cmd_ring->first_seg->dma); - /* Set the address in the Command Ring Control register */ - val_64 = xhci_read_64(xhci, &xhci->op_regs->cmd_ring); - val_64 = (val_64 & (u64) CMD_RING_RSVD_BITS) | - (xhci->cmd_ring->first_seg->dma & (u64) ~CMD_RING_RSVD_BITS) | - xhci->cmd_ring->cycle_state; - xhci_dbg_trace(xhci, trace_xhci_dbg_init, - "// Setting command ring address to 0x%016llx", val_64); - xhci_write_64(xhci, val_64, &xhci->op_regs->cmd_ring); + xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Allocated command ring at %p", xhci->cmd_ring); + xhci_dbg_trace(xhci, trace_xhci_dbg_init, "First segment DMA is 0x%pad", + &xhci->cmd_ring->first_seg->dma); - /* Reserve one command ring TRB for disabling LPM. + /* + * Reserve one command ring TRB for disabling LPM. * Since the USB core grabs the shared usb_bus bandwidth mutex before * disabling LPM, we only need to reserve one TRB for all devices. */ xhci->cmd_ring_reserved_trbs++; - val = readl(&xhci->cap_regs->db_off); - val &= DBOFF_MASK; - xhci_dbg_trace(xhci, trace_xhci_dbg_init, - "// Doorbell array is located at offset 0x%x from cap regs base addr", - val); - xhci->dba = (void __iomem *) xhci->cap_regs + val; - /* Allocate and set up primary interrupter 0 with an event ring. */ - xhci_dbg_trace(xhci, trace_xhci_dbg_init, - "Allocating primary event ring"); + xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Allocating primary event ring"); xhci->interrupters = kcalloc_node(xhci->max_interrupters, sizeof(*xhci->interrupters), flags, dev_to_node(dev)); - - ir = xhci_alloc_interrupter(xhci, 0, flags); - if (!ir) + if (!xhci->interrupters) goto fail; - if (xhci_add_interrupter(xhci, ir, 0)) + xhci->interrupters[0] = xhci_alloc_interrupter(xhci, 0, flags); + if (!xhci->interrupters[0]) goto fail; - ir->isoc_bei_interval = AVOID_BEI_INTERVAL_MAX; - - for (i = 0; i < MAX_HC_SLOTS; i++) - xhci->devs[i] = NULL; - if (scratchpad_alloc(xhci, flags)) goto fail; + if (xhci_setup_port_arrays(xhci, flags)) goto fail; - /* Enable USB 3.0 device notifications for function remote wake, which - * is necessary for allowing USB 3.0 devices to do remote wakeup from - * U3 (device suspend). - */ - temp = readl(&xhci->op_regs->dev_notification); - temp &= ~DEV_NOTE_MASK; - temp |= DEV_NOTE_FWAKE; - writel(temp, &xhci->op_regs->dev_notification); - return 0; fail: diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index 3155e3a842da..6dab142e7278 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -267,6 +267,8 @@ int xhci_plat_probe(struct platform_device *pdev, struct device *sysdev, const s device_property_read_u32(tmpdev, "imod-interval-ns", &xhci->imod_interval); + device_property_read_u16(tmpdev, "num-hc-interrupters", + &xhci->max_interrupters); } /* diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 423bf3649570..e038ad3375dc 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1898,6 +1898,8 @@ static void handle_cmd_completion(struct xhci_hcd *xhci, case TRB_NEC_GET_FW: xhci_handle_cmd_nec_get_fw(xhci, event); break; + case TRB_GET_BW: + break; default: /* Skip over unknown commands on the event ring */ xhci_info(xhci, "INFO unknown command type %d\n", cmd_type); @@ -2977,9 +2979,6 @@ debug_finding_td: (unsigned long long)xhci_trb_virt_to_dma(td->start_seg, td->start_trb), (unsigned long long)xhci_trb_virt_to_dma(td->end_seg, td->end_trb)); - xhci_for_each_ring_seg(ep_ring->first_seg, ep_seg) - xhci_warn(xhci, "Ring seg %u dma %pad\n", ep_seg->num, &ep_seg->dma); - return -ESHUTDOWN; err_out: @@ -3050,9 +3049,9 @@ static int xhci_handle_event_trb(struct xhci_hcd *xhci, struct xhci_interrupter * - When all events have finished * - To avoid "Event Ring Full Error" condition */ -static void xhci_update_erst_dequeue(struct xhci_hcd *xhci, - struct xhci_interrupter *ir, - bool clear_ehb) +void xhci_update_erst_dequeue(struct xhci_hcd *xhci, + struct xhci_interrupter *ir, + bool clear_ehb) { u64 temp_64; dma_addr_t deq; @@ -3083,11 +3082,14 @@ static void xhci_update_erst_dequeue(struct xhci_hcd *xhci, static void xhci_clear_interrupt_pending(struct xhci_interrupter *ir) { if (!ir->ip_autoclear) { - u32 irq_pending; + u32 iman; + + iman = readl(&ir->ir_set->iman); + iman |= IMAN_IP; + writel(iman, &ir->ir_set->iman); - irq_pending = readl(&ir->ir_set->irq_pending); - irq_pending |= IMAN_IP; - writel(irq_pending, &ir->ir_set->irq_pending); + /* Read operation to guarantee the write has been flushed from posted buffers */ + readl(&ir->ir_set->iman); } } @@ -3095,10 +3097,11 @@ static void xhci_clear_interrupt_pending(struct xhci_interrupter *ir) * Handle all OS-owned events on an interrupter event ring. It may drop * and reaquire xhci->lock between event processing. */ -static int xhci_handle_events(struct xhci_hcd *xhci, struct xhci_interrupter *ir) +static int xhci_handle_events(struct xhci_hcd *xhci, struct xhci_interrupter *ir, + bool skip_events) { int event_loop = 0; - int err; + int err = 0; u64 temp; xhci_clear_interrupt_pending(ir); @@ -3121,7 +3124,8 @@ static int xhci_handle_events(struct xhci_hcd *xhci, struct xhci_interrupter *ir /* Process all OS owned event TRBs on this event ring */ while (unhandled_event_trb(ir->event_ring)) { - err = xhci_handle_event_trb(xhci, ir, ir->event_ring->dequeue); + if (!skip_events) + err = xhci_handle_event_trb(xhci, ir, ir->event_ring->dequeue); /* * If half a segment of events have been handled in one go then @@ -3149,6 +3153,37 @@ static int xhci_handle_events(struct xhci_hcd *xhci, struct xhci_interrupter *ir } /* + * Move the event ring dequeue pointer to skip events kept in the secondary + * event ring. This is used to ensure that pending events in the ring are + * acknowledged, so the xHCI HCD can properly enter suspend/resume. The + * secondary ring is typically maintained by an external component. + */ +void xhci_skip_sec_intr_events(struct xhci_hcd *xhci, + struct xhci_ring *ring, struct xhci_interrupter *ir) +{ + union xhci_trb *current_trb; + u64 erdp_reg; + dma_addr_t deq; + + /* disable irq, ack pending interrupt and ack all pending events */ + xhci_disable_interrupter(xhci, ir); + + /* last acked event trb is in erdp reg */ + erdp_reg = xhci_read_64(xhci, &ir->ir_set->erst_dequeue); + deq = (dma_addr_t)(erdp_reg & ERST_PTR_MASK); + if (!deq) { + xhci_err(xhci, "event ring handling not required\n"); + return; + } + + current_trb = ir->event_ring->dequeue; + /* read cycle state of the last acked trb to find out CCS */ + ring->cycle_state = le32_to_cpu(current_trb->event_cmd.flags) & TRB_CYCLE; + + xhci_handle_events(xhci, ir, true); +} + +/* * xHCI spec says we can get an interrupt, and if the HC has an error condition, * we might get bad data out of the event ring. Section 4.10.2.7 has a list of * indicators of an event TRB error, but we check the status *first* to be safe. @@ -3192,7 +3227,7 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd) writel(status, &xhci->op_regs->status); /* This is the handler of the primary interrupter */ - xhci_handle_events(xhci, xhci->interrupters[0]); + xhci_handle_events(xhci, xhci->interrupters[0], false); out: spin_unlock(&xhci->lock); @@ -4414,6 +4449,17 @@ int xhci_queue_configure_endpoint(struct xhci_hcd *xhci, command_must_succeed); } +/* Queue a get root hub port bandwidth command TRB */ +int xhci_queue_get_port_bw(struct xhci_hcd *xhci, + struct xhci_command *cmd, dma_addr_t in_ctx_ptr, + u8 dev_speed, bool command_must_succeed) +{ + return queue_command(xhci, cmd, lower_32_bits(in_ctx_ptr), + upper_32_bits(in_ctx_ptr), 0, + TRB_TYPE(TRB_GET_BW) | DEV_SPEED_FOR_TRB(dev_speed), + command_must_succeed); +} + /* Queue an evaluate context command TRB */ int xhci_queue_evaluate_context(struct xhci_hcd *xhci, struct xhci_command *cmd, dma_addr_t in_ctx_ptr, u32 slot_id, bool command_must_succeed) diff --git a/drivers/usb/host/xhci-sideband.c b/drivers/usb/host/xhci-sideband.c new file mode 100644 index 000000000000..d49f9886dd84 --- /dev/null +++ b/drivers/usb/host/xhci-sideband.c @@ -0,0 +1,457 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * xHCI host controller sideband support + * + * Copyright (c) 2023-2025, Intel Corporation. + * + * Author: Mathias Nyman + */ + +#include <linux/usb/xhci-sideband.h> +#include <linux/dma-direct.h> + +#include "xhci.h" + +/* sideband internal helpers */ +static struct sg_table * +xhci_ring_to_sgtable(struct xhci_sideband *sb, struct xhci_ring *ring) +{ + struct xhci_segment *seg; + struct sg_table *sgt; + unsigned int n_pages; + struct page **pages; + struct device *dev; + size_t sz; + int i; + + dev = xhci_to_hcd(sb->xhci)->self.sysdev; + sz = ring->num_segs * TRB_SEGMENT_SIZE; + n_pages = PAGE_ALIGN(sz) >> PAGE_SHIFT; + pages = kvmalloc_array(n_pages, sizeof(struct page *), GFP_KERNEL); + if (!pages) + return NULL; + + sgt = kzalloc(sizeof(*sgt), GFP_KERNEL); + if (!sgt) { + kvfree(pages); + return NULL; + } + + seg = ring->first_seg; + if (!seg) + goto err; + /* + * Rings can potentially have multiple segments, create an array that + * carries page references to allocated segments. Utilize the + * sg_alloc_table_from_pages() to create the sg table, and to ensure + * that page links are created. + */ + for (i = 0; i < ring->num_segs; i++) { + dma_get_sgtable(dev, sgt, seg->trbs, seg->dma, + TRB_SEGMENT_SIZE); + pages[i] = sg_page(sgt->sgl); + sg_free_table(sgt); + seg = seg->next; + } + + if (sg_alloc_table_from_pages(sgt, pages, n_pages, 0, sz, GFP_KERNEL)) + goto err; + + /* + * Save first segment dma address to sg dma_address field for the sideband + * client to have access to the IOVA of the ring. + */ + sg_dma_address(sgt->sgl) = ring->first_seg->dma; + + return sgt; + +err: + kvfree(pages); + kfree(sgt); + + return NULL; +} + +static void +__xhci_sideband_remove_endpoint(struct xhci_sideband *sb, struct xhci_virt_ep *ep) +{ + /* + * Issue a stop endpoint command when an endpoint is removed. + * The stop ep cmd handler will handle the ring cleanup. + */ + xhci_stop_endpoint_sync(sb->xhci, ep, 0, GFP_KERNEL); + + ep->sideband = NULL; + sb->eps[ep->ep_index] = NULL; +} + +/* sideband api functions */ + +/** + * xhci_sideband_notify_ep_ring_free - notify client of xfer ring free + * @sb: sideband instance for this usb device + * @ep_index: usb endpoint index + * + * Notifies the xHCI sideband client driver of a xHCI transfer ring free + * routine. This will allow for the client to ensure that all transfers + * are completed. + * + * The callback should be synchronous, as the ring free happens after. + */ +void xhci_sideband_notify_ep_ring_free(struct xhci_sideband *sb, + unsigned int ep_index) +{ + struct xhci_sideband_event evt; + + evt.type = XHCI_SIDEBAND_XFER_RING_FREE; + evt.evt_data = &ep_index; + + if (sb->notify_client) + sb->notify_client(sb->intf, &evt); +} +EXPORT_SYMBOL_GPL(xhci_sideband_notify_ep_ring_free); + +/** + * xhci_sideband_add_endpoint - add endpoint to sideband access list + * @sb: sideband instance for this usb device + * @host_ep: usb host endpoint + * + * Adds an endpoint to the list of sideband accessed endpoints for this usb + * device. + * After an endpoint is added the sideband client can get the endpoint transfer + * ring buffer by calling xhci_sideband_endpoint_buffer() + * + * Return: 0 on success, negative error otherwise. + */ +int +xhci_sideband_add_endpoint(struct xhci_sideband *sb, + struct usb_host_endpoint *host_ep) +{ + struct xhci_virt_ep *ep; + unsigned int ep_index; + + mutex_lock(&sb->mutex); + ep_index = xhci_get_endpoint_index(&host_ep->desc); + ep = &sb->vdev->eps[ep_index]; + + if (ep->ep_state & EP_HAS_STREAMS) { + mutex_unlock(&sb->mutex); + return -EINVAL; + } + + /* + * Note, we don't know the DMA mask of the audio DSP device, if its + * smaller than for xhci it won't be able to access the endpoint ring + * buffer. This could be solved by not allowing the audio class driver + * to add the endpoint the normal way, but instead offload it immediately, + * and let this function add the endpoint and allocate the ring buffer + * with the smallest common DMA mask + */ + if (sb->eps[ep_index] || ep->sideband) { + mutex_unlock(&sb->mutex); + return -EBUSY; + } + + ep->sideband = sb; + sb->eps[ep_index] = ep; + mutex_unlock(&sb->mutex); + + return 0; +} +EXPORT_SYMBOL_GPL(xhci_sideband_add_endpoint); + +/** + * xhci_sideband_remove_endpoint - remove endpoint from sideband access list + * @sb: sideband instance for this usb device + * @host_ep: usb host endpoint + * + * Removes an endpoint from the list of sideband accessed endpoints for this usb + * device. + * sideband client should no longer touch the endpoint transfer buffer after + * calling this. + * + * Return: 0 on success, negative error otherwise. + */ +int +xhci_sideband_remove_endpoint(struct xhci_sideband *sb, + struct usb_host_endpoint *host_ep) +{ + struct xhci_virt_ep *ep; + unsigned int ep_index; + + mutex_lock(&sb->mutex); + ep_index = xhci_get_endpoint_index(&host_ep->desc); + ep = sb->eps[ep_index]; + + if (!ep || !ep->sideband || ep->sideband != sb) { + mutex_unlock(&sb->mutex); + return -ENODEV; + } + + __xhci_sideband_remove_endpoint(sb, ep); + xhci_initialize_ring_info(ep->ring); + mutex_unlock(&sb->mutex); + + return 0; +} +EXPORT_SYMBOL_GPL(xhci_sideband_remove_endpoint); + +int +xhci_sideband_stop_endpoint(struct xhci_sideband *sb, + struct usb_host_endpoint *host_ep) +{ + struct xhci_virt_ep *ep; + unsigned int ep_index; + + ep_index = xhci_get_endpoint_index(&host_ep->desc); + ep = sb->eps[ep_index]; + + if (!ep || !ep->sideband || ep->sideband != sb) + return -EINVAL; + + return xhci_stop_endpoint_sync(sb->xhci, ep, 0, GFP_KERNEL); +} +EXPORT_SYMBOL_GPL(xhci_sideband_stop_endpoint); + +/** + * xhci_sideband_get_endpoint_buffer - gets the endpoint transfer buffer address + * @sb: sideband instance for this usb device + * @host_ep: usb host endpoint + * + * Returns the address of the endpoint buffer where xHC controller reads queued + * transfer TRBs from. This is the starting address of the ringbuffer where the + * sideband client should write TRBs to. + * + * Caller needs to free the returned sg_table + * + * Return: struct sg_table * if successful. NULL otherwise. + */ +struct sg_table * +xhci_sideband_get_endpoint_buffer(struct xhci_sideband *sb, + struct usb_host_endpoint *host_ep) +{ + struct xhci_virt_ep *ep; + unsigned int ep_index; + + ep_index = xhci_get_endpoint_index(&host_ep->desc); + ep = sb->eps[ep_index]; + + if (!ep || !ep->ring || !ep->sideband || ep->sideband != sb) + return NULL; + + return xhci_ring_to_sgtable(sb, ep->ring); +} +EXPORT_SYMBOL_GPL(xhci_sideband_get_endpoint_buffer); + +/** + * xhci_sideband_get_event_buffer - return the event buffer for this device + * @sb: sideband instance for this usb device + * + * If a secondary xhci interupter is set up for this usb device then this + * function returns the address of the event buffer where xHC writes + * the transfer completion events. + * + * Caller needs to free the returned sg_table + * + * Return: struct sg_table * if successful. NULL otherwise. + */ +struct sg_table * +xhci_sideband_get_event_buffer(struct xhci_sideband *sb) +{ + if (!sb || !sb->ir) + return NULL; + + return xhci_ring_to_sgtable(sb, sb->ir->event_ring); +} +EXPORT_SYMBOL_GPL(xhci_sideband_get_event_buffer); + +/** + * xhci_sideband_create_interrupter - creates a new interrupter for this sideband + * @sb: sideband instance for this usb device + * @num_seg: number of event ring segments to allocate + * @ip_autoclear: IP autoclearing support such as MSI implemented + * + * Sets up a xhci interrupter that can be used for this sideband accessed usb + * device. Transfer events for this device can be routed to this interrupters + * event ring by setting the 'Interrupter Target' field correctly when queueing + * the transfer TRBs. + * Once this interrupter is created the interrupter target ID can be obtained + * by calling xhci_sideband_interrupter_id() + * + * Returns 0 on success, negative error otherwise + */ +int +xhci_sideband_create_interrupter(struct xhci_sideband *sb, int num_seg, + bool ip_autoclear, u32 imod_interval, int intr_num) +{ + int ret = 0; + + if (!sb || !sb->xhci) + return -ENODEV; + + mutex_lock(&sb->mutex); + if (sb->ir) { + ret = -EBUSY; + goto out; + } + + sb->ir = xhci_create_secondary_interrupter(xhci_to_hcd(sb->xhci), + num_seg, imod_interval, + intr_num); + if (!sb->ir) { + ret = -ENOMEM; + goto out; + } + + sb->ir->ip_autoclear = ip_autoclear; + +out: + mutex_unlock(&sb->mutex); + + return ret; +} +EXPORT_SYMBOL_GPL(xhci_sideband_create_interrupter); + +/** + * xhci_sideband_remove_interrupter - remove the interrupter from a sideband + * @sb: sideband instance for this usb device + * + * Removes a registered interrupt for a sideband. This would allow for other + * sideband users to utilize this interrupter. + */ +void +xhci_sideband_remove_interrupter(struct xhci_sideband *sb) +{ + if (!sb || !sb->ir) + return; + + mutex_lock(&sb->mutex); + xhci_remove_secondary_interrupter(xhci_to_hcd(sb->xhci), sb->ir); + + sb->ir = NULL; + mutex_unlock(&sb->mutex); +} +EXPORT_SYMBOL_GPL(xhci_sideband_remove_interrupter); + +/** + * xhci_sideband_interrupter_id - return the interrupter target id + * @sb: sideband instance for this usb device + * + * If a secondary xhci interrupter is set up for this usb device then this + * function returns the ID used by the interrupter. The sideband client + * needs to write this ID to the 'Interrupter Target' field of the transfer TRBs + * it queues on the endpoints transfer ring to ensure transfer completion event + * are written by xHC to the correct interrupter event ring. + * + * Returns interrupter id on success, negative error othgerwise + */ +int +xhci_sideband_interrupter_id(struct xhci_sideband *sb) +{ + if (!sb || !sb->ir) + return -ENODEV; + + return sb->ir->intr_num; +} +EXPORT_SYMBOL_GPL(xhci_sideband_interrupter_id); + +/** + * xhci_sideband_register - register a sideband for a usb device + * @intf: usb interface associated with the sideband device + * + * Allows for clients to utilize XHCI interrupters and fetch transfer and event + * ring parameters for executing data transfers. + * + * Return: pointer to a new xhci_sideband instance if successful. NULL otherwise. + */ +struct xhci_sideband * +xhci_sideband_register(struct usb_interface *intf, enum xhci_sideband_type type, + int (*notify_client)(struct usb_interface *intf, + struct xhci_sideband_event *evt)) +{ + struct usb_device *udev = interface_to_usbdev(intf); + struct usb_hcd *hcd = bus_to_hcd(udev->bus); + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + struct xhci_virt_device *vdev; + struct xhci_sideband *sb; + + /* + * Make sure the usb device is connected to a xhci controller. Fail + * registration if the type is anything other than XHCI_SIDEBAND_VENDOR, + * as this is the only type that is currently supported by xhci-sideband. + */ + if (!udev->slot_id || type != XHCI_SIDEBAND_VENDOR) + return NULL; + + sb = kzalloc_node(sizeof(*sb), GFP_KERNEL, dev_to_node(hcd->self.sysdev)); + if (!sb) + return NULL; + + mutex_init(&sb->mutex); + + /* check this device isn't already controlled via sideband */ + spin_lock_irq(&xhci->lock); + + vdev = xhci->devs[udev->slot_id]; + + if (!vdev || vdev->sideband) { + xhci_warn(xhci, "XHCI sideband for slot %d already in use\n", + udev->slot_id); + spin_unlock_irq(&xhci->lock); + kfree(sb); + return NULL; + } + + sb->xhci = xhci; + sb->vdev = vdev; + sb->intf = intf; + sb->type = type; + sb->notify_client = notify_client; + vdev->sideband = sb; + + spin_unlock_irq(&xhci->lock); + + return sb; +} +EXPORT_SYMBOL_GPL(xhci_sideband_register); + +/** + * xhci_sideband_unregister - unregister sideband access to a usb device + * @sb: sideband instance to be unregistered + * + * Unregisters sideband access to a usb device and frees the sideband + * instance. + * After this the endpoint and interrupter event buffers should no longer + * be accessed via sideband. The xhci driver can now take over handling + * the buffers. + */ +void +xhci_sideband_unregister(struct xhci_sideband *sb) +{ + struct xhci_hcd *xhci; + int i; + + if (!sb) + return; + + xhci = sb->xhci; + + mutex_lock(&sb->mutex); + for (i = 0; i < EP_CTX_PER_DEV; i++) + if (sb->eps[i]) + __xhci_sideband_remove_endpoint(sb, sb->eps[i]); + mutex_unlock(&sb->mutex); + + xhci_sideband_remove_interrupter(sb); + + spin_lock_irq(&xhci->lock); + sb->xhci = NULL; + sb->vdev->sideband = NULL; + spin_unlock_irq(&xhci->lock); + + kfree(sb); +} +EXPORT_SYMBOL_GPL(xhci_sideband_unregister); +MODULE_DESCRIPTION("xHCI sideband driver for secondary interrupter management"); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 90eb491267b5..4e6dbd2375c3 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -20,6 +20,7 @@ #include <linux/string_choices.h> #include <linux/dmi.h> #include <linux/dma-mapping.h> +#include <linux/usb/xhci-sideband.h> #include "xhci.h" #include "xhci-trace.h" @@ -329,21 +330,29 @@ int xhci_enable_interrupter(struct xhci_interrupter *ir) if (!ir || !ir->ir_set) return -EINVAL; - iman = readl(&ir->ir_set->irq_pending); - writel(ER_IRQ_ENABLE(iman), &ir->ir_set->irq_pending); + iman = readl(&ir->ir_set->iman); + iman |= IMAN_IE; + writel(iman, &ir->ir_set->iman); + /* Read operation to guarantee the write has been flushed from posted buffers */ + readl(&ir->ir_set->iman); return 0; } -int xhci_disable_interrupter(struct xhci_interrupter *ir) +int xhci_disable_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir) { u32 iman; if (!ir || !ir->ir_set) return -EINVAL; - iman = readl(&ir->ir_set->irq_pending); - writel(ER_IRQ_DISABLE(iman), &ir->ir_set->irq_pending); + iman = readl(&ir->ir_set->iman); + iman &= ~IMAN_IE; + writel(iman, &ir->ir_set->iman); + + iman = readl(&ir->ir_set->iman); + if (iman & IMAN_IP) + xhci_dbg(xhci, "%s: Interrupt pending\n", __func__); return 0; } @@ -354,13 +363,16 @@ int xhci_set_interrupter_moderation(struct xhci_interrupter *ir, { u32 imod; - if (!ir || !ir->ir_set || imod_interval > U16_MAX * 250) + if (!ir || !ir->ir_set) return -EINVAL; - imod = readl(&ir->ir_set->irq_control); - imod &= ~ER_IRQ_INTERVAL_MASK; - imod |= (imod_interval / 250) & ER_IRQ_INTERVAL_MASK; - writel(imod, &ir->ir_set->irq_control); + /* IMODI value in IMOD register is in 250ns increments */ + imod_interval = umin(imod_interval / 250, IMODI_MASK); + + imod = readl(&ir->ir_set->imod); + imod &= ~IMODI_MASK; + imod |= imod_interval; + writel(imod, &ir->ir_set->imod); return 0; } @@ -373,7 +385,7 @@ static void compliance_mode_recovery(struct timer_list *t) u32 temp; int i; - xhci = from_timer(xhci, t, comp_mode_recovery_timer); + xhci = timer_container_of(xhci, t, comp_mode_recovery_timer); rhub = &xhci->usb3_rhub; hcd = rhub->hcd; @@ -460,6 +472,82 @@ static int xhci_all_ports_seen_u0(struct xhci_hcd *xhci) return (xhci->port_status_u0 == ((1 << xhci->usb3_rhub.num_ports) - 1)); } +static void xhci_hcd_page_size(struct xhci_hcd *xhci) +{ + u32 page_size; + + page_size = readl(&xhci->op_regs->page_size) & XHCI_PAGE_SIZE_MASK; + if (!is_power_of_2(page_size)) { + xhci_warn(xhci, "Invalid page size register = 0x%x\n", page_size); + /* Fallback to 4K page size, since that's common */ + page_size = 1; + } + + xhci->page_size = page_size << 12; + xhci_dbg_trace(xhci, trace_xhci_dbg_init, "HCD page size set to %iK", + xhci->page_size >> 10); +} + +static void xhci_enable_max_dev_slots(struct xhci_hcd *xhci) +{ + u32 config_reg; + u32 max_slots; + + max_slots = HCS_MAX_SLOTS(xhci->hcs_params1); + xhci_dbg_trace(xhci, trace_xhci_dbg_init, "xHC can handle at most %d device slots", + max_slots); + + config_reg = readl(&xhci->op_regs->config_reg); + config_reg &= ~HCS_SLOTS_MASK; + config_reg |= max_slots; + + xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Setting Max device slots reg = 0x%x", + config_reg); + writel(config_reg, &xhci->op_regs->config_reg); +} + +static void xhci_set_cmd_ring_deq(struct xhci_hcd *xhci) +{ + dma_addr_t deq_dma; + u64 crcr; + + deq_dma = xhci_trb_virt_to_dma(xhci->cmd_ring->deq_seg, xhci->cmd_ring->dequeue); + deq_dma &= CMD_RING_PTR_MASK; + + crcr = xhci_read_64(xhci, &xhci->op_regs->cmd_ring); + crcr &= ~CMD_RING_PTR_MASK; + crcr |= deq_dma; + + crcr &= ~CMD_RING_CYCLE; + crcr |= xhci->cmd_ring->cycle_state; + + xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Setting command ring address to 0x%llx", crcr); + xhci_write_64(xhci, crcr, &xhci->op_regs->cmd_ring); +} + +static void xhci_set_doorbell_ptr(struct xhci_hcd *xhci) +{ + u32 offset; + + offset = readl(&xhci->cap_regs->db_off) & DBOFF_MASK; + xhci->dba = (void __iomem *)xhci->cap_regs + offset; + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "Doorbell array is located at offset 0x%x from cap regs base addr", offset); +} + +/* + * Enable USB 3.0 device notifications for function remote wake, which is necessary + * for allowing USB 3.0 devices to do remote wakeup from U3 (device suspend). + */ +static void xhci_set_dev_notifications(struct xhci_hcd *xhci) +{ + u32 dev_notf; + + dev_notf = readl(&xhci->op_regs->dev_notification); + dev_notf &= ~DEV_NOTE_MASK; + dev_notf |= DEV_NOTE_FWAKE; + writel(dev_notf, &xhci->op_regs->dev_notification); +} /* * Initialize memory for HCD and xHC (one-time init). @@ -473,11 +561,37 @@ static int xhci_init(struct usb_hcd *hcd) struct xhci_hcd *xhci = hcd_to_xhci(hcd); int retval; - xhci_dbg_trace(xhci, trace_xhci_dbg_init, "xhci_init"); + xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Starting %s", __func__); spin_lock_init(&xhci->lock); + INIT_LIST_HEAD(&xhci->cmd_list); + INIT_DELAYED_WORK(&xhci->cmd_timer, xhci_handle_command_timeout); + init_completion(&xhci->cmd_ring_stop_completion); + xhci_hcd_page_size(xhci); + memset(xhci->devs, 0, MAX_HC_SLOTS * sizeof(*xhci->devs)); + retval = xhci_mem_init(xhci, GFP_KERNEL); - xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Finished xhci_init"); + if (retval) + return retval; + + /* Set the Number of Device Slots Enabled to the maximum supported value */ + xhci_enable_max_dev_slots(xhci); + + /* Set the address in the Command Ring Control register */ + xhci_set_cmd_ring_deq(xhci); + + /* Set Device Context Base Address Array pointer */ + xhci_write_64(xhci, xhci->dcbaa->dma, &xhci->op_regs->dcbaa_ptr); + + /* Set Doorbell array pointer */ + xhci_set_doorbell_ptr(xhci); + + /* Set USB 3.0 device notifications for function remote wake */ + xhci_set_dev_notifications(xhci); + + /* Initialize the Primary interrupter */ + xhci_add_interrupter(xhci, 0); + xhci->interrupters[0]->isoc_bei_interval = AVOID_BEI_INTERVAL_MAX; /* Initializing Compliance Mode Recovery Data If Needed */ if (xhci_compliance_mode_recovery_timer_quirk_check()) { @@ -485,7 +599,8 @@ static int xhci_init(struct usb_hcd *hcd) compliance_mode_recovery_timer_init(xhci); } - return retval; + xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Finished %s", __func__); + return 0; } /*-------------------------------------------------------------------------*/ @@ -640,7 +755,7 @@ void xhci_stop(struct usb_hcd *hcd) "// Disabling event ring interrupts"); temp = readl(&xhci->op_regs->status); writel((temp & ~0x1fff) | STS_EINT, &xhci->op_regs->status); - xhci_disable_interrupter(ir); + xhci_disable_interrupter(xhci, ir); xhci_dbg_trace(xhci, trace_xhci_dbg_init, "cleaning up memory"); xhci_mem_cleanup(xhci); @@ -719,8 +834,8 @@ static void xhci_save_registers(struct xhci_hcd *xhci) ir->s3_erst_size = readl(&ir->ir_set->erst_size); ir->s3_erst_base = xhci_read_64(xhci, &ir->ir_set->erst_base); ir->s3_erst_dequeue = xhci_read_64(xhci, &ir->ir_set->erst_dequeue); - ir->s3_irq_pending = readl(&ir->ir_set->irq_pending); - ir->s3_irq_control = readl(&ir->ir_set->irq_control); + ir->s3_iman = readl(&ir->ir_set->iman); + ir->s3_imod = readl(&ir->ir_set->imod); } } @@ -743,28 +858,11 @@ static void xhci_restore_registers(struct xhci_hcd *xhci) writel(ir->s3_erst_size, &ir->ir_set->erst_size); xhci_write_64(xhci, ir->s3_erst_base, &ir->ir_set->erst_base); xhci_write_64(xhci, ir->s3_erst_dequeue, &ir->ir_set->erst_dequeue); - writel(ir->s3_irq_pending, &ir->ir_set->irq_pending); - writel(ir->s3_irq_control, &ir->ir_set->irq_control); + writel(ir->s3_iman, &ir->ir_set->iman); + writel(ir->s3_imod, &ir->ir_set->imod); } } -static void xhci_set_cmd_ring_deq(struct xhci_hcd *xhci) -{ - u64 val_64; - - /* step 2: initialize command ring buffer */ - val_64 = xhci_read_64(xhci, &xhci->op_regs->cmd_ring); - val_64 = (val_64 & (u64) CMD_RING_RSVD_BITS) | - (xhci_trb_virt_to_dma(xhci->cmd_ring->deq_seg, - xhci->cmd_ring->dequeue) & - (u64) ~CMD_RING_RSVD_BITS) | - xhci->cmd_ring->cycle_state; - xhci_dbg_trace(xhci, trace_xhci_dbg_init, - "// Setting command ring address to 0x%llx", - (long unsigned long) val_64); - xhci_write_64(xhci, val_64, &xhci->op_regs->cmd_ring); -} - /* * The whole command ring must be cleared to zero when we suspend the host. * @@ -1092,7 +1190,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool power_lost, bool is_auto_resume) xhci_dbg(xhci, "// Disabling event ring interrupts\n"); temp = readl(&xhci->op_regs->status); writel((temp & ~0x1fff) | STS_EINT, &xhci->op_regs->status); - xhci_disable_interrupter(xhci->interrupters[0]); + xhci_disable_interrupter(xhci, xhci->interrupters[0]); xhci_dbg(xhci, "cleaning up memory\n"); xhci_mem_cleanup(xhci); @@ -1359,6 +1457,7 @@ static void xhci_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb) * xhci_get_endpoint_index - Used for passing endpoint bitmasks between the core and * HCDs. Find the index for an endpoint given its descriptor. Use the return * value to right shift 1 for the bitmask. + * @desc: USB endpoint descriptor to determine index for * * Index = (epnum * 2) + direction - 1, * where direction = 0 for OUT, 1 for IN. @@ -3089,6 +3188,42 @@ void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev) } EXPORT_SYMBOL_GPL(xhci_reset_bandwidth); +/* Get the available bandwidth of the ports under the xhci roothub */ +int xhci_get_port_bandwidth(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx, + u8 dev_speed) +{ + struct xhci_command *cmd; + unsigned long flags; + int ret; + + if (!ctx || !xhci) + return -EINVAL; + + cmd = xhci_alloc_command(xhci, true, GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + cmd->in_ctx = ctx; + + /* get xhci port bandwidth, refer to xhci rev1_2 protocol 4.6.15 */ + spin_lock_irqsave(&xhci->lock, flags); + + ret = xhci_queue_get_port_bw(xhci, cmd, ctx->dma, dev_speed, 0); + if (ret) { + spin_unlock_irqrestore(&xhci->lock, flags); + goto err_out; + } + xhci_ring_cmd_db(xhci); + spin_unlock_irqrestore(&xhci->lock, flags); + + wait_for_completion(cmd->completion); +err_out: + kfree(cmd->completion); + kfree(cmd); + + return ret; +} + static void xhci_setup_input_ctx_for_config_ep(struct xhci_hcd *xhci, struct xhci_container_ctx *in_ctx, struct xhci_container_ctx *out_ctx, @@ -3911,6 +4046,8 @@ static int xhci_discover_or_reset_device(struct usb_hcd *hcd, } if (ep->ring) { + if (ep->sideband) + xhci_sideband_notify_ep_ring_free(ep->sideband, i); xhci_debugfs_remove_endpoint(xhci, virt_dev, i); xhci_free_endpoint_ring(xhci, virt_dev, i); } diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 242ab9fbc8ae..49887a303e43 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -152,10 +152,6 @@ struct xhci_op_regs { #define XHCI_RESET_LONG_USEC (10 * 1000 * 1000) #define XHCI_RESET_SHORT_USEC (250 * 1000) -/* IMAN - Interrupt Management Register */ -#define IMAN_IE (1 << 1) -#define IMAN_IP (1 << 0) - /* USBSTS - USB status - status bitmasks */ /* HC not running - set to 1 when run/stop bit is cleared. */ #define STS_HALT XHCI_STS_HALT @@ -184,23 +180,22 @@ struct xhci_op_regs { * notification type that matches a bit set in this bit field. */ #define DEV_NOTE_MASK (0xffff) -#define ENABLE_DEV_NOTE(x) (1 << (x)) /* Most of the device notification types should only be used for debug. * SW does need to pay attention to function wake notifications. */ -#define DEV_NOTE_FWAKE ENABLE_DEV_NOTE(1) +#define DEV_NOTE_FWAKE (1 << 1) /* CRCR - Command Ring Control Register - cmd_ring bitmasks */ -/* bit 0 is the command ring cycle state */ +/* bit 0 - Cycle bit indicates the ownership of the command ring */ +#define CMD_RING_CYCLE (1 << 0) /* stop ring operation after completion of the currently executing command */ #define CMD_RING_PAUSE (1 << 1) /* stop ring immediately - abort the currently executing command */ #define CMD_RING_ABORT (1 << 2) /* true: command ring is running */ #define CMD_RING_RUNNING (1 << 3) -/* bits 4:5 reserved and should be preserved */ -/* Command Ring pointer - bit mask for the lower 32 bits. */ -#define CMD_RING_RSVD_BITS (0x3f) +/* bits 63:6 - Command Ring pointer */ +#define CMD_RING_PTR_MASK GENMASK_ULL(63, 6) /* CONFIG - Configure Register - config_reg bitmasks */ /* bits 0:7 - maximum number of device slots enabled (NumSlotsEn) */ @@ -215,14 +210,13 @@ struct xhci_op_regs { #define XHCI_PAGE_SIZE_MASK 0xffff /** - * struct xhci_intr_reg - Interrupt Register Set - * @irq_pending: IMAN - Interrupt Management Register. Used to enable + * struct xhci_intr_reg - Interrupt Register Set, v1.2 section 5.5.2. + * @iman: IMAN - Interrupt Management Register. Used to enable * interrupts and check for pending interrupts. - * @irq_control: IMOD - Interrupt Moderation Register. - * Used to throttle interrupts. - * @erst_size: Number of segments in the Event Ring Segment Table (ERST). - * @erst_base: ERST base address. - * @erst_dequeue: Event ring dequeue pointer. + * @imod: IMOD - Interrupt Moderation Register. Used to throttle interrupts. + * @erst_size: ERSTSZ - Number of segments in the Event Ring Segment Table (ERST). + * @erst_base: ERSTBA - Event ring segment table base address. + * @erst_dequeue: ERDP - Event ring dequeue pointer. * * Each interrupter (defined by a MSI-X vector) has an event ring and an Event * Ring Segment Table (ERST) associated with it. The event ring is comprised of @@ -232,48 +226,51 @@ struct xhci_op_regs { * updates the dequeue pointer. */ struct xhci_intr_reg { - __le32 irq_pending; - __le32 irq_control; + __le32 iman; + __le32 imod; __le32 erst_size; __le32 rsvd; __le64 erst_base; __le64 erst_dequeue; }; -/* irq_pending bitmasks */ -#define ER_IRQ_PENDING(p) ((p) & 0x1) -/* bits 2:31 need to be preserved */ -/* THIS IS BUGGY - FIXME - IP IS WRITE 1 TO CLEAR */ -#define ER_IRQ_CLEAR(p) ((p) & 0xfffffffe) -#define ER_IRQ_ENABLE(p) ((ER_IRQ_CLEAR(p)) | 0x2) -#define ER_IRQ_DISABLE(p) ((ER_IRQ_CLEAR(p)) & ~(0x2)) - -/* irq_control bitmasks */ -/* Minimum interval between interrupts (in 250ns intervals). The interval - * between interrupts will be longer if there are no events on the event ring. - * Default is 4000 (1 ms). +/* iman bitmasks */ +/* bit 0 - Interrupt Pending (IP), whether there is an interrupt pending. Write-1-to-clear. */ +#define IMAN_IP (1 << 0) +/* bit 1 - Interrupt Enable (IE), whether the interrupter is capable of generating an interrupt */ +#define IMAN_IE (1 << 1) + +/* imod bitmasks */ +/* + * bits 15:0 - Interrupt Moderation Interval, the minimum interval between interrupts + * (in 250ns intervals). The interval between interrupts will be longer if there are no + * events on the event ring. Default is 4000 (1 ms). */ -#define ER_IRQ_INTERVAL_MASK (0xffff) -/* Counter used to count down the time to the next interrupt - HW use only */ -#define ER_IRQ_COUNTER_MASK (0xffff << 16) +#define IMODI_MASK (0xffff) +/* bits 31:16 - Interrupt Moderation Counter, used to count down the time to the next interrupt */ +#define IMODC_MASK (0xffff << 16) /* erst_size bitmasks */ -/* Preserve bits 16:31 of erst_size */ -#define ERST_SIZE_MASK (0xffff << 16) +/* bits 15:0 - Event Ring Segment Table Size, number of ERST entries */ +#define ERST_SIZE_MASK (0xffff) /* erst_base bitmasks */ -#define ERST_BASE_RSVDP (GENMASK_ULL(5, 0)) +/* bits 63:6 - Event Ring Segment Table Base Address Register */ +#define ERST_BASE_ADDRESS_MASK GENMASK_ULL(63, 6) /* erst_dequeue bitmasks */ -/* Dequeue ERST Segment Index (DESI) - Segment number (or alias) - * where the current dequeue pointer lies. This is an optional HW hint. +/* + * bits 2:0 - Dequeue ERST Segment Index (DESI), is the segment number (or alias) where the + * current dequeue pointer lies. This is an optional HW hint. */ #define ERST_DESI_MASK (0x7) -/* Event Handler Busy (EHB) - is the event ring scheduled to be serviced by +/* + * bit 3 - Event Handler Busy (EHB), whether the event ring is scheduled to be serviced by * a work queue (or delayed service routine)? */ #define ERST_EHB (1 << 3) -#define ERST_PTR_MASK (GENMASK_ULL(63, 4)) +/* bits 63:4 - Event Ring Dequeue Pointer */ +#define ERST_PTR_MASK GENMASK_ULL(63, 4) /** * struct xhci_run_regs @@ -589,6 +586,7 @@ struct xhci_stream_info { #define SMALL_STREAM_ARRAY_SIZE 256 #define MEDIUM_STREAM_ARRAY_SIZE 1024 +#define GET_PORT_BW_ARRAY_SIZE 256 /* Some Intel xHCI host controllers need software to keep track of the bus * bandwidth. Keep track of endpoint info here. Each root port is allocated @@ -700,6 +698,8 @@ struct xhci_virt_ep { int next_frame_id; /* Use new Isoch TRB layout needed for extended TBC support */ bool use_extended_tbc; + /* set if this endpoint is controlled via sideband access*/ + struct xhci_sideband *sideband; }; enum xhci_overhead_type { @@ -762,6 +762,8 @@ struct xhci_virt_device { u16 current_mel; /* Used for the debugfs interfaces. */ void *debugfs_private; + /* set if this endpoint is controlled via sideband access*/ + struct xhci_sideband *sideband; }; /* @@ -1002,6 +1004,9 @@ enum xhci_setup_dev { /* bits 16:23 are the virtual function ID */ /* bits 24:31 are the slot ID */ +/* bits 19:16 are the dev speed */ +#define DEV_SPEED_FOR_TRB(p) ((p) << 16) + /* Stop Endpoint TRB - ep_index to endpoint ID for this TRB */ #define SUSPEND_PORT_FOR_TRB(p) (((p) & 1) << 23) #define TRB_TO_SUSPEND_PORT(p) (((p) & (1 << 23)) >> 23) @@ -1447,8 +1452,8 @@ struct xhci_interrupter { bool ip_autoclear; u32 isoc_bei_interval; /* For interrupter registers save and restore over suspend/resume */ - u32 s3_irq_pending; - u32 s3_irq_control; + u32 s3_iman; + u32 s3_imod; u32 s3_erst_size; u64 s3_erst_base; u64 s3_erst_dequeue; @@ -1554,6 +1559,7 @@ struct xhci_hcd { struct dma_pool *device_pool; struct dma_pool *segment_pool; struct dma_pool *small_streams_pool; + struct dma_pool *port_bw_pool; struct dma_pool *medium_streams_pool; /* Host controller watchdog timer structures */ @@ -1846,11 +1852,18 @@ struct xhci_container_ctx *xhci_alloc_container_ctx(struct xhci_hcd *xhci, int type, gfp_t flags); void xhci_free_container_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx); +struct xhci_container_ctx *xhci_alloc_port_bw_ctx(struct xhci_hcd *xhci, + gfp_t flags); +void xhci_free_port_bw_ctx(struct xhci_hcd *xhci, + struct xhci_container_ctx *ctx); struct xhci_interrupter * xhci_create_secondary_interrupter(struct usb_hcd *hcd, unsigned int segs, - u32 imod_interval); + u32 imod_interval, unsigned int intr_num); void xhci_remove_secondary_interrupter(struct usb_hcd *hcd, struct xhci_interrupter *ir); +void xhci_skip_sec_intr_events(struct xhci_hcd *xhci, + struct xhci_ring *ring, + struct xhci_interrupter *ir); /* xHCI host controller glue */ typedef void (*xhci_get_quirks_t)(struct device *, struct xhci_hcd *); @@ -1891,7 +1904,7 @@ int xhci_alloc_tt_info(struct xhci_hcd *xhci, int xhci_set_interrupter_moderation(struct xhci_interrupter *ir, u32 imod_interval); int xhci_enable_interrupter(struct xhci_interrupter *ir); -int xhci_disable_interrupter(struct xhci_interrupter *ir); +int xhci_disable_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir); /* xHCI ring, segment, TRB, and TD functions */ dma_addr_t xhci_trb_virt_to_dma(struct xhci_segment *seg, union xhci_trb *trb); @@ -1916,6 +1929,11 @@ int xhci_queue_isoc_tx_prepare(struct xhci_hcd *xhci, gfp_t mem_flags, int xhci_queue_configure_endpoint(struct xhci_hcd *xhci, struct xhci_command *cmd, dma_addr_t in_ctx_ptr, u32 slot_id, bool command_must_succeed); +int xhci_queue_get_port_bw(struct xhci_hcd *xhci, + struct xhci_command *cmd, dma_addr_t in_ctx_ptr, + u8 dev_speed, bool command_must_succeed); +int xhci_get_port_bandwidth(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx, + u8 dev_speed); int xhci_queue_evaluate_context(struct xhci_hcd *xhci, struct xhci_command *cmd, dma_addr_t in_ctx_ptr, u32 slot_id, bool command_must_succeed); int xhci_queue_reset_ep(struct xhci_hcd *xhci, struct xhci_command *cmd, @@ -1936,6 +1954,10 @@ unsigned int count_trbs(u64 addr, u64 len); int xhci_stop_endpoint_sync(struct xhci_hcd *xhci, struct xhci_virt_ep *ep, int suspend, gfp_t gfp_flags); void xhci_process_cancelled_tds(struct xhci_virt_ep *ep); +void xhci_update_erst_dequeue(struct xhci_hcd *xhci, + struct xhci_interrupter *ir, + bool clear_ehb); +void xhci_add_interrupter(struct xhci_hcd *xhci, unsigned int intr_num); /* xHCI roothub code */ void xhci_set_link_state(struct xhci_hcd *xhci, struct xhci_port *port, diff --git a/drivers/usb/isp1760/isp1760-udc.c b/drivers/usb/isp1760/isp1760-udc.c index 2af89ee28baa..65ac91d0595a 100644 --- a/drivers/usb/isp1760/isp1760-udc.c +++ b/drivers/usb/isp1760/isp1760-udc.c @@ -1423,7 +1423,7 @@ static irqreturn_t isp1760_udc_irq(int irq, void *dev) static void isp1760_udc_vbus_poll(struct timer_list *t) { - struct isp1760_udc *udc = from_timer(udc, t, vbus_timer); + struct isp1760_udc *udc = timer_container_of(udc, t, vbus_timer); unsigned long flags; spin_lock_irqsave(&udc->lock, flags); diff --git a/drivers/usb/misc/onboard_usb_dev.c b/drivers/usb/misc/onboard_usb_dev.c index f5372dfa241a..5b481876af1b 100644 --- a/drivers/usb/misc/onboard_usb_dev.c +++ b/drivers/usb/misc/onboard_usb_dev.c @@ -36,9 +36,10 @@ #define USB5744_CMD_CREG_ACCESS 0x99 #define USB5744_CMD_CREG_ACCESS_LSB 0x37 #define USB5744_CREG_MEM_ADDR 0x00 +#define USB5744_CREG_MEM_RD_ADDR 0x04 #define USB5744_CREG_WRITE 0x00 -#define USB5744_CREG_RUNTIMEFLAGS2 0x41 -#define USB5744_CREG_RUNTIMEFLAGS2_LSB 0x1D +#define USB5744_CREG_READ 0x01 +#define USB5744_CREG_RUNTIMEFLAGS2 0x411D #define USB5744_CREG_BYPASS_UDC_SUSPEND BIT(3) static void onboard_dev_attach_usb_driver(struct work_struct *work); @@ -309,11 +310,88 @@ static void onboard_dev_attach_usb_driver(struct work_struct *work) pr_err("Failed to attach USB driver: %pe\n", ERR_PTR(err)); } +#if IS_ENABLED(CONFIG_USB_ONBOARD_DEV_USB5744) +static int onboard_dev_5744_i2c_read_byte(struct i2c_client *client, u16 addr, u8 *data) +{ + struct i2c_msg msg[2]; + u8 rd_buf[3]; + int ret; + + u8 wr_buf[7] = {0, USB5744_CREG_MEM_ADDR, 4, + USB5744_CREG_READ, 1, + addr >> 8 & 0xff, + addr & 0xff}; + msg[0].addr = client->addr; + msg[0].flags = 0; + msg[0].len = sizeof(wr_buf); + msg[0].buf = wr_buf; + + ret = i2c_transfer(client->adapter, msg, 1); + if (ret < 0) + return ret; + + wr_buf[0] = USB5744_CMD_CREG_ACCESS; + wr_buf[1] = USB5744_CMD_CREG_ACCESS_LSB; + wr_buf[2] = 0; + msg[0].len = 3; + + ret = i2c_transfer(client->adapter, msg, 1); + if (ret < 0) + return ret; + + wr_buf[0] = 0; + wr_buf[1] = USB5744_CREG_MEM_RD_ADDR; + msg[0].len = 2; + + msg[1].addr = client->addr; + msg[1].flags = I2C_M_RD; + msg[1].len = 2; + msg[1].buf = rd_buf; + + ret = i2c_transfer(client->adapter, msg, 2); + if (ret < 0) + return ret; + *data = rd_buf[1]; + + return 0; +} + +static int onboard_dev_5744_i2c_write_byte(struct i2c_client *client, u16 addr, u8 data) +{ + struct i2c_msg msg[2]; + int ret; + + u8 wr_buf[8] = {0, USB5744_CREG_MEM_ADDR, 5, + USB5744_CREG_WRITE, 1, + addr >> 8 & 0xff, + addr & 0xff, + data}; + msg[0].addr = client->addr; + msg[0].flags = 0; + msg[0].len = sizeof(wr_buf); + msg[0].buf = wr_buf; + + ret = i2c_transfer(client->adapter, msg, 1); + if (ret < 0) + return ret; + + msg[0].len = 3; + wr_buf[0] = USB5744_CMD_CREG_ACCESS; + wr_buf[1] = USB5744_CMD_CREG_ACCESS_LSB; + wr_buf[2] = 0; + + ret = i2c_transfer(client->adapter, msg, 1); + if (ret < 0) + return ret; + + return 0; +} + static int onboard_dev_5744_i2c_init(struct i2c_client *client) { -#if IS_ENABLED(CONFIG_USB_ONBOARD_DEV_USB5744) struct device *dev = &client->dev; int ret; + u8 reg; /* * Set BYPASS_UDC_SUSPEND bit to ensure MCU is always enabled @@ -321,20 +399,16 @@ static int onboard_dev_5744_i2c_init(struct i2c_client *client) * The command writes 5 bytes to memory and single data byte in * configuration register. */ - char wr_buf[7] = {USB5744_CREG_MEM_ADDR, 5, - USB5744_CREG_WRITE, 1, - USB5744_CREG_RUNTIMEFLAGS2, - USB5744_CREG_RUNTIMEFLAGS2_LSB, - USB5744_CREG_BYPASS_UDC_SUSPEND}; - - ret = i2c_smbus_write_block_data(client, 0, sizeof(wr_buf), wr_buf); + ret = onboard_dev_5744_i2c_read_byte(client, + USB5744_CREG_RUNTIMEFLAGS2, ®); if (ret) - return dev_err_probe(dev, ret, "BYPASS_UDC_SUSPEND bit configuration failed\n"); + return dev_err_probe(dev, ret, "CREG_RUNTIMEFLAGS2 read failed\n"); - ret = i2c_smbus_write_word_data(client, USB5744_CMD_CREG_ACCESS, - USB5744_CMD_CREG_ACCESS_LSB); + reg |= USB5744_CREG_BYPASS_UDC_SUSPEND; + ret = onboard_dev_5744_i2c_write_byte(client, + USB5744_CREG_RUNTIMEFLAGS2, reg); if (ret) - return dev_err_probe(dev, ret, "Configuration Register Access Command failed\n"); + return dev_err_probe(dev, ret, "BYPASS_UDC_SUSPEND bit configuration failed\n"); /* Send SMBus command to boot hub. */ ret = i2c_smbus_write_word_data(client, USB5744_CMD_ATTACH, @@ -343,10 +417,13 @@ static int onboard_dev_5744_i2c_init(struct i2c_client *client) return dev_err_probe(dev, ret, "USB Attach with SMBus command failed\n"); return ret; +} #else +static int onboard_dev_5744_i2c_init(struct i2c_client *client) +{ return -ENODEV; -#endif } +#endif static int onboard_dev_probe(struct platform_device *pdev) { @@ -490,6 +567,7 @@ static struct platform_driver onboard_dev_driver = { #define VENDOR_ID_CYPRESS 0x04b4 #define VENDOR_ID_GENESYS 0x05e3 #define VENDOR_ID_MICROCHIP 0x0424 +#define VENDOR_ID_PARADE 0x1da0 #define VENDOR_ID_REALTEK 0x0bda #define VENDOR_ID_TI 0x0451 #define VENDOR_ID_VIA 0x2109 @@ -586,14 +664,19 @@ static const struct usb_device_id onboard_dev_id_table[] = { { USB_DEVICE(VENDOR_ID_MICROCHIP, 0x2517) }, /* USB2517 USB 2.0 HUB */ { USB_DEVICE(VENDOR_ID_MICROCHIP, 0x2744) }, /* USB5744 USB 2.0 HUB */ { USB_DEVICE(VENDOR_ID_MICROCHIP, 0x5744) }, /* USB5744 USB 3.0 HUB */ + { USB_DEVICE(VENDOR_ID_PARADE, 0x5511) }, /* PS5511 USB 3.2 */ + { USB_DEVICE(VENDOR_ID_PARADE, 0x55a1) }, /* PS5511 USB 2.0 */ { USB_DEVICE(VENDOR_ID_REALTEK, 0x0411) }, /* RTS5411 USB 3.1 HUB */ { USB_DEVICE(VENDOR_ID_REALTEK, 0x5411) }, /* RTS5411 USB 2.1 HUB */ { USB_DEVICE(VENDOR_ID_REALTEK, 0x0414) }, /* RTS5414 USB 3.2 HUB */ { USB_DEVICE(VENDOR_ID_REALTEK, 0x5414) }, /* RTS5414 USB 2.1 HUB */ + { USB_DEVICE(VENDOR_ID_REALTEK, 0x0179) }, /* RTL8188ETV 2.4GHz WiFi */ { USB_DEVICE(VENDOR_ID_TI, 0x8025) }, /* TI USB8020B 3.0 HUB */ { USB_DEVICE(VENDOR_ID_TI, 0x8027) }, /* TI USB8020B 2.0 HUB */ { USB_DEVICE(VENDOR_ID_TI, 0x8140) }, /* TI USB8041 3.0 HUB */ { USB_DEVICE(VENDOR_ID_TI, 0x8142) }, /* TI USB8041 2.0 HUB */ + { USB_DEVICE(VENDOR_ID_TI, 0x8440) }, /* TI USB8044 3.0 HUB */ + { USB_DEVICE(VENDOR_ID_TI, 0x8442) }, /* TI USB8044 2.0 HUB */ { USB_DEVICE(VENDOR_ID_VIA, 0x0817) }, /* VIA VL817 3.1 HUB */ { USB_DEVICE(VENDOR_ID_VIA, 0x2817) }, /* VIA VL817 2.0 HUB */ { USB_DEVICE(VENDOR_ID_XMOS, 0x0013) }, /* XMOS XVF3500 Voice Processor */ diff --git a/drivers/usb/misc/onboard_usb_dev.h b/drivers/usb/misc/onboard_usb_dev.h index 933797a7e084..e017b8e22f93 100644 --- a/drivers/usb/misc/onboard_usb_dev.h +++ b/drivers/usb/misc/onboard_usb_dev.h @@ -38,6 +38,13 @@ static const struct onboard_dev_pdata microchip_usb5744_data = { .is_hub = true, }; +static const struct onboard_dev_pdata parade_ps5511_data = { + .reset_us = 500, + .num_supplies = 2, + .supply_names = { "vddd11", "vdd33"}, + .is_hub = true, +}; + static const struct onboard_dev_pdata realtek_rts5411_data = { .reset_us = 0, .num_supplies = 1, @@ -45,6 +52,13 @@ static const struct onboard_dev_pdata realtek_rts5411_data = { .is_hub = true, }; +static const struct onboard_dev_pdata realtek_rtl8188etv_data = { + .reset_us = 0, + .num_supplies = 1, + .supply_names = { "vdd" }, + .is_hub = false, +}; + static const struct onboard_dev_pdata ti_tusb8020b_data = { .reset_us = 3000, .num_supplies = 1, @@ -111,6 +125,8 @@ static const struct of_device_id onboard_dev_match[] = { { .compatible = "usb451,8027", .data = &ti_tusb8020b_data, }, { .compatible = "usb451,8140", .data = &ti_tusb8041_data, }, { .compatible = "usb451,8142", .data = &ti_tusb8041_data, }, + { .compatible = "usb451,8440", .data = &ti_tusb8041_data, }, + { .compatible = "usb451,8442", .data = &ti_tusb8041_data, }, { .compatible = "usb4b4,6504", .data = &cypress_hx3_data, }, { .compatible = "usb4b4,6506", .data = &cypress_hx3_data, }, { .compatible = "usb4b4,6570", .data = &cypress_hx2vl_data, }, @@ -118,10 +134,13 @@ static const struct of_device_id onboard_dev_match[] = { { .compatible = "usb5e3,610", .data = &genesys_gl852g_data, }, { .compatible = "usb5e3,620", .data = &genesys_gl852g_data, }, { .compatible = "usb5e3,626", .data = &genesys_gl852g_data, }, + { .compatible = "usbbda,179", .data = &realtek_rtl8188etv_data, }, { .compatible = "usbbda,411", .data = &realtek_rts5411_data, }, { .compatible = "usbbda,5411", .data = &realtek_rts5411_data, }, { .compatible = "usbbda,414", .data = &realtek_rts5411_data, }, { .compatible = "usbbda,5414", .data = &realtek_rts5411_data, }, + { .compatible = "usb1da0,5511", .data = ¶de_ps5511_data, }, + { .compatible = "usb1da0,55a1", .data = ¶de_ps5511_data, }, { .compatible = "usb2109,817", .data = &vialab_vl817_data, }, { .compatible = "usb2109,2817", .data = &vialab_vl817_data, }, { .compatible = "usb20b1,0013", .data = &xmos_xvf3500_data, }, diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c index 7c2041f61cde..5c92c8d8e283 100644 --- a/drivers/usb/misc/usbtest.c +++ b/drivers/usb/misc/usbtest.c @@ -592,7 +592,7 @@ struct sg_timeout { static void sg_timeout(struct timer_list *t) { - struct sg_timeout *timeout = from_timer(timeout, t, timer); + struct sg_timeout *timeout = timer_container_of(timeout, t, timer); usb_sg_cancel(timeout->req); } diff --git a/drivers/usb/musb/da8xx.c b/drivers/usb/musb/da8xx.c index eebb24ab3ec8..4209f438ba18 100644 --- a/drivers/usb/musb/da8xx.c +++ b/drivers/usb/musb/da8xx.c @@ -123,7 +123,8 @@ static void da8xx_musb_set_vbus(struct musb *musb, int is_on) static void otg_timer(struct timer_list *t) { - struct musb *musb = from_timer(musb, t, dev_timer); + struct musb *musb = timer_container_of(musb, t, + dev_timer); void __iomem *mregs = musb->mregs; u8 devctl; unsigned long flags; diff --git a/drivers/usb/musb/mpfs.c b/drivers/usb/musb/mpfs.c index 020348a98514..587127abd30a 100644 --- a/drivers/usb/musb/mpfs.c +++ b/drivers/usb/musb/mpfs.c @@ -91,7 +91,8 @@ static void mpfs_musb_set_vbus(struct musb *musb, int is_on) static void otg_timer(struct timer_list *t) { - struct musb *musb = from_timer(musb, t, dev_timer); + struct musb *musb = timer_container_of(musb, t, + dev_timer); void __iomem *mregs = musb->mregs; u8 devctl; unsigned long flags; diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index cbbb27178024..c7234b236971 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -596,7 +596,7 @@ void musb_load_testpacket(struct musb *musb) */ static void musb_otg_timer_func(struct timer_list *t) { - struct musb *musb = from_timer(musb, t, otg_timer); + struct musb *musb = timer_container_of(musb, t, otg_timer); unsigned long flags; spin_lock_irqsave(&musb->lock, flags); diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index e5e813f97fac..12f587ab8511 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c @@ -278,7 +278,7 @@ static int dsps_check_status(struct musb *musb, void *unused) static void otg_timer(struct timer_list *t) { - struct musb *musb = from_timer(musb, t, dev_timer); + struct musb *musb = timer_container_of(musb, t, dev_timer); struct device *dev = musb->controller; unsigned long flags; int err; diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c index abd2472da7f7..1d9571f24a56 100644 --- a/drivers/usb/musb/tusb6010.c +++ b/drivers/usb/musb/tusb6010.c @@ -457,7 +457,7 @@ static int tusb_musb_vbus_status(struct musb *musb) static void musb_do_idle(struct timer_list *t) { - struct musb *musb = from_timer(musb, t, dev_timer); + struct musb *musb = timer_container_of(musb, t, dev_timer); unsigned long flags; spin_lock_irqsave(&musb->lock, flags); diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig index 5f629d7cad64..b7acf3966cd7 100644 --- a/drivers/usb/phy/Kconfig +++ b/drivers/usb/phy/Kconfig @@ -126,18 +126,6 @@ config USB_ISP1301 To compile this driver as a module, choose M here: the module will be called phy-isp1301. -config USB_MV_OTG - tristate "Marvell USB OTG support" - depends on USB_EHCI_MV && USB_MV_UDC && PM && USB_OTG - depends on USB_GADGET || !USB_GADGET # if USB_GADGET=m, this can't be 'y' - select USB_PHY - help - Say Y here if you want to build Marvell USB OTG transceiver - driver in kernel (including PXA and MMP series). This driver - implements role switch between EHCI host driver and gadget driver. - - To compile this driver as a module, choose M here. - config USB_MXS_PHY tristate "Freescale MXS USB PHY support" depends on ARCH_MXC || ARCH_MXS diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile index e5d619b4d8f6..ceae46c5341d 100644 --- a/drivers/usb/phy/Makefile +++ b/drivers/usb/phy/Makefile @@ -18,7 +18,6 @@ obj-$(CONFIG_TWL6030_USB) += phy-twl6030-usb.o obj-$(CONFIG_USB_TEGRA_PHY) += phy-tegra-usb.o obj-$(CONFIG_USB_GPIO_VBUS) += phy-gpio-vbus-usb.o obj-$(CONFIG_USB_ISP1301) += phy-isp1301.o -obj-$(CONFIG_USB_MV_OTG) += phy-mv-usb.o obj-$(CONFIG_USB_MXS_PHY) += phy-mxs-usb.o obj-$(CONFIG_USB_ULPI) += phy-ulpi.o obj-$(CONFIG_USB_ULPI_VIEWPORT) += phy-ulpi-viewport.o diff --git a/drivers/usb/phy/phy-mv-usb.c b/drivers/usb/phy/phy-mv-usb.c deleted file mode 100644 index 638fba58420c..000000000000 --- a/drivers/usb/phy/phy-mv-usb.c +++ /dev/null @@ -1,881 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (C) 2011 Marvell International Ltd. All rights reserved. - * Author: Chao Xie <chao.xie@marvell.com> - * Neil Zhang <zhangwm@marvell.com> - */ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/io.h> -#include <linux/iopoll.h> -#include <linux/uaccess.h> -#include <linux/device.h> -#include <linux/proc_fs.h> -#include <linux/clk.h> -#include <linux/workqueue.h> -#include <linux/platform_device.h> -#include <linux/string_choices.h> - -#include <linux/usb.h> -#include <linux/usb/ch9.h> -#include <linux/usb/otg.h> -#include <linux/usb/gadget.h> -#include <linux/usb/hcd.h> -#include <linux/platform_data/mv_usb.h> - -#include "phy-mv-usb.h" - -#define DRIVER_DESC "Marvell USB OTG transceiver driver" - -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); - -static const char driver_name[] = "mv-otg"; - -static char *state_string[] = { - "undefined", - "b_idle", - "b_srp_init", - "b_peripheral", - "b_wait_acon", - "b_host", - "a_idle", - "a_wait_vrise", - "a_wait_bcon", - "a_host", - "a_suspend", - "a_peripheral", - "a_wait_vfall", - "a_vbus_err" -}; - -static int mv_otg_set_vbus(struct usb_otg *otg, bool on) -{ - struct mv_otg *mvotg = container_of(otg->usb_phy, struct mv_otg, phy); - if (mvotg->pdata->set_vbus == NULL) - return -ENODEV; - - return mvotg->pdata->set_vbus(on); -} - -static int mv_otg_set_host(struct usb_otg *otg, - struct usb_bus *host) -{ - otg->host = host; - - return 0; -} - -static int mv_otg_set_peripheral(struct usb_otg *otg, - struct usb_gadget *gadget) -{ - otg->gadget = gadget; - - return 0; -} - -static void mv_otg_run_state_machine(struct mv_otg *mvotg, - unsigned long delay) -{ - dev_dbg(&mvotg->pdev->dev, "transceiver is updated\n"); - if (!mvotg->qwork) - return; - - queue_delayed_work(mvotg->qwork, &mvotg->work, delay); -} - -static void mv_otg_timer_await_bcon(struct timer_list *t) -{ - struct mv_otg *mvotg = from_timer(mvotg, t, - otg_ctrl.timer[A_WAIT_BCON_TIMER]); - - mvotg->otg_ctrl.a_wait_bcon_timeout = 1; - - dev_info(&mvotg->pdev->dev, "B Device No Response!\n"); - - if (spin_trylock(&mvotg->wq_lock)) { - mv_otg_run_state_machine(mvotg, 0); - spin_unlock(&mvotg->wq_lock); - } -} - -static int mv_otg_cancel_timer(struct mv_otg *mvotg, unsigned int id) -{ - struct timer_list *timer; - - if (id >= OTG_TIMER_NUM) - return -EINVAL; - - timer = &mvotg->otg_ctrl.timer[id]; - - if (timer_pending(timer)) - timer_delete(timer); - - return 0; -} - -static int mv_otg_set_timer(struct mv_otg *mvotg, unsigned int id, - unsigned long interval) -{ - struct timer_list *timer; - - if (id >= OTG_TIMER_NUM) - return -EINVAL; - - timer = &mvotg->otg_ctrl.timer[id]; - if (timer_pending(timer)) { - dev_err(&mvotg->pdev->dev, "Timer%d is already running\n", id); - return -EBUSY; - } - - timer->expires = jiffies + interval; - add_timer(timer); - - return 0; -} - -static int mv_otg_reset(struct mv_otg *mvotg) -{ - u32 tmp; - int ret; - - /* Stop the controller */ - tmp = readl(&mvotg->op_regs->usbcmd); - tmp &= ~USBCMD_RUN_STOP; - writel(tmp, &mvotg->op_regs->usbcmd); - - /* Reset the controller to get default values */ - writel(USBCMD_CTRL_RESET, &mvotg->op_regs->usbcmd); - - ret = readl_poll_timeout_atomic(&mvotg->op_regs->usbcmd, tmp, - (tmp & USBCMD_CTRL_RESET), 10, 10000); - if (ret < 0) { - dev_err(&mvotg->pdev->dev, - "Wait for RESET completed TIMEOUT\n"); - return ret; - } - - writel(0x0, &mvotg->op_regs->usbintr); - tmp = readl(&mvotg->op_regs->usbsts); - writel(tmp, &mvotg->op_regs->usbsts); - - return 0; -} - -static void mv_otg_init_irq(struct mv_otg *mvotg) -{ - u32 otgsc; - - mvotg->irq_en = OTGSC_INTR_A_SESSION_VALID - | OTGSC_INTR_A_VBUS_VALID; - mvotg->irq_status = OTGSC_INTSTS_A_SESSION_VALID - | OTGSC_INTSTS_A_VBUS_VALID; - - if (mvotg->pdata->vbus == NULL) { - mvotg->irq_en |= OTGSC_INTR_B_SESSION_VALID - | OTGSC_INTR_B_SESSION_END; - mvotg->irq_status |= OTGSC_INTSTS_B_SESSION_VALID - | OTGSC_INTSTS_B_SESSION_END; - } - - if (mvotg->pdata->id == NULL) { - mvotg->irq_en |= OTGSC_INTR_USB_ID; - mvotg->irq_status |= OTGSC_INTSTS_USB_ID; - } - - otgsc = readl(&mvotg->op_regs->otgsc); - otgsc |= mvotg->irq_en; - writel(otgsc, &mvotg->op_regs->otgsc); -} - -static void mv_otg_start_host(struct mv_otg *mvotg, int on) -{ -#ifdef CONFIG_USB - struct usb_otg *otg = mvotg->phy.otg; - struct usb_hcd *hcd; - - if (!otg->host) - return; - - dev_info(&mvotg->pdev->dev, "%s host\n", on ? "start" : "stop"); - - hcd = bus_to_hcd(otg->host); - - if (on) { - usb_add_hcd(hcd, hcd->irq, IRQF_SHARED); - device_wakeup_enable(hcd->self.controller); - } else { - usb_remove_hcd(hcd); - } -#endif /* CONFIG_USB */ -} - -static void mv_otg_start_periphrals(struct mv_otg *mvotg, int on) -{ - struct usb_otg *otg = mvotg->phy.otg; - - if (!otg->gadget) - return; - - dev_info(mvotg->phy.dev, "gadget %s\n", str_on_off(on)); - - if (on) - usb_gadget_vbus_connect(otg->gadget); - else - usb_gadget_vbus_disconnect(otg->gadget); -} - -static void otg_clock_enable(struct mv_otg *mvotg) -{ - clk_prepare_enable(mvotg->clk); -} - -static void otg_clock_disable(struct mv_otg *mvotg) -{ - clk_disable_unprepare(mvotg->clk); -} - -static int mv_otg_enable_internal(struct mv_otg *mvotg) -{ - int retval = 0; - - if (mvotg->active) - return 0; - - dev_dbg(&mvotg->pdev->dev, "otg enabled\n"); - - otg_clock_enable(mvotg); - if (mvotg->pdata->phy_init) { - retval = mvotg->pdata->phy_init(mvotg->phy_regs); - if (retval) { - dev_err(&mvotg->pdev->dev, - "init phy error %d\n", retval); - otg_clock_disable(mvotg); - return retval; - } - } - mvotg->active = 1; - - return 0; - -} - -static int mv_otg_enable(struct mv_otg *mvotg) -{ - if (mvotg->clock_gating) - return mv_otg_enable_internal(mvotg); - - return 0; -} - -static void mv_otg_disable_internal(struct mv_otg *mvotg) -{ - if (mvotg->active) { - dev_dbg(&mvotg->pdev->dev, "otg disabled\n"); - if (mvotg->pdata->phy_deinit) - mvotg->pdata->phy_deinit(mvotg->phy_regs); - otg_clock_disable(mvotg); - mvotg->active = 0; - } -} - -static void mv_otg_disable(struct mv_otg *mvotg) -{ - if (mvotg->clock_gating) - mv_otg_disable_internal(mvotg); -} - -static void mv_otg_update_inputs(struct mv_otg *mvotg) -{ - struct mv_otg_ctrl *otg_ctrl = &mvotg->otg_ctrl; - u32 otgsc; - - otgsc = readl(&mvotg->op_regs->otgsc); - - if (mvotg->pdata->vbus) { - if (mvotg->pdata->vbus->poll() == VBUS_HIGH) { - otg_ctrl->b_sess_vld = 1; - otg_ctrl->b_sess_end = 0; - } else { - otg_ctrl->b_sess_vld = 0; - otg_ctrl->b_sess_end = 1; - } - } else { - otg_ctrl->b_sess_vld = !!(otgsc & OTGSC_STS_B_SESSION_VALID); - otg_ctrl->b_sess_end = !!(otgsc & OTGSC_STS_B_SESSION_END); - } - - if (mvotg->pdata->id) - otg_ctrl->id = !!mvotg->pdata->id->poll(); - else - otg_ctrl->id = !!(otgsc & OTGSC_STS_USB_ID); - - if (mvotg->pdata->otg_force_a_bus_req && !otg_ctrl->id) - otg_ctrl->a_bus_req = 1; - - otg_ctrl->a_sess_vld = !!(otgsc & OTGSC_STS_A_SESSION_VALID); - otg_ctrl->a_vbus_vld = !!(otgsc & OTGSC_STS_A_VBUS_VALID); - - dev_dbg(&mvotg->pdev->dev, "%s: ", __func__); - dev_dbg(&mvotg->pdev->dev, "id %d\n", otg_ctrl->id); - dev_dbg(&mvotg->pdev->dev, "b_sess_vld %d\n", otg_ctrl->b_sess_vld); - dev_dbg(&mvotg->pdev->dev, "b_sess_end %d\n", otg_ctrl->b_sess_end); - dev_dbg(&mvotg->pdev->dev, "a_vbus_vld %d\n", otg_ctrl->a_vbus_vld); - dev_dbg(&mvotg->pdev->dev, "a_sess_vld %d\n", otg_ctrl->a_sess_vld); -} - -static void mv_otg_update_state(struct mv_otg *mvotg) -{ - struct mv_otg_ctrl *otg_ctrl = &mvotg->otg_ctrl; - int old_state = mvotg->phy.otg->state; - - switch (old_state) { - case OTG_STATE_UNDEFINED: - mvotg->phy.otg->state = OTG_STATE_B_IDLE; - fallthrough; - case OTG_STATE_B_IDLE: - if (otg_ctrl->id == 0) - mvotg->phy.otg->state = OTG_STATE_A_IDLE; - else if (otg_ctrl->b_sess_vld) - mvotg->phy.otg->state = OTG_STATE_B_PERIPHERAL; - break; - case OTG_STATE_B_PERIPHERAL: - if (!otg_ctrl->b_sess_vld || otg_ctrl->id == 0) - mvotg->phy.otg->state = OTG_STATE_B_IDLE; - break; - case OTG_STATE_A_IDLE: - if (otg_ctrl->id) - mvotg->phy.otg->state = OTG_STATE_B_IDLE; - else if (!(otg_ctrl->a_bus_drop) && - (otg_ctrl->a_bus_req || otg_ctrl->a_srp_det)) - mvotg->phy.otg->state = OTG_STATE_A_WAIT_VRISE; - break; - case OTG_STATE_A_WAIT_VRISE: - if (otg_ctrl->a_vbus_vld) - mvotg->phy.otg->state = OTG_STATE_A_WAIT_BCON; - break; - case OTG_STATE_A_WAIT_BCON: - if (otg_ctrl->id || otg_ctrl->a_bus_drop - || otg_ctrl->a_wait_bcon_timeout) { - mv_otg_cancel_timer(mvotg, A_WAIT_BCON_TIMER); - mvotg->otg_ctrl.a_wait_bcon_timeout = 0; - mvotg->phy.otg->state = OTG_STATE_A_WAIT_VFALL; - otg_ctrl->a_bus_req = 0; - } else if (!otg_ctrl->a_vbus_vld) { - mv_otg_cancel_timer(mvotg, A_WAIT_BCON_TIMER); - mvotg->otg_ctrl.a_wait_bcon_timeout = 0; - mvotg->phy.otg->state = OTG_STATE_A_VBUS_ERR; - } else if (otg_ctrl->b_conn) { - mv_otg_cancel_timer(mvotg, A_WAIT_BCON_TIMER); - mvotg->otg_ctrl.a_wait_bcon_timeout = 0; - mvotg->phy.otg->state = OTG_STATE_A_HOST; - } - break; - case OTG_STATE_A_HOST: - if (otg_ctrl->id || !otg_ctrl->b_conn - || otg_ctrl->a_bus_drop) - mvotg->phy.otg->state = OTG_STATE_A_WAIT_BCON; - else if (!otg_ctrl->a_vbus_vld) - mvotg->phy.otg->state = OTG_STATE_A_VBUS_ERR; - break; - case OTG_STATE_A_WAIT_VFALL: - if (otg_ctrl->id - || (!otg_ctrl->b_conn && otg_ctrl->a_sess_vld) - || otg_ctrl->a_bus_req) - mvotg->phy.otg->state = OTG_STATE_A_IDLE; - break; - case OTG_STATE_A_VBUS_ERR: - if (otg_ctrl->id || otg_ctrl->a_clr_err - || otg_ctrl->a_bus_drop) { - otg_ctrl->a_clr_err = 0; - mvotg->phy.otg->state = OTG_STATE_A_WAIT_VFALL; - } - break; - default: - break; - } -} - -static void mv_otg_work(struct work_struct *work) -{ - struct mv_otg *mvotg; - struct usb_otg *otg; - int old_state; - - mvotg = container_of(to_delayed_work(work), struct mv_otg, work); - -run: - /* work queue is single thread, or we need spin_lock to protect */ - otg = mvotg->phy.otg; - old_state = otg->state; - - if (!mvotg->active) - return; - - mv_otg_update_inputs(mvotg); - mv_otg_update_state(mvotg); - - if (old_state != mvotg->phy.otg->state) { - dev_info(&mvotg->pdev->dev, "change from state %s to %s\n", - state_string[old_state], - state_string[mvotg->phy.otg->state]); - - switch (mvotg->phy.otg->state) { - case OTG_STATE_B_IDLE: - otg->default_a = 0; - if (old_state == OTG_STATE_B_PERIPHERAL) - mv_otg_start_periphrals(mvotg, 0); - mv_otg_reset(mvotg); - mv_otg_disable(mvotg); - usb_phy_set_event(&mvotg->phy, USB_EVENT_NONE); - break; - case OTG_STATE_B_PERIPHERAL: - mv_otg_enable(mvotg); - mv_otg_start_periphrals(mvotg, 1); - usb_phy_set_event(&mvotg->phy, USB_EVENT_ENUMERATED); - break; - case OTG_STATE_A_IDLE: - otg->default_a = 1; - mv_otg_enable(mvotg); - if (old_state == OTG_STATE_A_WAIT_VFALL) - mv_otg_start_host(mvotg, 0); - mv_otg_reset(mvotg); - break; - case OTG_STATE_A_WAIT_VRISE: - mv_otg_set_vbus(otg, 1); - break; - case OTG_STATE_A_WAIT_BCON: - if (old_state != OTG_STATE_A_HOST) - mv_otg_start_host(mvotg, 1); - mv_otg_set_timer(mvotg, A_WAIT_BCON_TIMER, - T_A_WAIT_BCON); - /* - * Now, we directly enter A_HOST. So set b_conn = 1 - * here. In fact, it need host driver to notify us. - */ - mvotg->otg_ctrl.b_conn = 1; - break; - case OTG_STATE_A_HOST: - break; - case OTG_STATE_A_WAIT_VFALL: - /* - * Now, we has exited A_HOST. So set b_conn = 0 - * here. In fact, it need host driver to notify us. - */ - mvotg->otg_ctrl.b_conn = 0; - mv_otg_set_vbus(otg, 0); - break; - case OTG_STATE_A_VBUS_ERR: - break; - default: - break; - } - goto run; - } -} - -static irqreturn_t mv_otg_irq(int irq, void *dev) -{ - struct mv_otg *mvotg = dev; - u32 otgsc; - - otgsc = readl(&mvotg->op_regs->otgsc); - writel(otgsc, &mvotg->op_regs->otgsc); - - /* - * if we have vbus, then the vbus detection for B-device - * will be done by mv_otg_inputs_irq(). - */ - if (mvotg->pdata->vbus) - if ((otgsc & OTGSC_STS_USB_ID) && - !(otgsc & OTGSC_INTSTS_USB_ID)) - return IRQ_NONE; - - if ((otgsc & mvotg->irq_status) == 0) - return IRQ_NONE; - - mv_otg_run_state_machine(mvotg, 0); - - return IRQ_HANDLED; -} - -static irqreturn_t mv_otg_inputs_irq(int irq, void *dev) -{ - struct mv_otg *mvotg = dev; - - /* The clock may disabled at this time */ - if (!mvotg->active) { - mv_otg_enable(mvotg); - mv_otg_init_irq(mvotg); - } - - mv_otg_run_state_machine(mvotg, 0); - - return IRQ_HANDLED; -} - -static ssize_t -a_bus_req_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct mv_otg *mvotg = dev_get_drvdata(dev); - return scnprintf(buf, PAGE_SIZE, "%d\n", - mvotg->otg_ctrl.a_bus_req); -} - -static ssize_t -a_bus_req_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct mv_otg *mvotg = dev_get_drvdata(dev); - - if (count > 2) - return -1; - - /* We will use this interface to change to A device */ - if (mvotg->phy.otg->state != OTG_STATE_B_IDLE - && mvotg->phy.otg->state != OTG_STATE_A_IDLE) - return -1; - - /* The clock may disabled and we need to set irq for ID detected */ - mv_otg_enable(mvotg); - mv_otg_init_irq(mvotg); - - if (buf[0] == '1') { - mvotg->otg_ctrl.a_bus_req = 1; - mvotg->otg_ctrl.a_bus_drop = 0; - dev_dbg(&mvotg->pdev->dev, - "User request: a_bus_req = 1\n"); - - if (spin_trylock(&mvotg->wq_lock)) { - mv_otg_run_state_machine(mvotg, 0); - spin_unlock(&mvotg->wq_lock); - } - } - - return count; -} - -static DEVICE_ATTR_RW(a_bus_req); - -static ssize_t -a_clr_err_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct mv_otg *mvotg = dev_get_drvdata(dev); - if (!mvotg->phy.otg->default_a) - return -1; - - if (count > 2) - return -1; - - if (buf[0] == '1') { - mvotg->otg_ctrl.a_clr_err = 1; - dev_dbg(&mvotg->pdev->dev, - "User request: a_clr_err = 1\n"); - } - - if (spin_trylock(&mvotg->wq_lock)) { - mv_otg_run_state_machine(mvotg, 0); - spin_unlock(&mvotg->wq_lock); - } - - return count; -} - -static DEVICE_ATTR_WO(a_clr_err); - -static ssize_t -a_bus_drop_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct mv_otg *mvotg = dev_get_drvdata(dev); - return scnprintf(buf, PAGE_SIZE, "%d\n", - mvotg->otg_ctrl.a_bus_drop); -} - -static ssize_t -a_bus_drop_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct mv_otg *mvotg = dev_get_drvdata(dev); - if (!mvotg->phy.otg->default_a) - return -1; - - if (count > 2) - return -1; - - if (buf[0] == '0') { - mvotg->otg_ctrl.a_bus_drop = 0; - dev_dbg(&mvotg->pdev->dev, - "User request: a_bus_drop = 0\n"); - } else if (buf[0] == '1') { - mvotg->otg_ctrl.a_bus_drop = 1; - mvotg->otg_ctrl.a_bus_req = 0; - dev_dbg(&mvotg->pdev->dev, - "User request: a_bus_drop = 1\n"); - dev_dbg(&mvotg->pdev->dev, - "User request: and a_bus_req = 0\n"); - } - - if (spin_trylock(&mvotg->wq_lock)) { - mv_otg_run_state_machine(mvotg, 0); - spin_unlock(&mvotg->wq_lock); - } - - return count; -} - -static DEVICE_ATTR_RW(a_bus_drop); - -static struct attribute *inputs_attrs[] = { - &dev_attr_a_bus_req.attr, - &dev_attr_a_clr_err.attr, - &dev_attr_a_bus_drop.attr, - NULL, -}; - -static const struct attribute_group inputs_attr_group = { - .name = "inputs", - .attrs = inputs_attrs, -}; - -static const struct attribute_group *mv_otg_groups[] = { - &inputs_attr_group, - NULL, -}; - -static void mv_otg_remove(struct platform_device *pdev) -{ - struct mv_otg *mvotg = platform_get_drvdata(pdev); - - if (mvotg->qwork) - destroy_workqueue(mvotg->qwork); - - mv_otg_disable(mvotg); - - usb_remove_phy(&mvotg->phy); -} - -static int mv_otg_probe(struct platform_device *pdev) -{ - struct mv_usb_platform_data *pdata = dev_get_platdata(&pdev->dev); - struct mv_otg *mvotg; - struct usb_otg *otg; - struct resource *r; - int retval = 0, i; - - if (pdata == NULL) { - dev_err(&pdev->dev, "failed to get platform data\n"); - return -ENODEV; - } - - mvotg = devm_kzalloc(&pdev->dev, sizeof(*mvotg), GFP_KERNEL); - if (!mvotg) - return -ENOMEM; - - otg = devm_kzalloc(&pdev->dev, sizeof(*otg), GFP_KERNEL); - if (!otg) - return -ENOMEM; - - platform_set_drvdata(pdev, mvotg); - - mvotg->pdev = pdev; - mvotg->pdata = pdata; - - mvotg->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(mvotg->clk)) - return PTR_ERR(mvotg->clk); - - mvotg->qwork = create_singlethread_workqueue("mv_otg_queue"); - if (!mvotg->qwork) { - dev_dbg(&pdev->dev, "cannot create workqueue for OTG\n"); - return -ENOMEM; - } - - INIT_DELAYED_WORK(&mvotg->work, mv_otg_work); - - /* OTG common part */ - mvotg->pdev = pdev; - mvotg->phy.dev = &pdev->dev; - mvotg->phy.otg = otg; - mvotg->phy.label = driver_name; - - otg->state = OTG_STATE_UNDEFINED; - otg->usb_phy = &mvotg->phy; - otg->set_host = mv_otg_set_host; - otg->set_peripheral = mv_otg_set_peripheral; - otg->set_vbus = mv_otg_set_vbus; - - for (i = 0; i < OTG_TIMER_NUM; i++) - timer_setup(&mvotg->otg_ctrl.timer[i], - mv_otg_timer_await_bcon, 0); - - r = platform_get_resource_byname(mvotg->pdev, - IORESOURCE_MEM, "phyregs"); - if (r == NULL) { - dev_err(&pdev->dev, "no phy I/O memory resource defined\n"); - retval = -ENODEV; - goto err_destroy_workqueue; - } - - mvotg->phy_regs = devm_ioremap(&pdev->dev, r->start, resource_size(r)); - if (mvotg->phy_regs == NULL) { - dev_err(&pdev->dev, "failed to map phy I/O memory\n"); - retval = -EFAULT; - goto err_destroy_workqueue; - } - - r = platform_get_resource_byname(mvotg->pdev, - IORESOURCE_MEM, "capregs"); - if (r == NULL) { - dev_err(&pdev->dev, "no I/O memory resource defined\n"); - retval = -ENODEV; - goto err_destroy_workqueue; - } - - mvotg->cap_regs = devm_ioremap(&pdev->dev, r->start, resource_size(r)); - if (mvotg->cap_regs == NULL) { - dev_err(&pdev->dev, "failed to map I/O memory\n"); - retval = -EFAULT; - goto err_destroy_workqueue; - } - - /* we will acces controller register, so enable the udc controller */ - retval = mv_otg_enable_internal(mvotg); - if (retval) { - dev_err(&pdev->dev, "mv otg enable error %d\n", retval); - goto err_destroy_workqueue; - } - - mvotg->op_regs = - (struct mv_otg_regs __iomem *) ((unsigned long) mvotg->cap_regs - + (readl(mvotg->cap_regs) & CAPLENGTH_MASK)); - - if (pdata->id) { - retval = devm_request_threaded_irq(&pdev->dev, pdata->id->irq, - NULL, mv_otg_inputs_irq, - IRQF_ONESHOT, "id", mvotg); - if (retval) { - dev_info(&pdev->dev, - "Failed to request irq for ID\n"); - pdata->id = NULL; - } - } - - if (pdata->vbus) { - mvotg->clock_gating = 1; - retval = devm_request_threaded_irq(&pdev->dev, pdata->vbus->irq, - NULL, mv_otg_inputs_irq, - IRQF_ONESHOT, "vbus", mvotg); - if (retval) { - dev_info(&pdev->dev, - "Failed to request irq for VBUS, " - "disable clock gating\n"); - mvotg->clock_gating = 0; - pdata->vbus = NULL; - } - } - - if (pdata->disable_otg_clock_gating) - mvotg->clock_gating = 0; - - mv_otg_reset(mvotg); - mv_otg_init_irq(mvotg); - - r = platform_get_resource(mvotg->pdev, IORESOURCE_IRQ, 0); - if (r == NULL) { - dev_err(&pdev->dev, "no IRQ resource defined\n"); - retval = -ENODEV; - goto err_disable_clk; - } - - mvotg->irq = r->start; - if (devm_request_irq(&pdev->dev, mvotg->irq, mv_otg_irq, IRQF_SHARED, - driver_name, mvotg)) { - dev_err(&pdev->dev, "Request irq %d for OTG failed\n", - mvotg->irq); - mvotg->irq = 0; - retval = -ENODEV; - goto err_disable_clk; - } - - retval = usb_add_phy(&mvotg->phy, USB_PHY_TYPE_USB2); - if (retval < 0) { - dev_err(&pdev->dev, "can't register transceiver, %d\n", - retval); - goto err_disable_clk; - } - - spin_lock_init(&mvotg->wq_lock); - if (spin_trylock(&mvotg->wq_lock)) { - mv_otg_run_state_machine(mvotg, 2 * HZ); - spin_unlock(&mvotg->wq_lock); - } - - dev_info(&pdev->dev, - "successful probe OTG device %s clock gating.\n", - mvotg->clock_gating ? "with" : "without"); - - return 0; - -err_disable_clk: - mv_otg_disable_internal(mvotg); -err_destroy_workqueue: - destroy_workqueue(mvotg->qwork); - - return retval; -} - -#ifdef CONFIG_PM -static int mv_otg_suspend(struct platform_device *pdev, pm_message_t state) -{ - struct mv_otg *mvotg = platform_get_drvdata(pdev); - - if (mvotg->phy.otg->state != OTG_STATE_B_IDLE) { - dev_info(&pdev->dev, - "OTG state is not B_IDLE, it is %d!\n", - mvotg->phy.otg->state); - return -EAGAIN; - } - - if (!mvotg->clock_gating) - mv_otg_disable_internal(mvotg); - - return 0; -} - -static int mv_otg_resume(struct platform_device *pdev) -{ - struct mv_otg *mvotg = platform_get_drvdata(pdev); - u32 otgsc; - - if (!mvotg->clock_gating) { - mv_otg_enable_internal(mvotg); - - otgsc = readl(&mvotg->op_regs->otgsc); - otgsc |= mvotg->irq_en; - writel(otgsc, &mvotg->op_regs->otgsc); - - if (spin_trylock(&mvotg->wq_lock)) { - mv_otg_run_state_machine(mvotg, 0); - spin_unlock(&mvotg->wq_lock); - } - } - return 0; -} -#endif - -static struct platform_driver mv_otg_driver = { - .probe = mv_otg_probe, - .remove = mv_otg_remove, - .driver = { - .name = driver_name, - .dev_groups = mv_otg_groups, - }, -#ifdef CONFIG_PM - .suspend = mv_otg_suspend, - .resume = mv_otg_resume, -#endif -}; -module_platform_driver(mv_otg_driver); diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c index 4b35ef216125..f52418fe3fd4 100644 --- a/drivers/usb/renesas_usbhs/common.c +++ b/drivers/usb/renesas_usbhs/common.c @@ -685,10 +685,29 @@ static int usbhs_probe(struct platform_device *pdev) INIT_DELAYED_WORK(&priv->notify_hotplug_work, usbhsc_notify_hotplug); spin_lock_init(usbhs_priv_to_lock(priv)); + /* + * Acquire clocks and enable power management (PM) early in the + * probe process, as the driver accesses registers during + * initialization. Ensure the device is active before proceeding. + */ + pm_runtime_enable(dev); + + ret = usbhsc_clk_get(dev, priv); + if (ret) + goto probe_pm_disable; + + ret = pm_runtime_resume_and_get(dev); + if (ret) + goto probe_clk_put; + + ret = usbhsc_clk_prepare_enable(priv); + if (ret) + goto probe_pm_put; + /* call pipe and module init */ ret = usbhs_pipe_probe(priv); if (ret < 0) - return ret; + goto probe_clk_dis_unprepare; ret = usbhs_fifo_probe(priv); if (ret < 0) @@ -698,19 +717,15 @@ static int usbhs_probe(struct platform_device *pdev) if (ret < 0) goto probe_end_fifo_exit; - /* dev_set_drvdata should be called after usbhs_mod_init */ + /* platform_set_drvdata() should be called after usbhs_mod_probe() */ platform_set_drvdata(pdev, priv); ret = reset_control_deassert(priv->rsts); if (ret) goto probe_fail_rst; - ret = usbhsc_clk_get(dev, priv); - if (ret) - goto probe_fail_clks; - /* - * deviece reset here because + * device reset here because * USB device might be used in boot loader. */ usbhs_sys_clock_ctrl(priv, 0); @@ -721,7 +736,7 @@ static int usbhs_probe(struct platform_device *pdev) if (ret) { dev_warn(dev, "USB function not selected (GPIO)\n"); ret = -ENOTSUPP; - goto probe_end_mod_exit; + goto probe_assert_rest; } } @@ -735,14 +750,19 @@ static int usbhs_probe(struct platform_device *pdev) ret = usbhs_platform_call(priv, hardware_init, pdev); if (ret < 0) { dev_err(dev, "platform init failed.\n"); - goto probe_end_mod_exit; + goto probe_assert_rest; } /* reset phy for connection */ usbhs_platform_call(priv, phy_reset, pdev); - /* power control */ - pm_runtime_enable(dev); + /* + * Disable the clocks that were enabled earlier in the probe path, + * and let the driver handle the clocks beyond this point. + */ + usbhsc_clk_disable_unprepare(priv); + pm_runtime_put(dev); + if (!usbhs_get_dparam(priv, runtime_pwctrl)) { usbhsc_power_ctrl(priv, 1); usbhs_mod_autonomy_mode(priv); @@ -759,9 +779,7 @@ static int usbhs_probe(struct platform_device *pdev) return ret; -probe_end_mod_exit: - usbhsc_clk_put(priv); -probe_fail_clks: +probe_assert_rest: reset_control_assert(priv->rsts); probe_fail_rst: usbhs_mod_remove(priv); @@ -769,6 +787,14 @@ probe_end_fifo_exit: usbhs_fifo_remove(priv); probe_end_pipe_exit: usbhs_pipe_remove(priv); +probe_clk_dis_unprepare: + usbhsc_clk_disable_unprepare(priv); +probe_pm_put: + pm_runtime_put(dev); +probe_clk_put: + usbhsc_clk_put(priv); +probe_pm_disable: + pm_runtime_disable(dev); dev_info(dev, "probe failed (%d)\n", ret); diff --git a/drivers/usb/serial/bus.c b/drivers/usb/serial/bus.c index 2fea1b1db4a2..9e2a18c0b218 100644 --- a/drivers/usb/serial/bus.c +++ b/drivers/usb/serial/bus.c @@ -17,7 +17,7 @@ static int usb_serial_device_match(struct device *dev, const struct device_driver *drv) { const struct usb_serial_port *port = to_usb_serial_port(dev); - struct usb_serial_driver *driver = to_usb_serial_driver(drv); + const struct usb_serial_driver *driver = to_usb_serial_driver(drv); /* * drivers are already assigned to ports in serial_probe so it's diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c index b97ba8ed6801..614de0c2f5f2 100644 --- a/drivers/usb/serial/garmin_gps.c +++ b/drivers/usb/serial/garmin_gps.c @@ -1357,7 +1357,8 @@ static void garmin_unthrottle(struct tty_struct *tty) */ static void timeout_handler(struct timer_list *t) { - struct garmin_data *garmin_data_p = from_timer(garmin_data_p, t, timer); + struct garmin_data *garmin_data_p = timer_container_of(garmin_data_p, + t, timer); /* send the next queued packet to the tty port */ if (garmin_data_p->mode == MODE_NATIVE) diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index 93710b762893..9e9aca271c0a 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -383,7 +383,7 @@ static void mos7840_set_led_sync(struct usb_serial_port *port, __u16 reg, static void mos7840_led_off(struct timer_list *t) { - struct moschip_port *mcs = from_timer(mcs, t, led_timer1); + struct moschip_port *mcs = timer_container_of(mcs, t, led_timer1); /* Turn off LED */ mos7840_set_led_async(mcs, 0x0300, MODEM_CONTROL_REGISTER); @@ -393,7 +393,7 @@ static void mos7840_led_off(struct timer_list *t) static void mos7840_led_flag_off(struct timer_list *t) { - struct moschip_port *mcs = from_timer(mcs, t, led_timer2); + struct moschip_port *mcs = timer_container_of(mcs, t, led_timer2); clear_bit_unlock(MOS7840_FLAG_LED_BUSY, &mcs->flags); } diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index 010688dd9e49..22579d0d8ab8 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -458,6 +458,8 @@ static int pl2303_detect_type(struct usb_serial *serial) case 0x605: case 0x700: /* GR */ case 0x705: + case 0x905: /* GT-2AB */ + case 0x1005: /* GC-Q20 */ return TYPE_HXN; } break; diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index a0c244bc77c0..d671189ecee2 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -729,11 +729,6 @@ static int ti_open(struct tty_struct *tty, struct usb_serial_port *port) /* start read urb */ urb = port->read_urb; - if (!urb) { - dev_err(&port->dev, "%s - no read urb\n", __func__); - status = -EINVAL; - goto unlink_int_urb; - } tport->tp_read_urb_state = TI_READ_URB_RUNNING; urb->context = tport; status = usb_submit_urb(urb, GFP_KERNEL); diff --git a/drivers/usb/storage/realtek_cr.c b/drivers/usb/storage/realtek_cr.c index b387863c245f..c18dfa2ca034 100644 --- a/drivers/usb/storage/realtek_cr.c +++ b/drivers/usb/storage/realtek_cr.c @@ -754,7 +754,8 @@ static void rts51x_modi_suspend_timer(struct rts51x_chip *chip) static void rts51x_suspend_timer_fn(struct timer_list *t) { - struct rts51x_chip *chip = from_timer(chip, t, rts51x_suspend_timer); + struct rts51x_chip *chip = timer_container_of(chip, t, + rts51x_suspend_timer); struct us_data *us = chip->us; switch (rts51x_get_stat(chip)) { diff --git a/drivers/usb/storage/unusual_uas.h b/drivers/usb/storage/unusual_uas.h index d460d71b4257..1477e31d7763 100644 --- a/drivers/usb/storage/unusual_uas.h +++ b/drivers/usb/storage/unusual_uas.h @@ -52,6 +52,13 @@ UNUSUAL_DEV(0x059f, 0x1061, 0x0000, 0x9999, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_NO_REPORT_OPCODES | US_FL_NO_SAME), +/* Reported-by: Zhihong Zhou <zhouzhihong@greatwall.com.cn> */ +UNUSUAL_DEV(0x0781, 0x55e8, 0x0000, 0x9999, + "SanDisk", + "", + USB_SC_DEVICE, USB_PR_DEVICE, NULL, + US_FL_IGNORE_UAS), + /* Reported-by: Hongling Zeng <zenghongling@kylinos.cn> */ UNUSUAL_DEV(0x090c, 0x2000, 0x0000, 0x9999, "Hiksemi", diff --git a/drivers/usb/typec/altmodes/displayport.c b/drivers/usb/typec/altmodes/displayport.c index ac84a6d64c2f..b09b58d7311d 100644 --- a/drivers/usb/typec/altmodes/displayport.c +++ b/drivers/usb/typec/altmodes/displayport.c @@ -393,6 +393,10 @@ static int dp_altmode_vdm(struct typec_altmode *alt, break; case CMDT_RSP_NAK: switch (cmd) { + case DP_CMD_STATUS_UPDATE: + if (typec_altmode_exit(alt)) + dev_err(&dp->alt->dev, "Exit Mode Failed!\n"); + break; case DP_CMD_CONFIGURE: dp->data.conf = 0; ret = dp_altmode_configured(dp); diff --git a/drivers/usb/typec/bus.c b/drivers/usb/typec/bus.c index ae90688d23e4..a884cec9ab7e 100644 --- a/drivers/usb/typec/bus.c +++ b/drivers/usb/typec/bus.c @@ -449,7 +449,7 @@ ATTRIBUTE_GROUPS(typec); static int typec_match(struct device *dev, const struct device_driver *driver) { - struct typec_altmode_driver *drv = to_altmode_driver(driver); + const struct typec_altmode_driver *drv = to_altmode_driver(driver); struct typec_altmode *altmode = to_typec_altmode(dev); const struct typec_device_id *id; diff --git a/drivers/usb/typec/mux.c b/drivers/usb/typec/mux.c index 49926d6e72c7..182c902c42f6 100644 --- a/drivers/usb/typec/mux.c +++ b/drivers/usb/typec/mux.c @@ -214,7 +214,7 @@ int typec_switch_set(struct typec_switch *sw, sw_dev = sw->sw_devs[i]; ret = sw_dev->set(sw_dev, orientation); - if (ret) + if (ret && ret != -EOPNOTSUPP) return ret; } @@ -378,7 +378,7 @@ int typec_mux_set(struct typec_mux *mux, struct typec_mux_state *state) mux_dev = mux->mux_devs[i]; ret = mux_dev->set(mux_dev, state); - if (ret) + if (ret && ret != -EOPNOTSUPP) return ret; } diff --git a/drivers/usb/typec/mux/fsa4480.c b/drivers/usb/typec/mux/fsa4480.c index f71dba8bf07c..c54e42c7e6a1 100644 --- a/drivers/usb/typec/mux/fsa4480.c +++ b/drivers/usb/typec/mux/fsa4480.c @@ -12,6 +12,7 @@ #include <linux/regmap.h> #include <linux/usb/typec_dp.h> #include <linux/usb/typec_mux.h> +#include <linux/regulator/consumer.h> #define FSA4480_DEVICE_ID 0x00 #define FSA4480_DEVICE_ID_VENDOR_ID GENMASK(7, 6) @@ -273,6 +274,10 @@ static int fsa4480_probe(struct i2c_client *client) if (IS_ERR(fsa->regmap)) return dev_err_probe(dev, PTR_ERR(fsa->regmap), "failed to initialize regmap\n"); + ret = devm_regulator_get_enable_optional(dev, "vcc"); + if (ret && ret != -ENODEV) + return dev_err_probe(dev, ret, "Failed to get regulator\n"); + ret = regmap_read(fsa->regmap, FSA4480_DEVICE_ID, &val); if (ret) return dev_err_probe(dev, -ENODEV, "FSA4480 not found\n"); diff --git a/drivers/usb/typec/port-mapper.c b/drivers/usb/typec/port-mapper.c index d42da5720a25..cdbb7c11d714 100644 --- a/drivers/usb/typec/port-mapper.c +++ b/drivers/usb/typec/port-mapper.c @@ -8,6 +8,7 @@ #include <linux/acpi.h> #include <linux/component.h> +#include <linux/thunderbolt.h> #include <linux/usb.h> #include "class.h" @@ -36,6 +37,11 @@ struct each_port_arg { struct component_match *match; }; +static int usb4_port_compare(struct device *dev, void *fwnode) +{ + return usb4_usb3_port_match(dev, fwnode); +} + static int typec_port_compare(struct device *dev, void *fwnode) { return device_match_fwnode(dev, fwnode); @@ -51,9 +57,22 @@ static int typec_port_match(struct device *dev, void *data) if (con_adev == adev) return 0; - if (con_adev->pld_crc == adev->pld_crc) + if (con_adev->pld_crc == adev->pld_crc) { + struct fwnode_handle *adev_fwnode = acpi_fwnode_handle(adev); + component_match_add(&arg->port->dev, &arg->match, typec_port_compare, - acpi_fwnode_handle(adev)); + adev_fwnode); + + /* + * If dev is USB 3.x port, it may have reference to the + * USB4 host interface in which case we can also link the + * Type-C port with the USB4 port. + */ + if (fwnode_property_present(adev_fwnode, "usb4-host-interface")) + component_match_add(&arg->port->dev, &arg->match, + usb4_port_compare, adev_fwnode); + } + return 0; } diff --git a/drivers/usb/typec/tcpm/tcpci.c b/drivers/usb/typec/tcpm/tcpci.c index 19ab6647af70..a56e31b20c21 100644 --- a/drivers/usb/typec/tcpm/tcpci.c +++ b/drivers/usb/typec/tcpm/tcpci.c @@ -17,6 +17,7 @@ #include <linux/usb/tcpci.h> #include <linux/usb/tcpm.h> #include <linux/usb/typec.h> +#include <linux/regulator/consumer.h> #define PD_RETRY_COUNT_DEFAULT 3 #define PD_RETRY_COUNT_3_0_OR_HIGHER 2 @@ -905,6 +906,10 @@ static int tcpci_probe(struct i2c_client *client) int err; u16 val = 0; + err = devm_regulator_get_enable_optional(&client->dev, "vdd"); + if (err && err != -ENODEV) + return dev_err_probe(&client->dev, err, "Failed to get regulator\n"); + chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); if (!chip) return -ENOMEM; diff --git a/drivers/usb/typec/tcpm/tcpci_maxim_core.c b/drivers/usb/typec/tcpm/tcpci_maxim_core.c index fd1b80593367..b5a5ed40faea 100644 --- a/drivers/usb/typec/tcpm/tcpci_maxim_core.c +++ b/drivers/usb/typec/tcpm/tcpci_maxim_core.c @@ -166,7 +166,8 @@ static void process_rx(struct max_tcpci_chip *chip, u16 status) return; } - if (count > sizeof(struct pd_message) || count + 1 > TCPC_RECEIVE_BUFFER_LEN) { + if (count > sizeof(struct pd_message) + 1 || + count + 1 > TCPC_RECEIVE_BUFFER_LEN) { dev_err(chip->dev, "Invalid TCPC_RX_BYTE_CNT %d\n", count); return; } @@ -536,7 +537,10 @@ static int max_tcpci_probe(struct i2c_client *client) return dev_err_probe(&client->dev, ret, "IRQ initialization failed\n"); - device_init_wakeup(chip->dev, true); + ret = devm_device_init_wakeup(chip->dev); + if (ret) + return dev_err_probe(chip->dev, ret, "Failed to init wakeup\n"); + return 0; } diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c index 5ea884ef36af..1a1f9e1f8e4e 100644 --- a/drivers/usb/typec/tcpm/tcpm.c +++ b/drivers/usb/typec/tcpm/tcpm.c @@ -67,6 +67,7 @@ \ S(ACC_UNATTACHED), \ S(DEBUG_ACC_ATTACHED), \ + S(DEBUG_ACC_DEBOUNCE), \ S(AUDIO_ACC_ATTACHED), \ S(AUDIO_ACC_DEBOUNCE), \ \ @@ -313,6 +314,10 @@ struct pd_data { unsigned int operating_snk_mw; }; +#define PD_CAP_REV10 0x1 +#define PD_CAP_REV20 0x2 +#define PD_CAP_REV30 0x3 + struct pd_revision_info { u8 rev_major; u8 rev_minor; @@ -596,6 +601,15 @@ struct pd_rx_event { enum tcpm_transmit_type rx_sop_type; }; +struct altmode_vdm_event { + struct kthread_work work; + struct tcpm_port *port; + u32 header; + u32 *data; + int cnt; + enum tcpm_transmit_type tx_sop_type; +}; + static const char * const pd_rev[] = { [PD_REV10] = "rev1", [PD_REV20] = "rev2", @@ -621,7 +635,8 @@ static const char * const pd_rev[] = { !tcpm_cc_is_source((port)->cc1))) #define tcpm_port_is_debug(port) \ - (tcpm_cc_is_source((port)->cc1) && tcpm_cc_is_source((port)->cc2)) + ((tcpm_cc_is_source((port)->cc1) && tcpm_cc_is_source((port)->cc2)) || \ + (tcpm_cc_is_sink((port)->cc1) && tcpm_cc_is_sink((port)->cc2))) #define tcpm_port_is_audio(port) \ (tcpm_cc_is_audio((port)->cc1) && tcpm_cc_is_audio((port)->cc2)) @@ -1151,7 +1166,7 @@ static int tcpm_set_attached_state(struct tcpm_port *port, bool attached) port->data_role); } -static int tcpm_set_roles(struct tcpm_port *port, bool attached, +static int tcpm_set_roles(struct tcpm_port *port, bool attached, int state, enum typec_role role, enum typec_data_role data) { enum typec_orientation orientation; @@ -1188,7 +1203,7 @@ static int tcpm_set_roles(struct tcpm_port *port, bool attached, } } - ret = tcpm_mux_set(port, TYPEC_STATE_USB, usb_role, orientation); + ret = tcpm_mux_set(port, state, usb_role, orientation); if (ret < 0) return ret; @@ -1608,18 +1623,68 @@ static void tcpm_queue_vdm(struct tcpm_port *port, const u32 header, mod_vdm_delayed_work(port, 0); } -static void tcpm_queue_vdm_unlocked(struct tcpm_port *port, const u32 header, - const u32 *data, int cnt, enum tcpm_transmit_type tx_sop_type) +static void tcpm_queue_vdm_work(struct kthread_work *work) { - if (port->state != SRC_READY && port->state != SNK_READY && - port->state != SRC_VDM_IDENTITY_REQUEST) - return; + struct altmode_vdm_event *event = container_of(work, + struct altmode_vdm_event, + work); + struct tcpm_port *port = event->port; mutex_lock(&port->lock); - tcpm_queue_vdm(port, header, data, cnt, tx_sop_type); + if (port->state != SRC_READY && port->state != SNK_READY && + port->state != SRC_VDM_IDENTITY_REQUEST) { + tcpm_log_force(port, "dropping altmode_vdm_event"); + goto port_unlock; + } + + tcpm_queue_vdm(port, event->header, event->data, event->cnt, event->tx_sop_type); + +port_unlock: + kfree(event->data); + kfree(event); mutex_unlock(&port->lock); } +static int tcpm_queue_vdm_unlocked(struct tcpm_port *port, const u32 header, + const u32 *data, int cnt, enum tcpm_transmit_type tx_sop_type) +{ + struct altmode_vdm_event *event; + u32 *data_cpy; + int ret = -ENOMEM; + + event = kzalloc(sizeof(*event), GFP_KERNEL); + if (!event) + goto err_event; + + data_cpy = kcalloc(cnt, sizeof(u32), GFP_KERNEL); + if (!data_cpy) + goto err_data; + + kthread_init_work(&event->work, tcpm_queue_vdm_work); + event->port = port; + event->header = header; + memcpy(data_cpy, data, sizeof(u32) * cnt); + event->data = data_cpy; + event->cnt = cnt; + event->tx_sop_type = tx_sop_type; + + ret = kthread_queue_work(port->wq, &event->work); + if (!ret) { + ret = -EBUSY; + goto err_queue; + } + + return 0; + +err_queue: + kfree(data_cpy); +err_data: + kfree(event); +err_event: + tcpm_log_force(port, "failed to queue altmode vdm, err:%d", ret); + return ret; +} + static void svdm_consume_identity(struct tcpm_port *port, const u32 *p, int cnt) { u32 vdo = p[VDO_INDEX_IDH]; @@ -2830,8 +2895,7 @@ static int tcpm_altmode_enter(struct typec_altmode *altmode, u32 *vdo) header = VDO(altmode->svid, vdo ? 2 : 1, svdm_version, CMD_ENTER_MODE); header |= VDO_OPOS(altmode->mode); - tcpm_queue_vdm_unlocked(port, header, vdo, vdo ? 1 : 0, TCPC_TX_SOP); - return 0; + return tcpm_queue_vdm_unlocked(port, header, vdo, vdo ? 1 : 0, TCPC_TX_SOP); } static int tcpm_altmode_exit(struct typec_altmode *altmode) @@ -2847,8 +2911,7 @@ static int tcpm_altmode_exit(struct typec_altmode *altmode) header = VDO(altmode->svid, 1, svdm_version, CMD_EXIT_MODE); header |= VDO_OPOS(altmode->mode); - tcpm_queue_vdm_unlocked(port, header, NULL, 0, TCPC_TX_SOP); - return 0; + return tcpm_queue_vdm_unlocked(port, header, NULL, 0, TCPC_TX_SOP); } static int tcpm_altmode_vdm(struct typec_altmode *altmode, @@ -2856,9 +2919,7 @@ static int tcpm_altmode_vdm(struct typec_altmode *altmode, { struct tcpm_port *port = typec_altmode_get_drvdata(altmode); - tcpm_queue_vdm_unlocked(port, header, data, count - 1, TCPC_TX_SOP); - - return 0; + return tcpm_queue_vdm_unlocked(port, header, data, count - 1, TCPC_TX_SOP); } static const struct typec_altmode_ops tcpm_altmode_ops = { @@ -2882,8 +2943,7 @@ static int tcpm_cable_altmode_enter(struct typec_altmode *altmode, enum typec_pl header = VDO(altmode->svid, vdo ? 2 : 1, svdm_version, CMD_ENTER_MODE); header |= VDO_OPOS(altmode->mode); - tcpm_queue_vdm_unlocked(port, header, vdo, vdo ? 1 : 0, TCPC_TX_SOP_PRIME); - return 0; + return tcpm_queue_vdm_unlocked(port, header, vdo, vdo ? 1 : 0, TCPC_TX_SOP_PRIME); } static int tcpm_cable_altmode_exit(struct typec_altmode *altmode, enum typec_plug_index sop) @@ -2899,8 +2959,7 @@ static int tcpm_cable_altmode_exit(struct typec_altmode *altmode, enum typec_plu header = VDO(altmode->svid, 1, svdm_version, CMD_EXIT_MODE); header |= VDO_OPOS(altmode->mode); - tcpm_queue_vdm_unlocked(port, header, NULL, 0, TCPC_TX_SOP_PRIME); - return 0; + return tcpm_queue_vdm_unlocked(port, header, NULL, 0, TCPC_TX_SOP_PRIME); } static int tcpm_cable_altmode_vdm(struct typec_altmode *altmode, enum typec_plug_index sop, @@ -2908,9 +2967,7 @@ static int tcpm_cable_altmode_vdm(struct typec_altmode *altmode, enum typec_plug { struct tcpm_port *port = typec_altmode_get_drvdata(altmode); - tcpm_queue_vdm_unlocked(port, header, data, count - 1, TCPC_TX_SOP_PRIME); - - return 0; + return tcpm_queue_vdm_unlocked(port, header, data, count - 1, TCPC_TX_SOP_PRIME); } static const struct typec_cable_ops tcpm_cable_ops = { @@ -4353,7 +4410,8 @@ static int tcpm_src_attach(struct tcpm_port *port) tcpm_enable_auto_vbus_discharge(port, true); - ret = tcpm_set_roles(port, true, TYPEC_SOURCE, tcpm_data_role_for_source(port)); + ret = tcpm_set_roles(port, true, TYPEC_STATE_USB, + TYPEC_SOURCE, tcpm_data_role_for_source(port)); if (ret < 0) return ret; @@ -4528,7 +4586,8 @@ static int tcpm_snk_attach(struct tcpm_port *port) tcpm_enable_auto_vbus_discharge(port, true); - ret = tcpm_set_roles(port, true, TYPEC_SINK, tcpm_data_role_for_sink(port)); + ret = tcpm_set_roles(port, true, TYPEC_STATE_USB, + TYPEC_SINK, tcpm_data_role_for_sink(port)); if (ret < 0) return ret; @@ -4551,12 +4610,24 @@ static void tcpm_snk_detach(struct tcpm_port *port) static int tcpm_acc_attach(struct tcpm_port *port) { int ret; + enum typec_role role; + enum typec_data_role data; + int state = TYPEC_STATE_USB; if (port->attached) return 0; - ret = tcpm_set_roles(port, true, TYPEC_SOURCE, - tcpm_data_role_for_source(port)); + role = tcpm_port_is_sink(port) ? TYPEC_SINK : TYPEC_SOURCE; + data = tcpm_port_is_sink(port) ? tcpm_data_role_for_sink(port) + : tcpm_data_role_for_source(port); + + if (tcpm_port_is_audio(port)) + state = TYPEC_MODE_AUDIO; + + if (tcpm_port_is_debug(port)) + state = TYPEC_MODE_DEBUG; + + ret = tcpm_set_roles(port, true, state, role, data); if (ret < 0) return ret; @@ -4665,6 +4736,25 @@ static void tcpm_set_initial_svdm_version(struct tcpm_port *port) } } +static void tcpm_set_initial_negotiated_rev(struct tcpm_port *port) +{ + switch (port->pd_rev.rev_major) { + case PD_CAP_REV10: + port->negotiated_rev = PD_REV10; + break; + case PD_CAP_REV20: + port->negotiated_rev = PD_REV20; + break; + case PD_CAP_REV30: + port->negotiated_rev = PD_REV30; + break; + default: + port->negotiated_rev = PD_MAX_REV; + break; + } + port->negotiated_rev_prime = port->negotiated_rev; +} + static void run_state_machine(struct tcpm_port *port) { int ret; @@ -4782,8 +4872,7 @@ static void run_state_machine(struct tcpm_port *port) typec_set_pwr_opmode(port->typec_port, opmode); port->pwr_opmode = TYPEC_PWR_MODE_USB; port->caps_count = 0; - port->negotiated_rev = PD_MAX_REV; - port->negotiated_rev_prime = PD_MAX_REV; + tcpm_set_initial_negotiated_rev(port); port->message_id = 0; port->message_id_prime = 0; port->rx_msgid = -1; @@ -4964,7 +5053,13 @@ static void run_state_machine(struct tcpm_port *port) tcpm_set_state(port, SRC_UNATTACHED, PD_T_DRP_SRC); break; case SNK_ATTACH_WAIT: - if ((port->cc1 == TYPEC_CC_OPEN && + if (tcpm_port_is_debug(port)) + tcpm_set_state(port, DEBUG_ACC_ATTACHED, + PD_T_CC_DEBOUNCE); + else if (tcpm_port_is_audio(port)) + tcpm_set_state(port, AUDIO_ACC_ATTACHED, + PD_T_CC_DEBOUNCE); + else if ((port->cc1 == TYPEC_CC_OPEN && port->cc2 != TYPEC_CC_OPEN) || (port->cc1 != TYPEC_CC_OPEN && port->cc2 == TYPEC_CC_OPEN)) @@ -4978,6 +5073,12 @@ static void run_state_machine(struct tcpm_port *port) if (tcpm_port_is_disconnected(port)) tcpm_set_state(port, SNK_UNATTACHED, PD_T_PD_DEBOUNCE); + else if (tcpm_port_is_debug(port)) + tcpm_set_state(port, DEBUG_ACC_ATTACHED, + PD_T_CC_DEBOUNCE); + else if (tcpm_port_is_audio(port)) + tcpm_set_state(port, AUDIO_ACC_ATTACHED, + PD_T_CC_DEBOUNCE); else if (port->vbus_present) tcpm_set_state(port, tcpm_try_src(port) ? SRC_TRY @@ -5048,8 +5149,7 @@ static void run_state_machine(struct tcpm_port *port) port->cc2 : port->cc1); typec_set_pwr_opmode(port->typec_port, opmode); port->pwr_opmode = TYPEC_PWR_MODE_USB; - port->negotiated_rev = PD_MAX_REV; - port->negotiated_rev_prime = PD_MAX_REV; + tcpm_set_initial_negotiated_rev(port); port->message_id = 0; port->message_id_prime = 0; port->rx_msgid = -1; @@ -5276,7 +5376,10 @@ static void run_state_machine(struct tcpm_port *port) /* Accessory states */ case ACC_UNATTACHED: tcpm_acc_detach(port); - tcpm_set_state(port, SRC_UNATTACHED, 0); + if (port->port_type == TYPEC_PORT_SRC) + tcpm_set_state(port, SRC_UNATTACHED, 0); + else + tcpm_set_state(port, SNK_UNATTACHED, 0); break; case DEBUG_ACC_ATTACHED: case AUDIO_ACC_ATTACHED: @@ -5284,6 +5387,7 @@ static void run_state_machine(struct tcpm_port *port) if (ret < 0) tcpm_set_state(port, ACC_UNATTACHED, 0); break; + case DEBUG_ACC_DEBOUNCE: case AUDIO_ACC_DEBOUNCE: tcpm_set_state(port, ACC_UNATTACHED, port->timings.cc_debounce_time); break; @@ -5326,7 +5430,7 @@ static void run_state_machine(struct tcpm_port *port) */ tcpm_set_vconn(port, false); tcpm_set_vbus(port, false); - tcpm_set_roles(port, port->self_powered, TYPEC_SOURCE, + tcpm_set_roles(port, port->self_powered, TYPEC_STATE_USB, TYPEC_SOURCE, tcpm_data_role_for_source(port)); /* * If tcpc fails to notify vbus off, TCPM will wait for PD_T_SAFE_0V + @@ -5358,7 +5462,7 @@ static void run_state_machine(struct tcpm_port *port) tcpm_set_vconn(port, false); if (port->pd_capable) tcpm_set_charge(port, false); - tcpm_set_roles(port, port->self_powered, TYPEC_SINK, + tcpm_set_roles(port, port->self_powered, TYPEC_STATE_USB, TYPEC_SINK, tcpm_data_role_for_sink(port)); /* * VBUS may or may not toggle, depending on the adapter. @@ -5482,10 +5586,10 @@ static void run_state_machine(struct tcpm_port *port) case DR_SWAP_CHANGE_DR: tcpm_unregister_altmodes(port); if (port->data_role == TYPEC_HOST) - tcpm_set_roles(port, true, port->pwr_role, + tcpm_set_roles(port, true, TYPEC_STATE_USB, port->pwr_role, TYPEC_DEVICE); else - tcpm_set_roles(port, true, port->pwr_role, + tcpm_set_roles(port, true, TYPEC_STATE_USB, port->pwr_role, TYPEC_HOST); tcpm_ams_finish(port); tcpm_set_state(port, ready_state(port), 0); @@ -5875,7 +5979,8 @@ static void _tcpm_cc_change(struct tcpm_port *port, enum typec_cc_status cc1, } break; case SNK_UNATTACHED: - if (tcpm_port_is_sink(port)) + if (tcpm_port_is_debug(port) || tcpm_port_is_audio(port) || + tcpm_port_is_sink(port)) tcpm_set_state(port, SNK_ATTACH_WAIT, 0); break; case SNK_ATTACH_WAIT: @@ -5938,7 +6043,12 @@ static void _tcpm_cc_change(struct tcpm_port *port, enum typec_cc_status cc1, case DEBUG_ACC_ATTACHED: if (cc1 == TYPEC_CC_OPEN || cc2 == TYPEC_CC_OPEN) - tcpm_set_state(port, ACC_UNATTACHED, 0); + tcpm_set_state(port, DEBUG_ACC_DEBOUNCE, 0); + break; + + case DEBUG_ACC_DEBOUNCE: + if (tcpm_port_is_debug(port)) + tcpm_set_state(port, DEBUG_ACC_ATTACHED, 0); break; case SNK_TRY: diff --git a/drivers/usb/typec/tipd/core.c b/drivers/usb/typec/tipd/core.c index 7ee721a877c1..dcf141ada078 100644 --- a/drivers/usb/typec/tipd/core.c +++ b/drivers/usb/typec/tipd/core.c @@ -1431,7 +1431,7 @@ static int tps6598x_probe(struct i2c_client *client) tps->wakeup = device_property_read_bool(tps->dev, "wakeup-source"); if (tps->wakeup && client->irq) { - device_init_wakeup(&client->dev, true); + devm_device_init_wakeup(&client->dev); enable_irq_wake(client->irq); } diff --git a/drivers/usb/typec/tipd/tps6598x.h b/drivers/usb/typec/tipd/tps6598x.h index 9b23e9017452..cecb8d11d239 100644 --- a/drivers/usb/typec/tipd/tps6598x.h +++ b/drivers/usb/typec/tipd/tps6598x.h @@ -27,7 +27,7 @@ #define TPS_STATUS_OVERCURRENT BIT(16) #define TPS_STATUS_GOTO_MIN_ACTIVE BIT(26) #define TPS_STATUS_BIST BIT(27) -#define TPS_STATUS_HIGH_VOLAGE_WARNING BIT(28) +#define TPS_STATUS_HIGH_VOLTAGE_WARNING BIT(28) #define TPS_STATUS_HIGH_LOW_VOLTAGE_WARNING BIT(29) #define TPS_STATUS_CONN_STATE_MASK GENMASK(3, 1) diff --git a/drivers/usb/typec/tipd/trace.h b/drivers/usb/typec/tipd/trace.h index 0669cca12ea1..bea383f2db9d 100644 --- a/drivers/usb/typec/tipd/trace.h +++ b/drivers/usb/typec/tipd/trace.h @@ -153,7 +153,7 @@ { TPS_STATUS_OVERCURRENT, "OVERCURRENT" }, \ { TPS_STATUS_GOTO_MIN_ACTIVE, "GOTO_MIN_ACTIVE" }, \ { TPS_STATUS_BIST, "BIST" }, \ - { TPS_STATUS_HIGH_VOLAGE_WARNING, "HIGH_VOLAGE_WARNING" }, \ + { TPS_STATUS_HIGH_VOLTAGE_WARNING, "HIGH_VOLTAGE_WARNING" }, \ { TPS_STATUS_HIGH_LOW_VOLTAGE_WARNING, "HIGH_LOW_VOLTAGE_WARNING" }) #define show_tps25750_status_flags(flags) \ diff --git a/drivers/usb/typec/ucsi/Kconfig b/drivers/usb/typec/ucsi/Kconfig index 75559601fe8f..8bf8fefb4f07 100644 --- a/drivers/usb/typec/ucsi/Kconfig +++ b/drivers/usb/typec/ucsi/Kconfig @@ -91,4 +91,15 @@ config UCSI_LENOVO_YOGA_C630 To compile the driver as a module, choose M here: the module will be called ucsi_yoga_c630. +config UCSI_HUAWEI_GAOKUN + tristate "UCSI Interface Driver for Huawei Matebook E Go" + depends on EC_HUAWEI_GAOKUN + select DRM_AUX_HPD_BRIDGE if DRM_BRIDGE && OF + help + This driver enables UCSI support on the Huawei Matebook E Go tablet, + which is a sc8280xp-based 2-in-1 tablet. + + To compile the driver as a module, choose M here: the module will be + called ucsi_huawei_gaokun. + endif diff --git a/drivers/usb/typec/ucsi/Makefile b/drivers/usb/typec/ucsi/Makefile index be98a879104d..dbc571763eff 100644 --- a/drivers/usb/typec/ucsi/Makefile +++ b/drivers/usb/typec/ucsi/Makefile @@ -23,3 +23,4 @@ obj-$(CONFIG_UCSI_STM32G0) += ucsi_stm32g0.o obj-$(CONFIG_UCSI_PMIC_GLINK) += ucsi_glink.o obj-$(CONFIG_CROS_EC_UCSI) += cros_ec_ucsi.o obj-$(CONFIG_UCSI_LENOVO_YOGA_C630) += ucsi_yoga_c630.o +obj-$(CONFIG_UCSI_HUAWEI_GAOKUN) += ucsi_huawei_gaokun.o diff --git a/drivers/usb/typec/ucsi/debugfs.c b/drivers/usb/typec/ucsi/debugfs.c index eae2b18a2d8a..92ebf1a2defd 100644 --- a/drivers/usb/typec/ucsi/debugfs.c +++ b/drivers/usb/typec/ucsi/debugfs.c @@ -34,16 +34,20 @@ static int ucsi_cmd(void *data, u64 val) case UCSI_CONNECTOR_RESET: case UCSI_SET_SINK_PATH: case UCSI_SET_NEW_CAM: + case UCSI_SET_USB: ret = ucsi_send_command(ucsi, val, NULL, 0); break; case UCSI_GET_CAPABILITY: case UCSI_GET_CONNECTOR_CAPABILITY: case UCSI_GET_ALTERNATE_MODES: + case UCSI_GET_CAM_SUPPORTED: case UCSI_GET_CURRENT_CAM: case UCSI_GET_PDOS: case UCSI_GET_CABLE_PROPERTY: case UCSI_GET_CONNECTOR_STATUS: case UCSI_GET_ERROR_STATUS: + case UCSI_GET_PD_MESSAGE: + case UCSI_GET_ATTENTION_VDO: case UCSI_GET_CAM_CS: case UCSI_GET_LPM_PPM_INFO: ret = ucsi_send_command(ucsi, val, diff --git a/drivers/usb/typec/ucsi/ucsi.h b/drivers/usb/typec/ucsi/ucsi.h index 9c5278a0c5d4..5a8f947fcece 100644 --- a/drivers/usb/typec/ucsi/ucsi.h +++ b/drivers/usb/typec/ucsi/ucsi.h @@ -125,9 +125,11 @@ void ucsi_connector_change(struct ucsi *ucsi, u8 num); #define UCSI_GET_CONNECTOR_STATUS 0x12 #define UCSI_GET_CONNECTOR_STATUS_SIZE 152 #define UCSI_GET_ERROR_STATUS 0x13 +#define UCSI_GET_ATTENTION_VDO 0x16 #define UCSI_GET_PD_MESSAGE 0x15 #define UCSI_GET_CAM_CS 0x18 #define UCSI_SET_SINK_PATH 0x1c +#define UCSI_SET_USB 0x21 #define UCSI_GET_LPM_PPM_INFO 0x22 #define UCSI_CONNECTOR_NUMBER(_num_) ((u64)(_num_) << 16) @@ -434,7 +436,7 @@ struct ucsi_debugfs_entry { u64 low; u64 high; } response; - u32 status; + int status; struct dentry *dentry; }; diff --git a/drivers/usb/typec/ucsi/ucsi_huawei_gaokun.c b/drivers/usb/typec/ucsi/ucsi_huawei_gaokun.c new file mode 100644 index 000000000000..7b5222081bbb --- /dev/null +++ b/drivers/usb/typec/ucsi/ucsi_huawei_gaokun.c @@ -0,0 +1,526 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * ucsi-huawei-gaokun - A UCSI driver for HUAWEI Matebook E Go + * + * Copyright (C) 2024-2025 Pengyu Luo <mitltlatltl@gmail.com> + */ + +#include <drm/bridge/aux-bridge.h> +#include <linux/auxiliary_bus.h> +#include <linux/bitops.h> +#include <linux/completion.h> +#include <linux/container_of.h> +#include <linux/module.h> +#include <linux/notifier.h> +#include <linux/of.h> +#include <linux/platform_data/huawei-gaokun-ec.h> +#include <linux/string.h> +#include <linux/usb/pd_vdo.h> +#include <linux/usb/typec_altmode.h> +#include <linux/usb/typec_dp.h> +#include <linux/workqueue_types.h> + +#include "ucsi.h" + +#define EC_EVENT_UCSI 0x21 +#define EC_EVENT_USB 0x22 + +#define GAOKUN_CCX_MASK GENMASK(1, 0) +#define GAOKUN_MUX_MASK GENMASK(3, 2) + +#define GAOKUN_DPAM_MASK GENMASK(3, 0) +#define GAOKUN_HPD_STATE_MASK BIT(4) +#define GAOKUN_HPD_IRQ_MASK BIT(5) + +#define GET_IDX(updt) (ffs(updt) - 1) + +#define CCX_TO_ORI(ccx) (++(ccx) % 3) /* convert ccx to enum typec_orientation */ + +/* Configuration Channel Extension */ +enum gaokun_ucsi_ccx { + USBC_CCX_NORMAL, + USBC_CCX_REVERSE, + USBC_CCX_NONE, +}; + +enum gaokun_ucsi_mux { + USBC_MUX_NONE, + USBC_MUX_USB_2L, + USBC_MUX_DP_4L, + USBC_MUX_USB_DP, +}; + +/* based on pmic_glink_altmode_pin_assignment */ +enum gaokun_ucsi_dpam_pan { /* DP Alt Mode Pin Assignments */ + USBC_DPAM_PAN_NONE, + USBC_DPAM_PAN_A, /* Not supported after USB Type-C Standard v1.0b */ + USBC_DPAM_PAN_B, /* Not supported after USB Type-C Standard v1.0b */ + USBC_DPAM_PAN_C, /* USBC_DPAM_PAN_C_REVERSE - 6 */ + USBC_DPAM_PAN_D, + USBC_DPAM_PAN_E, + USBC_DPAM_PAN_F, /* Not supported after USB Type-C Standard v1.0b */ + USBC_DPAM_PAN_A_REVERSE,/* Not supported after USB Type-C Standard v1.0b */ + USBC_DPAM_PAN_B_REVERSE,/* Not supported after USB Type-C Standard v1.0b */ + USBC_DPAM_PAN_C_REVERSE, + USBC_DPAM_PAN_D_REVERSE, + USBC_DPAM_PAN_E_REVERSE, + USBC_DPAM_PAN_F_REVERSE,/* Not supported after USB Type-C Standard v1.0b */ +}; + +struct gaokun_ucsi_reg { + u8 num_ports; + u8 port_updt; + u8 port_data[4]; + u8 checksum; + u8 reserved; +} __packed; + +struct gaokun_ucsi_port { + struct completion usb_ack; + spinlock_t lock; /* serializing port resource access */ + + struct gaokun_ucsi *ucsi; + struct auxiliary_device *bridge; + + int idx; + enum gaokun_ucsi_ccx ccx; + enum gaokun_ucsi_mux mux; + u8 mode; + u16 svid; + u8 hpd_state; + u8 hpd_irq; +}; + +struct gaokun_ucsi { + struct gaokun_ec *ec; + struct ucsi *ucsi; + struct gaokun_ucsi_port *ports; + struct device *dev; + struct delayed_work work; + struct notifier_block nb; + u16 version; + u8 num_ports; +}; + +/* -------------------------------------------------------------------------- */ +/* For UCSI */ + +static int gaokun_ucsi_read_version(struct ucsi *ucsi, u16 *version) +{ + struct gaokun_ucsi *uec = ucsi_get_drvdata(ucsi); + + *version = uec->version; + + return 0; +} + +static int gaokun_ucsi_read_cci(struct ucsi *ucsi, u32 *cci) +{ + struct gaokun_ucsi *uec = ucsi_get_drvdata(ucsi); + u8 buf[GAOKUN_UCSI_READ_SIZE]; + int ret; + + ret = gaokun_ec_ucsi_read(uec->ec, buf); + if (ret) + return ret; + + memcpy(cci, buf, sizeof(*cci)); + + return 0; +} + +static int gaokun_ucsi_read_message_in(struct ucsi *ucsi, + void *val, size_t val_len) +{ + struct gaokun_ucsi *uec = ucsi_get_drvdata(ucsi); + u8 buf[GAOKUN_UCSI_READ_SIZE]; + int ret; + + ret = gaokun_ec_ucsi_read(uec->ec, buf); + if (ret) + return ret; + + memcpy(val, buf + GAOKUN_UCSI_CCI_SIZE, + min(val_len, GAOKUN_UCSI_MSGI_SIZE)); + + return 0; +} + +static int gaokun_ucsi_async_control(struct ucsi *ucsi, u64 command) +{ + struct gaokun_ucsi *uec = ucsi_get_drvdata(ucsi); + u8 buf[GAOKUN_UCSI_WRITE_SIZE] = {}; + + memcpy(buf, &command, sizeof(command)); + + return gaokun_ec_ucsi_write(uec->ec, buf); +} + +static void gaokun_ucsi_update_connector(struct ucsi_connector *con) +{ + struct gaokun_ucsi *uec = ucsi_get_drvdata(con->ucsi); + + if (con->num > uec->num_ports) + return; + + con->typec_cap.orientation_aware = true; +} + +static void gaokun_set_orientation(struct ucsi_connector *con, + struct gaokun_ucsi_port *port) +{ + enum gaokun_ucsi_ccx ccx; + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + ccx = port->ccx; + spin_unlock_irqrestore(&port->lock, flags); + + typec_set_orientation(con->port, CCX_TO_ORI(ccx)); +} + +static void gaokun_ucsi_connector_status(struct ucsi_connector *con) +{ + struct gaokun_ucsi *uec = ucsi_get_drvdata(con->ucsi); + int idx; + + idx = con->num - 1; + if (con->num > uec->num_ports) { + dev_warn(uec->dev, "set orientation out of range: con%d\n", idx); + return; + } + + gaokun_set_orientation(con, &uec->ports[idx]); +} + +const struct ucsi_operations gaokun_ucsi_ops = { + .read_version = gaokun_ucsi_read_version, + .read_cci = gaokun_ucsi_read_cci, + .read_message_in = gaokun_ucsi_read_message_in, + .sync_control = ucsi_sync_control_common, + .async_control = gaokun_ucsi_async_control, + .update_connector = gaokun_ucsi_update_connector, + .connector_status = gaokun_ucsi_connector_status, +}; + +/* -------------------------------------------------------------------------- */ +/* For Altmode */ + +static void gaokun_ucsi_port_update(struct gaokun_ucsi_port *port, + const u8 *port_data) +{ + struct gaokun_ucsi *uec = port->ucsi; + int offset = port->idx * 2; /* every port has 2 Bytes data */ + unsigned long flags; + u8 dcc, ddi; + + dcc = port_data[offset]; + ddi = port_data[offset + 1]; + + spin_lock_irqsave(&port->lock, flags); + + port->ccx = FIELD_GET(GAOKUN_CCX_MASK, dcc); + port->mux = FIELD_GET(GAOKUN_MUX_MASK, dcc); + port->mode = FIELD_GET(GAOKUN_DPAM_MASK, ddi); + port->hpd_state = FIELD_GET(GAOKUN_HPD_STATE_MASK, ddi); + port->hpd_irq = FIELD_GET(GAOKUN_HPD_IRQ_MASK, ddi); + + /* Mode and SVID are unused; keeping them to make things clearer */ + switch (port->mode) { + case USBC_DPAM_PAN_C: + case USBC_DPAM_PAN_C_REVERSE: + port->mode = DP_PIN_ASSIGN_C; /* correct it for usb later */ + break; + case USBC_DPAM_PAN_D: + case USBC_DPAM_PAN_D_REVERSE: + port->mode = DP_PIN_ASSIGN_D; + break; + case USBC_DPAM_PAN_E: + case USBC_DPAM_PAN_E_REVERSE: + port->mode = DP_PIN_ASSIGN_E; + break; + case USBC_DPAM_PAN_NONE: + port->mode = TYPEC_STATE_SAFE; + break; + default: + dev_warn(uec->dev, "unknown mode %d\n", port->mode); + break; + } + + switch (port->mux) { + case USBC_MUX_NONE: + port->svid = 0; + break; + case USBC_MUX_USB_2L: + port->svid = USB_SID_PD; + port->mode = TYPEC_STATE_USB; /* same as PAN_C, correct it */ + break; + case USBC_MUX_DP_4L: + case USBC_MUX_USB_DP: + port->svid = USB_SID_DISPLAYPORT; + break; + default: + dev_warn(uec->dev, "unknown mux state %d\n", port->mux); + break; + } + + spin_unlock_irqrestore(&port->lock, flags); +} + +static int gaokun_ucsi_refresh(struct gaokun_ucsi *uec) +{ + struct gaokun_ucsi_reg ureg; + int ret, idx; + + ret = gaokun_ec_ucsi_get_reg(uec->ec, &ureg); + if (ret) + return GAOKUN_UCSI_NO_PORT_UPDATE; + + uec->num_ports = ureg.num_ports; + idx = GET_IDX(ureg.port_updt); + + if (idx < 0 || idx >= ureg.num_ports) + return GAOKUN_UCSI_NO_PORT_UPDATE; + + gaokun_ucsi_port_update(&uec->ports[idx], ureg.port_data); + return idx; +} + +static void gaokun_ucsi_handle_altmode(struct gaokun_ucsi_port *port) +{ + struct gaokun_ucsi *uec = port->ucsi; + int idx = port->idx; + + if (idx >= uec->ucsi->cap.num_connectors) { + dev_warn(uec->dev, "altmode port out of range: %d\n", idx); + return; + } + + /* UCSI callback .connector_status() have set orientation */ + if (port->bridge) + drm_aux_hpd_bridge_notify(&port->bridge->dev, + port->hpd_state ? + connector_status_connected : + connector_status_disconnected); + + gaokun_ec_ucsi_pan_ack(uec->ec, port->idx); +} + +static void gaokun_ucsi_altmode_notify_ind(struct gaokun_ucsi *uec) +{ + int idx; + + if (!uec->ucsi->connector) { /* slow to register */ + dev_err_ratelimited(uec->dev, "ucsi connector is not initialized yet\n"); + return; + } + + idx = gaokun_ucsi_refresh(uec); + if (idx == GAOKUN_UCSI_NO_PORT_UPDATE) + gaokun_ec_ucsi_pan_ack(uec->ec, idx); /* ack directly if no update */ + else + gaokun_ucsi_handle_altmode(&uec->ports[idx]); +} + +/* + * When inserting, 2 UCSI events(connector change) are followed by USB events. + * If we received one USB event, that means USB events are not blocked, so we + * can complelte for all ports, and we should signal all events. + */ +static void gaokun_ucsi_complete_usb_ack(struct gaokun_ucsi *uec) +{ + struct gaokun_ucsi_port *port; + int idx = 0; + + while (idx < uec->num_ports) { + port = &uec->ports[idx++]; + if (!completion_done(&port->usb_ack)) + complete_all(&port->usb_ack); + } +} + +/* + * USB event is necessary for enabling altmode, the event should follow + * UCSI event, if not after timeout(this notify may be disabled somehow), + * then force to enable altmode. + */ +static void gaokun_ucsi_handle_no_usb_event(struct gaokun_ucsi *uec, int idx) +{ + struct gaokun_ucsi_port *port; + + port = &uec->ports[idx]; + if (!wait_for_completion_timeout(&port->usb_ack, 2 * HZ)) { + dev_warn(uec->dev, "No USB EVENT, triggered by UCSI EVENT"); + gaokun_ucsi_altmode_notify_ind(uec); + } +} + +static int gaokun_ucsi_notify(struct notifier_block *nb, + unsigned long action, void *data) +{ + u32 cci; + int ret; + struct gaokun_ucsi *uec = container_of(nb, struct gaokun_ucsi, nb); + + switch (action) { + case EC_EVENT_USB: + gaokun_ucsi_complete_usb_ack(uec); + gaokun_ucsi_altmode_notify_ind(uec); + return NOTIFY_OK; + + case EC_EVENT_UCSI: + ret = gaokun_ucsi_read_cci(uec->ucsi, &cci); + if (ret) + return NOTIFY_DONE; + + ucsi_notify_common(uec->ucsi, cci); + if (UCSI_CCI_CONNECTOR(cci)) + gaokun_ucsi_handle_no_usb_event(uec, UCSI_CCI_CONNECTOR(cci) - 1); + + return NOTIFY_OK; + + default: + return NOTIFY_DONE; + } +} + +static int gaokun_ucsi_ports_init(struct gaokun_ucsi *uec) +{ + struct gaokun_ucsi_port *ucsi_port; + struct gaokun_ucsi_reg ureg = {}; + struct device *dev = uec->dev; + struct fwnode_handle *fwnode; + int i, ret, num_ports; + u32 port; + + gaokun_ec_ucsi_get_reg(uec->ec, &ureg); + num_ports = ureg.num_ports; + uec->ports = devm_kcalloc(dev, num_ports, sizeof(*uec->ports), + GFP_KERNEL); + if (!uec->ports) + return -ENOMEM; + + for (i = 0; i < num_ports; ++i) { + ucsi_port = &uec->ports[i]; + ucsi_port->ccx = USBC_CCX_NONE; + ucsi_port->idx = i; + ucsi_port->ucsi = uec; + init_completion(&ucsi_port->usb_ack); + spin_lock_init(&ucsi_port->lock); + } + + device_for_each_child_node(dev, fwnode) { + ret = fwnode_property_read_u32(fwnode, "reg", &port); + if (ret < 0) { + dev_err(dev, "missing reg property of %pOFn\n", fwnode); + fwnode_handle_put(fwnode); + return ret; + } + + if (port >= num_ports) { + dev_warn(dev, "invalid connector number %d, ignoring\n", port); + continue; + } + + ucsi_port = &uec->ports[port]; + ucsi_port->bridge = devm_drm_dp_hpd_bridge_alloc(dev, to_of_node(fwnode)); + if (IS_ERR(ucsi_port->bridge)) { + fwnode_handle_put(fwnode); + return PTR_ERR(ucsi_port->bridge); + } + } + + for (i = 0; i < num_ports; i++) { + if (!uec->ports[i].bridge) + continue; + + ret = devm_drm_dp_hpd_bridge_add(dev, uec->ports[i].bridge); + if (ret) + return ret; + } + + return 0; +} + +static void gaokun_ucsi_register_worker(struct work_struct *work) +{ + struct gaokun_ucsi *uec; + struct ucsi *ucsi; + int ret; + + uec = container_of(work, struct gaokun_ucsi, work.work); + ucsi = uec->ucsi; + + ret = gaokun_ec_register_notify(uec->ec, &uec->nb); + if (ret) { + dev_err_probe(ucsi->dev, ret, "notifier register failed\n"); + return; + } + + ret = ucsi_register(ucsi); + if (ret) + dev_err_probe(ucsi->dev, ret, "ucsi register failed\n"); +} + +static int gaokun_ucsi_probe(struct auxiliary_device *adev, + const struct auxiliary_device_id *id) +{ + struct gaokun_ec *ec = adev->dev.platform_data; + struct device *dev = &adev->dev; + struct gaokun_ucsi *uec; + int ret; + + uec = devm_kzalloc(dev, sizeof(*uec), GFP_KERNEL); + if (!uec) + return -ENOMEM; + + uec->ec = ec; + uec->dev = dev; + uec->version = UCSI_VERSION_1_0; + uec->nb.notifier_call = gaokun_ucsi_notify; + + INIT_DELAYED_WORK(&uec->work, gaokun_ucsi_register_worker); + + ret = gaokun_ucsi_ports_init(uec); + if (ret) + return ret; + + uec->ucsi = ucsi_create(dev, &gaokun_ucsi_ops); + if (IS_ERR(uec->ucsi)) + return PTR_ERR(uec->ucsi); + + ucsi_set_drvdata(uec->ucsi, uec); + auxiliary_set_drvdata(adev, uec); + + /* EC can't handle UCSI properly in the early stage */ + schedule_delayed_work(&uec->work, 3 * HZ); + + return 0; +} + +static void gaokun_ucsi_remove(struct auxiliary_device *adev) +{ + struct gaokun_ucsi *uec = auxiliary_get_drvdata(adev); + + gaokun_ec_unregister_notify(uec->ec, &uec->nb); + ucsi_unregister(uec->ucsi); + ucsi_destroy(uec->ucsi); +} + +static const struct auxiliary_device_id gaokun_ucsi_id_table[] = { + { .name = GAOKUN_MOD_NAME "." GAOKUN_DEV_UCSI, }, + {} +}; +MODULE_DEVICE_TABLE(auxiliary, gaokun_ucsi_id_table); + +static struct auxiliary_driver gaokun_ucsi_driver = { + .name = GAOKUN_DEV_UCSI, + .id_table = gaokun_ucsi_id_table, + .probe = gaokun_ucsi_probe, + .remove = gaokun_ucsi_remove, +}; + +module_auxiliary_driver(gaokun_ucsi_driver); + +MODULE_DESCRIPTION("HUAWEI Matebook E Go UCSI driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/usbip/vudc_transfer.c b/drivers/usb/usbip/vudc_transfer.c index 7e801fee33bf..a4f02ea3e3ef 100644 --- a/drivers/usb/usbip/vudc_transfer.c +++ b/drivers/usb/usbip/vudc_transfer.c @@ -301,7 +301,7 @@ top: static void v_timer(struct timer_list *t) { - struct vudc *udc = from_timer(udc, t, tr_timer.timer); + struct vudc *udc = timer_container_of(udc, t, tr_timer.timer); struct transfer_timer *timer = &udc->tr_timer; struct urbp *urb_p, *tmp; unsigned long flags; diff --git a/drivers/video/console/dummycon.c b/drivers/video/console/dummycon.c index 139049368fdc..7d02470f19b9 100644 --- a/drivers/video/console/dummycon.c +++ b/drivers/video/console/dummycon.c @@ -85,6 +85,15 @@ static bool dummycon_blank(struct vc_data *vc, enum vesa_blank_mode blank, /* Redraw, so that we get putc(s) for output done while blanked */ return true; } + +static bool dummycon_switch(struct vc_data *vc) +{ + /* + * Redraw, so that we get putc(s) for output done while switched + * away. Informs deferred consoles to take over the display. + */ + return true; +} #else static void dummycon_putc(struct vc_data *vc, u16 c, unsigned int y, unsigned int x) { } @@ -95,6 +104,10 @@ static bool dummycon_blank(struct vc_data *vc, enum vesa_blank_mode blank, { return false; } +static bool dummycon_switch(struct vc_data *vc) +{ + return false; +} #endif static const char *dummycon_startup(void) @@ -124,11 +137,6 @@ static bool dummycon_scroll(struct vc_data *vc, unsigned int top, return false; } -static bool dummycon_switch(struct vc_data *vc) -{ - return false; -} - /* * The console `switch' structure for the dummy console * diff --git a/drivers/video/fbdev/aty/radeon_base.c b/drivers/video/fbdev/aty/radeon_base.c index c6c4753f6415..0eef8c6b98c8 100644 --- a/drivers/video/fbdev/aty/radeon_base.c +++ b/drivers/video/fbdev/aty/radeon_base.c @@ -1443,7 +1443,7 @@ static void radeon_write_pll_regs(struct radeonfb_info *rinfo, struct radeon_reg */ static void radeon_lvds_timer_func(struct timer_list *t) { - struct radeonfb_info *rinfo = from_timer(rinfo, t, lvds_timer); + struct radeonfb_info *rinfo = timer_container_of(rinfo, t, lvds_timer); radeon_engine_idle(); diff --git a/drivers/video/screen_info_pci.c b/drivers/video/screen_info_pci.c index 6c5833517141..66bfc1d0a6dc 100644 --- a/drivers/video/screen_info_pci.c +++ b/drivers/video/screen_info_pci.c @@ -7,8 +7,8 @@ static struct pci_dev *screen_info_lfb_pdev; static size_t screen_info_lfb_bar; -static resource_size_t screen_info_lfb_offset; -static struct resource screen_info_lfb_res = DEFINE_RES_MEM(0, 0); +static resource_size_t screen_info_lfb_res_start; // original start of resource +static resource_size_t screen_info_lfb_offset; // framebuffer offset within resource static bool __screen_info_relocation_is_valid(const struct screen_info *si, struct resource *pr) { @@ -31,7 +31,7 @@ void screen_info_apply_fixups(void) if (screen_info_lfb_pdev) { struct resource *pr = &screen_info_lfb_pdev->resource[screen_info_lfb_bar]; - if (pr->start != screen_info_lfb_res.start) { + if (pr->start != screen_info_lfb_res_start) { if (__screen_info_relocation_is_valid(si, pr)) { /* * Only update base if we have an actual @@ -47,46 +47,67 @@ void screen_info_apply_fixups(void) } } +static int __screen_info_lfb_pci_bus_region(const struct screen_info *si, unsigned int type, + struct pci_bus_region *r) +{ + u64 base, size; + + base = __screen_info_lfb_base(si); + if (!base) + return -EINVAL; + + size = __screen_info_lfb_size(si, type); + if (!size) + return -EINVAL; + + r->start = base; + r->end = base + size - 1; + + return 0; +} + static void screen_info_fixup_lfb(struct pci_dev *pdev) { unsigned int type; - struct resource res[SCREEN_INFO_MAX_RESOURCES]; - size_t i, numres; + struct pci_bus_region bus_region; int ret; + struct resource r = { + .flags = IORESOURCE_MEM, + }; + const struct resource *pr; const struct screen_info *si = &screen_info; if (screen_info_lfb_pdev) return; // already found type = screen_info_video_type(si); - if (type != VIDEO_TYPE_EFI) - return; // only applies to EFI + if (!__screen_info_has_lfb(type)) + return; // only applies to EFI; maybe VESA - ret = screen_info_resources(si, res, ARRAY_SIZE(res)); + ret = __screen_info_lfb_pci_bus_region(si, type, &bus_region); if (ret < 0) return; - numres = ret; - for (i = 0; i < numres; ++i) { - struct resource *r = &res[i]; - const struct resource *pr; - - if (!(r->flags & IORESOURCE_MEM)) - continue; - pr = pci_find_resource(pdev, r); - if (!pr) - continue; - - /* - * We've found a PCI device with the framebuffer - * resource. Store away the parameters to track - * relocation of the framebuffer aperture. - */ - screen_info_lfb_pdev = pdev; - screen_info_lfb_bar = pr - pdev->resource; - screen_info_lfb_offset = r->start - pr->start; - memcpy(&screen_info_lfb_res, r, sizeof(screen_info_lfb_res)); - } + /* + * Translate the PCI bus address to resource. Account + * for an offset if the framebuffer is behind a PCI host + * bridge. + */ + pcibios_bus_to_resource(pdev->bus, &r, &bus_region); + + pr = pci_find_resource(pdev, &r); + if (!pr) + return; + + /* + * We've found a PCI device with the framebuffer + * resource. Store away the parameters to track + * relocation of the framebuffer aperture. + */ + screen_info_lfb_pdev = pdev; + screen_info_lfb_bar = pr - pdev->resource; + screen_info_lfb_offset = r.start - pr->start; + screen_info_lfb_res_start = bus_region.start; } DECLARE_PCI_FIXUP_CLASS_HEADER(PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY, 16, screen_info_fixup_lfb); diff --git a/drivers/virt/acrn/irqfd.c b/drivers/virt/acrn/irqfd.c index b7da24ca1475..64d32c8fbf79 100644 --- a/drivers/virt/acrn/irqfd.c +++ b/drivers/virt/acrn/irqfd.c @@ -16,8 +16,6 @@ #include "acrn_drv.h" -static LIST_HEAD(acrn_irqfd_clients); - /** * struct hsm_irqfd - Properties of HSM irqfd * @vm: Associated VM pointer diff --git a/drivers/virt/vboxguest/vboxguest_core.c b/drivers/virt/vboxguest/vboxguest_core.c index f1674f3ed923..b177a534b6a4 100644 --- a/drivers/virt/vboxguest/vboxguest_core.c +++ b/drivers/virt/vboxguest/vboxguest_core.c @@ -419,7 +419,7 @@ static void vbg_balloon_work(struct work_struct *work) */ static void vbg_heartbeat_timer(struct timer_list *t) { - struct vbg_dev *gdev = from_timer(gdev, t, heartbeat_timer); + struct vbg_dev *gdev = timer_container_of(gdev, t, heartbeat_timer); vbg_req_perform(gdev, gdev->guest_heartbeat_req); mod_timer(&gdev->heartbeat_timer, diff --git a/drivers/w1/w1_netlink.c b/drivers/w1/w1_netlink.c index 691978cddab7..e6b59d921076 100644 --- a/drivers/w1/w1_netlink.c +++ b/drivers/w1/w1_netlink.c @@ -194,16 +194,16 @@ static void w1_netlink_queue_status(struct w1_cb_block *block, static void w1_netlink_send_error(struct cn_msg *cn, struct w1_netlink_msg *msg, int portid, int error) { - struct { - struct cn_msg cn; - struct w1_netlink_msg msg; - } packet; - memcpy(&packet.cn, cn, sizeof(packet.cn)); - memcpy(&packet.msg, msg, sizeof(packet.msg)); - packet.cn.len = sizeof(packet.msg); - packet.msg.len = 0; - packet.msg.status = (u8)-error; - cn_netlink_send(&packet.cn, portid, 0, GFP_KERNEL); + DEFINE_RAW_FLEX(struct cn_msg, packet, data, + sizeof(struct w1_netlink_msg)); + struct w1_netlink_msg *pkt_msg = (struct w1_netlink_msg *)packet->data; + + *packet = *cn; + *pkt_msg = *msg; + packet->len = sizeof(*pkt_msg); + pkt_msg->len = 0; + pkt_msg->status = (u8)-error; + cn_netlink_send(packet, portid, 0, GFP_KERNEL); } /** @@ -215,22 +215,20 @@ static void w1_netlink_send_error(struct cn_msg *cn, struct w1_netlink_msg *msg, */ void w1_netlink_send(struct w1_master *dev, struct w1_netlink_msg *msg) { - struct { - struct cn_msg cn; - struct w1_netlink_msg msg; - } packet; - memset(&packet, 0, sizeof(packet)); + DEFINE_RAW_FLEX(struct cn_msg, packet, data, + sizeof(struct w1_netlink_msg)); + struct w1_netlink_msg *pkt_msg = (struct w1_netlink_msg *)packet->data; - packet.cn.id.idx = CN_W1_IDX; - packet.cn.id.val = CN_W1_VAL; + packet->id.idx = CN_W1_IDX; + packet->id.val = CN_W1_VAL; - packet.cn.seq = dev->seq++; - packet.cn.len = sizeof(*msg); + packet->seq = dev->seq++; + packet->len = sizeof(*msg); - memcpy(&packet.msg, msg, sizeof(*msg)); - packet.msg.len = 0; + *pkt_msg = *msg; + pkt_msg->len = 0; - cn_netlink_send(&packet.cn, 0, 0, GFP_KERNEL); + cn_netlink_send(packet, 0, 0, GFP_KERNEL); } static void w1_send_slave(struct w1_master *dev, u64 rn) diff --git a/drivers/watchdog/at91sam9_wdt.c b/drivers/watchdog/at91sam9_wdt.c index 1b47a2fc7d17..aba66b8e9d03 100644 --- a/drivers/watchdog/at91sam9_wdt.c +++ b/drivers/watchdog/at91sam9_wdt.c @@ -119,7 +119,7 @@ static inline void at91_wdt_reset(struct at91wdt *wdt) */ static void at91_ping(struct timer_list *t) { - struct at91wdt *wdt = from_timer(wdt, t, timer); + struct at91wdt *wdt = timer_container_of(wdt, t, timer); if (time_before(jiffies, wdt->next_heartbeat) || !watchdog_active(&wdt->wdd)) { at91_wdt_reset(wdt); diff --git a/drivers/watchdog/bcm47xx_wdt.c b/drivers/watchdog/bcm47xx_wdt.c index 4c0951307421..e13ec0975bef 100644 --- a/drivers/watchdog/bcm47xx_wdt.c +++ b/drivers/watchdog/bcm47xx_wdt.c @@ -105,7 +105,7 @@ static const struct watchdog_ops bcm47xx_wdt_hard_ops = { static void bcm47xx_wdt_soft_timer_tick(struct timer_list *t) { - struct bcm47xx_wdt *wdt = from_timer(wdt, t, soft_timer); + struct bcm47xx_wdt *wdt = timer_container_of(wdt, t, soft_timer); u32 next_tick = min(wdt->wdd.timeout * 1000, wdt->max_timer_ms); if (!atomic_dec_and_test(&wdt->soft_ticks)) { diff --git a/drivers/watchdog/lpc18xx_wdt.c b/drivers/watchdog/lpc18xx_wdt.c index 28e3fc0df4c6..3e8e80bbcb93 100644 --- a/drivers/watchdog/lpc18xx_wdt.c +++ b/drivers/watchdog/lpc18xx_wdt.c @@ -77,7 +77,8 @@ static int lpc18xx_wdt_feed(struct watchdog_device *wdt_dev) static void lpc18xx_wdt_timer_feed(struct timer_list *t) { - struct lpc18xx_wdt_dev *lpc18xx_wdt = from_timer(lpc18xx_wdt, t, timer); + struct lpc18xx_wdt_dev *lpc18xx_wdt = timer_container_of(lpc18xx_wdt, + t, timer); struct watchdog_device *wdt_dev = &lpc18xx_wdt->wdt_dev; lpc18xx_wdt_feed(wdt_dev); diff --git a/drivers/watchdog/shwdt.c b/drivers/watchdog/shwdt.c index 95af9ad94d16..719f100aae60 100644 --- a/drivers/watchdog/shwdt.c +++ b/drivers/watchdog/shwdt.c @@ -173,7 +173,7 @@ static int sh_wdt_set_heartbeat(struct watchdog_device *wdt_dev, unsigned t) static void sh_wdt_ping(struct timer_list *t) { - struct sh_wdt *wdt = from_timer(wdt, t, timer); + struct sh_wdt *wdt = timer_container_of(wdt, t, timer); unsigned long flags; spin_lock_irqsave(&wdt->lock, flags); diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c index b95c4cb21c13..60a621b00c65 100644 --- a/fs/ceph/addr.c +++ b/fs/ceph/addr.c @@ -409,6 +409,15 @@ static void ceph_netfs_issue_read(struct netfs_io_subrequest *subreq) struct page **pages; size_t page_off; + /* + * FIXME: io_iter.count needs to be corrected to aligned + * length. Otherwise, iov_iter_get_pages_alloc2() operates + * with the initial unaligned length value. As a result, + * ceph_msg_data_cursor_init() triggers BUG_ON() in the case + * if msg->sparse_read_total > msg->data_length. + */ + subreq->io_iter.count = len; + err = iov_iter_get_pages_alloc2(&subreq->io_iter, &pages, len, &page_off); if (err < 0) { doutc(cl, "%llx.%llx failed to allocate pages, %d\n", diff --git a/fs/ceph/export.c b/fs/ceph/export.c index 150076ced937..b2f2af104679 100644 --- a/fs/ceph/export.c +++ b/fs/ceph/export.c @@ -33,12 +33,19 @@ struct ceph_nfs_snapfh { u32 hash; } __attribute__ ((packed)); +#define BYTES_PER_U32 (sizeof(u32)) +#define CEPH_FH_BASIC_SIZE \ + (sizeof(struct ceph_nfs_fh) / BYTES_PER_U32) +#define CEPH_FH_WITH_PARENT_SIZE \ + (sizeof(struct ceph_nfs_confh) / BYTES_PER_U32) +#define CEPH_FH_SNAPPED_INODE_SIZE \ + (sizeof(struct ceph_nfs_snapfh) / BYTES_PER_U32) + static int ceph_encode_snapfh(struct inode *inode, u32 *rawfh, int *max_len, struct inode *parent_inode) { struct ceph_client *cl = ceph_inode_to_client(inode); - static const int snap_handle_length = - sizeof(struct ceph_nfs_snapfh) >> 2; + static const int snap_handle_length = CEPH_FH_SNAPPED_INODE_SIZE; struct ceph_nfs_snapfh *sfh = (void *)rawfh; u64 snapid = ceph_snap(inode); int ret; @@ -88,10 +95,8 @@ static int ceph_encode_fh(struct inode *inode, u32 *rawfh, int *max_len, struct inode *parent_inode) { struct ceph_client *cl = ceph_inode_to_client(inode); - static const int handle_length = - sizeof(struct ceph_nfs_fh) >> 2; - static const int connected_handle_length = - sizeof(struct ceph_nfs_confh) >> 2; + static const int handle_length = CEPH_FH_BASIC_SIZE; + static const int connected_handle_length = CEPH_FH_WITH_PARENT_SIZE; int type; if (ceph_snap(inode) != CEPH_NOSNAP) @@ -308,7 +313,7 @@ static struct dentry *ceph_fh_to_dentry(struct super_block *sb, if (fh_type != FILEID_INO32_GEN && fh_type != FILEID_INO32_GEN_PARENT) return NULL; - if (fh_len < sizeof(*fh) / 4) + if (fh_len < sizeof(*fh) / BYTES_PER_U32) return NULL; doutc(fsc->client, "%llx\n", fh->ino); @@ -427,7 +432,7 @@ static struct dentry *ceph_fh_to_parent(struct super_block *sb, if (fh_type != FILEID_INO32_GEN_PARENT) return NULL; - if (fh_len < sizeof(*cfh) / 4) + if (fh_len < sizeof(*cfh) / BYTES_PER_U32) return NULL; doutc(fsc->client, "%llx\n", cfh->parent_ino); diff --git a/fs/ceph/file.c b/fs/ceph/file.c index 851d70200c6b..a7254cab44cc 100644 --- a/fs/ceph/file.c +++ b/fs/ceph/file.c @@ -2616,7 +2616,7 @@ static int ceph_zero_objects(struct inode *inode, loff_t offset, loff_t length) s32 stripe_unit = ci->i_layout.stripe_unit; s32 stripe_count = ci->i_layout.stripe_count; s32 object_size = ci->i_layout.object_size; - u64 object_set_size = object_size * stripe_count; + u64 object_set_size = (u64) object_size * stripe_count; u64 nearly, t; /* round offset up to next period boundary */ diff --git a/fs/ceph/super.c b/fs/ceph/super.c index f3951253e393..2b8438d8a324 100644 --- a/fs/ceph/super.c +++ b/fs/ceph/super.c @@ -1033,8 +1033,7 @@ void ceph_umount_begin(struct super_block *sb) struct ceph_fs_client *fsc = ceph_sb_to_fs_client(sb); doutc(fsc->client, "starting forced umount\n"); - if (!fsc) - return; + fsc->mount_state = CEPH_MOUNT_SHUTDOWN; __ceph_umount_begin(fsc); } @@ -1227,6 +1226,7 @@ static int ceph_set_super(struct super_block *s, struct fs_context *fc) s->s_time_min = 0; s->s_time_max = U32_MAX; s->s_flags |= SB_NODIRATIME | SB_NOATIME; + s->s_magic = CEPH_SUPER_MAGIC; ceph_fscrypt_set_ops(s); diff --git a/fs/dlm/lock.c b/fs/dlm/lock.c index e01d5f29f4d2..6dd3a524cd35 100644 --- a/fs/dlm/lock.c +++ b/fs/dlm/lock.c @@ -509,7 +509,7 @@ static void add_scan(struct dlm_ls *ls, struct dlm_rsb *r) void dlm_rsb_scan(struct timer_list *timer) { - struct dlm_ls *ls = from_timer(ls, timer, ls_scan_timer); + struct dlm_ls *ls = timer_container_of(ls, timer, ls_scan_timer); int our_nodeid = dlm_our_nodeid(); struct dlm_rsb *r; int rv; diff --git a/fs/ext4/super.c b/fs/ext4/super.c index a7f80ca01174..c7d39da7e733 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -3627,7 +3627,7 @@ int ext4_feature_set_ok(struct super_block *sb, int readonly) */ static void print_daily_error_info(struct timer_list *t) { - struct ext4_sb_info *sbi = from_timer(sbi, t, s_err_report); + struct ext4_sb_info *sbi = timer_container_of(sbi, t, s_err_report); struct super_block *sb = sbi->s_sb; struct ext4_super_block *es = sbi->s_es; diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c index 6d5e76848733..d480b94117cd 100644 --- a/fs/jbd2/journal.c +++ b/fs/jbd2/journal.c @@ -134,7 +134,7 @@ static __be32 jbd2_superblock_csum(journal_superblock_t *sb) static void commit_timeout(struct timer_list *t) { - journal_t *journal = from_timer(journal, t, j_commit_timer); + journal_t *journal = timer_container_of(journal, t, j_commit_timer); wake_up_process(journal->j_task); } diff --git a/fs/jffs2/erase.c b/fs/jffs2/erase.c index ef3a1e1b6cb0..fda9f4d6093f 100644 --- a/fs/jffs2/erase.c +++ b/fs/jffs2/erase.c @@ -425,7 +425,9 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb .totlen = cpu_to_je32(c->cleanmarker_size) }; - jffs2_prealloc_raw_node_refs(c, jeb, 1); + ret = jffs2_prealloc_raw_node_refs(c, jeb, 1); + if (ret) + goto filebad; marker.hdr_crc = cpu_to_je32(crc32(0, &marker, sizeof(struct jffs2_unknown_node)-4)); diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index 29671e33a171..62879c218d4b 100644 --- a/fs/jffs2/scan.c +++ b/fs/jffs2/scan.c @@ -256,7 +256,9 @@ int jffs2_scan_medium(struct jffs2_sb_info *c) jffs2_dbg(1, "%s(): Skipping %d bytes in nextblock to ensure page alignment\n", __func__, skip); - jffs2_prealloc_raw_node_refs(c, c->nextblock, 1); + ret = jffs2_prealloc_raw_node_refs(c, c->nextblock, 1); + if (ret) + goto out; jffs2_scan_dirty_space(c, c->nextblock, skip); } #endif diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c index 4fe64519870f..d83372d3e1a0 100644 --- a/fs/jffs2/summary.c +++ b/fs/jffs2/summary.c @@ -858,7 +858,10 @@ int jffs2_sum_write_sumnode(struct jffs2_sb_info *c) spin_unlock(&c->erase_completion_lock); jeb = c->nextblock; - jffs2_prealloc_raw_node_refs(c, jeb, 1); + ret = jffs2_prealloc_raw_node_refs(c, jeb, 1); + + if (ret) + goto out; if (!c->summary->sum_num || !c->summary->sum_list_head) { JFFS2_WARNING("Empty summary info!!!\n"); @@ -872,6 +875,8 @@ int jffs2_sum_write_sumnode(struct jffs2_sb_info *c) datasize += padsize; ret = jffs2_sum_write_data(c, jeb, infosize, datasize, padsize); + +out: spin_lock(&c->erase_completion_lock); return ret; } diff --git a/fs/namespace.c b/fs/namespace.c index 2f2e93927f46..e13d9ab4f564 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -2410,7 +2410,7 @@ void drop_collected_mounts(struct vfsmount *mnt) namespace_unlock(); } -bool has_locked_children(struct mount *mnt, struct dentry *dentry) +static bool __has_locked_children(struct mount *mnt, struct dentry *dentry) { struct mount *child; @@ -2424,6 +2424,16 @@ bool has_locked_children(struct mount *mnt, struct dentry *dentry) return false; } +bool has_locked_children(struct mount *mnt, struct dentry *dentry) +{ + bool res; + + read_seqlock_excl(&mount_lock); + res = __has_locked_children(mnt, dentry); + read_sequnlock_excl(&mount_lock); + return res; +} + /* * Check that there aren't references to earlier/same mount namespaces in the * specified subtree. Such references can act as pins for mount namespaces @@ -2468,23 +2478,27 @@ struct vfsmount *clone_private_mount(const struct path *path) if (IS_MNT_UNBINDABLE(old_mnt)) return ERR_PTR(-EINVAL); - if (mnt_has_parent(old_mnt)) { - if (!check_mnt(old_mnt)) - return ERR_PTR(-EINVAL); - } else { - if (!is_mounted(&old_mnt->mnt)) - return ERR_PTR(-EINVAL); - - /* Make sure this isn't something purely kernel internal. */ - if (!is_anon_ns(old_mnt->mnt_ns)) + /* + * Make sure the source mount is acceptable. + * Anything mounted in our mount namespace is allowed. + * Otherwise, it must be the root of an anonymous mount + * namespace, and we need to make sure no namespace + * loops get created. + */ + if (!check_mnt(old_mnt)) { + if (!is_mounted(&old_mnt->mnt) || + !is_anon_ns(old_mnt->mnt_ns) || + mnt_has_parent(old_mnt)) return ERR_PTR(-EINVAL); - /* Make sure we don't create mount namespace loops. */ if (!check_for_nsfs_mounts(old_mnt)) return ERR_PTR(-EINVAL); } - if (has_locked_children(old_mnt, path->dentry)) + if (!ns_capable(old_mnt->mnt_ns->user_ns, CAP_SYS_ADMIN)) + return ERR_PTR(-EPERM); + + if (__has_locked_children(old_mnt, path->dentry)) return ERR_PTR(-EINVAL); new_mnt = clone_mnt(old_mnt, path->dentry, CL_PRIVATE); @@ -2930,6 +2944,10 @@ static int do_change_type(struct path *path, int ms_flags) return -EINVAL; namespace_lock(); + if (!check_mnt(mnt)) { + err = -EINVAL; + goto out_unlock; + } if (type == MS_SHARED) { err = invent_group_ids(mnt, recurse); if (err) @@ -3021,7 +3039,7 @@ static struct mount *__do_loopback(struct path *old_path, int recurse) if (!may_copy_tree(old_path)) return mnt; - if (!recurse && has_locked_children(old, old_path->dentry)) + if (!recurse && __has_locked_children(old, old_path->dentry)) return mnt; if (recurse) @@ -3414,7 +3432,7 @@ static int do_set_group(struct path *from_path, struct path *to_path) goto out; /* From mount should not have locked children in place of To's root */ - if (has_locked_children(from, to->mnt.mnt_root)) + if (__has_locked_children(from, to->mnt.mnt_root)) goto out; /* Setting sharing groups is only allowed on private mounts */ @@ -3428,7 +3446,7 @@ static int do_set_group(struct path *from_path, struct path *to_path) if (IS_MNT_SLAVE(from)) { struct mount *m = from->mnt_master; - list_add(&to->mnt_slave, &m->mnt_slave_list); + list_add(&to->mnt_slave, &from->mnt_slave); to->mnt_master = m; } @@ -3453,18 +3471,25 @@ out: * Check if path is overmounted, i.e., if there's a mount on top of * @path->mnt with @path->dentry as mountpoint. * - * Context: This function expects namespace_lock() to be held. + * Context: namespace_sem must be held at least shared. + * MUST NOT be called under lock_mount_hash() (there one should just + * call __lookup_mnt() and check if it returns NULL). * Return: If path is overmounted true is returned, false if not. */ static inline bool path_overmounted(const struct path *path) { + unsigned seq = read_seqbegin(&mount_lock); + bool no_child; + rcu_read_lock(); - if (unlikely(__lookup_mnt(path->mnt, path->dentry))) { - rcu_read_unlock(); - return true; - } + no_child = !__lookup_mnt(path->mnt, path->dentry); rcu_read_unlock(); - return false; + if (need_seqretry(&mount_lock, seq)) { + read_seqlock_excl(&mount_lock); + no_child = !__lookup_mnt(path->mnt, path->dentry); + read_sequnlock_excl(&mount_lock); + } + return unlikely(!no_child); } /** @@ -3623,37 +3648,41 @@ static int do_move_mount(struct path *old_path, ns = old->mnt_ns; err = -EINVAL; - if (!may_use_mount(p)) - goto out; - /* The thing moved must be mounted... */ if (!is_mounted(&old->mnt)) goto out; - /* ... and either ours or the root of anon namespace */ - if (!(attached ? check_mnt(old) : is_anon_ns(ns))) - goto out; - - if (is_anon_ns(ns) && ns == p->mnt_ns) { + if (check_mnt(old)) { + /* if the source is in our namespace... */ + /* ... it should be detachable from parent */ + if (!mnt_has_parent(old) || IS_MNT_LOCKED(old)) + goto out; + /* ... and the target should be in our namespace */ + if (!check_mnt(p)) + goto out; + } else { /* - * Ending up with two files referring to the root of the - * same anonymous mount namespace would cause an error - * as this would mean trying to move the same mount - * twice into the mount tree which would be rejected - * later. But be explicit about it right here. + * otherwise the source must be the root of some anon namespace. + * AV: check for mount being root of an anon namespace is worth + * an inlined predicate... */ - goto out; - } else if (is_anon_ns(p->mnt_ns)) { + if (!is_anon_ns(ns) || mnt_has_parent(old)) + goto out; /* - * Don't allow moving an attached mount tree to an - * anonymous mount tree. + * Bail out early if the target is within the same namespace - + * subsequent checks would've rejected that, but they lose + * some corner cases if we check it early. */ - goto out; + if (ns == p->mnt_ns) + goto out; + /* + * Target should be either in our namespace or in an acceptable + * anon namespace, sensu check_anonymous_mnt(). + */ + if (!may_use_mount(p)) + goto out; } - if (old->mnt.mnt_flags & MNT_LOCKED) - goto out; - if (!path_mounted(old_path)) goto out; diff --git a/fs/nilfs2/segment.c b/fs/nilfs2/segment.c index 61a4141f8d6b..f15ca6fc400d 100644 --- a/fs/nilfs2/segment.c +++ b/fs/nilfs2/segment.c @@ -2485,7 +2485,7 @@ static int nilfs_segctor_construct(struct nilfs_sc_info *sci, int mode) static void nilfs_construction_timeout(struct timer_list *t) { - struct nilfs_sc_info *sci = from_timer(sci, t, sc_timer); + struct nilfs_sc_info *sci = timer_container_of(sci, t, sc_timer); wake_up_process(sci->sc_task); } diff --git a/fs/ocfs2/cluster/tcp.c b/fs/ocfs2/cluster/tcp.c index 43e652a2adaf..b05d4e9d13b2 100644 --- a/fs/ocfs2/cluster/tcp.c +++ b/fs/ocfs2/cluster/tcp.c @@ -1488,7 +1488,8 @@ static void o2net_sc_send_keep_req(struct work_struct *work) * where shutdown is going to be involved */ static void o2net_idle_timer(struct timer_list *t) { - struct o2net_sock_container *sc = from_timer(sc, t, sc_idle_timeout); + struct o2net_sock_container *sc = timer_container_of(sc, t, + sc_idle_timeout); struct o2net_node *nn = o2net_nn_from_num(sc->sc_node->nd_num); #ifdef CONFIG_DEBUG_FS unsigned long msecs = ktime_to_ms(ktime_get()) - diff --git a/fs/overlayfs/file.c b/fs/overlayfs/file.c index 969b458100fe..dfea7bd800cb 100644 --- a/fs/overlayfs/file.c +++ b/fs/overlayfs/file.c @@ -48,8 +48,8 @@ static struct file *ovl_open_realfile(const struct file *file, if (!inode_owner_or_capable(real_idmap, realinode)) flags &= ~O_NOATIME; - realfile = backing_file_open(&file->f_path, flags, realpath, - current_cred()); + realfile = backing_file_open(file_user_path((struct file *) file), + flags, realpath, current_cred()); } ovl_revert_creds(old_cred); diff --git a/fs/overlayfs/namei.c b/fs/overlayfs/namei.c index bf722daf19a9..0b8b28392eb7 100644 --- a/fs/overlayfs/namei.c +++ b/fs/overlayfs/namei.c @@ -16,6 +16,7 @@ struct ovl_lookup_data { struct super_block *sb; + struct dentry *dentry; const struct ovl_layer *layer; struct qstr name; bool is_dir; @@ -24,6 +25,7 @@ struct ovl_lookup_data { bool stop; bool last; char *redirect; + char *upperredirect; int metacopy; /* Referring to last redirect xattr */ bool absolute_redirect; @@ -1024,6 +1026,31 @@ int ovl_verify_lowerdata(struct dentry *dentry) return ovl_maybe_validate_verity(dentry); } +/* + * Following redirects/metacopy can have security consequences: it's like a + * symlink into the lower layer without the permission checks. + * + * This is only a problem if the upper layer is untrusted (e.g comes from an USB + * drive). This can allow a non-readable file or directory to become readable. + * + * Only following redirects when redirects are enabled disables this attack + * vector when not necessary. + */ +static bool ovl_check_follow_redirect(struct ovl_lookup_data *d) +{ + struct ovl_fs *ofs = OVL_FS(d->sb); + + if (d->metacopy && !ofs->config.metacopy) { + pr_warn_ratelimited("refusing to follow metacopy origin for (%pd2)\n", d->dentry); + return false; + } + if ((d->redirect || d->upperredirect) && !ovl_redirect_follow(ofs)) { + pr_warn_ratelimited("refusing to follow redirect for (%pd2)\n", d->dentry); + return false; + } + return true; +} + struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) { @@ -1039,7 +1066,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, unsigned int ctr = 0; struct inode *inode = NULL; bool upperopaque = false; - char *upperredirect = NULL; + bool check_redirect = (ovl_redirect_follow(ofs) || ofs->numdatalayer); struct dentry *this; unsigned int i; int err; @@ -1047,12 +1074,14 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, int metacopy_size = 0; struct ovl_lookup_data d = { .sb = dentry->d_sb, + .dentry = dentry, .name = dentry->d_name, .is_dir = false, .opaque = false, .stop = false, - .last = ovl_redirect_follow(ofs) ? false : !ovl_numlower(poe), + .last = check_redirect ? false : !ovl_numlower(poe), .redirect = NULL, + .upperredirect = NULL, .metacopy = 0, }; @@ -1094,8 +1123,8 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, if (d.redirect) { err = -ENOMEM; - upperredirect = kstrdup(d.redirect, GFP_KERNEL); - if (!upperredirect) + d.upperredirect = kstrdup(d.redirect, GFP_KERNEL); + if (!d.upperredirect) goto out_put_upper; if (d.redirect[0] == '/') poe = roe; @@ -1113,7 +1142,12 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, for (i = 0; !d.stop && i < ovl_numlower(poe); i++) { struct ovl_path lower = ovl_lowerstack(poe)[i]; - if (!ovl_redirect_follow(ofs)) + if (!ovl_check_follow_redirect(&d)) { + err = -EPERM; + goto out_put; + } + + if (!check_redirect) d.last = i == ovl_numlower(poe) - 1; else if (d.is_dir || !ofs->numdatalayer) d.last = lower.layer->idx == ovl_numlower(roe); @@ -1126,13 +1160,6 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, if (!this) continue; - if ((uppermetacopy || d.metacopy) && !ofs->config.metacopy) { - dput(this); - err = -EPERM; - pr_warn_ratelimited("refusing to follow metacopy origin for (%pd2)\n", dentry); - goto out_put; - } - /* * If no origin fh is stored in upper of a merge dir, store fh * of lower dir and set upper parent "impure". @@ -1185,23 +1212,6 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, ctr++; } - /* - * Following redirects can have security consequences: it's like - * a symlink into the lower layer without the permission checks. - * This is only a problem if the upper layer is untrusted (e.g - * comes from an USB drive). This can allow a non-readable file - * or directory to become readable. - * - * Only following redirects when redirects are enabled disables - * this attack vector when not necessary. - */ - err = -EPERM; - if (d.redirect && !ovl_redirect_follow(ofs)) { - pr_warn_ratelimited("refusing to follow redirect for (%pd2)\n", - dentry); - goto out_put; - } - if (d.stop) break; @@ -1212,10 +1222,16 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, } } - /* Defer lookup of lowerdata in data-only layers to first access */ + /* + * Defer lookup of lowerdata in data-only layers to first access. + * Don't require redirect=follow and metacopy=on in this case. + */ if (d.metacopy && ctr && ofs->numdatalayer && d.absolute_redirect) { d.metacopy = 0; ctr++; + } else if (!ovl_check_follow_redirect(&d)) { + err = -EPERM; + goto out_put; } /* @@ -1298,20 +1314,26 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, /* * It's safe to assign upperredirect here: the previous - * assignment of happens only if upperdentry is non-NULL, and + * assignment happens only if upperdentry is non-NULL, and * this one only if upperdentry is NULL. */ - upperredirect = ovl_get_redirect_xattr(ofs, &upperpath, 0); - if (IS_ERR(upperredirect)) { - err = PTR_ERR(upperredirect); - upperredirect = NULL; + d.upperredirect = ovl_get_redirect_xattr(ofs, &upperpath, 0); + if (IS_ERR(d.upperredirect)) { + err = PTR_ERR(d.upperredirect); + d.upperredirect = NULL; goto out_free_oe; } + err = ovl_check_metacopy_xattr(ofs, &upperpath, NULL); if (err < 0) goto out_free_oe; - uppermetacopy = err; + d.metacopy = uppermetacopy = err; metacopy_size = err; + + if (!ovl_check_follow_redirect(&d)) { + err = -EPERM; + goto out_free_oe; + } } if (upperdentry || ctr) { @@ -1319,7 +1341,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, .upperdentry = upperdentry, .oe = oe, .index = index, - .redirect = upperredirect, + .redirect = d.upperredirect, }; /* Store lowerdata redirect for lazy lookup */ @@ -1361,7 +1383,7 @@ out_put_upper: kfree(origin_path); } dput(upperdentry); - kfree(upperredirect); + kfree(d.upperredirect); out: kfree(d.redirect); ovl_revert_creds(old_cred); diff --git a/fs/overlayfs/ovl_entry.h b/fs/overlayfs/ovl_entry.h index cb449ab310a7..afb7762f873f 100644 --- a/fs/overlayfs/ovl_entry.h +++ b/fs/overlayfs/ovl_entry.h @@ -51,7 +51,7 @@ struct ovl_path { struct ovl_entry { unsigned int __numlower; - struct ovl_path __lowerstack[]; + struct ovl_path __lowerstack[] __counted_by(__numlower); }; /* private information held for overlayfs's superblock */ diff --git a/fs/overlayfs/params.c b/fs/overlayfs/params.c index 6759f7d040c8..f42488c01957 100644 --- a/fs/overlayfs/params.c +++ b/fs/overlayfs/params.c @@ -871,18 +871,6 @@ int ovl_fs_params_verify(const struct ovl_fs_context *ctx, config->uuid = OVL_UUID_NULL; } - /* Resolve verity -> metacopy dependency */ - if (config->verity_mode && !config->metacopy) { - /* Don't allow explicit specified conflicting combinations */ - if (set.metacopy) { - pr_err("conflicting options: metacopy=off,verity=%s\n", - ovl_verity_mode(config)); - return -EINVAL; - } - /* Otherwise automatically enable metacopy. */ - config->metacopy = true; - } - /* * This is to make the logic below simpler. It doesn't make any other * difference, since redirect_dir=on is only used for upper. @@ -890,18 +878,13 @@ int ovl_fs_params_verify(const struct ovl_fs_context *ctx, if (!config->upperdir && config->redirect_mode == OVL_REDIRECT_FOLLOW) config->redirect_mode = OVL_REDIRECT_ON; - /* Resolve verity -> metacopy -> redirect_dir dependency */ + /* metacopy -> redirect_dir dependency */ if (config->metacopy && config->redirect_mode != OVL_REDIRECT_ON) { if (set.metacopy && set.redirect) { pr_err("conflicting options: metacopy=on,redirect_dir=%s\n", ovl_redirect_mode(config)); return -EINVAL; } - if (config->verity_mode && set.redirect) { - pr_err("conflicting options: verity=%s,redirect_dir=%s\n", - ovl_verity_mode(config), ovl_redirect_mode(config)); - return -EINVAL; - } if (set.redirect) { /* * There was an explicit redirect_dir=... that resulted @@ -970,7 +953,7 @@ int ovl_fs_params_verify(const struct ovl_fs_context *ctx, } - /* Resolve userxattr -> !redirect && !metacopy && !verity dependency */ + /* Resolve userxattr -> !redirect && !metacopy dependency */ if (config->userxattr) { if (set.redirect && config->redirect_mode != OVL_REDIRECT_NOFOLLOW) { @@ -982,11 +965,6 @@ int ovl_fs_params_verify(const struct ovl_fs_context *ctx, pr_err("conflicting options: userxattr,metacopy=on\n"); return -EINVAL; } - if (config->verity_mode) { - pr_err("conflicting options: userxattr,verity=%s\n", - ovl_verity_mode(config)); - return -EINVAL; - } /* * Silently disable default setting of redirect and metacopy. * This shall be the default in the future as well: these @@ -1025,11 +1003,6 @@ int ovl_fs_params_verify(const struct ovl_fs_context *ctx, */ } - if (ctx->nr_data > 0 && !config->metacopy) { - pr_err("lower data-only dirs require metacopy support.\n"); - return -EINVAL; - } - return 0; } @@ -1078,17 +1051,16 @@ int ovl_show_options(struct seq_file *m, struct dentry *dentry) seq_printf(m, ",redirect_dir=%s", ovl_redirect_mode(&ofs->config)); if (ofs->config.index != ovl_index_def) - seq_printf(m, ",index=%s", ofs->config.index ? "on" : "off"); + seq_printf(m, ",index=%s", str_on_off(ofs->config.index)); if (ofs->config.uuid != ovl_uuid_def()) seq_printf(m, ",uuid=%s", ovl_uuid_mode(&ofs->config)); if (ofs->config.nfs_export != ovl_nfs_export_def) - seq_printf(m, ",nfs_export=%s", ofs->config.nfs_export ? - "on" : "off"); + seq_printf(m, ",nfs_export=%s", + str_on_off(ofs->config.nfs_export)); if (ofs->config.xino != ovl_xino_def() && !ovl_same_fs(ofs)) seq_printf(m, ",xino=%s", ovl_xino_mode(&ofs->config)); if (ofs->config.metacopy != ovl_metacopy_def) - seq_printf(m, ",metacopy=%s", - ofs->config.metacopy ? "on" : "off"); + seq_printf(m, ",metacopy=%s", str_on_off(ofs->config.metacopy)); if (ofs->config.ovl_volatile) seq_puts(m, ",volatile"); if (ofs->config.userxattr) diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c index 44e208da417c..474c80d210d1 100644 --- a/fs/overlayfs/readdir.c +++ b/fs/overlayfs/readdir.c @@ -13,6 +13,7 @@ #include <linux/security.h> #include <linux/cred.h> #include <linux/ratelimit.h> +#include <linux/overflow.h> #include "overlayfs.h" struct ovl_cache_entry { @@ -147,9 +148,8 @@ static struct ovl_cache_entry *ovl_cache_entry_new(struct ovl_readdir_data *rdd, u64 ino, unsigned int d_type) { struct ovl_cache_entry *p; - size_t size = offsetof(struct ovl_cache_entry, name[len + 1]); - p = kmalloc(size, GFP_KERNEL); + p = kmalloc(struct_size(p, name, len + 1), GFP_KERNEL); if (!p) return NULL; diff --git a/fs/overlayfs/util.c b/fs/overlayfs/util.c index 0819c739cc2f..dcccb4b4a66c 100644 --- a/fs/overlayfs/util.c +++ b/fs/overlayfs/util.c @@ -15,6 +15,7 @@ #include <linux/uuid.h> #include <linux/namei.h> #include <linux/ratelimit.h> +#include <linux/overflow.h> #include "overlayfs.h" /* Get write access to upper mnt - may fail if upper sb was remounted ro */ @@ -145,9 +146,9 @@ void ovl_stack_free(struct ovl_path *stack, unsigned int n) struct ovl_entry *ovl_alloc_entry(unsigned int numlower) { - size_t size = offsetof(struct ovl_entry, __lowerstack[numlower]); - struct ovl_entry *oe = kzalloc(size, GFP_KERNEL); + struct ovl_entry *oe; + oe = kzalloc(struct_size(oe, __lowerstack, numlower), GFP_KERNEL); if (oe) oe->__numlower = numlower; @@ -305,7 +306,9 @@ enum ovl_path_type ovl_path_realdata(struct dentry *dentry, struct path *path) struct dentry *ovl_dentry_upper(struct dentry *dentry) { - return ovl_upperdentry_dereference(OVL_I(d_inode(dentry))); + struct inode *inode = d_inode(dentry); + + return inode ? ovl_upperdentry_dereference(OVL_I(inode)) : NULL; } struct dentry *ovl_dentry_lower(struct dentry *dentry) diff --git a/fs/resctrl/rdtgroup.c b/fs/resctrl/rdtgroup.c index cc37f58b47dd..1beb124e25f6 100644 --- a/fs/resctrl/rdtgroup.c +++ b/fs/resctrl/rdtgroup.c @@ -536,6 +536,8 @@ static ssize_t rdtgroup_cpus_write(struct kernfs_open_file *of, goto unlock; } + rdt_last_cmd_clear(); + if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKED || rdtgrp->mode == RDT_MODE_PSEUDO_LOCKSETUP) { ret = -EINVAL; @@ -3472,6 +3474,8 @@ static int mkdir_rdt_prepare(struct kernfs_node *parent_kn, goto out_unlock; } + rdt_last_cmd_clear(); + /* * Check that the parent directory for a monitor group is a "mon_groups" * directory. diff --git a/fs/smb/client/cifs_debug.c b/fs/smb/client/cifs_debug.c index e03c890de0a0..c0196be0e65f 100644 --- a/fs/smb/client/cifs_debug.c +++ b/fs/smb/client/cifs_debug.c @@ -362,6 +362,10 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v) c = 0; spin_lock(&cifs_tcp_ses_lock); list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) { +#ifdef CONFIG_CIFS_SMB_DIRECT + struct smbdirect_socket_parameters *sp; +#endif + /* channel info will be printed as a part of sessions below */ if (SERVER_IS_CHAN(server)) continue; @@ -383,25 +387,26 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v) seq_printf(m, "\nSMBDirect transport not available"); goto skip_rdma; } + sp = &server->smbd_conn->socket.parameters; seq_printf(m, "\nSMBDirect (in hex) protocol version: %x " "transport status: %x", server->smbd_conn->protocol, - server->smbd_conn->transport_status); + server->smbd_conn->socket.status); seq_printf(m, "\nConn receive_credit_max: %x " "send_credit_target: %x max_send_size: %x", - server->smbd_conn->receive_credit_max, - server->smbd_conn->send_credit_target, - server->smbd_conn->max_send_size); + sp->recv_credit_max, + sp->send_credit_target, + sp->max_send_size); seq_printf(m, "\nConn max_fragmented_recv_size: %x " "max_fragmented_send_size: %x max_receive_size:%x", - server->smbd_conn->max_fragmented_recv_size, - server->smbd_conn->max_fragmented_send_size, - server->smbd_conn->max_receive_size); + sp->max_fragmented_recv_size, + sp->max_fragmented_send_size, + sp->max_recv_size); seq_printf(m, "\nConn keep_alive_interval: %x " "max_readwrite_size: %x rdma_readwrite_threshold: %x", - server->smbd_conn->keep_alive_interval, - server->smbd_conn->max_readwrite_size, + sp->keepalive_interval_msec * 1000, + sp->max_read_write_size, server->smbd_conn->rdma_readwrite_threshold); seq_printf(m, "\nDebug count_get_receive_buffer: %x " "count_put_receive_buffer: %x count_send_empty: %x", diff --git a/fs/smb/client/cifsfs.h b/fs/smb/client/cifsfs.h index ca435a3841b8..b9ec9fe16a98 100644 --- a/fs/smb/client/cifsfs.h +++ b/fs/smb/client/cifsfs.h @@ -145,6 +145,6 @@ extern const struct export_operations cifs_export_ops; #endif /* CONFIG_CIFS_NFSD_EXPORT */ /* when changing internal version - update following two lines at same time */ -#define SMB3_PRODUCT_BUILD 54 -#define CIFS_VERSION "2.54" +#define SMB3_PRODUCT_BUILD 55 +#define CIFS_VERSION "2.55" #endif /* _CIFSFS_H */ diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h index ad7dd16db3e9..45e94e18f4d5 100644 --- a/fs/smb/client/cifsglob.h +++ b/fs/smb/client/cifsglob.h @@ -1085,6 +1085,7 @@ struct cifs_chan { }; #define CIFS_SES_FLAG_SCALE_CHANNELS (0x1) +#define CIFS_SES_FLAGS_PENDING_QUERY_INTERFACES (0x2) /* * Session structure. One of these for each uid session with a particular host diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c index 024817d40c5f..28bc33496623 100644 --- a/fs/smb/client/connect.c +++ b/fs/smb/client/connect.c @@ -116,13 +116,9 @@ static void smb2_query_server_interfaces(struct work_struct *work) rc = server->ops->query_server_interfaces(xid, tcon, false); free_xid(xid); - if (rc) { - if (rc == -EOPNOTSUPP) - return; - + if (rc) cifs_dbg(FYI, "%s: failed to query server interfaces: %d\n", __func__, rc); - } queue_delayed_work(cifsiod_wq, &tcon->query_interfaces, (SMB_INTERFACE_POLL_INTERVAL * HZ)); diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c index bab9f567d9b7..1468c16ea9b8 100644 --- a/fs/smb/client/smb2ops.c +++ b/fs/smb/client/smb2ops.c @@ -504,6 +504,9 @@ smb3_negotiate_wsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx) wsize = min_t(unsigned int, wsize, server->max_write); #ifdef CONFIG_CIFS_SMB_DIRECT if (server->rdma) { + struct smbdirect_socket_parameters *sp = + &server->smbd_conn->socket.parameters; + if (server->sign) /* * Account for SMB2 data transfer packet header and @@ -511,12 +514,12 @@ smb3_negotiate_wsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx) */ wsize = min_t(unsigned int, wsize, - server->smbd_conn->max_fragmented_send_size - + sp->max_fragmented_send_size - SMB2_READWRITE_PDU_HEADER_SIZE - sizeof(struct smb2_transform_hdr)); else wsize = min_t(unsigned int, - wsize, server->smbd_conn->max_readwrite_size); + wsize, sp->max_read_write_size); } #endif if (!(server->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU)) @@ -552,6 +555,9 @@ smb3_negotiate_rsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx) rsize = min_t(unsigned int, rsize, server->max_read); #ifdef CONFIG_CIFS_SMB_DIRECT if (server->rdma) { + struct smbdirect_socket_parameters *sp = + &server->smbd_conn->socket.parameters; + if (server->sign) /* * Account for SMB2 data transfer packet header and @@ -559,12 +565,12 @@ smb3_negotiate_rsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx) */ rsize = min_t(unsigned int, rsize, - server->smbd_conn->max_fragmented_recv_size - + sp->max_fragmented_recv_size - SMB2_READWRITE_PDU_HEADER_SIZE - sizeof(struct smb2_transform_hdr)); else rsize = min_t(unsigned int, - rsize, server->smbd_conn->max_readwrite_size); + rsize, sp->max_read_write_size); } #endif diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c index 0c320d06809c..a717be1626a3 100644 --- a/fs/smb/client/smb2pdu.c +++ b/fs/smb/client/smb2pdu.c @@ -36,6 +36,7 @@ #include "smb2glob.h" #include "cifspdu.h" #include "cifs_spnego.h" +#include "../common/smbdirect/smbdirect.h" #include "smbdirect.h" #include "trace.h" #ifdef CONFIG_CIFS_DFS_UPCALL @@ -411,14 +412,23 @@ skip_sess_setup: if (!rc && (server->capabilities & SMB2_GLOBAL_CAP_MULTI_CHANNEL) && server->ops->query_server_interfaces) { - mutex_unlock(&ses->session_mutex); - /* - * query server network interfaces, in case they change + * query server network interfaces, in case they change. + * Also mark the session as pending this update while the query + * is in progress. This will be used to avoid calling + * smb2_reconnect recursively. */ + ses->flags |= CIFS_SES_FLAGS_PENDING_QUERY_INTERFACES; xid = get_xid(); rc = server->ops->query_server_interfaces(xid, tcon, false); free_xid(xid); + ses->flags &= ~CIFS_SES_FLAGS_PENDING_QUERY_INTERFACES; + + /* regardless of rc value, setup polling */ + queue_delayed_work(cifsiod_wq, &tcon->query_interfaces, + (SMB_INTERFACE_POLL_INTERVAL * HZ)); + + mutex_unlock(&ses->session_mutex); if (rc == -EOPNOTSUPP && ses->chan_count > 1) { /* @@ -438,11 +448,8 @@ skip_sess_setup: if (ses->chan_max > ses->chan_count && ses->iface_count && !SERVER_IS_CHAN(server)) { - if (ses->chan_count == 1) { + if (ses->chan_count == 1) cifs_server_dbg(VFS, "supports multichannel now\n"); - queue_delayed_work(cifsiod_wq, &tcon->query_interfaces, - (SMB_INTERFACE_POLL_INTERVAL * HZ)); - } cifs_try_adding_channels(ses); } @@ -560,11 +567,18 @@ static int smb2_ioctl_req_init(u32 opcode, struct cifs_tcon *tcon, struct TCP_Server_Info *server, void **request_buf, unsigned int *total_len) { - /* Skip reconnect only for FSCTL_VALIDATE_NEGOTIATE_INFO IOCTLs */ - if (opcode == FSCTL_VALIDATE_NEGOTIATE_INFO) { + /* + * Skip reconnect in one of the following cases: + * 1. For FSCTL_VALIDATE_NEGOTIATE_INFO IOCTLs + * 2. For FSCTL_QUERY_NETWORK_INTERFACE_INFO IOCTL when called from + * smb2_reconnect (indicated by CIFS_SES_FLAG_SCALE_CHANNELS ses flag) + */ + if (opcode == FSCTL_VALIDATE_NEGOTIATE_INFO || + (opcode == FSCTL_QUERY_NETWORK_INTERFACE_INFO && + (tcon->ses->flags & CIFS_SES_FLAGS_PENDING_QUERY_INTERFACES))) return __smb2_plain_req_init(SMB2_IOCTL, tcon, server, request_buf, total_len); - } + return smb2_plain_req_init(SMB2_IOCTL, tcon, server, request_buf, total_len); } @@ -4449,10 +4463,10 @@ smb2_new_read_req(void **buf, unsigned int *total_len, #ifdef CONFIG_CIFS_SMB_DIRECT /* * If we want to do a RDMA write, fill in and append - * smbd_buffer_descriptor_v1 to the end of read request + * smbdirect_buffer_descriptor_v1 to the end of read request */ if (rdata && smb3_use_rdma_offload(io_parms)) { - struct smbd_buffer_descriptor_v1 *v1; + struct smbdirect_buffer_descriptor_v1 *v1; bool need_invalidate = server->dialect == SMB30_PROT_ID; rdata->mr = smbd_register_mr(server->smbd_conn, &rdata->subreq.io_iter, @@ -4466,8 +4480,8 @@ smb2_new_read_req(void **buf, unsigned int *total_len, req->ReadChannelInfoOffset = cpu_to_le16(offsetof(struct smb2_read_req, Buffer)); req->ReadChannelInfoLength = - cpu_to_le16(sizeof(struct smbd_buffer_descriptor_v1)); - v1 = (struct smbd_buffer_descriptor_v1 *) &req->Buffer[0]; + cpu_to_le16(sizeof(struct smbdirect_buffer_descriptor_v1)); + v1 = (struct smbdirect_buffer_descriptor_v1 *) &req->Buffer[0]; v1->offset = cpu_to_le64(rdata->mr->mr->iova); v1->token = cpu_to_le32(rdata->mr->mr->rkey); v1->length = cpu_to_le32(rdata->mr->mr->length); @@ -4975,10 +4989,10 @@ smb2_async_writev(struct cifs_io_subrequest *wdata) #ifdef CONFIG_CIFS_SMB_DIRECT /* * If we want to do a server RDMA read, fill in and append - * smbd_buffer_descriptor_v1 to the end of write request + * smbdirect_buffer_descriptor_v1 to the end of write request */ if (smb3_use_rdma_offload(io_parms)) { - struct smbd_buffer_descriptor_v1 *v1; + struct smbdirect_buffer_descriptor_v1 *v1; bool need_invalidate = server->dialect == SMB30_PROT_ID; wdata->mr = smbd_register_mr(server->smbd_conn, &wdata->subreq.io_iter, @@ -4997,8 +5011,8 @@ smb2_async_writev(struct cifs_io_subrequest *wdata) req->WriteChannelInfoOffset = cpu_to_le16(offsetof(struct smb2_write_req, Buffer)); req->WriteChannelInfoLength = - cpu_to_le16(sizeof(struct smbd_buffer_descriptor_v1)); - v1 = (struct smbd_buffer_descriptor_v1 *) &req->Buffer[0]; + cpu_to_le16(sizeof(struct smbdirect_buffer_descriptor_v1)); + v1 = (struct smbdirect_buffer_descriptor_v1 *) &req->Buffer[0]; v1->offset = cpu_to_le64(wdata->mr->mr->iova); v1->token = cpu_to_le32(wdata->mr->mr->rkey); v1->length = cpu_to_le32(wdata->mr->mr->length); diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c index b0b7254661e9..5ae847919da5 100644 --- a/fs/smb/client/smbdirect.c +++ b/fs/smb/client/smbdirect.c @@ -7,6 +7,7 @@ #include <linux/module.h> #include <linux/highmem.h> #include <linux/folio_queue.h> +#include "../common/smbdirect/smbdirect_pdu.h" #include "smbdirect.h" #include "cifs_debug.h" #include "cifsproto.h" @@ -50,9 +51,6 @@ struct smb_extract_to_rdma { static ssize_t smb_extract_iter_to_rdma(struct iov_iter *iter, size_t len, struct smb_extract_to_rdma *rdma); -/* SMBD version number */ -#define SMBD_V1 0x0100 - /* Port numbers for SMBD transport */ #define SMB_PORT 445 #define SMBD_PORT 5445 @@ -165,10 +163,11 @@ static void smbd_disconnect_rdma_work(struct work_struct *work) { struct smbd_connection *info = container_of(work, struct smbd_connection, disconnect_work); + struct smbdirect_socket *sc = &info->socket; - if (info->transport_status == SMBD_CONNECTED) { - info->transport_status = SMBD_DISCONNECTING; - rdma_disconnect(info->id); + if (sc->status == SMBDIRECT_SOCKET_CONNECTED) { + sc->status = SMBDIRECT_SOCKET_DISCONNECTING; + rdma_disconnect(sc->rdma.cm_id); } } @@ -182,6 +181,7 @@ static int smbd_conn_upcall( struct rdma_cm_id *id, struct rdma_cm_event *event) { struct smbd_connection *info = id->context; + struct smbdirect_socket *sc = &info->socket; log_rdma_event(INFO, "event=%d status=%d\n", event->event, event->status); @@ -205,7 +205,7 @@ static int smbd_conn_upcall( case RDMA_CM_EVENT_ESTABLISHED: log_rdma_event(INFO, "connected event=%d\n", event->event); - info->transport_status = SMBD_CONNECTED; + sc->status = SMBDIRECT_SOCKET_CONNECTED; wake_up_interruptible(&info->conn_wait); break; @@ -213,20 +213,20 @@ static int smbd_conn_upcall( case RDMA_CM_EVENT_UNREACHABLE: case RDMA_CM_EVENT_REJECTED: log_rdma_event(INFO, "connecting failed event=%d\n", event->event); - info->transport_status = SMBD_DISCONNECTED; + sc->status = SMBDIRECT_SOCKET_DISCONNECTED; wake_up_interruptible(&info->conn_wait); break; case RDMA_CM_EVENT_DEVICE_REMOVAL: case RDMA_CM_EVENT_DISCONNECTED: /* This happens when we fail the negotiation */ - if (info->transport_status == SMBD_NEGOTIATE_FAILED) { - info->transport_status = SMBD_DISCONNECTED; + if (sc->status == SMBDIRECT_SOCKET_NEGOTIATE_FAILED) { + sc->status = SMBDIRECT_SOCKET_DISCONNECTED; wake_up(&info->conn_wait); break; } - info->transport_status = SMBD_DISCONNECTED; + sc->status = SMBDIRECT_SOCKET_DISCONNECTED; wake_up_interruptible(&info->disconn_wait); wake_up_interruptible(&info->wait_reassembly_queue); wake_up_interruptible_all(&info->wait_send_queue); @@ -275,6 +275,8 @@ static void send_done(struct ib_cq *cq, struct ib_wc *wc) int i; struct smbd_request *request = container_of(wc->wr_cqe, struct smbd_request, cqe); + struct smbd_connection *info = request->info; + struct smbdirect_socket *sc = &info->socket; log_rdma_send(INFO, "smbd_request 0x%p completed wc->status=%d\n", request, wc->status); @@ -286,7 +288,7 @@ static void send_done(struct ib_cq *cq, struct ib_wc *wc) } for (i = 0; i < request->num_sge; i++) - ib_dma_unmap_single(request->info->id->device, + ib_dma_unmap_single(sc->ib.dev, request->sge[i].addr, request->sge[i].length, DMA_TO_DEVICE); @@ -299,7 +301,7 @@ static void send_done(struct ib_cq *cq, struct ib_wc *wc) mempool_free(request, request->info->request_mempool); } -static void dump_smbd_negotiate_resp(struct smbd_negotiate_resp *resp) +static void dump_smbdirect_negotiate_resp(struct smbdirect_negotiate_resp *resp) { log_rdma_event(INFO, "resp message min_version %u max_version %u negotiated_version %u credits_requested %u credits_granted %u status %u max_readwrite_size %u preferred_send_size %u max_receive_size %u max_fragmented_size %u\n", resp->min_version, resp->max_version, @@ -318,15 +320,17 @@ static bool process_negotiation_response( struct smbd_response *response, int packet_length) { struct smbd_connection *info = response->info; - struct smbd_negotiate_resp *packet = smbd_response_payload(response); + struct smbdirect_socket *sc = &info->socket; + struct smbdirect_socket_parameters *sp = &sc->parameters; + struct smbdirect_negotiate_resp *packet = smbd_response_payload(response); - if (packet_length < sizeof(struct smbd_negotiate_resp)) { + if (packet_length < sizeof(struct smbdirect_negotiate_resp)) { log_rdma_event(ERR, "error: packet_length=%d\n", packet_length); return false; } - if (le16_to_cpu(packet->negotiated_version) != SMBD_V1) { + if (le16_to_cpu(packet->negotiated_version) != SMBDIRECT_V1) { log_rdma_event(ERR, "error: negotiated_version=%x\n", le16_to_cpu(packet->negotiated_version)); return false; @@ -347,20 +351,20 @@ static bool process_negotiation_response( atomic_set(&info->receive_credits, 0); - if (le32_to_cpu(packet->preferred_send_size) > info->max_receive_size) { + if (le32_to_cpu(packet->preferred_send_size) > sp->max_recv_size) { log_rdma_event(ERR, "error: preferred_send_size=%d\n", le32_to_cpu(packet->preferred_send_size)); return false; } - info->max_receive_size = le32_to_cpu(packet->preferred_send_size); + sp->max_recv_size = le32_to_cpu(packet->preferred_send_size); if (le32_to_cpu(packet->max_receive_size) < SMBD_MIN_RECEIVE_SIZE) { log_rdma_event(ERR, "error: max_receive_size=%d\n", le32_to_cpu(packet->max_receive_size)); return false; } - info->max_send_size = min_t(int, info->max_send_size, - le32_to_cpu(packet->max_receive_size)); + sp->max_send_size = min_t(u32, sp->max_send_size, + le32_to_cpu(packet->max_receive_size)); if (le32_to_cpu(packet->max_fragmented_size) < SMBD_MIN_FRAGMENTED_SIZE) { @@ -368,18 +372,18 @@ static bool process_negotiation_response( le32_to_cpu(packet->max_fragmented_size)); return false; } - info->max_fragmented_send_size = + sp->max_fragmented_send_size = le32_to_cpu(packet->max_fragmented_size); info->rdma_readwrite_threshold = - rdma_readwrite_threshold > info->max_fragmented_send_size ? - info->max_fragmented_send_size : + rdma_readwrite_threshold > sp->max_fragmented_send_size ? + sp->max_fragmented_send_size : rdma_readwrite_threshold; - info->max_readwrite_size = min_t(u32, + sp->max_read_write_size = min_t(u32, le32_to_cpu(packet->max_readwrite_size), info->max_frmr_depth * PAGE_SIZE); - info->max_frmr_depth = info->max_readwrite_size / PAGE_SIZE; + info->max_frmr_depth = sp->max_read_write_size / PAGE_SIZE; return true; } @@ -393,8 +397,9 @@ static void smbd_post_send_credits(struct work_struct *work) struct smbd_connection *info = container_of(work, struct smbd_connection, post_send_credits_work); + struct smbdirect_socket *sc = &info->socket; - if (info->transport_status != SMBD_CONNECTED) { + if (sc->status != SMBDIRECT_SOCKET_CONNECTED) { wake_up(&info->wait_receive_queues); return; } @@ -448,7 +453,7 @@ static void smbd_post_send_credits(struct work_struct *work) /* Called from softirq, when recv is done */ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) { - struct smbd_data_transfer *data_transfer; + struct smbdirect_data_transfer *data_transfer; struct smbd_response *response = container_of(wc->wr_cqe, struct smbd_response, cqe); struct smbd_connection *info = response->info; @@ -474,7 +479,7 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) switch (response->type) { /* SMBD negotiation response */ case SMBD_NEGOTIATE_RESP: - dump_smbd_negotiate_resp(smbd_response_payload(response)); + dump_smbdirect_negotiate_resp(smbd_response_payload(response)); info->full_packet_received = true; info->negotiate_done = process_negotiation_response(response, wc->byte_len); @@ -531,7 +536,7 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) /* Send a KEEP_ALIVE response right away if requested */ info->keep_alive_requested = KEEP_ALIVE_NONE; if (le16_to_cpu(data_transfer->flags) & - SMB_DIRECT_RESPONSE_REQUESTED) { + SMBDIRECT_FLAG_RESPONSE_REQUESTED) { info->keep_alive_requested = KEEP_ALIVE_PENDING; } @@ -635,32 +640,34 @@ static int smbd_ia_open( struct smbd_connection *info, struct sockaddr *dstaddr, int port) { + struct smbdirect_socket *sc = &info->socket; int rc; - info->id = smbd_create_id(info, dstaddr, port); - if (IS_ERR(info->id)) { - rc = PTR_ERR(info->id); + sc->rdma.cm_id = smbd_create_id(info, dstaddr, port); + if (IS_ERR(sc->rdma.cm_id)) { + rc = PTR_ERR(sc->rdma.cm_id); goto out1; } + sc->ib.dev = sc->rdma.cm_id->device; - if (!frwr_is_supported(&info->id->device->attrs)) { + if (!frwr_is_supported(&sc->ib.dev->attrs)) { log_rdma_event(ERR, "Fast Registration Work Requests (FRWR) is not supported\n"); log_rdma_event(ERR, "Device capability flags = %llx max_fast_reg_page_list_len = %u\n", - info->id->device->attrs.device_cap_flags, - info->id->device->attrs.max_fast_reg_page_list_len); + sc->ib.dev->attrs.device_cap_flags, + sc->ib.dev->attrs.max_fast_reg_page_list_len); rc = -EPROTONOSUPPORT; goto out2; } info->max_frmr_depth = min_t(int, smbd_max_frmr_depth, - info->id->device->attrs.max_fast_reg_page_list_len); + sc->ib.dev->attrs.max_fast_reg_page_list_len); info->mr_type = IB_MR_TYPE_MEM_REG; - if (info->id->device->attrs.kernel_cap_flags & IBK_SG_GAPS_REG) + if (sc->ib.dev->attrs.kernel_cap_flags & IBK_SG_GAPS_REG) info->mr_type = IB_MR_TYPE_SG_GAPS; - info->pd = ib_alloc_pd(info->id->device, 0); - if (IS_ERR(info->pd)) { - rc = PTR_ERR(info->pd); + sc->ib.pd = ib_alloc_pd(sc->ib.dev, 0); + if (IS_ERR(sc->ib.pd)) { + rc = PTR_ERR(sc->ib.pd); log_rdma_event(ERR, "ib_alloc_pd() returned %d\n", rc); goto out2; } @@ -668,8 +675,8 @@ static int smbd_ia_open( return 0; out2: - rdma_destroy_id(info->id); - info->id = NULL; + rdma_destroy_id(sc->rdma.cm_id); + sc->rdma.cm_id = NULL; out1: return rc; @@ -683,10 +690,12 @@ out1: */ static int smbd_post_send_negotiate_req(struct smbd_connection *info) { + struct smbdirect_socket *sc = &info->socket; + struct smbdirect_socket_parameters *sp = &sc->parameters; struct ib_send_wr send_wr; int rc = -ENOMEM; struct smbd_request *request; - struct smbd_negotiate_req *packet; + struct smbdirect_negotiate_req *packet; request = mempool_alloc(info->request_mempool, GFP_KERNEL); if (!request) @@ -695,29 +704,29 @@ static int smbd_post_send_negotiate_req(struct smbd_connection *info) request->info = info; packet = smbd_request_payload(request); - packet->min_version = cpu_to_le16(SMBD_V1); - packet->max_version = cpu_to_le16(SMBD_V1); + packet->min_version = cpu_to_le16(SMBDIRECT_V1); + packet->max_version = cpu_to_le16(SMBDIRECT_V1); packet->reserved = 0; - packet->credits_requested = cpu_to_le16(info->send_credit_target); - packet->preferred_send_size = cpu_to_le32(info->max_send_size); - packet->max_receive_size = cpu_to_le32(info->max_receive_size); + packet->credits_requested = cpu_to_le16(sp->send_credit_target); + packet->preferred_send_size = cpu_to_le32(sp->max_send_size); + packet->max_receive_size = cpu_to_le32(sp->max_recv_size); packet->max_fragmented_size = - cpu_to_le32(info->max_fragmented_recv_size); + cpu_to_le32(sp->max_fragmented_recv_size); request->num_sge = 1; request->sge[0].addr = ib_dma_map_single( - info->id->device, (void *)packet, + sc->ib.dev, (void *)packet, sizeof(*packet), DMA_TO_DEVICE); - if (ib_dma_mapping_error(info->id->device, request->sge[0].addr)) { + if (ib_dma_mapping_error(sc->ib.dev, request->sge[0].addr)) { rc = -EIO; goto dma_mapping_failed; } request->sge[0].length = sizeof(*packet); - request->sge[0].lkey = info->pd->local_dma_lkey; + request->sge[0].lkey = sc->ib.pd->local_dma_lkey; ib_dma_sync_single_for_device( - info->id->device, request->sge[0].addr, + sc->ib.dev, request->sge[0].addr, request->sge[0].length, DMA_TO_DEVICE); request->cqe.done = send_done; @@ -734,14 +743,14 @@ static int smbd_post_send_negotiate_req(struct smbd_connection *info) request->sge[0].length, request->sge[0].lkey); atomic_inc(&info->send_pending); - rc = ib_post_send(info->id->qp, &send_wr, NULL); + rc = ib_post_send(sc->ib.qp, &send_wr, NULL); if (!rc) return 0; /* if we reach here, post send failed */ log_rdma_send(ERR, "ib_post_send failed rc=%d\n", rc); atomic_dec(&info->send_pending); - ib_dma_unmap_single(info->id->device, request->sge[0].addr, + ib_dma_unmap_single(sc->ib.dev, request->sge[0].addr, request->sge[0].length, DMA_TO_DEVICE); smbd_disconnect_rdma_connection(info); @@ -774,10 +783,10 @@ static int manage_credits_prior_sending(struct smbd_connection *info) /* * Check if we need to send a KEEP_ALIVE message * The idle connection timer triggers a KEEP_ALIVE message when expires - * SMB_DIRECT_RESPONSE_REQUESTED is set in the message flag to have peer send + * SMBDIRECT_FLAG_RESPONSE_REQUESTED is set in the message flag to have peer send * back a response. * return value: - * 1 if SMB_DIRECT_RESPONSE_REQUESTED needs to be set + * 1 if SMBDIRECT_FLAG_RESPONSE_REQUESTED needs to be set * 0: otherwise */ static int manage_keep_alive_before_sending(struct smbd_connection *info) @@ -793,6 +802,8 @@ static int manage_keep_alive_before_sending(struct smbd_connection *info) static int smbd_post_send(struct smbd_connection *info, struct smbd_request *request) { + struct smbdirect_socket *sc = &info->socket; + struct smbdirect_socket_parameters *sp = &sc->parameters; struct ib_send_wr send_wr; int rc, i; @@ -801,7 +812,7 @@ static int smbd_post_send(struct smbd_connection *info, "rdma_request sge[%d] addr=0x%llx length=%u\n", i, request->sge[i].addr, request->sge[i].length); ib_dma_sync_single_for_device( - info->id->device, + sc->ib.dev, request->sge[i].addr, request->sge[i].length, DMA_TO_DEVICE); @@ -816,7 +827,7 @@ static int smbd_post_send(struct smbd_connection *info, send_wr.opcode = IB_WR_SEND; send_wr.send_flags = IB_SEND_SIGNALED; - rc = ib_post_send(info->id->qp, &send_wr, NULL); + rc = ib_post_send(sc->ib.qp, &send_wr, NULL); if (rc) { log_rdma_send(ERR, "ib_post_send failed rc=%d\n", rc); smbd_disconnect_rdma_connection(info); @@ -824,7 +835,7 @@ static int smbd_post_send(struct smbd_connection *info, } else /* Reset timer for idle connection after packet is sent */ mod_delayed_work(info->workqueue, &info->idle_timer_work, - info->keep_alive_interval*HZ); + msecs_to_jiffies(sp->keepalive_interval_msec)); return rc; } @@ -833,22 +844,24 @@ static int smbd_post_send_iter(struct smbd_connection *info, struct iov_iter *iter, int *_remaining_data_length) { + struct smbdirect_socket *sc = &info->socket; + struct smbdirect_socket_parameters *sp = &sc->parameters; int i, rc; int header_length; int data_length; struct smbd_request *request; - struct smbd_data_transfer *packet; + struct smbdirect_data_transfer *packet; int new_credits = 0; wait_credit: /* Wait for send credits. A SMBD packet needs one credit */ rc = wait_event_interruptible(info->wait_send_queue, atomic_read(&info->send_credits) > 0 || - info->transport_status != SMBD_CONNECTED); + sc->status != SMBDIRECT_SOCKET_CONNECTED); if (rc) goto err_wait_credit; - if (info->transport_status != SMBD_CONNECTED) { + if (sc->status != SMBDIRECT_SOCKET_CONNECTED) { log_outgoing(ERR, "disconnected not sending on wait_credit\n"); rc = -EAGAIN; goto err_wait_credit; @@ -860,17 +873,17 @@ wait_credit: wait_send_queue: wait_event(info->wait_post_send, - atomic_read(&info->send_pending) < info->send_credit_target || - info->transport_status != SMBD_CONNECTED); + atomic_read(&info->send_pending) < sp->send_credit_target || + sc->status != SMBDIRECT_SOCKET_CONNECTED); - if (info->transport_status != SMBD_CONNECTED) { + if (sc->status != SMBDIRECT_SOCKET_CONNECTED) { log_outgoing(ERR, "disconnected not sending on wait_send_queue\n"); rc = -EAGAIN; goto err_wait_send_queue; } if (unlikely(atomic_inc_return(&info->send_pending) > - info->send_credit_target)) { + sp->send_credit_target)) { atomic_dec(&info->send_pending); goto wait_send_queue; } @@ -890,8 +903,8 @@ wait_send_queue: .nr_sge = 1, .max_sge = SMBDIRECT_MAX_SEND_SGE, .sge = request->sge, - .device = info->id->device, - .local_dma_lkey = info->pd->local_dma_lkey, + .device = sc->ib.dev, + .local_dma_lkey = sc->ib.pd->local_dma_lkey, .direction = DMA_TO_DEVICE, }; @@ -909,7 +922,7 @@ wait_send_queue: /* Fill in the packet header */ packet = smbd_request_payload(request); - packet->credits_requested = cpu_to_le16(info->send_credit_target); + packet->credits_requested = cpu_to_le16(sp->send_credit_target); new_credits = manage_credits_prior_sending(info); atomic_add(new_credits, &info->receive_credits); @@ -919,7 +932,7 @@ wait_send_queue: packet->flags = 0; if (manage_keep_alive_before_sending(info)) - packet->flags |= cpu_to_le16(SMB_DIRECT_RESPONSE_REQUESTED); + packet->flags |= cpu_to_le16(SMBDIRECT_FLAG_RESPONSE_REQUESTED); packet->reserved = 0; if (!data_length) @@ -938,23 +951,23 @@ wait_send_queue: le32_to_cpu(packet->remaining_data_length)); /* Map the packet to DMA */ - header_length = sizeof(struct smbd_data_transfer); + header_length = sizeof(struct smbdirect_data_transfer); /* If this is a packet without payload, don't send padding */ if (!data_length) - header_length = offsetof(struct smbd_data_transfer, padding); + header_length = offsetof(struct smbdirect_data_transfer, padding); - request->sge[0].addr = ib_dma_map_single(info->id->device, + request->sge[0].addr = ib_dma_map_single(sc->ib.dev, (void *)packet, header_length, DMA_TO_DEVICE); - if (ib_dma_mapping_error(info->id->device, request->sge[0].addr)) { + if (ib_dma_mapping_error(sc->ib.dev, request->sge[0].addr)) { rc = -EIO; request->sge[0].addr = 0; goto err_dma; } request->sge[0].length = header_length; - request->sge[0].lkey = info->pd->local_dma_lkey; + request->sge[0].lkey = sc->ib.pd->local_dma_lkey; rc = smbd_post_send(info, request); if (!rc) @@ -963,7 +976,7 @@ wait_send_queue: err_dma: for (i = 0; i < request->num_sge; i++) if (request->sge[i].addr) - ib_dma_unmap_single(info->id->device, + ib_dma_unmap_single(sc->ib.dev, request->sge[i].addr, request->sge[i].length, DMA_TO_DEVICE); @@ -1008,17 +1021,19 @@ static int smbd_post_send_empty(struct smbd_connection *info) static int smbd_post_recv( struct smbd_connection *info, struct smbd_response *response) { + struct smbdirect_socket *sc = &info->socket; + struct smbdirect_socket_parameters *sp = &sc->parameters; struct ib_recv_wr recv_wr; int rc = -EIO; response->sge.addr = ib_dma_map_single( - info->id->device, response->packet, - info->max_receive_size, DMA_FROM_DEVICE); - if (ib_dma_mapping_error(info->id->device, response->sge.addr)) + sc->ib.dev, response->packet, + sp->max_recv_size, DMA_FROM_DEVICE); + if (ib_dma_mapping_error(sc->ib.dev, response->sge.addr)) return rc; - response->sge.length = info->max_receive_size; - response->sge.lkey = info->pd->local_dma_lkey; + response->sge.length = sp->max_recv_size; + response->sge.lkey = sc->ib.pd->local_dma_lkey; response->cqe.done = recv_done; @@ -1027,9 +1042,9 @@ static int smbd_post_recv( recv_wr.sg_list = &response->sge; recv_wr.num_sge = 1; - rc = ib_post_recv(info->id->qp, &recv_wr, NULL); + rc = ib_post_recv(sc->ib.qp, &recv_wr, NULL); if (rc) { - ib_dma_unmap_single(info->id->device, response->sge.addr, + ib_dma_unmap_single(sc->ib.dev, response->sge.addr, response->sge.length, DMA_FROM_DEVICE); smbd_disconnect_rdma_connection(info); log_rdma_recv(ERR, "ib_post_recv failed rc=%d\n", rc); @@ -1187,9 +1202,10 @@ static struct smbd_response *get_receive_buffer(struct smbd_connection *info) static void put_receive_buffer( struct smbd_connection *info, struct smbd_response *response) { + struct smbdirect_socket *sc = &info->socket; unsigned long flags; - ib_dma_unmap_single(info->id->device, response->sge.addr, + ib_dma_unmap_single(sc->ib.dev, response->sge.addr, response->sge.length, DMA_FROM_DEVICE); spin_lock_irqsave(&info->receive_queue_lock, flags); @@ -1264,6 +1280,8 @@ static void idle_connection_timer(struct work_struct *work) struct smbd_connection *info = container_of( work, struct smbd_connection, idle_timer_work.work); + struct smbdirect_socket *sc = &info->socket; + struct smbdirect_socket_parameters *sp = &sc->parameters; if (info->keep_alive_requested != KEEP_ALIVE_NONE) { log_keep_alive(ERR, @@ -1278,7 +1296,7 @@ static void idle_connection_timer(struct work_struct *work) /* Setup the next idle timeout work */ queue_delayed_work(info->workqueue, &info->idle_timer_work, - info->keep_alive_interval*HZ); + msecs_to_jiffies(sp->keepalive_interval_msec)); } /* @@ -1289,6 +1307,8 @@ static void idle_connection_timer(struct work_struct *work) void smbd_destroy(struct TCP_Server_Info *server) { struct smbd_connection *info = server->smbd_conn; + struct smbdirect_socket *sc; + struct smbdirect_socket_parameters *sp; struct smbd_response *response; unsigned long flags; @@ -1296,19 +1316,22 @@ void smbd_destroy(struct TCP_Server_Info *server) log_rdma_event(INFO, "rdma session already destroyed\n"); return; } + sc = &info->socket; + sp = &sc->parameters; log_rdma_event(INFO, "destroying rdma session\n"); - if (info->transport_status != SMBD_DISCONNECTED) { - rdma_disconnect(server->smbd_conn->id); + if (sc->status != SMBDIRECT_SOCKET_DISCONNECTED) { + rdma_disconnect(sc->rdma.cm_id); log_rdma_event(INFO, "wait for transport being disconnected\n"); wait_event_interruptible( info->disconn_wait, - info->transport_status == SMBD_DISCONNECTED); + sc->status == SMBDIRECT_SOCKET_DISCONNECTED); } log_rdma_event(INFO, "destroying qp\n"); - ib_drain_qp(info->id->qp); - rdma_destroy_qp(info->id); + ib_drain_qp(sc->ib.qp); + rdma_destroy_qp(sc->rdma.cm_id); + sc->ib.qp = NULL; log_rdma_event(INFO, "cancelling idle timer\n"); cancel_delayed_work_sync(&info->idle_timer_work); @@ -1336,7 +1359,7 @@ void smbd_destroy(struct TCP_Server_Info *server) log_rdma_event(INFO, "free receive buffers\n"); wait_event(info->wait_receive_queues, info->count_receive_queue + info->count_empty_packet_queue - == info->receive_credit_max); + == sp->recv_credit_max); destroy_receive_buffers(info); /* @@ -1355,10 +1378,10 @@ void smbd_destroy(struct TCP_Server_Info *server) } destroy_mr_list(info); - ib_free_cq(info->send_cq); - ib_free_cq(info->recv_cq); - ib_dealloc_pd(info->pd); - rdma_destroy_id(info->id); + ib_free_cq(sc->ib.send_cq); + ib_free_cq(sc->ib.recv_cq); + ib_dealloc_pd(sc->ib.pd); + rdma_destroy_id(sc->rdma.cm_id); /* free mempools */ mempool_destroy(info->request_mempool); @@ -1367,7 +1390,7 @@ void smbd_destroy(struct TCP_Server_Info *server) mempool_destroy(info->response_mempool); kmem_cache_destroy(info->response_cache); - info->transport_status = SMBD_DESTROYED; + sc->status = SMBDIRECT_SOCKET_DESTROYED; destroy_workqueue(info->workqueue); log_rdma_event(INFO, "rdma session destroyed\n"); @@ -1392,7 +1415,7 @@ int smbd_reconnect(struct TCP_Server_Info *server) * This is possible if transport is disconnected and we haven't received * notification from RDMA, but upper layer has detected timeout */ - if (server->smbd_conn->transport_status == SMBD_CONNECTED) { + if (server->smbd_conn->socket.status == SMBDIRECT_SOCKET_CONNECTED) { log_rdma_event(INFO, "disconnecting transport\n"); smbd_destroy(server); } @@ -1424,6 +1447,8 @@ static void destroy_caches_and_workqueue(struct smbd_connection *info) #define MAX_NAME_LEN 80 static int allocate_caches_and_workqueue(struct smbd_connection *info) { + struct smbdirect_socket *sc = &info->socket; + struct smbdirect_socket_parameters *sp = &sc->parameters; char name[MAX_NAME_LEN]; int rc; @@ -1432,13 +1457,13 @@ static int allocate_caches_and_workqueue(struct smbd_connection *info) kmem_cache_create( name, sizeof(struct smbd_request) + - sizeof(struct smbd_data_transfer), + sizeof(struct smbdirect_data_transfer), 0, SLAB_HWCACHE_ALIGN, NULL); if (!info->request_cache) return -ENOMEM; info->request_mempool = - mempool_create(info->send_credit_target, mempool_alloc_slab, + mempool_create(sp->send_credit_target, mempool_alloc_slab, mempool_free_slab, info->request_cache); if (!info->request_mempool) goto out1; @@ -1448,13 +1473,13 @@ static int allocate_caches_and_workqueue(struct smbd_connection *info) kmem_cache_create( name, sizeof(struct smbd_response) + - info->max_receive_size, + sp->max_recv_size, 0, SLAB_HWCACHE_ALIGN, NULL); if (!info->response_cache) goto out2; info->response_mempool = - mempool_create(info->receive_credit_max, mempool_alloc_slab, + mempool_create(sp->recv_credit_max, mempool_alloc_slab, mempool_free_slab, info->response_cache); if (!info->response_mempool) goto out3; @@ -1464,7 +1489,7 @@ static int allocate_caches_and_workqueue(struct smbd_connection *info) if (!info->workqueue) goto out4; - rc = allocate_receive_buffers(info, info->receive_credit_max); + rc = allocate_receive_buffers(info, sp->recv_credit_max); if (rc) { log_rdma_event(ERR, "failed to allocate receive buffers\n"); goto out5; @@ -1491,6 +1516,8 @@ static struct smbd_connection *_smbd_get_connection( { int rc; struct smbd_connection *info; + struct smbdirect_socket *sc; + struct smbdirect_socket_parameters *sp; struct rdma_conn_param conn_param; struct ib_qp_init_attr qp_attr; struct sockaddr_in *addr_in = (struct sockaddr_in *) dstaddr; @@ -1500,101 +1527,102 @@ static struct smbd_connection *_smbd_get_connection( info = kzalloc(sizeof(struct smbd_connection), GFP_KERNEL); if (!info) return NULL; + sc = &info->socket; + sp = &sc->parameters; - info->transport_status = SMBD_CONNECTING; + sc->status = SMBDIRECT_SOCKET_CONNECTING; rc = smbd_ia_open(info, dstaddr, port); if (rc) { log_rdma_event(INFO, "smbd_ia_open rc=%d\n", rc); goto create_id_failed; } - if (smbd_send_credit_target > info->id->device->attrs.max_cqe || - smbd_send_credit_target > info->id->device->attrs.max_qp_wr) { + if (smbd_send_credit_target > sc->ib.dev->attrs.max_cqe || + smbd_send_credit_target > sc->ib.dev->attrs.max_qp_wr) { log_rdma_event(ERR, "consider lowering send_credit_target = %d. Possible CQE overrun, device reporting max_cqe %d max_qp_wr %d\n", smbd_send_credit_target, - info->id->device->attrs.max_cqe, - info->id->device->attrs.max_qp_wr); + sc->ib.dev->attrs.max_cqe, + sc->ib.dev->attrs.max_qp_wr); goto config_failed; } - if (smbd_receive_credit_max > info->id->device->attrs.max_cqe || - smbd_receive_credit_max > info->id->device->attrs.max_qp_wr) { + if (smbd_receive_credit_max > sc->ib.dev->attrs.max_cqe || + smbd_receive_credit_max > sc->ib.dev->attrs.max_qp_wr) { log_rdma_event(ERR, "consider lowering receive_credit_max = %d. Possible CQE overrun, device reporting max_cqe %d max_qp_wr %d\n", smbd_receive_credit_max, - info->id->device->attrs.max_cqe, - info->id->device->attrs.max_qp_wr); + sc->ib.dev->attrs.max_cqe, + sc->ib.dev->attrs.max_qp_wr); goto config_failed; } - info->receive_credit_max = smbd_receive_credit_max; - info->send_credit_target = smbd_send_credit_target; - info->max_send_size = smbd_max_send_size; - info->max_fragmented_recv_size = smbd_max_fragmented_recv_size; - info->max_receive_size = smbd_max_receive_size; - info->keep_alive_interval = smbd_keep_alive_interval; + sp->recv_credit_max = smbd_receive_credit_max; + sp->send_credit_target = smbd_send_credit_target; + sp->max_send_size = smbd_max_send_size; + sp->max_fragmented_recv_size = smbd_max_fragmented_recv_size; + sp->max_recv_size = smbd_max_receive_size; + sp->keepalive_interval_msec = smbd_keep_alive_interval * 1000; - if (info->id->device->attrs.max_send_sge < SMBDIRECT_MAX_SEND_SGE || - info->id->device->attrs.max_recv_sge < SMBDIRECT_MAX_RECV_SGE) { + if (sc->ib.dev->attrs.max_send_sge < SMBDIRECT_MAX_SEND_SGE || + sc->ib.dev->attrs.max_recv_sge < SMBDIRECT_MAX_RECV_SGE) { log_rdma_event(ERR, "device %.*s max_send_sge/max_recv_sge = %d/%d too small\n", IB_DEVICE_NAME_MAX, - info->id->device->name, - info->id->device->attrs.max_send_sge, - info->id->device->attrs.max_recv_sge); + sc->ib.dev->name, + sc->ib.dev->attrs.max_send_sge, + sc->ib.dev->attrs.max_recv_sge); goto config_failed; } - info->send_cq = NULL; - info->recv_cq = NULL; - info->send_cq = - ib_alloc_cq_any(info->id->device, info, - info->send_credit_target, IB_POLL_SOFTIRQ); - if (IS_ERR(info->send_cq)) { - info->send_cq = NULL; + sc->ib.send_cq = + ib_alloc_cq_any(sc->ib.dev, info, + sp->send_credit_target, IB_POLL_SOFTIRQ); + if (IS_ERR(sc->ib.send_cq)) { + sc->ib.send_cq = NULL; goto alloc_cq_failed; } - info->recv_cq = - ib_alloc_cq_any(info->id->device, info, - info->receive_credit_max, IB_POLL_SOFTIRQ); - if (IS_ERR(info->recv_cq)) { - info->recv_cq = NULL; + sc->ib.recv_cq = + ib_alloc_cq_any(sc->ib.dev, info, + sp->recv_credit_max, IB_POLL_SOFTIRQ); + if (IS_ERR(sc->ib.recv_cq)) { + sc->ib.recv_cq = NULL; goto alloc_cq_failed; } memset(&qp_attr, 0, sizeof(qp_attr)); qp_attr.event_handler = smbd_qp_async_error_upcall; qp_attr.qp_context = info; - qp_attr.cap.max_send_wr = info->send_credit_target; - qp_attr.cap.max_recv_wr = info->receive_credit_max; + qp_attr.cap.max_send_wr = sp->send_credit_target; + qp_attr.cap.max_recv_wr = sp->recv_credit_max; qp_attr.cap.max_send_sge = SMBDIRECT_MAX_SEND_SGE; qp_attr.cap.max_recv_sge = SMBDIRECT_MAX_RECV_SGE; qp_attr.cap.max_inline_data = 0; qp_attr.sq_sig_type = IB_SIGNAL_REQ_WR; qp_attr.qp_type = IB_QPT_RC; - qp_attr.send_cq = info->send_cq; - qp_attr.recv_cq = info->recv_cq; + qp_attr.send_cq = sc->ib.send_cq; + qp_attr.recv_cq = sc->ib.recv_cq; qp_attr.port_num = ~0; - rc = rdma_create_qp(info->id, info->pd, &qp_attr); + rc = rdma_create_qp(sc->rdma.cm_id, sc->ib.pd, &qp_attr); if (rc) { log_rdma_event(ERR, "rdma_create_qp failed %i\n", rc); goto create_qp_failed; } + sc->ib.qp = sc->rdma.cm_id->qp; memset(&conn_param, 0, sizeof(conn_param)); conn_param.initiator_depth = 0; conn_param.responder_resources = - min(info->id->device->attrs.max_qp_rd_atom, + min(sc->ib.dev->attrs.max_qp_rd_atom, SMBD_CM_RESPONDER_RESOURCES); info->responder_resources = conn_param.responder_resources; log_rdma_mr(INFO, "responder_resources=%d\n", info->responder_resources); /* Need to send IRD/ORD in private data for iWARP */ - info->id->device->ops.get_port_immutable( - info->id->device, info->id->port_num, &port_immutable); + sc->ib.dev->ops.get_port_immutable( + sc->ib.dev, sc->rdma.cm_id->port_num, &port_immutable); if (port_immutable.core_cap_flags & RDMA_CORE_PORT_IWARP) { ird_ord_hdr[0] = info->responder_resources; ird_ord_hdr[1] = 1; @@ -1615,16 +1643,16 @@ static struct smbd_connection *_smbd_get_connection( init_waitqueue_head(&info->conn_wait); init_waitqueue_head(&info->disconn_wait); init_waitqueue_head(&info->wait_reassembly_queue); - rc = rdma_connect(info->id, &conn_param); + rc = rdma_connect(sc->rdma.cm_id, &conn_param); if (rc) { log_rdma_event(ERR, "rdma_connect() failed with %i\n", rc); goto rdma_connect_failed; } wait_event_interruptible( - info->conn_wait, info->transport_status != SMBD_CONNECTING); + info->conn_wait, sc->status != SMBDIRECT_SOCKET_CONNECTING); - if (info->transport_status != SMBD_CONNECTED) { + if (sc->status != SMBDIRECT_SOCKET_CONNECTED) { log_rdma_event(ERR, "rdma_connect failed port=%d\n", port); goto rdma_connect_failed; } @@ -1640,7 +1668,7 @@ static struct smbd_connection *_smbd_get_connection( init_waitqueue_head(&info->wait_send_queue); INIT_DELAYED_WORK(&info->idle_timer_work, idle_connection_timer); queue_delayed_work(info->workqueue, &info->idle_timer_work, - info->keep_alive_interval*HZ); + msecs_to_jiffies(sp->keepalive_interval_msec)); init_waitqueue_head(&info->wait_send_pending); atomic_set(&info->send_pending, 0); @@ -1675,26 +1703,26 @@ allocate_mr_failed: negotiation_failed: cancel_delayed_work_sync(&info->idle_timer_work); destroy_caches_and_workqueue(info); - info->transport_status = SMBD_NEGOTIATE_FAILED; + sc->status = SMBDIRECT_SOCKET_NEGOTIATE_FAILED; init_waitqueue_head(&info->conn_wait); - rdma_disconnect(info->id); + rdma_disconnect(sc->rdma.cm_id); wait_event(info->conn_wait, - info->transport_status == SMBD_DISCONNECTED); + sc->status == SMBDIRECT_SOCKET_DISCONNECTED); allocate_cache_failed: rdma_connect_failed: - rdma_destroy_qp(info->id); + rdma_destroy_qp(sc->rdma.cm_id); create_qp_failed: alloc_cq_failed: - if (info->send_cq) - ib_free_cq(info->send_cq); - if (info->recv_cq) - ib_free_cq(info->recv_cq); + if (sc->ib.send_cq) + ib_free_cq(sc->ib.send_cq); + if (sc->ib.recv_cq) + ib_free_cq(sc->ib.recv_cq); config_failed: - ib_dealloc_pd(info->pd); - rdma_destroy_id(info->id); + ib_dealloc_pd(sc->ib.pd); + rdma_destroy_id(sc->rdma.cm_id); create_id_failed: kfree(info); @@ -1734,8 +1762,9 @@ try_again: static int smbd_recv_buf(struct smbd_connection *info, char *buf, unsigned int size) { + struct smbdirect_socket *sc = &info->socket; struct smbd_response *response; - struct smbd_data_transfer *data_transfer; + struct smbdirect_data_transfer *data_transfer; int to_copy, to_read, data_read, offset; u32 data_length, remaining_data_length, data_offset; int rc; @@ -1848,12 +1877,12 @@ read_rfc1002_done: rc = wait_event_interruptible( info->wait_reassembly_queue, info->reassembly_data_length >= size || - info->transport_status != SMBD_CONNECTED); + sc->status != SMBDIRECT_SOCKET_CONNECTED); /* Don't return any data if interrupted */ if (rc) return rc; - if (info->transport_status != SMBD_CONNECTED) { + if (sc->status != SMBDIRECT_SOCKET_CONNECTED) { log_read(ERR, "disconnected\n"); return -ECONNABORTED; } @@ -1871,6 +1900,7 @@ static int smbd_recv_page(struct smbd_connection *info, struct page *page, unsigned int page_offset, unsigned int to_read) { + struct smbdirect_socket *sc = &info->socket; int ret; char *to_address; void *page_address; @@ -1879,7 +1909,7 @@ static int smbd_recv_page(struct smbd_connection *info, ret = wait_event_interruptible( info->wait_reassembly_queue, info->reassembly_data_length >= to_read || - info->transport_status != SMBD_CONNECTED); + sc->status != SMBDIRECT_SOCKET_CONNECTED); if (ret) return ret; @@ -1954,12 +1984,14 @@ int smbd_send(struct TCP_Server_Info *server, int num_rqst, struct smb_rqst *rqst_array) { struct smbd_connection *info = server->smbd_conn; + struct smbdirect_socket *sc = &info->socket; + struct smbdirect_socket_parameters *sp = &sc->parameters; struct smb_rqst *rqst; struct iov_iter iter; unsigned int remaining_data_length, klen; int rc, i, rqst_idx; - if (info->transport_status != SMBD_CONNECTED) + if (sc->status != SMBDIRECT_SOCKET_CONNECTED) return -EAGAIN; /* @@ -1971,10 +2003,10 @@ int smbd_send(struct TCP_Server_Info *server, for (i = 0; i < num_rqst; i++) remaining_data_length += smb_rqst_len(server, &rqst_array[i]); - if (unlikely(remaining_data_length > info->max_fragmented_send_size)) { + if (unlikely(remaining_data_length > sp->max_fragmented_send_size)) { /* assertion: payload never exceeds negotiated maximum */ log_write(ERR, "payload size %d > max size %d\n", - remaining_data_length, info->max_fragmented_send_size); + remaining_data_length, sp->max_fragmented_send_size); return -EINVAL; } @@ -2053,6 +2085,7 @@ static void smbd_mr_recovery_work(struct work_struct *work) { struct smbd_connection *info = container_of(work, struct smbd_connection, mr_recovery_work); + struct smbdirect_socket *sc = &info->socket; struct smbd_mr *smbdirect_mr; int rc; @@ -2070,7 +2103,7 @@ static void smbd_mr_recovery_work(struct work_struct *work) } smbdirect_mr->mr = ib_alloc_mr( - info->pd, info->mr_type, + sc->ib.pd, info->mr_type, info->max_frmr_depth); if (IS_ERR(smbdirect_mr->mr)) { log_rdma_mr(ERR, "ib_alloc_mr failed mr_type=%x max_frmr_depth=%x\n", @@ -2099,12 +2132,13 @@ static void smbd_mr_recovery_work(struct work_struct *work) static void destroy_mr_list(struct smbd_connection *info) { + struct smbdirect_socket *sc = &info->socket; struct smbd_mr *mr, *tmp; cancel_work_sync(&info->mr_recovery_work); list_for_each_entry_safe(mr, tmp, &info->mr_list, list) { if (mr->state == MR_INVALIDATED) - ib_dma_unmap_sg(info->id->device, mr->sgt.sgl, + ib_dma_unmap_sg(sc->ib.dev, mr->sgt.sgl, mr->sgt.nents, mr->dir); ib_dereg_mr(mr->mr); kfree(mr->sgt.sgl); @@ -2121,6 +2155,7 @@ static void destroy_mr_list(struct smbd_connection *info) */ static int allocate_mr_list(struct smbd_connection *info) { + struct smbdirect_socket *sc = &info->socket; int i; struct smbd_mr *smbdirect_mr, *tmp; @@ -2136,7 +2171,7 @@ static int allocate_mr_list(struct smbd_connection *info) smbdirect_mr = kzalloc(sizeof(*smbdirect_mr), GFP_KERNEL); if (!smbdirect_mr) goto cleanup_entries; - smbdirect_mr->mr = ib_alloc_mr(info->pd, info->mr_type, + smbdirect_mr->mr = ib_alloc_mr(sc->ib.pd, info->mr_type, info->max_frmr_depth); if (IS_ERR(smbdirect_mr->mr)) { log_rdma_mr(ERR, "ib_alloc_mr failed mr_type=%x max_frmr_depth=%x\n", @@ -2181,20 +2216,20 @@ cleanup_entries: */ static struct smbd_mr *get_mr(struct smbd_connection *info) { + struct smbdirect_socket *sc = &info->socket; struct smbd_mr *ret; int rc; again: rc = wait_event_interruptible(info->wait_mr, atomic_read(&info->mr_ready_count) || - info->transport_status != SMBD_CONNECTED); + sc->status != SMBDIRECT_SOCKET_CONNECTED); if (rc) { log_rdma_mr(ERR, "wait_event_interruptible rc=%x\n", rc); return NULL; } - if (info->transport_status != SMBD_CONNECTED) { - log_rdma_mr(ERR, "info->transport_status=%x\n", - info->transport_status); + if (sc->status != SMBDIRECT_SOCKET_CONNECTED) { + log_rdma_mr(ERR, "sc->status=%x\n", sc->status); return NULL; } @@ -2247,6 +2282,7 @@ struct smbd_mr *smbd_register_mr(struct smbd_connection *info, struct iov_iter *iter, bool writing, bool need_invalidate) { + struct smbdirect_socket *sc = &info->socket; struct smbd_mr *smbdirect_mr; int rc, num_pages; enum dma_data_direction dir; @@ -2276,7 +2312,7 @@ struct smbd_mr *smbd_register_mr(struct smbd_connection *info, num_pages, iov_iter_count(iter), info->max_frmr_depth); smbd_iter_to_mr(info, iter, &smbdirect_mr->sgt, info->max_frmr_depth); - rc = ib_dma_map_sg(info->id->device, smbdirect_mr->sgt.sgl, + rc = ib_dma_map_sg(sc->ib.dev, smbdirect_mr->sgt.sgl, smbdirect_mr->sgt.nents, dir); if (!rc) { log_rdma_mr(ERR, "ib_dma_map_sg num_pages=%x dir=%x rc=%x\n", @@ -2312,7 +2348,7 @@ struct smbd_mr *smbd_register_mr(struct smbd_connection *info, * on IB_WR_REG_MR. Hardware enforces a barrier and order of execution * on the next ib_post_send when we actually send I/O to remote peer */ - rc = ib_post_send(info->id->qp, ®_wr->wr, NULL); + rc = ib_post_send(sc->ib.qp, ®_wr->wr, NULL); if (!rc) return smbdirect_mr; @@ -2321,7 +2357,7 @@ struct smbd_mr *smbd_register_mr(struct smbd_connection *info, /* If all failed, attempt to recover this MR by setting it MR_ERROR*/ map_mr_error: - ib_dma_unmap_sg(info->id->device, smbdirect_mr->sgt.sgl, + ib_dma_unmap_sg(sc->ib.dev, smbdirect_mr->sgt.sgl, smbdirect_mr->sgt.nents, smbdirect_mr->dir); dma_map_error: @@ -2359,6 +2395,7 @@ int smbd_deregister_mr(struct smbd_mr *smbdirect_mr) { struct ib_send_wr *wr; struct smbd_connection *info = smbdirect_mr->conn; + struct smbdirect_socket *sc = &info->socket; int rc = 0; if (smbdirect_mr->need_invalidate) { @@ -2372,7 +2409,7 @@ int smbd_deregister_mr(struct smbd_mr *smbdirect_mr) wr->send_flags = IB_SEND_SIGNALED; init_completion(&smbdirect_mr->invalidate_done); - rc = ib_post_send(info->id->qp, wr, NULL); + rc = ib_post_send(sc->ib.qp, wr, NULL); if (rc) { log_rdma_mr(ERR, "ib_post_send failed rc=%x\n", rc); smbd_disconnect_rdma_connection(info); @@ -2389,7 +2426,7 @@ int smbd_deregister_mr(struct smbd_mr *smbdirect_mr) if (smbdirect_mr->state == MR_INVALIDATED) { ib_dma_unmap_sg( - info->id->device, smbdirect_mr->sgt.sgl, + sc->ib.dev, smbdirect_mr->sgt.sgl, smbdirect_mr->sgt.nents, smbdirect_mr->dir); smbdirect_mr->state = MR_READY; diff --git a/fs/smb/client/smbdirect.h b/fs/smb/client/smbdirect.h index c08e3665150d..75b3f491c3ad 100644 --- a/fs/smb/client/smbdirect.h +++ b/fs/smb/client/smbdirect.h @@ -15,6 +15,9 @@ #include <rdma/rdma_cm.h> #include <linux/mempool.h> +#include "../common/smbdirect/smbdirect.h" +#include "../common/smbdirect/smbdirect_socket.h" + extern int rdma_readwrite_threshold; extern int smbd_max_frmr_depth; extern int smbd_keep_alive_interval; @@ -50,14 +53,8 @@ enum smbd_connection_status { * 5. mempools for allocating packets */ struct smbd_connection { - enum smbd_connection_status transport_status; - - /* RDMA related */ - struct rdma_cm_id *id; - struct ib_qp_init_attr qp_attr; - struct ib_pd *pd; - struct ib_cq *send_cq, *recv_cq; - struct ib_device_attr dev_attr; + struct smbdirect_socket socket; + int ri_rc; struct completion ri_done; wait_queue_head_t conn_wait; @@ -72,15 +69,7 @@ struct smbd_connection { spinlock_t lock_new_credits_offered; int new_credits_offered; - /* Connection parameters defined in [MS-SMBD] 3.1.1.1 */ - int receive_credit_max; - int send_credit_target; - int max_send_size; - int max_fragmented_recv_size; - int max_fragmented_send_size; - int max_receive_size; - int keep_alive_interval; - int max_readwrite_size; + /* dynamic connection parameters defined in [MS-SMBD] 3.1.1.1 */ enum keep_alive_status keep_alive_requested; int protocol; atomic_t send_credits; @@ -177,54 +166,6 @@ enum smbd_message_type { SMBD_TRANSFER_DATA, }; -#define SMB_DIRECT_RESPONSE_REQUESTED 0x0001 - -/* SMBD negotiation request packet [MS-SMBD] 2.2.1 */ -struct smbd_negotiate_req { - __le16 min_version; - __le16 max_version; - __le16 reserved; - __le16 credits_requested; - __le32 preferred_send_size; - __le32 max_receive_size; - __le32 max_fragmented_size; -} __packed; - -/* SMBD negotiation response packet [MS-SMBD] 2.2.2 */ -struct smbd_negotiate_resp { - __le16 min_version; - __le16 max_version; - __le16 negotiated_version; - __le16 reserved; - __le16 credits_requested; - __le16 credits_granted; - __le32 status; - __le32 max_readwrite_size; - __le32 preferred_send_size; - __le32 max_receive_size; - __le32 max_fragmented_size; -} __packed; - -/* SMBD data transfer packet with payload [MS-SMBD] 2.2.3 */ -struct smbd_data_transfer { - __le16 credits_requested; - __le16 credits_granted; - __le16 flags; - __le16 reserved; - __le32 remaining_data_length; - __le32 data_offset; - __le32 data_length; - __le32 padding; - __u8 buffer[]; -} __packed; - -/* The packet fields for a registered RDMA buffer */ -struct smbd_buffer_descriptor_v1 { - __le64 offset; - __le32 token; - __le32 length; -} __packed; - /* Maximum number of SGEs used by smbdirect.c in any send work request */ #define SMBDIRECT_MAX_SEND_SGE 6 diff --git a/fs/smb/client/transport.c b/fs/smb/client/transport.c index 266af17aa7d9..191783f553ce 100644 --- a/fs/smb/client/transport.c +++ b/fs/smb/client/transport.c @@ -1018,14 +1018,16 @@ struct TCP_Server_Info *cifs_pick_channel(struct cifs_ses *ses) uint index = 0; unsigned int min_in_flight = UINT_MAX, max_in_flight = 0; struct TCP_Server_Info *server = NULL; - int i; + int i, start, cur; if (!ses) return NULL; spin_lock(&ses->chan_lock); + start = atomic_inc_return(&ses->chan_seq); for (i = 0; i < ses->chan_count; i++) { - server = ses->chans[i].server; + cur = (start + i) % ses->chan_count; + server = ses->chans[cur].server; if (!server || server->terminate) continue; @@ -1042,17 +1044,15 @@ struct TCP_Server_Info *cifs_pick_channel(struct cifs_ses *ses) */ if (server->in_flight < min_in_flight) { min_in_flight = server->in_flight; - index = i; + index = cur; } if (server->in_flight > max_in_flight) max_in_flight = server->in_flight; } /* if all channels are equally loaded, fall back to round-robin */ - if (min_in_flight == max_in_flight) { - index = (uint)atomic_inc_return(&ses->chan_seq); - index %= ses->chan_count; - } + if (min_in_flight == max_in_flight) + index = (uint)start % ses->chan_count; server = ses->chans[index].server; spin_unlock(&ses->chan_lock); diff --git a/fs/smb/common/smbdirect/smbdirect.h b/fs/smb/common/smbdirect/smbdirect.h new file mode 100644 index 000000000000..b9a385344ff3 --- /dev/null +++ b/fs/smb/common/smbdirect/smbdirect.h @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2017, Microsoft Corporation. + * Copyright (C) 2018, LG Electronics. + */ + +#ifndef __FS_SMB_COMMON_SMBDIRECT_SMBDIRECT_H__ +#define __FS_SMB_COMMON_SMBDIRECT_SMBDIRECT_H__ + +/* SMB-DIRECT buffer descriptor V1 structure [MS-SMBD] 2.2.3.1 */ +struct smbdirect_buffer_descriptor_v1 { + __le64 offset; + __le32 token; + __le32 length; +} __packed; + +/* + * Connection parameters mostly from [MS-SMBD] 3.1.1.1 + * + * These are setup and negotiated at the beginning of a + * connection and remain constant unless explicitly changed. + * + * Some values are important for the upper layer. + */ +struct smbdirect_socket_parameters { + __u16 recv_credit_max; + __u16 send_credit_target; + __u32 max_send_size; + __u32 max_fragmented_send_size; + __u32 max_recv_size; + __u32 max_fragmented_recv_size; + __u32 max_read_write_size; + __u32 keepalive_interval_msec; + __u32 keepalive_timeout_msec; +} __packed; + +#endif /* __FS_SMB_COMMON_SMBDIRECT_SMBDIRECT_H__ */ diff --git a/fs/smb/common/smbdirect/smbdirect_pdu.h b/fs/smb/common/smbdirect/smbdirect_pdu.h new file mode 100644 index 000000000000..ae9fdb05ce23 --- /dev/null +++ b/fs/smb/common/smbdirect/smbdirect_pdu.h @@ -0,0 +1,55 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2017 Stefan Metzmacher + */ + +#ifndef __FS_SMB_COMMON_SMBDIRECT_SMBDIRECT_PDU_H__ +#define __FS_SMB_COMMON_SMBDIRECT_SMBDIRECT_PDU_H__ + +#define SMBDIRECT_V1 0x0100 + +/* SMBD negotiation request packet [MS-SMBD] 2.2.1 */ +struct smbdirect_negotiate_req { + __le16 min_version; + __le16 max_version; + __le16 reserved; + __le16 credits_requested; + __le32 preferred_send_size; + __le32 max_receive_size; + __le32 max_fragmented_size; +} __packed; + +/* SMBD negotiation response packet [MS-SMBD] 2.2.2 */ +struct smbdirect_negotiate_resp { + __le16 min_version; + __le16 max_version; + __le16 negotiated_version; + __le16 reserved; + __le16 credits_requested; + __le16 credits_granted; + __le32 status; + __le32 max_readwrite_size; + __le32 preferred_send_size; + __le32 max_receive_size; + __le32 max_fragmented_size; +} __packed; + +#define SMBDIRECT_DATA_MIN_HDR_SIZE 0x14 +#define SMBDIRECT_DATA_OFFSET 0x18 + +#define SMBDIRECT_FLAG_RESPONSE_REQUESTED 0x0001 + +/* SMBD data transfer packet with payload [MS-SMBD] 2.2.3 */ +struct smbdirect_data_transfer { + __le16 credits_requested; + __le16 credits_granted; + __le16 flags; + __le16 reserved; + __le32 remaining_data_length; + __le32 data_offset; + __le32 data_length; + __le32 padding; + __u8 buffer[]; +} __packed; + +#endif /* __FS_SMB_COMMON_SMBDIRECT_SMBDIRECT_PDU_H__ */ diff --git a/fs/smb/common/smbdirect/smbdirect_socket.h b/fs/smb/common/smbdirect/smbdirect_socket.h new file mode 100644 index 000000000000..e5b15cc44a7b --- /dev/null +++ b/fs/smb/common/smbdirect/smbdirect_socket.h @@ -0,0 +1,43 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2025 Stefan Metzmacher + */ + +#ifndef __FS_SMB_COMMON_SMBDIRECT_SMBDIRECT_SOCKET_H__ +#define __FS_SMB_COMMON_SMBDIRECT_SMBDIRECT_SOCKET_H__ + +enum smbdirect_socket_status { + SMBDIRECT_SOCKET_CREATED, + SMBDIRECT_SOCKET_CONNECTING, + SMBDIRECT_SOCKET_CONNECTED, + SMBDIRECT_SOCKET_NEGOTIATE_FAILED, + SMBDIRECT_SOCKET_DISCONNECTING, + SMBDIRECT_SOCKET_DISCONNECTED, + SMBDIRECT_SOCKET_DESTROYED +}; + +struct smbdirect_socket { + enum smbdirect_socket_status status; + + /* RDMA related */ + struct { + struct rdma_cm_id *cm_id; + } rdma; + + /* IB verbs related */ + struct { + struct ib_pd *pd; + struct ib_cq *send_cq; + struct ib_cq *recv_cq; + + /* + * shortcuts for rdma.cm_id->{qp,device}; + */ + struct ib_qp *qp; + struct ib_device *dev; + } ib; + + struct smbdirect_socket_parameters parameters; +}; + +#endif /* __FS_SMB_COMMON_SMBDIRECT_SMBDIRECT_SOCKET_H__ */ diff --git a/fs/ubifs/journal.c b/fs/ubifs/journal.c index ee954e64ce7f..e28ab4395e5c 100644 --- a/fs/ubifs/journal.c +++ b/fs/ubifs/journal.c @@ -985,7 +985,7 @@ int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode) dbg_jnl("ino %lu, nlink %u", inode->i_ino, inode->i_nlink); if (kill_xattrs && ui->xattr_cnt > ubifs_xattr_max_cnt(c)) { - ubifs_err(c, "Cannot delete inode, it has too much xattrs!"); + ubifs_err(c, "Cannot delete inode, it has too many xattrs!"); err = -EPERM; ubifs_ro_mode(c, err); return err; diff --git a/include/dt-bindings/iio/adc/adi,ad7606.h b/include/dt-bindings/iio/adc/adi,ad7606.h new file mode 100644 index 000000000000..f38a6d72b6dc --- /dev/null +++ b/include/dt-bindings/iio/adc/adi,ad7606.h @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ + +#ifndef _DT_BINDINGS_ADI_AD7606_H +#define _DT_BINDINGS_ADI_AD7606_H + +#define AD7606_TRIGGER_EVENT_BUSY 0 +#define AD7606_TRIGGER_EVENT_FRSTDATA 1 + +#endif /* _DT_BINDINGS_ADI_AD7606_H */ diff --git a/include/dt-bindings/interconnect/qcom,sm8650-rpmh.h b/include/dt-bindings/interconnect/qcom,sm8650-rpmh.h index 6c1eaf04e241..1216aa352d55 100644 --- a/include/dt-bindings/interconnect/qcom,sm8650-rpmh.h +++ b/include/dt-bindings/interconnect/qcom,sm8650-rpmh.h @@ -150,5 +150,6 @@ #define MASTER_A1NOC_SNOC 0 #define MASTER_A2NOC_SNOC 1 #define SLAVE_SNOC_GEM_NOC_SF 2 +#define MASTER_APSS_NOC 3 #endif diff --git a/include/dt-bindings/sound/qcom,q6dsp-lpass-ports.h b/include/dt-bindings/sound/qcom,q6dsp-lpass-ports.h index 39f203256c4f..6d1ce7f5da51 100644 --- a/include/dt-bindings/sound/qcom,q6dsp-lpass-ports.h +++ b/include/dt-bindings/sound/qcom,q6dsp-lpass-ports.h @@ -139,6 +139,7 @@ #define DISPLAY_PORT_RX_5 133 #define DISPLAY_PORT_RX_6 134 #define DISPLAY_PORT_RX_7 135 +#define USB_RX 136 #define LPASS_CLK_ID_PRI_MI2S_IBIT 1 #define LPASS_CLK_ID_PRI_MI2S_EBIT 2 diff --git a/include/linux/bcm963xx_nvram.h b/include/linux/bcm963xx_nvram.h index c8c7f01159fe..48830bf18042 100644 --- a/include/linux/bcm963xx_nvram.h +++ b/include/linux/bcm963xx_nvram.h @@ -81,25 +81,21 @@ static int __maybe_unused bcm963xx_nvram_checksum( const struct bcm963xx_nvram *nvram, u32 *expected_out, u32 *actual_out) { + const u32 zero = 0; u32 expected, actual; size_t len; if (nvram->version <= 4) { expected = nvram->checksum_v4; - len = BCM963XX_NVRAM_V4_SIZE - sizeof(u32); + len = BCM963XX_NVRAM_V4_SIZE; } else { expected = nvram->checksum_v5; - len = BCM963XX_NVRAM_V5_SIZE - sizeof(u32); + len = BCM963XX_NVRAM_V5_SIZE; } - /* - * Calculate the CRC32 value for the nvram with a checksum value - * of 0 without modifying or copying the nvram by combining: - * - The CRC32 of the nvram without the checksum value - * - The CRC32 of a zero checksum value (which is also 0) - */ - actual = crc32_le_combine( - crc32_le(~0, (u8 *)nvram, len), 0, sizeof(u32)); + /* Calculate the CRC32 of the nvram with the checksum field set to 0. */ + actual = crc32_le(~0, nvram, len - sizeof(u32)); + actual = crc32_le(actual, &zero, sizeof(u32)); if (expected_out) *expected_out = expected; diff --git a/include/linux/codetag.h b/include/linux/codetag.h index 0ee4c21c6dbc..5f2b9a1f722c 100644 --- a/include/linux/codetag.h +++ b/include/linux/codetag.h @@ -36,8 +36,8 @@ union codetag_ref { struct codetag_type_desc { const char *section; size_t tag_size; - void (*module_load)(struct module *mod, - struct codetag *start, struct codetag *end); + int (*module_load)(struct module *mod, + struct codetag *start, struct codetag *end); void (*module_unload)(struct module *mod, struct codetag *start, struct codetag *end); #ifdef CONFIG_MODULES @@ -89,7 +89,7 @@ void *codetag_alloc_module_section(struct module *mod, const char *name, unsigned long align); void codetag_free_module_sections(struct module *mod); void codetag_module_replaced(struct module *mod, struct module *new_mod); -void codetag_load_module(struct module *mod); +int codetag_load_module(struct module *mod); void codetag_unload_module(struct module *mod); #else /* defined(CONFIG_CODE_TAGGING) && defined(CONFIG_MODULES) */ @@ -103,7 +103,7 @@ codetag_alloc_module_section(struct module *mod, const char *name, unsigned long align) { return NULL; } static inline void codetag_free_module_sections(struct module *mod) {} static inline void codetag_module_replaced(struct module *mod, struct module *new_mod) {} -static inline void codetag_load_module(struct module *mod) {} +static inline int codetag_load_module(struct module *mod) { return 0; } static inline void codetag_unload_module(struct module *mod) {} #endif /* defined(CONFIG_CODE_TAGGING) && defined(CONFIG_MODULES) */ diff --git a/include/linux/comedi/comedidev.h b/include/linux/comedi/comedidev.h index c08416a7364b..4cb0400ad616 100644 --- a/include/linux/comedi/comedidev.h +++ b/include/linux/comedi/comedidev.h @@ -234,16 +234,12 @@ struct comedi_buf_page { * * A COMEDI data buffer is allocated as individual pages, either in * conventional memory or DMA coherent memory, depending on the attached, - * low-level hardware device. (The buffer pages also get mapped into the - * kernel's contiguous virtual address space pointed to by the 'prealloc_buf' - * member of &struct comedi_async.) + * low-level hardware device. * * The buffer is normally freed when the COMEDI device is detached from the * low-level driver (which may happen due to device removal), but if it happens * to be mmapped at the time, the pages cannot be freed until the buffer has - * been munmapped. That is what the reference counter is for. (The virtual - * address space pointed by 'prealloc_buf' is freed when the COMEDI device is - * detached.) + * been munmapped. That is what the reference counter is for. */ struct comedi_buf_map { struct device *dma_hw_dev; @@ -255,7 +251,6 @@ struct comedi_buf_map { /** * struct comedi_async - Control data for asynchronous COMEDI commands - * @prealloc_buf: Kernel virtual address of allocated acquisition buffer. * @prealloc_bufsz: Buffer size (in bytes). * @buf_map: Map of buffer pages. * @max_bufsize: Maximum allowed buffer size (in bytes). @@ -344,7 +339,6 @@ struct comedi_buf_map { * less than or equal to UINT_MAX). */ struct comedi_async { - void *prealloc_buf; unsigned int prealloc_bufsz; struct comedi_buf_map *buf_map; unsigned int max_bufsize; diff --git a/include/linux/console_struct.h b/include/linux/console_struct.h index 20f564e98552..59b4fec5f254 100644 --- a/include/linux/console_struct.h +++ b/include/linux/console_struct.h @@ -145,6 +145,7 @@ struct vc_data { unsigned int vc_need_wrap : 1; unsigned int vc_can_do_color : 1; unsigned int vc_report_mouse : 2; + unsigned int vc_bracketed_paste : 1; unsigned char vc_utf : 1; /* Unicode UTF-8 encoding */ unsigned char vc_utf_count; int vc_utf_char; diff --git a/include/linux/consolemap.h b/include/linux/consolemap.h index c35db4896c37..6180b803795c 100644 --- a/include/linux/consolemap.h +++ b/include/linux/consolemap.h @@ -28,6 +28,10 @@ int conv_uni_to_pc(struct vc_data *conp, long ucs); u32 conv_8bit_to_uni(unsigned char c); int conv_uni_to_8bit(u32 uni); void console_map_init(void); +bool ucs_is_double_width(uint32_t cp); +bool ucs_is_zero_width(uint32_t cp); +u32 ucs_recompose(u32 base, u32 mark); +u32 ucs_get_fallback(u32 cp); #else static inline u16 inverse_translate(const struct vc_data *conp, u16 glyph, bool use_unicode) @@ -57,6 +61,26 @@ static inline int conv_uni_to_8bit(u32 uni) } static inline void console_map_init(void) { } + +static inline bool ucs_is_double_width(uint32_t cp) +{ + return false; +} + +static inline bool ucs_is_zero_width(uint32_t cp) +{ + return false; +} + +static inline u32 ucs_recompose(u32 base, u32 mark) +{ + return 0; +} + +static inline u32 ucs_get_fallback(u32 cp) +{ + return 0; +} #endif /* CONFIG_CONSOLE_TRANSLATIONS */ #endif /* __LINUX_CONSOLEMAP_H__ */ diff --git a/include/linux/coresight.h b/include/linux/coresight.h index d79a242b271d..4ac65c68bbf4 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -398,6 +398,8 @@ struct coresight_ops_link { * is associated to. * @enable: enables tracing for a source. * @disable: disables tracing for a source. + * @resume_perf: resumes tracing for a source in perf session. + * @pause_perf: pauses tracing for a source in perf session. */ struct coresight_ops_source { int (*cpu_id)(struct coresight_device *csdev); @@ -405,6 +407,8 @@ struct coresight_ops_source { enum cs_mode mode, struct coresight_path *path); void (*disable)(struct coresight_device *csdev, struct perf_event *event); + int (*resume_perf)(struct coresight_device *csdev); + void (*pause_perf)(struct coresight_device *csdev); }; /** @@ -671,27 +675,27 @@ static inline void coresight_set_mode(struct coresight_device *csdev, local_set(&csdev->mode, new_mode); } -extern struct coresight_device * -coresight_register(struct coresight_desc *desc); -extern void coresight_unregister(struct coresight_device *csdev); -extern int coresight_enable_sysfs(struct coresight_device *csdev); -extern void coresight_disable_sysfs(struct coresight_device *csdev); -extern int coresight_timeout(struct csdev_access *csa, u32 offset, - int position, int value); +struct coresight_device *coresight_register(struct coresight_desc *desc); +void coresight_unregister(struct coresight_device *csdev); +int coresight_enable_sysfs(struct coresight_device *csdev); +void coresight_disable_sysfs(struct coresight_device *csdev); +int coresight_timeout(struct csdev_access *csa, u32 offset, int position, int value); typedef void (*coresight_timeout_cb_t) (struct csdev_access *, u32, int, int); -extern int coresight_timeout_action(struct csdev_access *csa, u32 offset, - int position, int value, - coresight_timeout_cb_t cb); - -extern int coresight_claim_device(struct coresight_device *csdev); -extern int coresight_claim_device_unlocked(struct coresight_device *csdev); - -extern void coresight_disclaim_device(struct coresight_device *csdev); -extern void coresight_disclaim_device_unlocked(struct coresight_device *csdev); -extern char *coresight_alloc_device_name(struct coresight_dev_list *devs, +int coresight_timeout_action(struct csdev_access *csa, u32 offset, int position, int value, + coresight_timeout_cb_t cb); +int coresight_claim_device(struct coresight_device *csdev); +int coresight_claim_device_unlocked(struct coresight_device *csdev); + +int coresight_claim_device(struct coresight_device *csdev); +int coresight_claim_device_unlocked(struct coresight_device *csdev); +void coresight_clear_self_claim_tag(struct csdev_access *csa); +void coresight_clear_self_claim_tag_unlocked(struct csdev_access *csa); +void coresight_disclaim_device(struct coresight_device *csdev); +void coresight_disclaim_device_unlocked(struct coresight_device *csdev); +char *coresight_alloc_device_name(struct coresight_dev_list *devs, struct device *dev); -extern bool coresight_loses_context_with_cpu(struct device *dev); +bool coresight_loses_context_with_cpu(struct device *dev); u32 coresight_relaxed_read32(struct coresight_device *csdev, u32 offset); u32 coresight_read32(struct coresight_device *csdev, u32 offset); @@ -704,8 +708,8 @@ void coresight_relaxed_write64(struct coresight_device *csdev, u64 val, u32 offset); void coresight_write64(struct coresight_device *csdev, u64 val, u32 offset); -extern int coresight_get_cpu(struct device *dev); -extern int coresight_get_static_trace_id(struct device *dev, u32 *id); +int coresight_get_cpu(struct device *dev); +int coresight_get_static_trace_id(struct device *dev, u32 *id); struct coresight_platform_data *coresight_get_platform_data(struct device *dev); struct coresight_connection * @@ -723,7 +727,7 @@ coresight_find_output_type(struct coresight_platform_data *pdata, union coresight_dev_subtype subtype); int coresight_init_driver(const char *drv, struct amba_driver *amba_drv, - struct platform_driver *pdev_drv); + struct platform_driver *pdev_drv, struct module *owner); void coresight_remove_driver(struct amba_driver *amba_drv, struct platform_driver *pdev_drv); diff --git a/include/linux/eisa.h b/include/linux/eisa.h index f98200cae637..21a2ecc1e538 100644 --- a/include/linux/eisa.h +++ b/include/linux/eisa.h @@ -28,6 +28,9 @@ #define EISA_CONFIG_ENABLED 1 #define EISA_CONFIG_FORCED 2 +/* Chosen to hold the longest string in eisa.ids. */ +#define EISA_DEVICE_INFO_NAME_SIZE 74 + /* There is not much we can say about an EISA device, apart from * signature, slot number, and base address. dma_mask is set by * default to parent device mask..*/ @@ -41,7 +44,7 @@ struct eisa_device { u64 dma_mask; struct device dev; /* generic device */ #ifdef CONFIG_EISA_NAMES - char pretty_name[50]; + char pretty_name[EISA_DEVICE_INFO_NAME_SIZE]; #endif }; diff --git a/include/linux/export.h b/include/linux/export.h index a8c23d945634..f35d03b4113b 100644 --- a/include/linux/export.h +++ b/include/linux/export.h @@ -24,11 +24,17 @@ .long sym #endif -#define ___EXPORT_SYMBOL(sym, license, ns) \ +/* + * LLVM integrated assembler cam merge adjacent string literals (like + * C and GNU-as) passed to '.ascii', but not to '.asciz' and chokes on: + * + * .asciz "MODULE_" "kvm" ; + */ +#define ___EXPORT_SYMBOL(sym, license, ns...) \ .section ".export_symbol","a" ASM_NL \ __export_symbol_##sym: ASM_NL \ .asciz license ASM_NL \ - .asciz ns ASM_NL \ + .ascii ns "\0" ASM_NL \ __EXPORT_SYMBOL_REF(sym) ASM_NL \ .previous @@ -85,4 +91,6 @@ #define EXPORT_SYMBOL_NS(sym, ns) __EXPORT_SYMBOL(sym, "", ns) #define EXPORT_SYMBOL_NS_GPL(sym, ns) __EXPORT_SYMBOL(sym, "GPL", ns) +#define EXPORT_SYMBOL_GPL_FOR_MODULES(sym, mods) __EXPORT_SYMBOL(sym, "GPL", "module:" mods) + #endif /* _LINUX_EXPORT_H */ diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h index a4d3816d252a..b672ca15f265 100644 --- a/include/linux/ftrace.h +++ b/include/linux/ftrace.h @@ -635,6 +635,8 @@ enum { #define ftrace_get_symaddr(fentry_ip) (0) #endif +void ftrace_sync_ipi(void *data); + #ifdef CONFIG_DYNAMIC_FTRACE void ftrace_arch_code_modify_prepare(void); diff --git a/include/linux/hid-sensor-hub.h b/include/linux/hid-sensor-hub.h index c27329e2a5ad..e71056553108 100644 --- a/include/linux/hid-sensor-hub.h +++ b/include/linux/hid-sensor-hub.h @@ -17,7 +17,7 @@ * @attrib_id: Attribute id for this attribute. * @report_id: Report id in which this information resides. * @index: Field index in the report. - * @units: Measurment unit for this attribute. + * @units: Measurement unit for this attribute. * @unit_expo: Exponent used in the data. * @size: Size in bytes for data size. * @logical_minimum: Logical minimum value for this attribute. @@ -39,8 +39,8 @@ struct hid_sensor_hub_attribute_info { * struct sensor_hub_pending - Synchronous read pending information * @status: Pending status true/false. * @ready: Completion synchronization data. - * @usage_id: Usage id for physical device, E.g. Gyro usage id. - * @attr_usage_id: Usage Id of a field, E.g. X-AXIS for a gyro. + * @usage_id: Usage id for physical device, e.g. gyro usage id. + * @attr_usage_id: Usage Id of a field, e.g. X-axis for a gyro. * @raw_size: Response size for a read request. * @raw_data: Place holder for received response. */ @@ -104,10 +104,10 @@ struct hid_sensor_hub_callbacks { int sensor_hub_device_open(struct hid_sensor_hub_device *hsdev); /** -* sensor_hub_device_clode() - Close hub device +* sensor_hub_device_close() - Close hub device * @hsdev: Hub device instance. * -* Used to clode hid device for sensor hub. +* Used to close hid device for sensor hub. */ void sensor_hub_device_close(struct hid_sensor_hub_device *hsdev); @@ -128,12 +128,13 @@ int sensor_hub_register_callback(struct hid_sensor_hub_device *hsdev, struct hid_sensor_hub_callbacks *usage_callback); /** -* sensor_hub_remove_callback() - Remove client callbacks +* sensor_hub_remove_callback() - Remove client callback * @hsdev: Hub device instance. -* @usage_id: Usage id of the client (E.g. 0x200076 for Gyro). +* @usage_id: Usage id of the client (e.g. 0x200076 for gyro). * -* If there is a callback registred, this call will remove that -* callbacks, so that it will stop data and event notifications. +* Removes a previously registered callback for the given usage_id +* and hsdev. Once removed, the client will no longer receive data or +* event notifications. */ int sensor_hub_remove_callback(struct hid_sensor_hub_device *hsdev, u32 usage_id); diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h index 0598f36931de..42f374e828a2 100644 --- a/include/linux/hugetlb.h +++ b/include/linux/hugetlb.h @@ -279,6 +279,7 @@ bool is_hugetlb_entry_migration(pte_t pte); bool is_hugetlb_entry_hwpoisoned(pte_t pte); void hugetlb_unshare_all_pmds(struct vm_area_struct *vma); void fixup_hugetlb_reservations(struct vm_area_struct *vma); +void hugetlb_split(struct vm_area_struct *vma, unsigned long addr); #else /* !CONFIG_HUGETLB_PAGE */ @@ -476,6 +477,8 @@ static inline void fixup_hugetlb_reservations(struct vm_area_struct *vma) { } +static inline void hugetlb_split(struct vm_area_struct *vma, unsigned long addr) {} + #endif /* !CONFIG_HUGETLB_PAGE */ #ifndef pgd_write diff --git a/include/linux/iio/adc-helpers.h b/include/linux/iio/adc-helpers.h new file mode 100644 index 000000000000..56b092a2a4c4 --- /dev/null +++ b/include/linux/iio/adc-helpers.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +/* + * The industrial I/O ADC firmware property parsing helpers + * + * Copyright (c) 2025 Matti Vaittinen <mazziesaccount@gmail.com> + */ + +#ifndef _INDUSTRIAL_IO_ADC_HELPERS_H_ +#define _INDUSTRIAL_IO_ADC_HELPERS_H_ + +#include <linux/property.h> + +struct device; +struct iio_chan_spec; + +static inline int iio_adc_device_num_channels(struct device *dev) +{ + return device_get_named_child_node_count(dev, "channel"); +} + +int devm_iio_adc_device_alloc_chaninfo_se(struct device *dev, + const struct iio_chan_spec *template, + int max_chan_id, + struct iio_chan_spec **cs); + +#endif /* _INDUSTRIAL_IO_ADC_HELPERS_H_ */ diff --git a/include/linux/iio/backend.h b/include/linux/iio/backend.h index e45b7dfbec35..e59d909cb659 100644 --- a/include/linux/iio/backend.h +++ b/include/linux/iio/backend.h @@ -84,6 +84,7 @@ enum iio_backend_interface_type { * @chan_disable: Disable one channel. * @data_format_set: Configure the data format for a specific channel. * @data_source_set: Configure the data source for a specific channel. + * @data_source_get: Data source getter for a specific channel. * @set_sample_rate: Configure the sampling rate for a specific channel. * @test_pattern_set: Configure a test pattern. * @chan_status: Get the channel status. @@ -115,6 +116,8 @@ struct iio_backend_ops { const struct iio_backend_data_fmt *data); int (*data_source_set)(struct iio_backend *back, unsigned int chan, enum iio_backend_data_source data); + int (*data_source_get)(struct iio_backend *back, unsigned int chan, + enum iio_backend_data_source *data); int (*set_sample_rate)(struct iio_backend *back, unsigned int chan, u64 sample_rate_hz); int (*test_pattern_set)(struct iio_backend *back, @@ -176,6 +179,8 @@ int iio_backend_data_format_set(struct iio_backend *back, unsigned int chan, const struct iio_backend_data_fmt *data); int iio_backend_data_source_set(struct iio_backend *back, unsigned int chan, enum iio_backend_data_source data); +int iio_backend_data_source_get(struct iio_backend *back, unsigned int chan, + enum iio_backend_data_source *data); int iio_backend_set_sampling_freq(struct iio_backend *back, unsigned int chan, u64 sample_rate_hz); int iio_backend_test_pattern_set(struct iio_backend *back, diff --git a/include/linux/iio/buffer.h b/include/linux/iio/buffer.h index 3b8d618bb3df..5c84ec4a9810 100644 --- a/include/linux/iio/buffer.h +++ b/include/linux/iio/buffer.h @@ -45,6 +45,18 @@ static inline int iio_push_to_buffers_with_timestamp(struct iio_dev *indio_dev, return iio_push_to_buffers(indio_dev, data); } +static inline int iio_push_to_buffers_with_ts(struct iio_dev *indio_dev, + void *data, size_t data_total_len, + s64 timestamp) +{ + if (unlikely(data_total_len < indio_dev->scan_bytes)) { + dev_err(&indio_dev->dev, "Undersized storage pushed to buffer\n"); + return -ENOSPC; + } + + return iio_push_to_buffers_with_timestamp(indio_dev, data, timestamp); +} + int iio_push_to_buffers_with_ts_unaligned(struct iio_dev *indio_dev, const void *data, size_t data_sz, int64_t timestamp); diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h index 07a0e8132e88..d11668f14a3e 100644 --- a/include/linux/iio/iio.h +++ b/include/linux/iio/iio.h @@ -7,9 +7,11 @@ #ifndef _INDUSTRIAL_IO_H_ #define _INDUSTRIAL_IO_H_ +#include <linux/align.h> #include <linux/device.h> #include <linux/cdev.h> #include <linux/compiler_types.h> +#include <linux/minmax.h> #include <linux/slab.h> #include <linux/iio/types.h> /* IIO TODO LIST */ @@ -659,8 +661,8 @@ void iio_device_unregister(struct iio_dev *indio_dev); int __devm_iio_device_register(struct device *dev, struct iio_dev *indio_dev, struct module *this_mod); int iio_push_event(struct iio_dev *indio_dev, u64 ev_code, s64 timestamp); -int iio_device_claim_direct_mode(struct iio_dev *indio_dev); -void iio_device_release_direct_mode(struct iio_dev *indio_dev); +bool __iio_device_claim_direct(struct iio_dev *indio_dev); +void __iio_device_release_direct(struct iio_dev *indio_dev); /* * Helper functions that allow claim and release of direct mode @@ -671,9 +673,7 @@ void iio_device_release_direct_mode(struct iio_dev *indio_dev); */ static inline bool iio_device_claim_direct(struct iio_dev *indio_dev) { - int ret = iio_device_claim_direct_mode(indio_dev); - - if (ret) + if (!__iio_device_claim_direct(indio_dev)) return false; __acquire(iio_dev); @@ -683,7 +683,7 @@ static inline bool iio_device_claim_direct(struct iio_dev *indio_dev) static inline void iio_device_release_direct(struct iio_dev *indio_dev) { - iio_device_release_direct_mode(indio_dev); + __iio_device_release_direct(indio_dev); __release(indio_dev); } @@ -777,8 +777,45 @@ static inline void *iio_device_get_drvdata(const struct iio_dev *indio_dev) * to in turn include IIO_DMA_MINALIGN'd elements such as buffers which * must not share cachelines with the rest of the structure, thus making * them safe for use with non-coherent DMA. + * + * A number of drivers also use this on buffers that include a 64-bit timestamp + * that is used with iio_push_to_buffer_with_ts(). Therefore, in the case where + * DMA alignment is not sufficient for proper timestamp alignment, we align to + * 8 bytes instead. + */ +#define IIO_DMA_MINALIGN MAX(ARCH_DMA_MINALIGN, sizeof(s64)) + +#define __IIO_DECLARE_BUFFER_WITH_TS(type, name, count) \ + type name[ALIGN((count), sizeof(s64) / sizeof(type)) + sizeof(s64) / sizeof(type)] + +/** + * IIO_DECLARE_BUFFER_WITH_TS() - Declare a buffer with timestamp + * @type: element type of the buffer + * @name: identifier name of the buffer + * @count: number of elements in the buffer + * + * Declares a buffer that is safe to use with iio_push_to_buffer_with_ts(). In + * addition to allocating enough space for @count elements of @type, it also + * allocates space for a s64 timestamp at the end of the buffer and ensures + * proper alignment of the timestamp. + */ +#define IIO_DECLARE_BUFFER_WITH_TS(type, name, count) \ + __IIO_DECLARE_BUFFER_WITH_TS(type, name, count) __aligned(sizeof(s64)) + +/** + * IIO_DECLARE_DMA_BUFFER_WITH_TS() - Declare a DMA-aligned buffer with timestamp + * @type: element type of the buffer + * @name: identifier name of the buffer + * @count: number of elements in the buffer + * + * Same as IIO_DECLARE_BUFFER_WITH_TS(), but is uses __aligned(IIO_DMA_MINALIGN) + * to ensure that the buffer doesn't share cachelines with anything that comes + * before it in a struct. This should not be used for stack-allocated buffers + * as stack memory cannot generally be used for DMA. */ -#define IIO_DMA_MINALIGN ARCH_DMA_MINALIGN +#define IIO_DECLARE_DMA_BUFFER_WITH_TS(type, name, count) \ + __IIO_DECLARE_BUFFER_WITH_TS(type, name, count) __aligned(IIO_DMA_MINALIGN) + struct iio_dev *iio_device_alloc(struct device *parent, int sizeof_priv); /* The information at the returned address is guaranteed to be cacheline aligned */ diff --git a/include/linux/iio/timer/stm32-lptim-trigger.h b/include/linux/iio/timer/stm32-lptim-trigger.h index a34dcf6a6001..ce3cf0addb2e 100644 --- a/include/linux/iio/timer/stm32-lptim-trigger.h +++ b/include/linux/iio/timer/stm32-lptim-trigger.h @@ -14,6 +14,15 @@ #define LPTIM1_OUT "lptim1_out" #define LPTIM2_OUT "lptim2_out" #define LPTIM3_OUT "lptim3_out" +#define LPTIM4_OUT "lptim4_out" +#define LPTIM5_OUT "lptim5_out" + +#define LPTIM1_CH1 "lptim1_ch1" +#define LPTIM1_CH2 "lptim1_ch2" +#define LPTIM2_CH1 "lptim2_ch1" +#define LPTIM2_CH2 "lptim2_ch2" +#define LPTIM3_CH1 "lptim3_ch1" +#define LPTIM4_CH1 "lptim4_ch1" #if IS_REACHABLE(CONFIG_IIO_STM32_LPTIMER_TRIGGER) bool is_stm32_lptim_trigger(struct iio_trigger *trig); diff --git a/include/linux/interconnect-provider.h b/include/linux/interconnect-provider.h index f5aef8784692..55cfebc658e6 100644 --- a/include/linux/interconnect-provider.h +++ b/include/linux/interconnect-provider.h @@ -116,8 +116,10 @@ struct icc_node { int icc_std_aggregate(struct icc_node *node, u32 tag, u32 avg_bw, u32 peak_bw, u32 *agg_avg, u32 *agg_peak); +struct icc_node *icc_node_create_dyn(void); struct icc_node *icc_node_create(int id); void icc_node_destroy(int id); +int icc_link_nodes(struct icc_node *src_node, struct icc_node **dst_node); int icc_link_create(struct icc_node *node, const int dst_id); void icc_node_add(struct icc_node *node, struct icc_provider *provider); void icc_node_del(struct icc_node *node); @@ -136,6 +138,11 @@ static inline int icc_std_aggregate(struct icc_node *node, u32 tag, u32 avg_bw, return -ENOTSUPP; } +static inline struct icc_node *icc_node_create_dyn(void) +{ + return ERR_PTR(-EOPNOTSUPP); +} + static inline struct icc_node *icc_node_create(int id) { return ERR_PTR(-ENOTSUPP); @@ -145,6 +152,11 @@ static inline void icc_node_destroy(int id) { } +static inline int icc_link_nodes(struct icc_node *src_node, struct icc_node **dst_node) +{ + return -EOPNOTSUPP; +} + static inline int icc_link_create(struct icc_node *node, const int dst_id) { return -ENOTSUPP; diff --git a/include/linux/interconnect.h b/include/linux/interconnect.h index 97ac253df62c..e4b8808823ad 100644 --- a/include/linux/interconnect.h +++ b/include/linux/interconnect.h @@ -20,6 +20,9 @@ #define Mbps_to_icc(x) ((x) * 1000 / 8) #define Gbps_to_icc(x) ((x) * 1000 * 1000 / 8) +/* macro to indicate dynamic id allocation */ +#define ICC_ALLOC_DYN_ID -1 + struct icc_path; struct device; diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h index ebcee9328168..6077972e8b45 100644 --- a/include/linux/mod_devicetable.h +++ b/include/linux/mod_devicetable.h @@ -340,7 +340,7 @@ struct pcmcia_device_id { #define INPUT_DEVICE_ID_LED_MAX 0x0f #define INPUT_DEVICE_ID_SND_MAX 0x07 #define INPUT_DEVICE_ID_FF_MAX 0x7f -#define INPUT_DEVICE_ID_SW_MAX 0x10 +#define INPUT_DEVICE_ID_SW_MAX 0x11 #define INPUT_DEVICE_ID_PROP_MAX 0x1f #define INPUT_DEVICE_ID_MATCH_BUS 1 diff --git a/include/linux/module.h b/include/linux/module.h index 8050f77c3b64..92e1420fccdf 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -249,8 +249,8 @@ struct module_kobject *lookup_or_create_module_kobject(const char *name); #ifdef MODULE /* Creates an alias so file2alias.c can find device table. */ #define MODULE_DEVICE_TABLE(type, name) \ -extern typeof(name) __mod_device_table__##type##__##name \ - __attribute__ ((unused, alias(__stringify(name)))) +static typeof(name) __mod_device_table__##type##__##name \ + __attribute__ ((used, alias(__stringify(name)))) #else /* !MODULE */ #define MODULE_DEVICE_TABLE(type, name) #endif diff --git a/include/linux/mount.h b/include/linux/mount.h index d3ee0e5162f0..4880f434c021 100644 --- a/include/linux/mount.h +++ b/include/linux/mount.h @@ -65,7 +65,8 @@ enum mount_flags { MNT_ATIME_MASK = MNT_NOATIME | MNT_NODIRATIME | MNT_RELATIME, MNT_INTERNAL_FLAGS = MNT_SHARED | MNT_WRITE_HOLD | MNT_INTERNAL | - MNT_DOOMED | MNT_SYNC_UMOUNT | MNT_MARKED, + MNT_DOOMED | MNT_SYNC_UMOUNT | MNT_MARKED | + MNT_LOCKED, }; struct vfsmount { diff --git a/include/linux/nvme.h b/include/linux/nvme.h index 51308f65b72f..b65a1b9f2116 100644 --- a/include/linux/nvme.h +++ b/include/linux/nvme.h @@ -2171,7 +2171,7 @@ enum { NVME_SC_BAD_ATTRIBUTES = 0x180, NVME_SC_INVALID_PI = 0x181, NVME_SC_READ_ONLY = 0x182, - NVME_SC_ONCS_NOT_SUPPORTED = 0x183, + NVME_SC_CMD_SIZE_LIM_EXCEEDED = 0x183, /* * I/O Command Set Specific - Fabrics commands: diff --git a/include/linux/nvmem-provider.h b/include/linux/nvmem-provider.h index 515676ebe598..615a560d9edb 100644 --- a/include/linux/nvmem-provider.h +++ b/include/linux/nvmem-provider.h @@ -138,25 +138,6 @@ struct nvmem_config { }; /** - * struct nvmem_cell_table - NVMEM cell definitions for given provider - * - * @nvmem_name: Provider name. - * @cells: Array of cell definitions. - * @ncells: Number of cell definitions in the array. - * @node: List node. - * - * This structure together with related helper functions is provided for users - * that don't can't access the nvmem provided structure but wish to register - * cell definitions for it e.g. board files registering an EEPROM device. - */ -struct nvmem_cell_table { - const char *nvmem_name; - const struct nvmem_cell_info *cells; - size_t ncells; - struct list_head node; -}; - -/** * struct nvmem_layout - NVMEM layout definitions * * @dev: Device-model layout device. @@ -190,9 +171,6 @@ void nvmem_unregister(struct nvmem_device *nvmem); struct nvmem_device *devm_nvmem_register(struct device *dev, const struct nvmem_config *cfg); -void nvmem_add_cell_table(struct nvmem_cell_table *table); -void nvmem_del_cell_table(struct nvmem_cell_table *table); - int nvmem_add_one_cell(struct nvmem_device *nvmem, const struct nvmem_cell_info *info); @@ -223,8 +201,6 @@ devm_nvmem_register(struct device *dev, const struct nvmem_config *c) return nvmem_register(c); } -static inline void nvmem_add_cell_table(struct nvmem_cell_table *table) {} -static inline void nvmem_del_cell_table(struct nvmem_cell_table *table) {} static inline int nvmem_add_one_cell(struct nvmem_device *nvmem, const struct nvmem_cell_info *info) { diff --git a/include/linux/property.h b/include/linux/property.h index bc5bfc98176b..f718dd4789e5 100644 --- a/include/linux/property.h +++ b/include/linux/property.h @@ -167,6 +167,10 @@ struct fwnode_handle *fwnode_get_next_available_child_node( for (child = fwnode_get_next_child_node(fwnode, NULL); child; \ child = fwnode_get_next_child_node(fwnode, child)) +#define fwnode_for_each_named_child_node(fwnode, child, name) \ + fwnode_for_each_child_node(fwnode, child) \ + if (!fwnode_name_eq(child, name)) { } else + #define fwnode_for_each_available_child_node(fwnode, child) \ for (child = fwnode_get_next_available_child_node(fwnode, NULL); child;\ child = fwnode_get_next_available_child_node(fwnode, child)) @@ -178,11 +182,19 @@ struct fwnode_handle *device_get_next_child_node(const struct device *dev, for (child = device_get_next_child_node(dev, NULL); child; \ child = device_get_next_child_node(dev, child)) +#define device_for_each_named_child_node(dev, child, name) \ + device_for_each_child_node(dev, child) \ + if (!fwnode_name_eq(child, name)) { } else + #define device_for_each_child_node_scoped(dev, child) \ for (struct fwnode_handle *child __free(fwnode_handle) = \ device_get_next_child_node(dev, NULL); \ child; child = device_get_next_child_node(dev, child)) +#define device_for_each_named_child_node_scoped(dev, child, name) \ + device_for_each_child_node_scoped(dev, child) \ + if (!fwnode_name_eq(child, name)) { } else + struct fwnode_handle *fwnode_get_named_child_node(const struct fwnode_handle *fwnode, const char *childname); struct fwnode_handle *device_get_named_child_node(const struct device *dev, @@ -215,6 +227,14 @@ static inline unsigned int device_get_child_node_count(const struct device *dev) return fwnode_get_child_node_count(dev_fwnode(dev)); } +unsigned int fwnode_get_named_child_node_count(const struct fwnode_handle *fwnode, + const char *name); +static inline unsigned int device_get_named_child_node_count(const struct device *dev, + const char *name) +{ + return fwnode_get_named_child_node_count(dev_fwnode(dev), name); +} + static inline int device_property_read_u8(const struct device *dev, const char *propname, u8 *val) { diff --git a/include/linux/raid/pq.h b/include/linux/raid/pq.h index 98030accf641..72ff44cca864 100644 --- a/include/linux/raid/pq.h +++ b/include/linux/raid/pq.h @@ -108,6 +108,10 @@ extern const struct raid6_calls raid6_vpermxor4; extern const struct raid6_calls raid6_vpermxor8; extern const struct raid6_calls raid6_lsx; extern const struct raid6_calls raid6_lasx; +extern const struct raid6_calls raid6_rvvx1; +extern const struct raid6_calls raid6_rvvx2; +extern const struct raid6_calls raid6_rvvx4; +extern const struct raid6_calls raid6_rvvx8; struct raid6_recov_calls { void (*data2)(int, size_t, int, int, void **); @@ -125,6 +129,7 @@ extern const struct raid6_recov_calls raid6_recov_s390xc; extern const struct raid6_recov_calls raid6_recov_neon; extern const struct raid6_recov_calls raid6_recov_lsx; extern const struct raid6_recov_calls raid6_recov_lasx; +extern const struct raid6_recov_calls raid6_recov_rvv; extern const struct raid6_calls raid6_neonx1; extern const struct raid6_calls raid6_neonx2; diff --git a/include/linux/rtsx_pci.h b/include/linux/rtsx_pci.h index 4612ef09a0c7..3b4c36705a9b 100644 --- a/include/linux/rtsx_pci.h +++ b/include/linux/rtsx_pci.h @@ -1312,8 +1312,6 @@ void rtsx_pci_add_cmd(struct rtsx_pcr *pcr, u8 cmd_type, u16 reg_addr, u8 mask, u8 data); void rtsx_pci_send_cmd_no_wait(struct rtsx_pcr *pcr); int rtsx_pci_send_cmd(struct rtsx_pcr *pcr, int timeout); -int rtsx_pci_transfer_data(struct rtsx_pcr *pcr, struct scatterlist *sglist, - int num_sg, bool read, int timeout); int rtsx_pci_dma_map_sg(struct rtsx_pcr *pcr, struct scatterlist *sglist, int num_sg, bool read); void rtsx_pci_dma_unmap_sg(struct rtsx_pcr *pcr, struct scatterlist *sglist, diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index 743b4afaad4c..914b5e97e056 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -427,6 +427,18 @@ struct uart_icount { typedef u64 __bitwise upf_t; typedef unsigned int __bitwise upstat_t; +enum uart_iotype { + UPIO_UNKNOWN = -1, + UPIO_PORT = SERIAL_IO_PORT, /* 8b I/O port access */ + UPIO_HUB6 = SERIAL_IO_HUB6, /* Hub6 ISA card */ + UPIO_MEM = SERIAL_IO_MEM, /* driver-specific */ + UPIO_MEM32 = SERIAL_IO_MEM32, /* 32b little endian */ + UPIO_AU = SERIAL_IO_AU, /* Au1x00 and RT288x type IO */ + UPIO_TSI = SERIAL_IO_TSI, /* Tsi108/109 type IO */ + UPIO_MEM32BE = SERIAL_IO_MEM32BE, /* 32b big endian */ + UPIO_MEM16 = SERIAL_IO_MEM16, /* 16b little endian */ +}; + struct uart_port { spinlock_t lock; /* port lock */ unsigned long iobase; /* in/out[bwl] */ @@ -469,23 +481,13 @@ struct uart_port { unsigned char x_char; /* xon/xoff char */ unsigned char regshift; /* reg offset shift */ - unsigned char iotype; /* io access style */ - -#define UPIO_UNKNOWN ((unsigned char)~0U) /* UCHAR_MAX */ -#define UPIO_PORT (SERIAL_IO_PORT) /* 8b I/O port access */ -#define UPIO_HUB6 (SERIAL_IO_HUB6) /* Hub6 ISA card */ -#define UPIO_MEM (SERIAL_IO_MEM) /* driver-specific */ -#define UPIO_MEM32 (SERIAL_IO_MEM32) /* 32b little endian */ -#define UPIO_AU (SERIAL_IO_AU) /* Au1x00 and RT288x type IO */ -#define UPIO_TSI (SERIAL_IO_TSI) /* Tsi108/109 type IO */ -#define UPIO_MEM32BE (SERIAL_IO_MEM32BE) /* 32b big endian */ -#define UPIO_MEM16 (SERIAL_IO_MEM16) /* 16b little endian */ - unsigned char quirks; /* internal quirks */ /* internal quirks must be updated while holding port mutex */ #define UPQ_NO_TXEN_TEST BIT(0) + enum uart_iotype iotype; /* io access style */ + unsigned int read_status_mask; /* driver specific */ unsigned int ignore_status_mask; /* driver specific */ struct uart_state *state; /* pointer to parent state */ @@ -1101,8 +1103,8 @@ static inline bool uart_console_registered(struct uart_port *port) struct uart_port *uart_get_console(struct uart_port *ports, int nr, struct console *c); -int uart_parse_earlycon(char *p, unsigned char *iotype, resource_size_t *addr, - char **options); +int uart_parse_earlycon(char *p, enum uart_iotype *iotype, + resource_size_t *addr, char **options); void uart_parse_options(const char *options, int *baud, int *parity, int *bits, int *flow); int uart_set_options(struct uart_port *port, struct console *co, int baud, diff --git a/include/linux/thunderbolt.h b/include/linux/thunderbolt.h index 7d902d8c054b..75247486616b 100644 --- a/include/linux/thunderbolt.h +++ b/include/linux/thunderbolt.h @@ -11,6 +11,13 @@ #ifndef THUNDERBOLT_H_ #define THUNDERBOLT_H_ +#include <linux/types.h> + +struct fwnode_handle; +struct device; + +#if IS_REACHABLE(CONFIG_USB4) + #include <linux/device.h> #include <linux/idr.h> #include <linux/list.h> @@ -674,4 +681,15 @@ static inline struct device *tb_ring_dma_device(struct tb_ring *ring) return &ring->nhi->pdev->dev; } +bool usb4_usb3_port_match(struct device *usb4_port_dev, + const struct fwnode_handle *usb3_port_fwnode); + +#else /* CONFIG_USB4 */ +static inline bool usb4_usb3_port_match(struct device *usb4_port_dev, + const struct fwnode_handle *usb3_port_fwnode) +{ + return false; +} +#endif /* CONFIG_USB4 */ + #endif /* THUNDERBOLT_H_ */ diff --git a/include/linux/time_namespace.h b/include/linux/time_namespace.h index 0b8b32bf0655..bb2c52f4fc94 100644 --- a/include/linux/time_namespace.h +++ b/include/linux/time_namespace.h @@ -12,6 +12,7 @@ struct user_namespace; extern struct user_namespace init_user_ns; +struct seq_file; struct vm_area_struct; struct timens_offsets { diff --git a/include/linux/timer.h b/include/linux/timer.h index f636f55c427d..0414d9e6b4fc 100644 --- a/include/linux/timer.h +++ b/include/linux/timer.h @@ -129,7 +129,7 @@ extern void timer_destroy_on_stack(struct timer_list *timer); static inline void timer_destroy_on_stack(struct timer_list *timer) { } #endif -#define from_timer(var, callback_timer, timer_fieldname) \ +#define timer_container_of(var, callback_timer, timer_fieldname) \ container_of(callback_timer, typeof(*var), timer_fieldname) /** diff --git a/include/linux/tty_port.h b/include/linux/tty_port.h index 1b861f2100b6..08f89a598366 100644 --- a/include/linux/tty_port.h +++ b/include/linux/tty_port.h @@ -147,9 +147,6 @@ struct device *tty_port_register_device_attr(struct tty_port *port, struct tty_driver *driver, unsigned index, struct device *device, void *drvdata, const struct attribute_group **attr_grp); -struct device *tty_port_register_device_serdev(struct tty_port *port, - struct tty_driver *driver, unsigned index, - struct device *host, struct device *parent); struct device *tty_port_register_device_attr_serdev(struct tty_port *port, struct tty_driver *driver, unsigned index, struct device *host, struct device *parent, void *drvdata, diff --git a/include/linux/usb.h b/include/linux/usb.h index b46738701f8d..1b2545b4363b 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -815,10 +815,10 @@ static inline void usb_mark_last_busy(struct usb_device *udev) #else -static inline int usb_enable_autosuspend(struct usb_device *udev) -{ return 0; } -static inline int usb_disable_autosuspend(struct usb_device *udev) -{ return 0; } +static inline void usb_enable_autosuspend(struct usb_device *udev) +{ } +static inline void usb_disable_autosuspend(struct usb_device *udev) +{ } static inline int usb_autopm_get_interface(struct usb_interface *intf) { return 0; } diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h index 6e38fb9d2117..d8c4e9f73839 100644 --- a/include/linux/usb/composite.h +++ b/include/linux/usb/composite.h @@ -237,7 +237,7 @@ struct usb_function { /* internals */ struct list_head list; DECLARE_BITMAP(endpoints, 32); - const struct usb_function_instance *fi; + struct usb_function_instance *fi; unsigned int bind_deactivated:1; }; diff --git a/include/linux/usb/xhci-sideband.h b/include/linux/usb/xhci-sideband.h new file mode 100644 index 000000000000..45288c392f6e --- /dev/null +++ b/include/linux/usb/xhci-sideband.h @@ -0,0 +1,102 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * xHCI host controller sideband support + * + * Copyright (c) 2023-2025, Intel Corporation. + * + * Author: Mathias Nyman <mathias.nyman@linux.intel.com> + */ +#ifndef __LINUX_XHCI_SIDEBAND_H +#define __LINUX_XHCI_SIDEBAND_H + +#include <linux/scatterlist.h> +#include <linux/usb.h> + +#define EP_CTX_PER_DEV 31 /* FIXME defined twice, from xhci.h */ + +struct xhci_sideband; + +enum xhci_sideband_type { + XHCI_SIDEBAND_AUDIO, + XHCI_SIDEBAND_VENDOR, +}; + +enum xhci_sideband_notify_type { + XHCI_SIDEBAND_XFER_RING_FREE, +}; + +/** + * struct xhci_sideband_event - sideband event + * @type: notifier type + * @evt_data: event data + */ +struct xhci_sideband_event { + enum xhci_sideband_notify_type type; + void *evt_data; +}; + +/** + * struct xhci_sideband - representation of a sideband accessed usb device. + * @xhci: The xhci host controller the usb device is connected to + * @vdev: the usb device accessed via sideband + * @eps: array of endpoints controlled via sideband + * @ir: event handling and buffer for sideband accessed device + * @type: xHCI sideband type + * @mutex: mutex for sideband operations + * @intf: USB sideband client interface + * @notify_client: callback for xHCI sideband sequences + * + * FIXME usb device accessed via sideband Keeping track of sideband accessed usb devices. + */ +struct xhci_sideband { + struct xhci_hcd *xhci; + struct xhci_virt_device *vdev; + struct xhci_virt_ep *eps[EP_CTX_PER_DEV]; + struct xhci_interrupter *ir; + enum xhci_sideband_type type; + + /* Synchronizing xHCI sideband operations with client drivers operations */ + struct mutex mutex; + + struct usb_interface *intf; + int (*notify_client)(struct usb_interface *intf, + struct xhci_sideband_event *evt); +}; + +struct xhci_sideband * +xhci_sideband_register(struct usb_interface *intf, enum xhci_sideband_type type, + int (*notify_client)(struct usb_interface *intf, + struct xhci_sideband_event *evt)); +void +xhci_sideband_unregister(struct xhci_sideband *sb); +int +xhci_sideband_add_endpoint(struct xhci_sideband *sb, + struct usb_host_endpoint *host_ep); +int +xhci_sideband_remove_endpoint(struct xhci_sideband *sb, + struct usb_host_endpoint *host_ep); +int +xhci_sideband_stop_endpoint(struct xhci_sideband *sb, + struct usb_host_endpoint *host_ep); +struct sg_table * +xhci_sideband_get_endpoint_buffer(struct xhci_sideband *sb, + struct usb_host_endpoint *host_ep); +struct sg_table * +xhci_sideband_get_event_buffer(struct xhci_sideband *sb); +int +xhci_sideband_create_interrupter(struct xhci_sideband *sb, int num_seg, + bool ip_autoclear, u32 imod_interval, int intr_num); +void +xhci_sideband_remove_interrupter(struct xhci_sideband *sb); +int +xhci_sideband_interrupter_id(struct xhci_sideband *sb); + +#if IS_ENABLED(CONFIG_USB_XHCI_SIDEBAND) +void xhci_sideband_notify_ep_ring_free(struct xhci_sideband *sb, + unsigned int ep_index); +#else +static inline void xhci_sideband_notify_ep_ring_free(struct xhci_sideband *sb, + unsigned int ep_index) +{ } +#endif /* IS_ENABLED(CONFIG_USB_XHCI_SIDEBAND) */ +#endif /* __LINUX_XHCI_SIDEBAND_H */ diff --git a/include/sound/jack.h b/include/sound/jack.h index 36dc104c1145..715b95983188 100644 --- a/include/sound/jack.h +++ b/include/sound/jack.h @@ -22,6 +22,7 @@ struct input_dev; * @SND_JACK_VIDEOOUT: Video out * @SND_JACK_AVOUT: AV (Audio Video) out * @SND_JACK_LINEIN: Line in + * @SND_JACK_USB: USB audio device * @SND_JACK_BTN_0: Button 0 * @SND_JACK_BTN_1: Button 1 * @SND_JACK_BTN_2: Button 2 @@ -43,6 +44,7 @@ enum snd_jack_types { SND_JACK_VIDEOOUT = 0x0010, SND_JACK_AVOUT = SND_JACK_LINEOUT | SND_JACK_VIDEOOUT, SND_JACK_LINEIN = 0x0020, + SND_JACK_USB = 0x0040, /* Kept separate from switches to facilitate implementation */ SND_JACK_BTN_0 = 0x4000, @@ -54,7 +56,7 @@ enum snd_jack_types { }; /* Keep in sync with definitions above */ -#define SND_JACK_SWITCH_TYPES 6 +#define SND_JACK_SWITCH_TYPES 7 struct snd_jack { struct list_head kctl_list; diff --git a/include/sound/q6usboffload.h b/include/sound/q6usboffload.h new file mode 100644 index 000000000000..f7e2449fe1b3 --- /dev/null +++ b/include/sound/q6usboffload.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * sound/q6usboffload.h -- QDSP6 USB offload + * + * Copyright (c) 2022-2025 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +/** + * struct q6usb_offload - USB backend DAI link offload parameters + * @dev: dev handle to usb be + * @domain: allocated iommu domain + * @intr_num: usb interrupter number + * @sid: streamID for iommu + **/ +struct q6usb_offload { + struct device *dev; + struct iommu_domain *domain; + u16 intr_num; + u8 sid; +}; diff --git a/include/sound/soc-usb.h b/include/sound/soc-usb.h new file mode 100644 index 000000000000..124acb1939e5 --- /dev/null +++ b/include/sound/soc-usb.h @@ -0,0 +1,138 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright (c) 2022-2025 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef __LINUX_SND_SOC_USB_H +#define __LINUX_SND_SOC_USB_H + +#include <sound/soc.h> + +enum snd_soc_usb_kctl { + SND_SOC_USB_KCTL_CARD_ROUTE, + SND_SOC_USB_KCTL_PCM_ROUTE, +}; + +/** + * struct snd_soc_usb_device - SoC USB representation of a USB sound device + * @card_idx: sound card index associated with USB device + * @chip_idx: USB sound chip array index + * @cpcm_idx: capture PCM index array associated with USB device + * @ppcm_idx: playback PCM index array associated with USB device + * @num_capture: number of capture streams + * @num_playback: number of playback streams + * @list: list head for SoC USB devices + **/ +struct snd_soc_usb_device { + int card_idx; + int chip_idx; + + /* PCM index arrays */ + unsigned int *cpcm_idx; /* TODO: capture path is not tested yet */ + unsigned int *ppcm_idx; + int num_capture; /* TODO: capture path is not tested yet */ + int num_playback; + + struct list_head list; +}; + +/** + * struct snd_soc_usb - representation of a SoC USB backend entity + * @list: list head for SND SOC struct list + * @component: reference to ASoC component + * @connection_status_cb: callback to notify connection events + * @update_offload_route_info: callback to fetch mapped ASoC card and pcm + * device pair. This is unrelated to the concept + * of DAPM route. The "route" argument carries + * an array used for a kcontrol output for either + * the card or pcm index. "path" determines the + * which entry to look for. (ie mapped card or pcm) + * @priv_data: driver data + **/ +struct snd_soc_usb { + struct list_head list; + struct snd_soc_component *component; + int (*connection_status_cb)(struct snd_soc_usb *usb, + struct snd_soc_usb_device *sdev, + bool connected); + int (*update_offload_route_info)(struct snd_soc_component *component, + int card, int pcm, int direction, + enum snd_soc_usb_kctl path, + long *route); + void *priv_data; +}; + +#if IS_ENABLED(CONFIG_SND_SOC_USB) +int snd_soc_usb_find_supported_format(int card_idx, + struct snd_pcm_hw_params *params, + int direction); + +int snd_soc_usb_connect(struct device *usbdev, struct snd_soc_usb_device *sdev); +int snd_soc_usb_disconnect(struct device *usbdev, struct snd_soc_usb_device *sdev); +void *snd_soc_usb_find_priv_data(struct device *usbdev); + +int snd_soc_usb_setup_offload_jack(struct snd_soc_component *component, + struct snd_soc_jack *jack); +int snd_soc_usb_update_offload_route(struct device *dev, int card, int pcm, + int direction, enum snd_soc_usb_kctl path, + long *route); + +struct snd_soc_usb *snd_soc_usb_allocate_port(struct snd_soc_component *component, + void *data); +void snd_soc_usb_free_port(struct snd_soc_usb *usb); +void snd_soc_usb_add_port(struct snd_soc_usb *usb); +void snd_soc_usb_remove_port(struct snd_soc_usb *usb); +#else +static inline int +snd_soc_usb_find_supported_format(int card_idx, struct snd_pcm_hw_params *params, + int direction) +{ + return -EINVAL; +} + +static inline int snd_soc_usb_connect(struct device *usbdev, + struct snd_soc_usb_device *sdev) +{ + return -ENODEV; +} + +static inline int snd_soc_usb_disconnect(struct device *usbdev, + struct snd_soc_usb_device *sdev) +{ + return -EINVAL; +} + +static inline void *snd_soc_usb_find_priv_data(struct device *usbdev) +{ + return NULL; +} + +static inline int snd_soc_usb_setup_offload_jack(struct snd_soc_component *component, + struct snd_soc_jack *jack) +{ + return 0; +} + +static int snd_soc_usb_update_offload_route(struct device *dev, int card, int pcm, + int direction, enum snd_soc_usb_kctl path, + long *route) +{ + return -ENODEV; +} + +static inline struct snd_soc_usb * +snd_soc_usb_allocate_port(struct snd_soc_component *component, void *data) +{ + return ERR_PTR(-ENOMEM); +} + +static inline void snd_soc_usb_free_port(struct snd_soc_usb *usb) +{ } + +static inline void snd_soc_usb_add_port(struct snd_soc_usb *usb) +{ } + +static inline void snd_soc_usb_remove_port(struct snd_soc_usb *usb) +{ } +#endif /* IS_ENABLED(CONFIG_SND_SOC_USB) */ +#endif /*__LINUX_SND_SOC_USB_H */ diff --git a/include/trace/events/power.h b/include/trace/events/power.h index 9253e83b9bb4..6c631eec23e3 100644 --- a/include/trace/events/power.h +++ b/include/trace/events/power.h @@ -338,53 +338,6 @@ DEFINE_EVENT(wakeup_source, wakeup_source_deactivate, ); /* - * The clock events are used for clock enable/disable and for - * clock rate change - */ -DECLARE_EVENT_CLASS(clock, - - TP_PROTO(const char *name, unsigned int state, unsigned int cpu_id), - - TP_ARGS(name, state, cpu_id), - - TP_STRUCT__entry( - __string( name, name ) - __field( u64, state ) - __field( u64, cpu_id ) - ), - - TP_fast_assign( - __assign_str(name); - __entry->state = state; - __entry->cpu_id = cpu_id; - ), - - TP_printk("%s state=%lu cpu_id=%lu", __get_str(name), - (unsigned long)__entry->state, (unsigned long)__entry->cpu_id) -); - -DEFINE_EVENT(clock, clock_enable, - - TP_PROTO(const char *name, unsigned int state, unsigned int cpu_id), - - TP_ARGS(name, state, cpu_id) -); - -DEFINE_EVENT(clock, clock_disable, - - TP_PROTO(const char *name, unsigned int state, unsigned int cpu_id), - - TP_ARGS(name, state, cpu_id) -); - -DEFINE_EVENT(clock, clock_set_rate, - - TP_PROTO(const char *name, unsigned int state, unsigned int cpu_id), - - TP_ARGS(name, state, cpu_id) -); - -/* * The power domain events are used for power domains transitions */ DECLARE_EVENT_CLASS(power_domain, diff --git a/include/uapi/drm/xe_drm.h b/include/uapi/drm/xe_drm.h index 9c08738c3b91..6a702ba7817c 100644 --- a/include/uapi/drm/xe_drm.h +++ b/include/uapi/drm/xe_drm.h @@ -1210,6 +1210,11 @@ struct drm_xe_vm_bind { * there is no need to explicitly set that. When a queue of type * %DRM_XE_PXP_TYPE_HWDRM is created, the PXP default HWDRM session * (%XE_PXP_HWDRM_DEFAULT_SESSION) will be started, if isn't already running. + * The user is expected to query the PXP status via the query ioctl (see + * %DRM_XE_DEVICE_QUERY_PXP_STATUS) and to wait for PXP to be ready before + * attempting to create a queue with this property. When a queue is created + * before PXP is ready, the ioctl will return -EBUSY if init is still in + * progress or -EIO if init failed. * Given that going into a power-saving state kills PXP HWDRM sessions, * runtime PM will be blocked while queues of this type are alive. * All PXP queues will be killed if a PXP invalidation event occurs. diff --git a/include/uapi/linux/input-event-codes.h b/include/uapi/linux/input-event-codes.h index 5a199f3d4a26..3b2524e4b667 100644 --- a/include/uapi/linux/input-event-codes.h +++ b/include/uapi/linux/input-event-codes.h @@ -925,7 +925,8 @@ #define SW_MUTE_DEVICE 0x0e /* set = device disabled */ #define SW_PEN_INSERTED 0x0f /* set = pen inserted */ #define SW_MACHINE_COVER 0x10 /* set = cover closed */ -#define SW_MAX 0x10 +#define SW_USB_INSERT 0x11 /* set = USB audio device connected */ +#define SW_MAX 0x11 #define SW_CNT (SW_MAX+1) /* diff --git a/include/uapi/linux/tiocl.h b/include/uapi/linux/tiocl.h index b32acc229024..88faba506c3d 100644 --- a/include/uapi/linux/tiocl.h +++ b/include/uapi/linux/tiocl.h @@ -36,5 +36,6 @@ struct tiocl_selection { #define TIOCL_BLANKSCREEN 14 /* keep screen blank even if a key is pressed */ #define TIOCL_BLANKEDSCREEN 15 /* return which vt was blanked */ #define TIOCL_GETKMSGREDIRECT 17 /* get the vt the kernel messages are restricted to */ +#define TIOCL_GETBRACKETEDPASTE 18 /* get whether paste may be bracketed */ #endif /* _LINUX_TIOCL_H */ diff --git a/include/uapi/linux/ublk_cmd.h b/include/uapi/linux/ublk_cmd.h index 56c7e3fc666f..77d9d6af46da 100644 --- a/include/uapi/linux/ublk_cmd.h +++ b/include/uapi/linux/ublk_cmd.h @@ -272,6 +272,15 @@ */ #define UBLK_F_QUIESCE (1ULL << 12) +/* + * If this feature is set, ublk_drv supports each (qid,tag) pair having + * its own independent daemon task that is responsible for handling it. + * If it is not set, daemons are per-queue instead, so for two pairs + * (qid1,tag1) and (qid2,tag2), if qid1 == qid2, then the same task must + * be responsible for handling (qid1,tag1) and (qid2,tag2). + */ +#define UBLK_F_PER_IO_DAEMON (1ULL << 13) + /* device state */ #define UBLK_S_DEV_DEAD 0 #define UBLK_S_DEV_LIVE 1 diff --git a/include/uapi/linux/vt.h b/include/uapi/linux/vt.h index e9d39c48520a..e5b0c492aa18 100644 --- a/include/uapi/linux/vt.h +++ b/include/uapi/linux/vt.h @@ -2,6 +2,8 @@ #ifndef _UAPI_LINUX_VT_H #define _UAPI_LINUX_VT_H +#include <linux/ioctl.h> +#include <linux/types.h> /* * These constants are also useful for user-level apps (e.g., VC @@ -84,4 +86,13 @@ struct vt_setactivate { #define VT_SETACTIVATE 0x560F /* Activate and set the mode of a console */ +/* get console size and cursor position */ +struct vt_consizecsrpos { + __u16 con_rows; /* number of console rows */ + __u16 con_cols; /* number of console columns */ + __u16 csr_row; /* current cursor's row */ + __u16 csr_col; /* current cursor's column */ +}; +#define VT_GETCONSIZECSRPOS _IOR('V', 0x10, struct vt_consizecsrpos) + #endif /* _UAPI_LINUX_VT_H */ diff --git a/include/uapi/misc/amd-apml.h b/include/uapi/misc/amd-apml.h new file mode 100644 index 000000000000..745b3338fc06 --- /dev/null +++ b/include/uapi/misc/amd-apml.h @@ -0,0 +1,152 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* + * Copyright (C) 2021-2024 Advanced Micro Devices, Inc. + */ +#ifndef _AMD_APML_H_ +#define _AMD_APML_H_ + +#include <linux/types.h> + +/* Mailbox data size for data_in and data_out */ +#define AMD_SBI_MB_DATA_SIZE 4 + +struct apml_mbox_msg { + /* + * Mailbox Message ID + */ + __u32 cmd; + /* + * [0]...[3] mailbox 32bit input/output data + */ + __u32 mb_in_out; + /* + * Error code is returned in case of soft mailbox error + */ + __u32 fw_ret_code; +}; + +struct apml_cpuid_msg { + /* + * CPUID input + * [0]...[3] cpuid func, + * [4][5] cpuid: thread + * [6] cpuid: ext function & read eax/ebx or ecx/edx + * [7:0] -> bits [7:4] -> ext function & + * bit [0] read eax/ebx or ecx/edx + * CPUID output + */ + __u64 cpu_in_out; + /* + * Status code for CPUID read + */ + __u32 fw_ret_code; + __u32 pad; +}; + +struct apml_mcamsr_msg { + /* + * MCAMSR input + * [0]...[3] mca msr func, + * [4][5] thread + * MCAMSR output + */ + __u64 mcamsr_in_out; + /* + * Status code for MCA/MSR access + */ + __u32 fw_ret_code; + __u32 pad; +}; + +struct apml_reg_xfer_msg { + /* + * RMI register address offset + */ + __u16 reg_addr; + /* + * Register data for read/write + */ + __u8 data_in_out; + /* + * Register read or write + */ + __u8 rflag; +}; + +/* + * AMD sideband interface base IOCTL + */ +#define SB_BASE_IOCTL_NR 0xF9 + +/** + * DOC: SBRMI_IOCTL_MBOX_CMD + * + * @Parameters + * + * @struct apml_mbox_msg + * Pointer to the &struct apml_mbox_msg that will contain the protocol + * information + * + * @Description + * IOCTL command for APML messages using generic _IOWR + * The IOCTL provides userspace access to AMD sideband mailbox protocol + * - Mailbox message read/write(0x0~0xFF) + * - returning "-EFAULT" if none of the above + * "-EPROTOTYPE" error is returned to provide additional error details + */ +#define SBRMI_IOCTL_MBOX_CMD _IOWR(SB_BASE_IOCTL_NR, 0, struct apml_mbox_msg) + +/** + * DOC: SBRMI_IOCTL_CPUID_CMD + * + * @Parameters + * + * @struct apml_cpuid_msg + * Pointer to the &struct apml_cpuid_msg that will contain the protocol + * information + * + * @Description + * IOCTL command for APML messages using generic _IOWR + * The IOCTL provides userspace access to AMD sideband cpuid protocol + * - CPUID protocol to get CPU details for Function/Ext Function + * at thread level + * - returning "-EFAULT" if none of the above + * "-EPROTOTYPE" error is returned to provide additional error details + */ +#define SBRMI_IOCTL_CPUID_CMD _IOWR(SB_BASE_IOCTL_NR, 1, struct apml_cpuid_msg) + +/** + * DOC: SBRMI_IOCTL_MCAMSR_CMD + * + * @Parameters + * + * @struct apml_mcamsr_msg + * Pointer to the &struct apml_mcamsr_msg that will contain the protocol + * information + * + * @Description + * IOCTL command for APML messages using generic _IOWR + * The IOCTL provides userspace access to AMD sideband MCAMSR protocol + * - MCAMSR protocol to get MCA bank details for Function at thread level + * - returning "-EFAULT" if none of the above + * "-EPROTOTYPE" error is returned to provide additional error details + */ +#define SBRMI_IOCTL_MCAMSR_CMD _IOWR(SB_BASE_IOCTL_NR, 2, struct apml_mcamsr_msg) + +/** + * DOC: SBRMI_IOCTL_REG_XFER_CMD + * + * @Parameters + * + * @struct apml_reg_xfer_msg + * Pointer to the &struct apml_reg_xfer_msg that will contain the protocol + * information + * + * @Description + * IOCTL command for APML messages using generic _IOWR + * The IOCTL provides userspace access to AMD sideband register xfer protocol + * - Register xfer protocol to get/set hardware register for given offset + */ +#define SBRMI_IOCTL_REG_XFER_CMD _IOWR(SB_BASE_IOCTL_NR, 3, struct apml_reg_xfer_msg) + +#endif /*_AMD_APML_H_*/ diff --git a/io_uring/futex.c b/io_uring/futex.c index fa374afbaa51..692462d50c8c 100644 --- a/io_uring/futex.c +++ b/io_uring/futex.c @@ -14,10 +14,7 @@ struct io_futex { struct file *file; - union { - u32 __user *uaddr; - struct futex_waitv __user *uwaitv; - }; + void __user *uaddr; unsigned long futex_val; unsigned long futex_mask; unsigned long futexv_owned; @@ -148,6 +145,8 @@ int io_futex_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe) !futex_validate_input(iof->futex_flags, iof->futex_mask)) return -EINVAL; + /* Mark as inflight, so file exit cancelation will find it */ + io_req_track_inflight(req); return 0; } @@ -186,13 +185,15 @@ int io_futexv_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe) if (!futexv) return -ENOMEM; - ret = futex_parse_waitv(futexv, iof->uwaitv, iof->futex_nr, + ret = futex_parse_waitv(futexv, iof->uaddr, iof->futex_nr, io_futex_wakev_fn, req); if (ret) { kfree(futexv); return ret; } + /* Mark as inflight, so file exit cancelation will find it */ + io_req_track_inflight(req); iof->futexv_owned = 0; iof->futexv_unqueued = 0; req->flags |= REQ_F_ASYNC_DATA; diff --git a/io_uring/io_uring.c b/io_uring/io_uring.c index c7a9cecf528e..cf759c172083 100644 --- a/io_uring/io_uring.c +++ b/io_uring/io_uring.c @@ -408,7 +408,12 @@ static void io_clean_op(struct io_kiocb *req) req->flags &= ~IO_REQ_CLEAN_FLAGS; } -static inline void io_req_track_inflight(struct io_kiocb *req) +/* + * Mark the request as inflight, so that file cancelation will find it. + * Can be used if the file is an io_uring instance, or if the request itself + * relies on ->mm being alive for the duration of the request. + */ +inline void io_req_track_inflight(struct io_kiocb *req) { if (!(req->flags & REQ_F_INFLIGHT)) { req->flags |= REQ_F_INFLIGHT; diff --git a/io_uring/io_uring.h b/io_uring/io_uring.h index 0ea7a435d1de..d59c12277d58 100644 --- a/io_uring/io_uring.h +++ b/io_uring/io_uring.h @@ -83,6 +83,7 @@ void io_add_aux_cqe(struct io_ring_ctx *ctx, u64 user_data, s32 res, u32 cflags) bool io_req_post_cqe(struct io_kiocb *req, s32 res, u32 cflags); void __io_commit_cqring_flush(struct io_ring_ctx *ctx); +void io_req_track_inflight(struct io_kiocb *req); struct file *io_file_get_normal(struct io_kiocb *req, int fd); struct file *io_file_get_fixed(struct io_kiocb *req, int fd, unsigned issue_flags); diff --git a/io_uring/kbuf.c b/io_uring/kbuf.c index 8cce3ebd813f..2ea65f3cef72 100644 --- a/io_uring/kbuf.c +++ b/io_uring/kbuf.c @@ -108,6 +108,7 @@ bool io_kbuf_recycle_legacy(struct io_kiocb *req, unsigned issue_flags) buf = req->kbuf; bl = io_buffer_get_list(ctx, buf->bgid); list_add(&buf->list, &bl->buf_list); + bl->nbufs++; req->flags &= ~REQ_F_BUFFER_SELECTED; io_ring_submit_unlock(ctx, issue_flags); @@ -122,6 +123,7 @@ static void __user *io_provided_buffer_select(struct io_kiocb *req, size_t *len, kbuf = list_first_entry(&bl->buf_list, struct io_buffer, list); list_del(&kbuf->list); + bl->nbufs--; if (*len == 0 || *len > kbuf->len) *len = kbuf->len; if (list_empty(&bl->buf_list)) @@ -390,6 +392,7 @@ static int io_remove_buffers_legacy(struct io_ring_ctx *ctx, for (i = 0; i < nbufs && !list_empty(&bl->buf_list); i++) { nxt = list_first_entry(&bl->buf_list, struct io_buffer, list); list_del(&nxt->list); + bl->nbufs--; kfree(nxt); cond_resched(); } @@ -491,14 +494,24 @@ static int io_add_buffers(struct io_ring_ctx *ctx, struct io_provide_buf *pbuf, { struct io_buffer *buf; u64 addr = pbuf->addr; - int i, bid = pbuf->bid; + int ret = -ENOMEM, i, bid = pbuf->bid; for (i = 0; i < pbuf->nbufs; i++) { + /* + * Nonsensical to have more than sizeof(bid) buffers in a + * buffer list, as the application then has no way of knowing + * which duplicate bid refers to what buffer. + */ + if (bl->nbufs == USHRT_MAX) { + ret = -EOVERFLOW; + break; + } buf = kmalloc(sizeof(*buf), GFP_KERNEL_ACCOUNT); if (!buf) break; list_add_tail(&buf->list, &bl->buf_list); + bl->nbufs++; buf->addr = addr; buf->len = min_t(__u32, pbuf->len, MAX_RW_COUNT); buf->bid = bid; @@ -508,7 +521,7 @@ static int io_add_buffers(struct io_ring_ctx *ctx, struct io_provide_buf *pbuf, cond_resched(); } - return i ? 0 : -ENOMEM; + return i ? 0 : ret; } static int __io_manage_buffers_legacy(struct io_kiocb *req, diff --git a/io_uring/kbuf.h b/io_uring/kbuf.h index 4d2c209d1a41..5d83c7adc739 100644 --- a/io_uring/kbuf.h +++ b/io_uring/kbuf.h @@ -21,6 +21,9 @@ struct io_buffer_list { struct list_head buf_list; struct io_uring_buf_ring *buf_ring; }; + /* count of classic/legacy buffers in buffer list */ + int nbufs; + __u16 bgid; /* below is for ring provided buffers */ diff --git a/io_uring/net.c b/io_uring/net.c index d13f3e8f6c72..e16633fd6630 100644 --- a/io_uring/net.c +++ b/io_uring/net.c @@ -832,7 +832,7 @@ static inline bool io_recv_finish(struct io_kiocb *req, int *ret, * If more is available AND it was a full transfer, retry and * append to this one */ - if (!sr->retry && kmsg->msg.msg_inq > 0 && this_ret > 0 && + if (!sr->retry && kmsg->msg.msg_inq > 1 && this_ret > 0 && !iov_iter_count(&kmsg->msg.msg_iter)) { req->cqe.flags = cflags & ~CQE_F_MASK; sr->len = kmsg->msg.msg_inq; @@ -1070,7 +1070,7 @@ static int io_recv_buf_select(struct io_kiocb *req, struct io_async_msghdr *kmsg arg.mode |= KBUF_MODE_FREE; } - if (kmsg->msg.msg_inq > 0) + if (kmsg->msg.msg_inq > 1) arg.max_len = min_not_zero(sr->len, kmsg->msg.msg_inq); ret = io_buffers_peek(req, &arg); diff --git a/io_uring/zcrx.c b/io_uring/zcrx.c index 1513431587a7..797247a34cb7 100644 --- a/io_uring/zcrx.c +++ b/io_uring/zcrx.c @@ -366,7 +366,8 @@ static void io_free_rbuf_ring(struct io_zcrx_ifq *ifq) static void io_zcrx_free_area(struct io_zcrx_area *area) { - io_zcrx_unmap_area(area->ifq, area); + if (area->ifq) + io_zcrx_unmap_area(area->ifq, area); io_release_area_mem(&area->mem); kvfree(area->freelist); @@ -631,12 +632,13 @@ ifq_free: void io_unregister_zcrx_ifqs(struct io_ring_ctx *ctx) { struct io_zcrx_ifq *ifq; - unsigned long id; lockdep_assert_held(&ctx->uring_lock); while (1) { scoped_guard(mutex, &ctx->mmap_lock) { + unsigned long id = 0; + ifq = xa_find(&ctx->zcrx_ctxs, &id, ULONG_MAX, XA_PRESENT); if (ifq) xa_erase(&ctx->zcrx_ctxs, id); diff --git a/kernel/configs/tiny.config b/kernel/configs/tiny.config index b753695c5a8f..5dd0f0a34a73 100644 --- a/kernel/configs/tiny.config +++ b/kernel/configs/tiny.config @@ -2,3 +2,4 @@ CONFIG_CC_OPTIMIZE_FOR_SIZE=y CONFIG_KERNEL_XZ=y CONFIG_SLUB=y CONFIG_SLUB_TINY=y +CONFIG_LD_DEAD_CODE_DATA_ELIMINATION=y diff --git a/kernel/kthread.c b/kernel/kthread.c index 77c44924cf54..85fc068f0083 100644 --- a/kernel/kthread.c +++ b/kernel/kthread.c @@ -1207,7 +1207,8 @@ EXPORT_SYMBOL_GPL(kthread_queue_work); */ void kthread_delayed_work_timer_fn(struct timer_list *t) { - struct kthread_delayed_work *dwork = from_timer(dwork, t, timer); + struct kthread_delayed_work *dwork = timer_container_of(dwork, t, + timer); struct kthread_work *work = &dwork->work; struct kthread_worker *worker = work->worker; unsigned long flags; diff --git a/kernel/module/main.c b/kernel/module/main.c index 3d64e69cc03e..413ac6ea3702 100644 --- a/kernel/module/main.c +++ b/kernel/module/main.c @@ -170,6 +170,30 @@ static inline void add_taint_module(struct module *mod, unsigned flag, } /* + * Like strncmp(), except s/-/_/g as per scripts/Makefile.lib:name-fix-token rule. + */ +static int mod_strncmp(const char *str_a, const char *str_b, size_t n) +{ + for (int i = 0; i < n; i++) { + char a = str_a[i]; + char b = str_b[i]; + int d; + + if (a == '-') a = '_'; + if (b == '-') b = '_'; + + d = a - b; + if (d) + return d; + + if (!a) + break; + } + + return 0; +} + +/* * A thread that wants to hold a reference to a module only while it * is running can call this to safely exit. */ @@ -1083,6 +1107,46 @@ static char *get_modinfo(const struct load_info *info, const char *tag) return get_next_modinfo(info, tag, NULL); } +/** + * verify_module_namespace() - does @modname have access to this symbol's @namespace + * @namespace: export symbol namespace + * @modname: module name + * + * If @namespace is prefixed with "module:" to indicate it is a module namespace + * then test if @modname matches any of the comma separated patterns. + * + * The patterns only support tail-glob. + */ +static bool verify_module_namespace(const char *namespace, const char *modname) +{ + size_t len, modlen = strlen(modname); + const char *prefix = "module:"; + const char *sep; + bool glob; + + if (!strstarts(namespace, prefix)) + return false; + + for (namespace += strlen(prefix); *namespace; namespace = sep) { + sep = strchrnul(namespace, ','); + len = sep - namespace; + + glob = false; + if (sep[-1] == '*') { + len--; + glob = true; + } + + if (*sep) + sep++; + + if (mod_strncmp(namespace, modname, len) == 0 && (glob || len == modlen)) + return true; + } + + return false; +} + static int verify_namespace_is_imported(const struct load_info *info, const struct kernel_symbol *sym, struct module *mod) @@ -1092,6 +1156,10 @@ static int verify_namespace_is_imported(const struct load_info *info, namespace = kernel_symbol_namespace(sym); if (namespace && namespace[0]) { + + if (verify_module_namespace(namespace, mod->name)) + return 0; + for_each_modinfo_entry(imported_namespace, info, "import_ns") { if (strcmp(namespace, imported_namespace) == 0) return 0; @@ -1658,15 +1726,30 @@ static void module_license_taint_check(struct module *mod, const char *license) } } -static void setup_modinfo(struct module *mod, struct load_info *info) +static int setup_modinfo(struct module *mod, struct load_info *info) { const struct module_attribute *attr; + char *imported_namespace; int i; for (i = 0; (attr = modinfo_attrs[i]); i++) { if (attr->setup) attr->setup(mod, get_modinfo(info, attr->attr.name)); } + + for_each_modinfo_entry(imported_namespace, info, "import_ns") { + /* + * 'module:' prefixed namespaces are implicit, disallow + * explicit imports. + */ + if (strstarts(imported_namespace, "module:")) { + pr_err("%s: module tries to import module namespace: %s\n", + mod->name, imported_namespace); + return -EPERM; + } + } + + return 0; } static void free_modinfo(struct module *mod) @@ -3323,7 +3406,9 @@ static int load_module(struct load_info *info, const char __user *uargs, goto free_unload; /* Set up MODINFO_ATTR fields */ - setup_modinfo(mod, info); + err = setup_modinfo(mod, info); + if (err) + goto free_modinfo; /* Fix up syms, so that st_value is a pointer to location. */ err = simplify_symbols(mod, info); @@ -3386,11 +3471,12 @@ static int load_module(struct load_info *info, const char __user *uargs, goto sysfs_cleanup; } + if (codetag_load_module(mod)) + goto sysfs_cleanup; + /* Get rid of temporary copy. */ free_copy(info, flags); - codetag_load_module(mod); - /* Done! */ trace_module_load(mod); diff --git a/kernel/rcu/tasks.h b/kernel/rcu/tasks.h index c0cc7ae41106..f92443561d36 100644 --- a/kernel/rcu/tasks.h +++ b/kernel/rcu/tasks.h @@ -316,7 +316,8 @@ static void call_rcu_tasks_generic_timer(struct timer_list *tlp) unsigned long flags; bool needwake = false; struct rcu_tasks *rtp; - struct rcu_tasks_percpu *rtpcp = from_timer(rtpcp, tlp, lazy_timer); + struct rcu_tasks_percpu *rtpcp = timer_container_of(rtpcp, tlp, + lazy_timer); rtp = rtpcp->rtpp; raw_spin_lock_irqsave_rcu_node(rtpcp, flags); diff --git a/kernel/rcu/tree_nocb.h b/kernel/rcu/tree_nocb.h index 1596812f7f12..b473ff056f49 100644 --- a/kernel/rcu/tree_nocb.h +++ b/kernel/rcu/tree_nocb.h @@ -985,7 +985,7 @@ static bool do_nocb_deferred_wakeup_common(struct rcu_data *rdp_gp, static void do_nocb_deferred_wakeup_timer(struct timer_list *t) { unsigned long flags; - struct rcu_data *rdp = from_timer(rdp, t, nocb_timer); + struct rcu_data *rdp = timer_container_of(rdp, t, nocb_timer); WARN_ON_ONCE(rdp->nocb_gp_rdp != rdp); trace_rcu_nocb_wake(rcu_state.name, rdp->cpu, TPS("Timer")); diff --git a/kernel/rcu/tree_stall.h b/kernel/rcu/tree_stall.h index 56b21219442b..486c00536207 100644 --- a/kernel/rcu/tree_stall.h +++ b/kernel/rcu/tree_stall.h @@ -20,6 +20,28 @@ int sysctl_panic_on_rcu_stall __read_mostly; int sysctl_max_rcu_stall_to_panic __read_mostly; +#ifdef CONFIG_SYSFS + +static unsigned int rcu_stall_count; + +static ssize_t rcu_stall_count_show(struct kobject *kobj, struct kobj_attribute *attr, + char *page) +{ + return sysfs_emit(page, "%u\n", rcu_stall_count); +} + +static struct kobj_attribute rcu_stall_count_attr = __ATTR_RO(rcu_stall_count); + +static __init int kernel_rcu_stall_sysfs_init(void) +{ + sysfs_add_file_to_group(kernel_kobj, &rcu_stall_count_attr.attr, NULL); + return 0; +} + +late_initcall(kernel_rcu_stall_sysfs_init); + +#endif // CONFIG_SYSFS + #ifdef CONFIG_PROVE_RCU #define RCU_STALL_DELAY_DELTA (5 * HZ) #else @@ -784,6 +806,10 @@ static void check_cpu_stall(struct rcu_data *rdp) if (kvm_check_and_clear_guest_paused()) return; +#ifdef CONFIG_SYSFS + ++rcu_stall_count; +#endif + rcu_stall_notifier_call_chain(RCU_STALL_NOTIFY_NORM, (void *)j - gps); if (READ_ONCE(csd_lock_suppress_rcu_stall) && csd_lock_is_stuck()) { pr_err("INFO: %s detected stall, but suppressed full report due to a stuck CSD-lock.\n", rcu_state.name); diff --git a/kernel/sched/psi.c b/kernel/sched/psi.c index 1396674fa722..ad04a5c3162a 100644 --- a/kernel/sched/psi.c +++ b/kernel/sched/psi.c @@ -733,7 +733,7 @@ static int psi_rtpoll_worker(void *data) static void poll_timer_fn(struct timer_list *t) { - struct psi_group *group = from_timer(group, t, rtpoll_timer); + struct psi_group *group = timer_container_of(group, t, rtpoll_timer); atomic_set(&group->rtpoll_wakeup, 1); wake_up_interruptible(&group->rtpoll_wait); diff --git a/kernel/time/sleep_timeout.c b/kernel/time/sleep_timeout.c index 5aa38b2cf40a..3c90574bd904 100644 --- a/kernel/time/sleep_timeout.c +++ b/kernel/time/sleep_timeout.c @@ -22,7 +22,7 @@ struct process_timer { static void process_timeout(struct timer_list *t) { - struct process_timer *timeout = from_timer(timeout, t, timer); + struct process_timer *timeout = timer_container_of(timeout, t, timer); wake_up_process(timeout->task); } diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index a7291685902e..4203fad56b6c 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -188,7 +188,7 @@ static void ftrace_pid_func(unsigned long ip, unsigned long parent_ip, op->saved_func(ip, parent_ip, op, fregs); } -static void ftrace_sync_ipi(void *data) +void ftrace_sync_ipi(void *data) { /* Probably not needed, but do it anyway */ smp_rmb(); diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index e24509bd0af5..00fc38d70e86 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c @@ -6795,7 +6795,7 @@ int ring_buffer_subbuf_order_set(struct trace_buffer *buffer, int order) old_size = buffer->subbuf_size; /* prevent another thread from changing buffer sizes */ - mutex_lock(&buffer->mutex); + guard(mutex)(&buffer->mutex); atomic_inc(&buffer->record_disabled); /* Make sure all commits have finished */ @@ -6900,7 +6900,6 @@ int ring_buffer_subbuf_order_set(struct trace_buffer *buffer, int order) } atomic_dec(&buffer->record_disabled); - mutex_unlock(&buffer->mutex); return 0; @@ -6909,7 +6908,6 @@ error: buffer->subbuf_size = old_size; atomic_dec(&buffer->record_disabled); - mutex_unlock(&buffer->mutex); for_each_buffer_cpu(buffer, cpu) { cpu_buffer = buffer->buffers[cpu]; diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c index 2048560264bb..ea8b364b6818 100644 --- a/kernel/trace/trace_events_filter.c +++ b/kernel/trace/trace_events_filter.c @@ -1250,7 +1250,9 @@ static void append_filter_err(struct trace_array *tr, static inline struct event_filter *event_filter(struct trace_event_file *file) { - return file->filter; + return rcu_dereference_protected(file->filter, + lockdep_is_held(&event_mutex)); + } /* caller must hold event_mutex */ @@ -1320,7 +1322,7 @@ void free_event_filter(struct event_filter *filter) static inline void __remove_filter(struct trace_event_file *file) { filter_disable(file); - remove_filter_string(file->filter); + remove_filter_string(event_filter(file)); } static void filter_free_subsystem_preds(struct trace_subsystem_dir *dir, @@ -1335,22 +1337,139 @@ static void filter_free_subsystem_preds(struct trace_subsystem_dir *dir, } } +struct filter_list { + struct list_head list; + struct event_filter *filter; +}; + +struct filter_head { + struct list_head list; + struct rcu_head rcu; +}; + + +static void free_filter_list(struct rcu_head *rhp) +{ + struct filter_head *filter_list = container_of(rhp, struct filter_head, rcu); + struct filter_list *filter_item, *tmp; + + list_for_each_entry_safe(filter_item, tmp, &filter_list->list, list) { + __free_filter(filter_item->filter); + list_del(&filter_item->list); + kfree(filter_item); + } + kfree(filter_list); +} + +static void free_filter_list_tasks(struct rcu_head *rhp) +{ + call_rcu(rhp, free_filter_list); +} + +/* + * The tracepoint_synchronize_unregister() is a double rcu call. + * It calls synchronize_rcu_tasks_trace() followed by synchronize_rcu(). + * Instead of waiting for it, simply call these via the call_rcu*() + * variants. + */ +static void delay_free_filter(struct filter_head *head) +{ + call_rcu_tasks_trace(&head->rcu, free_filter_list_tasks); +} + +static void try_delay_free_filter(struct event_filter *filter) +{ + struct filter_head *head; + struct filter_list *item; + + head = kmalloc(sizeof(*head), GFP_KERNEL); + if (!head) + goto free_now; + + INIT_LIST_HEAD(&head->list); + + item = kmalloc(sizeof(*item), GFP_KERNEL); + if (!item) { + kfree(head); + goto free_now; + } + + item->filter = filter; + list_add_tail(&item->list, &head->list); + delay_free_filter(head); + return; + + free_now: + /* Make sure the filter is not being used */ + tracepoint_synchronize_unregister(); + __free_filter(filter); +} + static inline void __free_subsystem_filter(struct trace_event_file *file) { - __free_filter(file->filter); + __free_filter(event_filter(file)); file->filter = NULL; } +static inline void event_set_filter(struct trace_event_file *file, + struct event_filter *filter) +{ + rcu_assign_pointer(file->filter, filter); +} + +static inline void event_clear_filter(struct trace_event_file *file) +{ + RCU_INIT_POINTER(file->filter, NULL); +} + static void filter_free_subsystem_filters(struct trace_subsystem_dir *dir, - struct trace_array *tr) + struct trace_array *tr, + struct event_filter *filter) { struct trace_event_file *file; + struct filter_head *head; + struct filter_list *item; + + head = kmalloc(sizeof(*head), GFP_KERNEL); + if (!head) + goto free_now; + + INIT_LIST_HEAD(&head->list); + + item = kmalloc(sizeof(*item), GFP_KERNEL); + if (!item) { + kfree(head); + goto free_now; + } + + item->filter = filter; + list_add_tail(&item->list, &head->list); list_for_each_entry(file, &tr->events, list) { if (file->system != dir) continue; + item = kmalloc(sizeof(*item), GFP_KERNEL); + if (!item) + goto free_now; + item->filter = event_filter(file); + list_add_tail(&item->list, &head->list); + event_clear_filter(file); + } + + delay_free_filter(head); + return; + free_now: + tracepoint_synchronize_unregister(); + + if (head) + free_filter_list(&head->rcu); + + list_for_each_entry(file, &tr->events, list) { + if (file->system != dir || !file->filter) + continue; __free_subsystem_filter(file); } + __free_filter(filter); } int filter_assign_type(const char *type) @@ -2120,22 +2239,6 @@ static inline void event_set_filtered_flag(struct trace_event_file *file) trace_buffered_event_enable(); } -static inline void event_set_filter(struct trace_event_file *file, - struct event_filter *filter) -{ - rcu_assign_pointer(file->filter, filter); -} - -static inline void event_clear_filter(struct trace_event_file *file) -{ - RCU_INIT_POINTER(file->filter, NULL); -} - -struct filter_list { - struct list_head list; - struct event_filter *filter; -}; - static int process_system_preds(struct trace_subsystem_dir *dir, struct trace_array *tr, struct filter_parse_error *pe, @@ -2144,11 +2247,16 @@ static int process_system_preds(struct trace_subsystem_dir *dir, struct trace_event_file *file; struct filter_list *filter_item; struct event_filter *filter = NULL; - struct filter_list *tmp; - LIST_HEAD(filter_list); + struct filter_head *filter_list; bool fail = true; int err; + filter_list = kmalloc(sizeof(*filter_list), GFP_KERNEL); + if (!filter_list) + return -ENOMEM; + + INIT_LIST_HEAD(&filter_list->list); + list_for_each_entry(file, &tr->events, list) { if (file->system != dir) @@ -2175,7 +2283,7 @@ static int process_system_preds(struct trace_subsystem_dir *dir, if (!filter_item) goto fail_mem; - list_add_tail(&filter_item->list, &filter_list); + list_add_tail(&filter_item->list, &filter_list->list); /* * Regardless of if this returned an error, we still * replace the filter for the call. @@ -2195,31 +2303,22 @@ static int process_system_preds(struct trace_subsystem_dir *dir, * Do a synchronize_rcu() and to ensure all calls are * done with them before we free them. */ - tracepoint_synchronize_unregister(); - list_for_each_entry_safe(filter_item, tmp, &filter_list, list) { - __free_filter(filter_item->filter); - list_del(&filter_item->list); - kfree(filter_item); - } + delay_free_filter(filter_list); return 0; fail: /* No call succeeded */ - list_for_each_entry_safe(filter_item, tmp, &filter_list, list) { - list_del(&filter_item->list); - kfree(filter_item); - } + free_filter_list(&filter_list->rcu); parse_error(pe, FILT_ERR_BAD_SUBSYS_FILTER, 0); return -EINVAL; fail_mem: __free_filter(filter); + /* If any call succeeded, we still need to sync */ if (!fail) - tracepoint_synchronize_unregister(); - list_for_each_entry_safe(filter_item, tmp, &filter_list, list) { - __free_filter(filter_item->filter); - list_del(&filter_item->list); - kfree(filter_item); - } + delay_free_filter(filter_list); + else + free_filter_list(&filter_list->rcu); + return -ENOMEM; } @@ -2361,9 +2460,7 @@ int apply_event_filter(struct trace_event_file *file, char *filter_string) event_clear_filter(file); - /* Make sure the filter is not being used */ - tracepoint_synchronize_unregister(); - __free_filter(filter); + try_delay_free_filter(filter); return 0; } @@ -2387,11 +2484,8 @@ int apply_event_filter(struct trace_event_file *file, char *filter_string) event_set_filter(file, filter); - if (tmp) { - /* Make sure the call is done with the filter */ - tracepoint_synchronize_unregister(); - __free_filter(tmp); - } + if (tmp) + try_delay_free_filter(tmp); } return err; @@ -2417,9 +2511,7 @@ int apply_subsystem_event_filter(struct trace_subsystem_dir *dir, filter = system->filter; system->filter = NULL; /* Ensure all filters are no longer used */ - tracepoint_synchronize_unregister(); - filter_free_subsystem_filters(dir, tr); - __free_filter(filter); + filter_free_subsystem_filters(dir, tr, filter); return 0; } diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 3bef0754cf73..97f37b5bae66 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -2481,7 +2481,7 @@ EXPORT_SYMBOL_GPL(queue_work_node); void delayed_work_timer_fn(struct timer_list *t) { - struct delayed_work *dwork = from_timer(dwork, t, timer); + struct delayed_work *dwork = timer_container_of(dwork, t, timer); /* should have been called from irqsafe timer with irq already off */ __queue_work(dwork->cpu, dwork->wq, &dwork->work); @@ -2909,7 +2909,7 @@ static void set_worker_dying(struct worker *worker, struct list_head *list) */ static void idle_worker_timeout(struct timer_list *t) { - struct worker_pool *pool = from_timer(pool, t, idle_timer); + struct worker_pool *pool = timer_container_of(pool, t, idle_timer); bool do_cull = false; if (work_pending(&pool->idle_cull_work)) @@ -3008,7 +3008,7 @@ static void send_mayday(struct work_struct *work) static void pool_mayday_timeout(struct timer_list *t) { - struct worker_pool *pool = from_timer(pool, t, mayday_timer); + struct worker_pool *pool = timer_container_of(pool, t, mayday_timer); struct work_struct *work; raw_spin_lock_irq(&pool->lock); diff --git a/lib/alloc_tag.c b/lib/alloc_tag.c index 45dae7da70e1..d48b80f3f007 100644 --- a/lib/alloc_tag.c +++ b/lib/alloc_tag.c @@ -607,15 +607,16 @@ out: mas_unlock(&mas); } -static void load_module(struct module *mod, struct codetag *start, struct codetag *stop) +static int load_module(struct module *mod, struct codetag *start, struct codetag *stop) { /* Allocate module alloc_tag percpu counters */ struct alloc_tag *start_tag; struct alloc_tag *stop_tag; struct alloc_tag *tag; + /* percpu counters for core allocations are already statically allocated */ if (!mod) - return; + return 0; start_tag = ct_to_alloc_tag(start); stop_tag = ct_to_alloc_tag(stop); @@ -627,12 +628,13 @@ static void load_module(struct module *mod, struct codetag *start, struct codeta free_percpu(tag->counters); tag->counters = NULL; } - shutdown_mem_profiling(true); - pr_err("Failed to allocate memory for allocation tag percpu counters in the module %s. Memory allocation profiling is disabled!\n", + pr_err("Failed to allocate memory for allocation tag percpu counters in the module %s\n", mod->name); - break; + return -ENOMEM; } } + + return 0; } static void replace_module(struct module *mod, struct module *new_mod) diff --git a/lib/codetag.c b/lib/codetag.c index de332e98d6f5..650d54d7e14d 100644 --- a/lib/codetag.c +++ b/lib/codetag.c @@ -167,6 +167,7 @@ static int codetag_module_init(struct codetag_type *cttype, struct module *mod) { struct codetag_range range; struct codetag_module *cmod; + int mod_id; int err; range = get_section_range(mod, cttype->desc.section); @@ -190,11 +191,20 @@ static int codetag_module_init(struct codetag_type *cttype, struct module *mod) cmod->range = range; down_write(&cttype->mod_lock); - err = idr_alloc(&cttype->mod_idr, cmod, 0, 0, GFP_KERNEL); - if (err >= 0) { - cttype->count += range_size(cttype, &range); - if (cttype->desc.module_load) - cttype->desc.module_load(mod, range.start, range.stop); + mod_id = idr_alloc(&cttype->mod_idr, cmod, 0, 0, GFP_KERNEL); + if (mod_id >= 0) { + if (cttype->desc.module_load) { + err = cttype->desc.module_load(mod, range.start, range.stop); + if (!err) + cttype->count += range_size(cttype, &range); + else + idr_remove(&cttype->mod_idr, mod_id); + } else { + cttype->count += range_size(cttype, &range); + err = 0; + } + } else { + err = mod_id; } up_write(&cttype->mod_lock); @@ -295,17 +305,23 @@ void codetag_module_replaced(struct module *mod, struct module *new_mod) mutex_unlock(&codetag_lock); } -void codetag_load_module(struct module *mod) +int codetag_load_module(struct module *mod) { struct codetag_type *cttype; + int ret = 0; if (!mod) - return; + return 0; mutex_lock(&codetag_lock); - list_for_each_entry(cttype, &codetag_types, link) - codetag_module_init(cttype, mod); + list_for_each_entry(cttype, &codetag_types, link) { + ret = codetag_module_init(cttype, mod); + if (ret) + break; + } mutex_unlock(&codetag_lock); + + return ret; } void codetag_unload_module(struct module *mod) diff --git a/lib/iov_iter.c b/lib/iov_iter.c index 969d4ad510df..f9193f952f49 100644 --- a/lib/iov_iter.c +++ b/lib/iov_iter.c @@ -817,7 +817,7 @@ static bool iov_iter_aligned_bvec(const struct iov_iter *i, unsigned addr_mask, size_t size = i->count; do { - size_t len = bvec->bv_len; + size_t len = bvec->bv_len - skip; if (len > size) len = size; diff --git a/lib/raid6/Makefile b/lib/raid6/Makefile index 29127dd05d63..5be0a4e60ab1 100644 --- a/lib/raid6/Makefile +++ b/lib/raid6/Makefile @@ -10,6 +10,7 @@ raid6_pq-$(CONFIG_ALTIVEC) += altivec1.o altivec2.o altivec4.o altivec8.o \ raid6_pq-$(CONFIG_KERNEL_MODE_NEON) += neon.o neon1.o neon2.o neon4.o neon8.o recov_neon.o recov_neon_inner.o raid6_pq-$(CONFIG_S390) += s390vx8.o recov_s390xc.o raid6_pq-$(CONFIG_LOONGARCH) += loongarch_simd.o recov_loongarch_simd.o +raid6_pq-$(CONFIG_RISCV_ISA_V) += rvv.o recov_rvv.o hostprogs += mktables diff --git a/lib/raid6/algos.c b/lib/raid6/algos.c index dfd3f800ac9b..75ce3e134b7c 100644 --- a/lib/raid6/algos.c +++ b/lib/raid6/algos.c @@ -77,6 +77,12 @@ const struct raid6_calls * const raid6_algos[] = { &raid6_lsx, #endif #endif +#ifdef CONFIG_RISCV_ISA_V + &raid6_rvvx1, + &raid6_rvvx2, + &raid6_rvvx4, + &raid6_rvvx8, +#endif &raid6_intx8, &raid6_intx4, &raid6_intx2, @@ -110,6 +116,9 @@ const struct raid6_recov_calls *const raid6_recov_algos[] = { &raid6_recov_lsx, #endif #endif +#ifdef CONFIG_RISCV_ISA_V + &raid6_recov_rvv, +#endif &raid6_recov_intx1, NULL }; diff --git a/lib/raid6/recov_rvv.c b/lib/raid6/recov_rvv.c new file mode 100644 index 000000000000..f29303795ccf --- /dev/null +++ b/lib/raid6/recov_rvv.c @@ -0,0 +1,229 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright 2024 Institute of Software, CAS. + * Author: Chunyan Zhang <zhangchunyan@iscas.ac.cn> + */ + +#include <asm/simd.h> +#include <asm/vector.h> +#include <crypto/internal/simd.h> +#include <linux/raid/pq.h> + +static int rvv_has_vector(void) +{ + return has_vector(); +} + +static void __raid6_2data_recov_rvv(int bytes, u8 *p, u8 *q, u8 *dp, + u8 *dq, const u8 *pbmul, + const u8 *qmul) +{ + asm volatile (".option push\n" + ".option arch,+v\n" + "vsetvli x0, %[avl], e8, m1, ta, ma\n" + ".option pop\n" + : : + [avl]"r"(16) + ); + + /* + * while ( bytes-- ) { + * uint8_t px, qx, db; + * + * px = *p ^ *dp; + * qx = qmul[*q ^ *dq]; + * *dq++ = db = pbmul[px] ^ qx; + * *dp++ = db ^ px; + * p++; q++; + * } + */ + while (bytes) { + /* + * v0:px, v1:dp, + * v2:qx, v3:dq, + * v4:vx, v5:vy, + * v6:qm0, v7:qm1, + * v8:pm0, v9:pm1, + * v14:p/qm[vx], v15:p/qm[vy] + */ + asm volatile (".option push\n" + ".option arch,+v\n" + "vle8.v v0, (%[px])\n" + "vle8.v v1, (%[dp])\n" + "vxor.vv v0, v0, v1\n" + "vle8.v v2, (%[qx])\n" + "vle8.v v3, (%[dq])\n" + "vxor.vv v4, v2, v3\n" + "vsrl.vi v5, v4, 4\n" + "vand.vi v4, v4, 0xf\n" + "vle8.v v6, (%[qm0])\n" + "vle8.v v7, (%[qm1])\n" + "vrgather.vv v14, v6, v4\n" /* v14 = qm[vx] */ + "vrgather.vv v15, v7, v5\n" /* v15 = qm[vy] */ + "vxor.vv v2, v14, v15\n" /* v2 = qmul[*q ^ *dq] */ + + "vsrl.vi v5, v0, 4\n" + "vand.vi v4, v0, 0xf\n" + "vle8.v v8, (%[pm0])\n" + "vle8.v v9, (%[pm1])\n" + "vrgather.vv v14, v8, v4\n" /* v14 = pm[vx] */ + "vrgather.vv v15, v9, v5\n" /* v15 = pm[vy] */ + "vxor.vv v4, v14, v15\n" /* v4 = pbmul[px] */ + "vxor.vv v3, v4, v2\n" /* v3 = db = pbmul[px] ^ qx */ + "vxor.vv v1, v3, v0\n" /* v1 = db ^ px; */ + "vse8.v v3, (%[dq])\n" + "vse8.v v1, (%[dp])\n" + ".option pop\n" + : : + [px]"r"(p), + [dp]"r"(dp), + [qx]"r"(q), + [dq]"r"(dq), + [qm0]"r"(qmul), + [qm1]"r"(qmul + 16), + [pm0]"r"(pbmul), + [pm1]"r"(pbmul + 16) + :); + + bytes -= 16; + p += 16; + q += 16; + dp += 16; + dq += 16; + } +} + +static void __raid6_datap_recov_rvv(int bytes, u8 *p, u8 *q, + u8 *dq, const u8 *qmul) +{ + asm volatile (".option push\n" + ".option arch,+v\n" + "vsetvli x0, %[avl], e8, m1, ta, ma\n" + ".option pop\n" + : : + [avl]"r"(16) + ); + + /* + * while (bytes--) { + * *p++ ^= *dq = qmul[*q ^ *dq]; + * q++; dq++; + * } + */ + while (bytes) { + /* + * v0:vx, v1:vy, + * v2:dq, v3:p, + * v4:qm0, v5:qm1, + * v10:m[vx], v11:m[vy] + */ + asm volatile (".option push\n" + ".option arch,+v\n" + "vle8.v v0, (%[vx])\n" + "vle8.v v2, (%[dq])\n" + "vxor.vv v0, v0, v2\n" + "vsrl.vi v1, v0, 4\n" + "vand.vi v0, v0, 0xf\n" + "vle8.v v4, (%[qm0])\n" + "vle8.v v5, (%[qm1])\n" + "vrgather.vv v10, v4, v0\n" + "vrgather.vv v11, v5, v1\n" + "vxor.vv v0, v10, v11\n" + "vle8.v v1, (%[vy])\n" + "vxor.vv v1, v0, v1\n" + "vse8.v v0, (%[dq])\n" + "vse8.v v1, (%[vy])\n" + ".option pop\n" + : : + [vx]"r"(q), + [vy]"r"(p), + [dq]"r"(dq), + [qm0]"r"(qmul), + [qm1]"r"(qmul + 16) + :); + + bytes -= 16; + p += 16; + q += 16; + dq += 16; + } +} + +static void raid6_2data_recov_rvv(int disks, size_t bytes, int faila, + int failb, void **ptrs) +{ + u8 *p, *q, *dp, *dq; + const u8 *pbmul; /* P multiplier table for B data */ + const u8 *qmul; /* Q multiplier table (for both) */ + + p = (u8 *)ptrs[disks - 2]; + q = (u8 *)ptrs[disks - 1]; + + /* + * Compute syndrome with zero for the missing data pages + * Use the dead data pages as temporary storage for + * delta p and delta q + */ + dp = (u8 *)ptrs[faila]; + ptrs[faila] = (void *)raid6_empty_zero_page; + ptrs[disks - 2] = dp; + dq = (u8 *)ptrs[failb]; + ptrs[failb] = (void *)raid6_empty_zero_page; + ptrs[disks - 1] = dq; + + raid6_call.gen_syndrome(disks, bytes, ptrs); + + /* Restore pointer table */ + ptrs[faila] = dp; + ptrs[failb] = dq; + ptrs[disks - 2] = p; + ptrs[disks - 1] = q; + + /* Now, pick the proper data tables */ + pbmul = raid6_vgfmul[raid6_gfexi[failb - faila]]; + qmul = raid6_vgfmul[raid6_gfinv[raid6_gfexp[faila] ^ + raid6_gfexp[failb]]]; + + kernel_vector_begin(); + __raid6_2data_recov_rvv(bytes, p, q, dp, dq, pbmul, qmul); + kernel_vector_end(); +} + +static void raid6_datap_recov_rvv(int disks, size_t bytes, int faila, + void **ptrs) +{ + u8 *p, *q, *dq; + const u8 *qmul; /* Q multiplier table */ + + p = (u8 *)ptrs[disks - 2]; + q = (u8 *)ptrs[disks - 1]; + + /* + * Compute syndrome with zero for the missing data page + * Use the dead data page as temporary storage for delta q + */ + dq = (u8 *)ptrs[faila]; + ptrs[faila] = (void *)raid6_empty_zero_page; + ptrs[disks - 1] = dq; + + raid6_call.gen_syndrome(disks, bytes, ptrs); + + /* Restore pointer table */ + ptrs[faila] = dq; + ptrs[disks - 1] = q; + + /* Now, pick the proper data tables */ + qmul = raid6_vgfmul[raid6_gfinv[raid6_gfexp[faila]]]; + + kernel_vector_begin(); + __raid6_datap_recov_rvv(bytes, p, q, dq, qmul); + kernel_vector_end(); +} + +const struct raid6_recov_calls raid6_recov_rvv = { + .data2 = raid6_2data_recov_rvv, + .datap = raid6_datap_recov_rvv, + .valid = rvv_has_vector, + .name = "rvv", + .priority = 1, +}; diff --git a/lib/raid6/rvv.c b/lib/raid6/rvv.c new file mode 100644 index 000000000000..f0887344b274 --- /dev/null +++ b/lib/raid6/rvv.c @@ -0,0 +1,1212 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * RAID-6 syndrome calculation using RISC-V vector instructions + * + * Copyright 2024 Institute of Software, CAS. + * Author: Chunyan Zhang <zhangchunyan@iscas.ac.cn> + * + * Based on neon.uc: + * Copyright 2002-2004 H. Peter Anvin + */ + +#include <asm/simd.h> +#include <asm/vector.h> +#include <crypto/internal/simd.h> +#include <linux/raid/pq.h> +#include <linux/types.h> +#include "rvv.h" + +#define NSIZE (riscv_v_vsize / 32) /* NSIZE = vlenb */ + +static int rvv_has_vector(void) +{ + return has_vector(); +} + +static void raid6_rvv1_gen_syndrome_real(int disks, unsigned long bytes, void **ptrs) +{ + u8 **dptr = (u8 **)ptrs; + unsigned long d; + int z, z0; + u8 *p, *q; + + z0 = disks - 3; /* Highest data disk */ + p = dptr[z0 + 1]; /* XOR parity */ + q = dptr[z0 + 2]; /* RS syndrome */ + + asm volatile (".option push\n" + ".option arch,+v\n" + "vsetvli t0, x0, e8, m1, ta, ma\n" + ".option pop\n" + ); + + /* v0:wp0, v1:wq0, v2:wd0/w20, v3:w10 */ + for (d = 0; d < bytes; d += NSIZE * 1) { + /* wq$$ = wp$$ = *(unative_t *)&dptr[z0][d+$$*NSIZE]; */ + asm volatile (".option push\n" + ".option arch,+v\n" + "vle8.v v0, (%[wp0])\n" + "vle8.v v1, (%[wp0])\n" + ".option pop\n" + : : + [wp0]"r"(&dptr[z0][d + 0 * NSIZE]) + ); + + for (z = z0 - 1 ; z >= 0 ; z--) { + /* + * w2$$ = MASK(wq$$); + * w1$$ = SHLBYTE(wq$$); + * w2$$ &= NBYTES(0x1d); + * w1$$ ^= w2$$; + * wd$$ = *(unative_t *)&dptr[z][d+$$*NSIZE]; + * wq$$ = w1$$ ^ wd$$; + * wp$$ ^= wd$$; + */ + asm volatile (".option push\n" + ".option arch,+v\n" + "vsra.vi v2, v1, 7\n" + "vsll.vi v3, v1, 1\n" + "vand.vx v2, v2, %[x1d]\n" + "vxor.vv v3, v3, v2\n" + "vle8.v v2, (%[wd0])\n" + "vxor.vv v1, v3, v2\n" + "vxor.vv v0, v0, v2\n" + ".option pop\n" + : : + [wd0]"r"(&dptr[z][d + 0 * NSIZE]), + [x1d]"r"(0x1d) + ); + } + + /* + * *(unative_t *)&p[d+NSIZE*$$] = wp$$; + * *(unative_t *)&q[d+NSIZE*$$] = wq$$; + */ + asm volatile (".option push\n" + ".option arch,+v\n" + "vse8.v v0, (%[wp0])\n" + "vse8.v v1, (%[wq0])\n" + ".option pop\n" + : : + [wp0]"r"(&p[d + NSIZE * 0]), + [wq0]"r"(&q[d + NSIZE * 0]) + ); + } +} + +static void raid6_rvv1_xor_syndrome_real(int disks, int start, int stop, + unsigned long bytes, void **ptrs) +{ + u8 **dptr = (u8 **)ptrs; + u8 *p, *q; + unsigned long d; + int z, z0; + + z0 = stop; /* P/Q right side optimization */ + p = dptr[disks - 2]; /* XOR parity */ + q = dptr[disks - 1]; /* RS syndrome */ + + asm volatile (".option push\n" + ".option arch,+v\n" + "vsetvli t0, x0, e8, m1, ta, ma\n" + ".option pop\n" + ); + + /* v0:wp0, v1:wq0, v2:wd0/w20, v3:w10 */ + for (d = 0 ; d < bytes ; d += NSIZE * 1) { + /* wq$$ = wp$$ = *(unative_t *)&dptr[z0][d+$$*NSIZE]; */ + asm volatile (".option push\n" + ".option arch,+v\n" + "vle8.v v0, (%[wp0])\n" + "vle8.v v1, (%[wp0])\n" + ".option pop\n" + : : + [wp0]"r"(&dptr[z0][d + 0 * NSIZE]) + ); + + /* P/Q data pages */ + for (z = z0 - 1; z >= start; z--) { + /* + * w2$$ = MASK(wq$$); + * w1$$ = SHLBYTE(wq$$); + * w2$$ &= NBYTES(0x1d); + * w1$$ ^= w2$$; + * wd$$ = *(unative_t *)&dptr[z][d+$$*NSIZE]; + * wq$$ = w1$$ ^ wd$$; + * wp$$ ^= wd$$; + */ + asm volatile (".option push\n" + ".option arch,+v\n" + "vsra.vi v2, v1, 7\n" + "vsll.vi v3, v1, 1\n" + "vand.vx v2, v2, %[x1d]\n" + "vxor.vv v3, v3, v2\n" + "vle8.v v2, (%[wd0])\n" + "vxor.vv v1, v3, v2\n" + "vxor.vv v0, v0, v2\n" + ".option pop\n" + : : + [wd0]"r"(&dptr[z][d + 0 * NSIZE]), + [x1d]"r"(0x1d) + ); + } + + /* P/Q left side optimization */ + for (z = start - 1; z >= 0; z--) { + /* + * w2$$ = MASK(wq$$); + * w1$$ = SHLBYTE(wq$$); + * w2$$ &= NBYTES(0x1d); + * wq$$ = w1$$ ^ w2$$; + */ + asm volatile (".option push\n" + ".option arch,+v\n" + "vsra.vi v2, v1, 7\n" + "vsll.vi v3, v1, 1\n" + "vand.vx v2, v2, %[x1d]\n" + "vxor.vv v1, v3, v2\n" + ".option pop\n" + : : + [x1d]"r"(0x1d) + ); + } + + /* + * *(unative_t *)&p[d+NSIZE*$$] ^= wp$$; + * *(unative_t *)&q[d+NSIZE*$$] ^= wq$$; + * v0:wp0, v1:wq0, v2:p0, v3:q0 + */ + asm volatile (".option push\n" + ".option arch,+v\n" + "vle8.v v2, (%[wp0])\n" + "vle8.v v3, (%[wq0])\n" + "vxor.vv v2, v2, v0\n" + "vxor.vv v3, v3, v1\n" + "vse8.v v2, (%[wp0])\n" + "vse8.v v3, (%[wq0])\n" + ".option pop\n" + : : + [wp0]"r"(&p[d + NSIZE * 0]), + [wq0]"r"(&q[d + NSIZE * 0]) + ); + } +} + +static void raid6_rvv2_gen_syndrome_real(int disks, unsigned long bytes, void **ptrs) +{ + u8 **dptr = (u8 **)ptrs; + unsigned long d; + int z, z0; + u8 *p, *q; + + z0 = disks - 3; /* Highest data disk */ + p = dptr[z0 + 1]; /* XOR parity */ + q = dptr[z0 + 2]; /* RS syndrome */ + + asm volatile (".option push\n" + ".option arch,+v\n" + "vsetvli t0, x0, e8, m1, ta, ma\n" + ".option pop\n" + ); + + /* + * v0:wp0, v1:wq0, v2:wd0/w20, v3:w10 + * v4:wp1, v5:wq1, v6:wd1/w21, v7:w11 + */ + for (d = 0; d < bytes; d += NSIZE * 2) { + /* wq$$ = wp$$ = *(unative_t *)&dptr[z0][d+$$*NSIZE]; */ + asm volatile (".option push\n" + ".option arch,+v\n" + "vle8.v v0, (%[wp0])\n" + "vle8.v v1, (%[wp0])\n" + "vle8.v v4, (%[wp1])\n" + "vle8.v v5, (%[wp1])\n" + ".option pop\n" + : : + [wp0]"r"(&dptr[z0][d + 0 * NSIZE]), + [wp1]"r"(&dptr[z0][d + 1 * NSIZE]) + ); + + for (z = z0 - 1; z >= 0; z--) { + /* + * w2$$ = MASK(wq$$); + * w1$$ = SHLBYTE(wq$$); + * w2$$ &= NBYTES(0x1d); + * w1$$ ^= w2$$; + * wd$$ = *(unative_t *)&dptr[z][d+$$*NSIZE]; + * wq$$ = w1$$ ^ wd$$; + * wp$$ ^= wd$$; + */ + asm volatile (".option push\n" + ".option arch,+v\n" + "vsra.vi v2, v1, 7\n" + "vsll.vi v3, v1, 1\n" + "vand.vx v2, v2, %[x1d]\n" + "vxor.vv v3, v3, v2\n" + "vle8.v v2, (%[wd0])\n" + "vxor.vv v1, v3, v2\n" + "vxor.vv v0, v0, v2\n" + + "vsra.vi v6, v5, 7\n" + "vsll.vi v7, v5, 1\n" + "vand.vx v6, v6, %[x1d]\n" + "vxor.vv v7, v7, v6\n" + "vle8.v v6, (%[wd1])\n" + "vxor.vv v5, v7, v6\n" + "vxor.vv v4, v4, v6\n" + ".option pop\n" + : : + [wd0]"r"(&dptr[z][d + 0 * NSIZE]), + [wd1]"r"(&dptr[z][d + 1 * NSIZE]), + [x1d]"r"(0x1d) + ); + } + + /* + * *(unative_t *)&p[d+NSIZE*$$] = wp$$; + * *(unative_t *)&q[d+NSIZE*$$] = wq$$; + */ + asm volatile (".option push\n" + ".option arch,+v\n" + "vse8.v v0, (%[wp0])\n" + "vse8.v v1, (%[wq0])\n" + "vse8.v v4, (%[wp1])\n" + "vse8.v v5, (%[wq1])\n" + ".option pop\n" + : : + [wp0]"r"(&p[d + NSIZE * 0]), + [wq0]"r"(&q[d + NSIZE * 0]), + [wp1]"r"(&p[d + NSIZE * 1]), + [wq1]"r"(&q[d + NSIZE * 1]) + ); + } +} + +static void raid6_rvv2_xor_syndrome_real(int disks, int start, int stop, + unsigned long bytes, void **ptrs) +{ + u8 **dptr = (u8 **)ptrs; + u8 *p, *q; + unsigned long d; + int z, z0; + + z0 = stop; /* P/Q right side optimization */ + p = dptr[disks - 2]; /* XOR parity */ + q = dptr[disks - 1]; /* RS syndrome */ + + asm volatile (".option push\n" + ".option arch,+v\n" + "vsetvli t0, x0, e8, m1, ta, ma\n" + ".option pop\n" + ); + + /* + * v0:wp0, v1:wq0, v2:wd0/w20, v3:w10 + * v4:wp1, v5:wq1, v6:wd1/w21, v7:w11 + */ + for (d = 0; d < bytes; d += NSIZE * 2) { + /* wq$$ = wp$$ = *(unative_t *)&dptr[z0][d+$$*NSIZE]; */ + asm volatile (".option push\n" + ".option arch,+v\n" + "vle8.v v0, (%[wp0])\n" + "vle8.v v1, (%[wp0])\n" + "vle8.v v4, (%[wp1])\n" + "vle8.v v5, (%[wp1])\n" + ".option pop\n" + : : + [wp0]"r"(&dptr[z0][d + 0 * NSIZE]), + [wp1]"r"(&dptr[z0][d + 1 * NSIZE]) + ); + + /* P/Q data pages */ + for (z = z0 - 1; z >= start; z--) { + /* + * w2$$ = MASK(wq$$); + * w1$$ = SHLBYTE(wq$$); + * w2$$ &= NBYTES(0x1d); + * w1$$ ^= w2$$; + * wd$$ = *(unative_t *)&dptr[z][d+$$*NSIZE]; + * wq$$ = w1$$ ^ wd$$; + * wp$$ ^= wd$$; + */ + asm volatile (".option push\n" + ".option arch,+v\n" + "vsra.vi v2, v1, 7\n" + "vsll.vi v3, v1, 1\n" + "vand.vx v2, v2, %[x1d]\n" + "vxor.vv v3, v3, v2\n" + "vle8.v v2, (%[wd0])\n" + "vxor.vv v1, v3, v2\n" + "vxor.vv v0, v0, v2\n" + + "vsra.vi v6, v5, 7\n" + "vsll.vi v7, v5, 1\n" + "vand.vx v6, v6, %[x1d]\n" + "vxor.vv v7, v7, v6\n" + "vle8.v v6, (%[wd1])\n" + "vxor.vv v5, v7, v6\n" + "vxor.vv v4, v4, v6\n" + ".option pop\n" + : : + [wd0]"r"(&dptr[z][d + 0 * NSIZE]), + [wd1]"r"(&dptr[z][d + 1 * NSIZE]), + [x1d]"r"(0x1d) + ); + } + + /* P/Q left side optimization */ + for (z = start - 1; z >= 0; z--) { + /* + * w2$$ = MASK(wq$$); + * w1$$ = SHLBYTE(wq$$); + * w2$$ &= NBYTES(0x1d); + * wq$$ = w1$$ ^ w2$$; + */ + asm volatile (".option push\n" + ".option arch,+v\n" + "vsra.vi v2, v1, 7\n" + "vsll.vi v3, v1, 1\n" + "vand.vx v2, v2, %[x1d]\n" + "vxor.vv v1, v3, v2\n" + + "vsra.vi v6, v5, 7\n" + "vsll.vi v7, v5, 1\n" + "vand.vx v6, v6, %[x1d]\n" + "vxor.vv v5, v7, v6\n" + ".option pop\n" + : : + [x1d]"r"(0x1d) + ); + } + + /* + * *(unative_t *)&p[d+NSIZE*$$] ^= wp$$; + * *(unative_t *)&q[d+NSIZE*$$] ^= wq$$; + * v0:wp0, v1:wq0, v2:p0, v3:q0 + * v4:wp1, v5:wq1, v6:p1, v7:q1 + */ + asm volatile (".option push\n" + ".option arch,+v\n" + "vle8.v v2, (%[wp0])\n" + "vle8.v v3, (%[wq0])\n" + "vxor.vv v2, v2, v0\n" + "vxor.vv v3, v3, v1\n" + "vse8.v v2, (%[wp0])\n" + "vse8.v v3, (%[wq0])\n" + + "vle8.v v6, (%[wp1])\n" + "vle8.v v7, (%[wq1])\n" + "vxor.vv v6, v6, v4\n" + "vxor.vv v7, v7, v5\n" + "vse8.v v6, (%[wp1])\n" + "vse8.v v7, (%[wq1])\n" + ".option pop\n" + : : + [wp0]"r"(&p[d + NSIZE * 0]), + [wq0]"r"(&q[d + NSIZE * 0]), + [wp1]"r"(&p[d + NSIZE * 1]), + [wq1]"r"(&q[d + NSIZE * 1]) + ); + } +} + +static void raid6_rvv4_gen_syndrome_real(int disks, unsigned long bytes, void **ptrs) +{ + u8 **dptr = (u8 **)ptrs; + unsigned long d; + int z, z0; + u8 *p, *q; + + z0 = disks - 3; /* Highest data disk */ + p = dptr[z0 + 1]; /* XOR parity */ + q = dptr[z0 + 2]; /* RS syndrome */ + + asm volatile (".option push\n" + ".option arch,+v\n" + "vsetvli t0, x0, e8, m1, ta, ma\n" + ".option pop\n" + ); + + /* + * v0:wp0, v1:wq0, v2:wd0/w20, v3:w10 + * v4:wp1, v5:wq1, v6:wd1/w21, v7:w11 + * v8:wp2, v9:wq2, v10:wd2/w22, v11:w12 + * v12:wp3, v13:wq3, v14:wd3/w23, v15:w13 + */ + for (d = 0; d < bytes; d += NSIZE * 4) { + /* wq$$ = wp$$ = *(unative_t *)&dptr[z0][d+$$*NSIZE]; */ + asm volatile (".option push\n" + ".option arch,+v\n" + "vle8.v v0, (%[wp0])\n" + "vle8.v v1, (%[wp0])\n" + "vle8.v v4, (%[wp1])\n" + "vle8.v v5, (%[wp1])\n" + "vle8.v v8, (%[wp2])\n" + "vle8.v v9, (%[wp2])\n" + "vle8.v v12, (%[wp3])\n" + "vle8.v v13, (%[wp3])\n" + ".option pop\n" + : : + [wp0]"r"(&dptr[z0][d + 0 * NSIZE]), + [wp1]"r"(&dptr[z0][d + 1 * NSIZE]), + [wp2]"r"(&dptr[z0][d + 2 * NSIZE]), + [wp3]"r"(&dptr[z0][d + 3 * NSIZE]) + ); + + for (z = z0 - 1; z >= 0; z--) { + /* + * w2$$ = MASK(wq$$); + * w1$$ = SHLBYTE(wq$$); + * w2$$ &= NBYTES(0x1d); + * w1$$ ^= w2$$; + * wd$$ = *(unative_t *)&dptr[z][d+$$*NSIZE]; + * wq$$ = w1$$ ^ wd$$; + * wp$$ ^= wd$$; + */ + asm volatile (".option push\n" + ".option arch,+v\n" + "vsra.vi v2, v1, 7\n" + "vsll.vi v3, v1, 1\n" + "vand.vx v2, v2, %[x1d]\n" + "vxor.vv v3, v3, v2\n" + "vle8.v v2, (%[wd0])\n" + "vxor.vv v1, v3, v2\n" + "vxor.vv v0, v0, v2\n" + + "vsra.vi v6, v5, 7\n" + "vsll.vi v7, v5, 1\n" + "vand.vx v6, v6, %[x1d]\n" + "vxor.vv v7, v7, v6\n" + "vle8.v v6, (%[wd1])\n" + "vxor.vv v5, v7, v6\n" + "vxor.vv v4, v4, v6\n" + + "vsra.vi v10, v9, 7\n" + "vsll.vi v11, v9, 1\n" + "vand.vx v10, v10, %[x1d]\n" + "vxor.vv v11, v11, v10\n" + "vle8.v v10, (%[wd2])\n" + "vxor.vv v9, v11, v10\n" + "vxor.vv v8, v8, v10\n" + + "vsra.vi v14, v13, 7\n" + "vsll.vi v15, v13, 1\n" + "vand.vx v14, v14, %[x1d]\n" + "vxor.vv v15, v15, v14\n" + "vle8.v v14, (%[wd3])\n" + "vxor.vv v13, v15, v14\n" + "vxor.vv v12, v12, v14\n" + ".option pop\n" + : : + [wd0]"r"(&dptr[z][d + 0 * NSIZE]), + [wd1]"r"(&dptr[z][d + 1 * NSIZE]), + [wd2]"r"(&dptr[z][d + 2 * NSIZE]), + [wd3]"r"(&dptr[z][d + 3 * NSIZE]), + [x1d]"r"(0x1d) + ); + } + + /* + * *(unative_t *)&p[d+NSIZE*$$] = wp$$; + * *(unative_t *)&q[d+NSIZE*$$] = wq$$; + */ + asm volatile (".option push\n" + ".option arch,+v\n" + "vse8.v v0, (%[wp0])\n" + "vse8.v v1, (%[wq0])\n" + "vse8.v v4, (%[wp1])\n" + "vse8.v v5, (%[wq1])\n" + "vse8.v v8, (%[wp2])\n" + "vse8.v v9, (%[wq2])\n" + "vse8.v v12, (%[wp3])\n" + "vse8.v v13, (%[wq3])\n" + ".option pop\n" + : : + [wp0]"r"(&p[d + NSIZE * 0]), + [wq0]"r"(&q[d + NSIZE * 0]), + [wp1]"r"(&p[d + NSIZE * 1]), + [wq1]"r"(&q[d + NSIZE * 1]), + [wp2]"r"(&p[d + NSIZE * 2]), + [wq2]"r"(&q[d + NSIZE * 2]), + [wp3]"r"(&p[d + NSIZE * 3]), + [wq3]"r"(&q[d + NSIZE * 3]) + ); + } +} + +static void raid6_rvv4_xor_syndrome_real(int disks, int start, int stop, + unsigned long bytes, void **ptrs) +{ + u8 **dptr = (u8 **)ptrs; + u8 *p, *q; + unsigned long d; + int z, z0; + + z0 = stop; /* P/Q right side optimization */ + p = dptr[disks - 2]; /* XOR parity */ + q = dptr[disks - 1]; /* RS syndrome */ + + asm volatile (".option push\n" + ".option arch,+v\n" + "vsetvli t0, x0, e8, m1, ta, ma\n" + ".option pop\n" + ); + + /* + * v0:wp0, v1:wq0, v2:wd0/w20, v3:w10 + * v4:wp1, v5:wq1, v6:wd1/w21, v7:w11 + * v8:wp2, v9:wq2, v10:wd2/w22, v11:w12 + * v12:wp3, v13:wq3, v14:wd3/w23, v15:w13 + */ + for (d = 0; d < bytes; d += NSIZE * 4) { + /* wq$$ = wp$$ = *(unative_t *)&dptr[z0][d+$$*NSIZE]; */ + asm volatile (".option push\n" + ".option arch,+v\n" + "vle8.v v0, (%[wp0])\n" + "vle8.v v1, (%[wp0])\n" + "vle8.v v4, (%[wp1])\n" + "vle8.v v5, (%[wp1])\n" + "vle8.v v8, (%[wp2])\n" + "vle8.v v9, (%[wp2])\n" + "vle8.v v12, (%[wp3])\n" + "vle8.v v13, (%[wp3])\n" + ".option pop\n" + : : + [wp0]"r"(&dptr[z0][d + 0 * NSIZE]), + [wp1]"r"(&dptr[z0][d + 1 * NSIZE]), + [wp2]"r"(&dptr[z0][d + 2 * NSIZE]), + [wp3]"r"(&dptr[z0][d + 3 * NSIZE]) + ); + + /* P/Q data pages */ + for (z = z0 - 1; z >= start; z--) { + /* + * w2$$ = MASK(wq$$); + * w1$$ = SHLBYTE(wq$$); + * w2$$ &= NBYTES(0x1d); + * w1$$ ^= w2$$; + * wd$$ = *(unative_t *)&dptr[z][d+$$*NSIZE]; + * wq$$ = w1$$ ^ wd$$; + * wp$$ ^= wd$$; + */ + asm volatile (".option push\n" + ".option arch,+v\n" + "vsra.vi v2, v1, 7\n" + "vsll.vi v3, v1, 1\n" + "vand.vx v2, v2, %[x1d]\n" + "vxor.vv v3, v3, v2\n" + "vle8.v v2, (%[wd0])\n" + "vxor.vv v1, v3, v2\n" + "vxor.vv v0, v0, v2\n" + + "vsra.vi v6, v5, 7\n" + "vsll.vi v7, v5, 1\n" + "vand.vx v6, v6, %[x1d]\n" + "vxor.vv v7, v7, v6\n" + "vle8.v v6, (%[wd1])\n" + "vxor.vv v5, v7, v6\n" + "vxor.vv v4, v4, v6\n" + + "vsra.vi v10, v9, 7\n" + "vsll.vi v11, v9, 1\n" + "vand.vx v10, v10, %[x1d]\n" + "vxor.vv v11, v11, v10\n" + "vle8.v v10, (%[wd2])\n" + "vxor.vv v9, v11, v10\n" + "vxor.vv v8, v8, v10\n" + + "vsra.vi v14, v13, 7\n" + "vsll.vi v15, v13, 1\n" + "vand.vx v14, v14, %[x1d]\n" + "vxor.vv v15, v15, v14\n" + "vle8.v v14, (%[wd3])\n" + "vxor.vv v13, v15, v14\n" + "vxor.vv v12, v12, v14\n" + ".option pop\n" + : : + [wd0]"r"(&dptr[z][d + 0 * NSIZE]), + [wd1]"r"(&dptr[z][d + 1 * NSIZE]), + [wd2]"r"(&dptr[z][d + 2 * NSIZE]), + [wd3]"r"(&dptr[z][d + 3 * NSIZE]), + [x1d]"r"(0x1d) + ); + } + + /* P/Q left side optimization */ + for (z = start - 1; z >= 0; z--) { + /* + * w2$$ = MASK(wq$$); + * w1$$ = SHLBYTE(wq$$); + * w2$$ &= NBYTES(0x1d); + * wq$$ = w1$$ ^ w2$$; + */ + asm volatile (".option push\n" + ".option arch,+v\n" + "vsra.vi v2, v1, 7\n" + "vsll.vi v3, v1, 1\n" + "vand.vx v2, v2, %[x1d]\n" + "vxor.vv v1, v3, v2\n" + + "vsra.vi v6, v5, 7\n" + "vsll.vi v7, v5, 1\n" + "vand.vx v6, v6, %[x1d]\n" + "vxor.vv v5, v7, v6\n" + + "vsra.vi v10, v9, 7\n" + "vsll.vi v11, v9, 1\n" + "vand.vx v10, v10, %[x1d]\n" + "vxor.vv v9, v11, v10\n" + + "vsra.vi v14, v13, 7\n" + "vsll.vi v15, v13, 1\n" + "vand.vx v14, v14, %[x1d]\n" + "vxor.vv v13, v15, v14\n" + ".option pop\n" + : : + [x1d]"r"(0x1d) + ); + } + + /* + * *(unative_t *)&p[d+NSIZE*$$] ^= wp$$; + * *(unative_t *)&q[d+NSIZE*$$] ^= wq$$; + * v0:wp0, v1:wq0, v2:p0, v3:q0 + * v4:wp1, v5:wq1, v6:p1, v7:q1 + * v8:wp2, v9:wq2, v10:p2, v11:q2 + * v12:wp3, v13:wq3, v14:p3, v15:q3 + */ + asm volatile (".option push\n" + ".option arch,+v\n" + "vle8.v v2, (%[wp0])\n" + "vle8.v v3, (%[wq0])\n" + "vxor.vv v2, v2, v0\n" + "vxor.vv v3, v3, v1\n" + "vse8.v v2, (%[wp0])\n" + "vse8.v v3, (%[wq0])\n" + + "vle8.v v6, (%[wp1])\n" + "vle8.v v7, (%[wq1])\n" + "vxor.vv v6, v6, v4\n" + "vxor.vv v7, v7, v5\n" + "vse8.v v6, (%[wp1])\n" + "vse8.v v7, (%[wq1])\n" + + "vle8.v v10, (%[wp2])\n" + "vle8.v v11, (%[wq2])\n" + "vxor.vv v10, v10, v8\n" + "vxor.vv v11, v11, v9\n" + "vse8.v v10, (%[wp2])\n" + "vse8.v v11, (%[wq2])\n" + + "vle8.v v14, (%[wp3])\n" + "vle8.v v15, (%[wq3])\n" + "vxor.vv v14, v14, v12\n" + "vxor.vv v15, v15, v13\n" + "vse8.v v14, (%[wp3])\n" + "vse8.v v15, (%[wq3])\n" + ".option pop\n" + : : + [wp0]"r"(&p[d + NSIZE * 0]), + [wq0]"r"(&q[d + NSIZE * 0]), + [wp1]"r"(&p[d + NSIZE * 1]), + [wq1]"r"(&q[d + NSIZE * 1]), + [wp2]"r"(&p[d + NSIZE * 2]), + [wq2]"r"(&q[d + NSIZE * 2]), + [wp3]"r"(&p[d + NSIZE * 3]), + [wq3]"r"(&q[d + NSIZE * 3]) + ); + } +} + +static void raid6_rvv8_gen_syndrome_real(int disks, unsigned long bytes, void **ptrs) +{ + u8 **dptr = (u8 **)ptrs; + unsigned long d; + int z, z0; + u8 *p, *q; + + z0 = disks - 3; /* Highest data disk */ + p = dptr[z0 + 1]; /* XOR parity */ + q = dptr[z0 + 2]; /* RS syndrome */ + + asm volatile (".option push\n" + ".option arch,+v\n" + "vsetvli t0, x0, e8, m1, ta, ma\n" + ".option pop\n" + ); + + /* + * v0:wp0, v1:wq0, v2:wd0/w20, v3:w10 + * v4:wp1, v5:wq1, v6:wd1/w21, v7:w11 + * v8:wp2, v9:wq2, v10:wd2/w22, v11:w12 + * v12:wp3, v13:wq3, v14:wd3/w23, v15:w13 + * v16:wp4, v17:wq4, v18:wd4/w24, v19:w14 + * v20:wp5, v21:wq5, v22:wd5/w25, v23:w15 + * v24:wp6, v25:wq6, v26:wd6/w26, v27:w16 + * v28:wp7, v29:wq7, v30:wd7/w27, v31:w17 + */ + for (d = 0; d < bytes; d += NSIZE * 8) { + /* wq$$ = wp$$ = *(unative_t *)&dptr[z0][d+$$*NSIZE]; */ + asm volatile (".option push\n" + ".option arch,+v\n" + "vle8.v v0, (%[wp0])\n" + "vle8.v v1, (%[wp0])\n" + "vle8.v v4, (%[wp1])\n" + "vle8.v v5, (%[wp1])\n" + "vle8.v v8, (%[wp2])\n" + "vle8.v v9, (%[wp2])\n" + "vle8.v v12, (%[wp3])\n" + "vle8.v v13, (%[wp3])\n" + "vle8.v v16, (%[wp4])\n" + "vle8.v v17, (%[wp4])\n" + "vle8.v v20, (%[wp5])\n" + "vle8.v v21, (%[wp5])\n" + "vle8.v v24, (%[wp6])\n" + "vle8.v v25, (%[wp6])\n" + "vle8.v v28, (%[wp7])\n" + "vle8.v v29, (%[wp7])\n" + ".option pop\n" + : : + [wp0]"r"(&dptr[z0][d + 0 * NSIZE]), + [wp1]"r"(&dptr[z0][d + 1 * NSIZE]), + [wp2]"r"(&dptr[z0][d + 2 * NSIZE]), + [wp3]"r"(&dptr[z0][d + 3 * NSIZE]), + [wp4]"r"(&dptr[z0][d + 4 * NSIZE]), + [wp5]"r"(&dptr[z0][d + 5 * NSIZE]), + [wp6]"r"(&dptr[z0][d + 6 * NSIZE]), + [wp7]"r"(&dptr[z0][d + 7 * NSIZE]) + ); + + for (z = z0 - 1; z >= 0; z--) { + /* + * w2$$ = MASK(wq$$); + * w1$$ = SHLBYTE(wq$$); + * w2$$ &= NBYTES(0x1d); + * w1$$ ^= w2$$; + * wd$$ = *(unative_t *)&dptr[z][d+$$*NSIZE]; + * wq$$ = w1$$ ^ wd$$; + * wp$$ ^= wd$$; + */ + asm volatile (".option push\n" + ".option arch,+v\n" + "vsra.vi v2, v1, 7\n" + "vsll.vi v3, v1, 1\n" + "vand.vx v2, v2, %[x1d]\n" + "vxor.vv v3, v3, v2\n" + "vle8.v v2, (%[wd0])\n" + "vxor.vv v1, v3, v2\n" + "vxor.vv v0, v0, v2\n" + + "vsra.vi v6, v5, 7\n" + "vsll.vi v7, v5, 1\n" + "vand.vx v6, v6, %[x1d]\n" + "vxor.vv v7, v7, v6\n" + "vle8.v v6, (%[wd1])\n" + "vxor.vv v5, v7, v6\n" + "vxor.vv v4, v4, v6\n" + + "vsra.vi v10, v9, 7\n" + "vsll.vi v11, v9, 1\n" + "vand.vx v10, v10, %[x1d]\n" + "vxor.vv v11, v11, v10\n" + "vle8.v v10, (%[wd2])\n" + "vxor.vv v9, v11, v10\n" + "vxor.vv v8, v8, v10\n" + + "vsra.vi v14, v13, 7\n" + "vsll.vi v15, v13, 1\n" + "vand.vx v14, v14, %[x1d]\n" + "vxor.vv v15, v15, v14\n" + "vle8.v v14, (%[wd3])\n" + "vxor.vv v13, v15, v14\n" + "vxor.vv v12, v12, v14\n" + + "vsra.vi v18, v17, 7\n" + "vsll.vi v19, v17, 1\n" + "vand.vx v18, v18, %[x1d]\n" + "vxor.vv v19, v19, v18\n" + "vle8.v v18, (%[wd4])\n" + "vxor.vv v17, v19, v18\n" + "vxor.vv v16, v16, v18\n" + + "vsra.vi v22, v21, 7\n" + "vsll.vi v23, v21, 1\n" + "vand.vx v22, v22, %[x1d]\n" + "vxor.vv v23, v23, v22\n" + "vle8.v v22, (%[wd5])\n" + "vxor.vv v21, v23, v22\n" + "vxor.vv v20, v20, v22\n" + + "vsra.vi v26, v25, 7\n" + "vsll.vi v27, v25, 1\n" + "vand.vx v26, v26, %[x1d]\n" + "vxor.vv v27, v27, v26\n" + "vle8.v v26, (%[wd6])\n" + "vxor.vv v25, v27, v26\n" + "vxor.vv v24, v24, v26\n" + + "vsra.vi v30, v29, 7\n" + "vsll.vi v31, v29, 1\n" + "vand.vx v30, v30, %[x1d]\n" + "vxor.vv v31, v31, v30\n" + "vle8.v v30, (%[wd7])\n" + "vxor.vv v29, v31, v30\n" + "vxor.vv v28, v28, v30\n" + ".option pop\n" + : : + [wd0]"r"(&dptr[z][d + 0 * NSIZE]), + [wd1]"r"(&dptr[z][d + 1 * NSIZE]), + [wd2]"r"(&dptr[z][d + 2 * NSIZE]), + [wd3]"r"(&dptr[z][d + 3 * NSIZE]), + [wd4]"r"(&dptr[z][d + 4 * NSIZE]), + [wd5]"r"(&dptr[z][d + 5 * NSIZE]), + [wd6]"r"(&dptr[z][d + 6 * NSIZE]), + [wd7]"r"(&dptr[z][d + 7 * NSIZE]), + [x1d]"r"(0x1d) + ); + } + + /* + * *(unative_t *)&p[d+NSIZE*$$] = wp$$; + * *(unative_t *)&q[d+NSIZE*$$] = wq$$; + */ + asm volatile (".option push\n" + ".option arch,+v\n" + "vse8.v v0, (%[wp0])\n" + "vse8.v v1, (%[wq0])\n" + "vse8.v v4, (%[wp1])\n" + "vse8.v v5, (%[wq1])\n" + "vse8.v v8, (%[wp2])\n" + "vse8.v v9, (%[wq2])\n" + "vse8.v v12, (%[wp3])\n" + "vse8.v v13, (%[wq3])\n" + "vse8.v v16, (%[wp4])\n" + "vse8.v v17, (%[wq4])\n" + "vse8.v v20, (%[wp5])\n" + "vse8.v v21, (%[wq5])\n" + "vse8.v v24, (%[wp6])\n" + "vse8.v v25, (%[wq6])\n" + "vse8.v v28, (%[wp7])\n" + "vse8.v v29, (%[wq7])\n" + ".option pop\n" + : : + [wp0]"r"(&p[d + NSIZE * 0]), + [wq0]"r"(&q[d + NSIZE * 0]), + [wp1]"r"(&p[d + NSIZE * 1]), + [wq1]"r"(&q[d + NSIZE * 1]), + [wp2]"r"(&p[d + NSIZE * 2]), + [wq2]"r"(&q[d + NSIZE * 2]), + [wp3]"r"(&p[d + NSIZE * 3]), + [wq3]"r"(&q[d + NSIZE * 3]), + [wp4]"r"(&p[d + NSIZE * 4]), + [wq4]"r"(&q[d + NSIZE * 4]), + [wp5]"r"(&p[d + NSIZE * 5]), + [wq5]"r"(&q[d + NSIZE * 5]), + [wp6]"r"(&p[d + NSIZE * 6]), + [wq6]"r"(&q[d + NSIZE * 6]), + [wp7]"r"(&p[d + NSIZE * 7]), + [wq7]"r"(&q[d + NSIZE * 7]) + ); + } +} + +static void raid6_rvv8_xor_syndrome_real(int disks, int start, int stop, + unsigned long bytes, void **ptrs) +{ + u8 **dptr = (u8 **)ptrs; + u8 *p, *q; + unsigned long d; + int z, z0; + + z0 = stop; /* P/Q right side optimization */ + p = dptr[disks - 2]; /* XOR parity */ + q = dptr[disks - 1]; /* RS syndrome */ + + asm volatile (".option push\n" + ".option arch,+v\n" + "vsetvli t0, x0, e8, m1, ta, ma\n" + ".option pop\n" + ); + + /* + * v0:wp0, v1:wq0, v2:wd0/w20, v3:w10 + * v4:wp1, v5:wq1, v6:wd1/w21, v7:w11 + * v8:wp2, v9:wq2, v10:wd2/w22, v11:w12 + * v12:wp3, v13:wq3, v14:wd3/w23, v15:w13 + * v16:wp4, v17:wq4, v18:wd4/w24, v19:w14 + * v20:wp5, v21:wq5, v22:wd5/w25, v23:w15 + * v24:wp6, v25:wq6, v26:wd6/w26, v27:w16 + * v28:wp7, v29:wq7, v30:wd7/w27, v31:w17 + */ + for (d = 0; d < bytes; d += NSIZE * 8) { + /* wq$$ = wp$$ = *(unative_t *)&dptr[z0][d+$$*NSIZE]; */ + asm volatile (".option push\n" + ".option arch,+v\n" + "vle8.v v0, (%[wp0])\n" + "vle8.v v1, (%[wp0])\n" + "vle8.v v4, (%[wp1])\n" + "vle8.v v5, (%[wp1])\n" + "vle8.v v8, (%[wp2])\n" + "vle8.v v9, (%[wp2])\n" + "vle8.v v12, (%[wp3])\n" + "vle8.v v13, (%[wp3])\n" + "vle8.v v16, (%[wp4])\n" + "vle8.v v17, (%[wp4])\n" + "vle8.v v20, (%[wp5])\n" + "vle8.v v21, (%[wp5])\n" + "vle8.v v24, (%[wp6])\n" + "vle8.v v25, (%[wp6])\n" + "vle8.v v28, (%[wp7])\n" + "vle8.v v29, (%[wp7])\n" + ".option pop\n" + : : + [wp0]"r"(&dptr[z0][d + 0 * NSIZE]), + [wp1]"r"(&dptr[z0][d + 1 * NSIZE]), + [wp2]"r"(&dptr[z0][d + 2 * NSIZE]), + [wp3]"r"(&dptr[z0][d + 3 * NSIZE]), + [wp4]"r"(&dptr[z0][d + 4 * NSIZE]), + [wp5]"r"(&dptr[z0][d + 5 * NSIZE]), + [wp6]"r"(&dptr[z0][d + 6 * NSIZE]), + [wp7]"r"(&dptr[z0][d + 7 * NSIZE]) + ); + + /* P/Q data pages */ + for (z = z0 - 1; z >= start; z--) { + /* + * w2$$ = MASK(wq$$); + * w1$$ = SHLBYTE(wq$$); + * w2$$ &= NBYTES(0x1d); + * w1$$ ^= w2$$; + * wd$$ = *(unative_t *)&dptr[z][d+$$*NSIZE]; + * wq$$ = w1$$ ^ wd$$; + * wp$$ ^= wd$$; + */ + asm volatile (".option push\n" + ".option arch,+v\n" + "vsra.vi v2, v1, 7\n" + "vsll.vi v3, v1, 1\n" + "vand.vx v2, v2, %[x1d]\n" + "vxor.vv v3, v3, v2\n" + "vle8.v v2, (%[wd0])\n" + "vxor.vv v1, v3, v2\n" + "vxor.vv v0, v0, v2\n" + + "vsra.vi v6, v5, 7\n" + "vsll.vi v7, v5, 1\n" + "vand.vx v6, v6, %[x1d]\n" + "vxor.vv v7, v7, v6\n" + "vle8.v v6, (%[wd1])\n" + "vxor.vv v5, v7, v6\n" + "vxor.vv v4, v4, v6\n" + + "vsra.vi v10, v9, 7\n" + "vsll.vi v11, v9, 1\n" + "vand.vx v10, v10, %[x1d]\n" + "vxor.vv v11, v11, v10\n" + "vle8.v v10, (%[wd2])\n" + "vxor.vv v9, v11, v10\n" + "vxor.vv v8, v8, v10\n" + + "vsra.vi v14, v13, 7\n" + "vsll.vi v15, v13, 1\n" + "vand.vx v14, v14, %[x1d]\n" + "vxor.vv v15, v15, v14\n" + "vle8.v v14, (%[wd3])\n" + "vxor.vv v13, v15, v14\n" + "vxor.vv v12, v12, v14\n" + + "vsra.vi v18, v17, 7\n" + "vsll.vi v19, v17, 1\n" + "vand.vx v18, v18, %[x1d]\n" + "vxor.vv v19, v19, v18\n" + "vle8.v v18, (%[wd4])\n" + "vxor.vv v17, v19, v18\n" + "vxor.vv v16, v16, v18\n" + + "vsra.vi v22, v21, 7\n" + "vsll.vi v23, v21, 1\n" + "vand.vx v22, v22, %[x1d]\n" + "vxor.vv v23, v23, v22\n" + "vle8.v v22, (%[wd5])\n" + "vxor.vv v21, v23, v22\n" + "vxor.vv v20, v20, v22\n" + + "vsra.vi v26, v25, 7\n" + "vsll.vi v27, v25, 1\n" + "vand.vx v26, v26, %[x1d]\n" + "vxor.vv v27, v27, v26\n" + "vle8.v v26, (%[wd6])\n" + "vxor.vv v25, v27, v26\n" + "vxor.vv v24, v24, v26\n" + + "vsra.vi v30, v29, 7\n" + "vsll.vi v31, v29, 1\n" + "vand.vx v30, v30, %[x1d]\n" + "vxor.vv v31, v31, v30\n" + "vle8.v v30, (%[wd7])\n" + "vxor.vv v29, v31, v30\n" + "vxor.vv v28, v28, v30\n" + ".option pop\n" + : : + [wd0]"r"(&dptr[z][d + 0 * NSIZE]), + [wd1]"r"(&dptr[z][d + 1 * NSIZE]), + [wd2]"r"(&dptr[z][d + 2 * NSIZE]), + [wd3]"r"(&dptr[z][d + 3 * NSIZE]), + [wd4]"r"(&dptr[z][d + 4 * NSIZE]), + [wd5]"r"(&dptr[z][d + 5 * NSIZE]), + [wd6]"r"(&dptr[z][d + 6 * NSIZE]), + [wd7]"r"(&dptr[z][d + 7 * NSIZE]), + [x1d]"r"(0x1d) + ); + } + + /* P/Q left side optimization */ + for (z = start - 1; z >= 0; z--) { + /* + * w2$$ = MASK(wq$$); + * w1$$ = SHLBYTE(wq$$); + * w2$$ &= NBYTES(0x1d); + * wq$$ = w1$$ ^ w2$$; + */ + asm volatile (".option push\n" + ".option arch,+v\n" + "vsra.vi v2, v1, 7\n" + "vsll.vi v3, v1, 1\n" + "vand.vx v2, v2, %[x1d]\n" + "vxor.vv v1, v3, v2\n" + + "vsra.vi v6, v5, 7\n" + "vsll.vi v7, v5, 1\n" + "vand.vx v6, v6, %[x1d]\n" + "vxor.vv v5, v7, v6\n" + + "vsra.vi v10, v9, 7\n" + "vsll.vi v11, v9, 1\n" + "vand.vx v10, v10, %[x1d]\n" + "vxor.vv v9, v11, v10\n" + + "vsra.vi v14, v13, 7\n" + "vsll.vi v15, v13, 1\n" + "vand.vx v14, v14, %[x1d]\n" + "vxor.vv v13, v15, v14\n" + + "vsra.vi v18, v17, 7\n" + "vsll.vi v19, v17, 1\n" + "vand.vx v18, v18, %[x1d]\n" + "vxor.vv v17, v19, v18\n" + + "vsra.vi v22, v21, 7\n" + "vsll.vi v23, v21, 1\n" + "vand.vx v22, v22, %[x1d]\n" + "vxor.vv v21, v23, v22\n" + + "vsra.vi v26, v25, 7\n" + "vsll.vi v27, v25, 1\n" + "vand.vx v26, v26, %[x1d]\n" + "vxor.vv v25, v27, v26\n" + + "vsra.vi v30, v29, 7\n" + "vsll.vi v31, v29, 1\n" + "vand.vx v30, v30, %[x1d]\n" + "vxor.vv v29, v31, v30\n" + ".option pop\n" + : : + [x1d]"r"(0x1d) + ); + } + + /* + * *(unative_t *)&p[d+NSIZE*$$] ^= wp$$; + * *(unative_t *)&q[d+NSIZE*$$] ^= wq$$; + * v0:wp0, v1:wq0, v2:p0, v3:q0 + * v4:wp1, v5:wq1, v6:p1, v7:q1 + * v8:wp2, v9:wq2, v10:p2, v11:q2 + * v12:wp3, v13:wq3, v14:p3, v15:q3 + * v16:wp4, v17:wq4, v18:p4, v19:q4 + * v20:wp5, v21:wq5, v22:p5, v23:q5 + * v24:wp6, v25:wq6, v26:p6, v27:q6 + * v28:wp7, v29:wq7, v30:p7, v31:q7 + */ + asm volatile (".option push\n" + ".option arch,+v\n" + "vle8.v v2, (%[wp0])\n" + "vle8.v v3, (%[wq0])\n" + "vxor.vv v2, v2, v0\n" + "vxor.vv v3, v3, v1\n" + "vse8.v v2, (%[wp0])\n" + "vse8.v v3, (%[wq0])\n" + + "vle8.v v6, (%[wp1])\n" + "vle8.v v7, (%[wq1])\n" + "vxor.vv v6, v6, v4\n" + "vxor.vv v7, v7, v5\n" + "vse8.v v6, (%[wp1])\n" + "vse8.v v7, (%[wq1])\n" + + "vle8.v v10, (%[wp2])\n" + "vle8.v v11, (%[wq2])\n" + "vxor.vv v10, v10, v8\n" + "vxor.vv v11, v11, v9\n" + "vse8.v v10, (%[wp2])\n" + "vse8.v v11, (%[wq2])\n" + + "vle8.v v14, (%[wp3])\n" + "vle8.v v15, (%[wq3])\n" + "vxor.vv v14, v14, v12\n" + "vxor.vv v15, v15, v13\n" + "vse8.v v14, (%[wp3])\n" + "vse8.v v15, (%[wq3])\n" + + "vle8.v v18, (%[wp4])\n" + "vle8.v v19, (%[wq4])\n" + "vxor.vv v18, v18, v16\n" + "vxor.vv v19, v19, v17\n" + "vse8.v v18, (%[wp4])\n" + "vse8.v v19, (%[wq4])\n" + + "vle8.v v22, (%[wp5])\n" + "vle8.v v23, (%[wq5])\n" + "vxor.vv v22, v22, v20\n" + "vxor.vv v23, v23, v21\n" + "vse8.v v22, (%[wp5])\n" + "vse8.v v23, (%[wq5])\n" + + "vle8.v v26, (%[wp6])\n" + "vle8.v v27, (%[wq6])\n" + "vxor.vv v26, v26, v24\n" + "vxor.vv v27, v27, v25\n" + "vse8.v v26, (%[wp6])\n" + "vse8.v v27, (%[wq6])\n" + + "vle8.v v30, (%[wp7])\n" + "vle8.v v31, (%[wq7])\n" + "vxor.vv v30, v30, v28\n" + "vxor.vv v31, v31, v29\n" + "vse8.v v30, (%[wp7])\n" + "vse8.v v31, (%[wq7])\n" + ".option pop\n" + : : + [wp0]"r"(&p[d + NSIZE * 0]), + [wq0]"r"(&q[d + NSIZE * 0]), + [wp1]"r"(&p[d + NSIZE * 1]), + [wq1]"r"(&q[d + NSIZE * 1]), + [wp2]"r"(&p[d + NSIZE * 2]), + [wq2]"r"(&q[d + NSIZE * 2]), + [wp3]"r"(&p[d + NSIZE * 3]), + [wq3]"r"(&q[d + NSIZE * 3]), + [wp4]"r"(&p[d + NSIZE * 4]), + [wq4]"r"(&q[d + NSIZE * 4]), + [wp5]"r"(&p[d + NSIZE * 5]), + [wq5]"r"(&q[d + NSIZE * 5]), + [wp6]"r"(&p[d + NSIZE * 6]), + [wq6]"r"(&q[d + NSIZE * 6]), + [wp7]"r"(&p[d + NSIZE * 7]), + [wq7]"r"(&q[d + NSIZE * 7]) + ); + } +} + +RAID6_RVV_WRAPPER(1); +RAID6_RVV_WRAPPER(2); +RAID6_RVV_WRAPPER(4); +RAID6_RVV_WRAPPER(8); diff --git a/lib/raid6/rvv.h b/lib/raid6/rvv.h new file mode 100644 index 000000000000..94044a1b707b --- /dev/null +++ b/lib/raid6/rvv.h @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright 2024 Institute of Software, CAS. + * + * raid6/rvv.h + * + * Definitions for RISC-V RAID-6 code + */ + +#define RAID6_RVV_WRAPPER(_n) \ + static void raid6_rvv ## _n ## _gen_syndrome(int disks, \ + size_t bytes, void **ptrs) \ + { \ + void raid6_rvv ## _n ## _gen_syndrome_real(int d, \ + unsigned long b, void **p); \ + kernel_vector_begin(); \ + raid6_rvv ## _n ## _gen_syndrome_real(disks, \ + (unsigned long)bytes, ptrs); \ + kernel_vector_end(); \ + } \ + static void raid6_rvv ## _n ## _xor_syndrome(int disks, \ + int start, int stop, \ + size_t bytes, void **ptrs) \ + { \ + void raid6_rvv ## _n ## _xor_syndrome_real(int d, \ + int s1, int s2, \ + unsigned long b, void **p); \ + kernel_vector_begin(); \ + raid6_rvv ## _n ## _xor_syndrome_real(disks, \ + start, stop, (unsigned long)bytes, ptrs); \ + kernel_vector_end(); \ + } \ + struct raid6_calls const raid6_rvvx ## _n = { \ + raid6_rvv ## _n ## _gen_syndrome, \ + raid6_rvv ## _n ## _xor_syndrome, \ + rvv_has_vector, \ + "rvvx" #_n, \ + 0 \ + } diff --git a/mm/Kconfig b/mm/Kconfig index f8bb8f070d0d..781be3240e21 100644 --- a/mm/Kconfig +++ b/mm/Kconfig @@ -1355,6 +1355,7 @@ config NUMA_MEMBLKS config NUMA_EMU bool "NUMA emulation" depends on NUMA_MEMBLKS + depends on X86 || GENERIC_ARCH_NUMA help Enable NUMA emulation. A flat machine will be split into virtual nodes when booted with "numa=fake=N", where N is the diff --git a/mm/damon/modules-common.c b/mm/damon/modules-common.c index 7cf96574cde7..86d58f8c4f63 100644 --- a/mm/damon/modules-common.c +++ b/mm/damon/modules-common.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Common Primitives for DAMON Modules + * Common Code for DAMON Modules * * Author: SeongJae Park <sj@kernel.org> */ diff --git a/mm/damon/modules-common.h b/mm/damon/modules-common.h index f49cdb417005..f103ad556368 100644 --- a/mm/damon/modules-common.h +++ b/mm/damon/modules-common.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* - * Common Primitives for DAMON Modules + * Common Code for DAMON Modules * * Author: SeongJae Park <sj@kernel.org> */ diff --git a/mm/damon/ops-common.c b/mm/damon/ops-common.c index 0db1fc70c84d..b43620fee6bb 100644 --- a/mm/damon/ops-common.c +++ b/mm/damon/ops-common.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Common Primitives for Data Access Monitoring + * Common Code for Data Access Monitoring * * Author: SeongJae Park <sj@kernel.org> */ diff --git a/mm/damon/ops-common.h b/mm/damon/ops-common.h index 18d837d11bce..cc9f5da9c012 100644 --- a/mm/damon/ops-common.h +++ b/mm/damon/ops-common.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* - * Common Primitives for Data Access Monitoring + * Common Code for Data Access Monitoring * * Author: SeongJae Park <sj@kernel.org> */ diff --git a/mm/damon/paddr.c b/mm/damon/paddr.c index e8464f7e0014..4102a8c5f992 100644 --- a/mm/damon/paddr.c +++ b/mm/damon/paddr.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * DAMON Primitives for The Physical Address Space + * DAMON Code for The Physical Address Space * * Author: SeongJae Park <sj@kernel.org> */ diff --git a/mm/damon/sysfs-common.c b/mm/damon/sysfs-common.c index 70edf45c2174..ffaf285e241a 100644 --- a/mm/damon/sysfs-common.c +++ b/mm/damon/sysfs-common.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Common Primitives for DAMON Sysfs Interface + * Common Code for DAMON Sysfs Interface * * Author: SeongJae Park <sj@kernel.org> */ diff --git a/mm/damon/sysfs-common.h b/mm/damon/sysfs-common.h index 70d84bdc9f5f..2099adee11d0 100644 --- a/mm/damon/sysfs-common.h +++ b/mm/damon/sysfs-common.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* - * Common Primitives for DAMON Sysfs Interface + * Common Code for DAMON Sysfs Interface * * Author: SeongJae Park <sj@kernel.org> */ diff --git a/mm/damon/vaddr.c b/mm/damon/vaddr.c index e6d99106a7f9..46554e49a478 100644 --- a/mm/damon/vaddr.c +++ b/mm/damon/vaddr.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * DAMON Primitives for Virtual Address Spaces + * DAMON Code for Virtual Address Spaces * * Author: SeongJae Park <sj@kernel.org> */ diff --git a/mm/hugetlb.c b/mm/hugetlb.c index f0b1d53079f9..8746ed2fec13 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -121,7 +121,7 @@ static void hugetlb_vma_lock_free(struct vm_area_struct *vma); static void hugetlb_vma_lock_alloc(struct vm_area_struct *vma); static void __hugetlb_vma_unlock_write_free(struct vm_area_struct *vma); static void hugetlb_unshare_pmds(struct vm_area_struct *vma, - unsigned long start, unsigned long end); + unsigned long start, unsigned long end, bool take_locks); static struct resv_map *vma_resv_map(struct vm_area_struct *vma); static void hugetlb_free_folio(struct folio *folio) @@ -5426,26 +5426,40 @@ static int hugetlb_vm_op_split(struct vm_area_struct *vma, unsigned long addr) { if (addr & ~(huge_page_mask(hstate_vma(vma)))) return -EINVAL; + return 0; +} +void hugetlb_split(struct vm_area_struct *vma, unsigned long addr) +{ /* * PMD sharing is only possible for PUD_SIZE-aligned address ranges * in HugeTLB VMAs. If we will lose PUD_SIZE alignment due to this * split, unshare PMDs in the PUD_SIZE interval surrounding addr now. + * This function is called in the middle of a VMA split operation, with + * MM, VMA and rmap all write-locked to prevent concurrent page table + * walks (except hardware and gup_fast()). */ + vma_assert_write_locked(vma); + i_mmap_assert_write_locked(vma->vm_file->f_mapping); + if (addr & ~PUD_MASK) { - /* - * hugetlb_vm_op_split is called right before we attempt to - * split the VMA. We will need to unshare PMDs in the old and - * new VMAs, so let's unshare before we split. - */ unsigned long floor = addr & PUD_MASK; unsigned long ceil = floor + PUD_SIZE; - if (floor >= vma->vm_start && ceil <= vma->vm_end) - hugetlb_unshare_pmds(vma, floor, ceil); + if (floor >= vma->vm_start && ceil <= vma->vm_end) { + /* + * Locking: + * Use take_locks=false here. + * The file rmap lock is already held. + * The hugetlb VMA lock can't be taken when we already + * hold the file rmap lock, and we don't need it because + * its purpose is to synchronize against concurrent page + * table walks, which are not possible thanks to the + * locks held by our caller. + */ + hugetlb_unshare_pmds(vma, floor, ceil, /* take_locks = */ false); + } } - - return 0; } static unsigned long hugetlb_vm_op_pagesize(struct vm_area_struct *vma) @@ -7615,6 +7629,13 @@ int huge_pmd_unshare(struct mm_struct *mm, struct vm_area_struct *vma, return 0; pud_clear(pud); + /* + * Once our caller drops the rmap lock, some other process might be + * using this page table as a normal, non-hugetlb page table. + * Wait for pending gup_fast() in other threads to finish before letting + * that happen. + */ + tlb_remove_table_sync_one(); ptdesc_pmd_pts_dec(virt_to_ptdesc(ptep)); mm_dec_nr_pmds(mm); return 1; @@ -7885,9 +7906,16 @@ void move_hugetlb_state(struct folio *old_folio, struct folio *new_folio, int re spin_unlock_irq(&hugetlb_lock); } +/* + * If @take_locks is false, the caller must ensure that no concurrent page table + * access can happen (except for gup_fast() and hardware page walks). + * If @take_locks is true, we take the hugetlb VMA lock (to lock out things like + * concurrent page fault handling) and the file rmap lock. + */ static void hugetlb_unshare_pmds(struct vm_area_struct *vma, unsigned long start, - unsigned long end) + unsigned long end, + bool take_locks) { struct hstate *h = hstate_vma(vma); unsigned long sz = huge_page_size(h); @@ -7911,8 +7939,12 @@ static void hugetlb_unshare_pmds(struct vm_area_struct *vma, mmu_notifier_range_init(&range, MMU_NOTIFY_CLEAR, 0, mm, start, end); mmu_notifier_invalidate_range_start(&range); - hugetlb_vma_lock_write(vma); - i_mmap_lock_write(vma->vm_file->f_mapping); + if (take_locks) { + hugetlb_vma_lock_write(vma); + i_mmap_lock_write(vma->vm_file->f_mapping); + } else { + i_mmap_assert_write_locked(vma->vm_file->f_mapping); + } for (address = start; address < end; address += PUD_SIZE) { ptep = hugetlb_walk(vma, address, sz); if (!ptep) @@ -7922,8 +7954,10 @@ static void hugetlb_unshare_pmds(struct vm_area_struct *vma, spin_unlock(ptl); } flush_hugetlb_tlb_range(vma, start, end); - i_mmap_unlock_write(vma->vm_file->f_mapping); - hugetlb_vma_unlock_write(vma); + if (take_locks) { + i_mmap_unlock_write(vma->vm_file->f_mapping); + hugetlb_vma_unlock_write(vma); + } /* * No need to call mmu_notifier_arch_invalidate_secondary_tlbs(), see * Documentation/mm/mmu_notifier.rst. @@ -7938,7 +7972,8 @@ static void hugetlb_unshare_pmds(struct vm_area_struct *vma, void hugetlb_unshare_all_pmds(struct vm_area_struct *vma) { hugetlb_unshare_pmds(vma, ALIGN(vma->vm_start, PUD_SIZE), - ALIGN_DOWN(vma->vm_end, PUD_SIZE)); + ALIGN_DOWN(vma->vm_end, PUD_SIZE), + /* take_locks = */ true); } /* diff --git a/mm/kmsan/kmsan_test.c b/mm/kmsan/kmsan_test.c index 9733a22c46c1..c6c5b2bbede0 100644 --- a/mm/kmsan/kmsan_test.c +++ b/mm/kmsan/kmsan_test.c @@ -732,3 +732,4 @@ kunit_test_suites(&kmsan_test_suite); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Alexander Potapenko <glider@google.com>"); +MODULE_DESCRIPTION("Test cases for KMSAN"); diff --git a/mm/madvise.c b/mm/madvise.c index 8433ac9b27e0..5f7a66a1617e 100644 --- a/mm/madvise.c +++ b/mm/madvise.c @@ -1881,7 +1881,9 @@ static ssize_t vector_madvise(struct mm_struct *mm, struct iov_iter *iter, /* Drop and reacquire lock to unwind race. */ madvise_finish_tlb(&madv_behavior); madvise_unlock(mm, behavior); - madvise_lock(mm, behavior); + ret = madvise_lock(mm, behavior); + if (ret) + goto out; madvise_init_tlb(&madv_behavior, mm); continue; } @@ -1892,6 +1894,7 @@ static ssize_t vector_madvise(struct mm_struct *mm, struct iov_iter *iter, madvise_finish_tlb(&madv_behavior); madvise_unlock(mm, behavior); +out: ret = (total_len - iov_iter_count(iter)) ? : ret; return ret; diff --git a/mm/mempolicy.c b/mm/mempolicy.c index 72fd72e156b1..3b1dfd08338b 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -3708,15 +3708,13 @@ static void wi_state_free(void) lockdep_is_held(&wi_state_lock)); if (!old_wi_state) { mutex_unlock(&wi_state_lock); - goto out; + return; } rcu_assign_pointer(wi_state, NULL); mutex_unlock(&wi_state_lock); synchronize_rcu(); kfree(old_wi_state); -out: - kfree(&wi_group->wi_kobj); } static struct kobj_attribute wi_auto_attr = diff --git a/mm/mremap.c b/mm/mremap.c index 83e359754961..60f6b8d0d5f0 100644 --- a/mm/mremap.c +++ b/mm/mremap.c @@ -237,6 +237,8 @@ static int move_ptes(struct pagetable_move_control *pmc, for (; old_addr < old_end; old_pte++, old_addr += PAGE_SIZE, new_pte++, new_addr += PAGE_SIZE) { + VM_WARN_ON_ONCE(!pte_none(*new_pte)); + if (pte_none(ptep_get(old_pte))) continue; diff --git a/mm/page-writeback.c b/mm/page-writeback.c index b8eea5b3c064..72b0ff0d4bae 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c @@ -608,7 +608,7 @@ EXPORT_SYMBOL_GPL(wb_writeout_inc); */ static void writeout_period(struct timer_list *t) { - struct wb_domain *dom = from_timer(dom, t, period_timer); + struct wb_domain *dom = timer_container_of(dom, t, period_timer); int miss_periods = (jiffies - dom->period_time) / VM_COMPLETIONS_PERIOD_LEN; @@ -2203,7 +2203,7 @@ static int dirty_writeback_centisecs_handler(const struct ctl_table *table, int void laptop_mode_timer_fn(struct timer_list *t) { struct backing_dev_info *backing_dev_info = - from_timer(backing_dev_info, t, laptop_mode_wb_timer); + timer_container_of(backing_dev_info, t, laptop_mode_wb_timer); wakeup_flusher_threads_bdi(backing_dev_info, WB_REASON_LAPTOP_TIMER); } @@ -169,6 +169,9 @@ static void init_multi_vma_prep(struct vma_prepare *vp, vp->file = vma->vm_file; if (vp->file) vp->mapping = vma->vm_file->f_mapping; + + if (vmg && vmg->skip_vma_uprobe) + vp->skip_vma_uprobe = true; } /* @@ -358,10 +361,13 @@ static void vma_complete(struct vma_prepare *vp, struct vma_iterator *vmi, if (vp->file) { i_mmap_unlock_write(vp->mapping); - uprobe_mmap(vp->vma); - if (vp->adj_next) - uprobe_mmap(vp->adj_next); + if (!vp->skip_vma_uprobe) { + uprobe_mmap(vp->vma); + + if (vp->adj_next) + uprobe_mmap(vp->adj_next); + } } if (vp->remove) { @@ -539,7 +545,14 @@ __split_vma(struct vma_iterator *vmi, struct vm_area_struct *vma, init_vma_prep(&vp, vma); vp.insert = new; vma_prepare(&vp); + + /* + * Get rid of huge pages and shared page tables straddling the split + * boundary. + */ vma_adjust_trans_huge(vma, vma->vm_start, addr, NULL); + if (is_vm_hugetlb_page(vma)) + hugetlb_split(vma, addr); if (new_below) { vma->vm_start = addr; @@ -1823,6 +1836,14 @@ struct vm_area_struct *copy_vma(struct vm_area_struct **vmap, faulted_in_anon_vma = false; } + /* + * If the VMA we are copying might contain a uprobe PTE, ensure + * that we do not establish one upon merge. Otherwise, when mremap() + * moves page tables, it will orphan the newly created PTE. + */ + if (vma->vm_file) + vmg.skip_vma_uprobe = true; + new_vma = find_vma_prev(mm, addr, &vmg.prev); if (new_vma && new_vma->vm_start < addr + len) return NULL; /* should never get here */ @@ -19,6 +19,8 @@ struct vma_prepare { struct vm_area_struct *insert; struct vm_area_struct *remove; struct vm_area_struct *remove2; + + bool skip_vma_uprobe :1; }; struct unlink_vma_file_batch { @@ -120,6 +122,11 @@ struct vma_merge_struct { */ bool give_up_on_oom :1; + /* + * If set, skip uprobe_mmap upon merged vma. + */ + bool skip_vma_uprobe :1; + /* Internal flags set during merge process: */ /* diff --git a/mm/vmstat.c b/mm/vmstat.c index 6f740f070b3d..429ae5339bfe 100644 --- a/mm/vmstat.c +++ b/mm/vmstat.c @@ -1201,7 +1201,6 @@ const char * const vmstat_text[] = { "nr_zone_unevictable", "nr_zone_write_pending", "nr_mlock", - "nr_bounce", #if IS_ENABLED(CONFIG_ZSMALLOC) "nr_zspages", #endif diff --git a/net/802/garp.c b/net/802/garp.c index 27f0ab146026..2d1ffc4d9462 100644 --- a/net/802/garp.c +++ b/net/802/garp.c @@ -414,7 +414,7 @@ static void garp_join_timer_arm(struct garp_applicant *app) static void garp_join_timer(struct timer_list *t) { - struct garp_applicant *app = from_timer(app, t, join_timer); + struct garp_applicant *app = timer_container_of(app, t, join_timer); spin_lock(&app->lock); garp_gid_event(app, GARP_EVENT_TRANSMIT_PDU); diff --git a/net/802/mrp.c b/net/802/mrp.c index e0c96d0da8d5..23a88305f900 100644 --- a/net/802/mrp.c +++ b/net/802/mrp.c @@ -599,7 +599,7 @@ static void mrp_join_timer_arm(struct mrp_applicant *app) static void mrp_join_timer(struct timer_list *t) { - struct mrp_applicant *app = from_timer(app, t, join_timer); + struct mrp_applicant *app = timer_container_of(app, t, join_timer); spin_lock(&app->lock); mrp_mad_event(app, MRP_EVENT_TX); @@ -621,7 +621,7 @@ static void mrp_periodic_timer_arm(struct mrp_applicant *app) static void mrp_periodic_timer(struct timer_list *t) { - struct mrp_applicant *app = from_timer(app, t, periodic_timer); + struct mrp_applicant *app = timer_container_of(app, t, periodic_timer); spin_lock(&app->lock); if (likely(app->active)) { diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c index b068651984fe..73ea7e67f05a 100644 --- a/net/appletalk/ddp.c +++ b/net/appletalk/ddp.c @@ -169,7 +169,7 @@ found: static void atalk_destroy_timer(struct timer_list *t) { - struct sock *sk = from_timer(sk, t, sk_timer); + struct sock *sk = timer_container_of(sk, t, sk_timer); if (sk_has_allocations(sk)) { sk->sk_timer.expires = jiffies + SOCK_DESTROY_TIME; diff --git a/net/atm/lec.c b/net/atm/lec.c index ded2f0df2ee6..acef984f3367 100644 --- a/net/atm/lec.c +++ b/net/atm/lec.c @@ -1551,7 +1551,7 @@ static void lec_arp_expire_arp(struct timer_list *t) { struct lec_arp_table *entry; - entry = from_timer(entry, t, timer); + entry = timer_container_of(entry, t, timer); pr_debug("\n"); if (entry->status == ESI_ARP_PENDING) { @@ -1572,7 +1572,8 @@ static void lec_arp_expire_arp(struct timer_list *t) static void lec_arp_expire_vcc(struct timer_list *t) { unsigned long flags; - struct lec_arp_table *to_remove = from_timer(to_remove, t, timer); + struct lec_arp_table *to_remove = timer_container_of(to_remove, t, + timer); struct lec_priv *priv = to_remove->priv; timer_delete(&to_remove->timer); diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c index b790bb92ed1c..6ef8b2a57a9b 100644 --- a/net/ax25/af_ax25.c +++ b/net/ax25/af_ax25.c @@ -287,7 +287,7 @@ void ax25_destroy_socket(ax25_cb *); */ static void ax25_destroy_timer(struct timer_list *t) { - ax25_cb *ax25 = from_timer(ax25, t, dtimer); + ax25_cb *ax25 = timer_container_of(ax25, t, dtimer); struct sock *sk; sk=ax25->sk; diff --git a/net/ax25/ax25_ds_timer.c b/net/ax25/ax25_ds_timer.c index 8d9fba069001..0c9e7775aa54 100644 --- a/net/ax25/ax25_ds_timer.c +++ b/net/ax25/ax25_ds_timer.c @@ -64,7 +64,7 @@ void ax25_ds_set_timer(ax25_dev *ax25_dev) static void ax25_ds_timeout(struct timer_list *t) { - ax25_dev *ax25_dev = from_timer(ax25_dev, t, dama.slave_timer); + ax25_dev *ax25_dev = timer_container_of(ax25_dev, t, dama.slave_timer); ax25_cb *ax25; if (ax25_dev == NULL || !ax25_dev->dama.slave) diff --git a/net/ax25/ax25_timer.c b/net/ax25/ax25_timer.c index 3891a3923d6c..a69bfbc8b679 100644 --- a/net/ax25/ax25_timer.c +++ b/net/ax25/ax25_timer.c @@ -121,7 +121,7 @@ EXPORT_SYMBOL(ax25_display_timer); static void ax25_heartbeat_expiry(struct timer_list *t) { int proto = AX25_PROTO_STD_SIMPLEX; - ax25_cb *ax25 = from_timer(ax25, t, timer); + ax25_cb *ax25 = timer_container_of(ax25, t, timer); if (ax25->ax25_dev) proto = ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]; @@ -145,7 +145,7 @@ static void ax25_heartbeat_expiry(struct timer_list *t) static void ax25_t1timer_expiry(struct timer_list *t) { - ax25_cb *ax25 = from_timer(ax25, t, t1timer); + ax25_cb *ax25 = timer_container_of(ax25, t, t1timer); switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) { case AX25_PROTO_STD_SIMPLEX: @@ -164,7 +164,7 @@ static void ax25_t1timer_expiry(struct timer_list *t) static void ax25_t2timer_expiry(struct timer_list *t) { - ax25_cb *ax25 = from_timer(ax25, t, t2timer); + ax25_cb *ax25 = timer_container_of(ax25, t, t2timer); switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) { case AX25_PROTO_STD_SIMPLEX: @@ -183,7 +183,7 @@ static void ax25_t2timer_expiry(struct timer_list *t) static void ax25_t3timer_expiry(struct timer_list *t) { - ax25_cb *ax25 = from_timer(ax25, t, t3timer); + ax25_cb *ax25 = timer_container_of(ax25, t, t3timer); switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) { case AX25_PROTO_STD_SIMPLEX: @@ -204,7 +204,7 @@ static void ax25_t3timer_expiry(struct timer_list *t) static void ax25_idletimer_expiry(struct timer_list *t) { - ax25_cb *ax25 = from_timer(ax25, t, idletimer); + ax25_cb *ax25 = timer_container_of(ax25, t, idletimer); switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) { case AX25_PROTO_STD_SIMPLEX: diff --git a/net/batman-adv/tp_meter.c b/net/batman-adv/tp_meter.c index adbadb436033..350b149e48be 100644 --- a/net/batman-adv/tp_meter.c +++ b/net/batman-adv/tp_meter.c @@ -485,7 +485,7 @@ static void batadv_tp_reset_sender_timer(struct batadv_tp_vars *tp_vars) */ static void batadv_tp_sender_timeout(struct timer_list *t) { - struct batadv_tp_vars *tp_vars = from_timer(tp_vars, t, timer); + struct batadv_tp_vars *tp_vars = timer_container_of(tp_vars, t, timer); struct batadv_priv *bat_priv = tp_vars->bat_priv; if (atomic_read(&tp_vars->sending) == 0) @@ -1101,7 +1101,7 @@ static void batadv_tp_reset_receiver_timer(struct batadv_tp_vars *tp_vars) */ static void batadv_tp_receiver_shutdown(struct timer_list *t) { - struct batadv_tp_vars *tp_vars = from_timer(tp_vars, t, timer); + struct batadv_tp_vars *tp_vars = timer_container_of(tp_vars, t, timer); struct batadv_tp_unacked *un, *safe; struct batadv_priv *bat_priv; diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c index fc5af8639b1e..6724adce615b 100644 --- a/net/bluetooth/hidp/core.c +++ b/net/bluetooth/hidp/core.c @@ -405,7 +405,7 @@ static int hidp_raw_request(struct hid_device *hid, unsigned char reportnum, static void hidp_idle_timeout(struct timer_list *t) { - struct hidp_session *session = from_timer(session, t, timer); + struct hidp_session *session = timer_container_of(session, t, timer); /* The HIDP user-space API only contains calls to add and remove * devices. There is no way to forward events of any kind. Therefore, diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index 20ea7dba0a9a..3b8f39618d65 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c @@ -235,7 +235,7 @@ static int rfcomm_check_security(struct rfcomm_dlc *d) static void rfcomm_session_timeout(struct timer_list *t) { - struct rfcomm_session *s = from_timer(s, t, timer); + struct rfcomm_session *s = timer_container_of(s, t, timer); BT_DBG("session %p state %ld", s, s->state); @@ -260,7 +260,7 @@ static void rfcomm_session_clear_timer(struct rfcomm_session *s) /* ---- RFCOMM DLCs ---- */ static void rfcomm_dlc_timeout(struct timer_list *t) { - struct rfcomm_dlc *d = from_timer(d, t, timer); + struct rfcomm_dlc *d = timer_container_of(d, t, timer); BT_DBG("dlc %p state %ld", d, d->state); diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c index fb6f7f2001c9..0224ef3dfec0 100644 --- a/net/bridge/br_multicast.c +++ b/net/bridge/br_multicast.c @@ -648,7 +648,7 @@ static void br_multicast_del_mdb_entry(struct net_bridge_mdb_entry *mp) static void br_multicast_group_expired(struct timer_list *t) { - struct net_bridge_mdb_entry *mp = from_timer(mp, t, timer); + struct net_bridge_mdb_entry *mp = timer_container_of(mp, t, timer); struct net_bridge *br = mp->br; spin_lock(&br->multicast_lock); @@ -856,7 +856,7 @@ static void br_multicast_find_del_pg(struct net_bridge *br, static void br_multicast_port_group_expired(struct timer_list *t) { - struct net_bridge_port_group *pg = from_timer(pg, t, timer); + struct net_bridge_port_group *pg = timer_container_of(pg, t, timer); struct net_bridge_group_src *src_ent; struct net_bridge *br = pg->key.port->br; struct hlist_node *tmp; @@ -1314,7 +1314,7 @@ struct net_bridge_mdb_entry *br_multicast_new_group(struct net_bridge *br, static void br_multicast_group_src_expired(struct timer_list *t) { - struct net_bridge_group_src *src = from_timer(src, t, timer); + struct net_bridge_group_src *src = timer_container_of(src, t, timer); struct net_bridge_port_group *pg; struct net_bridge *br = src->br; @@ -1667,8 +1667,8 @@ out: static void br_ip4_multicast_router_expired(struct timer_list *t) { - struct net_bridge_mcast_port *pmctx = from_timer(pmctx, t, - ip4_mc_router_timer); + struct net_bridge_mcast_port *pmctx = timer_container_of(pmctx, t, + ip4_mc_router_timer); br_multicast_router_expired(pmctx, t, &pmctx->ip4_rlist); } @@ -1676,8 +1676,8 @@ static void br_ip4_multicast_router_expired(struct timer_list *t) #if IS_ENABLED(CONFIG_IPV6) static void br_ip6_multicast_router_expired(struct timer_list *t) { - struct net_bridge_mcast_port *pmctx = from_timer(pmctx, t, - ip6_mc_router_timer); + struct net_bridge_mcast_port *pmctx = timer_container_of(pmctx, t, + ip6_mc_router_timer); br_multicast_router_expired(pmctx, t, &pmctx->ip6_rlist); } @@ -1713,8 +1713,8 @@ out: static void br_ip4_multicast_local_router_expired(struct timer_list *t) { - struct net_bridge_mcast *brmctx = from_timer(brmctx, t, - ip4_mc_router_timer); + struct net_bridge_mcast *brmctx = timer_container_of(brmctx, t, + ip4_mc_router_timer); br_multicast_local_router_expired(brmctx, t); } @@ -1722,8 +1722,8 @@ static void br_ip4_multicast_local_router_expired(struct timer_list *t) #if IS_ENABLED(CONFIG_IPV6) static void br_ip6_multicast_local_router_expired(struct timer_list *t) { - struct net_bridge_mcast *brmctx = from_timer(brmctx, t, - ip6_mc_router_timer); + struct net_bridge_mcast *brmctx = timer_container_of(brmctx, t, + ip6_mc_router_timer); br_multicast_local_router_expired(brmctx, t); } @@ -1746,8 +1746,8 @@ out: static void br_ip4_multicast_querier_expired(struct timer_list *t) { - struct net_bridge_mcast *brmctx = from_timer(brmctx, t, - ip4_other_query.timer); + struct net_bridge_mcast *brmctx = timer_container_of(brmctx, t, + ip4_other_query.timer); br_multicast_querier_expired(brmctx, &brmctx->ip4_own_query); } @@ -1755,8 +1755,8 @@ static void br_ip4_multicast_querier_expired(struct timer_list *t) #if IS_ENABLED(CONFIG_IPV6) static void br_ip6_multicast_querier_expired(struct timer_list *t) { - struct net_bridge_mcast *brmctx = from_timer(brmctx, t, - ip6_other_query.timer); + struct net_bridge_mcast *brmctx = timer_container_of(brmctx, t, + ip6_other_query.timer); br_multicast_querier_expired(brmctx, &brmctx->ip6_own_query); } @@ -1918,8 +1918,8 @@ out: static void br_ip4_multicast_port_query_expired(struct timer_list *t) { - struct net_bridge_mcast_port *pmctx = from_timer(pmctx, t, - ip4_own_query.timer); + struct net_bridge_mcast_port *pmctx = timer_container_of(pmctx, t, + ip4_own_query.timer); br_multicast_port_query_expired(pmctx, &pmctx->ip4_own_query); } @@ -1927,8 +1927,8 @@ static void br_ip4_multicast_port_query_expired(struct timer_list *t) #if IS_ENABLED(CONFIG_IPV6) static void br_ip6_multicast_port_query_expired(struct timer_list *t) { - struct net_bridge_mcast_port *pmctx = from_timer(pmctx, t, - ip6_own_query.timer); + struct net_bridge_mcast_port *pmctx = timer_container_of(pmctx, t, + ip6_own_query.timer); br_multicast_port_query_expired(pmctx, &pmctx->ip6_own_query); } @@ -1936,7 +1936,8 @@ static void br_ip6_multicast_port_query_expired(struct timer_list *t) static void br_multicast_port_group_rexmit(struct timer_list *t) { - struct net_bridge_port_group *pg = from_timer(pg, t, rexmit_timer); + struct net_bridge_port_group *pg = timer_container_of(pg, t, + rexmit_timer); struct bridge_mcast_other_query *other_query = NULL; struct net_bridge *br = pg->key.port->br; struct net_bridge_mcast_port *pmctx; @@ -4056,8 +4057,8 @@ out: static void br_ip4_multicast_query_expired(struct timer_list *t) { - struct net_bridge_mcast *brmctx = from_timer(brmctx, t, - ip4_own_query.timer); + struct net_bridge_mcast *brmctx = timer_container_of(brmctx, t, + ip4_own_query.timer); br_multicast_query_expired(brmctx, &brmctx->ip4_own_query, &brmctx->ip4_querier); @@ -4066,8 +4067,8 @@ static void br_ip4_multicast_query_expired(struct timer_list *t) #if IS_ENABLED(CONFIG_IPV6) static void br_ip6_multicast_query_expired(struct timer_list *t) { - struct net_bridge_mcast *brmctx = from_timer(brmctx, t, - ip6_own_query.timer); + struct net_bridge_mcast *brmctx = timer_container_of(brmctx, t, + ip6_own_query.timer); br_multicast_query_expired(brmctx, &brmctx->ip6_own_query, &brmctx->ip6_querier); diff --git a/net/bridge/br_multicast_eht.c b/net/bridge/br_multicast_eht.c index c126aa4e7551..adfd74102019 100644 --- a/net/bridge/br_multicast_eht.c +++ b/net/bridge/br_multicast_eht.c @@ -207,7 +207,9 @@ void br_multicast_eht_clean_sets(struct net_bridge_port_group *pg) static void br_multicast_eht_set_entry_expired(struct timer_list *t) { - struct net_bridge_group_eht_set_entry *set_h = from_timer(set_h, t, timer); + struct net_bridge_group_eht_set_entry *set_h = timer_container_of(set_h, + t, + timer); struct net_bridge *br = set_h->br; spin_lock(&br->multicast_lock); @@ -223,8 +225,9 @@ out: static void br_multicast_eht_set_expired(struct timer_list *t) { - struct net_bridge_group_eht_set *eht_set = from_timer(eht_set, t, - timer); + struct net_bridge_group_eht_set *eht_set = timer_container_of(eht_set, + t, + timer); struct net_bridge *br = eht_set->br; spin_lock(&br->multicast_lock); diff --git a/net/bridge/br_stp_timer.c b/net/bridge/br_stp_timer.c index 27bf1979b909..e5d453305381 100644 --- a/net/bridge/br_stp_timer.c +++ b/net/bridge/br_stp_timer.c @@ -29,7 +29,7 @@ static int br_is_designated_for_some_port(const struct net_bridge *br) static void br_hello_timer_expired(struct timer_list *t) { - struct net_bridge *br = from_timer(br, t, hello_timer); + struct net_bridge *br = timer_container_of(br, t, hello_timer); br_debug(br, "hello timer expired\n"); spin_lock(&br->lock); @@ -45,7 +45,8 @@ static void br_hello_timer_expired(struct timer_list *t) static void br_message_age_timer_expired(struct timer_list *t) { - struct net_bridge_port *p = from_timer(p, t, message_age_timer); + struct net_bridge_port *p = timer_container_of(p, t, + message_age_timer); struct net_bridge *br = p->br; const bridge_id *id = &p->designated_bridge; int was_root; @@ -78,7 +79,8 @@ static void br_message_age_timer_expired(struct timer_list *t) static void br_forward_delay_timer_expired(struct timer_list *t) { - struct net_bridge_port *p = from_timer(p, t, forward_delay_timer); + struct net_bridge_port *p = timer_container_of(p, t, + forward_delay_timer); struct net_bridge *br = p->br; br_debug(br, "port %u(%s) forward delay timer\n", @@ -102,7 +104,7 @@ static void br_forward_delay_timer_expired(struct timer_list *t) static void br_tcn_timer_expired(struct timer_list *t) { - struct net_bridge *br = from_timer(br, t, tcn_timer); + struct net_bridge *br = timer_container_of(br, t, tcn_timer); br_debug(br, "tcn timer expired\n"); spin_lock(&br->lock); @@ -116,7 +118,8 @@ static void br_tcn_timer_expired(struct timer_list *t) static void br_topology_change_timer_expired(struct timer_list *t) { - struct net_bridge *br = from_timer(br, t, topology_change_timer); + struct net_bridge *br = timer_container_of(br, t, + topology_change_timer); br_debug(br, "topo change timer expired\n"); spin_lock(&br->lock); @@ -127,7 +130,7 @@ static void br_topology_change_timer_expired(struct timer_list *t) static void br_hold_timer_expired(struct timer_list *t) { - struct net_bridge_port *p = from_timer(p, t, hold_timer); + struct net_bridge_port *p = timer_container_of(p, t, hold_timer); br_debug(p->br, "port %u(%s) hold timer expired\n", (unsigned int) p->port_no, p->dev->name); diff --git a/net/can/proc.c b/net/can/proc.c index 25fdf060e30d..0938bf7dd646 100644 --- a/net/can/proc.c +++ b/net/can/proc.c @@ -114,7 +114,7 @@ static unsigned long calc_rate(unsigned long oldjif, unsigned long newjif, void can_stat_update(struct timer_list *t) { - struct net *net = from_timer(net, t, can.stattimer); + struct net *net = timer_container_of(net, t, can.stattimer); struct can_pkg_stats *pkg_stats = net->can.pkg_stats; unsigned long j = jiffies; /* snapshot */ diff --git a/net/core/drop_monitor.c b/net/core/drop_monitor.c index 8a7ce640f74d..60d31c2feed3 100644 --- a/net/core/drop_monitor.c +++ b/net/core/drop_monitor.c @@ -208,7 +208,7 @@ static void send_dm_alert(struct work_struct *work) */ static void sched_send_work(struct timer_list *t) { - struct per_cpu_dm_data *data = from_timer(data, t, send_timer); + struct per_cpu_dm_data *data = timer_container_of(data, t, send_timer); schedule_work(&data->dm_alert_work); } diff --git a/net/core/gen_estimator.c b/net/core/gen_estimator.c index 2b821b9a8699..7d426a8e29f3 100644 --- a/net/core/gen_estimator.c +++ b/net/core/gen_estimator.c @@ -75,7 +75,7 @@ static void est_fetch_counters(struct net_rate_estimator *e, static void est_timer(struct timer_list *t) { - struct net_rate_estimator *est = from_timer(est, t, timer); + struct net_rate_estimator *est = timer_container_of(est, t, timer); struct gnet_stats_basic_sync b; u64 b_bytes, b_packets; u64 rate, brate; diff --git a/net/core/neighbour.c b/net/core/neighbour.c index a6e2c91ec3e7..49dce9a82295 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -1031,7 +1031,7 @@ static void neigh_probe(struct neighbour *neigh) static void neigh_timer_handler(struct timer_list *t) { unsigned long now, next; - struct neighbour *neigh = from_timer(neigh, t, timer); + struct neighbour *neigh = timer_container_of(neigh, t, timer); unsigned int state; int notify = 0; @@ -1569,7 +1569,7 @@ static void neigh_managed_work(struct work_struct *work) static void neigh_proxy_process(struct timer_list *t) { - struct neigh_table *tbl = from_timer(tbl, t, proxy_timer); + struct neigh_table *tbl = timer_container_of(tbl, t, proxy_timer); long sched_next = 0; unsigned long now = jiffies; struct sk_buff *skb, *n; diff --git a/net/ethtool/mm.c b/net/ethtool/mm.c index ad9b40034003..29bbbc149375 100644 --- a/net/ethtool/mm.c +++ b/net/ethtool/mm.c @@ -315,7 +315,7 @@ static void ethtool_mmsv_send_mpacket(struct ethtool_mmsv *mmsv, */ static void ethtool_mmsv_verify_timer(struct timer_list *t) { - struct ethtool_mmsv *mmsv = from_timer(mmsv, t, verify_timer); + struct ethtool_mmsv *mmsv = timer_container_of(mmsv, t, verify_timer); unsigned long flags; bool rearm = false; diff --git a/net/hsr/hsr_device.c b/net/hsr/hsr_device.c index 0d1e56965af0..88657255fec1 100644 --- a/net/hsr/hsr_device.c +++ b/net/hsr/hsr_device.c @@ -408,7 +408,7 @@ static void hsr_announce(struct timer_list *t) struct hsr_port *master; unsigned long interval; - hsr = from_timer(hsr, t, announce_timer); + hsr = timer_container_of(hsr, t, announce_timer); rcu_read_lock(); master = hsr_port_get_hsr(hsr, HSR_PT_MASTER); @@ -424,7 +424,8 @@ static void hsr_announce(struct timer_list *t) */ static void hsr_proxy_announce(struct timer_list *t) { - struct hsr_priv *hsr = from_timer(hsr, t, announce_proxy_timer); + struct hsr_priv *hsr = timer_container_of(hsr, t, + announce_proxy_timer); struct hsr_port *interlink; unsigned long interval = 0; struct hsr_node *node; diff --git a/net/hsr/hsr_framereg.c b/net/hsr/hsr_framereg.c index 4ce471a2f387..3a2a2fa7a0a3 100644 --- a/net/hsr/hsr_framereg.c +++ b/net/hsr/hsr_framereg.c @@ -617,7 +617,7 @@ static struct hsr_port *get_late_port(struct hsr_priv *hsr, */ void hsr_prune_nodes(struct timer_list *t) { - struct hsr_priv *hsr = from_timer(hsr, t, prune_timer); + struct hsr_priv *hsr = timer_container_of(hsr, t, prune_timer); struct hsr_node *node; struct hsr_node *tmp; struct hsr_port *port; @@ -685,7 +685,7 @@ void hsr_prune_nodes(struct timer_list *t) void hsr_prune_proxy_nodes(struct timer_list *t) { - struct hsr_priv *hsr = from_timer(hsr, t, prune_proxy_timer); + struct hsr_priv *hsr = timer_container_of(hsr, t, prune_proxy_timer); unsigned long timestamp; struct hsr_node *node; struct hsr_node *tmp; diff --git a/net/ieee802154/6lowpan/reassembly.c b/net/ieee802154/6lowpan/reassembly.c index d4b983d17038..ddb6a5817d09 100644 --- a/net/ieee802154/6lowpan/reassembly.c +++ b/net/ieee802154/6lowpan/reassembly.c @@ -44,7 +44,7 @@ static void lowpan_frag_init(struct inet_frag_queue *q, const void *a) static void lowpan_frag_expire(struct timer_list *t) { - struct inet_frag_queue *frag = from_timer(frag, t, timer); + struct inet_frag_queue *frag = timer_container_of(frag, t, timer); struct frag_queue *fq; int refs = 1; diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index ca7d539b3846..d1769034b643 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -801,7 +801,7 @@ static int igmp_send_report(struct in_device *in_dev, struct ip_mc_list *pmc, static void igmp_gq_timer_expire(struct timer_list *t) { - struct in_device *in_dev = from_timer(in_dev, t, mr_gq_timer); + struct in_device *in_dev = timer_container_of(in_dev, t, mr_gq_timer); in_dev->mr_gq_running = 0; igmpv3_send_report(in_dev, NULL); @@ -810,7 +810,7 @@ static void igmp_gq_timer_expire(struct timer_list *t) static void igmp_ifc_timer_expire(struct timer_list *t) { - struct in_device *in_dev = from_timer(in_dev, t, mr_ifc_timer); + struct in_device *in_dev = timer_container_of(in_dev, t, mr_ifc_timer); u32 mr_ifc_count; igmpv3_send_cr(in_dev); @@ -840,7 +840,7 @@ static void igmp_ifc_event(struct in_device *in_dev) static void igmp_timer_expire(struct timer_list *t) { - struct ip_mc_list *im = from_timer(im, t, timer); + struct ip_mc_list *im = timer_container_of(im, t, timer); struct in_device *in_dev = im->interface; spin_lock(&im->lock); diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index 20915895bdaa..6906bedad19a 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -1065,7 +1065,7 @@ EXPORT_IPV6_MOD(inet_csk_reqsk_queue_drop_and_put); static void reqsk_timer_handler(struct timer_list *t) { - struct request_sock *req = from_timer(req, t, rsk_timer); + struct request_sock *req = timer_container_of(req, t, rsk_timer); struct request_sock *nreq = NULL, *oreq = req; struct sock *sk_listener = req->rsk_listener; struct inet_connection_sock *icsk; diff --git a/net/ipv4/inet_timewait_sock.c b/net/ipv4/inet_timewait_sock.c index 67efe9501581..875ff923a8ed 100644 --- a/net/ipv4/inet_timewait_sock.c +++ b/net/ipv4/inet_timewait_sock.c @@ -169,7 +169,7 @@ void inet_twsk_hashdance_schedule(struct inet_timewait_sock *tw, static void tw_timer_handler(struct timer_list *t) { - struct inet_timewait_sock *tw = from_timer(tw, t, tw_timer); + struct inet_timewait_sock *tw = timer_container_of(tw, t, tw_timer); inet_twsk_kill(tw); } diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index 77f395b28ec7..64b3fb3208af 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -123,7 +123,7 @@ static bool frag_expire_skip_icmp(u32 user) static void ip_expire(struct timer_list *t) { enum skb_drop_reason reason = SKB_DROP_REASON_FRAG_REASM_TIMEOUT; - struct inet_frag_queue *frag = from_timer(frag, t, timer); + struct inet_frag_queue *frag = timer_container_of(frag, t, timer); const struct iphdr *iph; struct sk_buff *head = NULL; struct net *net; diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index 2ff2f79c7351..a7d09ae9d761 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -765,7 +765,7 @@ static void ipmr_destroy_unres(struct mr_table *mrt, struct mfc_cache *c) /* Timer process for the unresolved queue. */ static void ipmr_expire_process(struct timer_list *t) { - struct mr_table *mrt = from_timer(mrt, t, ipmr_expire_timer); + struct mr_table *mrt = timer_container_of(mrt, t, ipmr_expire_timer); struct mr_mfc *c, *next; unsigned long expires; unsigned long now; diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c index e4c616bbd727..bb37e24b97a7 100644 --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c @@ -359,7 +359,7 @@ void tcp_delack_timer_handler(struct sock *sk) static void tcp_delack_timer(struct timer_list *t) { struct inet_connection_sock *icsk = - from_timer(icsk, t, icsk_delack_timer); + timer_container_of(icsk, t, icsk_delack_timer); struct sock *sk = &icsk->icsk_inet.sk; /* Avoid taking socket spinlock if there is no ACK to send. @@ -726,7 +726,7 @@ void tcp_write_timer_handler(struct sock *sk) static void tcp_write_timer(struct timer_list *t) { struct inet_connection_sock *icsk = - from_timer(icsk, t, icsk_retransmit_timer); + timer_container_of(icsk, t, icsk_retransmit_timer); struct sock *sk = &icsk->icsk_inet.sk; /* Avoid locking the socket when there is no pending event. */ @@ -778,7 +778,7 @@ EXPORT_IPV6_MOD_GPL(tcp_set_keepalive); static void tcp_keepalive_timer(struct timer_list *t) { - struct sock *sk = from_timer(sk, t, sk_timer); + struct sock *sk = timer_container_of(sk, t, sk_timer); struct inet_connection_sock *icsk = inet_csk(sk); struct tcp_sock *tp = tcp_sk(sk); u32 elapsed; diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 43b19adfbf88..ba2ec7c870cc 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -4017,7 +4017,7 @@ restart: static void addrconf_rs_timer(struct timer_list *t) { - struct inet6_dev *idev = from_timer(idev, t, rs_timer); + struct inet6_dev *idev = timer_container_of(idev, t, rs_timer); struct net_device *dev = idev->dev; struct in6_addr lladdr; int rtr_solicits; diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index 7094d7708686..93578b2ec35f 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -2442,7 +2442,7 @@ void fib6_run_gc(unsigned long expires, struct net *net, bool force) static void fib6_gc_timer_cb(struct timer_list *t) { - struct net *arg = from_timer(arg, t, ipv6.ip6_fib_timer); + struct net *arg = timer_container_of(arg, t, ipv6.ip6_fib_timer); fib6_run_gc(0, arg, true); } diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index 3276cde5ebd7..9db31e5b998c 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c @@ -839,7 +839,7 @@ static void ipmr_do_expire_process(struct mr_table *mrt) static void ipmr_expire_process(struct timer_list *t) { - struct mr_table *mrt = from_timer(mrt, t, ipmr_expire_timer); + struct mr_table *mrt = timer_container_of(mrt, t, ipmr_expire_timer); if (!spin_trylock(&mfc_unres_lock)) { mod_timer(&mrt->ipmr_expire_timer, jiffies + 1); diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c index d6bd8f7079bb..64ab23ff559b 100644 --- a/net/ipv6/netfilter/nf_conntrack_reasm.c +++ b/net/ipv6/netfilter/nf_conntrack_reasm.c @@ -133,7 +133,7 @@ static inline u8 ip6_frag_ecn(const struct ipv6hdr *ipv6h) static void nf_ct_frag6_expire(struct timer_list *t) { - struct inet_frag_queue *frag = from_timer(frag, t, timer); + struct inet_frag_queue *frag = timer_container_of(frag, t, timer); struct frag_queue *fq; fq = container_of(frag, struct frag_queue, q); diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index 49740898bc13..7d4bcf3fda5b 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c @@ -73,7 +73,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *skb, static void ip6_frag_expire(struct timer_list *t) { - struct inet_frag_queue *frag = from_timer(frag, t, timer); + struct inet_frag_queue *frag = timer_container_of(frag, t, timer); struct frag_queue *fq; fq = container_of(frag, struct frag_queue, q); diff --git a/net/lapb/lapb_timer.c b/net/lapb/lapb_timer.c index 5b3f3b444d19..9fde6cf20f10 100644 --- a/net/lapb/lapb_timer.c +++ b/net/lapb/lapb_timer.c @@ -74,7 +74,7 @@ int lapb_t1timer_running(struct lapb_cb *lapb) static void lapb_t2timer_expiry(struct timer_list *t) { - struct lapb_cb *lapb = from_timer(lapb, t, t2timer); + struct lapb_cb *lapb = timer_container_of(lapb, t, t2timer); spin_lock_bh(&lapb->lock); if (timer_pending(&lapb->t2timer)) /* A new timer has been set up */ @@ -94,7 +94,7 @@ out: static void lapb_t1timer_expiry(struct timer_list *t) { - struct lapb_cb *lapb = from_timer(lapb, t, t1timer); + struct lapb_cb *lapb = timer_container_of(lapb, t, t1timer); spin_lock_bh(&lapb->lock); if (timer_pending(&lapb->t1timer)) /* A new timer has been set up */ diff --git a/net/llc/llc_c_ac.c b/net/llc/llc_c_ac.c index 7e8fc710c590..0779daa8aa8f 100644 --- a/net/llc/llc_c_ac.c +++ b/net/llc/llc_c_ac.c @@ -1335,28 +1335,31 @@ static void llc_conn_tmr_common_cb(struct sock *sk, u8 type) void llc_conn_pf_cycle_tmr_cb(struct timer_list *t) { - struct llc_sock *llc = from_timer(llc, t, pf_cycle_timer.timer); + struct llc_sock *llc = timer_container_of(llc, t, + pf_cycle_timer.timer); llc_conn_tmr_common_cb(&llc->sk, LLC_CONN_EV_TYPE_P_TMR); } void llc_conn_busy_tmr_cb(struct timer_list *t) { - struct llc_sock *llc = from_timer(llc, t, busy_state_timer.timer); + struct llc_sock *llc = timer_container_of(llc, t, + busy_state_timer.timer); llc_conn_tmr_common_cb(&llc->sk, LLC_CONN_EV_TYPE_BUSY_TMR); } void llc_conn_ack_tmr_cb(struct timer_list *t) { - struct llc_sock *llc = from_timer(llc, t, ack_timer.timer); + struct llc_sock *llc = timer_container_of(llc, t, ack_timer.timer); llc_conn_tmr_common_cb(&llc->sk, LLC_CONN_EV_TYPE_ACK_TMR); } void llc_conn_rej_tmr_cb(struct timer_list *t) { - struct llc_sock *llc = from_timer(llc, t, rej_sent_timer.timer); + struct llc_sock *llc = timer_container_of(llc, t, + rej_sent_timer.timer); llc_conn_tmr_common_cb(&llc->sk, LLC_CONN_EV_TYPE_REJ_TMR); } diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c index 85612234742a..ee534797c033 100644 --- a/net/mac80211/agg-rx.c +++ b/net/mac80211/agg-rx.c @@ -143,7 +143,8 @@ EXPORT_SYMBOL(ieee80211_stop_rx_ba_session); */ static void sta_rx_agg_session_timer_expired(struct timer_list *t) { - struct tid_ampdu_rx *tid_rx = from_timer(tid_rx, t, session_timer); + struct tid_ampdu_rx *tid_rx = timer_container_of(tid_rx, t, + session_timer); struct sta_info *sta = tid_rx->sta; u8 tid = tid_rx->tid; unsigned long timeout; @@ -163,7 +164,8 @@ static void sta_rx_agg_session_timer_expired(struct timer_list *t) static void sta_rx_agg_reorder_timer_expired(struct timer_list *t) { - struct tid_ampdu_rx *tid_rx = from_timer(tid_rx, t, reorder_timer); + struct tid_ampdu_rx *tid_rx = timer_container_of(tid_rx, t, + reorder_timer); rcu_read_lock(); ieee80211_release_reorder_timeout(tid_rx->sta, tid_rx->tid); diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index 8dc8c3c96b96..dbd9ad5f3992 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c @@ -422,7 +422,8 @@ int __ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, */ static void sta_addba_resp_timer_expired(struct timer_list *t) { - struct tid_ampdu_tx *tid_tx = from_timer(tid_tx, t, addba_resp_timer); + struct tid_ampdu_tx *tid_tx = timer_container_of(tid_tx, t, + addba_resp_timer); struct sta_info *sta = tid_tx->sta; u8 tid = tid_tx->tid; @@ -574,7 +575,8 @@ EXPORT_SYMBOL(ieee80211_refresh_tx_agg_session_timer); */ static void sta_tx_agg_session_timer_expired(struct timer_list *t) { - struct tid_ampdu_tx *tid_tx = from_timer(tid_tx, t, session_timer); + struct tid_ampdu_tx *tid_tx = timer_container_of(tid_tx, t, + session_timer); struct sta_info *sta = tid_tx->sta; u8 tid = tid_tx->tid; unsigned long timeout; diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index a6e7b7ba6a01..9ed87d6f5019 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -1673,7 +1673,7 @@ void ieee80211_ibss_work(struct ieee80211_sub_if_data *sdata) static void ieee80211_ibss_timer(struct timer_list *t) { struct ieee80211_sub_if_data *sdata = - from_timer(sdata, t, u.ibss.timer); + timer_container_of(sdata, t, u.ibss.timer); wiphy_work_queue(sdata->local->hw.wiphy, &sdata->work); } diff --git a/net/mac80211/led.c b/net/mac80211/led.c index 885fa6aa3fc1..fabbffdd3ac2 100644 --- a/net/mac80211/led.c +++ b/net/mac80211/led.c @@ -257,7 +257,8 @@ static unsigned long tpt_trig_traffic(struct ieee80211_local *local, static void tpt_trig_timer(struct timer_list *t) { - struct tpt_led_trigger *tpt_trig = from_timer(tpt_trig, t, timer); + struct tpt_led_trigger *tpt_trig = timer_container_of(tpt_trig, t, + timer); struct ieee80211_local *local = tpt_trig->local; unsigned long on, off, tpt; int i; diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 5cc56d578048..d00d9d413c5c 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -40,7 +40,7 @@ void ieee80211s_stop(void) static void ieee80211_mesh_housekeeping_timer(struct timer_list *t) { struct ieee80211_sub_if_data *sdata = - from_timer(sdata, t, u.mesh.housekeeping_timer); + timer_container_of(sdata, t, u.mesh.housekeeping_timer); struct ieee80211_local *local = sdata->local; struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; @@ -684,7 +684,7 @@ int mesh_add_eht_oper_ie(struct ieee80211_sub_if_data *sdata, struct sk_buff *sk static void ieee80211_mesh_path_timer(struct timer_list *t) { struct ieee80211_sub_if_data *sdata = - from_timer(sdata, t, u.mesh.mesh_path_timer); + timer_container_of(sdata, t, u.mesh.mesh_path_timer); wiphy_work_queue(sdata->local->hw.wiphy, &sdata->work); } @@ -692,7 +692,7 @@ static void ieee80211_mesh_path_timer(struct timer_list *t) static void ieee80211_mesh_path_root_timer(struct timer_list *t) { struct ieee80211_sub_if_data *sdata = - from_timer(sdata, t, u.mesh.mesh_path_root_timer); + timer_container_of(sdata, t, u.mesh.mesh_path_root_timer); struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; set_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags); diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 91444301a84a..9101858525dd 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -1292,7 +1292,7 @@ int mesh_nexthop_lookup(struct ieee80211_sub_if_data *sdata, void mesh_path_timer(struct timer_list *t) { - struct mesh_path *mpath = from_timer(mpath, t, timer); + struct mesh_path *mpath = timer_container_of(mpath, t, timer); struct ieee80211_sub_if_data *sdata = mpath->sdata; int ret; diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 9c6a2b342170..cb45a5d2009d 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -653,7 +653,7 @@ out: void mesh_plink_timer(struct timer_list *t) { - struct mesh_sta *mesh = from_timer(mesh, t, plink_timer); + struct mesh_sta *mesh = timer_container_of(mesh, t, plink_timer); struct sta_info *sta; u16 reason = 0; struct ieee80211_sub_if_data *sdata; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 948909a242d6..2d46d4af60d7 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -3383,7 +3383,8 @@ void ieee80211_dynamic_ps_enable_work(struct wiphy *wiphy, void ieee80211_dynamic_ps_timer(struct timer_list *t) { - struct ieee80211_local *local = from_timer(local, t, dynamic_ps_timer); + struct ieee80211_local *local = timer_container_of(local, t, + dynamic_ps_timer); wiphy_work_queue(local->hw.wiphy, &local->dynamic_ps_enable_work); } @@ -8079,7 +8080,7 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, static void ieee80211_sta_timer(struct timer_list *t) { struct ieee80211_sub_if_data *sdata = - from_timer(sdata, t, u.mgd.timer); + timer_container_of(sdata, t, u.mgd.timer); wiphy_work_queue(sdata->local->hw.wiphy, &sdata->work); } @@ -8385,7 +8386,7 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) static void ieee80211_sta_bcn_mon_timer(struct timer_list *t) { struct ieee80211_sub_if_data *sdata = - from_timer(sdata, t, u.mgd.bcn_mon_timer); + timer_container_of(sdata, t, u.mgd.bcn_mon_timer); if (WARN_ON(ieee80211_vif_is_mld(&sdata->vif))) return; @@ -8405,7 +8406,7 @@ static void ieee80211_sta_bcn_mon_timer(struct timer_list *t) static void ieee80211_sta_conn_mon_timer(struct timer_list *t) { struct ieee80211_sub_if_data *sdata = - from_timer(sdata, t, u.mgd.conn_mon_timer); + timer_container_of(sdata, t, u.mgd.conn_mon_timer); struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_local *local = sdata->local; struct sta_info *sta; diff --git a/net/mac80211/ocb.c b/net/mac80211/ocb.c index ece1e83c7b2f..a5d4358f122a 100644 --- a/net/mac80211/ocb.c +++ b/net/mac80211/ocb.c @@ -146,7 +146,7 @@ void ieee80211_ocb_work(struct ieee80211_sub_if_data *sdata) static void ieee80211_ocb_housekeeping_timer(struct timer_list *t) { struct ieee80211_sub_if_data *sdata = - from_timer(sdata, t, u.ocb.housekeeping_timer); + timer_container_of(sdata, t, u.ocb.housekeeping_timer); struct ieee80211_local *local = sdata->local; struct ieee80211_if_ocb *ifocb = &sdata->u.ocb; diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 84b18be1f0b1..61583173629e 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -1542,7 +1542,8 @@ int sta_info_destroy_addr_bss(struct ieee80211_sub_if_data *sdata, static void sta_info_cleanup(struct timer_list *t) { - struct ieee80211_local *local = from_timer(local, t, sta_cleanup); + struct ieee80211_local *local = timer_container_of(local, t, + sta_cleanup); struct sta_info *sta; bool timer_needed = false; diff --git a/net/mptcp/pm.c b/net/mptcp/pm.c index 1306d4dc287b..feb01747d7d8 100644 --- a/net/mptcp/pm.c +++ b/net/mptcp/pm.c @@ -270,7 +270,8 @@ int mptcp_pm_mp_prio_send_ack(struct mptcp_sock *msk, static void mptcp_pm_add_timer(struct timer_list *timer) { - struct mptcp_pm_add_entry *entry = from_timer(entry, timer, add_timer); + struct mptcp_pm_add_entry *entry = timer_container_of(entry, timer, + add_timer); struct mptcp_sock *msk = entry->sock; struct sock *sk = (struct sock *)msk; diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index 0749733ea897..edf14c2c2062 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -2203,8 +2203,8 @@ out_err: static void mptcp_retransmit_timer(struct timer_list *t) { - struct inet_connection_sock *icsk = from_timer(icsk, t, - icsk_retransmit_timer); + struct inet_connection_sock *icsk = timer_container_of(icsk, t, + icsk_retransmit_timer); struct sock *sk = &icsk->icsk_inet.sk; struct mptcp_sock *msk = mptcp_sk(sk); @@ -2223,7 +2223,7 @@ static void mptcp_retransmit_timer(struct timer_list *t) static void mptcp_tout_timer(struct timer_list *t) { - struct sock *sk = from_timer(sk, t, sk_timer); + struct sock *sk = timer_container_of(sk, t, sk_timer); mptcp_schedule_work(sk); sock_put(sk); diff --git a/net/ncsi/ncsi-manage.c b/net/ncsi/ncsi-manage.c index b36947063783..446e4e3b9553 100644 --- a/net/ncsi/ncsi-manage.c +++ b/net/ncsi/ncsi-manage.c @@ -88,7 +88,7 @@ report: static void ncsi_channel_monitor(struct timer_list *t) { - struct ncsi_channel *nc = from_timer(nc, t, monitor.timer); + struct ncsi_channel *nc = timer_container_of(nc, t, monitor.timer); struct ncsi_package *np = nc->package; struct ncsi_dev_priv *ndp = np->ndp; struct ncsi_channel_mode *ncm; @@ -430,7 +430,7 @@ struct ncsi_dev *ncsi_find_dev(struct net_device *dev) static void ncsi_request_timeout(struct timer_list *t) { - struct ncsi_request *nr = from_timer(nr, t, timer); + struct ncsi_request *nr = timer_container_of(nr, t, timer); struct ncsi_dev_priv *ndp = nr->ndp; struct ncsi_cmd_pkt *cmd; struct ncsi_package *np; diff --git a/net/netfilter/ipset/ip_set_bitmap_gen.h b/net/netfilter/ipset/ip_set_bitmap_gen.h index 6ae042f702d2..798c7993635e 100644 --- a/net/netfilter/ipset/ip_set_bitmap_gen.h +++ b/net/netfilter/ipset/ip_set_bitmap_gen.h @@ -264,7 +264,7 @@ out: static void mtype_gc(struct timer_list *t) { - struct mtype *map = from_timer(map, t, gc); + struct mtype *map = timer_container_of(map, t, gc); struct ip_set *set = map->set; void *x; u32 id; diff --git a/net/netfilter/ipset/ip_set_list_set.c b/net/netfilter/ipset/ip_set_list_set.c index db794fe1300e..13c7a08aa868 100644 --- a/net/netfilter/ipset/ip_set_list_set.c +++ b/net/netfilter/ipset/ip_set_list_set.c @@ -571,7 +571,7 @@ static const struct ip_set_type_variant set_variant = { static void list_set_gc(struct timer_list *t) { - struct list_set *map = from_timer(map, t, gc); + struct list_set *map = timer_container_of(map, t, gc); struct ip_set *set = map->set; spin_lock_bh(&set->lock); diff --git a/net/netfilter/ipvs/ip_vs_conn.c b/net/netfilter/ipvs/ip_vs_conn.c index 8699944c0baf..44b2ad695c15 100644 --- a/net/netfilter/ipvs/ip_vs_conn.c +++ b/net/netfilter/ipvs/ip_vs_conn.c @@ -846,7 +846,7 @@ static void ip_vs_conn_del_put(struct ip_vs_conn *cp) static void ip_vs_conn_expire(struct timer_list *t) { - struct ip_vs_conn *cp = from_timer(cp, t, timer); + struct ip_vs_conn *cp = timer_container_of(cp, t, timer); struct netns_ipvs *ipvs = cp->ipvs; /* diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c index 7d5b7418f8c7..6a6fc4478533 100644 --- a/net/netfilter/ipvs/ip_vs_ctl.c +++ b/net/netfilter/ipvs/ip_vs_ctl.c @@ -1331,7 +1331,8 @@ ip_vs_del_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest) static void ip_vs_dest_trash_expire(struct timer_list *t) { - struct netns_ipvs *ipvs = from_timer(ipvs, t, dest_trash_timer); + struct netns_ipvs *ipvs = timer_container_of(ipvs, t, + dest_trash_timer); struct ip_vs_dest *dest, *next; unsigned long now = jiffies; diff --git a/net/netfilter/ipvs/ip_vs_lblc.c b/net/netfilter/ipvs/ip_vs_lblc.c index 2423513d701d..156181a3bacd 100644 --- a/net/netfilter/ipvs/ip_vs_lblc.c +++ b/net/netfilter/ipvs/ip_vs_lblc.c @@ -292,7 +292,8 @@ static inline void ip_vs_lblc_full_check(struct ip_vs_service *svc) */ static void ip_vs_lblc_check_expire(struct timer_list *t) { - struct ip_vs_lblc_table *tbl = from_timer(tbl, t, periodic_timer); + struct ip_vs_lblc_table *tbl = timer_container_of(tbl, t, + periodic_timer); struct ip_vs_service *svc = tbl->svc; unsigned long now = jiffies; int goal; diff --git a/net/netfilter/ipvs/ip_vs_lblcr.c b/net/netfilter/ipvs/ip_vs_lblcr.c index cdb1d4bf6761..a021e6aba3d7 100644 --- a/net/netfilter/ipvs/ip_vs_lblcr.c +++ b/net/netfilter/ipvs/ip_vs_lblcr.c @@ -456,7 +456,8 @@ static inline void ip_vs_lblcr_full_check(struct ip_vs_service *svc) */ static void ip_vs_lblcr_check_expire(struct timer_list *t) { - struct ip_vs_lblcr_table *tbl = from_timer(tbl, t, periodic_timer); + struct ip_vs_lblcr_table *tbl = timer_container_of(tbl, t, + periodic_timer); struct ip_vs_service *svc = tbl->svc; unsigned long now = jiffies; int goal; diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c index 21d22fa22e4e..cfc2daa3fc7f 100644 --- a/net/netfilter/nf_conntrack_expect.c +++ b/net/netfilter/nf_conntrack_expect.c @@ -71,7 +71,7 @@ EXPORT_SYMBOL_GPL(nf_ct_unlink_expect_report); static void nf_ct_expectation_timed_out(struct timer_list *t) { - struct nf_conntrack_expect *exp = from_timer(exp, t, timeout); + struct nf_conntrack_expect *exp = timer_container_of(exp, t, timeout); spin_lock_bh(&nf_conntrack_expect_lock); nf_ct_unlink_expect(exp); diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c index 882962f3c84d..bfcb9cd335bf 100644 --- a/net/netfilter/nfnetlink_log.c +++ b/net/netfilter/nfnetlink_log.c @@ -390,7 +390,7 @@ __nfulnl_flush(struct nfulnl_instance *inst) static void nfulnl_timer(struct timer_list *t) { - struct nfulnl_instance *inst = from_timer(inst, t, timer); + struct nfulnl_instance *inst = timer_container_of(inst, t, timer); spin_lock_bh(&inst->lock); if (inst->skb) diff --git a/net/netfilter/xt_IDLETIMER.c b/net/netfilter/xt_IDLETIMER.c index 9082155ee558..d73957592c9d 100644 --- a/net/netfilter/xt_IDLETIMER.c +++ b/net/netfilter/xt_IDLETIMER.c @@ -100,7 +100,7 @@ static void idletimer_tg_work(struct work_struct *work) static void idletimer_tg_expired(struct timer_list *t) { - struct idletimer_tg *timer = from_timer(timer, t, timer); + struct idletimer_tg *timer = timer_container_of(timer, t, timer); pr_debug("timer %s expired\n", timer->attr.attr.name); diff --git a/net/netfilter/xt_LED.c b/net/netfilter/xt_LED.c index 8a80fd76fe45..90dcf088071a 100644 --- a/net/netfilter/xt_LED.c +++ b/net/netfilter/xt_LED.c @@ -72,8 +72,9 @@ led_tg(struct sk_buff *skb, const struct xt_action_param *par) static void led_timeout_callback(struct timer_list *t) { - struct xt_led_info_internal *ledinternal = from_timer(ledinternal, t, - timer); + struct xt_led_info_internal *ledinternal = timer_container_of(ledinternal, + t, + timer); led_trigger_event(&ledinternal->netfilter_led_trigger, LED_OFF); } diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c index 6ee148f0e6d0..3331669d8e33 100644 --- a/net/netrom/af_netrom.c +++ b/net/netrom/af_netrom.c @@ -240,7 +240,7 @@ void nr_destroy_socket(struct sock *); */ static void nr_destroy_timer(struct timer_list *t) { - struct sock *sk = from_timer(sk, t, sk_timer); + struct sock *sk = timer_container_of(sk, t, sk_timer); bh_lock_sock(sk); sock_hold(sk); nr_destroy_socket(sk); diff --git a/net/netrom/nr_timer.c b/net/netrom/nr_timer.c index 5e3ca068f04e..b3a62b1f3a09 100644 --- a/net/netrom/nr_timer.c +++ b/net/netrom/nr_timer.c @@ -111,7 +111,7 @@ int nr_t1timer_running(struct sock *sk) static void nr_heartbeat_expiry(struct timer_list *t) { - struct sock *sk = from_timer(sk, t, sk_timer); + struct sock *sk = timer_container_of(sk, t, sk_timer); struct nr_sock *nr = nr_sk(sk); bh_lock_sock(sk); @@ -152,7 +152,7 @@ out: static void nr_t2timer_expiry(struct timer_list *t) { - struct nr_sock *nr = from_timer(nr, t, t2timer); + struct nr_sock *nr = timer_container_of(nr, t, t2timer); struct sock *sk = &nr->sock; bh_lock_sock(sk); @@ -166,7 +166,7 @@ static void nr_t2timer_expiry(struct timer_list *t) static void nr_t4timer_expiry(struct timer_list *t) { - struct nr_sock *nr = from_timer(nr, t, t4timer); + struct nr_sock *nr = timer_container_of(nr, t, t4timer); struct sock *sk = &nr->sock; bh_lock_sock(sk); @@ -177,7 +177,7 @@ static void nr_t4timer_expiry(struct timer_list *t) static void nr_idletimer_expiry(struct timer_list *t) { - struct nr_sock *nr = from_timer(nr, t, idletimer); + struct nr_sock *nr = timer_container_of(nr, t, idletimer); struct sock *sk = &nr->sock; bh_lock_sock(sk); @@ -206,7 +206,7 @@ static void nr_idletimer_expiry(struct timer_list *t) static void nr_t1timer_expiry(struct timer_list *t) { - struct nr_sock *nr = from_timer(nr, t, t1timer); + struct nr_sock *nr = timer_container_of(nr, t, t1timer); struct sock *sk = &nr->sock; bh_lock_sock(sk); diff --git a/net/nfc/core.c b/net/nfc/core.c index 75ed8a9146ba..ae1c842f9c64 100644 --- a/net/nfc/core.c +++ b/net/nfc/core.c @@ -1010,7 +1010,7 @@ exit: static void nfc_check_pres_timeout(struct timer_list *t) { - struct nfc_dev *dev = from_timer(dev, t, check_pres_timer); + struct nfc_dev *dev = timer_container_of(dev, t, check_pres_timer); schedule_work(&dev->check_pres_work); } diff --git a/net/nfc/hci/core.c b/net/nfc/hci/core.c index aa493344d93e..8618d57c23da 100644 --- a/net/nfc/hci/core.c +++ b/net/nfc/hci/core.c @@ -441,7 +441,7 @@ exit_noskb: static void nfc_hci_cmd_timeout(struct timer_list *t) { - struct nfc_hci_dev *hdev = from_timer(hdev, t, cmd_timer); + struct nfc_hci_dev *hdev = timer_container_of(hdev, t, cmd_timer); schedule_work(&hdev->msg_tx_work); } diff --git a/net/nfc/hci/llc_shdlc.c b/net/nfc/hci/llc_shdlc.c index ce9c683a3ead..4fc37894860c 100644 --- a/net/nfc/hci/llc_shdlc.c +++ b/net/nfc/hci/llc_shdlc.c @@ -564,14 +564,14 @@ static void llc_shdlc_handle_send_queue(struct llc_shdlc *shdlc) static void llc_shdlc_connect_timeout(struct timer_list *t) { - struct llc_shdlc *shdlc = from_timer(shdlc, t, connect_timer); + struct llc_shdlc *shdlc = timer_container_of(shdlc, t, connect_timer); schedule_work(&shdlc->sm_work); } static void llc_shdlc_t1_timeout(struct timer_list *t) { - struct llc_shdlc *shdlc = from_timer(shdlc, t, t1_timer); + struct llc_shdlc *shdlc = timer_container_of(shdlc, t, t1_timer); pr_debug("SoftIRQ: need to send ack\n"); @@ -580,7 +580,7 @@ static void llc_shdlc_t1_timeout(struct timer_list *t) static void llc_shdlc_t2_timeout(struct timer_list *t) { - struct llc_shdlc *shdlc = from_timer(shdlc, t, t2_timer); + struct llc_shdlc *shdlc = timer_container_of(shdlc, t, t2_timer); pr_debug("SoftIRQ: need to retransmit\n"); diff --git a/net/nfc/llcp_core.c b/net/nfc/llcp_core.c index 27e863f96ed1..beeb3b4d28ca 100644 --- a/net/nfc/llcp_core.c +++ b/net/nfc/llcp_core.c @@ -243,7 +243,8 @@ static void nfc_llcp_timeout_work(struct work_struct *work) static void nfc_llcp_symm_timer(struct timer_list *t) { - struct nfc_llcp_local *local = from_timer(local, t, link_timer); + struct nfc_llcp_local *local = timer_container_of(local, t, + link_timer); pr_err("SYMM timeout\n"); @@ -286,7 +287,8 @@ static void nfc_llcp_sdreq_timeout_work(struct work_struct *work) static void nfc_llcp_sdreq_timer(struct timer_list *t) { - struct nfc_llcp_local *local = from_timer(local, t, sdreq_timer); + struct nfc_llcp_local *local = timer_container_of(local, t, + sdreq_timer); schedule_work(&local->sdreq_timeout_work); } diff --git a/net/nfc/nci/core.c b/net/nfc/nci/core.c index 0171bf3c7016..fc921cd2cdff 100644 --- a/net/nfc/nci/core.c +++ b/net/nfc/nci/core.c @@ -610,7 +610,7 @@ static int nci_close_device(struct nci_dev *ndev) /* NCI command timer function */ static void nci_cmd_timer(struct timer_list *t) { - struct nci_dev *ndev = from_timer(ndev, t, cmd_timer); + struct nci_dev *ndev = timer_container_of(ndev, t, cmd_timer); atomic_set(&ndev->cmd_cnt, 1); queue_work(ndev->cmd_wq, &ndev->cmd_work); @@ -619,7 +619,7 @@ static void nci_cmd_timer(struct timer_list *t) /* NCI data exchange timer function */ static void nci_data_timer(struct timer_list *t) { - struct nci_dev *ndev = from_timer(ndev, t, data_timer); + struct nci_dev *ndev = timer_container_of(ndev, t, data_timer); set_bit(NCI_DATA_EXCHANGE_TO, &ndev->flags); queue_work(ndev->rx_wq, &ndev->rx_work); diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 20be2c47cf41..3d43f3eae759 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -722,7 +722,7 @@ static void _prb_refresh_rx_retire_blk_timer(struct tpacket_kbdq_core *pkc) static void prb_retire_rx_blk_timer_expired(struct timer_list *t) { struct packet_sock *po = - from_timer(po, t, rx_ring.prb_bdqc.retire_blk_timer); + timer_container_of(po, t, rx_ring.prb_bdqc.retire_blk_timer); struct tpacket_kbdq_core *pkc = GET_PBDQC_FROM_RB(&po->rx_ring); unsigned int frozen; struct tpacket_block_desc *pbd; diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c index a4a668b88a8f..4e72b636a46a 100644 --- a/net/rose/af_rose.c +++ b/net/rose/af_rose.c @@ -345,7 +345,7 @@ void rose_destroy_socket(struct sock *); */ static void rose_destroy_timer(struct timer_list *t) { - struct sock *sk = from_timer(sk, t, sk_timer); + struct sock *sk = timer_container_of(sk, t, sk_timer); rose_destroy_socket(sk); } diff --git a/net/rose/rose_link.c b/net/rose/rose_link.c index 9f9629e6fdae..7746229fdc8c 100644 --- a/net/rose/rose_link.c +++ b/net/rose/rose_link.c @@ -78,7 +78,7 @@ static void rose_ftimer_expiry(struct timer_list *t) static void rose_t0timer_expiry(struct timer_list *t) { - struct rose_neigh *neigh = from_timer(neigh, t, t0timer); + struct rose_neigh *neigh = timer_container_of(neigh, t, t0timer); rose_transmit_restart_request(neigh); diff --git a/net/rose/rose_timer.c b/net/rose/rose_timer.c index 1525773e94aa..020369c49587 100644 --- a/net/rose/rose_timer.c +++ b/net/rose/rose_timer.c @@ -118,7 +118,7 @@ void rose_stop_idletimer(struct sock *sk) static void rose_heartbeat_expiry(struct timer_list *t) { - struct sock *sk = from_timer(sk, t, sk_timer); + struct sock *sk = timer_container_of(sk, t, sk_timer); struct rose_sock *rose = rose_sk(sk); bh_lock_sock(sk); @@ -163,7 +163,7 @@ out: static void rose_timer_expiry(struct timer_list *t) { - struct rose_sock *rose = from_timer(rose, t, timer); + struct rose_sock *rose = timer_container_of(rose, t, timer); struct sock *sk = &rose->sock; bh_lock_sock(sk); @@ -198,7 +198,7 @@ out: static void rose_idletimer_expiry(struct timer_list *t) { - struct rose_sock *rose = from_timer(rose, t, idletimer); + struct rose_sock *rose = timer_container_of(rose, t, idletimer); struct sock *sk = &rose->sock; bh_lock_sock(sk); diff --git a/net/rxrpc/call_object.c b/net/rxrpc/call_object.c index e9e8f0ef3fd5..15067ff7b1f2 100644 --- a/net/rxrpc/call_object.c +++ b/net/rxrpc/call_object.c @@ -64,7 +64,7 @@ void rxrpc_poke_call(struct rxrpc_call *call, enum rxrpc_call_poke_trace what) static void rxrpc_call_timer_expired(struct timer_list *t) { - struct rxrpc_call *call = from_timer(call, t, timer); + struct rxrpc_call *call = timer_container_of(call, t, timer); _enter("%d", call->debug_id); diff --git a/net/sched/cls_flow.c b/net/sched/cls_flow.c index 5c2580a07530..5693b41b093f 100644 --- a/net/sched/cls_flow.c +++ b/net/sched/cls_flow.c @@ -345,7 +345,7 @@ TC_INDIRECT_SCOPE int flow_classify(struct sk_buff *skb, static void flow_perturbation(struct timer_list *t) { - struct flow_filter *f = from_timer(f, t, perturb_timer); + struct flow_filter *f = timer_container_of(f, t, perturb_timer); get_random_bytes(&f->hashrnd, 4); if (f->perturb_period) diff --git a/net/sched/sch_fq_pie.c b/net/sched/sch_fq_pie.c index df7fac95ab15..b0e34daf1f75 100644 --- a/net/sched/sch_fq_pie.c +++ b/net/sched/sch_fq_pie.c @@ -384,7 +384,7 @@ flow_error: static void fq_pie_timer(struct timer_list *t) { - struct fq_pie_sched_data *q = from_timer(q, t, adapt_timer); + struct fq_pie_sched_data *q = timer_container_of(q, t, adapt_timer); unsigned long next, tupdate; struct Qdisc *sch = q->sch; spinlock_t *root_lock; /* to lock qdisc for probability calculations */ diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index 08e0e3aff976..16afb834fe4a 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c @@ -496,7 +496,7 @@ EXPORT_SYMBOL(netif_tx_unlock); static void dev_watchdog(struct timer_list *t) { - struct net_device *dev = from_timer(dev, t, watchdog_timer); + struct net_device *dev = timer_container_of(dev, t, watchdog_timer); bool release = true; spin_lock(&dev->tx_global_lock); diff --git a/net/sched/sch_pie.c b/net/sched/sch_pie.c index ff49a6c97033..ad46ee3ed5a9 100644 --- a/net/sched/sch_pie.c +++ b/net/sched/sch_pie.c @@ -424,7 +424,7 @@ EXPORT_SYMBOL_GPL(pie_calculate_probability); static void pie_timer(struct timer_list *t) { - struct pie_sched_data *q = from_timer(q, t, adapt_timer); + struct pie_sched_data *q = timer_container_of(q, t, adapt_timer); struct Qdisc *sch = q->sch; spinlock_t *root_lock; diff --git a/net/sched/sch_red.c b/net/sched/sch_red.c index 1ba3e0bba54f..339d70b4a4c5 100644 --- a/net/sched/sch_red.c +++ b/net/sched/sch_red.c @@ -321,7 +321,7 @@ unlock_out: static inline void red_adaptative_timer(struct timer_list *t) { - struct red_sched_data *q = from_timer(q, t, adapt_timer); + struct red_sched_data *q = timer_container_of(q, t, adapt_timer); struct Qdisc *sch = q->sch; spinlock_t *root_lock; diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c index b912ad99aa15..a8081492d671 100644 --- a/net/sched/sch_sfq.c +++ b/net/sched/sch_sfq.c @@ -597,7 +597,7 @@ drop: static void sfq_perturbation(struct timer_list *t) { - struct sfq_sched_data *q = from_timer(q, t, perturb_timer); + struct sfq_sched_data *q = timer_container_of(q, t, perturb_timer); struct Qdisc *sch = q->sch; spinlock_t *root_lock; siphash_key_t nkey; diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 8c3b80c4d40b..f402f90eb6b6 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -631,7 +631,7 @@ static void sctp_v4_ecn_capable(struct sock *sk) static void sctp_addr_wq_timeout_handler(struct timer_list *t) { - struct net *net = from_timer(net, t, sctp.addr_wq_timer); + struct net *net = timer_container_of(net, t, sctp.addr_wq_timer); struct sctp_sockaddr_entry *addrw, *temp; struct sctp_sock *sp; diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c index 3aa5da5e3bbd..424f10a6fdba 100644 --- a/net/sctp/sm_sideeffect.c +++ b/net/sctp/sm_sideeffect.c @@ -231,7 +231,7 @@ nomem: void sctp_generate_t3_rtx_event(struct timer_list *t) { struct sctp_transport *transport = - from_timer(transport, t, T3_rtx_timer); + timer_container_of(transport, t, T3_rtx_timer); struct sctp_association *asoc = transport->asoc; struct sock *sk = asoc->base.sk; struct net *net = sock_net(sk); @@ -308,7 +308,8 @@ out_unlock: static void sctp_generate_t1_cookie_event(struct timer_list *t) { struct sctp_association *asoc = - from_timer(asoc, t, timers[SCTP_EVENT_TIMEOUT_T1_COOKIE]); + timer_container_of(asoc, t, + timers[SCTP_EVENT_TIMEOUT_T1_COOKIE]); sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_T1_COOKIE); } @@ -316,7 +317,8 @@ static void sctp_generate_t1_cookie_event(struct timer_list *t) static void sctp_generate_t1_init_event(struct timer_list *t) { struct sctp_association *asoc = - from_timer(asoc, t, timers[SCTP_EVENT_TIMEOUT_T1_INIT]); + timer_container_of(asoc, t, + timers[SCTP_EVENT_TIMEOUT_T1_INIT]); sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_T1_INIT); } @@ -324,7 +326,8 @@ static void sctp_generate_t1_init_event(struct timer_list *t) static void sctp_generate_t2_shutdown_event(struct timer_list *t) { struct sctp_association *asoc = - from_timer(asoc, t, timers[SCTP_EVENT_TIMEOUT_T2_SHUTDOWN]); + timer_container_of(asoc, t, + timers[SCTP_EVENT_TIMEOUT_T2_SHUTDOWN]); sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_T2_SHUTDOWN); } @@ -332,7 +335,7 @@ static void sctp_generate_t2_shutdown_event(struct timer_list *t) static void sctp_generate_t4_rto_event(struct timer_list *t) { struct sctp_association *asoc = - from_timer(asoc, t, timers[SCTP_EVENT_TIMEOUT_T4_RTO]); + timer_container_of(asoc, t, timers[SCTP_EVENT_TIMEOUT_T4_RTO]); sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_T4_RTO); } @@ -340,8 +343,8 @@ static void sctp_generate_t4_rto_event(struct timer_list *t) static void sctp_generate_t5_shutdown_guard_event(struct timer_list *t) { struct sctp_association *asoc = - from_timer(asoc, t, - timers[SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD]); + timer_container_of(asoc, t, + timers[SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD]); sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD); @@ -351,7 +354,8 @@ static void sctp_generate_t5_shutdown_guard_event(struct timer_list *t) static void sctp_generate_autoclose_event(struct timer_list *t) { struct sctp_association *asoc = - from_timer(asoc, t, timers[SCTP_EVENT_TIMEOUT_AUTOCLOSE]); + timer_container_of(asoc, t, + timers[SCTP_EVENT_TIMEOUT_AUTOCLOSE]); sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_AUTOCLOSE); } @@ -361,7 +365,8 @@ static void sctp_generate_autoclose_event(struct timer_list *t) */ void sctp_generate_heartbeat_event(struct timer_list *t) { - struct sctp_transport *transport = from_timer(transport, t, hb_timer); + struct sctp_transport *transport = timer_container_of(transport, t, + hb_timer); struct sctp_association *asoc = transport->asoc; struct sock *sk = asoc->base.sk; struct net *net = sock_net(sk); @@ -407,7 +412,7 @@ out_unlock: void sctp_generate_proto_unreach_event(struct timer_list *t) { struct sctp_transport *transport = - from_timer(transport, t, proto_unreach_timer); + timer_container_of(transport, t, proto_unreach_timer); struct sctp_association *asoc = transport->asoc; struct sock *sk = asoc->base.sk; struct net *net = sock_net(sk); @@ -442,7 +447,7 @@ out_unlock: void sctp_generate_reconf_event(struct timer_list *t) { struct sctp_transport *transport = - from_timer(transport, t, reconf_timer); + timer_container_of(transport, t, reconf_timer); struct sctp_association *asoc = transport->asoc; struct sock *sk = asoc->base.sk; struct net *net = sock_net(sk); @@ -478,7 +483,8 @@ out_unlock: /* Handle the timeout of the probe timer. */ void sctp_generate_probe_event(struct timer_list *t) { - struct sctp_transport *transport = from_timer(transport, t, probe_timer); + struct sctp_transport *transport = timer_container_of(transport, t, + probe_timer); struct sctp_association *asoc = transport->asoc; struct sock *sk = asoc->base.sk; struct net *net = sock_net(sk); @@ -511,7 +517,7 @@ out_unlock: static void sctp_generate_sack_event(struct timer_list *t) { struct sctp_association *asoc = - from_timer(asoc, t, timers[SCTP_EVENT_TIMEOUT_SACK]); + timer_container_of(asoc, t, timers[SCTP_EVENT_TIMEOUT_SACK]); sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_SACK); } diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c index cb14d6ddac6c..8b1837228799 100644 --- a/net/sunrpc/svc_xprt.c +++ b/net/sunrpc/svc_xprt.c @@ -922,7 +922,7 @@ void svc_send(struct svc_rqst *rqstp) */ static void svc_age_temp_xprts(struct timer_list *t) { - struct svc_serv *serv = from_timer(serv, t, sv_temptimer); + struct svc_serv *serv = timer_container_of(serv, t, sv_temptimer); struct svc_xprt *xprt; struct list_head *le, *next; diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index d5e0cdcad9e0..1023361845f9 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -854,7 +854,7 @@ xprt_schedule_autodisconnect(struct rpc_xprt *xprt) static void xprt_init_autodisconnect(struct timer_list *t) { - struct rpc_xprt *xprt = from_timer(xprt, t, timer); + struct rpc_xprt *xprt = timer_container_of(xprt, t, timer); if (!RB_EMPTY_ROOT(&xprt->recv_queue)) return; diff --git a/net/tipc/discover.c b/net/tipc/discover.c index 685389d4b245..775fd4f3f072 100644 --- a/net/tipc/discover.c +++ b/net/tipc/discover.c @@ -292,7 +292,7 @@ void tipc_disc_remove_dest(struct tipc_discoverer *d) */ static void tipc_disc_timeout(struct timer_list *t) { - struct tipc_discoverer *d = from_timer(d, t, timer); + struct tipc_discoverer *d = timer_container_of(d, t, timer); struct tipc_net *tn = tipc_net(d->net); struct tipc_media_addr maddr; struct sk_buff *skb = NULL; diff --git a/net/tipc/monitor.c b/net/tipc/monitor.c index b45c5b91bc7a..572b79bf76ce 100644 --- a/net/tipc/monitor.c +++ b/net/tipc/monitor.c @@ -630,7 +630,7 @@ void tipc_mon_get_state(struct net *net, u32 addr, static void mon_timeout(struct timer_list *t) { - struct tipc_monitor *mon = from_timer(mon, t, timer); + struct tipc_monitor *mon = timer_container_of(mon, t, timer); struct tipc_peer *self; int best_member_cnt = dom_size(mon->peer_cnt) - 1; diff --git a/net/tipc/node.c b/net/tipc/node.c index cb43f2016a70..a07fb073368c 100644 --- a/net/tipc/node.c +++ b/net/tipc/node.c @@ -800,7 +800,7 @@ static bool tipc_node_cleanup(struct tipc_node *peer) */ static void tipc_node_timeout(struct timer_list *t) { - struct tipc_node *n = from_timer(n, t, timer); + struct tipc_node *n = timer_container_of(n, t, timer); struct tipc_link_entry *le; struct sk_buff_head xmitq; int remains = n->link_cnt; diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 65dcbb54f55d..7c61d47ea208 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -2862,7 +2862,7 @@ static void tipc_sk_retry_connect(struct sock *sk, struct sk_buff_head *list) static void tipc_sk_timeout(struct timer_list *t) { - struct sock *sk = from_timer(sk, t, sk_timer); + struct sock *sk = timer_container_of(sk, t, sk_timer); struct tipc_sock *tsk = tipc_sk(sk); u32 pnode = tsk_peer_node(tsk); struct sk_buff_head list; diff --git a/net/tipc/subscr.c b/net/tipc/subscr.c index 621addab2834..f8490d94e323 100644 --- a/net/tipc/subscr.c +++ b/net/tipc/subscr.c @@ -105,7 +105,7 @@ void tipc_sub_report_overlap(struct tipc_subscription *sub, static void tipc_sub_timeout(struct timer_list *t) { - struct tipc_subscription *sub = from_timer(sub, t, timer); + struct tipc_subscription *sub = timer_container_of(sub, t, timer); spin_lock(&sub->lock); tipc_sub_send_event(sub, NULL, TIPC_SUBSCR_TIMEOUT); diff --git a/net/wireless/core.c b/net/wireless/core.c index dcce326fdb8c..5c3c72df0591 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -1709,7 +1709,7 @@ EXPORT_SYMBOL_GPL(wiphy_work_flush); void wiphy_delayed_work_timer(struct timer_list *t) { - struct wiphy_delayed_work *dwork = from_timer(dwork, t, timer); + struct wiphy_delayed_work *dwork = timer_container_of(dwork, t, timer); wiphy_work_queue(dwork->wiphy, &dwork->work); } diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c index 8dda4178497c..1f8ae9f4a3f1 100644 --- a/net/x25/af_x25.c +++ b/net/x25/af_x25.c @@ -359,7 +359,7 @@ static void __x25_destroy_socket(struct sock *); */ static void x25_destroy_timer(struct timer_list *t) { - struct sock *sk = from_timer(sk, t, sk_timer); + struct sock *sk = timer_container_of(sk, t, sk_timer); x25_destroy_socket_from_timer(sk); } diff --git a/net/x25/x25_link.c b/net/x25/x25_link.c index 37b190499405..4608aa5b4f31 100644 --- a/net/x25/x25_link.c +++ b/net/x25/x25_link.c @@ -46,7 +46,7 @@ static inline void x25_start_t20timer(struct x25_neigh *nb) static void x25_t20timer_expiry(struct timer_list *t) { - struct x25_neigh *nb = from_timer(nb, t, t20timer); + struct x25_neigh *nb = timer_container_of(nb, t, t20timer); x25_transmit_restart_request(nb); diff --git a/net/x25/x25_timer.c b/net/x25/x25_timer.c index e4c5ad5b070f..2ec63a1f4c6d 100644 --- a/net/x25/x25_timer.c +++ b/net/x25/x25_timer.c @@ -89,7 +89,7 @@ unsigned long x25_display_timer(struct sock *sk) static void x25_heartbeat_expiry(struct timer_list *t) { - struct sock *sk = from_timer(sk, t, sk_timer); + struct sock *sk = timer_container_of(sk, t, sk_timer); bh_lock_sock(sk); if (sock_owned_by_user(sk)) /* can currently only occur in state 3 */ @@ -156,7 +156,7 @@ static inline void x25_do_timer_expiry(struct sock * sk) static void x25_timer_expiry(struct timer_list *t) { - struct x25_sock *x25 = from_timer(x25, t, timer); + struct x25_sock *x25 = timer_container_of(x25, t, timer); struct sock *sk = &x25->sk; bh_lock_sock(sk); diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index d4134a18c658..094d2454602e 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -353,7 +353,7 @@ static inline unsigned long make_jiffies(long secs) static void xfrm_policy_timer(struct timer_list *t) { - struct xfrm_policy *xp = from_timer(xp, t, timer); + struct xfrm_policy *xp = timer_container_of(xp, t, timer); time64_t now = ktime_get_real_seconds(); time64_t next = TIME64_MAX; int warn = 0; @@ -2898,7 +2898,7 @@ static void xfrm_policy_queue_process(struct timer_list *t) struct sk_buff *skb; struct sock *sk; struct dst_entry *dst; - struct xfrm_policy *pol = from_timer(pol, t, polq.hold_timer); + struct xfrm_policy *pol = timer_container_of(pol, t, polq.hold_timer); struct net *net = xp_net(pol); struct xfrm_policy_queue *pq = &pol->polq; struct flowi fl; diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index 203b585c2ae2..77cc418ad69e 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c @@ -2697,7 +2697,7 @@ EXPORT_SYMBOL(xfrm_state_walk_done); static void xfrm_replay_timer_handler(struct timer_list *t) { - struct xfrm_state *x = from_timer(x, t, rtimer); + struct xfrm_state *x = timer_container_of(x, t, rtimer); spin_lock(&x->lock); diff --git a/rust/kernel/miscdevice.rs b/rust/kernel/miscdevice.rs index f33c13c3ff97..939278bc7b03 100644 --- a/rust/kernel/miscdevice.rs +++ b/rust/kernel/miscdevice.rs @@ -138,7 +138,7 @@ pub trait MiscDevice: Sized { /// Handler for ioctls. /// - /// The `cmd` argument is usually manipulated using the utilties in [`kernel::ioctl`]. + /// The `cmd` argument is usually manipulated using the utilities in [`kernel::ioctl`]. /// /// [`kernel::ioctl`]: mod@crate::ioctl fn ioctl( diff --git a/scripts/Makefile.build b/scripts/Makefile.build index 557e725ab932..a6461ea411f7 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -37,6 +37,90 @@ include $(srctree)/scripts/Makefile.compiler include $(kbuild-file) include $(srctree)/scripts/Makefile.lib +# flags that take effect in current and sub directories +KBUILD_AFLAGS += $(subdir-asflags-y) +KBUILD_CFLAGS += $(subdir-ccflags-y) +KBUILD_RUSTFLAGS += $(subdir-rustflags-y) + +# Figure out what we need to build from the various variables +# =========================================================================== + +# When an object is listed to be built compiled-in and modular, +# only build the compiled-in version +obj-m := $(filter-out $(obj-y),$(obj-m)) + +# Libraries are always collected in one lib file. +# Filter out objects already built-in +lib-y := $(filter-out $(obj-y), $(sort $(lib-y) $(lib-m))) + +# Subdirectories we need to descend into +subdir-ym := $(sort $(subdir-y) $(subdir-m) \ + $(patsubst %/,%, $(filter %/, $(obj-y) $(obj-m)))) + +# Handle objects in subdirs: +# - If we encounter foo/ in $(obj-y), replace it by foo/built-in.a and +# foo/modules.order +# - If we encounter foo/ in $(obj-m), replace it by foo/modules.order +# +# Generate modules.order to determine modorder. Unfortunately, we don't have +# information about ordering between -y and -m subdirs. Just put -y's first. + +ifdef need-modorder +obj-m := $(patsubst %/,%/modules.order, $(filter %/, $(obj-y)) $(obj-m)) +else +obj-m := $(filter-out %/, $(obj-m)) +endif + +ifdef need-builtin +obj-y := $(patsubst %/, %/built-in.a, $(obj-y)) +else +obj-y := $(filter-out %/, $(obj-y)) +endif + +# Expand $(foo-objs) $(foo-y) etc. by replacing their individuals +suffix-search = $(strip $(foreach s, $3, $($(1:%$(strip $2)=%$s)))) +# List composite targets that are constructed by combining other targets +multi-search = $(sort $(foreach m, $1, $(if $(call suffix-search, $m, $2, $3 -), $m))) +# List primitive targets that are compiled from source files +real-search = $(foreach m, $1, $(if $(call suffix-search, $m, $2, $3 -), $(call suffix-search, $m, $2, $3), $m)) + +# If $(foo-objs), $(foo-y), $(foo-m), or $(foo-) exists, foo.o is a composite object +multi-obj-y := $(call multi-search, $(obj-y), .o, -objs -y) +multi-obj-m := $(call multi-search, $(obj-m), .o, -objs -y -m) +multi-obj-ym := $(multi-obj-y) $(multi-obj-m) + +# Replace multi-part objects by their individual parts, +# including built-in.a from subdirectories +real-obj-y := $(call real-search, $(obj-y), .o, -objs -y) +real-obj-m := $(call real-search, $(obj-m), .o, -objs -y -m) + +always-y += $(always-m) + +# hostprogs-always-y += foo +# ... is a shorthand for +# hostprogs += foo +# always-y += foo +hostprogs += $(hostprogs-always-y) $(hostprogs-always-m) +always-y += $(hostprogs-always-y) $(hostprogs-always-m) + +# userprogs-always-y is likewise. +userprogs += $(userprogs-always-y) $(userprogs-always-m) +always-y += $(userprogs-always-y) $(userprogs-always-m) + +# Add subdir path + +ifneq ($(obj),.) +extra-y := $(addprefix $(obj)/, $(extra-y)) +always-y := $(addprefix $(obj)/, $(always-y)) +targets := $(addprefix $(obj)/, $(targets)) +obj-m := $(addprefix $(obj)/, $(obj-m)) +lib-y := $(addprefix $(obj)/, $(lib-y)) +real-obj-y := $(addprefix $(obj)/, $(real-obj-y)) +real-obj-m := $(addprefix $(obj)/, $(real-obj-m)) +multi-obj-m := $(addprefix $(obj)/, $(multi-obj-m)) +subdir-ym := $(addprefix $(obj)/, $(subdir-ym)) +endif + ifndef obj $(warning kbuild: Makefile.build is included improperly) endif diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index 2b332645e0c2..1d581ba5df66 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -1,89 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 -# flags that take effect in current and sub directories -KBUILD_AFLAGS += $(subdir-asflags-y) -KBUILD_CFLAGS += $(subdir-ccflags-y) -KBUILD_RUSTFLAGS += $(subdir-rustflags-y) - -# Figure out what we need to build from the various variables -# =========================================================================== - -# When an object is listed to be built compiled-in and modular, -# only build the compiled-in version -obj-m := $(filter-out $(obj-y),$(obj-m)) - -# Libraries are always collected in one lib file. -# Filter out objects already built-in -lib-y := $(filter-out $(obj-y), $(sort $(lib-y) $(lib-m))) - -# Subdirectories we need to descend into -subdir-ym := $(sort $(subdir-y) $(subdir-m) \ - $(patsubst %/,%, $(filter %/, $(obj-y) $(obj-m)))) - -# Handle objects in subdirs: -# - If we encounter foo/ in $(obj-y), replace it by foo/built-in.a and -# foo/modules.order -# - If we encounter foo/ in $(obj-m), replace it by foo/modules.order -# -# Generate modules.order to determine modorder. Unfortunately, we don't have -# information about ordering between -y and -m subdirs. Just put -y's first. - -ifdef need-modorder -obj-m := $(patsubst %/,%/modules.order, $(filter %/, $(obj-y)) $(obj-m)) -else -obj-m := $(filter-out %/, $(obj-m)) -endif - -ifdef need-builtin -obj-y := $(patsubst %/, %/built-in.a, $(obj-y)) -else -obj-y := $(filter-out %/, $(obj-y)) -endif - -# Expand $(foo-objs) $(foo-y) etc. by replacing their individuals -suffix-search = $(strip $(foreach s, $3, $($(1:%$(strip $2)=%$s)))) -# List composite targets that are constructed by combining other targets -multi-search = $(sort $(foreach m, $1, $(if $(call suffix-search, $m, $2, $3 -), $m))) -# List primitive targets that are compiled from source files -real-search = $(foreach m, $1, $(if $(call suffix-search, $m, $2, $3 -), $(call suffix-search, $m, $2, $3), $m)) - -# If $(foo-objs), $(foo-y), $(foo-m), or $(foo-) exists, foo.o is a composite object -multi-obj-y := $(call multi-search, $(obj-y), .o, -objs -y) -multi-obj-m := $(call multi-search, $(obj-m), .o, -objs -y -m) -multi-obj-ym := $(multi-obj-y) $(multi-obj-m) - -# Replace multi-part objects by their individual parts, -# including built-in.a from subdirectories -real-obj-y := $(call real-search, $(obj-y), .o, -objs -y) -real-obj-m := $(call real-search, $(obj-m), .o, -objs -y -m) - -always-y += $(always-m) - -# hostprogs-always-y += foo -# ... is a shorthand for -# hostprogs += foo -# always-y += foo -hostprogs += $(hostprogs-always-y) $(hostprogs-always-m) -always-y += $(hostprogs-always-y) $(hostprogs-always-m) - -# userprogs-always-y is likewise. -userprogs += $(userprogs-always-y) $(userprogs-always-m) -always-y += $(userprogs-always-y) $(userprogs-always-m) - -# Add subdir path - -ifneq ($(obj),.) -extra-y := $(addprefix $(obj)/,$(extra-y)) -always-y := $(addprefix $(obj)/,$(always-y)) -targets := $(addprefix $(obj)/,$(targets)) -obj-m := $(addprefix $(obj)/,$(obj-m)) -lib-y := $(addprefix $(obj)/,$(lib-y)) -real-obj-y := $(addprefix $(obj)/,$(real-obj-y)) -real-obj-m := $(addprefix $(obj)/,$(real-obj-m)) -multi-obj-m := $(addprefix $(obj)/, $(multi-obj-m)) -subdir-ym := $(addprefix $(obj)/,$(subdir-ym)) -endif - # Finds the multi-part object the current object will be linked into. # If the object belongs to two or more multi-part objects, list them all. modname-multi = $(sort $(foreach m,$(multi-obj-ym),\ diff --git a/scripts/gendwarfksyms/dwarf.c b/scripts/gendwarfksyms/dwarf.c index eed247d8abfc..13ea7bf1ae7d 100644 --- a/scripts/gendwarfksyms/dwarf.c +++ b/scripts/gendwarfksyms/dwarf.c @@ -228,12 +228,24 @@ static void process_fqn(struct die *cache, Dwarf_Die *die) DEFINE_PROCESS_UDATA_ATTRIBUTE(accessibility) DEFINE_PROCESS_UDATA_ATTRIBUTE(alignment) DEFINE_PROCESS_UDATA_ATTRIBUTE(bit_size) -DEFINE_PROCESS_UDATA_ATTRIBUTE(byte_size) DEFINE_PROCESS_UDATA_ATTRIBUTE(encoding) DEFINE_PROCESS_UDATA_ATTRIBUTE(data_bit_offset) DEFINE_PROCESS_UDATA_ATTRIBUTE(data_member_location) DEFINE_PROCESS_UDATA_ATTRIBUTE(discr_value) +static void process_byte_size_attr(struct die *cache, Dwarf_Die *die) +{ + Dwarf_Word value; + unsigned long override; + + if (get_udata_attr(die, DW_AT_byte_size, &value)) { + if (stable && kabi_get_byte_size(cache->fqn, &override)) + value = override; + + process_fmt(cache, " byte_size(%" PRIu64 ")", value); + } +} + /* Match functions -- die_match_callback_t */ #define DEFINE_MATCH(type) \ static bool match_##type##_type(Dwarf_Die *die) \ diff --git a/scripts/gendwarfksyms/examples/kabi.h b/scripts/gendwarfksyms/examples/kabi.h index 97a5669b083d..170733a3fba4 100644 --- a/scripts/gendwarfksyms/examples/kabi.h +++ b/scripts/gendwarfksyms/examples/kabi.h @@ -37,11 +37,14 @@ #define __stringify(x...) __stringify_1(x) #endif -#define __KABI_RULE(hint, target, value) \ +#define ___KABI_RULE(hint, target, value) \ static const char __PASTE(__gendwarfksyms_rule_, \ __COUNTER__)[] __used __aligned(1) \ __section(".discard.gendwarfksyms.kabi_rules") = \ - "1\0" #hint "\0" #target "\0" #value + "1\0" #hint "\0" target "\0" value + +#define __KABI_RULE(hint, target, value) \ + ___KABI_RULE(hint, #target, #value) #define __KABI_NORMAL_SIZE_ALIGN(_orig, _new) \ union { \ @@ -90,6 +93,20 @@ __KABI_RULE(enumerator_value, fqn field, value) /* + * KABI_BYTE_SIZE(fqn, value) + * Set the byte_size attribute for the struct/union/enum fqn to + * value bytes. + */ +#define KABI_BYTE_SIZE(fqn, value) __KABI_RULE(byte_size, fqn, value) + +/* + * KABI_TYPE_STRING(type, str) + * For the given type, override the type string used in symtypes + * output and version calculation with str. + */ +#define KABI_TYPE_STRING(type, str) ___KABI_RULE(type_string, type, str) + +/* * KABI_RESERVE * Reserve some "padding" in a structure for use by LTS backports. * This is normally placed at the end of a structure. diff --git a/scripts/gendwarfksyms/examples/kabi_ex.c b/scripts/gendwarfksyms/examples/kabi_ex.c index 0b7ffd830541..1f799eb7c756 100644 --- a/scripts/gendwarfksyms/examples/kabi_ex.c +++ b/scripts/gendwarfksyms/examples/kabi_ex.c @@ -28,3 +28,10 @@ struct ex2c ex2c; struct ex3a ex3a; struct ex3b ex3b; struct ex3c ex3c; + +struct ex4a ex4a; + +struct ex5a ex5a; +struct ex5b ex5b; + +int ex6a; diff --git a/scripts/gendwarfksyms/examples/kabi_ex.h b/scripts/gendwarfksyms/examples/kabi_ex.h index 1736e0f65208..785b211d9c58 100644 --- a/scripts/gendwarfksyms/examples/kabi_ex.h +++ b/scripts/gendwarfksyms/examples/kabi_ex.h @@ -21,6 +21,12 @@ * ./gendwarfksyms --stable --dump-dies \ * examples/kabi_ex.o 2>&1 >/dev/null | \ * FileCheck examples/kabi_ex.h --check-prefix=STABLE + + * $ nm examples/kabi_ex.o | awk '{ print $NF }' | \ + * ./gendwarfksyms --stable --dump-versions \ + * examples/kabi_ex.o 2>&1 >/dev/null | \ + * sort | \ + * FileCheck examples/kabi_ex.h --check-prefix=VERSIONS */ #ifndef __KABI_EX_H__ @@ -170,7 +176,7 @@ struct ex2a { /* * STABLE: variable structure_type ex2a { * STABLE-NEXT: member base_type int byte_size(4) encoding(5) a data_member_location(0) , - * STABLE-NEXT: member base_type [[ULONG:long unsigned int|unsigned long]] byte_size(8) encoding(7) b data_member_location(8) + * STABLE-NEXT: member base_type [[ULONG]] byte_size(8) encoding(7) b data_member_location(8) * STABLE-NEXT: member base_type int byte_size(4) encoding(5) c data_member_location(16) , * STABLE-NEXT: member base_type [[ULONG]] byte_size(8) encoding(7) d data_member_location(24) * STABLE-NEXT: } byte_size(32) @@ -227,7 +233,7 @@ struct ex3a { /* * STABLE: variable structure_type ex3a { - * STABLE-NEXT: member base_type [[ULONG:long unsigned int|unsigned long]] byte_size(8) encoding(7) a data_member_location(0) + * STABLE-NEXT: member base_type [[ULONG]] byte_size(8) encoding(7) a data_member_location(0) * STABLE-NEXT: member base_type [[ULONG]] byte_size(8) encoding(7) unused data_member_location(8) * STABLE-NEXT: } byte_size(16) */ @@ -260,4 +266,95 @@ _Static_assert(sizeof(struct ex3a) == sizeof(struct ex3c), "ex3a size doesn't ma * STABLE-NEXT: } byte_size(16) */ +/* + * Example: An ignored field added to an end of a partially opaque struct, + * while keeping the byte_size attribute unchanged. + */ + +struct ex4a { + unsigned long a; + KABI_IGNORE(0, unsigned long b); +}; + +/* + * This may be safe if the structure allocation is managed by the core kernel + * and the layout remains unchanged except for appended new members. + */ +KABI_BYTE_SIZE(ex4a, 8); + +/* + * STABLE: variable structure_type ex4a { + * STABLE-NEXT: member base_type [[ULONG]] byte_size(8) encoding(7) a data_member_location(0) + * STABLE-NEXT: } byte_size(8) + */ + +/* + * Example: A type string override. + */ + +struct ex5a { + unsigned long a; +}; + +/* + * This may be safe if the structure is fully opaque to modules, even though + * its definition has inadvertently become part of the ABI. + */ +KABI_TYPE_STRING( + "s#ex5a", + "structure_type ex5a { member pointer_type { s#ex4a } byte_size(8) p data_member_location(0) } byte_size(8)"); + +/* + * Make sure the fully expanded type string includes ex4a. + * + * VERSIONS: ex5a variable structure_type ex5a { + * VERSIONS-SAME: member pointer_type { + * VERSIONS-SAME: structure_type ex4a { + * VERSIONS-SAME: member base_type [[ULONG:long unsigned int|unsigned long]] byte_size(8) encoding(7) a data_member_location(0) + * VERSIONS-SAME: } byte_size(8) + * VERSIONS-SAME: } byte_size(8) p data_member_location(0) + * VERSIONS-SAME: } byte_size(8) + */ + +/* + * Example: A type string definition for a non-existent type. + */ + +struct ex5b { + unsigned long a; +}; + +/* Replace the type string for struct ex5b */ +KABI_TYPE_STRING( + "s#ex5b", + "structure_type ex5b { member pointer_type { s#ex5c } byte_size(8) p data_member_location(0) } byte_size(8)"); + +/* Define a type string for a non-existent struct ex5c */ +KABI_TYPE_STRING( + "s#ex5c", + "structure_type ex5c { member base_type int byte_size(4) encoding(5) n data_member_location(0) } byte_size(8)"); + +/* + * Make sure the fully expanded type string includes the definition for ex5c. + * + * VERSIONS: ex5b variable structure_type ex5b { + * VERSIONS-SAME: member pointer_type { + * VERSIONS-SAME: structure_type ex5c { + * VERSIONS-SAME: member base_type int byte_size(4) encoding(5) n data_member_location(0) + * VERSIONS-SAME: } byte_size(8) + * VERSIONS-SAME: } byte_size(8) p data_member_location(0) + * VERSIONS-SAME: } byte_size(8) + */ + +/* + * Example: A type string override for a symbol. + */ + +KABI_TYPE_STRING("ex6a", "variable s#ex5c"); + +/* + * VERSIONS: ex6a variable structure_type ex5c { + * VERSIONS-SAME: member base_type int byte_size(4) encoding(5) n data_member_location(0) + * VERSIONS-SAME: } byte_size(8) + */ #endif /* __KABI_EX_H__ */ diff --git a/scripts/gendwarfksyms/gendwarfksyms.h b/scripts/gendwarfksyms/gendwarfksyms.h index 2feec168bf73..7dd03ffe0c5c 100644 --- a/scripts/gendwarfksyms/gendwarfksyms.h +++ b/scripts/gendwarfksyms/gendwarfksyms.h @@ -287,10 +287,12 @@ void generate_symtypes_and_versions(FILE *file); * kabi.c */ +bool kabi_get_byte_size(const char *fqn, unsigned long *value); bool kabi_is_enumerator_ignored(const char *fqn, const char *field); bool kabi_get_enumerator_value(const char *fqn, const char *field, unsigned long *value); bool kabi_is_declonly(const char *fqn); +bool kabi_get_type_string(const char *type, const char **str); void kabi_read_rules(int fd); void kabi_free(void); diff --git a/scripts/gendwarfksyms/kabi.c b/scripts/gendwarfksyms/kabi.c index 66f01fcd1607..b3ade713778f 100644 --- a/scripts/gendwarfksyms/kabi.c +++ b/scripts/gendwarfksyms/kabi.c @@ -54,11 +54,27 @@ */ #define KABI_RULE_TAG_ENUMERATOR_VALUE "enumerator_value" +/* + * Rule: byte_size + * - For the fqn_field in the target field, set the byte_size + * attribute to the value in the value field. + */ +#define KABI_RULE_TAG_BYTE_SIZE "byte_size" + +/* + * Rule: type_string + * - For the type reference in the fqn field, use the type string + * in the value field. + */ +#define KABI_RULE_TAG_TYPE_STRING "type_string" + enum kabi_rule_type { KABI_RULE_TYPE_UNKNOWN, KABI_RULE_TYPE_DECLONLY, KABI_RULE_TYPE_ENUMERATOR_IGNORE, KABI_RULE_TYPE_ENUMERATOR_VALUE, + KABI_RULE_TYPE_BYTE_SIZE, + KABI_RULE_TYPE_TYPE_STRING, }; #define RULE_HASH_BITS 7 @@ -127,6 +143,14 @@ void kabi_read_rules(int fd) .type = KABI_RULE_TYPE_ENUMERATOR_VALUE, .tag = KABI_RULE_TAG_ENUMERATOR_VALUE, }, + { + .type = KABI_RULE_TYPE_BYTE_SIZE, + .tag = KABI_RULE_TAG_BYTE_SIZE, + }, + { + .type = KABI_RULE_TYPE_TYPE_STRING, + .tag = KABI_RULE_TAG_TYPE_STRING, + }, }; if (!stable) @@ -222,33 +246,55 @@ void kabi_read_rules(int fd) check(elf_end(elf)); } -bool kabi_is_declonly(const char *fqn) +static char *get_enumerator_target(const char *fqn, const char *field) +{ + char *target = NULL; + + if (asprintf(&target, "%s %s", fqn, field) < 0) + error("asprintf failed for '%s %s'", fqn, field); + + return target; +} + +static struct rule *find_rule(enum kabi_rule_type type, const char *target) { struct rule *rule; if (!stable) - return false; - if (!fqn || !*fqn) - return false; + return NULL; + if (!target || !*target) + return NULL; hash_for_each_possible(rules, rule, hash, - rule_values_hash(KABI_RULE_TYPE_DECLONLY, fqn)) { - if (rule->type == KABI_RULE_TYPE_DECLONLY && - !strcmp(fqn, rule->target)) - return true; + rule_values_hash(type, target)) { + if (rule->type == type && !strcmp(target, rule->target)) + return rule; } - return false; + return NULL; } -static char *get_enumerator_target(const char *fqn, const char *field) +static struct rule *find_enumerator_rule(enum kabi_rule_type type, + const char *fqn, const char *field) { - char *target = NULL; + struct rule *rule; + char *target; - if (asprintf(&target, "%s %s", fqn, field) < 0) - error("asprintf failed for '%s %s'", fqn, field); + if (!stable) + return NULL; + if (!fqn || !*fqn || !field || !*field) + return NULL; - return target; + target = get_enumerator_target(fqn, field); + rule = find_rule(type, target); + + free(target); + return rule; +} + +bool kabi_is_declonly(const char *fqn) +{ + return !!find_rule(KABI_RULE_TYPE_DECLONLY, fqn); } static unsigned long get_ulong_value(const char *value) @@ -267,58 +313,49 @@ static unsigned long get_ulong_value(const char *value) bool kabi_is_enumerator_ignored(const char *fqn, const char *field) { - bool match = false; - struct rule *rule; - char *target; - - if (!stable) - return false; - if (!fqn || !*fqn || !field || !*field) - return false; + return !!find_enumerator_rule(KABI_RULE_TYPE_ENUMERATOR_IGNORE, fqn, + field); +} - target = get_enumerator_target(fqn, field); +bool kabi_get_enumerator_value(const char *fqn, const char *field, + unsigned long *value) +{ + struct rule *rule; - hash_for_each_possible( - rules, rule, hash, - rule_values_hash(KABI_RULE_TYPE_ENUMERATOR_IGNORE, target)) { - if (rule->type == KABI_RULE_TYPE_ENUMERATOR_IGNORE && - !strcmp(target, rule->target)) { - match = true; - break; - } + rule = find_enumerator_rule(KABI_RULE_TYPE_ENUMERATOR_VALUE, fqn, + field); + if (rule) { + *value = get_ulong_value(rule->value); + return true; } - free(target); - return match; + return false; } -bool kabi_get_enumerator_value(const char *fqn, const char *field, - unsigned long *value) +bool kabi_get_byte_size(const char *fqn, unsigned long *value) { - bool match = false; struct rule *rule; - char *target; - if (!stable) - return false; - if (!fqn || !*fqn || !field || !*field) - return false; + rule = find_rule(KABI_RULE_TYPE_BYTE_SIZE, fqn); + if (rule) { + *value = get_ulong_value(rule->value); + return true; + } - target = get_enumerator_target(fqn, field); + return false; +} - hash_for_each_possible(rules, rule, hash, - rule_values_hash(KABI_RULE_TYPE_ENUMERATOR_VALUE, - target)) { - if (rule->type == KABI_RULE_TYPE_ENUMERATOR_VALUE && - !strcmp(target, rule->target)) { - *value = get_ulong_value(rule->value); - match = true; - break; - } +bool kabi_get_type_string(const char *type, const char **str) +{ + struct rule *rule; + + rule = find_rule(KABI_RULE_TYPE_TYPE_STRING, type); + if (rule) { + *str = rule->value; + return true; } - free(target); - return match; + return false; } void kabi_free(void) diff --git a/scripts/gendwarfksyms/types.c b/scripts/gendwarfksyms/types.c index 6f37289104ff..39ce1770e463 100644 --- a/scripts/gendwarfksyms/types.c +++ b/scripts/gendwarfksyms/types.c @@ -100,7 +100,7 @@ static void type_expansion_append(struct type_expansion *type, const char *s, #define TYPE_HASH_BITS 12 static HASHTABLE_DEFINE(type_map, 1 << TYPE_HASH_BITS); -static int type_map_get(const char *name, struct type_expansion **res) +static int __type_map_get(const char *name, struct type_expansion **res) { struct type_expansion *e; @@ -114,11 +114,12 @@ static int type_map_get(const char *name, struct type_expansion **res) return -1; } -static void type_map_add(const char *name, struct type_expansion *type) +static struct type_expansion *type_map_add(const char *name, + struct type_expansion *type) { struct type_expansion *e; - if (type_map_get(name, &e)) { + if (__type_map_get(name, &e)) { e = xmalloc(sizeof(struct type_expansion)); type_expansion_init(e); e->name = xstrdup(name); @@ -130,7 +131,7 @@ static void type_map_add(const char *name, struct type_expansion *type) } else { /* Use the longest available expansion */ if (type->len <= e->len) - return; + return e; type_list_free(&e->expanded); @@ -148,6 +149,34 @@ static void type_map_add(const char *name, struct type_expansion *type) type_list_write(&e->expanded, stderr); checkp(fputs("\n", stderr)); } + + return e; +} + +static void type_parse(const char *name, const char *str, + struct type_expansion *type); + +static int type_map_get(const char *name, struct type_expansion **res) +{ + struct type_expansion type; + const char *override; + + if (!__type_map_get(name, res)) + return 0; + + /* + * If die_map didn't contain a type, we might still have + * a type_string kABI rule that defines it. + */ + if (stable && kabi_get_type_string(name, &override)) { + type_expansion_init(&type); + type_parse(name, override, &type); + *res = type_map_add(name, &type); + type_expansion_free(&type); + return 0; + } + + return -1; } static void type_map_write(FILE *file) @@ -267,15 +296,18 @@ static char *get_type_name(struct die *cache) return name; } -static void __calculate_version(struct version *version, struct list_head *list) +static void __calculate_version(struct version *version, + struct type_expansion *type) { struct type_list_entry *entry; struct type_expansion *e; /* Calculate a CRC over an expanded type string */ - list_for_each_entry(entry, list, list) { + list_for_each_entry(entry, &type->expanded, list) { if (is_type_prefix(entry->str)) { - check(type_map_get(entry->str, &e)); + if (type_map_get(entry->str, &e)) + error("unknown type reference to '%s' when expanding '%s'", + entry->str, type->name); /* * It's sufficient to expand each type reference just @@ -285,7 +317,7 @@ static void __calculate_version(struct version *version, struct list_head *list) version_add(version, entry->str); } else { cache_mark_expanded(&expansion_cache, e); - __calculate_version(version, &e->expanded); + __calculate_version(version, e); } } else { version_add(version, entry->str); @@ -293,10 +325,11 @@ static void __calculate_version(struct version *version, struct list_head *list) } } -static void calculate_version(struct version *version, struct list_head *list) +static void calculate_version(struct version *version, + struct type_expansion *type) { version_init(version); - __calculate_version(version, list); + __calculate_version(version, type); cache_free(&expansion_cache); } @@ -372,9 +405,80 @@ static void type_expand(struct die *cache, struct type_expansion *type, cache_free(&expansion_cache); } +static void type_parse(const char *name, const char *str, + struct type_expansion *type) +{ + char *fragment; + size_t start = 0; + size_t end; + size_t pos; + + if (!*str) + error("empty type string override for '%s'", name); + + type_expansion_init(type); + + for (pos = 0; str[pos]; ++pos) { + bool empty; + char marker = ' '; + + if (!is_type_prefix(&str[pos])) + continue; + + end = pos + 2; + + /* + * Find the end of the type reference. If the type name contains + * spaces, it must be in single quotes. + */ + if (str[end] == '\'') { + marker = '\''; + ++end; + } + while (str[end] && str[end] != marker) + ++end; + + /* Check that we have a non-empty type name */ + if (marker == '\'') { + if (str[end] != marker) + error("incomplete %c# type reference for '%s' (string : '%s')", + str[pos], name, str); + empty = end == pos + 3; + ++end; + } else { + empty = end == pos + 2; + } + if (empty) + error("empty %c# type name for '%s' (string: '%s')", + str[pos], name, str); + + /* Append the part of the string before the type reference */ + if (pos > start) { + fragment = xstrndup(&str[start], pos - start); + type_expansion_append(type, fragment, fragment); + } + + /* + * Append the type reference -- note that if the reference + * is invalid, i.e. points to a non-existent type, we will + * print out an error when calculating versions. + */ + fragment = xstrndup(&str[pos], end - pos); + type_expansion_append(type, fragment, fragment); + + start = end; + pos = end - 1; + } + + /* Append the rest of the type string, if there's any left */ + if (str[start]) + type_expansion_append(type, &str[start], NULL); +} + static void expand_type(struct die *cache, void *arg) { struct type_expansion type; + const char *override; char *name; if (cache->mapped) @@ -399,9 +503,13 @@ static void expand_type(struct die *cache, void *arg) return; debug("%s", name); - type_expand(cache, &type, true); - type_map_add(name, &type); + if (stable && kabi_get_type_string(name, &override)) + type_parse(name, override, &type); + else + type_expand(cache, &type, true); + + type_map_add(name, &type); type_expansion_free(&type); free(name); } @@ -410,6 +518,7 @@ static void expand_symbol(struct symbol *sym, void *arg) { struct type_expansion type; struct version version; + const char *override; struct die *cache; /* @@ -423,11 +532,14 @@ static void expand_symbol(struct symbol *sym, void *arg) if (__die_map_get(sym->die_addr, DIE_SYMBOL, &cache)) return; /* We'll warn about missing CRCs later. */ - type_expand(cache, &type, false); + if (stable && kabi_get_type_string(sym->name, &override)) + type_parse(sym->name, override, &type); + else + type_expand(cache, &type, false); /* If the symbol already has a version, don't calculate it again. */ if (sym->state != SYMBOL_PROCESSED) { - calculate_version(&version, &type.expanded); + calculate_version(&version, &type); symbol_set_crc(sym, version.crc); debug("%s = %lx", sym->name, version.crc); diff --git a/scripts/genksyms/genksyms.c b/scripts/genksyms/genksyms.c index 8b0d7ac73dbb..83e48670c2fc 100644 --- a/scripts/genksyms/genksyms.c +++ b/scripts/genksyms/genksyms.c @@ -181,13 +181,9 @@ static int is_unknown_symbol(struct symbol *sym) strcmp(defn->string, "{") == 0); } -static struct symbol *__add_symbol(const char *name, enum symbol_type type, - struct string_list *defn, int is_extern, - int is_reference) +static struct string_list *process_enum(const char *name, enum symbol_type type, + struct string_list *defn) { - unsigned long h; - struct symbol *sym; - enum symbol_status status = STATUS_UNCHANGED; /* The parser adds symbols in the order their declaration completes, * so it is safe to store the value of the previous enum constant in * a static variable. @@ -216,7 +212,7 @@ static struct symbol *__add_symbol(const char *name, enum symbol_type type, defn = mk_node(buf); } } - } else if (type == SYM_ENUM) { + } else { free_list(last_enum_expr, NULL); last_enum_expr = NULL; enum_counter = 0; @@ -225,6 +221,23 @@ static struct symbol *__add_symbol(const char *name, enum symbol_type type, return NULL; } + return defn; +} + +static struct symbol *__add_symbol(const char *name, enum symbol_type type, + struct string_list *defn, int is_extern, + int is_reference) +{ + unsigned long h; + struct symbol *sym; + enum symbol_status status = STATUS_UNCHANGED; + + if ((type == SYM_ENUM_CONST || type == SYM_ENUM) && !is_reference) { + defn = process_enum(name, type, defn); + if (defn == NULL) + return NULL; + } + h = crc32(name); hash_for_each_possible(symbol_hashtable, sym, hnode, h) { if (map_to_ns(sym->type) != map_to_ns(type) || diff --git a/scripts/git-resolve.sh b/scripts/git-resolve.sh new file mode 100755 index 000000000000..e9b5940c0f28 --- /dev/null +++ b/scripts/git-resolve.sh @@ -0,0 +1,201 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 +# (c) 2025, Sasha Levin <sashal@kernel.org> + +usage() { + echo "Usage: $(basename "$0") [--selftest] [--force] <commit-id> [commit-subject]" + echo "Resolves a short git commit ID to its full SHA-1 hash, particularly useful for fixing references in commit messages." + echo "" + echo "Arguments:" + echo " --selftest Run self-tests" + echo " --force Try to find commit by subject if ID lookup fails" + echo " commit-id Short git commit ID to resolve" + echo " commit-subject Optional commit subject to help resolve between multiple matches" + exit 1 +} + +# Convert subject with ellipsis to grep pattern +convert_to_grep_pattern() { + local subject="$1" + # First escape ALL regex special characters + local escaped_subject + escaped_subject=$(printf '%s\n' "$subject" | sed 's/[[\.*^$()+?{}|]/\\&/g') + # Also escape colons, parentheses, and hyphens as they are special in our context + escaped_subject=$(echo "$escaped_subject" | sed 's/[:-]/\\&/g') + # Then convert escaped ... sequence to .*? + escaped_subject=$(echo "$escaped_subject" | sed 's/\\\.\\\.\\\./.*?/g') + echo "^${escaped_subject}$" +} + +git_resolve_commit() { + local force=0 + if [ "$1" = "--force" ]; then + force=1 + shift + fi + + # Split input into commit ID and subject + local input="$*" + local commit_id="${input%% *}" + local subject="" + + # Extract subject if present (everything after the first space) + if [[ "$input" == *" "* ]]; then + subject="${input#* }" + # Strip the ("...") quotes if present + subject="${subject#*(\"}" + subject="${subject%\")*}" + fi + + # Get all possible matching commit IDs + local matches + readarray -t matches < <(git rev-parse --disambiguate="$commit_id" 2>/dev/null) + + # Return immediately if we have exactly one match + if [ ${#matches[@]} -eq 1 ]; then + echo "${matches[0]}" + return 0 + fi + + # If no matches and not in force mode, return failure + if [ ${#matches[@]} -eq 0 ] && [ $force -eq 0 ]; then + return 1 + fi + + # If we have a subject, try to find a match with that subject + if [ -n "$subject" ]; then + # Convert subject with possible ellipsis to grep pattern + local grep_pattern + grep_pattern=$(convert_to_grep_pattern "$subject") + + # In force mode with no ID matches, use git log --grep directly + if [ ${#matches[@]} -eq 0 ] && [ $force -eq 1 ]; then + # Use git log to search, but filter to ensure subject matches exactly + local match + match=$(git log --format="%H %s" --grep="$grep_pattern" --perl-regexp -10 | \ + while read -r hash subject; do + if echo "$subject" | grep -qP "$grep_pattern"; then + echo "$hash" + break + fi + done) + if [ -n "$match" ]; then + echo "$match" + return 0 + fi + else + # Normal subject matching for existing matches + for match in "${matches[@]}"; do + if git log -1 --format="%s" "$match" | grep -qP "$grep_pattern"; then + echo "$match" + return 0 + fi + done + fi + fi + + # No match found + return 1 +} + +run_selftest() { + local test_cases=( + '00250b5 ("MAINTAINERS: add new Rockchip SoC list")' + '0037727 ("KVM: selftests: Convert xen_shinfo_test away from VCPU_ID")' + 'ffef737 ("net/tls: Fix skb memory leak when running kTLS traffic")' + 'd3d7 ("cifs: Improve guard for excluding $LXDEV xattr")' + 'dbef ("Rename .data.once to .data..once to fix resetting WARN*_ONCE")' + '12345678' # Non-existent commit + '12345 ("I'\''m a dummy commit")' # Valid prefix but wrong subject + '--force 99999999 ("net/tls: Fix skb memory leak when running kTLS traffic")' # Force mode with non-existent ID but valid subject + '83be ("firmware: ... auto-update: fix poll_complete() ... errors")' # Wildcard test + '--force 999999999999 ("firmware: ... auto-update: fix poll_complete() ... errors")' # Force mode wildcard test + ) + + local expected=( + "00250b529313d6262bb0ebbd6bdf0a88c809f6f0" + "0037727b3989c3fe1929c89a9a1dfe289ad86f58" + "ffef737fd0372ca462b5be3e7a592a8929a82752" + "d3d797e326533794c3f707ce1761da7a8895458c" + "dbefa1f31a91670c9e7dac9b559625336206466f" + "" # Expect empty output for non-existent commit + "" # Expect empty output for wrong subject + "ffef737fd0372ca462b5be3e7a592a8929a82752" # Should find commit by subject in force mode + "83beece5aff75879bdfc6df8ba84ea88fd93050e" # Wildcard test + "83beece5aff75879bdfc6df8ba84ea88fd93050e" # Force mode wildcard test + ) + + local expected_exit_codes=( + 0 + 0 + 0 + 0 + 0 + 1 # Expect failure for non-existent commit + 1 # Expect failure for wrong subject + 0 # Should succeed in force mode + 0 # Should succeed with wildcard + 0 # Should succeed with force mode and wildcard + ) + + local failed=0 + + echo "Running self-tests..." + for i in "${!test_cases[@]}"; do + # Capture both output and exit code + local result + result=$(git_resolve_commit ${test_cases[$i]}) # Removed quotes to allow --force to be parsed + local exit_code=$? + + # Check both output and exit code + if [ "$result" != "${expected[$i]}" ] || [ $exit_code != ${expected_exit_codes[$i]} ]; then + echo "Test case $((i+1)) FAILED" + echo "Input: ${test_cases[$i]}" + echo "Expected output: '${expected[$i]}'" + echo "Got output: '$result'" + echo "Expected exit code: ${expected_exit_codes[$i]}" + echo "Got exit code: $exit_code" + failed=1 + else + echo "Test case $((i+1)) PASSED" + fi + done + + if [ $failed -eq 0 ]; then + echo "All tests passed!" + exit 0 + else + echo "Some tests failed!" + exit 1 + fi +} + +# Check for selftest +if [ "$1" = "--selftest" ]; then + run_selftest + exit $? +fi + +# Handle --force flag +force="" +if [ "$1" = "--force" ]; then + force="--force" + shift +fi + +# Verify arguments +if [ $# -eq 0 ]; then + usage +fi + +# Skip validation in force mode +if [ -z "$force" ]; then + # Validate that the first argument matches at least one git commit + if [ "$(git rev-parse --disambiguate="$1" 2>/dev/null | wc -l)" -eq 0 ]; then + echo "Error: '$1' does not match any git commit" + exit 1 + fi +fi + +git_resolve_commit $force "$@" +exit $? diff --git a/scripts/kconfig/expr.h b/scripts/kconfig/expr.h index 21578dcd4292..fe2231e0e6a4 100644 --- a/scripts/kconfig/expr.h +++ b/scripts/kconfig/expr.h @@ -205,15 +205,26 @@ struct property { for (st = sym->prop; st; st = st->next) \ if (st->text) +enum menu_type { + M_CHOICE, // "choice" + M_COMMENT, // "comment" + M_IF, // "if" + M_MENU, // "mainmenu", "menu", "menuconfig" + M_NORMAL, // others, i.e., "config" +}; + /* * Represents a node in the menu tree, as seen in e.g. menuconfig (though used * for all front ends). Each symbol, menu, etc. defined in the Kconfig files * gets a node. A symbol defined in multiple locations gets one node at each * location. * + * @type: type of the menu entry * @choice_members: list of choice members with priority. */ struct menu { + enum menu_type type; + /* The next menu node at the same level */ struct menu *next; diff --git a/scripts/kconfig/lkc.h b/scripts/kconfig/lkc.h index b8ebc3094a23..fbc907f75eac 100644 --- a/scripts/kconfig/lkc.h +++ b/scripts/kconfig/lkc.h @@ -81,7 +81,7 @@ void _menu_init(void); void menu_warn(const struct menu *menu, const char *fmt, ...); struct menu *menu_add_menu(void); void menu_end_menu(void); -void menu_add_entry(struct symbol *sym); +void menu_add_entry(struct symbol *sym, enum menu_type type); void menu_add_dep(struct expr *dep); void menu_add_visibility(struct expr *dep); struct property *menu_add_prompt(enum prop_type type, const char *prompt, diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c index 6587ac86d0d5..7d48a692bd27 100644 --- a/scripts/kconfig/menu.c +++ b/scripts/kconfig/menu.c @@ -15,7 +15,7 @@ static const char nohelp_text[] = "There is no help available for this option."; -struct menu rootmenu; +struct menu rootmenu = { .type = M_MENU }; static struct menu **last_entry_ptr; /** @@ -65,12 +65,13 @@ void _menu_init(void) last_entry_ptr = &rootmenu.list; } -void menu_add_entry(struct symbol *sym) +void menu_add_entry(struct symbol *sym, enum menu_type type) { struct menu *menu; menu = xmalloc(sizeof(*menu)); memset(menu, 0, sizeof(*menu)); + menu->type = type; menu->sym = sym; menu->parent = current_menu; menu->filename = cur_filename; diff --git a/scripts/kconfig/parser.y b/scripts/kconfig/parser.y index 68372d3ff325..e9c3c664e925 100644 --- a/scripts/kconfig/parser.y +++ b/scripts/kconfig/parser.y @@ -139,7 +139,7 @@ stmt_list_in_choice: config_entry_start: T_CONFIG nonconst_symbol T_EOL { - menu_add_entry($2); + menu_add_entry($2, M_NORMAL); printd(DEBUG_PARSE, "%s:%d:config %s\n", cur_filename, cur_lineno, $2->name); }; @@ -173,7 +173,7 @@ config_stmt: config_entry_start config_option_list menuconfig_entry_start: T_MENUCONFIG nonconst_symbol T_EOL { - menu_add_entry($2); + menu_add_entry($2, M_MENU); printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", cur_filename, cur_lineno, $2->name); }; @@ -246,7 +246,7 @@ choice: T_CHOICE T_EOL { struct symbol *sym = sym_lookup(NULL, 0); - menu_add_entry(sym); + menu_add_entry(sym, M_CHOICE); menu_set_type(S_BOOLEAN); INIT_LIST_HEAD(¤t_entry->choice_members); @@ -315,7 +315,7 @@ default: if_entry: T_IF expr T_EOL { printd(DEBUG_PARSE, "%s:%d:if\n", cur_filename, cur_lineno); - menu_add_entry(NULL); + menu_add_entry(NULL, M_IF); menu_add_dep($2); $$ = menu_add_menu(); }; @@ -338,7 +338,7 @@ if_stmt_in_choice: if_entry stmt_list_in_choice if_end menu: T_MENU T_WORD_QUOTE T_EOL { - menu_add_entry(NULL); + menu_add_entry(NULL, M_MENU); menu_add_prompt(P_MENU, $2, NULL); printd(DEBUG_PARSE, "%s:%d:menu\n", cur_filename, cur_lineno); }; @@ -376,7 +376,7 @@ source_stmt: T_SOURCE T_WORD_QUOTE T_EOL comment: T_COMMENT T_WORD_QUOTE T_EOL { - menu_add_entry(NULL); + menu_add_entry(NULL, M_COMMENT); menu_add_prompt(P_COMMENT, $2, NULL); printd(DEBUG_PARSE, "%s:%d:comment\n", cur_filename, cur_lineno); }; diff --git a/scripts/misc-check b/scripts/misc-check index d40d5484e0c5..a74450e799d1 100755 --- a/scripts/misc-check +++ b/scripts/misc-check @@ -3,17 +3,65 @@ set -e -# Detect files that are tracked but ignored by git. This is checked only when -# ${KBUILD_EXTRA_WARN} contains 1, git is installed, and the source tree is -# tracked by git. +# Detect files that are tracked but ignored by git. check_tracked_ignored_files () { - case "${KBUILD_EXTRA_WARN}" in - *1*) ;; - *) return;; - esac - - git -C ${srctree:-.} ls-files -i -c --exclude-per-directory=.gitignore 2>/dev/null | + git -C "${srctree:-.}" ls-files -i -c --exclude-per-directory=.gitignore 2>/dev/null | sed 's/$/: warning: ignored by one of the .gitignore files/' >&2 } +# Check for missing #include <linux/export.h> +# +# The rule for including <linux/export.h> is very simple: +# Include <linux/export.h> only when you use EXPORT_SYMBOL(). That's it. +# +# However, some headers include <linux/export.h> even though they are completely +# unrelated to EXPORT_SYMBOL(). +# +# One example is include/linux/module.h. Please note <linux/module.h> and +# <linux/export.h> are orthogonal. <linux/module.h> should be included by files +# that can be compiled as modules. In other words, <linux/module.h> should be +# included by EXPORT_SYMBOL consumers. In contrast, <linux/export.h> should be +# included from EXPORT_SYMBOL providers, which may or may not be modular. +# Hence, include/linux/module.h should *not* include <linux/export.h>. +# +# Another example is include/linux/linkage.h, which is completely unrelated to +# EXPORT_SYMBOL(). Worse, it is included by most C files, which means, most C +# files end up including <linux/export.h>, even though only some of them +# actually export symbols. Hence, include/linux/linkage.h should *not* include +# <linux/export.h>. +# +# Before fixing such headers, we must ensure that C files using EXPORT_SYMBOL() +# include <linux/export.h> directly, since many C files currently rely on +# <linux/export.h> being included indirectly (likely, via <linux/linkage> etc.). +# +# Therefore, this check. +# +# The problem is simple - the warned files use EXPORT_SYMBOL(), but do not +# include <linux/export.h>. Please add #include <linux/export.h> to them. +# +# If the included headers are sorted alphabetically, please insert +# <linux/export.h> in the appropriate position to maintain the sort order. +# For this reason, this script only checks missing <linux/export.h>, but +# does not automatically fix it. +check_missing_include_linux_export_h () { + + git -C "${srctree:-.}" grep --files-with-matches -E 'EXPORT_SYMBOL((_NS)?(_GPL)?|_GPL_FOR_MODULES)\(.*\)' \ + -- '*.[ch]' :^tools/ :^include/linux/export.h | + xargs -r git -C "${srctree:-.}" grep --files-without-match '#include[[:space:]]*<linux/export\.h>' | + xargs -r printf "%s: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing\n" >&2 +} + +# If you do not use EXPORT_SYMBOL(), please do not include <linux/export.h>. +# Currently, this is checked for *.c files, but not for *.h files, because some +# *.c files rely on <linux/export.h> being included indirectly. +check_unnecessary_include_linux_export_h () { + + git -C "${srctree:-.}" grep --files-with-matches '#include[[:space:]]*<linux/export\.h>' \ + -- '*.[c]' :^tools/ | + xargs -r git -C "${srctree:-.}" grep --files-without-match -E 'EXPORT_SYMBOL((_NS)?(_GPL)?|_GPL_FOR_MODULES)\(.*\)' | + xargs -r printf "%s: warning: EXPORT_SYMBOL() is not used, but #include <linux/export.h> is present\n" >&2 +} + check_tracked_ignored_files +check_missing_include_linux_export_h +check_unnecessary_include_linux_export_h diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index be89921d60b6..5ca7c268294e 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -28,6 +28,8 @@ #include "modpost.h" #include "../../include/linux/license.h" +#define MODULE_NS_PREFIX "module:" + static bool module_enabled; /* Are we using CONFIG_MODVERSIONS? */ static bool modversions; @@ -1595,11 +1597,14 @@ static void read_symbols(const char *modname) license = get_next_modinfo(&info, "license", license); } - namespace = get_modinfo(&info, "import_ns"); - while (namespace) { + for (namespace = get_modinfo(&info, "import_ns"); + namespace; + namespace = get_next_modinfo(&info, "import_ns", namespace)) { + if (strstarts(namespace, MODULE_NS_PREFIX)) + error("%s: explicitly importing namespace \"%s\" is not allowed.\n", + mod->name, namespace); + add_namespace(&mod->imported_namespaces, namespace); - namespace = get_next_modinfo(&info, "import_ns", - namespace); } if (!get_modinfo(&info, "description")) @@ -1684,6 +1689,46 @@ void buf_write(struct buffer *buf, const char *s, int len) buf->pos += len; } +/** + * verify_module_namespace() - does @modname have access to this symbol's @namespace + * @namespace: export symbol namespace + * @modname: module name + * + * If @namespace is prefixed with "module:" to indicate it is a module namespace + * then test if @modname matches any of the comma separated patterns. + * + * The patterns only support tail-glob. + */ +static bool verify_module_namespace(const char *namespace, const char *modname) +{ + size_t len, modlen = strlen(modname); + const char *prefix = "module:"; + const char *sep; + bool glob; + + if (!strstarts(namespace, prefix)) + return false; + + for (namespace += strlen(prefix); *namespace; namespace = sep) { + sep = strchrnul(namespace, ','); + len = sep - namespace; + + glob = false; + if (sep[-1] == '*') { + len--; + glob = true; + } + + if (*sep) + sep++; + + if (strncmp(namespace, modname, len) == 0 && (glob || len == modlen)) + return true; + } + + return false; +} + static void check_exports(struct module *mod) { struct symbol *s, *exp; @@ -1711,7 +1756,8 @@ static void check_exports(struct module *mod) basename = get_basename(mod->name); - if (!contains_namespace(&mod->imported_namespaces, exp->namespace)) { + if (!verify_module_namespace(exp->namespace, basename) && + !contains_namespace(&mod->imported_namespaces, exp->namespace)) { modpost_log(!allow_missing_ns_imports, "module %s uses symbol %s from namespace %s, but does not import it.\n", basename, exp->name, exp->namespace); diff --git a/scripts/tags.sh b/scripts/tags.sh index 98680e9cd7be..99ce427d9a69 100755 --- a/scripts/tags.sh +++ b/scripts/tags.sh @@ -344,7 +344,7 @@ case "$1" in "tags") rm -f tags - xtags ctags + xtags ${CTAGS:-ctags} remove_structs=y ;; diff --git a/sound/core/jack.c b/sound/core/jack.c index 850f82340278..93e357a23f17 100644 --- a/sound/core/jack.c +++ b/sound/core/jack.c @@ -34,6 +34,7 @@ static const int jack_switch_types[SND_JACK_SWITCH_TYPES] = { SW_JACK_PHYSICAL_INSERT, SW_VIDEOOUT_INSERT, SW_LINEIN_INSERT, + SW_USB_INSERT, }; #endif /* CONFIG_SND_JACK_INPUT_DEV */ @@ -241,8 +242,9 @@ static ssize_t jack_kctl_id_read(struct file *file, static const char * const jack_events_name[] = { "HEADPHONE(0x0001)", "MICROPHONE(0x0002)", "LINEOUT(0x0004)", "MECHANICAL(0x0008)", "VIDEOOUT(0x0010)", "LINEIN(0x0020)", - "", "", "", "BTN_5(0x0200)", "BTN_4(0x0400)", "BTN_3(0x0800)", - "BTN_2(0x1000)", "BTN_1(0x2000)", "BTN_0(0x4000)", "", + "USB(0x0040)", "", "", "BTN_5(0x0200)", "BTN_4(0x0400)", + "BTN_3(0x0800)", "BTN_2(0x1000)", "BTN_1(0x2000)", "BTN_0(0x4000)", + "", }; /* the recommended buffer size is 256 */ diff --git a/sound/core/timer.c b/sound/core/timer.c index 1de4b90fd4d1..8072183c33d3 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -1118,8 +1118,8 @@ struct snd_timer_system_private { static void snd_timer_s_function(struct timer_list *t) { - struct snd_timer_system_private *priv = from_timer(priv, t, - tlist); + struct snd_timer_system_private *priv = timer_container_of(priv, t, + tlist); struct snd_timer *timer = priv->snd_timer; unsigned long jiff = jiffies; if (time_after(jiff, priv->last_expires)) diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c index 4b02ec127cc0..6c318a5903ab 100644 --- a/sound/drivers/aloop.c +++ b/sound/drivers/aloop.c @@ -699,7 +699,7 @@ static unsigned int loopback_jiffies_timer_pos_update static void loopback_jiffies_timer_function(struct timer_list *t) { - struct loopback_pcm *dpcm = from_timer(dpcm, t, timer); + struct loopback_pcm *dpcm = timer_container_of(dpcm, t, timer); unsigned long flags; spin_lock_irqsave(&dpcm->cable->lock, flags); diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c index 1d923cbe8cd0..783fe3a22bc9 100644 --- a/sound/drivers/dummy.c +++ b/sound/drivers/dummy.c @@ -301,7 +301,7 @@ static int dummy_systimer_prepare(struct snd_pcm_substream *substream) static void dummy_systimer_callback(struct timer_list *t) { - struct dummy_systimer_pcm *dpcm = from_timer(dpcm, t, timer); + struct dummy_systimer_pcm *dpcm = timer_container_of(dpcm, t, timer); unsigned long flags; int elapsed = 0; diff --git a/sound/drivers/mpu401/mpu401_uart.c b/sound/drivers/mpu401/mpu401_uart.c index a63e7558ac07..670f8ba92c08 100644 --- a/sound/drivers/mpu401/mpu401_uart.c +++ b/sound/drivers/mpu401/mpu401_uart.c @@ -157,7 +157,7 @@ EXPORT_SYMBOL(snd_mpu401_uart_interrupt_tx); */ static void snd_mpu401_uart_timer(struct timer_list *t) { - struct snd_mpu401 *mpu = from_timer(mpu, t, timer); + struct snd_mpu401 *mpu = timer_container_of(mpu, t, timer); unsigned long flags; spin_lock_irqsave(&mpu->timer_lock, flags); diff --git a/sound/drivers/mtpav.c b/sound/drivers/mtpav.c index dffcdf9e10d4..851f34e2cdd0 100644 --- a/sound/drivers/mtpav.c +++ b/sound/drivers/mtpav.c @@ -388,7 +388,7 @@ static void snd_mtpav_input_trigger(struct snd_rawmidi_substream *substream, int static void snd_mtpav_output_timer(struct timer_list *t) { unsigned long flags; - struct mtpav *chip = from_timer(chip, t, timer); + struct mtpav *chip = timer_container_of(chip, t, timer); int p; spin_lock_irqsave(&chip->spinlock, flags); diff --git a/sound/drivers/opl3/opl3_midi.c b/sound/drivers/opl3/opl3_midi.c index 9bee454441b0..de7449cb6515 100644 --- a/sound/drivers/opl3/opl3_midi.c +++ b/sound/drivers/opl3/opl3_midi.c @@ -233,7 +233,7 @@ static int opl3_get_voice(struct snd_opl3 *opl3, int instr_4op, void snd_opl3_timer_func(struct timer_list *t) { - struct snd_opl3 *opl3 = from_timer(opl3, t, tlist); + struct snd_opl3 *opl3 = timer_container_of(opl3, t, tlist); unsigned long flags; int again = 0; int i; diff --git a/sound/drivers/pcmtest.c b/sound/drivers/pcmtest.c index 72378f354fd0..39f1e1fe4c44 100644 --- a/sound/drivers/pcmtest.c +++ b/sound/drivers/pcmtest.c @@ -345,7 +345,7 @@ static void timer_timeout(struct timer_list *data) struct pcmtst_buf_iter *v_iter; struct snd_pcm_substream *substream; - v_iter = from_timer(v_iter, data, timer_instance); + v_iter = timer_container_of(v_iter, data, timer_instance); substream = v_iter->substream; if (v_iter->suspend) diff --git a/sound/drivers/serial-u16550.c b/sound/drivers/serial-u16550.c index 1857a78f55d7..6d0656fcd574 100644 --- a/sound/drivers/serial-u16550.c +++ b/sound/drivers/serial-u16550.c @@ -299,7 +299,7 @@ static void snd_uart16550_buffer_timer(struct timer_list *t) unsigned long flags; struct snd_uart16550 *uart; - uart = from_timer(uart, t, buffer_timer); + uart = timer_container_of(uart, t, buffer_timer); spin_lock_irqsave(&uart->open_lock, flags); snd_uart16550_del_timer(uart); snd_uart16550_io_loop(uart); diff --git a/sound/i2c/other/ak4117.c b/sound/i2c/other/ak4117.c index 657b331d7a79..cd380db195ef 100644 --- a/sound/i2c/other/ak4117.c +++ b/sound/i2c/other/ak4117.c @@ -504,7 +504,7 @@ int snd_ak4117_check_rate_and_errors(struct ak4117 *ak4117, unsigned int flags) static void snd_ak4117_timer(struct timer_list *t) { - struct ak4117 *chip = from_timer(chip, t, timer); + struct ak4117 *chip = timer_container_of(chip, t, timer); if (chip->init) return; diff --git a/sound/isa/sb/emu8000_pcm.c b/sound/isa/sb/emu8000_pcm.c index 016235209928..215bbcd0360e 100644 --- a/sound/isa/sb/emu8000_pcm.c +++ b/sound/isa/sb/emu8000_pcm.c @@ -182,7 +182,7 @@ static inline int emu8k_get_curpos(struct snd_emu8k_pcm *rec, int ch) */ static void emu8k_pcm_timer_func(struct timer_list *t) { - struct snd_emu8k_pcm *rec = from_timer(rec, t, timer); + struct snd_emu8k_pcm *rec = timer_container_of(rec, t, timer); int ptr, delta; spin_lock(&rec->timer_lock); diff --git a/sound/isa/sb/sb8_midi.c b/sound/isa/sb/sb8_midi.c index 57867e51d367..637079a2f02a 100644 --- a/sound/isa/sb/sb8_midi.c +++ b/sound/isa/sb/sb8_midi.c @@ -200,7 +200,7 @@ static void snd_sb8dsp_midi_output_write(struct snd_rawmidi_substream *substream static void snd_sb8dsp_midi_output_timer(struct timer_list *t) { - struct snd_sb *chip = from_timer(chip, t, midi_timer); + struct snd_sb *chip = timer_container_of(chip, t, midi_timer); struct snd_rawmidi_substream *substream = chip->midi_substream_output; unsigned long flags; diff --git a/sound/isa/wavefront/wavefront_midi.c b/sound/isa/wavefront/wavefront_midi.c index fcc2a0d67792..494b21be665c 100644 --- a/sound/isa/wavefront/wavefront_midi.c +++ b/sound/isa/wavefront/wavefront_midi.c @@ -352,7 +352,7 @@ static void snd_wavefront_midi_input_trigger(struct snd_rawmidi_substream *subst static void snd_wavefront_midi_output_timer(struct timer_list *t) { - snd_wavefront_midi_t *midi = from_timer(midi, t, timer); + snd_wavefront_midi_t *midi = timer_container_of(midi, t, timer); snd_wavefront_card_t *card = midi->timer_card; unsigned long flags; diff --git a/sound/pci/asihpi/asihpi.c b/sound/pci/asihpi/asihpi.c index 7e5ce96954b9..cbd964f87349 100644 --- a/sound/pci/asihpi/asihpi.c +++ b/sound/pci/asihpi/asihpi.c @@ -709,7 +709,7 @@ static inline unsigned int modulo_min(unsigned int a, unsigned int b, */ static void snd_card_asihpi_timer_function(struct timer_list *t) { - struct snd_card_asihpi_pcm *dpcm = from_timer(dpcm, t, timer); + struct snd_card_asihpi_pcm *dpcm = timer_container_of(dpcm, t, timer); struct snd_pcm_substream *substream = dpcm->substream; struct snd_card_asihpi *card = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime; diff --git a/sound/pci/ctxfi/cttimer.c b/sound/pci/ctxfi/cttimer.c index aa179644b5c9..fa6867adb42b 100644 --- a/sound/pci/ctxfi/cttimer.c +++ b/sound/pci/ctxfi/cttimer.c @@ -62,7 +62,7 @@ struct ct_timer { static void ct_systimer_callback(struct timer_list *t) { - struct ct_timer_instance *ti = from_timer(ti, t, timer); + struct ct_timer_instance *ti = timer_container_of(ti, t, timer); struct snd_pcm_substream *substream = ti->substream; struct snd_pcm_runtime *runtime = substream->runtime; struct ct_atc_pcm *apcm = ti->apcm; diff --git a/sound/pci/echoaudio/midi.c b/sound/pci/echoaudio/midi.c index 2ef59184249c..c3f3c9129561 100644 --- a/sound/pci/echoaudio/midi.c +++ b/sound/pci/echoaudio/midi.c @@ -200,7 +200,7 @@ static int snd_echo_midi_output_open(struct snd_rawmidi_substream *substream) static void snd_echo_midi_output_write(struct timer_list *t) { - struct echoaudio *chip = from_timer(chip, t, timer); + struct echoaudio *chip = timer_container_of(chip, t, timer); unsigned long flags; int bytes, sent, time; unsigned char buf[MIDI_OUT_BUFFER_SIZE - 1]; diff --git a/sound/pci/hda/cs35l41_hda.c b/sound/pci/hda/cs35l41_hda.c index d9c8872b1866..d5bc81099d0d 100644 --- a/sound/pci/hda/cs35l41_hda.c +++ b/sound/pci/hda/cs35l41_hda.c @@ -1603,7 +1603,7 @@ static const struct regmap_irq cs35l41_reg_irqs[] = { CS35L41_REG_IRQ(IRQ1_STATUS1, AMP_SHORT_ERR), }; -static struct regmap_irq_chip cs35l41_regmap_irq_chip = { +static const struct regmap_irq_chip cs35l41_regmap_irq_chip = { .name = "cs35l41 IRQ1 Controller", .status_base = CS35L41_IRQ1_STATUS1, .mask_base = CS35L41_IRQ1_MASK1, diff --git a/sound/pci/hda/hda_bind.c b/sound/pci/hda/hda_bind.c index 1fef350d821e..df8f88beddd0 100644 --- a/sound/pci/hda/hda_bind.c +++ b/sound/pci/hda/hda_bind.c @@ -44,7 +44,7 @@ static void hda_codec_unsol_event(struct hdac_device *dev, unsigned int ev) struct hda_codec *codec = container_of(dev, struct hda_codec, core); /* ignore unsol events during shutdown */ - if (codec->bus->shutdown) + if (codec->card->shutdown || codec->bus->shutdown) return; /* ignore unsol events during system suspend/resume */ diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index e6df706f740d..e5210ed48ddf 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -2724,6 +2724,9 @@ static const struct pci_device_id azx_ids[] = { { PCI_VDEVICE(ATI, 0xab38), .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS | AZX_DCAPS_PM_RUNTIME }, + { PCI_VDEVICE(ATI, 0xab40), + .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS | + AZX_DCAPS_PM_RUNTIME }, /* GLENFLY */ { PCI_DEVICE(PCI_VENDOR_ID_GLENFLY, PCI_ANY_ID), .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8, diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c index 873b7eadfc50..8df0f5bba0f6 100644 --- a/sound/pci/rme9652/hdsp.c +++ b/sound/pci/rme9652/hdsp.c @@ -1393,7 +1393,7 @@ static void snd_hdsp_midi_input_trigger(struct snd_rawmidi_substream *substream, static void snd_hdsp_midi_output_timer(struct timer_list *t) { - struct hdsp_midi *hmidi = from_timer(hmidi, t, timer); + struct hdsp_midi *hmidi = timer_container_of(hmidi, t, timer); unsigned long flags; snd_hdsp_midi_output_write(hmidi); diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index 64de54089955..2041cf00cca0 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -1943,7 +1943,7 @@ snd_hdspm_midi_input_trigger(struct snd_rawmidi_substream *substream, int up) static void snd_hdspm_midi_output_timer(struct timer_list *t) { - struct hdspm_midi *hmidi = from_timer(hmidi, t, timer); + struct hdspm_midi *hmidi = timer_container_of(hmidi, t, timer); unsigned long flags; snd_hdspm_midi_output_write(hmidi); diff --git a/sound/sh/aica.c b/sound/sh/aica.c index f88331a48638..40ea843113a7 100644 --- a/sound/sh/aica.c +++ b/sound/sh/aica.c @@ -284,8 +284,8 @@ static void run_spu_dma(struct work_struct *work) static void aica_period_elapsed(struct timer_list *t) { - struct snd_card_aica *dreamcastcard = from_timer(dreamcastcard, - t, timer); + struct snd_card_aica *dreamcastcard = timer_container_of(dreamcastcard, + t, timer); struct snd_pcm_substream *substream = dreamcastcard->substream; /*timer function - so cannot sleep */ int play_period; diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index 8b7d51266f81..1b983c7006f1 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig @@ -91,6 +91,16 @@ config SND_SOC_OPS_KUNIT_TEST config SND_SOC_ACPI tristate +config SND_SOC_USB + tristate "SoC based USB audio offloading" + depends on SND_USB_AUDIO + help + Enable this option if an ASoC platform card has support to handle + USB audio offloading. This enables the SoC USB layer, which will + notify the ASoC USB DPCM backend DAI link about available USB audio + devices. Based on the notifications, sequences to enable the audio + stream can be taken based on the design. + # All the supported SoCs source "sound/soc/adi/Kconfig" source "sound/soc/amd/Kconfig" diff --git a/sound/soc/Makefile b/sound/soc/Makefile index 358e227c5ab6..462322c38aa4 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile @@ -39,6 +39,8 @@ endif obj-$(CONFIG_SND_SOC_ACPI) += snd-soc-acpi.o +obj-$(CONFIG_SND_SOC_USB) += soc-usb.o + obj-$(CONFIG_SND_SOC) += snd-soc-core.o obj-$(CONFIG_SND_SOC) += codecs/ obj-$(CONFIG_SND_SOC) += generic/ diff --git a/sound/soc/amd/yc/acp6x-mach.c b/sound/soc/amd/yc/acp6x-mach.c index 3d9da93d22ee..7e62445e02c1 100644 --- a/sound/soc/amd/yc/acp6x-mach.c +++ b/sound/soc/amd/yc/acp6x-mach.c @@ -315,6 +315,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = { .driver_data = &acp6x_card, .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_NAME, "83BS"), + } + }, + { + .driver_data = &acp6x_card, + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), DMI_MATCH(DMI_PRODUCT_NAME, "83HN"), } }, diff --git a/sound/soc/codecs/es8375.c b/sound/soc/codecs/es8375.c index decc86c92427..009259632107 100644 --- a/sound/soc/codecs/es8375.c +++ b/sound/soc/codecs/es8375.c @@ -319,6 +319,7 @@ static int es8375_hw_params(struct snd_pcm_substream *substream, coeff = get_coeff(es8375->vddd, dmic_enable, es8375->mclk_freq, params_rate(params)); if (coeff < 0) { dev_warn(component->dev, "Clock coefficients do not match"); + return coeff; } regmap_write(es8375->regmap, ES8375_CLK_MGR4, coeff_div[coeff].Reg0x04); diff --git a/sound/soc/codecs/hda.c b/sound/soc/codecs/hda.c index ddc00927313c..dc7794c9ac44 100644 --- a/sound/soc/codecs/hda.c +++ b/sound/soc/codecs/hda.c @@ -152,7 +152,7 @@ int hda_codec_probe_complete(struct hda_codec *codec) ret = snd_hda_codec_build_controls(codec); if (ret < 0) { dev_err(&hdev->dev, "unable to create controls %d\n", ret); - goto out; + return ret; } /* Bus suspended codecs as it does not manage their pm */ @@ -160,7 +160,7 @@ int hda_codec_probe_complete(struct hda_codec *codec) /* rpm was forbidden in snd_hda_codec_device_new() */ snd_hda_codec_set_power_save(codec, 2000); snd_hda_codec_register(codec); -out: + /* Complement pm_runtime_get_sync(bus) in probe */ pm_runtime_mark_last_busy(bus->dev); pm_runtime_put_autosuspend(bus->dev); diff --git a/sound/soc/codecs/rt1320-sdw.c b/sound/soc/codecs/rt1320-sdw.c index f51ba345a16e..015cc710e6dc 100644 --- a/sound/soc/codecs/rt1320-sdw.c +++ b/sound/soc/codecs/rt1320-sdw.c @@ -204,7 +204,7 @@ static const struct reg_sequence rt1320_vc_blind_write[] = { { 0x3fc2bfc0, 0x03 }, { 0x0000d486, 0x43 }, { SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0x00 }, - { 0x1000db00, 0x04 }, + { 0x1000db00, 0x07 }, { 0x1000db01, 0x00 }, { 0x1000db02, 0x11 }, { 0x1000db03, 0x00 }, @@ -225,6 +225,21 @@ static const struct reg_sequence rt1320_vc_blind_write[] = { { 0x1000db12, 0x00 }, { 0x1000db13, 0x00 }, { 0x1000db14, 0x45 }, + { 0x1000db15, 0x0d }, + { 0x1000db16, 0x01 }, + { 0x1000db17, 0x00 }, + { 0x1000db18, 0x00 }, + { 0x1000db19, 0xbf }, + { 0x1000db1a, 0x13 }, + { 0x1000db1b, 0x09 }, + { 0x1000db1c, 0x00 }, + { 0x1000db1d, 0x00 }, + { 0x1000db1e, 0x00 }, + { 0x1000db1f, 0x12 }, + { 0x1000db20, 0x09 }, + { 0x1000db21, 0x00 }, + { 0x1000db22, 0x00 }, + { 0x1000db23, 0x00 }, { 0x0000d540, 0x01 }, { 0x0000c081, 0xfc }, { 0x0000f01e, 0x80 }, diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index dba78efadc85..08df87238eee 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -3439,7 +3439,8 @@ static irqreturn_t rt5645_irq(int irq, void *data) static void rt5645_btn_check_callback(struct timer_list *t) { - struct rt5645_priv *rt5645 = from_timer(rt5645, t, btn_check_timer); + struct rt5645_priv *rt5645 = timer_container_of(rt5645, t, + btn_check_timer); queue_delayed_work(system_power_efficient_wq, &rt5645->jack_detect_work, msecs_to_jiffies(5)); diff --git a/sound/soc/codecs/tas571x.c b/sound/soc/codecs/tas571x.c index 6c6e7ae07d80..6bf37c77f0a7 100644 --- a/sound/soc/codecs/tas571x.c +++ b/sound/soc/codecs/tas571x.c @@ -718,6 +718,69 @@ static const struct regmap_config tas5721_regmap_config = { .volatile_table = &tas571x_volatile_regs, }; +static const struct snd_kcontrol_new tas5733_controls[] = { + /* MVOL LSB is ignored - see comments in tas571x_i2c_probe() */ + SOC_SINGLE_TLV("Master Volume", + TAS571X_MVOL_REG, 1, 0x1ff, 1, + tas5717_volume_tlv), + SOC_DOUBLE_R_TLV("Speaker Volume", + TAS571X_CH1_VOL_REG, TAS571X_CH2_VOL_REG, + 1, 0x1ff, 1, tas5717_volume_tlv), + SOC_DOUBLE("Speaker Switch", + TAS571X_SOFT_MUTE_REG, + TAS571X_SOFT_MUTE_CH1_SHIFT, TAS571X_SOFT_MUTE_CH2_SHIFT, + 1, 1), + + SOC_DOUBLE_R_RANGE("CH1 Mixer Volume", + TAS5717_CH1_LEFT_CH_MIX_REG, + TAS5717_CH1_RIGHT_CH_MIX_REG, + 16, 0, 0x80, 0), + + SOC_DOUBLE_R_RANGE("CH2 Mixer Volume", + TAS5717_CH2_LEFT_CH_MIX_REG, + TAS5717_CH2_RIGHT_CH_MIX_REG, + 16, 0, 0x80, 0), + + /* + * The biquads are named according to the register names. + * Please note that TI's TAS57xx Graphical Development Environment + * tool names them different. + */ + BIQUAD_COEFS("CH1 - Biquad 0", TAS5733_CH1_BQ0_REG), + BIQUAD_COEFS("CH1 - Biquad 1", TAS5733_CH1_BQ1_REG), + BIQUAD_COEFS("CH1 - Biquad 2", TAS5733_CH1_BQ2_REG), + BIQUAD_COEFS("CH1 - Biquad 3", TAS5733_CH1_BQ3_REG), + BIQUAD_COEFS("CH1 - Biquad 4", TAS5733_CH1_BQ4_REG), + BIQUAD_COEFS("CH1 - Biquad 5", TAS5733_CH1_BQ5_REG), + BIQUAD_COEFS("CH1 - Biquad 6", TAS5733_CH1_BQ6_REG), + BIQUAD_COEFS("CH1 - Biquad 7", TAS5733_CH1_BQ7_REG), + BIQUAD_COEFS("CH1 - Biquad 8", TAS5733_CH1_BQ8_REG), + BIQUAD_COEFS("CH1 - Biquad 9", TAS5733_CH1_BQ9_REG), + BIQUAD_COEFS("CH1 - Biquad 10", TAS5733_CH1_BQ10_REG), + + BIQUAD_COEFS("CH2 - Biquad 0", TAS5733_CH2_BQ0_REG), + BIQUAD_COEFS("CH2 - Biquad 1", TAS5733_CH2_BQ1_REG), + BIQUAD_COEFS("CH2 - Biquad 2", TAS5733_CH2_BQ2_REG), + BIQUAD_COEFS("CH2 - Biquad 3", TAS5733_CH2_BQ3_REG), + BIQUAD_COEFS("CH2 - Biquad 4", TAS5733_CH2_BQ4_REG), + BIQUAD_COEFS("CH2 - Biquad 5", TAS5733_CH2_BQ5_REG), + BIQUAD_COEFS("CH2 - Biquad 6", TAS5733_CH2_BQ6_REG), + BIQUAD_COEFS("CH2 - Biquad 7", TAS5733_CH2_BQ7_REG), + BIQUAD_COEFS("CH2 - Biquad 8", TAS5733_CH2_BQ8_REG), + BIQUAD_COEFS("CH2 - Biquad 9", TAS5733_CH2_BQ9_REG), + BIQUAD_COEFS("CH2 - Biquad 10", TAS5733_CH2_BQ10_REG), + + BIQUAD_COEFS("CH1 - Cross Biquad 0", TAS5733_CH1_CBQ0_REG), + BIQUAD_COEFS("CH1 - Cross Biquad 1", TAS5733_CH1_CBQ1_REG), + BIQUAD_COEFS("CH1 - Cross Biquad 2", TAS5733_CH1_CBQ2_REG), + BIQUAD_COEFS("CH1 - Cross Biquad 3", TAS5733_CH1_CBQ3_REG), + + BIQUAD_COEFS("CH2 - Cross Biquad 0", TAS5733_CH2_CBQ0_REG), + BIQUAD_COEFS("CH2 - Cross Biquad 1", TAS5733_CH2_CBQ1_REG), + BIQUAD_COEFS("CH2 - Cross Biquad 2", TAS5733_CH2_CBQ2_REG), + BIQUAD_COEFS("CH2 - Cross Biquad 3", TAS5733_CH2_CBQ3_REG), +}; + static const char *const tas5733_supply_names[] = { "AVDD", "DVDD", @@ -770,8 +833,8 @@ static const struct regmap_config tas5733_regmap_config = { static const struct tas571x_chip tas5733_chip = { .supply_names = tas5733_supply_names, .num_supply_names = ARRAY_SIZE(tas5733_supply_names), - .controls = tas5717_controls, - .num_controls = ARRAY_SIZE(tas5717_controls), + .controls = tas5733_controls, + .num_controls = ARRAY_SIZE(tas5733_controls), .regmap_config = &tas5733_regmap_config, .vol_reg_size = 2, }; diff --git a/sound/soc/codecs/tas571x.h b/sound/soc/codecs/tas571x.h index 5340d3bec31d..2b3eff4023b9 100644 --- a/sound/soc/codecs/tas571x.h +++ b/sound/soc/codecs/tas571x.h @@ -104,4 +104,38 @@ #define TAS5717_CH2_LEFT_CH_MIX_REG 0x76 #define TAS5717_CH2_RIGHT_CH_MIX_REG 0x77 +#define TAS5733_CH1_BQ0_REG 0x26 +#define TAS5733_CH1_BQ1_REG 0x27 +#define TAS5733_CH1_BQ2_REG 0x28 +#define TAS5733_CH1_BQ3_REG 0x29 +#define TAS5733_CH1_BQ4_REG 0x2a +#define TAS5733_CH1_BQ5_REG 0x2b +#define TAS5733_CH1_BQ6_REG 0x2c +#define TAS5733_CH1_BQ7_REG 0x2d +#define TAS5733_CH1_BQ8_REG 0x2e +#define TAS5733_CH1_BQ9_REG 0x2f + +#define TAS5733_CH2_BQ0_REG 0x30 +#define TAS5733_CH2_BQ1_REG 0x31 +#define TAS5733_CH2_BQ2_REG 0x32 +#define TAS5733_CH2_BQ3_REG 0x33 +#define TAS5733_CH2_BQ4_REG 0x34 +#define TAS5733_CH2_BQ5_REG 0x35 +#define TAS5733_CH2_BQ6_REG 0x36 +#define TAS5733_CH2_BQ7_REG 0x37 +#define TAS5733_CH2_BQ8_REG 0x38 +#define TAS5733_CH2_BQ9_REG 0x39 + +#define TAS5733_CH1_BQ10_REG 0x58 +#define TAS5733_CH1_CBQ0_REG 0x59 +#define TAS5733_CH1_CBQ1_REG 0x5a +#define TAS5733_CH1_CBQ2_REG 0x5b +#define TAS5733_CH1_CBQ3_REG 0x5c + +#define TAS5733_CH2_BQ10_REG 0x5d +#define TAS5733_CH2_CBQ0_REG 0x5e +#define TAS5733_CH2_CBQ1_REG 0x5f +#define TAS5733_CH2_CBQ2_REG 0x60 +#define TAS5733_CH2_CBQ3_REG 0x61 + #endif /* _TAS571X_H */ diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c index 8ee4360aff92..5e19e813748d 100644 --- a/sound/soc/codecs/wcd9335.c +++ b/sound/soc/codecs/wcd9335.c @@ -332,7 +332,6 @@ struct wcd9335_codec { int intr1; struct gpio_desc *reset_gpio; - struct regulator_bulk_data supplies[WCD9335_MAX_SUPPLY]; unsigned int rx_port_value[WCD9335_RX_MAX]; unsigned int tx_port_value[WCD9335_TX_MAX]; @@ -355,6 +354,10 @@ struct wcd9335_irq { char *name; }; +static const char * const wcd9335_supplies[] = { + "vdd-buck", "vdd-buck-sido", "vdd-tx", "vdd-rx", "vdd-io", +}; + static const struct wcd9335_slim_ch wcd9335_tx_chs[WCD9335_TX_MAX] = { WCD9335_SLIM_TX_CH(0), WCD9335_SLIM_TX_CH(1), @@ -4989,30 +4992,16 @@ static int wcd9335_parse_dt(struct wcd9335_codec *wcd) if (IS_ERR(wcd->native_clk)) return dev_err_probe(dev, PTR_ERR(wcd->native_clk), "slimbus clock not found\n"); - wcd->supplies[0].supply = "vdd-buck"; - wcd->supplies[1].supply = "vdd-buck-sido"; - wcd->supplies[2].supply = "vdd-tx"; - wcd->supplies[3].supply = "vdd-rx"; - wcd->supplies[4].supply = "vdd-io"; - - ret = regulator_bulk_get(dev, WCD9335_MAX_SUPPLY, wcd->supplies); + ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(wcd9335_supplies), + wcd9335_supplies); if (ret) - return dev_err_probe(dev, ret, "Failed to get supplies\n"); + return dev_err_probe(dev, ret, "Failed to get and enable supplies\n"); return 0; } static int wcd9335_power_on_reset(struct wcd9335_codec *wcd) { - struct device *dev = wcd->dev; - int ret; - - ret = regulator_bulk_enable(WCD9335_MAX_SUPPLY, wcd->supplies); - if (ret) { - dev_err(dev, "Failed to get supplies: err = %d\n", ret); - return ret; - } - /* * For WCD9335, it takes about 600us for the Vout_A and * Vout_D to be ready after BUCK_SIDO is powered up. diff --git a/sound/soc/codecs/wcd937x.c b/sound/soc/codecs/wcd937x.c index 3b1a1518e764..b9df58b86ce9 100644 --- a/sound/soc/codecs/wcd937x.c +++ b/sound/soc/codecs/wcd937x.c @@ -91,7 +91,6 @@ struct wcd937x_priv { struct regmap_irq_chip *wcd_regmap_irq_chip; struct regmap_irq_chip_data *irq_chip; struct regulator_bulk_data supplies[WCD937X_MAX_BULK_SUPPLY]; - struct regulator *buck_supply; struct snd_soc_jack *jack; unsigned long status_mask; s32 micb_ref[WCD937X_MAX_MICBIAS]; @@ -2945,10 +2944,8 @@ static int wcd937x_probe(struct platform_device *pdev) return dev_err_probe(dev, ret, "Failed to get supplies\n"); ret = regulator_bulk_enable(WCD937X_MAX_BULK_SUPPLY, wcd937x->supplies); - if (ret) { - regulator_bulk_free(WCD937X_MAX_BULK_SUPPLY, wcd937x->supplies); + if (ret) return dev_err_probe(dev, ret, "Failed to enable supplies\n"); - } wcd937x_dt_parse_micbias_info(dev, wcd937x); @@ -2984,7 +2981,6 @@ static int wcd937x_probe(struct platform_device *pdev) err_disable_regulators: regulator_bulk_disable(WCD937X_MAX_BULK_SUPPLY, wcd937x->supplies); - regulator_bulk_free(WCD937X_MAX_BULK_SUPPLY, wcd937x->supplies); return ret; } @@ -3001,7 +2997,6 @@ static void wcd937x_remove(struct platform_device *pdev) pm_runtime_dont_use_autosuspend(dev); regulator_bulk_disable(WCD937X_MAX_BULK_SUPPLY, wcd937x->supplies); - regulator_bulk_free(WCD937X_MAX_BULK_SUPPLY, wcd937x->supplies); } #if defined(CONFIG_OF) diff --git a/sound/soc/fsl/imx-pcm-rpmsg.c b/sound/soc/fsl/imx-pcm-rpmsg.c index 8ed62d43ffd5..edab68ae8366 100644 --- a/sound/soc/fsl/imx-pcm-rpmsg.c +++ b/sound/soc/fsl/imx-pcm-rpmsg.c @@ -209,7 +209,7 @@ static snd_pcm_uframes_t imx_rpmsg_pcm_pointer(struct snd_soc_component *compone static void imx_rpmsg_timer_callback(struct timer_list *t) { struct stream_timer *stream_timer = - from_timer(stream_timer, t, timer); + timer_container_of(stream_timer, t, timer); struct snd_pcm_substream *substream = stream_timer->substream; struct rpmsg_info *info = stream_timer->info; struct rpmsg_msg *msg; diff --git a/sound/soc/intel/avs/board_selection.c b/sound/soc/intel/avs/board_selection.c index 636315060eb4..673ccf162023 100644 --- a/sound/soc/intel/avs/board_selection.c +++ b/sound/soc/intel/avs/board_selection.c @@ -548,7 +548,7 @@ static int avs_register_i2s_test_boards(struct avs_dev *adev) u32 *array, num_elems; ret = parse_int_array(i2s_test, strlen(i2s_test), (int **)&array); - if (ret < 0) { + if (ret) { dev_err(adev->dev, "failed to parse i2s_test parameter\n"); return ret; } diff --git a/sound/soc/intel/avs/boards/rt5663.c b/sound/soc/intel/avs/boards/rt5663.c index 122b6c48fd80..51648801710a 100644 --- a/sound/soc/intel/avs/boards/rt5663.c +++ b/sound/soc/intel/avs/boards/rt5663.c @@ -228,7 +228,7 @@ static int avs_rt5663_probe(struct platform_device *pdev) card->name = "avs_rt5663"; } else { card->driver_name = "avs_rt5663"; - card->long_name = card->name = "AVS I2S ALC5640"; + card->long_name = card->name = "AVS I2S ALC5663"; } card->dev = dev; card->owner = THIS_MODULE; diff --git a/sound/soc/intel/avs/core.c b/sound/soc/intel/avs/core.c index 485842838025..ec1b3f55cb5c 100644 --- a/sound/soc/intel/avs/core.c +++ b/sound/soc/intel/avs/core.c @@ -945,14 +945,14 @@ MODULE_AUTHOR("Cezary Rojewski <cezary.rojewski@intel.com>"); MODULE_AUTHOR("Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>"); MODULE_DESCRIPTION("Intel cAVS sound driver"); MODULE_LICENSE("GPL"); -MODULE_FIRMWARE("intel/skl/dsp_basefw.bin"); -MODULE_FIRMWARE("intel/apl/dsp_basefw.bin"); -MODULE_FIRMWARE("intel/cnl/dsp_basefw.bin"); -MODULE_FIRMWARE("intel/icl/dsp_basefw.bin"); -MODULE_FIRMWARE("intel/jsl/dsp_basefw.bin"); -MODULE_FIRMWARE("intel/lkf/dsp_basefw.bin"); -MODULE_FIRMWARE("intel/tgl/dsp_basefw.bin"); -MODULE_FIRMWARE("intel/ehl/dsp_basefw.bin"); -MODULE_FIRMWARE("intel/adl/dsp_basefw.bin"); -MODULE_FIRMWARE("intel/adl_n/dsp_basefw.bin"); +MODULE_FIRMWARE("intel/avs/skl/dsp_basefw.bin"); +MODULE_FIRMWARE("intel/avs/apl/dsp_basefw.bin"); +MODULE_FIRMWARE("intel/avs/cnl/dsp_basefw.bin"); +MODULE_FIRMWARE("intel/avs/icl/dsp_basefw.bin"); +MODULE_FIRMWARE("intel/avs/jsl/dsp_basefw.bin"); +MODULE_FIRMWARE("intel/avs/lkf/dsp_basefw.bin"); +MODULE_FIRMWARE("intel/avs/tgl/dsp_basefw.bin"); +MODULE_FIRMWARE("intel/avs/ehl/dsp_basefw.bin"); +MODULE_FIRMWARE("intel/avs/adl/dsp_basefw.bin"); +MODULE_FIRMWARE("intel/avs/adl_n/dsp_basefw.bin"); MODULE_FIRMWARE("intel/fcl/dsp_basefw.bin"); diff --git a/sound/soc/intel/avs/debugfs.c b/sound/soc/intel/avs/debugfs.c index 8c4edda97f75..c625cf879f17 100644 --- a/sound/soc/intel/avs/debugfs.c +++ b/sound/soc/intel/avs/debugfs.c @@ -144,7 +144,7 @@ static ssize_t probe_points_write(struct file *file, const char __user *from, si int ret; ret = parse_int_array_user(from, count, (int **)&array); - if (ret < 0) + if (ret) return ret; num_elems = *array; @@ -181,7 +181,7 @@ static ssize_t probe_points_disconnect_write(struct file *file, const char __use int ret; ret = parse_int_array_user(from, count, (int **)&array); - if (ret < 0) + if (ret) return ret; num_elems = *array; @@ -369,11 +369,14 @@ static ssize_t trace_control_write(struct file *file, const char __user *from, s int ret; ret = parse_int_array_user(from, count, (int **)&array); - if (ret < 0) + if (ret) return ret; num_elems = *array; - resource_mask = array[1]; + if (!num_elems) { + ret = -EINVAL; + goto free_array; + } /* * Disable if just resource mask is provided - no log priority flags. @@ -381,6 +384,7 @@ static ssize_t trace_control_write(struct file *file, const char __user *from, s * Enable input format: mask, prio1, .., prioN * Where 'N' equals number of bits set in the 'mask'. */ + resource_mask = array[1]; if (num_elems == 1) { ret = disable_logs(adev, resource_mask); } else { diff --git a/sound/soc/intel/avs/ipc.c b/sound/soc/intel/avs/ipc.c index 08ed9d96738a..0314f9d4ea5f 100644 --- a/sound/soc/intel/avs/ipc.c +++ b/sound/soc/intel/avs/ipc.c @@ -169,7 +169,9 @@ static void avs_dsp_exception_caught(struct avs_dev *adev, union avs_notify_msg dev_crit(adev->dev, "communication severed, rebooting dsp..\n"); - cancel_delayed_work_sync(&ipc->d0ix_work); + /* Avoid deadlock as the exception may be the response to SET_D0IX. */ + if (current_work() != &ipc->d0ix_work.work) + cancel_delayed_work_sync(&ipc->d0ix_work); ipc->in_d0ix = false; /* Re-enabled on recovery completion. */ pm_runtime_disable(adev->dev); diff --git a/sound/soc/intel/avs/loader.c b/sound/soc/intel/avs/loader.c index 138e4e9de5e3..353e343b1d28 100644 --- a/sound/soc/intel/avs/loader.c +++ b/sound/soc/intel/avs/loader.c @@ -9,6 +9,7 @@ #include <linux/firmware.h> #include <linux/module.h> #include <linux/slab.h> +#include <linux/string.h> #include <sound/hdaudio.h> #include <sound/hdaudio_ext.h> #include "avs.h" diff --git a/sound/soc/intel/avs/path.c b/sound/soc/intel/avs/path.c index ed8f0ea0e10d..e8e6b1c7fc90 100644 --- a/sound/soc/intel/avs/path.c +++ b/sound/soc/intel/avs/path.c @@ -134,6 +134,8 @@ int avs_path_set_constraint(struct avs_dev *adev, struct avs_tplg_path_template rlist = kcalloc(i, sizeof(*rlist), GFP_KERNEL); clist = kcalloc(i, sizeof(*clist), GFP_KERNEL); slist = kcalloc(i, sizeof(*slist), GFP_KERNEL); + if (!rlist || !clist || !slist) + return -ENOMEM; i = 0; list_for_each_entry(path_template, &template->path_list, node) { diff --git a/sound/soc/intel/avs/pcm.c b/sound/soc/intel/avs/pcm.c index 405cfc1ab0cb..ccf90428126d 100644 --- a/sound/soc/intel/avs/pcm.c +++ b/sound/soc/intel/avs/pcm.c @@ -83,10 +83,8 @@ void avs_period_elapsed(struct snd_pcm_substream *substream) static int hw_rule_param_size(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule); static int avs_hw_constraints_init(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct snd_pcm_runtime *runtime = substream->runtime; struct snd_pcm_hw_constraint_list *r, *c, *s; - struct avs_tplg_path_template *template; struct avs_dma_data *data; int ret; @@ -99,8 +97,7 @@ static int avs_hw_constraints_init(struct snd_pcm_substream *substream, struct s c = &(data->channels_list); s = &(data->sample_bits_list); - template = avs_dai_find_path_template(dai, !rtd->dai_link->no_pcm, substream->stream); - ret = avs_path_set_constraint(data->adev, template, r, c, s); + ret = avs_path_set_constraint(data->adev, data->template, r, c, s); if (ret <= 0) return ret; @@ -450,9 +447,10 @@ static int avs_dai_hda_be_hw_free(struct snd_pcm_substream *substream, struct sn static int avs_dai_hda_be_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_soc_pcm_runtime *be = snd_soc_substream_to_rtd(substream); const struct snd_soc_pcm_stream *stream_info; struct hdac_ext_stream *link_stream; + const struct snd_pcm_hw_params *p; struct avs_dma_data *data; unsigned int format_val; unsigned int bits; @@ -460,14 +458,15 @@ static int avs_dai_hda_be_prepare(struct snd_pcm_substream *substream, struct sn data = snd_soc_dai_get_dma_data(dai, substream); link_stream = data->link_stream; + p = &be->dpcm[substream->stream].hw_params; if (link_stream->link_prepared) return 0; stream_info = snd_soc_dai_get_pcm_stream(dai, substream->stream); - bits = snd_hdac_stream_format_bits(runtime->format, runtime->subformat, + bits = snd_hdac_stream_format_bits(params_format(p), params_subformat(p), stream_info->sig_bits); - format_val = snd_hdac_stream_format(runtime->channels, bits, runtime->rate); + format_val = snd_hdac_stream_format(params_channels(p), bits, params_rate(p)); snd_hdac_ext_stream_decouple(&data->adev->base.core, link_stream, true); snd_hdac_ext_stream_reset(link_stream); diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig index ca7a30ebd26a..e86b4a03dd61 100644 --- a/sound/soc/qcom/Kconfig +++ b/sound/soc/qcom/Kconfig @@ -118,6 +118,22 @@ config SND_SOC_QDSP6_PRM tristate select SND_SOC_QDSP6_PRM_LPASS_CLOCKS +config SND_SOC_QCOM_OFFLOAD_UTILS + tristate + +config SND_SOC_QDSP6_USB + tristate "SoC ALSA USB offloading backing for QDSP6" + depends on SND_SOC_USB + select AUXILIARY_BUS + select SND_SOC_QCOM_OFFLOAD_UTILS + + help + Adds support for USB offloading for QDSP6 ASoC + based platform sound cards. This will enable the + Q6USB DPCM backend DAI link, which will interact + with the SoC USB framework to initialize a session + with active USB SND devices. + config SND_SOC_QDSP6 tristate "SoC ALSA audio driver for QDSP6" depends on QCOM_APR diff --git a/sound/soc/qcom/Makefile b/sound/soc/qcom/Makefile index 16db7b53ddac..985ce2ae286b 100644 --- a/sound/soc/qcom/Makefile +++ b/sound/soc/qcom/Makefile @@ -30,6 +30,7 @@ snd-soc-sc8280xp-y := sc8280xp.o snd-soc-qcom-common-y := common.o snd-soc-qcom-sdw-y := sdw.o snd-soc-x1e80100-y := x1e80100.o +snd-soc-qcom-offload-utils-objs := usb_offload_utils.o obj-$(CONFIG_SND_SOC_STORM) += snd-soc-storm.o obj-$(CONFIG_SND_SOC_APQ8016_SBC) += snd-soc-apq8016-sbc.o @@ -42,6 +43,7 @@ obj-$(CONFIG_SND_SOC_SM8250) += snd-soc-sm8250.o obj-$(CONFIG_SND_SOC_QCOM_COMMON) += snd-soc-qcom-common.o obj-$(CONFIG_SND_SOC_QCOM_SDW) += snd-soc-qcom-sdw.o obj-$(CONFIG_SND_SOC_X1E80100) += snd-soc-x1e80100.o +obj-$(CONFIG_SND_SOC_QCOM_OFFLOAD_UTILS) += snd-soc-qcom-offload-utils.o #DSP lib obj-$(CONFIG_SND_SOC_QDSP6) += qdsp6/ diff --git a/sound/soc/qcom/qdsp6/Makefile b/sound/soc/qcom/qdsp6/Makefile index 26b7c55c9c11..67267304e7e9 100644 --- a/sound/soc/qcom/qdsp6/Makefile +++ b/sound/soc/qcom/qdsp6/Makefile @@ -17,3 +17,4 @@ obj-$(CONFIG_SND_SOC_QDSP6_APM_DAI) += q6apm-dai.o obj-$(CONFIG_SND_SOC_QDSP6_APM_LPASS_DAI) += q6apm-lpass-dais.o obj-$(CONFIG_SND_SOC_QDSP6_PRM) += q6prm.o obj-$(CONFIG_SND_SOC_QDSP6_PRM_LPASS_CLOCKS) += q6prm-clocks.o +obj-$(CONFIG_SND_SOC_QDSP6_USB) += q6usb.o diff --git a/sound/soc/qcom/qdsp6/q6afe-dai.c b/sound/soc/qcom/qdsp6/q6afe-dai.c index 7d9628cda875..0f47aadaabe1 100644 --- a/sound/soc/qcom/qdsp6/q6afe-dai.c +++ b/sound/soc/qcom/qdsp6/q6afe-dai.c @@ -92,6 +92,39 @@ static int q6hdmi_hw_params(struct snd_pcm_substream *substream, return 0; } +static int q6afe_usb_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev); + int channels = params_channels(params); + int rate = params_rate(params); + struct q6afe_usb_cfg *usb = &dai_data->port_config[dai->id].usb_audio; + + usb->sample_rate = rate; + usb->num_channels = channels; + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_U16_LE: + case SNDRV_PCM_FORMAT_S16_LE: + usb->bit_width = 16; + break; + case SNDRV_PCM_FORMAT_S24_LE: + case SNDRV_PCM_FORMAT_S24_3LE: + usb->bit_width = 24; + break; + case SNDRV_PCM_FORMAT_S32_LE: + usb->bit_width = 32; + break; + default: + dev_err(dai->dev, "%s: invalid format %d\n", + __func__, params_format(params)); + return -EINVAL; + } + + return 0; +} + static int q6i2s_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) @@ -394,6 +427,10 @@ static int q6afe_dai_prepare(struct snd_pcm_substream *substream, q6afe_cdc_dma_port_prepare(dai_data->port[dai->id], &dai_data->port_config[dai->id].dma_cfg); break; + case USB_RX: + q6afe_usb_port_prepare(dai_data->port[dai->id], + &dai_data->port_config[dai->id].usb_audio); + break; default: return -EINVAL; } @@ -622,6 +659,9 @@ static const struct snd_soc_dapm_route q6afe_dapm_routes[] = { {"TX_CODEC_DMA_TX_5", NULL, "TX_CODEC_DMA_TX_5 Capture"}, {"RX_CODEC_DMA_RX_6 Playback", NULL, "RX_CODEC_DMA_RX_6"}, {"RX_CODEC_DMA_RX_7 Playback", NULL, "RX_CODEC_DMA_RX_7"}, + + /* USB playback AFE port receives data for playback, hence use the RX port */ + {"USB Playback", NULL, "USB_RX"}, }; static int msm_dai_q6_dai_probe(struct snd_soc_dai *dai) @@ -649,6 +689,23 @@ static int msm_dai_q6_dai_remove(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops q6afe_usb_ops = { + .probe = msm_dai_q6_dai_probe, + .prepare = q6afe_dai_prepare, + .hw_params = q6afe_usb_hw_params, + /* + * Shutdown callback required to stop the USB AFE port, which is enabled + * by the prepare() stage. This stops the audio traffic on the USB AFE + * port on the Q6DSP. + */ + .shutdown = q6afe_dai_shutdown, + /* + * Startup callback not needed, as AFE port start command passes the PCM + * parameters within the AFE command, which is provided by the PCM core + * during the prepare() stage. + */ +}; + static const struct snd_soc_dai_ops q6hdmi_ops = { .probe = msm_dai_q6_dai_probe, .remove = msm_dai_q6_dai_remove, @@ -947,6 +1004,8 @@ static const struct snd_soc_dapm_widget q6afe_dai_widgets[] = { 0, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_AIF_IN("RX_CODEC_DMA_RX_7", "NULL", 0, SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_AIF_IN("USB_RX", NULL, 0, SND_SOC_NOPM, 0, 0), }; static const struct snd_soc_component_driver q6afe_dai_component = { @@ -1061,6 +1120,7 @@ static int q6afe_dai_dev_probe(struct platform_device *pdev) cfg.q6i2s_ops = &q6i2s_ops; cfg.q6tdm_ops = &q6tdm_ops; cfg.q6dma_ops = &q6dma_ops; + cfg.q6usb_ops = &q6afe_usb_ops; dais = q6dsp_audio_ports_set_config(dev, &cfg, &num_dais); return devm_snd_soc_register_component(dev, &q6afe_dai_component, dais, num_dais); diff --git a/sound/soc/qcom/qdsp6/q6afe.c b/sound/soc/qcom/qdsp6/q6afe.c index ef7557be5d66..7b59d514b432 100644 --- a/sound/soc/qcom/qdsp6/q6afe.c +++ b/sound/soc/qcom/qdsp6/q6afe.c @@ -35,6 +35,8 @@ #define AFE_MODULE_TDM 0x0001028A #define AFE_PARAM_ID_CDC_SLIMBUS_SLAVE_CFG 0x00010235 +#define AFE_PARAM_ID_USB_AUDIO_DEV_PARAMS 0x000102A5 +#define AFE_PARAM_ID_USB_AUDIO_DEV_LPCM_FMT 0x000102AA #define AFE_PARAM_ID_LPAIF_CLK_CONFIG 0x00010238 #define AFE_PARAM_ID_INT_DIGITAL_CDC_CLK_CONFIG 0x00010239 @@ -44,6 +46,7 @@ #define AFE_PARAM_ID_TDM_CONFIG 0x0001029D #define AFE_PARAM_ID_PORT_SLOT_MAPPING_CONFIG 0x00010297 #define AFE_PARAM_ID_CODEC_DMA_CONFIG 0x000102B8 +#define AFE_PARAM_ID_USB_AUDIO_CONFIG 0x000102A4 #define AFE_CMD_REMOTE_LPASS_CORE_HW_VOTE_REQUEST 0x000100f4 #define AFE_CMD_RSP_REMOTE_LPASS_CORE_HW_VOTE_REQUEST 0x000100f5 #define AFE_CMD_REMOTE_LPASS_CORE_HW_DEVOTE_REQUEST 0x000100f6 @@ -72,12 +75,16 @@ #define AFE_PORT_CONFIG_I2S_WS_SRC_INTERNAL 0x1 #define AFE_LINEAR_PCM_DATA 0x0 +#define AFE_API_MINOR_VERSION_USB_AUDIO_CONFIG 0x1 /* Port IDs */ #define AFE_API_VERSION_HDMI_CONFIG 0x1 #define AFE_PORT_ID_MULTICHAN_HDMI_RX 0x100E #define AFE_PORT_ID_HDMI_OVER_DP_RX 0x6020 +/* USB AFE port */ +#define AFE_PORT_ID_USB_RX 0x7000 + #define AFE_API_VERSION_SLIMBUS_CONFIG 0x1 /* Clock set API version */ #define AFE_API_VERSION_CLOCK_SET 1 @@ -359,7 +366,7 @@ #define AFE_API_VERSION_SLOT_MAPPING_CONFIG 1 #define AFE_API_VERSION_CODEC_DMA_CONFIG 1 -#define TIMEOUT_MS 1000 +#define TIMEOUT_MS 3000 #define AFE_CMD_RESP_AVAIL 0 #define AFE_CMD_RESP_NONE 1 #define AFE_CLK_TOKEN 1024 @@ -513,12 +520,96 @@ struct afe_param_id_cdc_dma_cfg { u16 active_channels_mask; } __packed; +struct afe_param_id_usb_cfg { +/* Minor version used for tracking USB audio device configuration. + * Supported values: AFE_API_MINOR_VERSION_USB_AUDIO_CONFIG + */ + u32 cfg_minor_version; +/* Sampling rate of the port. + * Supported values: + * - AFE_PORT_SAMPLE_RATE_8K + * - AFE_PORT_SAMPLE_RATE_11025 + * - AFE_PORT_SAMPLE_RATE_12K + * - AFE_PORT_SAMPLE_RATE_16K + * - AFE_PORT_SAMPLE_RATE_22050 + * - AFE_PORT_SAMPLE_RATE_24K + * - AFE_PORT_SAMPLE_RATE_32K + * - AFE_PORT_SAMPLE_RATE_44P1K + * - AFE_PORT_SAMPLE_RATE_48K + * - AFE_PORT_SAMPLE_RATE_96K + * - AFE_PORT_SAMPLE_RATE_192K + */ + u32 sample_rate; +/* Bit width of the sample. + * Supported values: 16, 24 + */ + u16 bit_width; +/* Number of channels. + * Supported values: 1 and 2 + */ + u16 num_channels; +/* Data format supported by the USB. The supported value is + * 0 (#AFE_USB_AUDIO_DATA_FORMAT_LINEAR_PCM). + */ + u16 data_format; +/* this field must be 0 */ + u16 reserved; +/* device token of actual end USB audio device */ + u32 dev_token; +/* endianness of this interface */ + u32 endian; +/* service interval */ + u32 service_interval; +} __packed; + +/** + * struct afe_param_id_usb_audio_dev_params + * @cfg_minor_version: Minor version used for tracking USB audio device + * configuration. + * Supported values: + * AFE_API_MINOR_VERSION_USB_AUDIO_CONFIG + * @dev_token: device token of actual end USB audio device + **/ +struct afe_param_id_usb_audio_dev_params { + u32 cfg_minor_version; + u32 dev_token; +} __packed; + +/** + * struct afe_param_id_usb_audio_dev_lpcm_fmt + * @cfg_minor_version: Minor version used for tracking USB audio device + * configuration. + * Supported values: + * AFE_API_MINOR_VERSION_USB_AUDIO_CONFIG + * @endian: endianness of this interface + **/ +struct afe_param_id_usb_audio_dev_lpcm_fmt { + u32 cfg_minor_version; + u32 endian; +} __packed; + +#define AFE_PARAM_ID_USB_AUDIO_SVC_INTERVAL 0x000102B7 + +/** + * struct afe_param_id_usb_audio_svc_interval + * @cfg_minor_version: Minor version used for tracking USB audio device + * configuration. + * Supported values: + * AFE_API_MINOR_VERSION_USB_AUDIO_CONFIG + * @svc_interval: service interval + **/ +struct afe_param_id_usb_audio_svc_interval { + u32 cfg_minor_version; + u32 svc_interval; +} __packed; + union afe_port_config { struct afe_param_id_hdmi_multi_chan_audio_cfg hdmi_multi_ch; struct afe_param_id_slimbus_cfg slim_cfg; struct afe_param_id_i2s_cfg i2s_cfg; struct afe_param_id_tdm_cfg tdm_cfg; struct afe_param_id_cdc_dma_cfg dma_cfg; + struct afe_param_id_usb_cfg usb_cfg; } __packed; @@ -833,6 +924,7 @@ static struct afe_port_map port_maps[AFE_PORT_MAX] = { RX_CODEC_DMA_RX_6, 1, 1}, [RX_CODEC_DMA_RX_7] = { AFE_PORT_ID_RX_CODEC_DMA_RX_7, RX_CODEC_DMA_RX_7, 1, 1}, + [USB_RX] = { AFE_PORT_ID_USB_RX, USB_RX, 1, 1}, }; static void q6afe_port_free(struct kref *ref) @@ -1291,6 +1383,99 @@ void q6afe_tdm_port_prepare(struct q6afe_port *port, EXPORT_SYMBOL_GPL(q6afe_tdm_port_prepare); /** + * afe_port_send_usb_dev_param() - Send USB dev token + * + * @port: Instance of afe port + * @cardidx: USB SND card index to reference + * @pcmidx: USB SND PCM device index to reference + * + * The USB dev token carries information about which USB SND card instance and + * PCM device to execute the offload on. This information is carried through + * to the stream enable QMI request, which is handled by the offload class + * driver. The information is parsed to determine which USB device to query + * the required resources for. + */ +int afe_port_send_usb_dev_param(struct q6afe_port *port, int cardidx, int pcmidx) +{ + struct afe_param_id_usb_audio_dev_params usb_dev; + int ret; + + memset(&usb_dev, 0, sizeof(usb_dev)); + + usb_dev.cfg_minor_version = AFE_API_MINOR_VERSION_USB_AUDIO_CONFIG; + usb_dev.dev_token = (cardidx << 16) | (pcmidx << 8); + ret = q6afe_port_set_param_v2(port, &usb_dev, + AFE_PARAM_ID_USB_AUDIO_DEV_PARAMS, + AFE_MODULE_AUDIO_DEV_INTERFACE, + sizeof(usb_dev)); + if (ret) + dev_err(port->afe->dev, "%s: AFE device param cmd failed %d\n", + __func__, ret); + + return ret; +} +EXPORT_SYMBOL_GPL(afe_port_send_usb_dev_param); + +static int afe_port_send_usb_params(struct q6afe_port *port, struct q6afe_usb_cfg *cfg) +{ + union afe_port_config *pcfg = &port->port_cfg; + struct afe_param_id_usb_audio_dev_lpcm_fmt lpcm_fmt; + struct afe_param_id_usb_audio_svc_interval svc_int; + int ret; + + if (!pcfg) { + dev_err(port->afe->dev, "%s: Error, no configuration data\n", __func__); + return -EINVAL; + } + + memset(&lpcm_fmt, 0, sizeof(lpcm_fmt)); + memset(&svc_int, 0, sizeof(svc_int)); + + lpcm_fmt.cfg_minor_version = AFE_API_MINOR_VERSION_USB_AUDIO_CONFIG; + lpcm_fmt.endian = pcfg->usb_cfg.endian; + ret = q6afe_port_set_param_v2(port, &lpcm_fmt, + AFE_PARAM_ID_USB_AUDIO_DEV_LPCM_FMT, + AFE_MODULE_AUDIO_DEV_INTERFACE, sizeof(lpcm_fmt)); + if (ret) { + dev_err(port->afe->dev, "%s: AFE device param cmd LPCM_FMT failed %d\n", + __func__, ret); + return ret; + } + + svc_int.cfg_minor_version = AFE_API_MINOR_VERSION_USB_AUDIO_CONFIG; + svc_int.svc_interval = pcfg->usb_cfg.service_interval; + ret = q6afe_port_set_param_v2(port, &svc_int, + AFE_PARAM_ID_USB_AUDIO_SVC_INTERVAL, + AFE_MODULE_AUDIO_DEV_INTERFACE, sizeof(svc_int)); + if (ret) + dev_err(port->afe->dev, "%s: AFE device param cmd svc_interval failed %d\n", + __func__, ret); + + return ret; +} + +/** + * q6afe_usb_port_prepare() - Prepare usb afe port. + * + * @port: Instance of afe port + * @cfg: USB configuration for the afe port + * + */ +void q6afe_usb_port_prepare(struct q6afe_port *port, + struct q6afe_usb_cfg *cfg) +{ + union afe_port_config *pcfg = &port->port_cfg; + + pcfg->usb_cfg.cfg_minor_version = AFE_API_MINOR_VERSION_USB_AUDIO_CONFIG; + pcfg->usb_cfg.sample_rate = cfg->sample_rate; + pcfg->usb_cfg.num_channels = cfg->num_channels; + pcfg->usb_cfg.bit_width = cfg->bit_width; + + afe_port_send_usb_params(port, cfg); +} +EXPORT_SYMBOL_GPL(q6afe_usb_port_prepare); + +/** * q6afe_hdmi_port_prepare() - Prepare hdmi afe port. * * @port: Instance of afe port @@ -1612,7 +1797,10 @@ struct q6afe_port *q6afe_port_get_from_id(struct device *dev, int id) break; case AFE_PORT_ID_WSA_CODEC_DMA_RX_0 ... AFE_PORT_ID_RX_CODEC_DMA_RX_7: cfg_type = AFE_PARAM_ID_CODEC_DMA_CONFIG; - break; + break; + case AFE_PORT_ID_USB_RX: + cfg_type = AFE_PARAM_ID_USB_AUDIO_CONFIG; + break; default: dev_err(dev, "Invalid port id 0x%x\n", port_id); return ERR_PTR(-EINVAL); diff --git a/sound/soc/qcom/qdsp6/q6afe.h b/sound/soc/qcom/qdsp6/q6afe.h index 65d0676075e1..a29abe4ce436 100644 --- a/sound/soc/qcom/qdsp6/q6afe.h +++ b/sound/soc/qcom/qdsp6/q6afe.h @@ -3,7 +3,7 @@ #ifndef __Q6AFE_H__ #define __Q6AFE_H__ -#define AFE_PORT_MAX 129 +#define AFE_PORT_MAX 137 #define MSM_AFE_PORT_TYPE_RX 0 #define MSM_AFE_PORT_TYPE_TX 1 @@ -203,6 +203,36 @@ struct q6afe_cdc_dma_cfg { u16 active_channels_mask; }; +/** + * struct q6afe_usb_cfg + * @cfg_minor_version: Minor version used for tracking USB audio device + * configuration. + * Supported values: + * AFE_API_MINOR_VERSION_USB_AUDIO_CONFIG + * @sample_rate: Sampling rate of the port + * Supported values: + * AFE_PORT_SAMPLE_RATE_8K + * AFE_PORT_SAMPLE_RATE_11025 + * AFE_PORT_SAMPLE_RATE_12K + * AFE_PORT_SAMPLE_RATE_16K + * AFE_PORT_SAMPLE_RATE_22050 + * AFE_PORT_SAMPLE_RATE_24K + * AFE_PORT_SAMPLE_RATE_32K + * AFE_PORT_SAMPLE_RATE_44P1K + * AFE_PORT_SAMPLE_RATE_48K + * AFE_PORT_SAMPLE_RATE_96K + * AFE_PORT_SAMPLE_RATE_192K + * @bit_width: Bit width of the sample. + * Supported values: 16, 24 + * @num_channels: Number of channels + * Supported values: 1, 2 + **/ +struct q6afe_usb_cfg { + u32 cfg_minor_version; + u32 sample_rate; + u16 bit_width; + u16 num_channels; +}; struct q6afe_port_config { struct q6afe_hdmi_cfg hdmi; @@ -210,6 +240,7 @@ struct q6afe_port_config { struct q6afe_i2s_cfg i2s_cfg; struct q6afe_tdm_cfg tdm; struct q6afe_cdc_dma_cfg dma_cfg; + struct q6afe_usb_cfg usb_audio; }; struct q6afe_port; @@ -219,6 +250,8 @@ int q6afe_port_start(struct q6afe_port *port); int q6afe_port_stop(struct q6afe_port *port); void q6afe_port_put(struct q6afe_port *port); int q6afe_get_port_id(int index); +void q6afe_usb_port_prepare(struct q6afe_port *port, + struct q6afe_usb_cfg *cfg); void q6afe_hdmi_port_prepare(struct q6afe_port *port, struct q6afe_hdmi_cfg *cfg); void q6afe_slim_port_prepare(struct q6afe_port *port, @@ -228,6 +261,7 @@ void q6afe_tdm_port_prepare(struct q6afe_port *port, struct q6afe_tdm_cfg *cfg); void q6afe_cdc_dma_port_prepare(struct q6afe_port *port, struct q6afe_cdc_dma_cfg *cfg); +int afe_port_send_usb_dev_param(struct q6afe_port *port, int cardidx, int pcmidx); int q6afe_port_set_sysclk(struct q6afe_port *port, int clk_id, int clk_src, int clk_root, unsigned int freq, int dir); diff --git a/sound/soc/qcom/qdsp6/q6dsp-lpass-ports.c b/sound/soc/qcom/qdsp6/q6dsp-lpass-ports.c index 4919001de08b..4eed54b071a5 100644 --- a/sound/soc/qcom/qdsp6/q6dsp-lpass-ports.c +++ b/sound/soc/qcom/qdsp6/q6dsp-lpass-ports.c @@ -99,6 +99,26 @@ static struct snd_soc_dai_driver q6dsp_audio_fe_dais[] = { { .playback = { + .stream_name = "USB Playback", + .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | + SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | + SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | + SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | + SNDRV_PCM_RATE_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | + SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_U16_BE | + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE | + SNDRV_PCM_FMTBIT_U24_LE | SNDRV_PCM_FMTBIT_U24_BE, + .channels_min = 1, + .channels_max = 2, + .rate_min = 8000, + .rate_max = 192000, + }, + .id = USB_RX, + .name = "USB_RX", + }, + { + .playback = { .stream_name = "HDMI Playback", .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | @@ -624,6 +644,9 @@ struct snd_soc_dai_driver *q6dsp_audio_ports_set_config(struct device *dev, case WSA_CODEC_DMA_RX_0 ... RX_CODEC_DMA_RX_7: q6dsp_audio_fe_dais[i].ops = cfg->q6dma_ops; break; + case USB_RX: + q6dsp_audio_fe_dais[i].ops = cfg->q6usb_ops; + break; default: break; } diff --git a/sound/soc/qcom/qdsp6/q6dsp-lpass-ports.h b/sound/soc/qcom/qdsp6/q6dsp-lpass-ports.h index 7f052c8a1257..d8dde6dd0aca 100644 --- a/sound/soc/qcom/qdsp6/q6dsp-lpass-ports.h +++ b/sound/soc/qcom/qdsp6/q6dsp-lpass-ports.h @@ -11,6 +11,7 @@ struct q6dsp_audio_port_dai_driver_config { const struct snd_soc_dai_ops *q6i2s_ops; const struct snd_soc_dai_ops *q6tdm_ops; const struct snd_soc_dai_ops *q6dma_ops; + const struct snd_soc_dai_ops *q6usb_ops; }; struct snd_soc_dai_driver *q6dsp_audio_ports_set_config(struct device *dev, diff --git a/sound/soc/qcom/qdsp6/q6routing.c b/sound/soc/qcom/qdsp6/q6routing.c index 90228699ba7d..f49243daa517 100644 --- a/sound/soc/qcom/qdsp6/q6routing.c +++ b/sound/soc/qcom/qdsp6/q6routing.c @@ -435,6 +435,7 @@ static struct session_data *get_session_from_id(struct msm_routing_data *data, return NULL; } + /** * q6routing_stream_close() - Deregister a stream * @@ -515,6 +516,9 @@ static int msm_routing_put_audio_mixer(struct snd_kcontrol *kcontrol, return 1; } +static const struct snd_kcontrol_new usb_rx_mixer_controls[] = { + Q6ROUTING_RX_MIXERS(USB_RX) }; + static const struct snd_kcontrol_new hdmi_mixer_controls[] = { Q6ROUTING_RX_MIXERS(HDMI_RX) }; @@ -933,6 +937,9 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = { SND_SOC_DAPM_MIXER("RX_CODEC_DMA_RX_7 Audio Mixer", SND_SOC_NOPM, 0, 0, rx_codec_dma_rx_7_mixer_controls, ARRAY_SIZE(rx_codec_dma_rx_7_mixer_controls)), + SND_SOC_DAPM_MIXER("USB_RX Audio Mixer", SND_SOC_NOPM, 0, 0, + usb_rx_mixer_controls, + ARRAY_SIZE(usb_rx_mixer_controls)), SND_SOC_DAPM_MIXER("MultiMedia1 Mixer", SND_SOC_NOPM, 0, 0, mmul1_mixer_controls, ARRAY_SIZE(mmul1_mixer_controls)), SND_SOC_DAPM_MIXER("MultiMedia2 Mixer", SND_SOC_NOPM, 0, 0, @@ -949,7 +956,6 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = { mmul7_mixer_controls, ARRAY_SIZE(mmul7_mixer_controls)), SND_SOC_DAPM_MIXER("MultiMedia8 Mixer", SND_SOC_NOPM, 0, 0, mmul8_mixer_controls, ARRAY_SIZE(mmul8_mixer_controls)), - }; static const struct snd_soc_dapm_route intercon[] = { @@ -1026,6 +1032,7 @@ static const struct snd_soc_dapm_route intercon[] = { Q6ROUTING_RX_DAPM_ROUTE("RX_CODEC_DMA_RX_5 Audio Mixer", "RX_CODEC_DMA_RX_5"), Q6ROUTING_RX_DAPM_ROUTE("RX_CODEC_DMA_RX_6 Audio Mixer", "RX_CODEC_DMA_RX_6"), Q6ROUTING_RX_DAPM_ROUTE("RX_CODEC_DMA_RX_7 Audio Mixer", "RX_CODEC_DMA_RX_7"), + Q6ROUTING_RX_DAPM_ROUTE("USB_RX Audio Mixer", "USB_RX"), Q6ROUTING_TX_DAPM_ROUTE("MultiMedia1 Mixer"), Q6ROUTING_TX_DAPM_ROUTE("MultiMedia2 Mixer"), Q6ROUTING_TX_DAPM_ROUTE("MultiMedia3 Mixer"), diff --git a/sound/soc/qcom/qdsp6/q6usb.c b/sound/soc/qcom/qdsp6/q6usb.c new file mode 100644 index 000000000000..ebe0c2425927 --- /dev/null +++ b/sound/soc/qcom/qdsp6/q6usb.c @@ -0,0 +1,421 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2022-2025 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include <linux/auxiliary_bus.h> +#include <linux/device.h> +#include <linux/dma-mapping.h> +#include <linux/dma-map-ops.h> +#include <linux/err.h> +#include <linux/init.h> +#include <linux/iommu.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +#include <sound/asound.h> +#include <sound/jack.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/q6usboffload.h> +#include <sound/soc.h> +#include <sound/soc-usb.h> + +#include <dt-bindings/sound/qcom,q6afe.h> + +#include "q6afe.h" +#include "q6dsp-lpass-ports.h" + +#define Q6_USB_SID_MASK 0xF + +struct q6usb_port_data { + struct auxiliary_device uauxdev; + struct q6afe_usb_cfg usb_cfg; + struct snd_soc_usb *usb; + struct snd_soc_jack *hs_jack; + struct q6usb_offload priv; + + /* Protects against operations between SOC USB and ASoC */ + struct mutex mutex; + struct list_head devices; +}; + +static const struct snd_soc_dapm_widget q6usb_dai_widgets[] = { + SND_SOC_DAPM_HP("USB_RX_BE", NULL), +}; + +static const struct snd_soc_dapm_route q6usb_dapm_routes[] = { + {"USB Playback", NULL, "USB_RX_BE"}, +}; + +static int q6usb_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct q6usb_port_data *data = dev_get_drvdata(dai->dev); + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); + int direction = substream->stream; + struct q6afe_port *q6usb_afe; + struct snd_soc_usb_device *sdev; + int ret = -EINVAL; + + mutex_lock(&data->mutex); + + /* No active chip index */ + if (list_empty(&data->devices)) + goto out; + + sdev = list_last_entry(&data->devices, struct snd_soc_usb_device, list); + + ret = snd_soc_usb_find_supported_format(sdev->chip_idx, params, direction); + if (ret < 0) + goto out; + + q6usb_afe = q6afe_port_get_from_id(cpu_dai->dev, USB_RX); + if (IS_ERR(q6usb_afe)) { + ret = PTR_ERR(q6usb_afe); + goto out; + } + + /* Notify audio DSP about the devices being offloaded */ + ret = afe_port_send_usb_dev_param(q6usb_afe, sdev->card_idx, + sdev->ppcm_idx[sdev->num_playback - 1]); + +out: + mutex_unlock(&data->mutex); + + return ret; +} + +static const struct snd_soc_dai_ops q6usb_ops = { + .hw_params = q6usb_hw_params, +}; + +static struct snd_soc_dai_driver q6usb_be_dais[] = { + { + .playback = { + .stream_name = "USB BE RX", + .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | + SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | + SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | + SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | + SNDRV_PCM_RATE_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | + SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_U16_BE | + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE | + SNDRV_PCM_FMTBIT_U24_LE | SNDRV_PCM_FMTBIT_U24_BE, + .channels_min = 1, + .channels_max = 2, + .rate_max = 192000, + .rate_min = 8000, + }, + .id = USB_RX, + .name = "USB_RX_BE", + .ops = &q6usb_ops, + }, +}; + +static int q6usb_audio_ports_of_xlate_dai_name(struct snd_soc_component *component, + const struct of_phandle_args *args, + const char **dai_name) +{ + int id = args->args[0]; + int ret = -EINVAL; + int i; + + for (i = 0; i < ARRAY_SIZE(q6usb_be_dais); i++) { + if (q6usb_be_dais[i].id == id) { + *dai_name = q6usb_be_dais[i].name; + ret = 0; + break; + } + } + + return ret; +} + +static int q6usb_get_pcm_id_from_widget(struct snd_soc_dapm_widget *w) +{ + struct snd_soc_pcm_runtime *rtd; + struct snd_soc_dai *dai; + + for_each_card_rtds(w->dapm->card, rtd) { + dai = snd_soc_rtd_to_cpu(rtd, 0); + /* + * Only look for playback widget. RTD number carries the assigned + * PCM index. + */ + if (dai->stream[0].widget == w) + return rtd->id; + } + + return -1; +} + +static int q6usb_usb_mixer_enabled(struct snd_soc_dapm_widget *w) +{ + struct snd_soc_dapm_path *p; + + /* Checks to ensure USB path is enabled/connected */ + snd_soc_dapm_widget_for_each_sink_path(w, p) + if (!strcmp(p->sink->name, "USB Mixer") && p->connect) + return 1; + + return 0; +} + +static int q6usb_get_pcm_id(struct snd_soc_component *component) +{ + struct snd_soc_dapm_widget *w; + struct snd_soc_dapm_path *p; + int pidx; + + /* + * Traverse widgets to find corresponding FE widget. The DAI links are + * built like the following: + * MultiMedia* <-> MM_DL* <-> USB Mixer* + */ + for_each_card_widgets(component->card, w) { + if (!strncmp(w->name, "MultiMedia", 10)) { + /* + * Look up all paths associated with the FE widget to see if + * the USB BE is enabled. The sink widget is responsible to + * link with the USB mixers. + */ + snd_soc_dapm_widget_for_each_sink_path(w, p) { + if (q6usb_usb_mixer_enabled(p->sink)) { + pidx = q6usb_get_pcm_id_from_widget(w); + return pidx; + } + } + } + } + + return -1; +} + +static int q6usb_update_offload_route(struct snd_soc_component *component, int card, + int pcm, int direction, enum snd_soc_usb_kctl path, + long *route) +{ + struct q6usb_port_data *data = dev_get_drvdata(component->dev); + struct snd_soc_usb_device *sdev; + int ret = 0; + int idx = -1; + + mutex_lock(&data->mutex); + + if (list_empty(&data->devices) || + direction == SNDRV_PCM_STREAM_CAPTURE) { + ret = -ENODEV; + goto out; + } + + sdev = list_last_entry(&data->devices, struct snd_soc_usb_device, list); + + /* + * Will always look for last PCM device discovered/probed as the + * active offload index. + */ + if (card == sdev->card_idx && + pcm == sdev->ppcm_idx[sdev->num_playback - 1]) { + idx = path == SND_SOC_USB_KCTL_CARD_ROUTE ? + component->card->snd_card->number : + q6usb_get_pcm_id(component); + } + +out: + route[0] = idx; + mutex_unlock(&data->mutex); + + return ret; +} + +static int q6usb_alsa_connection_cb(struct snd_soc_usb *usb, + struct snd_soc_usb_device *sdev, bool connected) +{ + struct q6usb_port_data *data; + + if (!usb->component) + return -ENODEV; + + data = dev_get_drvdata(usb->component->dev); + + mutex_lock(&data->mutex); + if (connected) { + if (data->hs_jack) + snd_jack_report(data->hs_jack->jack, SND_JACK_USB); + + /* Selects the latest USB headset plugged in for offloading */ + list_add_tail(&sdev->list, &data->devices); + } else { + list_del(&sdev->list); + + if (data->hs_jack) + snd_jack_report(data->hs_jack->jack, 0); + } + mutex_unlock(&data->mutex); + + return 0; +} + +static void q6usb_component_disable_jack(struct q6usb_port_data *data) +{ + /* Offload jack has already been disabled */ + if (!data->hs_jack) + return; + + snd_jack_report(data->hs_jack->jack, 0); + data->hs_jack = NULL; +} + +static void q6usb_component_enable_jack(struct q6usb_port_data *data, + struct snd_soc_jack *jack) +{ + snd_jack_report(jack->jack, !list_empty(&data->devices) ? SND_JACK_USB : 0); + data->hs_jack = jack; +} + +static int q6usb_component_set_jack(struct snd_soc_component *component, + struct snd_soc_jack *jack, void *priv) +{ + struct q6usb_port_data *data = dev_get_drvdata(component->dev); + + mutex_lock(&data->mutex); + if (jack) + q6usb_component_enable_jack(data, jack); + else + q6usb_component_disable_jack(data); + mutex_unlock(&data->mutex); + + return 0; +} + +static void q6usb_dai_aux_release(struct device *dev) {} + +static int q6usb_dai_add_aux_device(struct q6usb_port_data *data, + struct auxiliary_device *auxdev) +{ + int ret; + + auxdev->dev.parent = data->priv.dev; + auxdev->dev.release = q6usb_dai_aux_release; + auxdev->name = "qc-usb-audio-offload"; + + ret = auxiliary_device_init(auxdev); + if (ret) + return ret; + + ret = auxiliary_device_add(auxdev); + if (ret) + auxiliary_device_uninit(auxdev); + + return ret; +} + +static int q6usb_component_probe(struct snd_soc_component *component) +{ + struct q6usb_port_data *data = dev_get_drvdata(component->dev); + struct snd_soc_usb *usb; + int ret; + + /* Add the QC USB SND aux device */ + ret = q6usb_dai_add_aux_device(data, &data->uauxdev); + if (ret < 0) + return ret; + + usb = snd_soc_usb_allocate_port(component, &data->priv); + if (IS_ERR(usb)) + return -ENOMEM; + + usb->connection_status_cb = q6usb_alsa_connection_cb; + usb->update_offload_route_info = q6usb_update_offload_route; + + snd_soc_usb_add_port(usb); + data->usb = usb; + + return 0; +} + +static void q6usb_component_remove(struct snd_soc_component *component) +{ + struct q6usb_port_data *data = dev_get_drvdata(component->dev); + + snd_soc_usb_remove_port(data->usb); + auxiliary_device_delete(&data->uauxdev); + auxiliary_device_uninit(&data->uauxdev); + snd_soc_usb_free_port(data->usb); +} + +static const struct snd_soc_component_driver q6usb_dai_component = { + .probe = q6usb_component_probe, + .set_jack = q6usb_component_set_jack, + .remove = q6usb_component_remove, + .name = "q6usb-dai-component", + .dapm_widgets = q6usb_dai_widgets, + .num_dapm_widgets = ARRAY_SIZE(q6usb_dai_widgets), + .dapm_routes = q6usb_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(q6usb_dapm_routes), + .of_xlate_dai_name = q6usb_audio_ports_of_xlate_dai_name, +}; + +static int q6usb_dai_dev_probe(struct platform_device *pdev) +{ + struct device_node *node = pdev->dev.of_node; + struct q6usb_port_data *data; + struct device *dev = &pdev->dev; + struct of_phandle_args args; + int ret; + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + ret = of_property_read_u16(node, "qcom,usb-audio-intr-idx", + &data->priv.intr_num); + if (ret) { + dev_err(&pdev->dev, "failed to read intr idx.\n"); + return ret; + } + + ret = of_parse_phandle_with_fixed_args(node, "iommus", 1, 0, &args); + if (!ret) + data->priv.sid = args.args[0] & Q6_USB_SID_MASK; + + ret = devm_mutex_init(dev, &data->mutex); + if (ret < 0) + return ret; + + data->priv.domain = iommu_get_domain_for_dev(&pdev->dev); + + data->priv.dev = dev; + INIT_LIST_HEAD(&data->devices); + dev_set_drvdata(dev, data); + + return devm_snd_soc_register_component(dev, &q6usb_dai_component, + q6usb_be_dais, ARRAY_SIZE(q6usb_be_dais)); +} + +static const struct of_device_id q6usb_dai_device_id[] = { + { .compatible = "qcom,q6usb" }, + {}, +}; +MODULE_DEVICE_TABLE(of, q6usb_dai_device_id); + +static struct platform_driver q6usb_dai_platform_driver = { + .driver = { + .name = "q6usb-dai", + .of_match_table = q6usb_dai_device_id, + }, + .probe = q6usb_dai_dev_probe, + /* + * Remove not required as resources are cleaned up as part of + * component removal. Others are device managed resources. + */ +}; +module_platform_driver(q6usb_dai_platform_driver); + +MODULE_DESCRIPTION("Q6 USB backend dai driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/qcom/sm8250.c b/sound/soc/qcom/sm8250.c index 9039107972e2..b70b2a5031df 100644 --- a/sound/soc/qcom/sm8250.c +++ b/sound/soc/qcom/sm8250.c @@ -13,6 +13,7 @@ #include <linux/input-event-codes.h> #include "qdsp6/q6afe.h" #include "common.h" +#include "usb_offload_utils.h" #include "sdw.h" #define DRIVER_NAME "sm8250" @@ -23,14 +24,34 @@ struct sm8250_snd_data { struct snd_soc_card *card; struct sdw_stream_runtime *sruntime[AFE_PORT_MAX]; struct snd_soc_jack jack; + struct snd_soc_jack usb_offload_jack; + bool usb_offload_jack_setup; bool jack_setup; }; static int sm8250_snd_init(struct snd_soc_pcm_runtime *rtd) { struct sm8250_snd_data *data = snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); + int ret; + + if (cpu_dai->id == USB_RX) + ret = qcom_snd_usb_offload_jack_setup(rtd, &data->usb_offload_jack, + &data->usb_offload_jack_setup); + else + ret = qcom_snd_wcd_jack_setup(rtd, &data->jack, &data->jack_setup); + return ret; +} + +static void sm8250_snd_exit(struct snd_soc_pcm_runtime *rtd) +{ + struct sm8250_snd_data *data = snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); + + if (cpu_dai->id == USB_RX) + qcom_snd_usb_offload_jack_remove(rtd, + &data->usb_offload_jack_setup); - return qcom_snd_wcd_jack_setup(rtd, &data->jack, &data->jack_setup); } static int sm8250_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, @@ -148,6 +169,7 @@ static void sm8250_add_be_ops(struct snd_soc_card *card) for_each_card_prelinks(card, i, link) { if (link->no_pcm == 1) { link->init = sm8250_snd_init; + link->exit = sm8250_snd_exit; link->be_hw_params_fixup = sm8250_be_hw_params_fixup; link->ops = &sm8250_be_ops; } diff --git a/sound/soc/qcom/usb_offload_utils.c b/sound/soc/qcom/usb_offload_utils.c new file mode 100644 index 000000000000..0a24b278fcdf --- /dev/null +++ b/sound/soc/qcom/usb_offload_utils.c @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2022-2025 Qualcomm Innovation Center, Inc. All rights reserved. + */ +#include <dt-bindings/sound/qcom,q6afe.h> +#include <linux/module.h> +#include <sound/jack.h> +#include <sound/soc-usb.h> + +#include "usb_offload_utils.h" + +int qcom_snd_usb_offload_jack_setup(struct snd_soc_pcm_runtime *rtd, + struct snd_soc_jack *jack, bool *jack_setup) +{ + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); + struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); + int ret = 0; + + if (cpu_dai->id != USB_RX) + return -EINVAL; + + if (!*jack_setup) { + ret = snd_soc_usb_setup_offload_jack(codec_dai->component, jack); + if (ret) + return ret; + } + + *jack_setup = true; + + return 0; +} +EXPORT_SYMBOL_GPL(qcom_snd_usb_offload_jack_setup); + +int qcom_snd_usb_offload_jack_remove(struct snd_soc_pcm_runtime *rtd, + bool *jack_setup) +{ + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); + struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); + int ret = 0; + + if (cpu_dai->id != USB_RX) + return -EINVAL; + + if (*jack_setup) { + ret = snd_soc_component_set_jack(codec_dai->component, NULL, NULL); + if (ret) + return ret; + } + + *jack_setup = false; + + return 0; +} +EXPORT_SYMBOL_GPL(qcom_snd_usb_offload_jack_remove); +MODULE_DESCRIPTION("ASoC Q6 USB offload controls"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/qcom/usb_offload_utils.h b/sound/soc/qcom/usb_offload_utils.h new file mode 100644 index 000000000000..c3f411f565b0 --- /dev/null +++ b/sound/soc/qcom/usb_offload_utils.h @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright (c) 2022-2025 Qualcomm Innovation Center, Inc. All rights reserved. + */ +#ifndef __QCOM_SND_USB_OFFLOAD_UTILS_H__ +#define __QCOM_SND_USB_OFFLOAD_UTILS_H__ + +#include <sound/soc.h> + +#if IS_ENABLED(CONFIG_SND_SOC_QCOM_OFFLOAD_UTILS) +int qcom_snd_usb_offload_jack_setup(struct snd_soc_pcm_runtime *rtd, + struct snd_soc_jack *jack, bool *jack_setup); + +int qcom_snd_usb_offload_jack_remove(struct snd_soc_pcm_runtime *rtd, + bool *jack_setup); +#else +static inline int qcom_snd_usb_offload_jack_setup(struct snd_soc_pcm_runtime *rtd, + struct snd_soc_jack *jack, + bool *jack_setup) +{ + return -ENODEV; +} + +static inline int qcom_snd_usb_offload_jack_remove(struct snd_soc_pcm_runtime *rtd, + bool *jack_setup) +{ + return -ENODEV; +} +#endif /* IS_ENABLED(CONFIG_SND_SOC_QCOM_OFFLOAD_UTILS) */ +#endif /* __QCOM_SND_USB_OFFLOAD_UTILS_H__ */ diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 43835197d1fe..2c21fd528afd 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -2510,17 +2510,6 @@ static int dpcm_fe_dai_prepare(struct snd_pcm_substream *substream) dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE); - /* there is no point preparing this FE if there are no BEs */ - if (list_empty(&fe->dpcm[stream].be_clients)) { - /* dev_err_once() for visibility, dev_dbg() for debugging UCM profiles */ - dev_err_once(fe->dev, "ASoC: no backend DAIs enabled for %s, possibly missing ALSA mixer-based routing or UCM profile\n", - fe->dai_link->name); - dev_dbg(fe->dev, "ASoC: no backend DAIs enabled for %s\n", - fe->dai_link->name); - ret = -EINVAL; - goto out; - } - ret = dpcm_be_dai_prepare(fe, stream); if (ret < 0) goto out; @@ -2776,11 +2765,23 @@ static int dpcm_fe_dai_open(struct snd_pcm_substream *fe_substream) /* calculate valid and active FE <-> BE dpcms */ dpcm_add_paths(fe, stream, &list); + /* There is no point starting up this FE if there are no BEs. */ + if (list_empty(&fe->dpcm[stream].be_clients)) { + /* dev_err_once() for visibility, dev_dbg() for debugging UCM profiles. */ + dev_err_once(fe->dev, "ASoC: no backend DAIs enabled for %s, possibly missing ALSA mixer-based routing or UCM profile\n", + fe->dai_link->name); + dev_dbg(fe->dev, "ASoC: no backend DAIs enabled for %s\n", fe->dai_link->name); + + ret = -EINVAL; + goto put_path; + } + ret = dpcm_fe_dai_startup(fe_substream); if (ret < 0) dpcm_fe_dai_cleanup(fe_substream); dpcm_clear_pending_state(fe, stream); +put_path: dpcm_path_put(&list); open_end: snd_soc_dpcm_mutex_unlock(fe); diff --git a/sound/soc/soc-usb.c b/sound/soc/soc-usb.c new file mode 100644 index 000000000000..26baa66d29a8 --- /dev/null +++ b/sound/soc/soc-usb.c @@ -0,0 +1,322 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2022-2025 Qualcomm Innovation Center, Inc. All rights reserved. + */ +#include <linux/of.h> +#include <linux/usb.h> + +#include <sound/jack.h> +#include <sound/soc-usb.h> + +#include "../usb/card.h" + +static DEFINE_MUTEX(ctx_mutex); +static LIST_HEAD(usb_ctx_list); + +static struct device_node *snd_soc_find_phandle(struct device *dev) +{ + struct device_node *node; + + node = of_parse_phandle(dev->of_node, "usb-soc-be", 0); + if (!node) + return ERR_PTR(-ENODEV); + + return node; +} + +static struct snd_soc_usb *snd_soc_usb_ctx_lookup(struct device_node *node) +{ + struct snd_soc_usb *ctx; + + if (!node) + return NULL; + + list_for_each_entry(ctx, &usb_ctx_list, list) { + if (ctx->component->dev->of_node == node) + return ctx; + } + + return NULL; +} + +static struct snd_soc_usb *snd_soc_find_usb_ctx(struct device *dev) +{ + struct snd_soc_usb *ctx; + struct device_node *node; + + node = snd_soc_find_phandle(dev); + if (!IS_ERR(node)) { + ctx = snd_soc_usb_ctx_lookup(node); + of_node_put(node); + } else { + ctx = snd_soc_usb_ctx_lookup(dev->of_node); + } + + return ctx ? ctx : NULL; +} + +/* SOC USB sound kcontrols */ +/** + * snd_soc_usb_setup_offload_jack() - Create USB offloading jack + * @component: USB DPCM backend DAI component + * @jack: jack structure to create + * + * Creates a jack device for notifying userspace of the availability + * of an offload capable device. + * + * Returns 0 on success, negative on error. + * + */ +int snd_soc_usb_setup_offload_jack(struct snd_soc_component *component, + struct snd_soc_jack *jack) +{ + int ret; + + ret = snd_soc_card_jack_new(component->card, "USB Offload Jack", + SND_JACK_USB, jack); + if (ret < 0) { + dev_err(component->card->dev, "Unable to add USB offload jack: %d\n", + ret); + return ret; + } + + ret = snd_soc_component_set_jack(component, jack, NULL); + if (ret) { + dev_err(component->card->dev, "Failed to set jack: %d\n", ret); + return ret; + } + + return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_usb_setup_offload_jack); + +/** + * snd_soc_usb_update_offload_route - Find active USB offload path + * @dev: USB device to get offload status + * @card: USB card index + * @pcm: USB PCM device index + * @direction: playback or capture direction + * @path: pcm or card index + * @route: pointer to route output array + * + * Fetch the current status for the USB SND card and PCM device indexes + * specified. The "route" argument should be an array of integers being + * used for a kcontrol output. The first element should have the selected + * card index, and the second element should have the selected pcm device + * index. + */ +int snd_soc_usb_update_offload_route(struct device *dev, int card, int pcm, + int direction, enum snd_soc_usb_kctl path, + long *route) +{ + struct snd_soc_usb *ctx; + int ret = -ENODEV; + + mutex_lock(&ctx_mutex); + ctx = snd_soc_find_usb_ctx(dev); + if (!ctx) + goto exit; + + if (ctx->update_offload_route_info) + ret = ctx->update_offload_route_info(ctx->component, card, pcm, + direction, path, route); +exit: + mutex_unlock(&ctx_mutex); + + return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_usb_update_offload_route); + +/** + * snd_soc_usb_find_priv_data() - Retrieve private data stored + * @usbdev: device reference + * + * Fetch the private data stored in the USB SND SoC structure. + * + */ +void *snd_soc_usb_find_priv_data(struct device *usbdev) +{ + struct snd_soc_usb *ctx; + + mutex_lock(&ctx_mutex); + ctx = snd_soc_find_usb_ctx(usbdev); + mutex_unlock(&ctx_mutex); + + return ctx ? ctx->priv_data : NULL; +} +EXPORT_SYMBOL_GPL(snd_soc_usb_find_priv_data); + +/** + * snd_soc_usb_find_supported_format() - Check if audio format is supported + * @card_idx: USB sound chip array index + * @params: PCM parameters + * @direction: capture or playback + * + * Ensure that a requested audio profile from the ASoC side is able to be + * supported by the USB device. + * + * Return 0 on success, negative on error. + * + */ +int snd_soc_usb_find_supported_format(int card_idx, + struct snd_pcm_hw_params *params, + int direction) +{ + struct snd_usb_stream *as; + + as = snd_usb_find_suppported_substream(card_idx, params, direction); + if (!as) + return -EOPNOTSUPP; + + return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_usb_find_supported_format); + +/** + * snd_soc_usb_allocate_port() - allocate a SoC USB port for offloading support + * @component: USB DPCM backend DAI component + * @data: private data + * + * Allocate and initialize a SoC USB port. The SoC USB port is used to communicate + * different USB audio devices attached, in order to start audio offloading handled + * by an ASoC entity. USB device plug in/out events are signaled with a + * notification, but don't directly impact the memory allocated for the SoC USB + * port. + * + */ +struct snd_soc_usb *snd_soc_usb_allocate_port(struct snd_soc_component *component, + void *data) +{ + struct snd_soc_usb *usb; + + usb = kzalloc(sizeof(*usb), GFP_KERNEL); + if (!usb) + return ERR_PTR(-ENOMEM); + + usb->component = component; + usb->priv_data = data; + + return usb; +} +EXPORT_SYMBOL_GPL(snd_soc_usb_allocate_port); + +/** + * snd_soc_usb_free_port() - free a SoC USB port used for offloading support + * @usb: allocated SoC USB port + * + * Free and remove the SoC USB port from the available list of ports. This will + * ensure that the communication between USB SND and ASoC is halted. + * + */ +void snd_soc_usb_free_port(struct snd_soc_usb *usb) +{ + snd_soc_usb_remove_port(usb); + kfree(usb); +} +EXPORT_SYMBOL_GPL(snd_soc_usb_free_port); + +/** + * snd_soc_usb_add_port() - Add a USB backend port + * @usb: soc usb port to add + * + * Register a USB backend DAI link to the USB SoC framework. Memory is allocated + * as part of the USB backend DAI link. + * + */ +void snd_soc_usb_add_port(struct snd_soc_usb *usb) +{ + mutex_lock(&ctx_mutex); + list_add_tail(&usb->list, &usb_ctx_list); + mutex_unlock(&ctx_mutex); + + snd_usb_rediscover_devices(); +} +EXPORT_SYMBOL_GPL(snd_soc_usb_add_port); + +/** + * snd_soc_usb_remove_port() - Remove a USB backend port + * @usb: soc usb port to remove + * + * Remove a USB backend DAI link from USB SoC. Memory is freed when USB backend + * DAI is removed, or when snd_soc_usb_free_port() is called. + * + */ +void snd_soc_usb_remove_port(struct snd_soc_usb *usb) +{ + struct snd_soc_usb *ctx, *tmp; + + mutex_lock(&ctx_mutex); + list_for_each_entry_safe(ctx, tmp, &usb_ctx_list, list) { + if (ctx == usb) { + list_del(&ctx->list); + break; + } + } + mutex_unlock(&ctx_mutex); +} +EXPORT_SYMBOL_GPL(snd_soc_usb_remove_port); + +/** + * snd_soc_usb_connect() - Notification of USB device connection + * @usbdev: USB bus device + * @sdev: USB SND device to add + * + * Notify of a new USB SND device connection. The sdev->card_idx can be used to + * handle how the DPCM backend selects, which device to enable USB offloading + * on. + * + */ +int snd_soc_usb_connect(struct device *usbdev, struct snd_soc_usb_device *sdev) +{ + struct snd_soc_usb *ctx; + + if (!usbdev) + return -ENODEV; + + mutex_lock(&ctx_mutex); + ctx = snd_soc_find_usb_ctx(usbdev); + if (!ctx) + goto exit; + + if (ctx->connection_status_cb) + ctx->connection_status_cb(ctx, sdev, true); + +exit: + mutex_unlock(&ctx_mutex); + + return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_usb_connect); + +/** + * snd_soc_usb_disconnect() - Notification of USB device disconnection + * @usbdev: USB bus device + * @sdev: USB SND device to remove + * + * Notify of a new USB SND device disconnection to the USB backend. + * + */ +int snd_soc_usb_disconnect(struct device *usbdev, struct snd_soc_usb_device *sdev) +{ + struct snd_soc_usb *ctx; + + if (!usbdev) + return -ENODEV; + + mutex_lock(&ctx_mutex); + ctx = snd_soc_find_usb_ctx(usbdev); + if (!ctx) + goto exit; + + if (ctx->connection_status_cb) + ctx->connection_status_cb(ctx, sdev, false); + +exit: + mutex_unlock(&ctx_mutex); + + return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_usb_disconnect); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("SoC USB driver for offloading"); diff --git a/sound/soc/ti/omap-hdmi.c b/sound/soc/ti/omap-hdmi.c index cf43ac19c4a6..55e7cb96858f 100644 --- a/sound/soc/ti/omap-hdmi.c +++ b/sound/soc/ti/omap-hdmi.c @@ -361,17 +361,20 @@ static int omap_hdmi_audio_probe(struct platform_device *pdev) if (!card->dai_link) return -ENOMEM; - compnent = devm_kzalloc(dev, sizeof(*compnent), GFP_KERNEL); + compnent = devm_kzalloc(dev, 2 * sizeof(*compnent), GFP_KERNEL); if (!compnent) return -ENOMEM; - card->dai_link->cpus = compnent; + card->dai_link->cpus = &compnent[0]; card->dai_link->num_cpus = 1; card->dai_link->codecs = &snd_soc_dummy_dlc; card->dai_link->num_codecs = 1; + card->dai_link->platforms = &compnent[1]; + card->dai_link->num_platforms = 1; card->dai_link->name = card->name; card->dai_link->stream_name = card->name; card->dai_link->cpus->dai_name = dev_name(ad->dssdev); + card->dai_link->platforms->name = dev_name(ad->dssdev); card->num_links = 1; card->dev = dev; diff --git a/sound/synth/emux/emux_synth.c b/sound/synth/emux/emux_synth.c index 02e2c69d7f18..cff6aba9bfc3 100644 --- a/sound/synth/emux/emux_synth.c +++ b/sound/synth/emux/emux_synth.c @@ -190,7 +190,7 @@ snd_emux_note_off(void *p, int note, int vel, struct snd_midi_channel *chan) */ void snd_emux_timer_callback(struct timer_list *t) { - struct snd_emux *emu = from_timer(emu, t, tlist); + struct snd_emux *emu = timer_container_of(emu, t, tlist); struct snd_emux_voice *vp; unsigned long flags; int ch, do_again = 0; diff --git a/sound/usb/Kconfig b/sound/usb/Kconfig index 4a9569a3a39a..41c47301bc19 100644 --- a/sound/usb/Kconfig +++ b/sound/usb/Kconfig @@ -176,6 +176,21 @@ config SND_BCD2000 To compile this driver as a module, choose M here: the module will be called snd-bcd2000. +config SND_USB_AUDIO_QMI + tristate "Qualcomm Audio Offload driver" + depends on QCOM_QMI_HELPERS && SND_USB_AUDIO && SND_SOC_USB + depends on USB_XHCI_HCD && USB_XHCI_SIDEBAND + help + Say Y here to enable the Qualcomm USB audio offloading feature. + + This module sets up the required QMI stream enable/disable + responses to requests generated by the audio DSP. It passes the + USB transfer resource references, so that the audio DSP can issue + USB transfers to the host controller. + + To compile this driver as a module, choose M here: the module + will be called snd-usb-audio-qmi. + source "sound/usb/line6/Kconfig" endif # SND_USB diff --git a/sound/usb/Makefile b/sound/usb/Makefile index 30bd5348477b..e62794a87e73 100644 --- a/sound/usb/Makefile +++ b/sound/usb/Makefile @@ -35,5 +35,5 @@ obj-$(CONFIG_SND_USB_UA101) += snd-usbmidi-lib.o obj-$(CONFIG_SND_USB_USX2Y) += snd-usbmidi-lib.o obj-$(CONFIG_SND_USB_US122L) += snd-usbmidi-lib.o -obj-$(CONFIG_SND) += misc/ usx2y/ caiaq/ 6fire/ hiface/ bcd2000/ +obj-$(CONFIG_SND) += misc/ usx2y/ caiaq/ 6fire/ hiface/ bcd2000/ qcom/ obj-$(CONFIG_SND_USB_LINE6) += line6/ diff --git a/sound/usb/card.c b/sound/usb/card.c index 9c411b82a218..9fb8726a6c93 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c @@ -118,6 +118,95 @@ MODULE_PARM_DESC(skip_validation, "Skip unit descriptor validation (default: no) static DEFINE_MUTEX(register_mutex); static struct snd_usb_audio *usb_chip[SNDRV_CARDS]; static struct usb_driver usb_audio_driver; +static struct snd_usb_platform_ops *platform_ops; + +/* + * Register platform specific operations that will be notified on events + * which occur in USB SND. The platform driver can utilize this path to + * enable features, such as USB audio offloading, which allows for audio data + * to be queued by an audio DSP. + * + * Only one set of platform operations can be registered to USB SND. The + * platform register operation is protected by the register_mutex. + */ +int snd_usb_register_platform_ops(struct snd_usb_platform_ops *ops) +{ + guard(mutex)(®ister_mutex); + if (platform_ops) + return -EEXIST; + + platform_ops = ops; + return 0; +} +EXPORT_SYMBOL_GPL(snd_usb_register_platform_ops); + +/* + * Unregisters the current set of platform operations. This allows for + * a new set to be registered if required. + * + * The platform unregister operation is protected by the register_mutex. + */ +int snd_usb_unregister_platform_ops(void) +{ + guard(mutex)(®ister_mutex); + platform_ops = NULL; + + return 0; +} +EXPORT_SYMBOL_GPL(snd_usb_unregister_platform_ops); + +/* + * in case the platform driver was not ready at the time of USB SND + * device connect, expose an API to discover all connected USB devices + * so it can populate any dependent resources/structures. + */ +void snd_usb_rediscover_devices(void) +{ + int i; + + guard(mutex)(®ister_mutex); + + if (!platform_ops || !platform_ops->connect_cb) + return; + + for (i = 0; i < SNDRV_CARDS; i++) { + if (usb_chip[i]) + platform_ops->connect_cb(usb_chip[i]); + } +} +EXPORT_SYMBOL_GPL(snd_usb_rediscover_devices); + +/* + * Checks to see if requested audio profile, i.e sample rate, # of + * channels, etc... is supported by the substream associated to the + * USB audio device. + */ +struct snd_usb_stream * +snd_usb_find_suppported_substream(int card_idx, struct snd_pcm_hw_params *params, + int direction) +{ + struct snd_usb_audio *chip; + struct snd_usb_substream *subs; + struct snd_usb_stream *as; + + /* + * Register mutex is held when populating and clearing usb_chip + * array. + */ + guard(mutex)(®ister_mutex); + chip = usb_chip[card_idx]; + + if (chip && enable[card_idx]) { + list_for_each_entry(as, &chip->pcm_list, list) { + subs = &as->substream[direction]; + if (snd_usb_find_substream_format(subs, params)) + return as; + } + } + + return NULL; +} +EXPORT_SYMBOL_GPL(snd_usb_find_suppported_substream); /* * disconnect streams @@ -922,7 +1011,11 @@ static int usb_audio_probe(struct usb_interface *intf, chip->num_interfaces++; usb_set_intfdata(intf, chip); atomic_dec(&chip->active); + + if (platform_ops && platform_ops->connect_cb) + platform_ops->connect_cb(chip); mutex_unlock(®ister_mutex); + return 0; __error: @@ -959,6 +1052,9 @@ static void usb_audio_disconnect(struct usb_interface *intf) card = chip->card; mutex_lock(®ister_mutex); + if (platform_ops && platform_ops->disconnect_cb) + platform_ops->disconnect_cb(chip); + if (atomic_inc_return(&chip->shutdown) == 1) { struct snd_usb_stream *as; struct snd_usb_endpoint *ep; @@ -1030,6 +1126,7 @@ int snd_usb_lock_shutdown(struct snd_usb_audio *chip) wake_up(&chip->shutdown_wait); return err; } +EXPORT_SYMBOL_GPL(snd_usb_lock_shutdown); /* autosuspend and unlock the shutdown */ void snd_usb_unlock_shutdown(struct snd_usb_audio *chip) @@ -1038,6 +1135,7 @@ void snd_usb_unlock_shutdown(struct snd_usb_audio *chip) if (atomic_dec_and_test(&chip->usage_count)) wake_up(&chip->shutdown_wait); } +EXPORT_SYMBOL_GPL(snd_usb_unlock_shutdown); int snd_usb_autoresume(struct snd_usb_audio *chip) { @@ -1060,6 +1158,7 @@ int snd_usb_autoresume(struct snd_usb_audio *chip) } return 0; } +EXPORT_SYMBOL_GPL(snd_usb_autoresume); void snd_usb_autosuspend(struct snd_usb_audio *chip) { @@ -1073,6 +1172,7 @@ void snd_usb_autosuspend(struct snd_usb_audio *chip) for (i = 0; i < chip->num_interfaces; i++) usb_autopm_put_interface(chip->intf[i]); } +EXPORT_SYMBOL_GPL(snd_usb_autosuspend); static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message) { @@ -1102,6 +1202,9 @@ static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message) chip->system_suspend = chip->num_suspended_intf; } + if (platform_ops && platform_ops->suspend_cb) + platform_ops->suspend_cb(intf, message); + return 0; } @@ -1142,6 +1245,9 @@ static int usb_audio_resume(struct usb_interface *intf) snd_usb_midi_v2_resume_all(chip); + if (platform_ops && platform_ops->resume_cb) + platform_ops->resume_cb(intf); + out: if (chip->num_suspended_intf == chip->system_suspend) { snd_power_change_state(chip->card, SNDRV_CTL_POWER_D0); diff --git a/sound/usb/card.h b/sound/usb/card.h index 6ec95b2edf86..94404c24d240 100644 --- a/sound/usb/card.h +++ b/sound/usb/card.h @@ -15,6 +15,7 @@ struct audioformat { unsigned int channels; /* # channels */ unsigned int fmt_type; /* USB audio format type (1-3) */ unsigned int fmt_bits; /* number of significant bits */ + unsigned int fmt_sz; /* overall audio sub frame/slot size */ unsigned int frame_size; /* samples per frame for non-audio */ unsigned char iface; /* interface number */ unsigned char altsetting; /* corresponding alternate setting */ @@ -164,6 +165,7 @@ struct snd_usb_substream { unsigned int pkt_offset_adj; /* Bytes to drop from beginning of packets (for non-compliant devices) */ unsigned int stream_offset_adj; /* Bytes to drop from beginning of stream (for non-compliant devices) */ + unsigned int opened:1; /* pcm device opened */ unsigned int running: 1; /* running status */ unsigned int period_elapsed_pending; /* delay period handling */ @@ -207,4 +209,19 @@ struct snd_usb_stream { struct list_head list; }; +struct snd_usb_platform_ops { + void (*connect_cb)(struct snd_usb_audio *chip); + void (*disconnect_cb)(struct snd_usb_audio *chip); + void (*suspend_cb)(struct usb_interface *intf, pm_message_t message); + void (*resume_cb)(struct usb_interface *intf); +}; + +struct snd_usb_stream * +snd_usb_find_suppported_substream(int card_idx, struct snd_pcm_hw_params *params, + int direction); + +int snd_usb_register_platform_ops(struct snd_usb_platform_ops *ops); +int snd_usb_unregister_platform_ops(void); + +void snd_usb_rediscover_devices(void); #endif /* __USBAUDIO_CARD_H */ diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index f36ec98da460..7b01e7b4e335 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c @@ -1531,6 +1531,7 @@ unlock: mutex_unlock(&chip->mutex); return err; } +EXPORT_SYMBOL_GPL(snd_usb_endpoint_prepare); /* get the current rate set to the given clock by any endpoint */ int snd_usb_endpoint_get_clock_rate(struct snd_usb_audio *chip, int clock) diff --git a/sound/usb/format.c b/sound/usb/format.c index 0ba4641a0eb1..8cd54f7bf33a 100644 --- a/sound/usb/format.c +++ b/sound/usb/format.c @@ -85,6 +85,7 @@ static u64 parse_audio_format_i_type(struct snd_usb_audio *chip, } fp->fmt_bits = sample_width; + fp->fmt_sz = sample_bytes; if ((pcm_formats == 0) && (format == 0 || format == BIT(UAC_FORMAT_TYPE_I_UNDEFINED))) { diff --git a/sound/usb/helper.c b/sound/usb/helper.c index 72b671fb2c84..497d2b27fb59 100644 --- a/sound/usb/helper.c +++ b/sound/usb/helper.c @@ -62,6 +62,7 @@ void *snd_usb_find_csint_desc(void *buffer, int buflen, void *after, u8 dsubtype } return NULL; } +EXPORT_SYMBOL_GPL(snd_usb_find_csint_desc); /* * Wrapper for usb_control_msg(). diff --git a/sound/usb/implicit.c b/sound/usb/implicit.c index 4727043fd745..77f06da93151 100644 --- a/sound/usb/implicit.c +++ b/sound/usb/implicit.c @@ -57,6 +57,7 @@ static const struct snd_usb_implicit_fb_match playback_implicit_fb_quirks[] = { IMPLICIT_FB_FIXED_DEV(0x31e9, 0x0002, 0x81, 2), /* Solid State Logic SSL2+ */ IMPLICIT_FB_FIXED_DEV(0x0499, 0x172f, 0x81, 2), /* Steinberg UR22C */ IMPLICIT_FB_FIXED_DEV(0x0d9a, 0x00df, 0x81, 2), /* RTX6001 */ + IMPLICIT_FB_FIXED_DEV(0x19f7, 0x000a, 0x84, 3), /* RODE AI-1 */ IMPLICIT_FB_FIXED_DEV(0x22f0, 0x0006, 0x81, 3), /* Allen&Heath Qu-16 */ IMPLICIT_FB_FIXED_DEV(0x1686, 0xf029, 0x82, 2), /* Zoom UAC-2 */ IMPLICIT_FB_FIXED_DEV(0x2466, 0x8003, 0x86, 2), /* Fractal Audio Axe-Fx II */ diff --git a/sound/usb/midi.c b/sound/usb/midi.c index 3a8a977ed359..866e613fee4f 100644 --- a/sound/usb/midi.c +++ b/sound/usb/midi.c @@ -339,7 +339,7 @@ static void snd_usbmidi_out_work(struct work_struct *work) /* called after transfers had been interrupted due to some USB error */ static void snd_usbmidi_error_timer(struct timer_list *t) { - struct snd_usb_midi *umidi = from_timer(umidi, t, error_timer); + struct snd_usb_midi *umidi = timer_container_of(umidi, t, error_timer); unsigned int i, j; spin_lock(&umidi->disc_lock); diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 08bf535ed163..b24ee38fad72 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -148,6 +148,16 @@ find_format(struct list_head *fmt_list_head, snd_pcm_format_t format, return found; } +const struct audioformat * +snd_usb_find_format(struct list_head *fmt_list_head, snd_pcm_format_t format, + unsigned int rate, unsigned int channels, bool strict_match, + struct snd_usb_substream *subs) +{ + return find_format(fmt_list_head, format, rate, channels, strict_match, + subs); +} +EXPORT_SYMBOL_GPL(snd_usb_find_format); + static const struct audioformat * find_substream_format(struct snd_usb_substream *subs, const struct snd_pcm_hw_params *params) @@ -157,6 +167,14 @@ find_substream_format(struct snd_usb_substream *subs, true, subs); } +const struct audioformat * +snd_usb_find_substream_format(struct snd_usb_substream *subs, + const struct snd_pcm_hw_params *params) +{ + return find_substream_format(subs, params); +} +EXPORT_SYMBOL_GPL(snd_usb_find_substream_format); + bool snd_usb_pcm_has_fixed_rate(struct snd_usb_substream *subs) { const struct audioformat *fp; @@ -461,20 +479,9 @@ static void close_endpoints(struct snd_usb_audio *chip, } } -/* - * hw_params callback - * - * allocate a buffer and set the given audio format. - * - * so far we use a physically linear buffer although packetize transfer - * doesn't need a continuous area. - * if sg buffer is supported on the later version of alsa, we'll follow - * that. - */ -static int snd_usb_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *hw_params) +int snd_usb_hw_params(struct snd_usb_substream *subs, + struct snd_pcm_hw_params *hw_params) { - struct snd_usb_substream *subs = substream->runtime->private_data; struct snd_usb_audio *chip = subs->stream->chip; const struct audioformat *fmt; const struct audioformat *sync_fmt; @@ -499,7 +506,7 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream, if (fmt->implicit_fb) { sync_fmt = snd_usb_find_implicit_fb_sync_format(chip, fmt, hw_params, - !substream->stream, + !subs->direction, &sync_fixed_rate); if (!sync_fmt) { usb_audio_dbg(chip, @@ -579,15 +586,28 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream, return ret; } +EXPORT_SYMBOL_GPL(snd_usb_hw_params); /* - * hw_free callback + * hw_params callback * - * reset the audio format and release the buffer + * allocate a buffer and set the given audio format. + * + * so far we use a physically linear buffer although packetize transfer + * doesn't need a continuous area. + * if sg buffer is supported on the later version of alsa, we'll follow + * that. */ -static int snd_usb_hw_free(struct snd_pcm_substream *substream) +static int snd_usb_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) { struct snd_usb_substream *subs = substream->runtime->private_data; + + return snd_usb_hw_params(subs, hw_params); +} + +int snd_usb_hw_free(struct snd_usb_substream *subs) +{ struct snd_usb_audio *chip = subs->stream->chip; snd_media_stop_pipeline(subs); @@ -603,6 +623,19 @@ static int snd_usb_hw_free(struct snd_pcm_substream *substream) return 0; } +EXPORT_SYMBOL_GPL(snd_usb_hw_free); + +/* + * hw_free callback + * + * reset the audio format and release the buffer + */ +static int snd_usb_pcm_hw_free(struct snd_pcm_substream *substream) +{ + struct snd_usb_substream *subs = substream->runtime->private_data; + + return snd_usb_hw_free(subs); +} /* free-wheeling mode? (e.g. dmix) */ static int in_free_wheeling_mode(struct snd_pcm_runtime *runtime) @@ -1208,8 +1241,17 @@ static int snd_usb_pcm_open(struct snd_pcm_substream *substream) struct snd_usb_stream *as = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; struct snd_usb_substream *subs = &as->substream[direction]; + struct snd_usb_audio *chip = subs->stream->chip; int ret; + mutex_lock(&chip->mutex); + if (subs->opened) { + mutex_unlock(&chip->mutex); + return -EBUSY; + } + subs->opened = 1; + mutex_unlock(&chip->mutex); + runtime->hw = snd_usb_hardware; /* need an explicit sync to catch applptr update in low-latency mode */ if (direction == SNDRV_PCM_STREAM_PLAYBACK && @@ -1226,13 +1268,23 @@ static int snd_usb_pcm_open(struct snd_pcm_substream *substream) ret = setup_hw_info(runtime, subs); if (ret < 0) - return ret; + goto err_open; ret = snd_usb_autoresume(subs->stream->chip); if (ret < 0) - return ret; + goto err_open; ret = snd_media_stream_init(subs, as->pcm, direction); if (ret < 0) - snd_usb_autosuspend(subs->stream->chip); + goto err_resume; + + return 0; + +err_resume: + snd_usb_autosuspend(subs->stream->chip); +err_open: + mutex_lock(&chip->mutex); + subs->opened = 0; + mutex_unlock(&chip->mutex); + return ret; } @@ -1241,6 +1293,7 @@ static int snd_usb_pcm_close(struct snd_pcm_substream *substream) int direction = substream->stream; struct snd_usb_stream *as = snd_pcm_substream_chip(substream); struct snd_usb_substream *subs = &as->substream[direction]; + struct snd_usb_audio *chip = subs->stream->chip; int ret; snd_media_stop_pipeline(subs); @@ -1254,6 +1307,9 @@ static int snd_usb_pcm_close(struct snd_pcm_substream *substream) subs->pcm_substream = NULL; snd_usb_autosuspend(subs->stream->chip); + mutex_lock(&chip->mutex); + subs->opened = 0; + mutex_unlock(&chip->mutex); return 0; } @@ -1746,8 +1802,8 @@ static int snd_usb_substream_capture_trigger(struct snd_pcm_substream *substream static const struct snd_pcm_ops snd_usb_playback_ops = { .open = snd_usb_pcm_open, .close = snd_usb_pcm_close, - .hw_params = snd_usb_hw_params, - .hw_free = snd_usb_hw_free, + .hw_params = snd_usb_pcm_hw_params, + .hw_free = snd_usb_pcm_hw_free, .prepare = snd_usb_pcm_prepare, .trigger = snd_usb_substream_playback_trigger, .sync_stop = snd_usb_pcm_sync_stop, @@ -1758,8 +1814,8 @@ static const struct snd_pcm_ops snd_usb_playback_ops = { static const struct snd_pcm_ops snd_usb_capture_ops = { .open = snd_usb_pcm_open, .close = snd_usb_pcm_close, - .hw_params = snd_usb_hw_params, - .hw_free = snd_usb_hw_free, + .hw_params = snd_usb_pcm_hw_params, + .hw_free = snd_usb_pcm_hw_free, .prepare = snd_usb_pcm_prepare, .trigger = snd_usb_substream_capture_trigger, .sync_stop = snd_usb_pcm_sync_stop, diff --git a/sound/usb/pcm.h b/sound/usb/pcm.h index 388fe2ba346d..c096021adb2b 100644 --- a/sound/usb/pcm.h +++ b/sound/usb/pcm.h @@ -15,4 +15,15 @@ void snd_usb_preallocate_buffer(struct snd_usb_substream *subs); int snd_usb_audioformat_set_sync_ep(struct snd_usb_audio *chip, struct audioformat *fmt); +const struct audioformat * +snd_usb_find_format(struct list_head *fmt_list_head, snd_pcm_format_t format, + unsigned int rate, unsigned int channels, bool strict_match, + struct snd_usb_substream *subs); +const struct audioformat * +snd_usb_find_substream_format(struct snd_usb_substream *subs, + const struct snd_pcm_hw_params *params); + +int snd_usb_hw_params(struct snd_usb_substream *subs, + struct snd_pcm_hw_params *hw_params); +int snd_usb_hw_free(struct snd_usb_substream *subs); #endif /* __USBAUDIO_PCM_H */ diff --git a/sound/usb/qcom/Makefile b/sound/usb/qcom/Makefile new file mode 100644 index 000000000000..6567727b66f0 --- /dev/null +++ b/sound/usb/qcom/Makefile @@ -0,0 +1,4 @@ +snd-usb-audio-qmi-y := usb_audio_qmi_v01.o qc_audio_offload.o +snd-usb-audio-qmi-y += mixer_usb_offload.o +obj-$(CONFIG_SND_USB_AUDIO_QMI) += snd-usb-audio-qmi.o + diff --git a/sound/usb/qcom/mixer_usb_offload.c b/sound/usb/qcom/mixer_usb_offload.c new file mode 100644 index 000000000000..2adeb64f4d33 --- /dev/null +++ b/sound/usb/qcom/mixer_usb_offload.c @@ -0,0 +1,155 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2022-2025 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include <linux/usb.h> + +#include <sound/core.h> +#include <sound/control.h> +#include <sound/soc-usb.h> + +#include "../usbaudio.h" +#include "../card.h" +#include "../helper.h" +#include "../mixer.h" + +#include "mixer_usb_offload.h" + +#define PCM_IDX(n) ((n) & 0xffff) +#define CARD_IDX(n) ((n) >> 16) + +static int +snd_usb_offload_card_route_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct device *sysdev = snd_kcontrol_chip(kcontrol); + int ret; + + ret = snd_soc_usb_update_offload_route(sysdev, + CARD_IDX(kcontrol->private_value), + PCM_IDX(kcontrol->private_value), + SNDRV_PCM_STREAM_PLAYBACK, + SND_SOC_USB_KCTL_CARD_ROUTE, + ucontrol->value.integer.value); + if (ret < 0) { + ucontrol->value.integer.value[0] = -1; + ucontrol->value.integer.value[1] = -1; + } + + return 0; +} + +static int snd_usb_offload_card_route_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = -1; + uinfo->value.integer.max = SNDRV_CARDS; + + return 0; +} + +static struct snd_kcontrol_new snd_usb_offload_mapped_card_ctl = { + .iface = SNDRV_CTL_ELEM_IFACE_CARD, + .access = SNDRV_CTL_ELEM_ACCESS_READ, + .info = snd_usb_offload_card_route_info, + .get = snd_usb_offload_card_route_get, +}; + +static int +snd_usb_offload_pcm_route_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct device *sysdev = snd_kcontrol_chip(kcontrol); + int ret; + + ret = snd_soc_usb_update_offload_route(sysdev, + CARD_IDX(kcontrol->private_value), + PCM_IDX(kcontrol->private_value), + SNDRV_PCM_STREAM_PLAYBACK, + SND_SOC_USB_KCTL_PCM_ROUTE, + ucontrol->value.integer.value); + if (ret < 0) { + ucontrol->value.integer.value[0] = -1; + ucontrol->value.integer.value[1] = -1; + } + + return 0; +} + +static int snd_usb_offload_pcm_route_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = -1; + /* Arbitrary max value, as there is no 'limit' on number of PCM devices */ + uinfo->value.integer.max = 0xff; + + return 0; +} + +static struct snd_kcontrol_new snd_usb_offload_mapped_pcm_ctl = { + .iface = SNDRV_CTL_ELEM_IFACE_CARD, + .access = SNDRV_CTL_ELEM_ACCESS_READ, + .info = snd_usb_offload_pcm_route_info, + .get = snd_usb_offload_pcm_route_get, +}; + +/** + * snd_usb_offload_create_ctl() - Add USB offload bounded mixer + * @chip: USB SND chip device + * @bedev: Reference to USB backend DAI device + * + * Creates a sound control for a USB audio device, so that applications can + * query for if there is an available USB audio offload path, and which + * card is managing it. + */ +int snd_usb_offload_create_ctl(struct snd_usb_audio *chip, struct device *bedev) +{ + struct snd_kcontrol_new *chip_kctl; + struct snd_usb_substream *subs; + struct snd_usb_stream *as; + char ctl_name[48]; + int ret; + + list_for_each_entry(as, &chip->pcm_list, list) { + subs = &as->substream[SNDRV_PCM_STREAM_PLAYBACK]; + if (!subs->ep_num || as->pcm_index > 0xff) + continue; + + chip_kctl = &snd_usb_offload_mapped_card_ctl; + chip_kctl->count = 1; + /* + * Store the associated USB SND card number and PCM index for + * the kctl. + */ + chip_kctl->private_value = as->pcm_index | + chip->card->number << 16; + sprintf(ctl_name, "USB Offload Playback Card Route PCM#%d", + as->pcm_index); + chip_kctl->name = ctl_name; + ret = snd_ctl_add(chip->card, snd_ctl_new1(chip_kctl, bedev)); + if (ret < 0) + break; + + chip_kctl = &snd_usb_offload_mapped_pcm_ctl; + chip_kctl->count = 1; + /* + * Store the associated USB SND card number and PCM index for + * the kctl. + */ + chip_kctl->private_value = as->pcm_index | + chip->card->number << 16; + sprintf(ctl_name, "USB Offload Playback PCM Route PCM#%d", + as->pcm_index); + chip_kctl->name = ctl_name; + ret = snd_ctl_add(chip->card, snd_ctl_new1(chip_kctl, bedev)); + if (ret < 0) + break; + } + + return ret; +} diff --git a/sound/usb/qcom/mixer_usb_offload.h b/sound/usb/qcom/mixer_usb_offload.h new file mode 100644 index 000000000000..cf20673f4dc9 --- /dev/null +++ b/sound/usb/qcom/mixer_usb_offload.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright (c) 2022-2025 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef __USB_OFFLOAD_MIXER_H +#define __USB_OFFLOAD_MIXER_H + +int snd_usb_offload_create_ctl(struct snd_usb_audio *chip, struct device *bedev); + +#endif /* __USB_OFFLOAD_MIXER_H */ diff --git a/sound/usb/qcom/qc_audio_offload.c b/sound/usb/qcom/qc_audio_offload.c new file mode 100644 index 000000000000..5bc27c82e0af --- /dev/null +++ b/sound/usb/qcom/qc_audio_offload.c @@ -0,0 +1,2017 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2022-2025 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include <linux/auxiliary_bus.h> +#include <linux/ctype.h> +#include <linux/dma-mapping.h> +#include <linux/dma-map-ops.h> +#include <linux/init.h> +#include <linux/iommu.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/soc/qcom/qmi.h> +#include <linux/usb.h> +#include <linux/usb/audio.h> +#include <linux/usb/audio-v2.h> +#include <linux/usb/audio-v3.h> +#include <linux/usb/hcd.h> +#include <linux/usb/quirks.h> +#include <linux/usb/xhci-sideband.h> + +#include <sound/control.h> +#include <sound/core.h> +#include <sound/info.h> +#include <sound/initval.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/q6usboffload.h> +#include <sound/soc.h> +#include <sound/soc-usb.h> + +#include "../usbaudio.h" +#include "../card.h" +#include "../endpoint.h" +#include "../format.h" +#include "../helper.h" +#include "../pcm.h" +#include "../power.h" + +#include "mixer_usb_offload.h" +#include "usb_audio_qmi_v01.h" + +/* Stream disable request timeout during USB device disconnect */ +#define DEV_RELEASE_WAIT_TIMEOUT 10000 /* in ms */ + +/* Data interval calculation parameters */ +#define BUS_INTERVAL_FULL_SPEED 1000 /* in us */ +#define BUS_INTERVAL_HIGHSPEED_AND_ABOVE 125 /* in us */ +#define MAX_BINTERVAL_ISOC_EP 16 + +#define QMI_STREAM_REQ_CARD_NUM_MASK 0xffff0000 +#define QMI_STREAM_REQ_DEV_NUM_MASK 0xff00 +#define QMI_STREAM_REQ_DIRECTION 0xff + +/* iommu resource parameters and management */ +#define PREPEND_SID_TO_IOVA(iova, sid) ((u64)(((u64)(iova)) | \ + (((u64)sid) << 32))) +#define IOVA_MASK(iova) (((u64)(iova)) & 0xFFFFFFFF) +#define IOVA_BASE 0x1000 +#define IOVA_XFER_RING_BASE (IOVA_BASE + PAGE_SIZE * (SNDRV_CARDS + 1)) +#define IOVA_XFER_BUF_BASE (IOVA_XFER_RING_BASE + PAGE_SIZE * SNDRV_CARDS * 32) +#define IOVA_XFER_RING_MAX (IOVA_XFER_BUF_BASE - PAGE_SIZE) +#define IOVA_XFER_BUF_MAX (0xfffff000 - PAGE_SIZE) + +#define MAX_XFER_BUFF_LEN (24 * PAGE_SIZE) + +struct iova_info { + struct list_head list; + unsigned long start_iova; + size_t size; + bool in_use; +}; + +struct intf_info { + /* IOMMU ring/buffer mapping information */ + unsigned long data_xfer_ring_va; + size_t data_xfer_ring_size; + unsigned long sync_xfer_ring_va; + size_t sync_xfer_ring_size; + dma_addr_t xfer_buf_iova; + size_t xfer_buf_size; + dma_addr_t xfer_buf_dma; + u8 *xfer_buf_cpu; + + /* USB endpoint information */ + unsigned int data_ep_pipe; + unsigned int sync_ep_pipe; + unsigned int data_ep_idx; + unsigned int sync_ep_idx; + + u8 intf_num; + u8 pcm_card_num; + u8 pcm_dev_num; + u8 direction; + bool in_use; +}; + +struct uaudio_qmi_dev { + struct device *dev; + struct q6usb_offload *data; + struct auxiliary_device *auxdev; + + /* list to keep track of available iova */ + struct list_head xfer_ring_list; + size_t xfer_ring_iova_size; + unsigned long curr_xfer_ring_iova; + struct list_head xfer_buf_list; + size_t xfer_buf_iova_size; + unsigned long curr_xfer_buf_iova; + + /* bit fields representing pcm card enabled */ + unsigned long card_slot; + /* indicate event ring mapped or not */ + bool er_mapped; +}; + +struct uaudio_dev { + struct usb_device *udev; + /* audio control interface */ + struct usb_host_interface *ctrl_intf; + unsigned int usb_core_id; + atomic_t in_use; + struct kref kref; + wait_queue_head_t disconnect_wq; + + /* interface specific */ + int num_intf; + struct intf_info *info; + struct snd_usb_audio *chip; + + /* xhci sideband */ + struct xhci_sideband *sb; + + /* SoC USB device */ + struct snd_soc_usb_device *sdev; +}; + +static struct uaudio_dev uadev[SNDRV_CARDS]; +static struct uaudio_qmi_dev *uaudio_qdev; +static struct uaudio_qmi_svc *uaudio_svc; +static DEFINE_MUTEX(qdev_mutex); + +struct uaudio_qmi_svc { + struct qmi_handle *uaudio_svc_hdl; + struct sockaddr_qrtr client_sq; + bool client_connected; +}; + +enum mem_type { + MEM_EVENT_RING, + MEM_XFER_RING, + MEM_XFER_BUF, +}; + +/* Supported audio formats */ +enum usb_qmi_audio_format { + USB_QMI_PCM_FORMAT_S8 = 0, + USB_QMI_PCM_FORMAT_U8, + USB_QMI_PCM_FORMAT_S16_LE, + USB_QMI_PCM_FORMAT_S16_BE, + USB_QMI_PCM_FORMAT_U16_LE, + USB_QMI_PCM_FORMAT_U16_BE, + USB_QMI_PCM_FORMAT_S24_LE, + USB_QMI_PCM_FORMAT_S24_BE, + USB_QMI_PCM_FORMAT_U24_LE, + USB_QMI_PCM_FORMAT_U24_BE, + USB_QMI_PCM_FORMAT_S24_3LE, + USB_QMI_PCM_FORMAT_S24_3BE, + USB_QMI_PCM_FORMAT_U24_3LE, + USB_QMI_PCM_FORMAT_U24_3BE, + USB_QMI_PCM_FORMAT_S32_LE, + USB_QMI_PCM_FORMAT_S32_BE, + USB_QMI_PCM_FORMAT_U32_LE, + USB_QMI_PCM_FORMAT_U32_BE, +}; + +static int usb_qmi_get_pcm_num(struct snd_usb_audio *chip, int direction) +{ + struct snd_usb_substream *subs = NULL; + struct snd_usb_stream *as; + int count = 0; + + list_for_each_entry(as, &chip->pcm_list, list) { + subs = &as->substream[direction]; + if (subs->ep_num) + count++; + } + + return count; +} + +static enum usb_qmi_audio_device_speed_enum_v01 +get_speed_info(enum usb_device_speed udev_speed) +{ + switch (udev_speed) { + case USB_SPEED_LOW: + return USB_QMI_DEVICE_SPEED_LOW_V01; + case USB_SPEED_FULL: + return USB_QMI_DEVICE_SPEED_FULL_V01; + case USB_SPEED_HIGH: + return USB_QMI_DEVICE_SPEED_HIGH_V01; + case USB_SPEED_SUPER: + return USB_QMI_DEVICE_SPEED_SUPER_V01; + case USB_SPEED_SUPER_PLUS: + return USB_QMI_DEVICE_SPEED_SUPER_PLUS_V01; + default: + return USB_QMI_DEVICE_SPEED_INVALID_V01; + } +} + +static struct snd_usb_substream *find_substream(unsigned int card_num, + unsigned int pcm_idx, + unsigned int direction) +{ + struct snd_usb_substream *subs = NULL; + struct snd_usb_audio *chip; + struct snd_usb_stream *as; + + chip = uadev[card_num].chip; + if (!chip || atomic_read(&chip->shutdown)) + goto done; + + if (pcm_idx >= chip->pcm_devs) + goto done; + + if (direction > SNDRV_PCM_STREAM_CAPTURE) + goto done; + + list_for_each_entry(as, &chip->pcm_list, list) { + if (as->pcm_index == pcm_idx) { + subs = &as->substream[direction]; + goto done; + } + } + +done: + return subs; +} + +static int info_idx_from_ifnum(int card_num, int intf_num, bool enable) +{ + int i; + + /* + * default index 0 is used when info is allocated upon + * first enable audio stream req for a pcm device + */ + if (enable && !uadev[card_num].info) + return 0; + + for (i = 0; i < uadev[card_num].num_intf; i++) { + if (enable && !uadev[card_num].info[i].in_use) + return i; + else if (!enable && + uadev[card_num].info[i].intf_num == intf_num) + return i; + } + + return -EINVAL; +} + +static int get_data_interval_from_si(struct snd_usb_substream *subs, + u32 service_interval) +{ + unsigned int bus_intval_mult; + unsigned int bus_intval; + unsigned int binterval; + + if (subs->dev->speed >= USB_SPEED_HIGH) + bus_intval = BUS_INTERVAL_HIGHSPEED_AND_ABOVE; + else + bus_intval = BUS_INTERVAL_FULL_SPEED; + + if (service_interval % bus_intval) + return -EINVAL; + + bus_intval_mult = service_interval / bus_intval; + binterval = ffs(bus_intval_mult); + if (!binterval || binterval > MAX_BINTERVAL_ISOC_EP) + return -EINVAL; + + /* check if another bit is set then bail out */ + bus_intval_mult = bus_intval_mult >> binterval; + if (bus_intval_mult) + return -EINVAL; + + return (binterval - 1); +} + +/* maps audio format received over QMI to asound.h based pcm format */ +static snd_pcm_format_t map_pcm_format(enum usb_qmi_audio_format fmt_received) +{ + switch (fmt_received) { + case USB_QMI_PCM_FORMAT_S8: + return SNDRV_PCM_FORMAT_S8; + case USB_QMI_PCM_FORMAT_U8: + return SNDRV_PCM_FORMAT_U8; + case USB_QMI_PCM_FORMAT_S16_LE: + return SNDRV_PCM_FORMAT_S16_LE; + case USB_QMI_PCM_FORMAT_S16_BE: + return SNDRV_PCM_FORMAT_S16_BE; + case USB_QMI_PCM_FORMAT_U16_LE: + return SNDRV_PCM_FORMAT_U16_LE; + case USB_QMI_PCM_FORMAT_U16_BE: + return SNDRV_PCM_FORMAT_U16_BE; + case USB_QMI_PCM_FORMAT_S24_LE: + return SNDRV_PCM_FORMAT_S24_LE; + case USB_QMI_PCM_FORMAT_S24_BE: + return SNDRV_PCM_FORMAT_S24_BE; + case USB_QMI_PCM_FORMAT_U24_LE: + return SNDRV_PCM_FORMAT_U24_LE; + case USB_QMI_PCM_FORMAT_U24_BE: + return SNDRV_PCM_FORMAT_U24_BE; + case USB_QMI_PCM_FORMAT_S24_3LE: + return SNDRV_PCM_FORMAT_S24_3LE; + case USB_QMI_PCM_FORMAT_S24_3BE: + return SNDRV_PCM_FORMAT_S24_3BE; + case USB_QMI_PCM_FORMAT_U24_3LE: + return SNDRV_PCM_FORMAT_U24_3LE; + case USB_QMI_PCM_FORMAT_U24_3BE: + return SNDRV_PCM_FORMAT_U24_3BE; + case USB_QMI_PCM_FORMAT_S32_LE: + return SNDRV_PCM_FORMAT_S32_LE; + case USB_QMI_PCM_FORMAT_S32_BE: + return SNDRV_PCM_FORMAT_S32_BE; + case USB_QMI_PCM_FORMAT_U32_LE: + return SNDRV_PCM_FORMAT_U32_LE; + case USB_QMI_PCM_FORMAT_U32_BE: + return SNDRV_PCM_FORMAT_U32_BE; + default: + /* + * We expect the caller to do input validation so we should + * never hit this. But we do have to return a proper + * snd_pcm_format_t value due to the __bitwise attribute; so + * just return the equivalent of 0 in case of bad input. + */ + return SNDRV_PCM_FORMAT_S8; + } +} + +/* + * Sends QMI disconnect indication message, assumes chip->mutex and qdev_mutex + * lock held by caller. + */ +static int uaudio_send_disconnect_ind(struct snd_usb_audio *chip) +{ + struct qmi_uaudio_stream_ind_msg_v01 disconnect_ind = {0}; + struct uaudio_qmi_svc *svc = uaudio_svc; + struct uaudio_dev *dev; + int ret = 0; + + dev = &uadev[chip->card->number]; + + if (atomic_read(&dev->in_use)) { + mutex_unlock(&chip->mutex); + mutex_unlock(&qdev_mutex); + dev_dbg(uaudio_qdev->data->dev, "sending qmi indication suspend\n"); + disconnect_ind.dev_event = USB_QMI_DEV_DISCONNECT_V01; + disconnect_ind.slot_id = dev->udev->slot_id; + disconnect_ind.controller_num = dev->usb_core_id; + disconnect_ind.controller_num_valid = 1; + ret = qmi_send_indication(svc->uaudio_svc_hdl, &svc->client_sq, + QMI_UAUDIO_STREAM_IND_V01, + QMI_UAUDIO_STREAM_IND_MSG_V01_MAX_MSG_LEN, + qmi_uaudio_stream_ind_msg_v01_ei, + &disconnect_ind); + if (ret < 0) + dev_err(uaudio_qdev->data->dev, + "qmi send failed with err: %d\n", ret); + + ret = wait_event_interruptible_timeout(dev->disconnect_wq, + !atomic_read(&dev->in_use), + msecs_to_jiffies(DEV_RELEASE_WAIT_TIMEOUT)); + if (!ret) { + dev_err(uaudio_qdev->data->dev, + "timeout while waiting for dev_release\n"); + atomic_set(&dev->in_use, 0); + } else if (ret < 0) { + dev_err(uaudio_qdev->data->dev, + "failed with ret %d\n", ret); + atomic_set(&dev->in_use, 0); + } + mutex_lock(&qdev_mutex); + mutex_lock(&chip->mutex); + } + + return ret; +} + +/* Offloading IOMMU management */ +static unsigned long uaudio_get_iova(unsigned long *curr_iova, + size_t *curr_iova_size, + struct list_head *head, size_t size) +{ + struct iova_info *info, *new_info = NULL; + struct list_head *curr_head; + size_t tmp_size = size; + unsigned long iova = 0; + + if (size % PAGE_SIZE) + goto done; + + if (size > *curr_iova_size) + goto done; + + if (*curr_iova_size == 0) + goto done; + + list_for_each_entry(info, head, list) { + /* exact size iova_info */ + if (!info->in_use && info->size == size) { + info->in_use = true; + iova = info->start_iova; + *curr_iova_size -= size; + goto done; + } else if (!info->in_use && tmp_size >= info->size) { + if (!new_info) + new_info = info; + tmp_size -= info->size; + if (tmp_size) + continue; + + iova = new_info->start_iova; + for (curr_head = &new_info->list; curr_head != + &info->list; curr_head = curr_head->next) { + new_info = list_entry(curr_head, struct + iova_info, list); + new_info->in_use = true; + } + info->in_use = true; + *curr_iova_size -= size; + goto done; + } else { + /* iova region in use */ + new_info = NULL; + tmp_size = size; + } + } + + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (!info) { + iova = 0; + goto done; + } + + iova = *curr_iova; + info->start_iova = *curr_iova; + info->size = size; + info->in_use = true; + *curr_iova += size; + *curr_iova_size -= size; + list_add_tail(&info->list, head); + +done: + return iova; +} + +static void uaudio_put_iova(unsigned long iova, size_t size, struct list_head + *head, size_t *curr_iova_size) +{ + struct iova_info *info; + size_t tmp_size = size; + bool found = false; + + list_for_each_entry(info, head, list) { + if (info->start_iova == iova) { + if (!info->in_use) + return; + + found = true; + info->in_use = false; + if (info->size == size) + goto done; + } + + if (found && tmp_size >= info->size) { + info->in_use = false; + tmp_size -= info->size; + if (!tmp_size) + goto done; + } + } + + if (!found) + return; + +done: + *curr_iova_size += size; +} + +/** + * uaudio_iommu_unmap() - unmaps iommu memory for adsp + * @mtype: ring type + * @iova: virtual address to unmap + * @iova_size: region size + * @mapped_iova_size: mapped region size + * + * Unmaps the memory region that was previously assigned to the adsp. + * + */ +static void uaudio_iommu_unmap(enum mem_type mtype, unsigned long iova, + size_t iova_size, size_t mapped_iova_size) +{ + size_t umap_size; + bool unmap = true; + + if (!iova || !iova_size) + return; + + switch (mtype) { + case MEM_EVENT_RING: + if (uaudio_qdev->er_mapped) + uaudio_qdev->er_mapped = false; + else + unmap = false; + break; + + case MEM_XFER_RING: + uaudio_put_iova(iova, iova_size, &uaudio_qdev->xfer_ring_list, + &uaudio_qdev->xfer_ring_iova_size); + break; + case MEM_XFER_BUF: + uaudio_put_iova(iova, iova_size, &uaudio_qdev->xfer_buf_list, + &uaudio_qdev->xfer_buf_iova_size); + break; + default: + unmap = false; + } + + if (!unmap || !mapped_iova_size) + return; + + umap_size = iommu_unmap(uaudio_qdev->data->domain, iova, mapped_iova_size); + if (umap_size != mapped_iova_size) + dev_err(uaudio_qdev->data->dev, + "unmapped size %zu for iova 0x%08lx of mapped size %zu\n", + umap_size, iova, mapped_iova_size); +} + +/** + * uaudio_iommu_map() - maps iommu memory for adsp + * @mtype: ring type + * @dma_coherent: dma coherent + * @pa: physical address for ring/buffer + * @size: size of memory region + * @sgt: sg table for memory region + * + * Maps the XHCI related resources to a memory region that is assigned to be + * used by the adsp. This will be mapped to the domain, which is created by + * the ASoC USB backend driver. + * + */ +static unsigned long uaudio_iommu_map(enum mem_type mtype, bool dma_coherent, + phys_addr_t pa, size_t size, + struct sg_table *sgt) +{ + struct scatterlist *sg; + unsigned long iova = 0; + size_t total_len = 0; + unsigned long iova_sg; + phys_addr_t pa_sg; + bool map = true; + size_t sg_len; + int prot; + int ret; + int i; + + prot = IOMMU_READ | IOMMU_WRITE; + + if (dma_coherent) + prot |= IOMMU_CACHE; + + switch (mtype) { + case MEM_EVENT_RING: + iova = IOVA_BASE; + /* er already mapped */ + if (uaudio_qdev->er_mapped) + map = false; + break; + case MEM_XFER_RING: + iova = uaudio_get_iova(&uaudio_qdev->curr_xfer_ring_iova, + &uaudio_qdev->xfer_ring_iova_size, + &uaudio_qdev->xfer_ring_list, size); + break; + case MEM_XFER_BUF: + iova = uaudio_get_iova(&uaudio_qdev->curr_xfer_buf_iova, + &uaudio_qdev->xfer_buf_iova_size, + &uaudio_qdev->xfer_buf_list, size); + break; + default: + dev_err(uaudio_qdev->data->dev, "unknown mem type %d\n", mtype); + } + + if (!iova || !map) + goto done; + + if (!sgt) + goto skip_sgt_map; + + iova_sg = iova; + for_each_sg(sgt->sgl, sg, sgt->nents, i) { + sg_len = PAGE_ALIGN(sg->offset + sg->length); + pa_sg = page_to_phys(sg_page(sg)); + ret = iommu_map(uaudio_qdev->data->domain, iova_sg, pa_sg, sg_len, + prot, GFP_KERNEL); + if (ret) { + uaudio_iommu_unmap(MEM_XFER_BUF, iova, size, total_len); + iova = 0; + goto done; + } + + iova_sg += sg_len; + total_len += sg_len; + } + + if (size != total_len) { + uaudio_iommu_unmap(MEM_XFER_BUF, iova, size, total_len); + iova = 0; + } + return iova; + +skip_sgt_map: + iommu_map(uaudio_qdev->data->domain, iova, pa, size, prot, GFP_KERNEL); + +done: + return iova; +} + +/* looks up alias, if any, for controller DT node and returns the index */ +static int usb_get_controller_id(struct usb_device *udev) +{ + if (udev->bus->sysdev && udev->bus->sysdev->of_node) + return of_alias_get_id(udev->bus->sysdev->of_node, "usb"); + + return -ENODEV; +} + +/** + * uaudio_dev_intf_cleanup() - cleanup transfer resources + * @udev: usb device + * @info: usb offloading interface + * + * Cleans up the transfer ring related resources which are assigned per + * endpoint from XHCI. This is invoked when the USB endpoints are no + * longer in use by the adsp. + * + */ +static void uaudio_dev_intf_cleanup(struct usb_device *udev, struct intf_info *info) +{ + uaudio_iommu_unmap(MEM_XFER_RING, info->data_xfer_ring_va, + info->data_xfer_ring_size, info->data_xfer_ring_size); + info->data_xfer_ring_va = 0; + info->data_xfer_ring_size = 0; + + uaudio_iommu_unmap(MEM_XFER_RING, info->sync_xfer_ring_va, + info->sync_xfer_ring_size, info->sync_xfer_ring_size); + info->sync_xfer_ring_va = 0; + info->sync_xfer_ring_size = 0; + + uaudio_iommu_unmap(MEM_XFER_BUF, info->xfer_buf_iova, info->xfer_buf_size, + info->xfer_buf_size); + info->xfer_buf_iova = 0; + + usb_free_coherent(udev, info->xfer_buf_size, info->xfer_buf_cpu, + info->xfer_buf_dma); + info->xfer_buf_size = 0; + info->xfer_buf_cpu = NULL; + info->xfer_buf_dma = 0; + + info->in_use = false; +} + +/** + * uaudio_event_ring_cleanup_free() - cleanup secondary event ring + * @dev: usb offload device + * + * Cleans up the secondary event ring that was requested. This will + * occur when the adsp is no longer transferring data on the USB bus + * across all endpoints. + * + */ +static void uaudio_event_ring_cleanup_free(struct uaudio_dev *dev) +{ + clear_bit(dev->chip->card->number, &uaudio_qdev->card_slot); + /* all audio devices are disconnected */ + if (!uaudio_qdev->card_slot) { + uaudio_iommu_unmap(MEM_EVENT_RING, IOVA_BASE, PAGE_SIZE, + PAGE_SIZE); + xhci_sideband_remove_interrupter(uadev[dev->chip->card->number].sb); + } +} + +static void uaudio_dev_cleanup(struct uaudio_dev *dev) +{ + int if_idx; + + if (!dev->udev) + return; + + /* free xfer buffer and unmap xfer ring and buf per interface */ + for (if_idx = 0; if_idx < dev->num_intf; if_idx++) { + if (!dev->info[if_idx].in_use) + continue; + uaudio_dev_intf_cleanup(dev->udev, &dev->info[if_idx]); + dev_dbg(uaudio_qdev->data->dev, + "release resources: intf# %d card# %d\n", + dev->info[if_idx].intf_num, dev->chip->card->number); + } + + dev->num_intf = 0; + + /* free interface info */ + kfree(dev->info); + dev->info = NULL; + uaudio_event_ring_cleanup_free(dev); + dev->udev = NULL; +} + +/** + * disable_audio_stream() - disable usb snd endpoints + * @subs: usb substream + * + * Closes the USB SND endpoints associated with the current audio stream + * used. This will decrement the USB SND endpoint opened reference count. + * + */ +static void disable_audio_stream(struct snd_usb_substream *subs) +{ + struct snd_usb_audio *chip = subs->stream->chip; + + snd_usb_hw_free(subs); + snd_usb_autosuspend(chip); +} + +/* QMI service disconnect handlers */ +static void qmi_stop_session(void) +{ + struct snd_usb_substream *subs; + struct usb_host_endpoint *ep; + struct snd_usb_audio *chip; + struct intf_info *info; + int pcm_card_num; + int if_idx; + int idx; + + mutex_lock(&qdev_mutex); + /* find all active intf for set alt 0 and cleanup usb audio dev */ + for (idx = 0; idx < SNDRV_CARDS; idx++) { + if (!atomic_read(&uadev[idx].in_use)) + continue; + + chip = uadev[idx].chip; + for (if_idx = 0; if_idx < uadev[idx].num_intf; if_idx++) { + if (!uadev[idx].info || !uadev[idx].info[if_idx].in_use) + continue; + info = &uadev[idx].info[if_idx]; + pcm_card_num = info->pcm_card_num; + subs = find_substream(pcm_card_num, info->pcm_dev_num, + info->direction); + if (!subs || !chip || atomic_read(&chip->shutdown)) { + dev_err(&subs->dev->dev, + "no sub for c#%u dev#%u dir%u\n", + info->pcm_card_num, + info->pcm_dev_num, + info->direction); + continue; + } + /* Release XHCI endpoints */ + if (info->data_ep_pipe) + ep = usb_pipe_endpoint(uadev[pcm_card_num].udev, + info->data_ep_pipe); + xhci_sideband_remove_endpoint(uadev[pcm_card_num].sb, ep); + + if (info->sync_ep_pipe) + ep = usb_pipe_endpoint(uadev[pcm_card_num].udev, + info->sync_ep_pipe); + xhci_sideband_remove_endpoint(uadev[pcm_card_num].sb, ep); + + disable_audio_stream(subs); + } + atomic_set(&uadev[idx].in_use, 0); + mutex_lock(&chip->mutex); + uaudio_dev_cleanup(&uadev[idx]); + mutex_unlock(&chip->mutex); + } + mutex_unlock(&qdev_mutex); +} + +/** + * uaudio_sideband_notifier() - xHCI sideband event handler + * @intf: USB interface handle + * @evt: xHCI sideband event type + * + * This callback is executed when the xHCI sideband encounters a sequence + * that requires the sideband clients to take action. An example, is when + * xHCI frees the transfer ring, so the client has to ensure that the + * offload path is halted. + * + */ +static int uaudio_sideband_notifier(struct usb_interface *intf, + struct xhci_sideband_event *evt) +{ + struct snd_usb_audio *chip; + struct uaudio_dev *dev; + int if_idx; + + if (!intf || !evt) + return 0; + + chip = usb_get_intfdata(intf); + + mutex_lock(&qdev_mutex); + mutex_lock(&chip->mutex); + + dev = &uadev[chip->card->number]; + + if (evt->type == XHCI_SIDEBAND_XFER_RING_FREE) { + unsigned int *ep = (unsigned int *) evt->evt_data; + + for (if_idx = 0; if_idx < dev->num_intf; if_idx++) { + if (dev->info[if_idx].data_ep_idx == *ep || + dev->info[if_idx].sync_ep_idx == *ep) + uaudio_send_disconnect_ind(chip); + } + } + + mutex_unlock(&qdev_mutex); + mutex_unlock(&chip->mutex); + + return 0; +} + +/** + * qmi_bye_cb() - qmi bye message callback + * @handle: QMI handle + * @node: id of the dying node + * + * This callback is invoked when the QMI bye control message is received + * from the QMI client. Handle the message accordingly by ensuring that + * the USB offload path is disabled and cleaned up. At this point, ADSP + * is not utilizing the USB bus. + * + */ +static void qmi_bye_cb(struct qmi_handle *handle, unsigned int node) +{ + struct uaudio_qmi_svc *svc = uaudio_svc; + + if (svc->uaudio_svc_hdl != handle) + return; + + if (svc->client_connected && svc->client_sq.sq_node == node) { + qmi_stop_session(); + + /* clear QMI client parameters to block further QMI messages */ + svc->client_sq.sq_node = 0; + svc->client_sq.sq_port = 0; + svc->client_sq.sq_family = 0; + svc->client_connected = false; + } +} + +/** + * qmi_svc_disconnect_cb() - qmi client disconnected + * @handle: QMI handle + * @node: id of the dying node + * @port: port of the dying client + * + * Invoked when the remote QMI client is disconnected. Handle this event + * the same way as when the QMI bye message is received. This will ensure + * the USB offloading path is disabled and cleaned up. + * + */ +static void qmi_svc_disconnect_cb(struct qmi_handle *handle, + unsigned int node, unsigned int port) +{ + struct uaudio_qmi_svc *svc; + + if (!uaudio_svc) + return; + + svc = uaudio_svc; + if (svc->uaudio_svc_hdl != handle) + return; + + if (svc->client_connected && svc->client_sq.sq_node == node && + svc->client_sq.sq_port == port) { + qmi_stop_session(); + + /* clear QMI client parameters to block further QMI messages */ + svc->client_sq.sq_node = 0; + svc->client_sq.sq_port = 0; + svc->client_sq.sq_family = 0; + svc->client_connected = false; + } +} + +/* QMI client callback handlers from QMI interface */ +static struct qmi_ops uaudio_svc_ops_options = { + .bye = qmi_bye_cb, + .del_client = qmi_svc_disconnect_cb, +}; + +/* kref release callback when all streams are disabled */ +static void uaudio_dev_release(struct kref *kref) +{ + struct uaudio_dev *dev = container_of(kref, struct uaudio_dev, kref); + + uaudio_event_ring_cleanup_free(dev); + atomic_set(&dev->in_use, 0); + wake_up(&dev->disconnect_wq); +} + +/** + * enable_audio_stream() - enable usb snd endpoints + * @subs: usb substream + * @pcm_format: pcm format requested + * @channels: number of channels + * @cur_rate: sample rate + * @datainterval: interval + * + * Opens all USB SND endpoints used for the data interface. This will increment + * the USB SND endpoint's opened count. Requests to keep the interface resumed + * until the audio stream is stopped. Will issue the USB set interface control + * message to enable the data interface. + * + */ +static int enable_audio_stream(struct snd_usb_substream *subs, + snd_pcm_format_t pcm_format, + unsigned int channels, unsigned int cur_rate, + int datainterval) +{ + struct snd_pcm_hw_params params; + struct snd_usb_audio *chip; + struct snd_interval *i; + struct snd_mask *m; + int ret; + + chip = subs->stream->chip; + + _snd_pcm_hw_params_any(¶ms); + + m = hw_param_mask(¶ms, SNDRV_PCM_HW_PARAM_FORMAT); + snd_mask_leave(m, pcm_format); + + i = hw_param_interval(¶ms, SNDRV_PCM_HW_PARAM_CHANNELS); + snd_interval_setinteger(i); + i->min = channels; + i->max = channels; + + i = hw_param_interval(¶ms, SNDRV_PCM_HW_PARAM_RATE); + snd_interval_setinteger(i); + i->min = cur_rate; + i->max = cur_rate; + + pm_runtime_barrier(&chip->intf[0]->dev); + snd_usb_autoresume(chip); + + ret = snd_usb_hw_params(subs, ¶ms); + if (ret < 0) + goto put_suspend; + + if (!atomic_read(&chip->shutdown)) { + ret = snd_usb_lock_shutdown(chip); + if (ret < 0) + goto detach_ep; + + if (subs->sync_endpoint) { + ret = snd_usb_endpoint_prepare(chip, subs->sync_endpoint); + if (ret < 0) + goto unlock; + } + + ret = snd_usb_endpoint_prepare(chip, subs->data_endpoint); + if (ret < 0) + goto unlock; + + snd_usb_unlock_shutdown(chip); + + dev_dbg(uaudio_qdev->data->dev, + "selected %s iface:%d altsetting:%d datainterval:%dus\n", + subs->direction ? "capture" : "playback", + subs->cur_audiofmt->iface, subs->cur_audiofmt->altsetting, + (1 << subs->cur_audiofmt->datainterval) * + (subs->dev->speed >= USB_SPEED_HIGH ? + BUS_INTERVAL_HIGHSPEED_AND_ABOVE : + BUS_INTERVAL_FULL_SPEED)); + } + + return 0; + +unlock: + snd_usb_unlock_shutdown(chip); + +detach_ep: + snd_usb_hw_free(subs); + +put_suspend: + snd_usb_autosuspend(chip); + + return ret; +} + +/** + * uaudio_transfer_buffer_setup() - fetch and populate xfer buffer params + * @subs: usb substream + * @xfer_buf: xfer buf to be allocated + * @xfer_buf_len: size of allocation + * @mem_info: QMI response info + * + * Allocates and maps the transfer buffers that will be utilized by the + * audio DSP. Will populate the information in the QMI response that is + * sent back to the stream enable request. + * + */ +static int uaudio_transfer_buffer_setup(struct snd_usb_substream *subs, + void **xfer_buf_cpu, u32 xfer_buf_len, + struct mem_info_v01 *mem_info) +{ + struct sg_table xfer_buf_sgt; + dma_addr_t xfer_buf_dma; + void *xfer_buf; + phys_addr_t xfer_buf_pa; + u32 len = xfer_buf_len; + bool dma_coherent; + dma_addr_t xfer_buf_dma_sysdev; + u32 remainder; + u32 mult; + int ret; + + dma_coherent = dev_is_dma_coherent(subs->dev->bus->sysdev); + + /* xfer buffer, multiple of 4K only */ + if (!len) + len = PAGE_SIZE; + + mult = len / PAGE_SIZE; + remainder = len % PAGE_SIZE; + len = mult * PAGE_SIZE; + len += remainder ? PAGE_SIZE : 0; + + if (len > MAX_XFER_BUFF_LEN) { + dev_err(uaudio_qdev->data->dev, + "req buf len %d > max buf len %lu, setting %lu\n", + len, MAX_XFER_BUFF_LEN, MAX_XFER_BUFF_LEN); + len = MAX_XFER_BUFF_LEN; + } + + /* get buffer mapped into subs->dev */ + xfer_buf = usb_alloc_coherent(subs->dev, len, GFP_KERNEL, &xfer_buf_dma); + if (!xfer_buf) + return -ENOMEM; + + /* Remapping is not possible if xfer_buf is outside of linear map */ + xfer_buf_pa = virt_to_phys(xfer_buf); + if (WARN_ON(!page_is_ram(PFN_DOWN(xfer_buf_pa)))) { + ret = -ENXIO; + goto unmap_sync; + } + dma_get_sgtable(subs->dev->bus->sysdev, &xfer_buf_sgt, xfer_buf, + xfer_buf_dma, len); + + /* map the physical buffer into sysdev as well */ + xfer_buf_dma_sysdev = uaudio_iommu_map(MEM_XFER_BUF, dma_coherent, + xfer_buf_pa, len, &xfer_buf_sgt); + if (!xfer_buf_dma_sysdev) { + ret = -ENOMEM; + goto unmap_sync; + } + + mem_info->dma = xfer_buf_dma; + mem_info->size = len; + mem_info->iova = PREPEND_SID_TO_IOVA(xfer_buf_dma_sysdev, uaudio_qdev->data->sid); + *xfer_buf_cpu = xfer_buf; + sg_free_table(&xfer_buf_sgt); + + return 0; + +unmap_sync: + usb_free_coherent(subs->dev, len, xfer_buf, xfer_buf_dma); + + return ret; +} + +/** + * uaudio_endpoint_setup() - fetch and populate endpoint params + * @subs: usb substream + * @endpoint: usb endpoint to add + * @card_num: uadev index + * @mem_info: QMI response info + * @ep_desc: QMI ep desc response field + * + * Initialize the USB endpoint being used for a particular USB + * stream. Will request XHCI sec intr to reserve the EP for + * offloading as well as populating the QMI response with the + * transfer ring parameters. + * + */ +static phys_addr_t +uaudio_endpoint_setup(struct snd_usb_substream *subs, + struct snd_usb_endpoint *endpoint, int card_num, + struct mem_info_v01 *mem_info, + struct usb_endpoint_descriptor_v01 *ep_desc) +{ + struct usb_host_endpoint *ep; + phys_addr_t tr_pa = 0; + struct sg_table *sgt; + bool dma_coherent; + unsigned long iova; + struct page *pg; + int ret = -ENODEV; + + dma_coherent = dev_is_dma_coherent(subs->dev->bus->sysdev); + + ep = usb_pipe_endpoint(subs->dev, endpoint->pipe); + if (!ep) { + dev_err(uaudio_qdev->data->dev, "data ep # %d context is null\n", + subs->data_endpoint->ep_num); + goto exit; + } + + memcpy(ep_desc, &ep->desc, sizeof(ep->desc)); + + ret = xhci_sideband_add_endpoint(uadev[card_num].sb, ep); + if (ret < 0) { + dev_err(&subs->dev->dev, + "failed to add data ep to sec intr\n"); + ret = -ENODEV; + goto exit; + } + + sgt = xhci_sideband_get_endpoint_buffer(uadev[card_num].sb, ep); + if (!sgt) { + dev_err(&subs->dev->dev, + "failed to get data ep ring address\n"); + ret = -ENODEV; + goto remove_ep; + } + + pg = sg_page(sgt->sgl); + tr_pa = page_to_phys(pg); + mem_info->dma = sg_dma_address(sgt->sgl); + sg_free_table(sgt); + + /* data transfer ring */ + iova = uaudio_iommu_map(MEM_XFER_RING, dma_coherent, tr_pa, + PAGE_SIZE, NULL); + if (!iova) { + ret = -ENOMEM; + goto clear_pa; + } + + mem_info->iova = PREPEND_SID_TO_IOVA(iova, uaudio_qdev->data->sid); + mem_info->size = PAGE_SIZE; + + return 0; + +clear_pa: + mem_info->dma = 0; +remove_ep: + xhci_sideband_remove_endpoint(uadev[card_num].sb, ep); +exit: + return ret; +} + +/** + * uaudio_event_ring_setup() - fetch and populate event ring params + * @subs: usb substream + * @card_num: uadev index + * @mem_info: QMI response info + * + * Register secondary interrupter to XHCI and fetch the event buffer info + * and populate the information into the QMI response. + * + */ +static int uaudio_event_ring_setup(struct snd_usb_substream *subs, + int card_num, struct mem_info_v01 *mem_info) +{ + struct sg_table *sgt; + phys_addr_t er_pa; + bool dma_coherent; + unsigned long iova; + struct page *pg; + int ret; + + dma_coherent = dev_is_dma_coherent(subs->dev->bus->sysdev); + er_pa = 0; + + /* event ring */ + ret = xhci_sideband_create_interrupter(uadev[card_num].sb, 1, false, + 0, uaudio_qdev->data->intr_num); + if (ret < 0) { + dev_err(&subs->dev->dev, "failed to fetch interrupter\n"); + goto exit; + } + + sgt = xhci_sideband_get_event_buffer(uadev[card_num].sb); + if (!sgt) { + dev_err(&subs->dev->dev, + "failed to get event ring address\n"); + ret = -ENODEV; + goto remove_interrupter; + } + + pg = sg_page(sgt->sgl); + er_pa = page_to_phys(pg); + mem_info->dma = sg_dma_address(sgt->sgl); + sg_free_table(sgt); + + iova = uaudio_iommu_map(MEM_EVENT_RING, dma_coherent, er_pa, + PAGE_SIZE, NULL); + if (!iova) { + ret = -ENOMEM; + goto clear_pa; + } + + mem_info->iova = PREPEND_SID_TO_IOVA(iova, uaudio_qdev->data->sid); + mem_info->size = PAGE_SIZE; + + return 0; + +clear_pa: + mem_info->dma = 0; +remove_interrupter: + xhci_sideband_remove_interrupter(uadev[card_num].sb); +exit: + return ret; +} + +/** + * uaudio_populate_uac_desc() - parse UAC parameters and populate QMI resp + * @subs: usb substream + * @resp: QMI response buffer + * + * Parses information specified within UAC descriptors which explain the + * sample parameters that the device expects. This information is populated + * to the QMI response sent back to the audio DSP. + * + */ +static int uaudio_populate_uac_desc(struct snd_usb_substream *subs, + struct qmi_uaudio_stream_resp_msg_v01 *resp) +{ + struct usb_interface_descriptor *altsd; + struct usb_host_interface *alts; + struct usb_interface *iface; + int protocol; + + iface = usb_ifnum_to_if(subs->dev, subs->cur_audiofmt->iface); + if (!iface) { + dev_err(&subs->dev->dev, "interface # %d does not exist\n", + subs->cur_audiofmt->iface); + return -ENODEV; + } + + alts = &iface->altsetting[subs->cur_audiofmt->altset_idx]; + altsd = get_iface_desc(alts); + protocol = altsd->bInterfaceProtocol; + + if (protocol == UAC_VERSION_1) { + struct uac1_as_header_descriptor *as; + + as = snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, + UAC_AS_GENERAL); + if (!as) { + dev_err(&subs->dev->dev, + "%u:%d : no UAC_AS_GENERAL desc\n", + subs->cur_audiofmt->iface, + subs->cur_audiofmt->altset_idx); + return -ENODEV; + } + + resp->data_path_delay = as->bDelay; + resp->data_path_delay_valid = 1; + + resp->usb_audio_subslot_size = subs->cur_audiofmt->fmt_sz; + resp->usb_audio_subslot_size_valid = 1; + + resp->usb_audio_spec_revision = le16_to_cpu((__force __le16)0x0100); + resp->usb_audio_spec_revision_valid = 1; + } else if (protocol == UAC_VERSION_2) { + resp->usb_audio_subslot_size = subs->cur_audiofmt->fmt_sz; + resp->usb_audio_subslot_size_valid = 1; + + resp->usb_audio_spec_revision = le16_to_cpu((__force __le16)0x0200); + resp->usb_audio_spec_revision_valid = 1; + } else if (protocol == UAC_VERSION_3) { + if (iface->intf_assoc->bFunctionSubClass == + UAC3_FUNCTION_SUBCLASS_FULL_ADC_3_0) { + dev_err(&subs->dev->dev, + "full adc is not supported\n"); + return -EINVAL; + } + + switch (le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize)) { + case UAC3_BADD_EP_MAXPSIZE_SYNC_MONO_16: + case UAC3_BADD_EP_MAXPSIZE_SYNC_STEREO_16: + case UAC3_BADD_EP_MAXPSIZE_ASYNC_MONO_16: + case UAC3_BADD_EP_MAXPSIZE_ASYNC_STEREO_16: { + resp->usb_audio_subslot_size = 0x2; + break; + } + + case UAC3_BADD_EP_MAXPSIZE_SYNC_MONO_24: + case UAC3_BADD_EP_MAXPSIZE_SYNC_STEREO_24: + case UAC3_BADD_EP_MAXPSIZE_ASYNC_MONO_24: + case UAC3_BADD_EP_MAXPSIZE_ASYNC_STEREO_24: { + resp->usb_audio_subslot_size = 0x3; + break; + } + + default: + dev_err(&subs->dev->dev, + "%d: %u: Invalid wMaxPacketSize\n", + subs->cur_audiofmt->iface, + subs->cur_audiofmt->altset_idx); + return -EINVAL; + } + resp->usb_audio_subslot_size_valid = 1; + } else { + dev_err(&subs->dev->dev, "unknown protocol version %x\n", + protocol); + return -ENODEV; + } + + memcpy(&resp->std_as_opr_intf_desc, &alts->desc, sizeof(alts->desc)); + + return 0; +} + +/** + * prepare_qmi_response() - prepare stream enable response + * @subs: usb substream + * @req_msg: QMI request message + * @resp: QMI response buffer + * @info_idx: usb interface array index + * + * Prepares the QMI response for a USB QMI stream enable request. Will parse + * out the parameters within the stream enable request, in order to match + * requested audio profile to the ones exposed by the USB device connected. + * + * In addition, will fetch the XHCI transfer resources needed for the handoff to + * happen. This includes, transfer ring and buffer addresses and secondary event + * ring address. These parameters will be communicated as part of the USB QMI + * stream enable response. + * + */ +static int prepare_qmi_response(struct snd_usb_substream *subs, + struct qmi_uaudio_stream_req_msg_v01 *req_msg, + struct qmi_uaudio_stream_resp_msg_v01 *resp, + int info_idx) +{ + struct q6usb_offload *data; + int pcm_dev_num; + int card_num; + void *xfer_buf_cpu; + int ret; + + pcm_dev_num = (req_msg->usb_token & QMI_STREAM_REQ_DEV_NUM_MASK) >> 8; + card_num = (req_msg->usb_token & QMI_STREAM_REQ_CARD_NUM_MASK) >> 16; + + if (!uadev[card_num].ctrl_intf) { + dev_err(&subs->dev->dev, "audio ctrl intf info not cached\n"); + ret = -ENODEV; + goto err; + } + + ret = uaudio_populate_uac_desc(subs, resp); + if (ret < 0) + goto err; + + resp->slot_id = subs->dev->slot_id; + resp->slot_id_valid = 1; + + data = snd_soc_usb_find_priv_data(uaudio_qdev->auxdev->dev.parent); + if (!data) + goto err; + + uaudio_qdev->data = data; + + resp->std_as_opr_intf_desc_valid = 1; + ret = uaudio_endpoint_setup(subs, subs->data_endpoint, card_num, + &resp->xhci_mem_info.tr_data, + &resp->std_as_data_ep_desc); + if (ret < 0) + goto err; + + resp->std_as_data_ep_desc_valid = 1; + + if (subs->sync_endpoint) { + ret = uaudio_endpoint_setup(subs, subs->sync_endpoint, card_num, + &resp->xhci_mem_info.tr_sync, + &resp->std_as_sync_ep_desc); + if (ret < 0) + goto drop_data_ep; + + resp->std_as_sync_ep_desc_valid = 1; + } + + resp->interrupter_num_valid = 1; + resp->controller_num_valid = 0; + ret = usb_get_controller_id(subs->dev); + if (ret >= 0) { + resp->controller_num = ret; + resp->controller_num_valid = 1; + } + + /* event ring */ + ret = uaudio_event_ring_setup(subs, card_num, + &resp->xhci_mem_info.evt_ring); + if (ret < 0) + goto drop_sync_ep; + + uaudio_qdev->er_mapped = true; + resp->interrupter_num = xhci_sideband_interrupter_id(uadev[card_num].sb); + + resp->speed_info = get_speed_info(subs->dev->speed); + if (resp->speed_info == USB_QMI_DEVICE_SPEED_INVALID_V01) { + ret = -ENODEV; + goto free_sec_ring; + } + + resp->speed_info_valid = 1; + + ret = uaudio_transfer_buffer_setup(subs, &xfer_buf_cpu, req_msg->xfer_buff_size, + &resp->xhci_mem_info.xfer_buff); + if (ret < 0) { + ret = -ENOMEM; + goto free_sec_ring; + } + + resp->xhci_mem_info_valid = 1; + + if (!atomic_read(&uadev[card_num].in_use)) { + kref_init(&uadev[card_num].kref); + init_waitqueue_head(&uadev[card_num].disconnect_wq); + uadev[card_num].num_intf = + subs->dev->config->desc.bNumInterfaces; + uadev[card_num].info = kcalloc(uadev[card_num].num_intf, + sizeof(struct intf_info), + GFP_KERNEL); + if (!uadev[card_num].info) { + ret = -ENOMEM; + goto unmap_er; + } + uadev[card_num].udev = subs->dev; + atomic_set(&uadev[card_num].in_use, 1); + } else { + kref_get(&uadev[card_num].kref); + } + + uadev[card_num].usb_core_id = resp->controller_num; + + /* cache intf specific info to use it for unmap and free xfer buf */ + uadev[card_num].info[info_idx].data_xfer_ring_va = + IOVA_MASK(resp->xhci_mem_info.tr_data.iova); + uadev[card_num].info[info_idx].data_xfer_ring_size = PAGE_SIZE; + uadev[card_num].info[info_idx].sync_xfer_ring_va = + IOVA_MASK(resp->xhci_mem_info.tr_sync.iova); + uadev[card_num].info[info_idx].sync_xfer_ring_size = PAGE_SIZE; + uadev[card_num].info[info_idx].xfer_buf_iova = + IOVA_MASK(resp->xhci_mem_info.xfer_buff.iova); + uadev[card_num].info[info_idx].xfer_buf_dma = + resp->xhci_mem_info.xfer_buff.dma; + uadev[card_num].info[info_idx].xfer_buf_size = + resp->xhci_mem_info.xfer_buff.size; + uadev[card_num].info[info_idx].data_ep_pipe = subs->data_endpoint ? + subs->data_endpoint->pipe : 0; + uadev[card_num].info[info_idx].sync_ep_pipe = subs->sync_endpoint ? + subs->sync_endpoint->pipe : 0; + uadev[card_num].info[info_idx].data_ep_idx = subs->data_endpoint ? + subs->data_endpoint->ep_num : 0; + uadev[card_num].info[info_idx].sync_ep_idx = subs->sync_endpoint ? + subs->sync_endpoint->ep_num : 0; + uadev[card_num].info[info_idx].xfer_buf_cpu = xfer_buf_cpu; + uadev[card_num].info[info_idx].pcm_card_num = card_num; + uadev[card_num].info[info_idx].pcm_dev_num = pcm_dev_num; + uadev[card_num].info[info_idx].direction = subs->direction; + uadev[card_num].info[info_idx].intf_num = subs->cur_audiofmt->iface; + uadev[card_num].info[info_idx].in_use = true; + + set_bit(card_num, &uaudio_qdev->card_slot); + + return 0; + +unmap_er: + uaudio_iommu_unmap(MEM_EVENT_RING, IOVA_BASE, PAGE_SIZE, PAGE_SIZE); +free_sec_ring: + xhci_sideband_remove_interrupter(uadev[card_num].sb); +drop_sync_ep: + if (subs->sync_endpoint) { + uaudio_iommu_unmap(MEM_XFER_RING, + IOVA_MASK(resp->xhci_mem_info.tr_sync.iova), + PAGE_SIZE, PAGE_SIZE); + xhci_sideband_remove_endpoint(uadev[card_num].sb, + usb_pipe_endpoint(subs->dev, subs->sync_endpoint->pipe)); + } +drop_data_ep: + uaudio_iommu_unmap(MEM_XFER_RING, IOVA_MASK(resp->xhci_mem_info.tr_data.iova), + PAGE_SIZE, PAGE_SIZE); + xhci_sideband_remove_endpoint(uadev[card_num].sb, + usb_pipe_endpoint(subs->dev, subs->data_endpoint->pipe)); + +err: + return ret; +} + +/** + * handle_uaudio_stream_req() - handle stream enable/disable request + * @handle: QMI client handle + * @sq: qrtr socket + * @txn: QMI transaction context + * @decoded_msg: decoded QMI message + * + * Main handler for the QMI stream enable/disable requests. This executes the + * corresponding enable/disable stream apis, respectively. + * + */ +static void handle_uaudio_stream_req(struct qmi_handle *handle, + struct sockaddr_qrtr *sq, + struct qmi_txn *txn, + const void *decoded_msg) +{ + struct qmi_uaudio_stream_req_msg_v01 *req_msg; + struct qmi_uaudio_stream_resp_msg_v01 resp = {{0}, 0}; + struct uaudio_qmi_svc *svc = uaudio_svc; + struct snd_usb_audio *chip = NULL; + struct snd_usb_substream *subs; + struct usb_host_endpoint *ep; + int datainterval = -EINVAL; + int info_idx = -EINVAL; + struct intf_info *info; + u8 pcm_card_num; + u8 pcm_dev_num; + u8 direction; + int ret = 0; + + if (!svc->client_connected) { + svc->client_sq = *sq; + svc->client_connected = true; + } + + mutex_lock(&qdev_mutex); + req_msg = (struct qmi_uaudio_stream_req_msg_v01 *)decoded_msg; + if (!req_msg->audio_format_valid || !req_msg->bit_rate_valid || + !req_msg->number_of_ch_valid || !req_msg->xfer_buff_size_valid) { + ret = -EINVAL; + goto response; + } + + if (!uaudio_qdev) { + ret = -EINVAL; + goto response; + } + + direction = (req_msg->usb_token & QMI_STREAM_REQ_DIRECTION); + pcm_dev_num = (req_msg->usb_token & QMI_STREAM_REQ_DEV_NUM_MASK) >> 8; + pcm_card_num = (req_msg->usb_token & QMI_STREAM_REQ_CARD_NUM_MASK) >> 16; + if (pcm_card_num >= SNDRV_CARDS) { + ret = -EINVAL; + goto response; + } + + if (req_msg->audio_format > USB_QMI_PCM_FORMAT_U32_BE) { + ret = -EINVAL; + goto response; + } + + subs = find_substream(pcm_card_num, pcm_dev_num, direction); + chip = uadev[pcm_card_num].chip; + if (!subs || !chip || atomic_read(&chip->shutdown)) { + ret = -ENODEV; + goto response; + } + + info_idx = info_idx_from_ifnum(pcm_card_num, subs->cur_audiofmt ? + subs->cur_audiofmt->iface : -1, req_msg->enable); + if (atomic_read(&chip->shutdown) || !subs->stream || !subs->stream->pcm || + !subs->stream->chip) { + ret = -ENODEV; + goto response; + } + + mutex_lock(&chip->mutex); + if (req_msg->enable) { + if (info_idx < 0 || chip->system_suspend || subs->opened) { + ret = -EBUSY; + mutex_unlock(&chip->mutex); + + goto response; + } + subs->opened = 1; + } + mutex_unlock(&chip->mutex); + + if (req_msg->service_interval_valid) { + ret = get_data_interval_from_si(subs, + req_msg->service_interval); + if (ret == -EINVAL) + goto response; + + datainterval = ret; + } + + uadev[pcm_card_num].ctrl_intf = chip->ctrl_intf; + + if (req_msg->enable) { + ret = enable_audio_stream(subs, + map_pcm_format(req_msg->audio_format), + req_msg->number_of_ch, req_msg->bit_rate, + datainterval); + + if (!ret) + ret = prepare_qmi_response(subs, req_msg, &resp, + info_idx); + if (ret < 0) { + mutex_lock(&chip->mutex); + subs->opened = 0; + mutex_unlock(&chip->mutex); + } + } else { + info = &uadev[pcm_card_num].info[info_idx]; + if (info->data_ep_pipe) { + ep = usb_pipe_endpoint(uadev[pcm_card_num].udev, + info->data_ep_pipe); + if (ep) { + xhci_sideband_stop_endpoint(uadev[pcm_card_num].sb, + ep); + xhci_sideband_remove_endpoint(uadev[pcm_card_num].sb, + ep); + } + + info->data_ep_pipe = 0; + } + + if (info->sync_ep_pipe) { + ep = usb_pipe_endpoint(uadev[pcm_card_num].udev, + info->sync_ep_pipe); + if (ep) { + xhci_sideband_stop_endpoint(uadev[pcm_card_num].sb, + ep); + xhci_sideband_remove_endpoint(uadev[pcm_card_num].sb, + ep); + } + + info->sync_ep_pipe = 0; + } + + disable_audio_stream(subs); + mutex_lock(&chip->mutex); + subs->opened = 0; + mutex_unlock(&chip->mutex); + } + +response: + if (!req_msg->enable && ret != -EINVAL && ret != -ENODEV) { + mutex_lock(&chip->mutex); + if (info_idx >= 0) { + info = &uadev[pcm_card_num].info[info_idx]; + uaudio_dev_intf_cleanup(uadev[pcm_card_num].udev, + info); + } + if (atomic_read(&uadev[pcm_card_num].in_use)) + kref_put(&uadev[pcm_card_num].kref, + uaudio_dev_release); + mutex_unlock(&chip->mutex); + } + mutex_unlock(&qdev_mutex); + + resp.usb_token = req_msg->usb_token; + resp.usb_token_valid = 1; + resp.internal_status = ret; + resp.internal_status_valid = 1; + resp.status = ret ? USB_QMI_STREAM_REQ_FAILURE_V01 : ret; + resp.status_valid = 1; + ret = qmi_send_response(svc->uaudio_svc_hdl, sq, txn, + QMI_UAUDIO_STREAM_RESP_V01, + QMI_UAUDIO_STREAM_RESP_MSG_V01_MAX_MSG_LEN, + qmi_uaudio_stream_resp_msg_v01_ei, &resp); +} + +static struct qmi_msg_handler uaudio_stream_req_handlers = { + .type = QMI_REQUEST, + .msg_id = QMI_UAUDIO_STREAM_REQ_V01, + .ei = qmi_uaudio_stream_req_msg_v01_ei, + .decoded_size = QMI_UAUDIO_STREAM_REQ_MSG_V01_MAX_MSG_LEN, + .fn = handle_uaudio_stream_req, +}; + +/** + * qc_usb_audio_offload_init_qmi_dev() - initializes qmi dev + * + * Initializes the USB qdev, which is used to carry information pertaining to + * the offloading resources. This device is freed only when there are no longer + * any offloading candidates. (i.e, when all audio devices are disconnected) + * + */ +static int qc_usb_audio_offload_init_qmi_dev(void) +{ + uaudio_qdev = kzalloc(sizeof(*uaudio_qdev), GFP_KERNEL); + if (!uaudio_qdev) + return -ENOMEM; + + /* initialize xfer ring and xfer buf iova list */ + INIT_LIST_HEAD(&uaudio_qdev->xfer_ring_list); + uaudio_qdev->curr_xfer_ring_iova = IOVA_XFER_RING_BASE; + uaudio_qdev->xfer_ring_iova_size = + IOVA_XFER_RING_MAX - IOVA_XFER_RING_BASE; + + INIT_LIST_HEAD(&uaudio_qdev->xfer_buf_list); + uaudio_qdev->curr_xfer_buf_iova = IOVA_XFER_BUF_BASE; + uaudio_qdev->xfer_buf_iova_size = + IOVA_XFER_BUF_MAX - IOVA_XFER_BUF_BASE; + + return 0; +} + +/* Populates ppcm_idx array with supported PCM indexes */ +static int qc_usb_audio_offload_fill_avail_pcms(struct snd_usb_audio *chip, + struct snd_soc_usb_device *sdev) +{ + struct snd_usb_stream *as; + struct snd_usb_substream *subs; + int idx = 0; + + list_for_each_entry(as, &chip->pcm_list, list) { + subs = &as->substream[SNDRV_PCM_STREAM_PLAYBACK]; + if (subs->ep_num) { + sdev->ppcm_idx[idx] = as->pcm->device; + idx++; + } + /* + * Break if the current index exceeds the number of possible + * playback streams counted from the UAC descriptors. + */ + if (idx >= sdev->num_playback) + break; + } + + return -1; +} + +/** + * qc_usb_audio_offload_probe() - platform op connect handler + * @chip: USB SND device + * + * Platform connect handler when a USB SND device is detected. Will + * notify SOC USB about the connection to enable the USB ASoC backend + * and populate internal USB chip array. + * + */ +static void qc_usb_audio_offload_probe(struct snd_usb_audio *chip) +{ + struct usb_interface *intf = chip->intf[chip->num_interfaces - 1]; + struct usb_interface_descriptor *altsd; + struct usb_host_interface *alts; + struct snd_soc_usb_device *sdev; + struct xhci_sideband *sb; + + /* + * If there is no priv_data, or no playback paths, the connected + * device doesn't support offloading. Avoid populating entries for + * this device. + */ + if (!snd_soc_usb_find_priv_data(uaudio_qdev->auxdev->dev.parent) || + !usb_qmi_get_pcm_num(chip, 0)) + return; + + mutex_lock(&qdev_mutex); + mutex_lock(&chip->mutex); + if (!uadev[chip->card->number].chip) { + sdev = kzalloc(sizeof(*sdev), GFP_KERNEL); + if (!sdev) + goto exit; + + sb = xhci_sideband_register(intf, XHCI_SIDEBAND_VENDOR, + uaudio_sideband_notifier); + if (!sb) + goto free_sdev; + } else { + sb = uadev[chip->card->number].sb; + sdev = uadev[chip->card->number].sdev; + } + + uadev[chip->card->number].sb = sb; + uadev[chip->card->number].chip = chip; + uadev[chip->card->number].sdev = sdev; + + alts = &intf->altsetting[0]; + altsd = get_iface_desc(alts); + + /* Wait until all PCM devices are populated before notifying soc-usb */ + if (altsd->bInterfaceNumber == chip->last_iface) { + sdev->num_playback = usb_qmi_get_pcm_num(chip, 0); + + /* + * Allocate playback pcm index array based on number of possible + * playback paths within the UAC descriptors. + */ + sdev->ppcm_idx = kcalloc(sdev->num_playback, sizeof(unsigned int), + GFP_KERNEL); + if (!sdev->ppcm_idx) + goto unreg_xhci; + + qc_usb_audio_offload_fill_avail_pcms(chip, sdev); + sdev->card_idx = chip->card->number; + sdev->chip_idx = chip->index; + + snd_usb_offload_create_ctl(chip, uaudio_qdev->auxdev->dev.parent); + snd_soc_usb_connect(uaudio_qdev->auxdev->dev.parent, sdev); + } + + mutex_unlock(&chip->mutex); + mutex_unlock(&qdev_mutex); + + return; + +unreg_xhci: + xhci_sideband_unregister(sb); + uadev[chip->card->number].sb = NULL; +free_sdev: + kfree(sdev); + uadev[chip->card->number].sdev = NULL; + uadev[chip->card->number].chip = NULL; +exit: + mutex_unlock(&chip->mutex); + mutex_unlock(&qdev_mutex); +} + +/** + * qc_usb_audio_cleanup_qmi_dev() - release qmi device + * + * Frees the USB qdev. Only occurs when there are no longer any potential + * devices that can utilize USB audio offloading. + * + */ +static void qc_usb_audio_cleanup_qmi_dev(void) +{ + kfree(uaudio_qdev); + uaudio_qdev = NULL; +} + +/** + * qc_usb_audio_offload_disconnect() - platform op disconnect handler + * @chip: USB SND device + * + * Platform disconnect handler. Will ensure that any pending stream is + * halted by issuing a QMI disconnect indication packet to the adsp. + * + */ +static void qc_usb_audio_offload_disconnect(struct snd_usb_audio *chip) +{ + struct uaudio_dev *dev; + int card_num; + + if (!chip) + return; + + card_num = chip->card->number; + if (card_num >= SNDRV_CARDS) + return; + + mutex_lock(&qdev_mutex); + mutex_lock(&chip->mutex); + dev = &uadev[card_num]; + + /* Device has already been cleaned up, or never populated */ + if (!dev->chip) { + mutex_unlock(&qdev_mutex); + mutex_unlock(&chip->mutex); + return; + } + + /* cleaned up already */ + if (!dev->udev) + goto done; + + uaudio_send_disconnect_ind(chip); + uaudio_dev_cleanup(dev); +done: + /* + * If num_interfaces == 1, the last USB SND interface is being removed. + * This is to accommodate for devices w/ multiple UAC functions. + */ + if (chip->num_interfaces == 1) { + snd_soc_usb_disconnect(uaudio_qdev->auxdev->dev.parent, dev->sdev); + xhci_sideband_unregister(dev->sb); + dev->chip = NULL; + kfree(dev->sdev->ppcm_idx); + kfree(dev->sdev); + dev->sdev = NULL; + } + mutex_unlock(&chip->mutex); + + mutex_unlock(&qdev_mutex); +} + +/** + * qc_usb_audio_offload_suspend() - USB offload PM suspend handler + * @intf: USB interface + * @message: suspend type + * + * PM suspend handler to ensure that the USB offloading driver is able to stop + * any pending traffic, so that the bus can be suspended. + * + */ +static void qc_usb_audio_offload_suspend(struct usb_interface *intf, + pm_message_t message) +{ + struct snd_usb_audio *chip = usb_get_intfdata(intf); + int card_num; + + if (!chip) + return; + + card_num = chip->card->number; + if (card_num >= SNDRV_CARDS) + return; + + mutex_lock(&qdev_mutex); + mutex_lock(&chip->mutex); + + uaudio_send_disconnect_ind(chip); + + mutex_unlock(&qdev_mutex); + mutex_unlock(&chip->mutex); +} + +static struct snd_usb_platform_ops offload_ops = { + .connect_cb = qc_usb_audio_offload_probe, + .disconnect_cb = qc_usb_audio_offload_disconnect, + .suspend_cb = qc_usb_audio_offload_suspend, +}; + +static int qc_usb_audio_probe(struct auxiliary_device *auxdev, + const struct auxiliary_device_id *id) + +{ + struct uaudio_qmi_svc *svc; + int ret; + + svc = kzalloc(sizeof(*svc), GFP_KERNEL); + if (!svc) + return -ENOMEM; + + svc->uaudio_svc_hdl = kzalloc(sizeof(*svc->uaudio_svc_hdl), GFP_KERNEL); + if (!svc->uaudio_svc_hdl) { + ret = -ENOMEM; + goto free_svc; + } + + ret = qmi_handle_init(svc->uaudio_svc_hdl, + QMI_UAUDIO_STREAM_REQ_MSG_V01_MAX_MSG_LEN, + &uaudio_svc_ops_options, + &uaudio_stream_req_handlers); + ret = qmi_add_server(svc->uaudio_svc_hdl, UAUDIO_STREAM_SERVICE_ID_V01, + UAUDIO_STREAM_SERVICE_VERS_V01, 0); + + uaudio_svc = svc; + + qc_usb_audio_offload_init_qmi_dev(); + uaudio_qdev->auxdev = auxdev; + + ret = snd_usb_register_platform_ops(&offload_ops); + if (ret < 0) + goto release_qmi; + + snd_usb_rediscover_devices(); + + return 0; + +release_qmi: + qc_usb_audio_cleanup_qmi_dev(); + qmi_handle_release(svc->uaudio_svc_hdl); +free_svc: + kfree(svc); + + return ret; +} + +static void qc_usb_audio_remove(struct auxiliary_device *auxdev) +{ + struct uaudio_qmi_svc *svc = uaudio_svc; + int idx; + + /* + * Remove all connected devices after unregistering ops, to ensure + * that no further connect events will occur. The disconnect routine + * will issue the QMI disconnect indication, which results in the + * external DSP to stop issuing transfers. + */ + snd_usb_unregister_platform_ops(); + for (idx = 0; idx < SNDRV_CARDS; idx++) + qc_usb_audio_offload_disconnect(uadev[idx].chip); + + qc_usb_audio_cleanup_qmi_dev(); + + qmi_handle_release(svc->uaudio_svc_hdl); + kfree(svc); + uaudio_svc = NULL; +} + +static const struct auxiliary_device_id qc_usb_audio_table[] = { + { .name = "q6usb.qc-usb-audio-offload" }, + {}, +}; +MODULE_DEVICE_TABLE(auxiliary, qc_usb_audio_table); + +static struct auxiliary_driver qc_usb_audio_offload_drv = { + .name = "qc-usb-audio-offload", + .id_table = qc_usb_audio_table, + .probe = qc_usb_audio_probe, + .remove = qc_usb_audio_remove, +}; +module_auxiliary_driver(qc_usb_audio_offload_drv); + +MODULE_DESCRIPTION("QC USB Audio Offloading"); +MODULE_LICENSE("GPL"); diff --git a/sound/usb/qcom/usb_audio_qmi_v01.c b/sound/usb/qcom/usb_audio_qmi_v01.c new file mode 100644 index 000000000000..502857612277 --- /dev/null +++ b/sound/usb/qcom/usb_audio_qmi_v01.c @@ -0,0 +1,863 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2022-2025 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include <linux/soc/qcom/qmi.h> + +#include "usb_audio_qmi_v01.h" + +static const struct qmi_elem_info mem_info_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_8_BYTE, + .elem_len = 1, + .elem_size = sizeof(u64), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct mem_info_v01, iova), + }, + { + .data_type = QMI_UNSIGNED_8_BYTE, + .elem_len = 1, + .elem_size = sizeof(u64), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct mem_info_v01, dma), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct mem_info_v01, size), + }, + { + .data_type = QMI_EOTI, + .array_type = NO_ARRAY, + .tlv_type = QMI_COMMON_TLV_TYPE, + }, +}; + +static const struct qmi_elem_info apps_mem_info_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct mem_info_v01), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct apps_mem_info_v01, evt_ring), + .ei_array = mem_info_v01_ei, + }, + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct mem_info_v01), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct apps_mem_info_v01, tr_data), + .ei_array = mem_info_v01_ei, + }, + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct mem_info_v01), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct apps_mem_info_v01, tr_sync), + .ei_array = mem_info_v01_ei, + }, + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct mem_info_v01), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct apps_mem_info_v01, xfer_buff), + .ei_array = mem_info_v01_ei, + }, + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct mem_info_v01), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct apps_mem_info_v01, dcba), + .ei_array = mem_info_v01_ei, + }, + { + .data_type = QMI_EOTI, + .array_type = NO_ARRAY, + .tlv_type = QMI_COMMON_TLV_TYPE, + }, +}; + +static const struct qmi_elem_info usb_endpoint_descriptor_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct usb_endpoint_descriptor_v01, + bLength), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct usb_endpoint_descriptor_v01, + bDescriptorType), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct usb_endpoint_descriptor_v01, + bEndpointAddress), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct usb_endpoint_descriptor_v01, + bmAttributes), + }, + { + .data_type = QMI_UNSIGNED_2_BYTE, + .elem_len = 1, + .elem_size = sizeof(u16), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct usb_endpoint_descriptor_v01, + wMaxPacketSize), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct usb_endpoint_descriptor_v01, + bInterval), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct usb_endpoint_descriptor_v01, + bRefresh), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct usb_endpoint_descriptor_v01, + bSynchAddress), + }, + { + .data_type = QMI_EOTI, + .array_type = NO_ARRAY, + .tlv_type = QMI_COMMON_TLV_TYPE, + }, +}; + +static const struct qmi_elem_info usb_interface_descriptor_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct usb_interface_descriptor_v01, + bLength), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct usb_interface_descriptor_v01, + bDescriptorType), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct usb_interface_descriptor_v01, + bInterfaceNumber), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct usb_interface_descriptor_v01, + bAlternateSetting), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct usb_interface_descriptor_v01, + bNumEndpoints), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct usb_interface_descriptor_v01, + bInterfaceClass), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct usb_interface_descriptor_v01, + bInterfaceSubClass), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct usb_interface_descriptor_v01, + bInterfaceProtocol), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct usb_interface_descriptor_v01, + iInterface), + }, + { + .data_type = QMI_EOTI, + .array_type = NO_ARRAY, + .tlv_type = QMI_COMMON_TLV_TYPE, + }, +}; + +const struct qmi_elem_info qmi_uaudio_stream_req_msg_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct qmi_uaudio_stream_req_msg_v01, + enable), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct qmi_uaudio_stream_req_msg_v01, + usb_token), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct qmi_uaudio_stream_req_msg_v01, + audio_format_valid), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct qmi_uaudio_stream_req_msg_v01, + audio_format), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof(struct qmi_uaudio_stream_req_msg_v01, + number_of_ch_valid), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof(struct qmi_uaudio_stream_req_msg_v01, + number_of_ch), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x12, + .offset = offsetof(struct qmi_uaudio_stream_req_msg_v01, + bit_rate_valid), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0x12, + .offset = offsetof(struct qmi_uaudio_stream_req_msg_v01, + bit_rate), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x13, + .offset = offsetof(struct qmi_uaudio_stream_req_msg_v01, + xfer_buff_size_valid), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0x13, + .offset = offsetof(struct qmi_uaudio_stream_req_msg_v01, + xfer_buff_size), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x14, + .offset = offsetof(struct qmi_uaudio_stream_req_msg_v01, + service_interval_valid), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0x14, + .offset = offsetof(struct qmi_uaudio_stream_req_msg_v01, + service_interval), + }, + { + .data_type = QMI_EOTI, + .array_type = NO_ARRAY, + .tlv_type = QMI_COMMON_TLV_TYPE, + }, +}; + +const struct qmi_elem_info qmi_uaudio_stream_resp_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct qmi_uaudio_stream_resp_msg_v01, + resp), + .ei_array = qmi_response_type_v01_ei, + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct qmi_uaudio_stream_resp_msg_v01, + status_valid), + }, + { + .data_type = QMI_SIGNED_4_BYTE_ENUM, + .elem_len = 1, + .elem_size = sizeof(enum usb_qmi_audio_stream_status_enum_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct qmi_uaudio_stream_resp_msg_v01, + status), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof(struct qmi_uaudio_stream_resp_msg_v01, + internal_status_valid), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof(struct qmi_uaudio_stream_resp_msg_v01, + internal_status), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x12, + .offset = offsetof(struct qmi_uaudio_stream_resp_msg_v01, + slot_id_valid), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0x12, + .offset = offsetof(struct qmi_uaudio_stream_resp_msg_v01, + slot_id), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x13, + .offset = offsetof(struct qmi_uaudio_stream_resp_msg_v01, + usb_token_valid), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0x13, + .offset = offsetof(struct qmi_uaudio_stream_resp_msg_v01, + usb_token), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x14, + .offset = offsetof(struct qmi_uaudio_stream_resp_msg_v01, + std_as_opr_intf_desc_valid), + }, + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct usb_interface_descriptor_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x14, + .offset = offsetof(struct qmi_uaudio_stream_resp_msg_v01, + std_as_opr_intf_desc), + .ei_array = usb_interface_descriptor_v01_ei, + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x15, + .offset = offsetof(struct qmi_uaudio_stream_resp_msg_v01, + std_as_data_ep_desc_valid), + }, + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct usb_endpoint_descriptor_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x15, + .offset = offsetof(struct qmi_uaudio_stream_resp_msg_v01, + std_as_data_ep_desc), + .ei_array = usb_endpoint_descriptor_v01_ei, + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x16, + .offset = offsetof(struct qmi_uaudio_stream_resp_msg_v01, + std_as_sync_ep_desc_valid), + }, + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct usb_endpoint_descriptor_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x16, + .offset = offsetof(struct qmi_uaudio_stream_resp_msg_v01, + std_as_sync_ep_desc), + .ei_array = usb_endpoint_descriptor_v01_ei, + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x17, + .offset = offsetof(struct qmi_uaudio_stream_resp_msg_v01, + usb_audio_spec_revision_valid), + }, + { + .data_type = QMI_UNSIGNED_2_BYTE, + .elem_len = 1, + .elem_size = sizeof(u16), + .array_type = NO_ARRAY, + .tlv_type = 0x17, + .offset = offsetof(struct qmi_uaudio_stream_resp_msg_v01, + usb_audio_spec_revision), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x18, + .offset = offsetof(struct qmi_uaudio_stream_resp_msg_v01, + data_path_delay_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x18, + .offset = offsetof(struct qmi_uaudio_stream_resp_msg_v01, + data_path_delay), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x19, + .offset = offsetof(struct qmi_uaudio_stream_resp_msg_v01, + usb_audio_subslot_size_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x19, + .offset = offsetof(struct qmi_uaudio_stream_resp_msg_v01, + usb_audio_subslot_size), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x1A, + .offset = offsetof(struct qmi_uaudio_stream_resp_msg_v01, + xhci_mem_info_valid), + }, + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct apps_mem_info_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x1A, + .offset = offsetof(struct qmi_uaudio_stream_resp_msg_v01, + xhci_mem_info), + .ei_array = apps_mem_info_v01_ei, + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x1B, + .offset = offsetof(struct qmi_uaudio_stream_resp_msg_v01, + interrupter_num_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x1B, + .offset = offsetof(struct qmi_uaudio_stream_resp_msg_v01, + interrupter_num), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x1C, + .offset = offsetof(struct qmi_uaudio_stream_resp_msg_v01, + speed_info_valid), + }, + { + .data_type = QMI_SIGNED_4_BYTE_ENUM, + .elem_len = 1, + .elem_size = sizeof(enum usb_qmi_audio_device_speed_enum_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x1C, + .offset = offsetof(struct qmi_uaudio_stream_resp_msg_v01, + speed_info), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x1D, + .offset = offsetof(struct qmi_uaudio_stream_resp_msg_v01, + controller_num_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x1D, + .offset = offsetof(struct qmi_uaudio_stream_resp_msg_v01, + controller_num), + }, + { + .data_type = QMI_EOTI, + .array_type = NO_ARRAY, + .tlv_type = QMI_COMMON_TLV_TYPE, + }, +}; + +const struct qmi_elem_info qmi_uaudio_stream_ind_msg_v01_ei[] = { + { + .data_type = QMI_SIGNED_4_BYTE_ENUM, + .elem_len = 1, + .elem_size = sizeof( + enum usb_qmi_audio_device_indication_enum_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct qmi_uaudio_stream_ind_msg_v01, + dev_event), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct qmi_uaudio_stream_ind_msg_v01, + slot_id), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct qmi_uaudio_stream_ind_msg_v01, + usb_token_valid), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct qmi_uaudio_stream_ind_msg_v01, + usb_token), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof(struct qmi_uaudio_stream_ind_msg_v01, + std_as_opr_intf_desc_valid), + }, + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct usb_interface_descriptor_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof(struct qmi_uaudio_stream_ind_msg_v01, + std_as_opr_intf_desc), + .ei_array = usb_interface_descriptor_v01_ei, + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x12, + .offset = offsetof(struct qmi_uaudio_stream_ind_msg_v01, + std_as_data_ep_desc_valid), + }, + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct usb_endpoint_descriptor_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x12, + .offset = offsetof(struct qmi_uaudio_stream_ind_msg_v01, + std_as_data_ep_desc), + .ei_array = usb_endpoint_descriptor_v01_ei, + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x13, + .offset = offsetof(struct qmi_uaudio_stream_ind_msg_v01, + std_as_sync_ep_desc_valid), + }, + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct usb_endpoint_descriptor_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x13, + .offset = offsetof(struct qmi_uaudio_stream_ind_msg_v01, + std_as_sync_ep_desc), + .ei_array = usb_endpoint_descriptor_v01_ei, + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x14, + .offset = offsetof(struct qmi_uaudio_stream_ind_msg_v01, + usb_audio_spec_revision_valid), + }, + { + .data_type = QMI_UNSIGNED_2_BYTE, + .elem_len = 1, + .elem_size = sizeof(u16), + .array_type = NO_ARRAY, + .tlv_type = 0x14, + .offset = offsetof(struct qmi_uaudio_stream_ind_msg_v01, + usb_audio_spec_revision), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x15, + .offset = offsetof(struct qmi_uaudio_stream_ind_msg_v01, + data_path_delay_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x15, + .offset = offsetof(struct qmi_uaudio_stream_ind_msg_v01, + data_path_delay), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x16, + .offset = offsetof(struct qmi_uaudio_stream_ind_msg_v01, + usb_audio_subslot_size_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x16, + .offset = offsetof(struct qmi_uaudio_stream_ind_msg_v01, + usb_audio_subslot_size), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x17, + .offset = offsetof(struct qmi_uaudio_stream_ind_msg_v01, + xhci_mem_info_valid), + }, + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct apps_mem_info_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x17, + .offset = offsetof(struct qmi_uaudio_stream_ind_msg_v01, + xhci_mem_info), + .ei_array = apps_mem_info_v01_ei, + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x18, + .offset = offsetof(struct qmi_uaudio_stream_ind_msg_v01, + interrupter_num_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x18, + .offset = offsetof(struct qmi_uaudio_stream_ind_msg_v01, + interrupter_num), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x19, + .offset = offsetof(struct qmi_uaudio_stream_ind_msg_v01, + controller_num_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x19, + .offset = offsetof(struct qmi_uaudio_stream_ind_msg_v01, + controller_num), + }, + { + .data_type = QMI_EOTI, + .array_type = NO_ARRAY, + .tlv_type = QMI_COMMON_TLV_TYPE, + }, +}; diff --git a/sound/usb/qcom/usb_audio_qmi_v01.h b/sound/usb/qcom/usb_audio_qmi_v01.h new file mode 100644 index 000000000000..a1298d75d9f8 --- /dev/null +++ b/sound/usb/qcom/usb_audio_qmi_v01.h @@ -0,0 +1,164 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright (c) 2022-2025 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef USB_QMI_V01_H +#define USB_QMI_V01_H + +#define UAUDIO_STREAM_SERVICE_ID_V01 0x41D +#define UAUDIO_STREAM_SERVICE_VERS_V01 0x01 + +#define QMI_UAUDIO_STREAM_RESP_V01 0x0001 +#define QMI_UAUDIO_STREAM_REQ_V01 0x0001 +#define QMI_UAUDIO_STREAM_IND_V01 0x0001 + +struct mem_info_v01 { + u64 iova; /* mapped into sysdev */ + u64 dma; /* mapped into usb host */ + u32 size; +}; + +struct apps_mem_info_v01 { + struct mem_info_v01 evt_ring; + struct mem_info_v01 tr_data; + struct mem_info_v01 tr_sync; + struct mem_info_v01 xfer_buff; + struct mem_info_v01 dcba; +}; + +struct usb_endpoint_descriptor_v01 { + u8 bLength; + u8 bDescriptorType; + u8 bEndpointAddress; + u8 bmAttributes; + u16 wMaxPacketSize; + u8 bInterval; + u8 bRefresh; + u8 bSynchAddress; +}; + +struct usb_interface_descriptor_v01 { + u8 bLength; + u8 bDescriptorType; + u8 bInterfaceNumber; + u8 bAlternateSetting; + u8 bNumEndpoints; + u8 bInterfaceClass; + u8 bInterfaceSubClass; + u8 bInterfaceProtocol; + u8 iInterface; +}; + +enum usb_qmi_audio_stream_status_enum_v01 { + USB_QMI_STREAM_STATUS_ENUM_MIN_VAL_V01 = INT_MIN, + USB_QMI_STREAM_REQ_SUCCESS_V01 = 0, + USB_QMI_STREAM_REQ_FAILURE_V01 = 1, + USB_QMI_STREAM_REQ_FAILURE_NOT_FOUND_V01 = 2, + USB_QMI_STREAM_REQ_FAILURE_INVALID_PARAM_V01 = 3, + USB_QMI_STREAM_REQ_FAILURE_MEMALLOC_V01 = 4, + USB_QMI_STREAM_STATUS_ENUM_MAX_VAL_V01 = INT_MAX, +}; + +enum usb_qmi_audio_device_indication_enum_v01 { + USB_QMI_DEVICE_INDICATION_ENUM_MIN_VAL_V01 = INT_MIN, + USB_QMI_DEV_CONNECT_V01 = 0, + USB_QMI_DEV_DISCONNECT_V01 = 1, + USB_QMI_DEV_SUSPEND_V01 = 2, + USB_QMI_DEV_RESUME_V01 = 3, + USB_QMI_DEVICE_INDICATION_ENUM_MAX_VAL_V01 = INT_MAX, +}; + +enum usb_qmi_audio_device_speed_enum_v01 { + USB_QMI_DEVICE_SPEED_ENUM_MIN_VAL_V01 = INT_MIN, + USB_QMI_DEVICE_SPEED_INVALID_V01 = 0, + USB_QMI_DEVICE_SPEED_LOW_V01 = 1, + USB_QMI_DEVICE_SPEED_FULL_V01 = 2, + USB_QMI_DEVICE_SPEED_HIGH_V01 = 3, + USB_QMI_DEVICE_SPEED_SUPER_V01 = 4, + USB_QMI_DEVICE_SPEED_SUPER_PLUS_V01 = 5, + USB_QMI_DEVICE_SPEED_ENUM_MAX_VAL_V01 = INT_MAX, +}; + +struct qmi_uaudio_stream_req_msg_v01 { + u8 enable; + u32 usb_token; + u8 audio_format_valid; + u32 audio_format; + u8 number_of_ch_valid; + u32 number_of_ch; + u8 bit_rate_valid; + u32 bit_rate; + u8 xfer_buff_size_valid; + u32 xfer_buff_size; + u8 service_interval_valid; + u32 service_interval; +}; + +#define QMI_UAUDIO_STREAM_REQ_MSG_V01_MAX_MSG_LEN 46 +extern const struct qmi_elem_info qmi_uaudio_stream_req_msg_v01_ei[]; + +struct qmi_uaudio_stream_resp_msg_v01 { + struct qmi_response_type_v01 resp; + u8 status_valid; + enum usb_qmi_audio_stream_status_enum_v01 status; + u8 internal_status_valid; + u32 internal_status; + u8 slot_id_valid; + u32 slot_id; + u8 usb_token_valid; + u32 usb_token; + u8 std_as_opr_intf_desc_valid; + struct usb_interface_descriptor_v01 std_as_opr_intf_desc; + u8 std_as_data_ep_desc_valid; + struct usb_endpoint_descriptor_v01 std_as_data_ep_desc; + u8 std_as_sync_ep_desc_valid; + struct usb_endpoint_descriptor_v01 std_as_sync_ep_desc; + u8 usb_audio_spec_revision_valid; + u16 usb_audio_spec_revision; + u8 data_path_delay_valid; + u8 data_path_delay; + u8 usb_audio_subslot_size_valid; + u8 usb_audio_subslot_size; + u8 xhci_mem_info_valid; + struct apps_mem_info_v01 xhci_mem_info; + u8 interrupter_num_valid; + u8 interrupter_num; + u8 speed_info_valid; + enum usb_qmi_audio_device_speed_enum_v01 speed_info; + u8 controller_num_valid; + u8 controller_num; +}; + +#define QMI_UAUDIO_STREAM_RESP_MSG_V01_MAX_MSG_LEN 202 +extern const struct qmi_elem_info qmi_uaudio_stream_resp_msg_v01_ei[]; + +struct qmi_uaudio_stream_ind_msg_v01 { + enum usb_qmi_audio_device_indication_enum_v01 dev_event; + u32 slot_id; + u8 usb_token_valid; + u32 usb_token; + u8 std_as_opr_intf_desc_valid; + struct usb_interface_descriptor_v01 std_as_opr_intf_desc; + u8 std_as_data_ep_desc_valid; + struct usb_endpoint_descriptor_v01 std_as_data_ep_desc; + u8 std_as_sync_ep_desc_valid; + struct usb_endpoint_descriptor_v01 std_as_sync_ep_desc; + u8 usb_audio_spec_revision_valid; + u16 usb_audio_spec_revision; + u8 data_path_delay_valid; + u8 data_path_delay; + u8 usb_audio_subslot_size_valid; + u8 usb_audio_subslot_size; + u8 xhci_mem_info_valid; + struct apps_mem_info_v01 xhci_mem_info; + u8 interrupter_num_valid; + u8 interrupter_num; + u8 controller_num_valid; + u8 controller_num; +}; + +#define QMI_UAUDIO_STREAM_IND_MSG_V01_MAX_MSG_LEN 181 +extern const struct qmi_elem_info qmi_uaudio_stream_ind_msg_v01_ei[]; + +#endif diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index 5ed523b13fad..bd24f3a78ea9 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -2285,6 +2285,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { QUIRK_FLAG_DISABLE_AUTOSUSPEND), DEVICE_FLG(0x17aa, 0x104d, /* Lenovo ThinkStation P620 Internal Speaker + Front Headset */ QUIRK_FLAG_DISABLE_AUTOSUSPEND), + DEVICE_FLG(0x17ef, 0x3083, /* Lenovo TBT3 dock */ + QUIRK_FLAG_GET_SAMPLE_RATE), DEVICE_FLG(0x1852, 0x5062, /* Luxman D-08u */ QUIRK_FLAG_ITF_USB_DSD_DAC | QUIRK_FLAG_CTL_MSG_DELAY), DEVICE_FLG(0x1852, 0x5065, /* Luxman DA-06 */ diff --git a/tools/iio/iio_generic_buffer.c b/tools/iio/iio_generic_buffer.c index 9ef5ee087eda..bc82bb6a7a2a 100644 --- a/tools/iio/iio_generic_buffer.c +++ b/tools/iio/iio_generic_buffer.c @@ -335,7 +335,7 @@ static const struct option longopts[] = { { "device-num", 1, 0, 'N' }, { "trigger-name", 1, 0, 't' }, { "trigger-num", 1, 0, 'T' }, - { }, + { } }; int main(int argc, char **argv) diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c index 01818abd02df..6d2c280a1730 100644 --- a/tools/perf/util/symbol-elf.c +++ b/tools/perf/util/symbol-elf.c @@ -1668,6 +1668,12 @@ dso__load_sym_internal(struct dso *dso, struct map *map, struct symsrc *syms_ss, continue; } + /* Reject RISCV ELF "mapping symbols" */ + if (ehdr.e_machine == EM_RISCV) { + if (elf_name[0] == '$' && strchr("dx", elf_name[1])) + continue; + } + if (runtime_ss->opdsec && sym.st_shndx == runtime_ss->opdidx) { u32 offset = sym.st_value - syms_ss->opdshdr.sh_addr; u64 *opd = opddata->d_buf + offset; diff --git a/tools/power/x86/turbostat/turbostat.8 b/tools/power/x86/turbostat/turbostat.8 index b74ed916057e..fb11108aaf42 100644 --- a/tools/power/x86/turbostat/turbostat.8 +++ b/tools/power/x86/turbostat/turbostat.8 @@ -100,7 +100,7 @@ The column name "all" can be used to enable all disabled-by-default built-in cou .PP \fB--show column\fP show only the specified built-in columns. May be invoked multiple times, or with a comma-separated list of column names. .PP -\fB--show CATEGORY --hide CATEGORY\fP Show and hide also accept a single CATEGORY of columns: "all", "topology", "idle", "frequency", "power", "cpuidle", "hwidle", "swidle", "other". "idle" (enabled by default), includes "hwidle" and "idle_pct". "cpuidle" (default disabled) includes cpuidle software invocation counters. "swidle" includes "cpuidle" plus "idle_pct". "hwidle" includes only hardware based idle residency counters. Older versions of turbostat used the term "sysfs" for what is now "swidle". +\fB--show CATEGORY --hide CATEGORY\fP Show and hide also accept a single CATEGORY of columns: "all", "topology", "idle", "frequency", "power", "cpuidle", "hwidle", "swidle", "other". "idle" (enabled by default), includes "hwidle" and "pct_idle". "cpuidle" (default disabled) includes cpuidle software invocation counters. "swidle" includes "cpuidle" plus "pct_idle". "hwidle" includes only hardware based idle residency counters. Older versions of turbostat used the term "sysfs" for what is now "swidle". .PP \fB--Dump\fP displays the raw counter values. .PP @@ -204,8 +204,8 @@ The system configuration dump (if --quiet is not used) is followed by statistics .PP \fBUncMHz\fP per-package uncore MHz, instantaneous sample. .PP -\fBUMHz1.0\fP per-package uncore MHz for domain=1 and fabric_cluster=0, instantaneous sample. System summary is the average of all packages. -Intel Granite Rapids systems use domains 0-2 for CPUs, and 3-4 for IO, with cluster always 0. +\fBUMHz1.0\fP per-package uncore MHz for pm_domain=1 and fabric_cluster=0, instantaneous sample. System summary is the average of all packages. +Intel Granite Rapids systems use pm_domains 0-2 for CPUs, and 3-4 for IO, with cluster always 0. For the "--show" and "--hide" options, use "UncMHz" to operate on all UMHz*.* as a group. .SH TOO MUCH INFORMATION EXAMPLE By default, turbostat dumps all possible information -- a system configuration header, followed by columns for all counters. diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c index 0170d3cc6819..5230e072e414 100644 --- a/tools/power/x86/turbostat/turbostat.c +++ b/tools/power/x86/turbostat/turbostat.c @@ -280,7 +280,7 @@ struct msr_counter bic[] = { #define BIC_GROUP_FREQUENCY (BIC_Avg_MHz | BIC_Busy | BIC_Bzy_MHz | BIC_TSC_MHz | BIC_GFXMHz | BIC_GFXACTMHz | BIC_SAMMHz | BIC_SAMACTMHz | BIC_UNCORE_MHZ) #define BIC_GROUP_HW_IDLE (BIC_Busy | BIC_CPU_c1 | BIC_CPU_c3 | BIC_CPU_c6 | BIC_CPU_c7 | BIC_GFX_rc6 | BIC_Pkgpc2 | BIC_Pkgpc3 | BIC_Pkgpc6 | BIC_Pkgpc7 | BIC_Pkgpc8 | BIC_Pkgpc9 | BIC_Pkgpc10 | BIC_CPU_LPI | BIC_SYS_LPI | BIC_Mod_c6 | BIC_Totl_c0 | BIC_Any_c0 | BIC_GFX_c0 | BIC_CPUGFX | BIC_SAM_mc6 | BIC_Diec6) #define BIC_GROUP_SW_IDLE (BIC_Busy | BIC_cpuidle | BIC_pct_idle ) -#define BIC_GROUP_IDLE (BIC_GROUP_HW_IDLE | BIC_pct_idle) +#define BIC_GROUP_IDLE (BIC_GROUP_HW_IDLE | BIC_pct_idle) #define BIC_OTHER (BIC_IRQ | BIC_NMI | BIC_SMI | BIC_ThreadC | BIC_CoreTmp | BIC_IPC) #define BIC_DISABLED_BY_DEFAULT (BIC_USEC | BIC_TOD | BIC_APIC | BIC_X2APIC | BIC_cpuidle) @@ -539,7 +539,7 @@ enum rapl_msrs { #define RAPL_PKG_ALL (RAPL_PKG | RAPL_PKG_PERF_STATUS | RAPL_PKG_POWER_INFO) #define RAPL_DRAM_ALL (RAPL_DRAM | RAPL_DRAM_PERF_STATUS | RAPL_DRAM_POWER_INFO) #define RAPL_CORE_ALL (RAPL_CORE | RAPL_CORE_POLICY) -#define RAPL_GFX_ALL (RAPL_GFX | RAPL_GFX_POLIGY) +#define RAPL_GFX_ALL (RAPL_GFX | RAPL_GFX_POLICY) #define RAPL_AMD_F17H (RAPL_AMD_PWR_UNIT | RAPL_AMD_CORE_ENERGY_STAT | RAPL_AMD_PKG_ENERGY_STAT) @@ -839,6 +839,23 @@ static const struct platform_features spr_features = { .rapl_msrs = RAPL_PKG_ALL | RAPL_DRAM_ALL | RAPL_PSYS, }; +static const struct platform_features dmr_features = { + .has_msr_misc_feature_control = spr_features.has_msr_misc_feature_control, + .has_msr_misc_pwr_mgmt = spr_features.has_msr_misc_pwr_mgmt, + .has_nhm_msrs = spr_features.has_nhm_msrs, + .has_config_tdp = spr_features.has_config_tdp, + .bclk_freq = spr_features.bclk_freq, + .supported_cstates = spr_features.supported_cstates, + .cst_limit = spr_features.cst_limit, + .has_msr_core_c1_res = spr_features.has_msr_core_c1_res, + .has_msr_module_c6_res_ms = 1, /* DMR has Dual Core Module and MC6 MSR */ + .has_irtl_msrs = spr_features.has_irtl_msrs, + .has_cst_prewake_bit = spr_features.has_cst_prewake_bit, + .has_fixed_rapl_psys_unit = spr_features.has_fixed_rapl_psys_unit, + .trl_msrs = spr_features.trl_msrs, + .rapl_msrs = 0, /* DMR does not have RAPL MSRs */ +}; + static const struct platform_features srf_features = { .has_msr_misc_feature_control = 1, .has_msr_misc_pwr_mgmt = 1, @@ -1028,12 +1045,14 @@ static const struct platform_data turbostat_pdata[] = { { INTEL_EMERALDRAPIDS_X, &spr_features }, { INTEL_GRANITERAPIDS_X, &spr_features }, { INTEL_GRANITERAPIDS_D, &spr_features }, + { INTEL_PANTHERCOVE_X, &dmr_features }, { INTEL_LAKEFIELD, &cnl_features }, { INTEL_ALDERLAKE, &adl_features }, { INTEL_ALDERLAKE_L, &adl_features }, { INTEL_RAPTORLAKE, &adl_features }, { INTEL_RAPTORLAKE_P, &adl_features }, { INTEL_RAPTORLAKE_S, &adl_features }, + { INTEL_BARTLETTLAKE, &adl_features }, { INTEL_METEORLAKE, &adl_features }, { INTEL_METEORLAKE_L, &adl_features }, { INTEL_ARROWLAKE_H, &adl_features }, @@ -1072,7 +1091,6 @@ void probe_platform_features(unsigned int family, unsigned int model) { int i; - if (authentic_amd || hygon_genuine) { /* fallback to default features on unsupported models */ force_load++; @@ -1106,8 +1124,7 @@ end: if (platform) return; - fprintf(stderr, "Unsupported platform detected.\n" - "\tSee RUN THE LATEST VERSION on turbostat(8)\n"); + fprintf(stderr, "Unsupported platform detected.\n\tSee RUN THE LATEST VERSION on turbostat(8)\n"); exit(1); } @@ -1127,7 +1144,8 @@ char *progname; #define CPU_SUBSET_MAXCPUS 8192 /* need to use before probe... */ cpu_set_t *cpu_present_set, *cpu_possible_set, *cpu_effective_set, *cpu_allowed_set, *cpu_affinity_set, *cpu_subset; -size_t cpu_present_setsize, cpu_possible_setsize, cpu_effective_setsize, cpu_allowed_setsize, cpu_affinity_setsize, cpu_subset_size; +size_t cpu_present_setsize, cpu_possible_setsize, cpu_effective_setsize, cpu_allowed_setsize, cpu_affinity_setsize, + cpu_subset_size; #define MAX_ADDED_THREAD_COUNTERS 24 #define MAX_ADDED_CORE_COUNTERS 8 #define MAX_ADDED_PACKAGE_COUNTERS 16 @@ -2140,13 +2158,20 @@ int get_msr_fd(int cpu) if (fd) return fd; - +#if defined(ANDROID) + sprintf(pathname, "/dev/msr%d", cpu); +#else sprintf(pathname, "/dev/cpu/%d/msr", cpu); +#endif fd = open(pathname, O_RDONLY); if (fd < 0) +#if defined(ANDROID) + err(-1, "%s open failed, try chown or chmod +r /dev/msr*, " + "or run with --no-msr, or run as root", pathname); +#else err(-1, "%s open failed, try chown or chmod +r /dev/cpu/*/msr, " "or run with --no-msr, or run as root", pathname); - +#endif fd_percpu[cpu] = fd; return fd; @@ -2215,32 +2240,52 @@ int get_msr(int cpu, off_t offset, unsigned long long *msr) return 0; } -int probe_rapl_msr(int cpu, off_t offset, int index) +int add_msr_counter(int cpu, off_t offset) { ssize_t retval; unsigned long long value; - assert(!no_msr); + if (no_msr) + return -1; + + if (!offset) + return -1; retval = pread(get_msr_fd(cpu), &value, sizeof(value), offset); /* if the read failed, the probe fails */ if (retval != sizeof(value)) - return 1; + return -1; + + if (value == 0) + return 0; + + return 1; +} + +int add_rapl_msr_counter(int cpu, const struct rapl_counter_arch_info *cai) +{ + int ret; + + if (!(platform->rapl_msrs & cai->feature_mask)) + return -1; + + ret = add_msr_counter(cpu, cai->msr); + if (ret < 0) + return -1; - /* If an Energy Status Counter MSR returns 0, the probe fails */ - switch (index) { + switch (cai->rci_index) { case RAPL_RCI_INDEX_ENERGY_PKG: case RAPL_RCI_INDEX_ENERGY_CORES: case RAPL_RCI_INDEX_DRAM: case RAPL_RCI_INDEX_GFX: case RAPL_RCI_INDEX_ENERGY_PLATFORM: - if (value == 0) + if (ret == 0) return 1; } /* PKG,DRAM_PERF_STATUS MSRs, can return any value */ - return 0; + return 1; } /* Convert CPU ID to domain ID for given added perf counter. */ @@ -2327,8 +2372,7 @@ void help(void) " degrees Celsius\n" " -h, --help\n" " print this help message\n" - " -v, --version\n" - " print version information\n\nFor more help, run \"man turbostat\"\n"); + " -v, --version\n\t\tprint version information\n\nFor more help, run \"man turbostat\"\n"); } /* @@ -2644,7 +2688,7 @@ void print_header(char *delim) if (DO_BIC(BIC_SYS_LPI)) outp += sprintf(outp, "%sSYS%%LPI", (printed++ ? delim : "")); - if (platform->rapl_msrs && !rapl_joules) { + if (!rapl_joules) { if (DO_BIC(BIC_PkgWatt)) outp += sprintf(outp, "%sPkgWatt", (printed++ ? delim : "")); if (DO_BIC(BIC_CorWatt) && !platform->has_per_core_rapl) @@ -2657,7 +2701,7 @@ void print_header(char *delim) outp += sprintf(outp, "%sPKG_%%", (printed++ ? delim : "")); if (DO_BIC(BIC_RAM__)) outp += sprintf(outp, "%sRAM_%%", (printed++ ? delim : "")); - } else if (platform->rapl_msrs && rapl_joules) { + } else { if (DO_BIC(BIC_Pkg_J)) outp += sprintf(outp, "%sPkg_J", (printed++ ? delim : "")); if (DO_BIC(BIC_Cor_J) && !platform->has_per_core_rapl) @@ -3943,7 +3987,6 @@ void compute_average(struct thread_data *t, struct core_data *c, struct pkg_data if (average.threads.nmi_count > 9999999) sums_need_wide_columns = 1; - average.cores.c3 /= topo.allowed_cores; average.cores.c6 /= topo.allowed_cores; average.cores.c7 /= topo.allowed_cores; @@ -4766,6 +4809,37 @@ unsigned long pmt_read_counter(struct pmt_counter *ppmt, unsigned int domain_id) return (value & value_mask) >> value_shift; } +/* Rapl domain enumeration helpers */ +static inline int get_rapl_num_domains(void) +{ + int num_packages = topo.max_package_id + 1; + int num_cores_per_package; + int num_cores; + + if (!platform->has_per_core_rapl) + return num_packages; + + num_cores_per_package = topo.max_core_id + 1; + num_cores = num_cores_per_package * num_packages; + + return num_cores; +} + +static inline int get_rapl_domain_id(int cpu) +{ + int nr_cores_per_package = topo.max_core_id + 1; + int rapl_core_id; + + if (!platform->has_per_core_rapl) + return cpus[cpu].physical_package_id; + + /* Compute the system-wide unique core-id for @cpu */ + rapl_core_id = cpus[cpu].physical_core_id; + rapl_core_id += cpus[cpu].physical_package_id * nr_cores_per_package; + + return rapl_core_id; +} + /* * get_counters(...) * migrate to cpu @@ -4821,7 +4895,7 @@ int get_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p) goto done; if (platform->has_per_core_rapl) { - status = get_rapl_counters(cpu, c->core_id, c, p); + status = get_rapl_counters(cpu, get_rapl_domain_id(cpu), c, p); if (status != 0) return status; } @@ -4887,7 +4961,7 @@ int get_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p) p->sys_lpi = cpuidle_cur_sys_lpi_us; if (!platform->has_per_core_rapl) { - status = get_rapl_counters(cpu, p->package_id, c, p); + status = get_rapl_counters(cpu, get_rapl_domain_id(cpu), c, p); if (status != 0) return status; } @@ -6476,8 +6550,11 @@ void check_dev_msr() if (no_msr) return; - +#if defined(ANDROID) + sprintf(pathname, "/dev/msr%d", base_cpu); +#else sprintf(pathname, "/dev/cpu/%d/msr", base_cpu); +#endif if (stat(pathname, &sb)) if (system("/sbin/modprobe msr > /dev/null 2>&1")) no_msr = 1; @@ -6527,7 +6604,11 @@ void check_msr_permission(void) failed += check_for_cap_sys_rawio(); /* test file permissions */ +#if defined(ANDROID) + sprintf(pathname, "/dev/msr%d", base_cpu); +#else sprintf(pathname, "/dev/cpu/%d/msr", base_cpu); +#endif if (euidaccess(pathname, R_OK)) { failed++; } @@ -6737,8 +6818,10 @@ static void probe_intel_uncore_frequency_cluster(void) * This allows "--show/--hide UncMHz" to be effective for * the clustered MHz counters, as a group. */ - if BIC_IS_ENABLED(BIC_UNCORE_MHZ) - add_counter(0, path, name_buf, 0, SCOPE_PACKAGE, COUNTER_K2M, FORMAT_AVERAGE, 0, package_id); + if BIC_IS_ENABLED + (BIC_UNCORE_MHZ) + add_counter(0, path, name_buf, 0, SCOPE_PACKAGE, COUNTER_K2M, FORMAT_AVERAGE, 0, + package_id); if (quiet) continue; @@ -6810,17 +6893,21 @@ static void probe_graphics(void) else goto next; - set_graphics_fp("/sys/class/drm/card0/device/tile0/gt0/gtidle/idle_residency_ms", gt0_is_gt ? GFX_rc6 : SAM_mc6); + set_graphics_fp("/sys/class/drm/card0/device/tile0/gt0/gtidle/idle_residency_ms", + gt0_is_gt ? GFX_rc6 : SAM_mc6); set_graphics_fp("/sys/class/drm/card0/device/tile0/gt0/freq0/cur_freq", gt0_is_gt ? GFX_MHz : SAM_MHz); - set_graphics_fp("/sys/class/drm/card0/device/tile0/gt0/freq0/act_freq", gt0_is_gt ? GFX_ACTMHz : SAM_ACTMHz); + set_graphics_fp("/sys/class/drm/card0/device/tile0/gt0/freq0/act_freq", + gt0_is_gt ? GFX_ACTMHz : SAM_ACTMHz); - set_graphics_fp("/sys/class/drm/card0/device/tile0/gt1/gtidle/idle_residency_ms", gt0_is_gt ? SAM_mc6 : GFX_rc6); + set_graphics_fp("/sys/class/drm/card0/device/tile0/gt1/gtidle/idle_residency_ms", + gt0_is_gt ? SAM_mc6 : GFX_rc6); set_graphics_fp("/sys/class/drm/card0/device/tile0/gt1/freq0/cur_freq", gt0_is_gt ? SAM_MHz : GFX_MHz); - set_graphics_fp("/sys/class/drm/card0/device/tile0/gt1/freq0/act_freq", gt0_is_gt ? SAM_ACTMHz : GFX_ACTMHz); + set_graphics_fp("/sys/class/drm/card0/device/tile0/gt1/freq0/act_freq", + gt0_is_gt ? SAM_ACTMHz : GFX_ACTMHz); goto end; } @@ -7256,6 +7343,9 @@ void rapl_probe_intel(void) else bic_enabled &= ~bic_joules_bits; + if (!platform->rapl_msrs || no_msr) + return; + if (!(platform->rapl_msrs & RAPL_PKG_PERF_STATUS)) bic_enabled &= ~BIC_PKG__; if (!(platform->rapl_msrs & RAPL_DRAM_PERF_STATUS)) @@ -7306,6 +7396,9 @@ void rapl_probe_amd(void) else bic_enabled &= ~bic_joules_bits; + if (!platform->rapl_msrs || no_msr) + return; + if (get_msr(base_cpu, MSR_RAPL_PWR_UNIT, &msr)) return; @@ -7332,6 +7425,158 @@ void print_power_limit_msr(int cpu, unsigned long long msr, char *label) return; } +static int fread_int(char *path, int *val) +{ + FILE *filep; + int ret; + + filep = fopen(path, "r"); + if (!filep) + return -1; + + ret = fscanf(filep, "%d", val); + fclose(filep); + return ret; +} + +static int fread_ull(char *path, unsigned long long *val) +{ + FILE *filep; + int ret; + + filep = fopen(path, "r"); + if (!filep) + return -1; + + ret = fscanf(filep, "%llu", val); + fclose(filep); + return ret; +} + +static int fread_str(char *path, char *buf, int size) +{ + FILE *filep; + int ret; + char *cp; + + filep = fopen(path, "r"); + if (!filep) + return -1; + + ret = fread(buf, 1, size, filep); + fclose(filep); + + /* replace '\n' with '\0' */ + cp = strchr(buf, '\n'); + if (cp != NULL) + *cp = '\0'; + + return ret; +} + +#define PATH_RAPL_SYSFS "/sys/class/powercap" + +static int dump_one_domain(char *domain_path) +{ + char path[PATH_MAX]; + char str[PATH_MAX]; + unsigned long long val; + int constraint; + int enable; + int ret; + + snprintf(path, PATH_MAX, "%s/name", domain_path); + ret = fread_str(path, str, PATH_MAX); + if (ret <= 0) + return -1; + + fprintf(outf, "%s: %s", domain_path + strlen(PATH_RAPL_SYSFS) + 1, str); + + snprintf(path, PATH_MAX, "%s/enabled", domain_path); + ret = fread_int(path, &enable); + if (ret <= 0) + return -1; + + if (!enable) { + fputs(" disabled\n", outf); + return 0; + } + + for (constraint = 0;; constraint++) { + snprintf(path, PATH_MAX, "%s/constraint_%d_time_window_us", domain_path, constraint); + ret = fread_ull(path, &val); + if (ret <= 0) + break; + + if (val > 1000000) + fprintf(outf, " %0.1fs", (double)val / 1000000); + else if (val > 1000) + fprintf(outf, " %0.1fms", (double)val / 1000); + else + fprintf(outf, " %0.1fus", (double)val); + + snprintf(path, PATH_MAX, "%s/constraint_%d_power_limit_uw", domain_path, constraint); + ret = fread_ull(path, &val); + if (ret > 0 && val) + fprintf(outf, ":%lluW", val / 1000000); + + snprintf(path, PATH_MAX, "%s/constraint_%d_max_power_uw", domain_path, constraint); + ret = fread_ull(path, &val); + if (ret > 0 && val) + fprintf(outf, ",max:%lluW", val / 1000000); + } + fputc('\n', outf); + + return 0; +} + +static int print_rapl_sysfs(void) +{ + DIR *dir, *cdir; + struct dirent *entry, *centry; + char path[PATH_MAX]; + char str[PATH_MAX]; + + if ((dir = opendir(PATH_RAPL_SYSFS)) == NULL) { + warn("open %s failed", PATH_RAPL_SYSFS); + return 1; + } + + while ((entry = readdir(dir)) != NULL) { + if (strlen(entry->d_name) > 100) + continue; + + if (strncmp(entry->d_name, "intel-rapl", strlen("intel-rapl"))) + continue; + + snprintf(path, PATH_MAX, "%s/%s/name", PATH_RAPL_SYSFS, entry->d_name); + + /* Parse top level domains first, including package and psys */ + fread_str(path, str, PATH_MAX); + if (strncmp(str, "package", strlen("package")) && strncmp(str, "psys", strlen("psys"))) + continue; + + snprintf(path, PATH_MAX, "%s/%s", PATH_RAPL_SYSFS, entry->d_name); + if ((cdir = opendir(path)) == NULL) { + perror("opendir() error"); + return 1; + } + + dump_one_domain(path); + + while ((centry = readdir(cdir)) != NULL) { + if (strncmp(centry->d_name, "intel-rapl", strlen("intel-rapl"))) + continue; + snprintf(path, PATH_MAX, "%s/%s/%s", PATH_RAPL_SYSFS, entry->d_name, centry->d_name); + dump_one_domain(path); + } + closedir(cdir); + } + + closedir(dir); + return 0; +} + int print_rapl(struct thread_data *t, struct core_data *c, struct pkg_data *p) { unsigned long long msr; @@ -7458,9 +7703,6 @@ int print_rapl(struct thread_data *t, struct core_data *c, struct pkg_data *p) */ void probe_rapl(void) { - if (!platform->rapl_msrs || no_msr) - return; - if (genuine_intel) rapl_probe_intel(); if (authentic_amd || hygon_genuine) @@ -7469,6 +7711,11 @@ void probe_rapl(void) if (quiet) return; + print_rapl_sysfs(); + + if (!platform->rapl_msrs || no_msr) + return; + for_all_cpus(print_rapl, ODD_COUNTERS); } @@ -7801,44 +8048,42 @@ static int has_instr_count_access(void) return has_access; } -int add_rapl_perf_counter_(int cpu, struct rapl_counter_info_t *rci, const struct rapl_counter_arch_info *cai, - double *scale_, enum rapl_unit *unit_) +int add_rapl_perf_counter(int cpu, struct rapl_counter_info_t *rci, const struct rapl_counter_arch_info *cai, + double *scale_, enum rapl_unit *unit_) { + int ret = -1; + if (no_perf) return -1; + if (!cai->perf_name) + return -1; + const double scale = read_perf_scale(cai->perf_subsys, cai->perf_name); if (scale == 0.0) - return -1; + goto end; const enum rapl_unit unit = read_perf_rapl_unit(cai->perf_subsys, cai->perf_name); if (unit == RAPL_UNIT_INVALID) - return -1; + goto end; const unsigned int rapl_type = read_perf_type(cai->perf_subsys); const unsigned int rapl_energy_pkg_config = read_perf_config(cai->perf_subsys, cai->perf_name); - const int fd_counter = - open_perf_counter(cpu, rapl_type, rapl_energy_pkg_config, rci->fd_perf, PERF_FORMAT_GROUP); - if (fd_counter == -1) - return -1; + ret = open_perf_counter(cpu, rapl_type, rapl_energy_pkg_config, rci->fd_perf, PERF_FORMAT_GROUP); + if (ret == -1) + goto end; /* If it's the first counter opened, make it a group descriptor */ if (rci->fd_perf == -1) - rci->fd_perf = fd_counter; + rci->fd_perf = ret; *scale_ = scale; *unit_ = unit; - return fd_counter; -} - -int add_rapl_perf_counter(int cpu, struct rapl_counter_info_t *rci, const struct rapl_counter_arch_info *cai, - double *scale, enum rapl_unit *unit) -{ - int ret = add_rapl_perf_counter_(cpu, rci, cai, scale, unit); +end: if (debug >= 2) fprintf(stderr, "%s: %d (cpu: %d)\n", __func__, ret, cpu); @@ -7863,7 +8108,7 @@ void linux_perf_init(void) void rapl_perf_init(void) { - const unsigned int num_domains = (platform->has_per_core_rapl ? topo.max_core_id : topo.max_package_id) + 1; + const unsigned int num_domains = get_rapl_num_domains(); bool *domain_visited = calloc(num_domains, sizeof(bool)); rapl_counter_info_perdomain = calloc(num_domains, sizeof(*rapl_counter_info_perdomain)); @@ -7896,6 +8141,9 @@ void rapl_perf_init(void) enum rapl_unit unit; unsigned int next_domain; + if (!BIC_IS_ENABLED(cai->bic)) + continue; + memset(domain_visited, 0, num_domains * sizeof(*domain_visited)); for (int cpu = 0; cpu < topo.max_cpu_num + 1; ++cpu) { @@ -7904,8 +8152,7 @@ void rapl_perf_init(void) continue; /* Skip already seen and handled RAPL domains */ - next_domain = - platform->has_per_core_rapl ? cpus[cpu].physical_core_id : cpus[cpu].physical_package_id; + next_domain = get_rapl_domain_id(cpu); assert(next_domain < num_domains); @@ -7919,27 +8166,37 @@ void rapl_perf_init(void) struct rapl_counter_info_t *rci = &rapl_counter_info_perdomain[next_domain]; - /* Check if the counter is enabled and accessible */ - if (BIC_IS_ENABLED(cai->bic) && (platform->rapl_msrs & cai->feature_mask)) { + /* + * rapl_counter_arch_infos[] can have multiple entries describing the same + * counter, due to the difference from different platforms/Vendors. + * E.g. rapl_counter_arch_infos[0] and rapl_counter_arch_infos[1] share the + * same perf_subsys and perf_name, but with different MSR address. + * rapl_counter_arch_infos[0] is for Intel and rapl_counter_arch_infos[1] + * is for AMD. + * In this case, it is possible that multiple rapl_counter_arch_infos[] + * entries are probed just because their perf/msr is duplicate and valid. + * + * Thus need a check to avoid re-probe the same counters. + */ + if (rci->source[cai->rci_index] != COUNTER_SOURCE_NONE) + break; - /* Use perf API for this counter */ - if (!no_perf && cai->perf_name - && add_rapl_perf_counter(cpu, rci, cai, &scale, &unit) != -1) { - rci->source[cai->rci_index] = COUNTER_SOURCE_PERF; - rci->scale[cai->rci_index] = scale * cai->compat_scale; - rci->unit[cai->rci_index] = unit; - rci->flags[cai->rci_index] = cai->flags; - - /* Use MSR for this counter */ - } else if (!no_msr && cai->msr && probe_rapl_msr(cpu, cai->msr, cai->rci_index) == 0) { - rci->source[cai->rci_index] = COUNTER_SOURCE_MSR; - rci->msr[cai->rci_index] = cai->msr; - rci->msr_mask[cai->rci_index] = cai->msr_mask; - rci->msr_shift[cai->rci_index] = cai->msr_shift; - rci->unit[cai->rci_index] = RAPL_UNIT_JOULES; - rci->scale[cai->rci_index] = *cai->platform_rapl_msr_scale * cai->compat_scale; - rci->flags[cai->rci_index] = cai->flags; - } + /* Use perf API for this counter */ + if (add_rapl_perf_counter(cpu, rci, cai, &scale, &unit) != -1) { + rci->source[cai->rci_index] = COUNTER_SOURCE_PERF; + rci->scale[cai->rci_index] = scale * cai->compat_scale; + rci->unit[cai->rci_index] = unit; + rci->flags[cai->rci_index] = cai->flags; + + /* Use MSR for this counter */ + } else if (add_rapl_msr_counter(cpu, cai) >= 0) { + rci->source[cai->rci_index] = COUNTER_SOURCE_MSR; + rci->msr[cai->rci_index] = cai->msr; + rci->msr_mask[cai->rci_index] = cai->msr_mask; + rci->msr_shift[cai->rci_index] = cai->msr_shift; + rci->unit[cai->rci_index] = RAPL_UNIT_JOULES; + rci->scale[cai->rci_index] = *cai->platform_rapl_msr_scale * cai->compat_scale; + rci->flags[cai->rci_index] = cai->flags; } if (rci->source[cai->rci_index] != COUNTER_SOURCE_NONE) @@ -7972,65 +8229,63 @@ int *get_cstate_perf_group_fd(struct cstate_counter_info_t *cci, const char *gro return NULL; } -int add_cstate_perf_counter_(int cpu, struct cstate_counter_info_t *cci, const struct cstate_counter_arch_info *cai) +int add_cstate_perf_counter(int cpu, struct cstate_counter_info_t *cci, const struct cstate_counter_arch_info *cai) { + int ret = -1; + if (no_perf) return -1; + if (!cai->perf_name) + return -1; + int *pfd_group = get_cstate_perf_group_fd(cci, cai->perf_subsys); if (pfd_group == NULL) - return -1; + goto end; const unsigned int type = read_perf_type(cai->perf_subsys); const unsigned int config = read_perf_config(cai->perf_subsys, cai->perf_name); - const int fd_counter = open_perf_counter(cpu, type, config, *pfd_group, PERF_FORMAT_GROUP); + ret = open_perf_counter(cpu, type, config, *pfd_group, PERF_FORMAT_GROUP); - if (fd_counter == -1) - return -1; + if (ret == -1) + goto end; /* If it's the first counter opened, make it a group descriptor */ if (*pfd_group == -1) - *pfd_group = fd_counter; - - return fd_counter; -} - -int add_cstate_perf_counter(int cpu, struct cstate_counter_info_t *cci, const struct cstate_counter_arch_info *cai) -{ - int ret = add_cstate_perf_counter_(cpu, cci, cai); + *pfd_group = ret; +end: if (debug >= 2) fprintf(stderr, "%s: %d (cpu: %d)\n", __func__, ret, cpu); return ret; } -int add_msr_perf_counter_(int cpu, struct msr_counter_info_t *cci, const struct msr_counter_arch_info *cai) +int add_msr_perf_counter(int cpu, struct msr_counter_info_t *cci, const struct msr_counter_arch_info *cai) { + int ret = -1; + if (no_perf) return -1; + if (!cai->perf_name) + return -1; + const unsigned int type = read_perf_type(cai->perf_subsys); const unsigned int config = read_perf_config(cai->perf_subsys, cai->perf_name); - const int fd_counter = open_perf_counter(cpu, type, config, cci->fd_perf, PERF_FORMAT_GROUP); + ret = open_perf_counter(cpu, type, config, cci->fd_perf, PERF_FORMAT_GROUP); - if (fd_counter == -1) - return -1; + if (ret == -1) + goto end; /* If it's the first counter opened, make it a group descriptor */ if (cci->fd_perf == -1) - cci->fd_perf = fd_counter; - - return fd_counter; -} - -int add_msr_perf_counter(int cpu, struct msr_counter_info_t *cci, const struct msr_counter_arch_info *cai) -{ - int ret = add_msr_perf_counter_(cpu, cci, cai); + cci->fd_perf = ret; +end: if (debug) fprintf(stderr, "%s: %s/%s: %d (cpu: %d)\n", __func__, cai->perf_subsys, cai->perf_name, ret, cpu); @@ -8064,12 +8319,12 @@ void msr_perf_init_(void) if (cai->needed) { /* Use perf API for this counter */ - if (!no_perf && cai->perf_name && add_msr_perf_counter(cpu, cci, cai) != -1) { + if (add_msr_perf_counter(cpu, cci, cai) != -1) { cci->source[cai->rci_index] = COUNTER_SOURCE_PERF; cai->present = true; /* User MSR for this counter */ - } else if (!no_msr && cai->msr && probe_rapl_msr(cpu, cai->msr, cai->rci_index) == 0) { + } else if (add_msr_counter(cpu, cai->msr) >= 0) { cci->source[cai->rci_index] = COUNTER_SOURCE_MSR; cci->msr[cai->rci_index] = cai->msr; cci->msr_mask[cai->rci_index] = cai->msr_mask; @@ -8177,13 +8432,13 @@ void cstate_perf_init_(bool soft_c1) if (counter_needed && counter_supported) { /* Use perf API for this counter */ - if (!no_perf && cai->perf_name && add_cstate_perf_counter(cpu, cci, cai) != -1) { + if (add_cstate_perf_counter(cpu, cci, cai) != -1) { cci->source[cai->rci_index] = COUNTER_SOURCE_PERF; /* User MSR for this counter */ - } else if (!no_msr && cai->msr && pkg_cstate_limit >= cai->pkg_cstate_limit - && probe_rapl_msr(cpu, cai->msr, cai->rci_index) == 0) { + } else if (pkg_cstate_limit >= cai->pkg_cstate_limit + && add_msr_counter(cpu, cai->msr) >= 0) { cci->source[cai->rci_index] = COUNTER_SOURCE_MSR; cci->msr[cai->rci_index] = cai->msr; } @@ -9044,15 +9299,14 @@ int added_perf_counters_init_(struct perf_counter_info *pinfo) perf_device = "cpu_atom"; break; - default: /* Don't change, we will probably fail and report a problem soon. */ + default: /* Don't change, we will probably fail and report a problem soon. */ break; } } perf_type = read_perf_type(perf_device); if (perf_type == (unsigned int)-1) { - warnx("%s: perf/%s/%s: failed to read %s", - __func__, perf_device, pinfo->event, "type"); + warnx("%s: perf/%s/%s: failed to read %s", __func__, perf_device, pinfo->event, "type"); continue; } @@ -9154,7 +9408,7 @@ struct pmt_mmio *pmt_mmio_open(unsigned int target_guid) return NULL; } - for ( ; entry != NULL; entry = pmt_diriter_next(&pmt_iter)) { + for (; entry != NULL; entry = pmt_diriter_next(&pmt_iter)) { if (fstatat(dirfd(pmt_iter.dir), entry->d_name, &st, 0) == -1) break; @@ -9594,7 +9848,7 @@ int get_and_dump_counters(void) void print_version() { - fprintf(outf, "turbostat version 2025.04.06 - Len Brown <lenb@kernel.org>\n"); + fprintf(outf, "turbostat version 2025.06.08 - Len Brown <lenb@kernel.org>\n"); } #define COMMAND_LINE_SIZE 2048 @@ -10050,7 +10304,7 @@ void parse_add_command_pmt(char *add_command) unsigned int lsb; unsigned int msb; unsigned int guid; - unsigned int seq = 0; /* By default, pick first file in a sequence with a given GUID. */ + unsigned int seq = 0; /* By default, pick first file in a sequence with a given GUID. */ unsigned int domain_id; enum counter_scope scope = 0; enum pmt_datatype type = PMT_TYPE_RAW; diff --git a/tools/testing/selftests/mm/ksm_tests.c b/tools/testing/selftests/mm/ksm_tests.c index dcdd5bb20f3d..e80deac1436b 100644 --- a/tools/testing/selftests/mm/ksm_tests.c +++ b/tools/testing/selftests/mm/ksm_tests.c @@ -58,40 +58,12 @@ int debug; static int ksm_write_sysfs(const char *file_path, unsigned long val) { - FILE *f = fopen(file_path, "w"); - - if (!f) { - fprintf(stderr, "f %s\n", file_path); - perror("fopen"); - return 1; - } - if (fprintf(f, "%lu", val) < 0) { - perror("fprintf"); - fclose(f); - return 1; - } - fclose(f); - - return 0; + return write_sysfs(file_path, val); } static int ksm_read_sysfs(const char *file_path, unsigned long *val) { - FILE *f = fopen(file_path, "r"); - - if (!f) { - fprintf(stderr, "f %s\n", file_path); - perror("fopen"); - return 1; - } - if (fscanf(f, "%lu", val) != 1) { - perror("fscanf"); - fclose(f); - return 1; - } - fclose(f); - - return 0; + return read_sysfs(file_path, val); } static void ksm_print_sysfs(void) diff --git a/tools/testing/selftests/mm/merge.c b/tools/testing/selftests/mm/merge.c index c76646cdf6e6..bbae66fc5038 100644 --- a/tools/testing/selftests/mm/merge.c +++ b/tools/testing/selftests/mm/merge.c @@ -2,11 +2,14 @@ #define _GNU_SOURCE #include "../kselftest_harness.h" +#include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/mman.h> +#include <sys/syscall.h> #include <sys/wait.h> +#include <linux/perf_event.h> #include "vm_util.h" FIXTURE(merge) @@ -452,4 +455,44 @@ TEST_F(merge, forked_source_vma) ASSERT_EQ(procmap->query.vma_end, (unsigned long)ptr2 + 5 * page_size); } +TEST_F(merge, handle_uprobe_upon_merged_vma) +{ + const size_t attr_sz = sizeof(struct perf_event_attr); + unsigned int page_size = self->page_size; + const char *probe_file = "./foo"; + char *carveout = self->carveout; + struct perf_event_attr attr; + unsigned long type; + void *ptr1, *ptr2; + int fd; + + fd = open(probe_file, O_RDWR|O_CREAT, 0600); + ASSERT_GE(fd, 0); + + ASSERT_EQ(ftruncate(fd, page_size), 0); + ASSERT_EQ(read_sysfs("/sys/bus/event_source/devices/uprobe/type", &type), 0); + + memset(&attr, 0, attr_sz); + attr.size = attr_sz; + attr.type = type; + attr.config1 = (__u64)(long)probe_file; + attr.config2 = 0x0; + + ASSERT_GE(syscall(__NR_perf_event_open, &attr, 0, -1, -1, 0), 0); + + ptr1 = mmap(&carveout[page_size], 10 * page_size, PROT_EXEC, + MAP_PRIVATE | MAP_FIXED, fd, 0); + ASSERT_NE(ptr1, MAP_FAILED); + + ptr2 = mremap(ptr1, page_size, 2 * page_size, + MREMAP_MAYMOVE | MREMAP_FIXED, ptr1 + 5 * page_size); + ASSERT_NE(ptr2, MAP_FAILED); + + ASSERT_NE(mremap(ptr2, page_size, page_size, + MREMAP_MAYMOVE | MREMAP_FIXED, ptr1), MAP_FAILED); + + close(fd); + remove(probe_file); +} + TEST_HARNESS_MAIN diff --git a/tools/testing/selftests/mm/thuge-gen.c b/tools/testing/selftests/mm/thuge-gen.c index a41bc1234b37..95b6f043a3cb 100644 --- a/tools/testing/selftests/mm/thuge-gen.c +++ b/tools/testing/selftests/mm/thuge-gen.c @@ -77,7 +77,7 @@ void show(unsigned long ps) system(buf); } -unsigned long read_sysfs(int warn, char *fmt, ...) +unsigned long thuge_read_sysfs(int warn, char *fmt, ...) { char *line = NULL; size_t linelen = 0; @@ -106,7 +106,7 @@ unsigned long read_sysfs(int warn, char *fmt, ...) unsigned long read_free(unsigned long ps) { - return read_sysfs(ps != getpagesize(), + return thuge_read_sysfs(ps != getpagesize(), "/sys/kernel/mm/hugepages/hugepages-%lukB/free_hugepages", ps >> 10); } @@ -195,7 +195,7 @@ void find_pagesizes(void) } globfree(&g); - if (read_sysfs(0, "/proc/sys/kernel/shmmax") < NUM_PAGES * largest) + if (thuge_read_sysfs(0, "/proc/sys/kernel/shmmax") < NUM_PAGES * largest) ksft_exit_fail_msg("Please do echo %lu > /proc/sys/kernel/shmmax", largest * NUM_PAGES); diff --git a/tools/testing/selftests/mm/vm_util.c b/tools/testing/selftests/mm/vm_util.c index 61d7bf1f8c62..5492e3f784df 100644 --- a/tools/testing/selftests/mm/vm_util.c +++ b/tools/testing/selftests/mm/vm_util.c @@ -486,3 +486,41 @@ int close_procmap(struct procmap_fd *procmap) { return close(procmap->fd); } + +int write_sysfs(const char *file_path, unsigned long val) +{ + FILE *f = fopen(file_path, "w"); + + if (!f) { + fprintf(stderr, "f %s\n", file_path); + perror("fopen"); + return 1; + } + if (fprintf(f, "%lu", val) < 0) { + perror("fprintf"); + fclose(f); + return 1; + } + fclose(f); + + return 0; +} + +int read_sysfs(const char *file_path, unsigned long *val) +{ + FILE *f = fopen(file_path, "r"); + + if (!f) { + fprintf(stderr, "f %s\n", file_path); + perror("fopen"); + return 1; + } + if (fscanf(f, "%lu", val) != 1) { + perror("fscanf"); + fclose(f); + return 1; + } + fclose(f); + + return 0; +} diff --git a/tools/testing/selftests/mm/vm_util.h b/tools/testing/selftests/mm/vm_util.h index adb5d294a220..b8136d12a0f8 100644 --- a/tools/testing/selftests/mm/vm_util.h +++ b/tools/testing/selftests/mm/vm_util.h @@ -88,6 +88,8 @@ int open_procmap(pid_t pid, struct procmap_fd *procmap_out); int query_procmap(struct procmap_fd *procmap); bool find_vma_procmap(struct procmap_fd *procmap, void *address); int close_procmap(struct procmap_fd *procmap); +int write_sysfs(const char *file_path, unsigned long val); +int read_sysfs(const char *file_path, unsigned long *val); static inline int open_self_procmap(struct procmap_fd *procmap_out) { diff --git a/tools/testing/selftests/mount_setattr/mount_setattr_test.c b/tools/testing/selftests/mount_setattr/mount_setattr_test.c index 8b378c91debf..b1e4618399be 100644 --- a/tools/testing/selftests/mount_setattr/mount_setattr_test.c +++ b/tools/testing/selftests/mount_setattr/mount_setattr_test.c @@ -2079,24 +2079,9 @@ TEST_F(mount_setattr, detached_tree_propagation) * means that the device information will be different for any * statx() that was taken from /mnt/A before the mount compared * to one after the mount. - * - * Since we already now that the device information between the - * stx1 and stx2 samples are identical we also now that stx2 and - * stx3 device information will necessarily differ. */ ASSERT_NE(stx1.stx_dev_minor, stx3.stx_dev_minor); - - /* - * If mount propagation worked correctly then the tmpfs mount - * that was created after the mount namespace was unshared will - * have propagated onto /mnt/A in the detached mount tree. - * - * Verify that the device information for stx3 and stx4 are - * identical. It is already established that stx3 is different - * from both stx1 and stx2 sampled before the tmpfs mount was - * done so if stx3 and stx4 are identical the proof is done. - */ - ASSERT_EQ(stx3.stx_dev_minor, stx4.stx_dev_minor); + ASSERT_EQ(stx1.stx_dev_minor, stx4.stx_dev_minor); EXPECT_EQ(close(fd_tree), 0); } diff --git a/tools/testing/selftests/ublk/Makefile b/tools/testing/selftests/ublk/Makefile index 4dde8838261d..5d7f4ecfb816 100644 --- a/tools/testing/selftests/ublk/Makefile +++ b/tools/testing/selftests/ublk/Makefile @@ -19,6 +19,7 @@ TEST_PROGS += test_generic_08.sh TEST_PROGS += test_generic_09.sh TEST_PROGS += test_generic_10.sh TEST_PROGS += test_generic_11.sh +TEST_PROGS += test_generic_12.sh TEST_PROGS += test_null_01.sh TEST_PROGS += test_null_02.sh diff --git a/tools/testing/selftests/ublk/fault_inject.c b/tools/testing/selftests/ublk/fault_inject.c index 5421774d7867..6e60f7d97125 100644 --- a/tools/testing/selftests/ublk/fault_inject.c +++ b/tools/testing/selftests/ublk/fault_inject.c @@ -46,9 +46,9 @@ static int ublk_fault_inject_queue_io(struct ublk_queue *q, int tag) .tv_nsec = (long long)q->dev->private_data, }; - ublk_queue_alloc_sqes(q, &sqe, 1); + ublk_io_alloc_sqes(ublk_get_io(q, tag), &sqe, 1); io_uring_prep_timeout(sqe, &ts, 1, 0); - sqe->user_data = build_user_data(tag, ublksrv_get_op(iod), 0, 1); + sqe->user_data = build_user_data(tag, ublksrv_get_op(iod), 0, q->q_id, 1); ublk_queued_tgt_io(q, tag, 1); diff --git a/tools/testing/selftests/ublk/file_backed.c b/tools/testing/selftests/ublk/file_backed.c index 509842df9bee..cfa59b631693 100644 --- a/tools/testing/selftests/ublk/file_backed.c +++ b/tools/testing/selftests/ublk/file_backed.c @@ -18,11 +18,11 @@ static int loop_queue_flush_io(struct ublk_queue *q, const struct ublksrv_io_des unsigned ublk_op = ublksrv_get_op(iod); struct io_uring_sqe *sqe[1]; - ublk_queue_alloc_sqes(q, sqe, 1); + ublk_io_alloc_sqes(ublk_get_io(q, tag), sqe, 1); io_uring_prep_fsync(sqe[0], 1 /*fds[1]*/, IORING_FSYNC_DATASYNC); io_uring_sqe_set_flags(sqe[0], IOSQE_FIXED_FILE); /* bit63 marks us as tgt io */ - sqe[0]->user_data = build_user_data(tag, ublk_op, 0, 1); + sqe[0]->user_data = build_user_data(tag, ublk_op, 0, q->q_id, 1); return 1; } @@ -36,7 +36,7 @@ static int loop_queue_tgt_rw_io(struct ublk_queue *q, const struct ublksrv_io_de void *addr = (zc | auto_zc) ? NULL : (void *)iod->addr; if (!zc || auto_zc) { - ublk_queue_alloc_sqes(q, sqe, 1); + ublk_io_alloc_sqes(ublk_get_io(q, tag), sqe, 1); if (!sqe[0]) return -ENOMEM; @@ -48,26 +48,26 @@ static int loop_queue_tgt_rw_io(struct ublk_queue *q, const struct ublksrv_io_de sqe[0]->buf_index = tag; io_uring_sqe_set_flags(sqe[0], IOSQE_FIXED_FILE); /* bit63 marks us as tgt io */ - sqe[0]->user_data = build_user_data(tag, ublk_op, 0, 1); + sqe[0]->user_data = build_user_data(tag, ublk_op, 0, q->q_id, 1); return 1; } - ublk_queue_alloc_sqes(q, sqe, 3); + ublk_io_alloc_sqes(ublk_get_io(q, tag), sqe, 3); - io_uring_prep_buf_register(sqe[0], 0, tag, q->q_id, tag); + io_uring_prep_buf_register(sqe[0], 0, tag, q->q_id, ublk_get_io(q, tag)->buf_index); sqe[0]->flags |= IOSQE_CQE_SKIP_SUCCESS | IOSQE_IO_HARDLINK; sqe[0]->user_data = build_user_data(tag, - ublk_cmd_op_nr(sqe[0]->cmd_op), 0, 1); + ublk_cmd_op_nr(sqe[0]->cmd_op), 0, q->q_id, 1); io_uring_prep_rw(op, sqe[1], 1 /*fds[1]*/, 0, iod->nr_sectors << 9, iod->start_sector << 9); sqe[1]->buf_index = tag; sqe[1]->flags |= IOSQE_FIXED_FILE | IOSQE_IO_HARDLINK; - sqe[1]->user_data = build_user_data(tag, ublk_op, 0, 1); + sqe[1]->user_data = build_user_data(tag, ublk_op, 0, q->q_id, 1); - io_uring_prep_buf_unregister(sqe[2], 0, tag, q->q_id, tag); - sqe[2]->user_data = build_user_data(tag, ublk_cmd_op_nr(sqe[2]->cmd_op), 0, 1); + io_uring_prep_buf_unregister(sqe[2], 0, tag, q->q_id, ublk_get_io(q, tag)->buf_index); + sqe[2]->user_data = build_user_data(tag, ublk_cmd_op_nr(sqe[2]->cmd_op), 0, q->q_id, 1); return 2; } diff --git a/tools/testing/selftests/ublk/kublk.c b/tools/testing/selftests/ublk/kublk.c index b5131a000795..e2d2042810d4 100644 --- a/tools/testing/selftests/ublk/kublk.c +++ b/tools/testing/selftests/ublk/kublk.c @@ -348,8 +348,8 @@ static void ublk_ctrl_dump(struct ublk_dev *dev) for (i = 0; i < info->nr_hw_queues; i++) { ublk_print_cpu_set(&affinity[i], buf, sizeof(buf)); - printf("\tqueue %u: tid %d affinity(%s)\n", - i, dev->q[i].tid, buf); + printf("\tqueue %u: affinity(%s)\n", + i, buf); } free(affinity); } @@ -412,16 +412,6 @@ static void ublk_queue_deinit(struct ublk_queue *q) int i; int nr_ios = q->q_depth; - io_uring_unregister_buffers(&q->ring); - - io_uring_unregister_ring_fd(&q->ring); - - if (q->ring.ring_fd > 0) { - io_uring_unregister_files(&q->ring); - close(q->ring.ring_fd); - q->ring.ring_fd = -1; - } - if (q->io_cmd_buf) munmap(q->io_cmd_buf, ublk_queue_cmd_buf_sz(q)); @@ -429,20 +419,30 @@ static void ublk_queue_deinit(struct ublk_queue *q) free(q->ios[i].buf_addr); } +static void ublk_thread_deinit(struct ublk_thread *t) +{ + io_uring_unregister_buffers(&t->ring); + + io_uring_unregister_ring_fd(&t->ring); + + if (t->ring.ring_fd > 0) { + io_uring_unregister_files(&t->ring); + close(t->ring.ring_fd); + t->ring.ring_fd = -1; + } +} + static int ublk_queue_init(struct ublk_queue *q, unsigned extra_flags) { struct ublk_dev *dev = q->dev; int depth = dev->dev_info.queue_depth; - int i, ret = -1; + int i; int cmd_buf_size, io_buf_size; unsigned long off; - int ring_depth = dev->tgt.sq_depth, cq_depth = dev->tgt.cq_depth; q->tgt_ops = dev->tgt.ops; q->state = 0; q->q_depth = depth; - q->cmd_inflight = 0; - q->tid = gettid(); if (dev->dev_info.flags & (UBLK_F_SUPPORT_ZERO_COPY | UBLK_F_AUTO_BUF_REG)) { q->state |= UBLKSRV_NO_BUF; @@ -467,6 +467,7 @@ static int ublk_queue_init(struct ublk_queue *q, unsigned extra_flags) for (i = 0; i < q->q_depth; i++) { q->ios[i].buf_addr = NULL; q->ios[i].flags = UBLKSRV_NEED_FETCH_RQ | UBLKSRV_IO_FREE; + q->ios[i].tag = i; if (q->state & UBLKSRV_NO_BUF) continue; @@ -479,39 +480,57 @@ static int ublk_queue_init(struct ublk_queue *q, unsigned extra_flags) } } - ret = ublk_setup_ring(&q->ring, ring_depth, cq_depth, + return 0; + fail: + ublk_queue_deinit(q); + ublk_err("ublk dev %d queue %d failed\n", + dev->dev_info.dev_id, q->q_id); + return -ENOMEM; +} + +static int ublk_thread_init(struct ublk_thread *t) +{ + struct ublk_dev *dev = t->dev; + int ring_depth = dev->tgt.sq_depth, cq_depth = dev->tgt.cq_depth; + int ret; + + ret = ublk_setup_ring(&t->ring, ring_depth, cq_depth, IORING_SETUP_COOP_TASKRUN | IORING_SETUP_SINGLE_ISSUER | IORING_SETUP_DEFER_TASKRUN); if (ret < 0) { - ublk_err("ublk dev %d queue %d setup io_uring failed %d\n", - q->dev->dev_info.dev_id, q->q_id, ret); + ublk_err("ublk dev %d thread %d setup io_uring failed %d\n", + dev->dev_info.dev_id, t->idx, ret); goto fail; } if (dev->dev_info.flags & (UBLK_F_SUPPORT_ZERO_COPY | UBLK_F_AUTO_BUF_REG)) { - ret = io_uring_register_buffers_sparse(&q->ring, q->q_depth); + unsigned nr_ios = dev->dev_info.queue_depth * dev->dev_info.nr_hw_queues; + unsigned max_nr_ios_per_thread = nr_ios / dev->nthreads; + max_nr_ios_per_thread += !!(nr_ios % dev->nthreads); + ret = io_uring_register_buffers_sparse( + &t->ring, max_nr_ios_per_thread); if (ret) { - ublk_err("ublk dev %d queue %d register spare buffers failed %d", - dev->dev_info.dev_id, q->q_id, ret); + ublk_err("ublk dev %d thread %d register spare buffers failed %d", + dev->dev_info.dev_id, t->idx, ret); goto fail; } } - io_uring_register_ring_fd(&q->ring); + io_uring_register_ring_fd(&t->ring); - ret = io_uring_register_files(&q->ring, dev->fds, dev->nr_fds); + ret = io_uring_register_files(&t->ring, dev->fds, dev->nr_fds); if (ret) { - ublk_err("ublk dev %d queue %d register files failed %d\n", - q->dev->dev_info.dev_id, q->q_id, ret); + ublk_err("ublk dev %d thread %d register files failed %d\n", + t->dev->dev_info.dev_id, t->idx, ret); goto fail; } return 0; - fail: - ublk_queue_deinit(q); - ublk_err("ublk dev %d queue %d failed\n", - dev->dev_info.dev_id, q->q_id); +fail: + ublk_thread_deinit(t); + ublk_err("ublk dev %d thread %d init failed\n", + dev->dev_info.dev_id, t->idx); return -ENOMEM; } @@ -562,7 +581,7 @@ static void ublk_set_auto_buf_reg(const struct ublk_queue *q, if (q->tgt_ops->buf_index) buf.index = q->tgt_ops->buf_index(q, tag); else - buf.index = tag; + buf.index = q->ios[tag].buf_index; if (q->state & UBLKSRV_AUTO_BUF_REG_FALLBACK) buf.flags = UBLK_AUTO_BUF_REG_FALLBACK; @@ -570,8 +589,10 @@ static void ublk_set_auto_buf_reg(const struct ublk_queue *q, sqe->addr = ublk_auto_buf_reg_to_sqe_addr(&buf); } -int ublk_queue_io_cmd(struct ublk_queue *q, struct ublk_io *io, unsigned tag) +int ublk_queue_io_cmd(struct ublk_io *io) { + struct ublk_thread *t = io->t; + struct ublk_queue *q = ublk_io_to_queue(io); struct ublksrv_io_cmd *cmd; struct io_uring_sqe *sqe[1]; unsigned int cmd_op = 0; @@ -596,13 +617,13 @@ int ublk_queue_io_cmd(struct ublk_queue *q, struct ublk_io *io, unsigned tag) else if (io->flags & UBLKSRV_NEED_FETCH_RQ) cmd_op = UBLK_U_IO_FETCH_REQ; - if (io_uring_sq_space_left(&q->ring) < 1) - io_uring_submit(&q->ring); + if (io_uring_sq_space_left(&t->ring) < 1) + io_uring_submit(&t->ring); - ublk_queue_alloc_sqes(q, sqe, 1); + ublk_io_alloc_sqes(io, sqe, 1); if (!sqe[0]) { - ublk_err("%s: run out of sqe %d, tag %d\n", - __func__, q->q_id, tag); + ublk_err("%s: run out of sqe. thread %u, tag %d\n", + __func__, t->idx, io->tag); return -1; } @@ -617,7 +638,7 @@ int ublk_queue_io_cmd(struct ublk_queue *q, struct ublk_io *io, unsigned tag) sqe[0]->opcode = IORING_OP_URING_CMD; sqe[0]->flags = IOSQE_FIXED_FILE; sqe[0]->rw_flags = 0; - cmd->tag = tag; + cmd->tag = io->tag; cmd->q_id = q->q_id; if (!(q->state & UBLKSRV_NO_BUF)) cmd->addr = (__u64) (uintptr_t) io->buf_addr; @@ -625,37 +646,72 @@ int ublk_queue_io_cmd(struct ublk_queue *q, struct ublk_io *io, unsigned tag) cmd->addr = 0; if (q->state & UBLKSRV_AUTO_BUF_REG) - ublk_set_auto_buf_reg(q, sqe[0], tag); + ublk_set_auto_buf_reg(q, sqe[0], io->tag); - user_data = build_user_data(tag, _IOC_NR(cmd_op), 0, 0); + user_data = build_user_data(io->tag, _IOC_NR(cmd_op), 0, q->q_id, 0); io_uring_sqe_set_data64(sqe[0], user_data); io->flags = 0; - q->cmd_inflight += 1; + t->cmd_inflight += 1; - ublk_dbg(UBLK_DBG_IO_CMD, "%s: (qid %d tag %u cmd_op %u) iof %x stopping %d\n", - __func__, q->q_id, tag, cmd_op, - io->flags, !!(q->state & UBLKSRV_QUEUE_STOPPING)); + ublk_dbg(UBLK_DBG_IO_CMD, "%s: (thread %u qid %d tag %u cmd_op %u) iof %x stopping %d\n", + __func__, t->idx, q->q_id, io->tag, cmd_op, + io->flags, !!(t->state & UBLKSRV_THREAD_STOPPING)); return 1; } -static void ublk_submit_fetch_commands(struct ublk_queue *q) +static void ublk_submit_fetch_commands(struct ublk_thread *t) { - int i = 0; + struct ublk_queue *q; + struct ublk_io *io; + int i = 0, j = 0; - for (i = 0; i < q->q_depth; i++) - ublk_queue_io_cmd(q, &q->ios[i], i); + if (t->dev->per_io_tasks) { + /* + * Lexicographically order all the (qid,tag) pairs, with + * qid taking priority (so (1,0) > (0,1)). Then make + * this thread the daemon for every Nth entry in this + * list (N is the number of threads), starting at this + * thread's index. This ensures that each queue is + * handled by as many ublk server threads as possible, + * so that load that is concentrated on one or a few + * queues can make use of all ublk server threads. + */ + const struct ublksrv_ctrl_dev_info *dinfo = &t->dev->dev_info; + int nr_ios = dinfo->nr_hw_queues * dinfo->queue_depth; + for (i = t->idx; i < nr_ios; i += t->dev->nthreads) { + int q_id = i / dinfo->queue_depth; + int tag = i % dinfo->queue_depth; + q = &t->dev->q[q_id]; + io = &q->ios[tag]; + io->t = t; + io->buf_index = j++; + ublk_queue_io_cmd(io); + } + } else { + /* + * Service exclusively the queue whose q_id matches our + * thread index. + */ + struct ublk_queue *q = &t->dev->q[t->idx]; + for (i = 0; i < q->q_depth; i++) { + io = &q->ios[i]; + io->t = t; + io->buf_index = i; + ublk_queue_io_cmd(io); + } + } } -static int ublk_queue_is_idle(struct ublk_queue *q) +static int ublk_thread_is_idle(struct ublk_thread *t) { - return !io_uring_sq_ready(&q->ring) && !q->io_inflight; + return !io_uring_sq_ready(&t->ring) && !t->io_inflight; } -static int ublk_queue_is_done(struct ublk_queue *q) +static int ublk_thread_is_done(struct ublk_thread *t) { - return (q->state & UBLKSRV_QUEUE_STOPPING) && ublk_queue_is_idle(q); + return (t->state & UBLKSRV_THREAD_STOPPING) && ublk_thread_is_idle(t); } static inline void ublksrv_handle_tgt_cqe(struct ublk_queue *q, @@ -673,14 +729,16 @@ static inline void ublksrv_handle_tgt_cqe(struct ublk_queue *q, q->tgt_ops->tgt_io_done(q, tag, cqe); } -static void ublk_handle_cqe(struct io_uring *r, +static void ublk_handle_cqe(struct ublk_thread *t, struct io_uring_cqe *cqe, void *data) { - struct ublk_queue *q = container_of(r, struct ublk_queue, ring); + struct ublk_dev *dev = t->dev; + unsigned q_id = user_data_to_q_id(cqe->user_data); + struct ublk_queue *q = &dev->q[q_id]; unsigned tag = user_data_to_tag(cqe->user_data); unsigned cmd_op = user_data_to_op(cqe->user_data); int fetch = (cqe->res != UBLK_IO_RES_ABORT) && - !(q->state & UBLKSRV_QUEUE_STOPPING); + !(t->state & UBLKSRV_THREAD_STOPPING); struct ublk_io *io; if (cqe->res < 0 && cqe->res != -ENODEV) @@ -691,7 +749,7 @@ static void ublk_handle_cqe(struct io_uring *r, __func__, cqe->res, q->q_id, tag, cmd_op, is_target_io(cqe->user_data), user_data_to_tgt_data(cqe->user_data), - (q->state & UBLKSRV_QUEUE_STOPPING)); + (t->state & UBLKSRV_THREAD_STOPPING)); /* Don't retrieve io in case of target io */ if (is_target_io(cqe->user_data)) { @@ -700,10 +758,10 @@ static void ublk_handle_cqe(struct io_uring *r, } io = &q->ios[tag]; - q->cmd_inflight--; + t->cmd_inflight--; if (!fetch) { - q->state |= UBLKSRV_QUEUE_STOPPING; + t->state |= UBLKSRV_THREAD_STOPPING; io->flags &= ~UBLKSRV_NEED_FETCH_RQ; } @@ -713,7 +771,7 @@ static void ublk_handle_cqe(struct io_uring *r, q->tgt_ops->queue_io(q, tag); } else if (cqe->res == UBLK_IO_RES_NEED_GET_DATA) { io->flags |= UBLKSRV_NEED_GET_DATA | UBLKSRV_IO_FREE; - ublk_queue_io_cmd(q, io, tag); + ublk_queue_io_cmd(io); } else { /* * COMMIT_REQ will be completed immediately since no fetching @@ -727,92 +785,93 @@ static void ublk_handle_cqe(struct io_uring *r, } } -static int ublk_reap_events_uring(struct io_uring *r) +static int ublk_reap_events_uring(struct ublk_thread *t) { struct io_uring_cqe *cqe; unsigned head; int count = 0; - io_uring_for_each_cqe(r, head, cqe) { - ublk_handle_cqe(r, cqe, NULL); + io_uring_for_each_cqe(&t->ring, head, cqe) { + ublk_handle_cqe(t, cqe, NULL); count += 1; } - io_uring_cq_advance(r, count); + io_uring_cq_advance(&t->ring, count); return count; } -static int ublk_process_io(struct ublk_queue *q) +static int ublk_process_io(struct ublk_thread *t) { int ret, reapped; - ublk_dbg(UBLK_DBG_QUEUE, "dev%d-q%d: to_submit %d inflight cmd %u stopping %d\n", - q->dev->dev_info.dev_id, - q->q_id, io_uring_sq_ready(&q->ring), - q->cmd_inflight, - (q->state & UBLKSRV_QUEUE_STOPPING)); + ublk_dbg(UBLK_DBG_THREAD, "dev%d-t%u: to_submit %d inflight cmd %u stopping %d\n", + t->dev->dev_info.dev_id, + t->idx, io_uring_sq_ready(&t->ring), + t->cmd_inflight, + (t->state & UBLKSRV_THREAD_STOPPING)); - if (ublk_queue_is_done(q)) + if (ublk_thread_is_done(t)) return -ENODEV; - ret = io_uring_submit_and_wait(&q->ring, 1); - reapped = ublk_reap_events_uring(&q->ring); + ret = io_uring_submit_and_wait(&t->ring, 1); + reapped = ublk_reap_events_uring(t); - ublk_dbg(UBLK_DBG_QUEUE, "submit result %d, reapped %d stop %d idle %d\n", - ret, reapped, (q->state & UBLKSRV_QUEUE_STOPPING), - (q->state & UBLKSRV_QUEUE_IDLE)); + ublk_dbg(UBLK_DBG_THREAD, "submit result %d, reapped %d stop %d idle %d\n", + ret, reapped, (t->state & UBLKSRV_THREAD_STOPPING), + (t->state & UBLKSRV_THREAD_IDLE)); return reapped; } -static void ublk_queue_set_sched_affinity(const struct ublk_queue *q, +static void ublk_thread_set_sched_affinity(const struct ublk_thread *t, cpu_set_t *cpuset) { if (sched_setaffinity(0, sizeof(*cpuset), cpuset) < 0) - ublk_err("ublk dev %u queue %u set affinity failed", - q->dev->dev_info.dev_id, q->q_id); + ublk_err("ublk dev %u thread %u set affinity failed", + t->dev->dev_info.dev_id, t->idx); } -struct ublk_queue_info { - struct ublk_queue *q; - sem_t *queue_sem; +struct ublk_thread_info { + struct ublk_dev *dev; + unsigned idx; + sem_t *ready; cpu_set_t *affinity; - unsigned char auto_zc_fallback; }; static void *ublk_io_handler_fn(void *data) { - struct ublk_queue_info *info = data; - struct ublk_queue *q = info->q; - int dev_id = q->dev->dev_info.dev_id; - unsigned extra_flags = 0; + struct ublk_thread_info *info = data; + struct ublk_thread *t = &info->dev->threads[info->idx]; + int dev_id = info->dev->dev_info.dev_id; int ret; - if (info->auto_zc_fallback) - extra_flags = UBLKSRV_AUTO_BUF_REG_FALLBACK; + t->dev = info->dev; + t->idx = info->idx; - ret = ublk_queue_init(q, extra_flags); + ret = ublk_thread_init(t); if (ret) { - ublk_err("ublk dev %d queue %d init queue failed\n", - dev_id, q->q_id); + ublk_err("ublk dev %d thread %u init failed\n", + dev_id, t->idx); return NULL; } /* IO perf is sensitive with queue pthread affinity on NUMA machine*/ - ublk_queue_set_sched_affinity(q, info->affinity); - sem_post(info->queue_sem); + if (info->affinity) + ublk_thread_set_sched_affinity(t, info->affinity); + sem_post(info->ready); - ublk_dbg(UBLK_DBG_QUEUE, "tid %d: ublk dev %d queue %d started\n", - q->tid, dev_id, q->q_id); + ublk_dbg(UBLK_DBG_THREAD, "tid %d: ublk dev %d thread %u started\n", + gettid(), dev_id, t->idx); /* submit all io commands to ublk driver */ - ublk_submit_fetch_commands(q); + ublk_submit_fetch_commands(t); do { - if (ublk_process_io(q) < 0) + if (ublk_process_io(t) < 0) break; } while (1); - ublk_dbg(UBLK_DBG_QUEUE, "ublk dev %d queue %d exited\n", dev_id, q->q_id); - ublk_queue_deinit(q); + ublk_dbg(UBLK_DBG_THREAD, "tid %d: ublk dev %d thread %d exiting\n", + gettid(), dev_id, t->idx); + ublk_thread_deinit(t); return NULL; } @@ -855,20 +914,20 @@ static int ublk_send_dev_event(const struct dev_ctx *ctx, struct ublk_dev *dev, static int ublk_start_daemon(const struct dev_ctx *ctx, struct ublk_dev *dev) { const struct ublksrv_ctrl_dev_info *dinfo = &dev->dev_info; - struct ublk_queue_info *qinfo; + struct ublk_thread_info *tinfo; + unsigned extra_flags = 0; cpu_set_t *affinity_buf; void *thread_ret; - sem_t queue_sem; + sem_t ready; int ret, i; ublk_dbg(UBLK_DBG_DEV, "%s enter\n", __func__); - qinfo = (struct ublk_queue_info *)calloc(sizeof(struct ublk_queue_info), - dinfo->nr_hw_queues); - if (!qinfo) + tinfo = calloc(sizeof(struct ublk_thread_info), dev->nthreads); + if (!tinfo) return -ENOMEM; - sem_init(&queue_sem, 0, 0); + sem_init(&ready, 0, 0); ret = ublk_dev_prep(ctx, dev); if (ret) return ret; @@ -877,22 +936,44 @@ static int ublk_start_daemon(const struct dev_ctx *ctx, struct ublk_dev *dev) if (ret) return ret; + if (ctx->auto_zc_fallback) + extra_flags = UBLKSRV_AUTO_BUF_REG_FALLBACK; + for (i = 0; i < dinfo->nr_hw_queues; i++) { dev->q[i].dev = dev; dev->q[i].q_id = i; - qinfo[i].q = &dev->q[i]; - qinfo[i].queue_sem = &queue_sem; - qinfo[i].affinity = &affinity_buf[i]; - qinfo[i].auto_zc_fallback = ctx->auto_zc_fallback; - pthread_create(&dev->q[i].thread, NULL, + ret = ublk_queue_init(&dev->q[i], extra_flags); + if (ret) { + ublk_err("ublk dev %d queue %d init queue failed\n", + dinfo->dev_id, i); + goto fail; + } + } + + for (i = 0; i < dev->nthreads; i++) { + tinfo[i].dev = dev; + tinfo[i].idx = i; + tinfo[i].ready = &ready; + + /* + * If threads are not tied 1:1 to queues, setting thread + * affinity based on queue affinity makes little sense. + * However, thread CPU affinity has significant impact + * on performance, so to compare fairly, we'll still set + * thread CPU affinity based on queue affinity where + * possible. + */ + if (dev->nthreads == dinfo->nr_hw_queues) + tinfo[i].affinity = &affinity_buf[i]; + pthread_create(&dev->threads[i].thread, NULL, ublk_io_handler_fn, - &qinfo[i]); + &tinfo[i]); } - for (i = 0; i < dinfo->nr_hw_queues; i++) - sem_wait(&queue_sem); - free(qinfo); + for (i = 0; i < dev->nthreads; i++) + sem_wait(&ready); + free(tinfo); free(affinity_buf); /* everything is fine now, start us */ @@ -914,9 +995,11 @@ static int ublk_start_daemon(const struct dev_ctx *ctx, struct ublk_dev *dev) ublk_send_dev_event(ctx, dev, dev->dev_info.dev_id); /* wait until we are terminated */ - for (i = 0; i < dinfo->nr_hw_queues; i++) - pthread_join(dev->q[i].thread, &thread_ret); + for (i = 0; i < dev->nthreads; i++) + pthread_join(dev->threads[i].thread, &thread_ret); fail: + for (i = 0; i < dinfo->nr_hw_queues; i++) + ublk_queue_deinit(&dev->q[i]); ublk_dev_unprep(dev); ublk_dbg(UBLK_DBG_DEV, "%s exit\n", __func__); @@ -1022,13 +1105,14 @@ wait: static int __cmd_dev_add(const struct dev_ctx *ctx) { + unsigned nthreads = ctx->nthreads; unsigned nr_queues = ctx->nr_hw_queues; const char *tgt_type = ctx->tgt_type; unsigned depth = ctx->queue_depth; __u64 features; const struct ublk_tgt_ops *ops; struct ublksrv_ctrl_dev_info *info; - struct ublk_dev *dev; + struct ublk_dev *dev = NULL; int dev_id = ctx->dev_id; int ret, i; @@ -1036,29 +1120,55 @@ static int __cmd_dev_add(const struct dev_ctx *ctx) if (!ops) { ublk_err("%s: no such tgt type, type %s\n", __func__, tgt_type); - return -ENODEV; + ret = -ENODEV; + goto fail; } if (nr_queues > UBLK_MAX_QUEUES || depth > UBLK_QUEUE_DEPTH) { ublk_err("%s: invalid nr_queues or depth queues %u depth %u\n", __func__, nr_queues, depth); - return -EINVAL; + ret = -EINVAL; + goto fail; + } + + /* default to 1:1 threads:queues if nthreads is unspecified */ + if (!nthreads) + nthreads = nr_queues; + + if (nthreads > UBLK_MAX_THREADS) { + ublk_err("%s: %u is too many threads (max %u)\n", + __func__, nthreads, UBLK_MAX_THREADS); + ret = -EINVAL; + goto fail; + } + + if (nthreads != nr_queues && !ctx->per_io_tasks) { + ublk_err("%s: threads %u must be same as queues %u if " + "not using per_io_tasks\n", + __func__, nthreads, nr_queues); + ret = -EINVAL; + goto fail; } dev = ublk_ctrl_init(); if (!dev) { ublk_err("%s: can't alloc dev id %d, type %s\n", __func__, dev_id, tgt_type); - return -ENOMEM; + ret = -ENOMEM; + goto fail; } /* kernel doesn't support get_features */ ret = ublk_ctrl_get_features(dev, &features); - if (ret < 0) - return -EINVAL; + if (ret < 0) { + ret = -EINVAL; + goto fail; + } - if (!(features & UBLK_F_CMD_IOCTL_ENCODE)) - return -ENOTSUP; + if (!(features & UBLK_F_CMD_IOCTL_ENCODE)) { + ret = -ENOTSUP; + goto fail; + } info = &dev->dev_info; info->dev_id = ctx->dev_id; @@ -1068,6 +1178,8 @@ static int __cmd_dev_add(const struct dev_ctx *ctx) if ((features & UBLK_F_QUIESCE) && (info->flags & UBLK_F_USER_RECOVERY)) info->flags |= UBLK_F_QUIESCE; + dev->nthreads = nthreads; + dev->per_io_tasks = ctx->per_io_tasks; dev->tgt.ops = ops; dev->tgt.sq_depth = depth; dev->tgt.cq_depth = depth; @@ -1097,7 +1209,8 @@ static int __cmd_dev_add(const struct dev_ctx *ctx) fail: if (ret < 0) ublk_send_dev_event(ctx, dev, -1); - ublk_ctrl_deinit(dev); + if (dev) + ublk_ctrl_deinit(dev); return ret; } @@ -1159,6 +1272,8 @@ run: shmctl(ctx->_shmid, IPC_RMID, NULL); /* wait for child and detach from it */ wait(NULL); + if (exit_code == EXIT_FAILURE) + ublk_err("%s: command failed\n", __func__); exit(exit_code); } else { exit(EXIT_FAILURE); @@ -1266,6 +1381,7 @@ static int cmd_dev_get_features(void) [const_ilog2(UBLK_F_UPDATE_SIZE)] = "UPDATE_SIZE", [const_ilog2(UBLK_F_AUTO_BUF_REG)] = "AUTO_BUF_REG", [const_ilog2(UBLK_F_QUIESCE)] = "QUIESCE", + [const_ilog2(UBLK_F_PER_IO_DAEMON)] = "PER_IO_DAEMON", }; struct ublk_dev *dev; __u64 features = 0; @@ -1360,8 +1476,10 @@ static void __cmd_create_help(char *exe, bool recovery) exe, recovery ? "recover" : "add"); printf("\t[--foreground] [--quiet] [-z] [--auto_zc] [--auto_zc_fallback] [--debug_mask mask] [-r 0|1 ] [-g]\n"); printf("\t[-e 0|1 ] [-i 0|1]\n"); + printf("\t[--nthreads threads] [--per_io_tasks]\n"); printf("\t[target options] [backfile1] [backfile2] ...\n"); printf("\tdefault: nr_queues=2(max 32), depth=128(max 1024), dev_id=-1(auto allocation)\n"); + printf("\tdefault: nthreads=nr_queues"); for (i = 0; i < sizeof(tgt_ops_list) / sizeof(tgt_ops_list[0]); i++) { const struct ublk_tgt_ops *ops = tgt_ops_list[i]; @@ -1418,6 +1536,8 @@ int main(int argc, char *argv[]) { "auto_zc", 0, NULL, 0 }, { "auto_zc_fallback", 0, NULL, 0 }, { "size", 1, NULL, 's'}, + { "nthreads", 1, NULL, 0 }, + { "per_io_tasks", 0, NULL, 0 }, { 0, 0, 0, 0 } }; const struct ublk_tgt_ops *ops = NULL; @@ -1493,6 +1613,10 @@ int main(int argc, char *argv[]) ctx.flags |= UBLK_F_AUTO_BUF_REG; if (!strcmp(longopts[option_idx].name, "auto_zc_fallback")) ctx.auto_zc_fallback = 1; + if (!strcmp(longopts[option_idx].name, "nthreads")) + ctx.nthreads = strtol(optarg, NULL, 10); + if (!strcmp(longopts[option_idx].name, "per_io_tasks")) + ctx.per_io_tasks = 1; break; case '?': /* diff --git a/tools/testing/selftests/ublk/kublk.h b/tools/testing/selftests/ublk/kublk.h index e34508bf5798..6be601536b3d 100644 --- a/tools/testing/selftests/ublk/kublk.h +++ b/tools/testing/selftests/ublk/kublk.h @@ -49,11 +49,14 @@ #define UBLKSRV_IO_IDLE_SECS 20 #define UBLK_IO_MAX_BYTES (1 << 20) -#define UBLK_MAX_QUEUES 32 +#define UBLK_MAX_QUEUES_SHIFT 5 +#define UBLK_MAX_QUEUES (1 << UBLK_MAX_QUEUES_SHIFT) +#define UBLK_MAX_THREADS_SHIFT 5 +#define UBLK_MAX_THREADS (1 << UBLK_MAX_THREADS_SHIFT) #define UBLK_QUEUE_DEPTH 1024 #define UBLK_DBG_DEV (1U << 0) -#define UBLK_DBG_QUEUE (1U << 1) +#define UBLK_DBG_THREAD (1U << 1) #define UBLK_DBG_IO_CMD (1U << 2) #define UBLK_DBG_IO (1U << 3) #define UBLK_DBG_CTRL_CMD (1U << 4) @@ -61,6 +64,7 @@ struct ublk_dev; struct ublk_queue; +struct ublk_thread; struct stripe_ctx { /* stripe */ @@ -76,6 +80,7 @@ struct dev_ctx { char tgt_type[16]; unsigned long flags; unsigned nr_hw_queues; + unsigned short nthreads; unsigned queue_depth; int dev_id; int nr_files; @@ -85,6 +90,7 @@ struct dev_ctx { unsigned int fg:1; unsigned int recovery:1; unsigned int auto_zc_fallback:1; + unsigned int per_io_tasks:1; int _evtfd; int _shmid; @@ -123,10 +129,14 @@ struct ublk_io { unsigned short flags; unsigned short refs; /* used by target code only */ + int tag; + int result; + unsigned short buf_index; unsigned short tgt_ios; void *private_data; + struct ublk_thread *t; }; struct ublk_tgt_ops { @@ -165,28 +175,39 @@ struct ublk_tgt { struct ublk_queue { int q_id; int q_depth; - unsigned int cmd_inflight; - unsigned int io_inflight; struct ublk_dev *dev; const struct ublk_tgt_ops *tgt_ops; struct ublksrv_io_desc *io_cmd_buf; - struct io_uring ring; + struct ublk_io ios[UBLK_QUEUE_DEPTH]; -#define UBLKSRV_QUEUE_STOPPING (1U << 0) -#define UBLKSRV_QUEUE_IDLE (1U << 1) #define UBLKSRV_NO_BUF (1U << 2) #define UBLKSRV_ZC (1U << 3) #define UBLKSRV_AUTO_BUF_REG (1U << 4) #define UBLKSRV_AUTO_BUF_REG_FALLBACK (1U << 5) unsigned state; - pid_t tid; +}; + +struct ublk_thread { + struct ublk_dev *dev; + struct io_uring ring; + unsigned int cmd_inflight; + unsigned int io_inflight; + pthread_t thread; + unsigned idx; + +#define UBLKSRV_THREAD_STOPPING (1U << 0) +#define UBLKSRV_THREAD_IDLE (1U << 1) + unsigned state; }; struct ublk_dev { struct ublk_tgt tgt; struct ublksrv_ctrl_dev_info dev_info; struct ublk_queue q[UBLK_MAX_QUEUES]; + struct ublk_thread threads[UBLK_MAX_THREADS]; + unsigned nthreads; + unsigned per_io_tasks; int fds[MAX_BACK_FILES + 1]; /* fds[0] points to /dev/ublkcN */ int nr_fds; @@ -211,7 +232,7 @@ struct ublk_dev { extern unsigned int ublk_dbg_mask; -extern int ublk_queue_io_cmd(struct ublk_queue *q, struct ublk_io *io, unsigned tag); +extern int ublk_queue_io_cmd(struct ublk_io *io); static inline int ublk_io_auto_zc_fallback(const struct ublksrv_io_desc *iod) @@ -225,11 +246,14 @@ static inline int is_target_io(__u64 user_data) } static inline __u64 build_user_data(unsigned tag, unsigned op, - unsigned tgt_data, unsigned is_target_io) + unsigned tgt_data, unsigned q_id, unsigned is_target_io) { - assert(!(tag >> 16) && !(op >> 8) && !(tgt_data >> 16)); + /* we only have 7 bits to encode q_id */ + _Static_assert(UBLK_MAX_QUEUES_SHIFT <= 7); + assert(!(tag >> 16) && !(op >> 8) && !(tgt_data >> 16) && !(q_id >> 7)); - return tag | (op << 16) | (tgt_data << 24) | (__u64)is_target_io << 63; + return tag | (op << 16) | (tgt_data << 24) | + (__u64)q_id << 56 | (__u64)is_target_io << 63; } static inline unsigned int user_data_to_tag(__u64 user_data) @@ -247,6 +271,11 @@ static inline unsigned int user_data_to_tgt_data(__u64 user_data) return (user_data >> 24) & 0xffff; } +static inline unsigned int user_data_to_q_id(__u64 user_data) +{ + return (user_data >> 56) & 0x7f; +} + static inline unsigned short ublk_cmd_op_nr(unsigned int op) { return _IOC_NR(op); @@ -280,17 +309,23 @@ static inline void ublk_dbg(int level, const char *fmt, ...) } } -static inline int ublk_queue_alloc_sqes(struct ublk_queue *q, +static inline struct ublk_queue *ublk_io_to_queue(const struct ublk_io *io) +{ + return container_of(io, struct ublk_queue, ios[io->tag]); +} + +static inline int ublk_io_alloc_sqes(struct ublk_io *io, struct io_uring_sqe *sqes[], int nr_sqes) { - unsigned left = io_uring_sq_space_left(&q->ring); + struct io_uring *ring = &io->t->ring; + unsigned left = io_uring_sq_space_left(ring); int i; if (left < nr_sqes) - io_uring_submit(&q->ring); + io_uring_submit(ring); for (i = 0; i < nr_sqes; i++) { - sqes[i] = io_uring_get_sqe(&q->ring); + sqes[i] = io_uring_get_sqe(ring); if (!sqes[i]) return i; } @@ -373,7 +408,7 @@ static inline int ublk_complete_io(struct ublk_queue *q, unsigned tag, int res) ublk_mark_io_done(io, res); - return ublk_queue_io_cmd(q, io, tag); + return ublk_queue_io_cmd(io); } static inline void ublk_queued_tgt_io(struct ublk_queue *q, unsigned tag, int queued) @@ -383,7 +418,7 @@ static inline void ublk_queued_tgt_io(struct ublk_queue *q, unsigned tag, int qu else { struct ublk_io *io = ublk_get_io(q, tag); - q->io_inflight += queued; + io->t->io_inflight += queued; io->tgt_ios = queued; io->result = 0; } @@ -393,7 +428,7 @@ static inline int ublk_completed_tgt_io(struct ublk_queue *q, unsigned tag) { struct ublk_io *io = ublk_get_io(q, tag); - q->io_inflight--; + io->t->io_inflight--; return --io->tgt_ios == 0; } diff --git a/tools/testing/selftests/ublk/null.c b/tools/testing/selftests/ublk/null.c index 44aca31cf2b0..afe0b99d77ee 100644 --- a/tools/testing/selftests/ublk/null.c +++ b/tools/testing/selftests/ublk/null.c @@ -43,7 +43,7 @@ static int ublk_null_tgt_init(const struct dev_ctx *ctx, struct ublk_dev *dev) } static void __setup_nop_io(int tag, const struct ublksrv_io_desc *iod, - struct io_uring_sqe *sqe) + struct io_uring_sqe *sqe, int q_id) { unsigned ublk_op = ublksrv_get_op(iod); @@ -52,7 +52,7 @@ static void __setup_nop_io(int tag, const struct ublksrv_io_desc *iod, sqe->flags |= IOSQE_FIXED_FILE; sqe->rw_flags = IORING_NOP_FIXED_BUFFER | IORING_NOP_INJECT_RESULT; sqe->len = iod->nr_sectors << 9; /* injected result */ - sqe->user_data = build_user_data(tag, ublk_op, 0, 1); + sqe->user_data = build_user_data(tag, ublk_op, 0, q_id, 1); } static int null_queue_zc_io(struct ublk_queue *q, int tag) @@ -60,18 +60,18 @@ static int null_queue_zc_io(struct ublk_queue *q, int tag) const struct ublksrv_io_desc *iod = ublk_get_iod(q, tag); struct io_uring_sqe *sqe[3]; - ublk_queue_alloc_sqes(q, sqe, 3); + ublk_io_alloc_sqes(ublk_get_io(q, tag), sqe, 3); - io_uring_prep_buf_register(sqe[0], 0, tag, q->q_id, tag); + io_uring_prep_buf_register(sqe[0], 0, tag, q->q_id, ublk_get_io(q, tag)->buf_index); sqe[0]->user_data = build_user_data(tag, - ublk_cmd_op_nr(sqe[0]->cmd_op), 0, 1); + ublk_cmd_op_nr(sqe[0]->cmd_op), 0, q->q_id, 1); sqe[0]->flags |= IOSQE_CQE_SKIP_SUCCESS | IOSQE_IO_HARDLINK; - __setup_nop_io(tag, iod, sqe[1]); + __setup_nop_io(tag, iod, sqe[1], q->q_id); sqe[1]->flags |= IOSQE_IO_HARDLINK; - io_uring_prep_buf_unregister(sqe[2], 0, tag, q->q_id, tag); - sqe[2]->user_data = build_user_data(tag, ublk_cmd_op_nr(sqe[2]->cmd_op), 0, 1); + io_uring_prep_buf_unregister(sqe[2], 0, tag, q->q_id, ublk_get_io(q, tag)->buf_index); + sqe[2]->user_data = build_user_data(tag, ublk_cmd_op_nr(sqe[2]->cmd_op), 0, q->q_id, 1); // buf register is marked as IOSQE_CQE_SKIP_SUCCESS return 2; @@ -82,8 +82,8 @@ static int null_queue_auto_zc_io(struct ublk_queue *q, int tag) const struct ublksrv_io_desc *iod = ublk_get_iod(q, tag); struct io_uring_sqe *sqe[1]; - ublk_queue_alloc_sqes(q, sqe, 1); - __setup_nop_io(tag, iod, sqe[0]); + ublk_io_alloc_sqes(ublk_get_io(q, tag), sqe, 1); + __setup_nop_io(tag, iod, sqe[0], q->q_id); return 1; } @@ -136,7 +136,7 @@ static unsigned short ublk_null_buf_index(const struct ublk_queue *q, int tag) { if (q->state & UBLKSRV_AUTO_BUF_REG_FALLBACK) return (unsigned short)-1; - return tag; + return q->ios[tag].buf_index; } const struct ublk_tgt_ops null_tgt_ops = { diff --git a/tools/testing/selftests/ublk/stripe.c b/tools/testing/selftests/ublk/stripe.c index 404a143bf3d6..37d50bbf5f5e 100644 --- a/tools/testing/selftests/ublk/stripe.c +++ b/tools/testing/selftests/ublk/stripe.c @@ -138,13 +138,13 @@ static int stripe_queue_tgt_rw_io(struct ublk_queue *q, const struct ublksrv_io_ io->private_data = s; calculate_stripe_array(conf, iod, s, base); - ublk_queue_alloc_sqes(q, sqe, s->nr + extra); + ublk_io_alloc_sqes(ublk_get_io(q, tag), sqe, s->nr + extra); if (zc) { - io_uring_prep_buf_register(sqe[0], 0, tag, q->q_id, tag); + io_uring_prep_buf_register(sqe[0], 0, tag, q->q_id, io->buf_index); sqe[0]->flags |= IOSQE_CQE_SKIP_SUCCESS | IOSQE_IO_HARDLINK; sqe[0]->user_data = build_user_data(tag, - ublk_cmd_op_nr(sqe[0]->cmd_op), 0, 1); + ublk_cmd_op_nr(sqe[0]->cmd_op), 0, q->q_id, 1); } for (i = zc; i < s->nr + extra - zc; i++) { @@ -162,13 +162,14 @@ static int stripe_queue_tgt_rw_io(struct ublk_queue *q, const struct ublksrv_io_ sqe[i]->flags |= IOSQE_IO_HARDLINK; } /* bit63 marks us as tgt io */ - sqe[i]->user_data = build_user_data(tag, ublksrv_get_op(iod), i - zc, 1); + sqe[i]->user_data = build_user_data(tag, ublksrv_get_op(iod), i - zc, q->q_id, 1); } if (zc) { struct io_uring_sqe *unreg = sqe[s->nr + 1]; - io_uring_prep_buf_unregister(unreg, 0, tag, q->q_id, tag); - unreg->user_data = build_user_data(tag, ublk_cmd_op_nr(unreg->cmd_op), 0, 1); + io_uring_prep_buf_unregister(unreg, 0, tag, q->q_id, io->buf_index); + unreg->user_data = build_user_data( + tag, ublk_cmd_op_nr(unreg->cmd_op), 0, q->q_id, 1); } /* register buffer is skip_success */ @@ -181,11 +182,11 @@ static int handle_flush(struct ublk_queue *q, const struct ublksrv_io_desc *iod, struct io_uring_sqe *sqe[NR_STRIPE]; int i; - ublk_queue_alloc_sqes(q, sqe, conf->nr_files); + ublk_io_alloc_sqes(ublk_get_io(q, tag), sqe, conf->nr_files); for (i = 0; i < conf->nr_files; i++) { io_uring_prep_fsync(sqe[i], i + 1, IORING_FSYNC_DATASYNC); io_uring_sqe_set_flags(sqe[i], IOSQE_FIXED_FILE); - sqe[i]->user_data = build_user_data(tag, UBLK_IO_OP_FLUSH, 0, 1); + sqe[i]->user_data = build_user_data(tag, UBLK_IO_OP_FLUSH, 0, q->q_id, 1); } return conf->nr_files; } diff --git a/tools/testing/selftests/ublk/test_common.sh b/tools/testing/selftests/ublk/test_common.sh index 0145569ee7e9..8a4dbd09feb0 100755 --- a/tools/testing/selftests/ublk/test_common.sh +++ b/tools/testing/selftests/ublk/test_common.sh @@ -278,6 +278,11 @@ __run_io_and_remove() fio --name=job1 --filename=/dev/ublkb"${dev_id}" --ioengine=libaio \ --rw=randrw --norandommap --iodepth=256 --size="${size}" --numjobs="$(nproc)" \ --runtime=20 --time_based > /dev/null 2>&1 & + fio --name=batchjob --filename=/dev/ublkb"${dev_id}" --ioengine=io_uring \ + --rw=randrw --norandommap --iodepth=256 --size="${size}" \ + --numjobs="$(nproc)" --runtime=20 --time_based \ + --iodepth_batch_submit=32 --iodepth_batch_complete_min=32 \ + --force_async=7 > /dev/null 2>&1 & sleep 2 if [ "${kill_server}" = "yes" ]; then local state diff --git a/tools/testing/selftests/ublk/test_generic_12.sh b/tools/testing/selftests/ublk/test_generic_12.sh new file mode 100755 index 000000000000..7abbb00d251d --- /dev/null +++ b/tools/testing/selftests/ublk/test_generic_12.sh @@ -0,0 +1,55 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +. "$(cd "$(dirname "$0")" && pwd)"/test_common.sh + +TID="generic_12" +ERR_CODE=0 + +if ! _have_program bpftrace; then + exit "$UBLK_SKIP_CODE" +fi + +_prep_test "null" "do imbalanced load, it should be balanced over I/O threads" + +NTHREADS=6 +dev_id=$(_add_ublk_dev -t null -q 4 -d 16 --nthreads $NTHREADS --per_io_tasks) +_check_add_dev $TID $? + +dev_t=$(_get_disk_dev_t "$dev_id") +bpftrace trace/count_ios_per_tid.bt "$dev_t" > "$UBLK_TMP" 2>&1 & +btrace_pid=$! +sleep 2 + +if ! kill -0 "$btrace_pid" > /dev/null 2>&1; then + _cleanup_test "null" + exit "$UBLK_SKIP_CODE" +fi + +# do imbalanced I/O on the ublk device +# pin to cpu 0 to prevent migration/only target one queue +fio --name=write_seq \ + --filename=/dev/ublkb"${dev_id}" \ + --ioengine=libaio --iodepth=16 \ + --rw=write \ + --size=512M \ + --direct=1 \ + --bs=4k \ + --cpus_allowed=0 > /dev/null 2>&1 +ERR_CODE=$? +kill "$btrace_pid" +wait + +# check that every task handles some I/O, even though all I/O was issued +# from a single CPU. when ublk gets support for round-robin tag +# allocation, this check can be strengthened to assert that every thread +# handles the same number of I/Os +NR_THREADS_THAT_HANDLED_IO=$(grep -c '@' ${UBLK_TMP}) +if [[ $NR_THREADS_THAT_HANDLED_IO -ne $NTHREADS ]]; then + echo "only $NR_THREADS_THAT_HANDLED_IO handled I/O! expected $NTHREADS" + cat "$UBLK_TMP" + ERR_CODE=255 +fi + +_cleanup_test "null" +_show_result $TID $ERR_CODE diff --git a/tools/testing/selftests/ublk/test_stress_03.sh b/tools/testing/selftests/ublk/test_stress_03.sh index 7d728ce50774..6eef282d569f 100755 --- a/tools/testing/selftests/ublk/test_stress_03.sh +++ b/tools/testing/selftests/ublk/test_stress_03.sh @@ -41,5 +41,13 @@ if _have_feature "AUTO_BUF_REG"; then fi wait +if _have_feature "PER_IO_DAEMON"; then + ublk_io_and_remove 8G -t null -q 4 --auto_zc --nthreads 8 --per_io_tasks & + ublk_io_and_remove 256M -t loop -q 4 --auto_zc --nthreads 8 --per_io_tasks "${UBLK_BACKFILES[0]}" & + ublk_io_and_remove 256M -t stripe -q 4 --auto_zc --nthreads 8 --per_io_tasks "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" & + ublk_io_and_remove 8G -t null -q 4 -z --auto_zc --auto_zc_fallback --nthreads 8 --per_io_tasks & +fi +wait + _cleanup_test "stress" _show_result $TID $ERR_CODE diff --git a/tools/testing/selftests/ublk/test_stress_04.sh b/tools/testing/selftests/ublk/test_stress_04.sh index 9bcfa64ea1f0..40d1437ca298 100755 --- a/tools/testing/selftests/ublk/test_stress_04.sh +++ b/tools/testing/selftests/ublk/test_stress_04.sh @@ -38,6 +38,13 @@ if _have_feature "AUTO_BUF_REG"; then ublk_io_and_kill_daemon 256M -t stripe -q 4 --auto_zc "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" & ublk_io_and_kill_daemon 8G -t null -q 4 -z --auto_zc --auto_zc_fallback & fi + +if _have_feature "PER_IO_DAEMON"; then + ublk_io_and_kill_daemon 8G -t null -q 4 --nthreads 8 --per_io_tasks & + ublk_io_and_kill_daemon 256M -t loop -q 4 --nthreads 8 --per_io_tasks "${UBLK_BACKFILES[0]}" & + ublk_io_and_kill_daemon 256M -t stripe -q 4 --nthreads 8 --per_io_tasks "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" & + ublk_io_and_kill_daemon 8G -t null -q 4 --nthreads 8 --per_io_tasks & +fi wait _cleanup_test "stress" diff --git a/tools/testing/selftests/ublk/test_stress_05.sh b/tools/testing/selftests/ublk/test_stress_05.sh index bcfc904cefc6..566cfd90d192 100755 --- a/tools/testing/selftests/ublk/test_stress_05.sh +++ b/tools/testing/selftests/ublk/test_stress_05.sh @@ -69,5 +69,12 @@ if _have_feature "AUTO_BUF_REG"; then done fi +if _have_feature "PER_IO_DAEMON"; then + ublk_io_and_remove 8G -t null -q 4 --nthreads 8 --per_io_tasks -r 1 -i "$reissue" & + ublk_io_and_remove 256M -t loop -q 4 --nthreads 8 --per_io_tasks -r 1 -i "$reissue" "${UBLK_BACKFILES[0]}" & + ublk_io_and_remove 8G -t null -q 4 --nthreads 8 --per_io_tasks -r 1 -i "$reissue" & +fi +wait + _cleanup_test "stress" _show_result $TID $ERR_CODE diff --git a/tools/testing/selftests/ublk/trace/count_ios_per_tid.bt b/tools/testing/selftests/ublk/trace/count_ios_per_tid.bt new file mode 100644 index 000000000000..f4aa63ff2938 --- /dev/null +++ b/tools/testing/selftests/ublk/trace/count_ios_per_tid.bt @@ -0,0 +1,11 @@ +/* + * Tabulates and prints I/O completions per thread for the given device + * + * $1: dev_t +*/ +tracepoint:block:block_rq_complete +{ + if (args.dev == $1) { + @[tid] = count(); + } +} diff --git a/tools/testing/selftests/vDSO/vgetrandom-chacha.S b/tools/testing/selftests/vDSO/vgetrandom-chacha.S index d6e09af7c0a9..a4a82e1c28a9 100644 --- a/tools/testing/selftests/vDSO/vgetrandom-chacha.S +++ b/tools/testing/selftests/vDSO/vgetrandom-chacha.S @@ -11,6 +11,8 @@ #include "../../../../arch/loongarch/vdso/vgetrandom-chacha.S" #elif defined(__powerpc__) || defined(__powerpc64__) #include "../../../../arch/powerpc/kernel/vdso/vgetrandom-chacha.S" +#elif defined(__riscv) && __riscv_xlen == 64 +#include "../../../../arch/riscv/kernel/vdso/vgetrandom-chacha.S" #elif defined(__s390x__) #include "../../../../arch/s390/kernel/vdso64/vgetrandom-chacha.S" #elif defined(__x86_64__) diff --git a/tools/testing/vma/vma_internal.h b/tools/testing/vma/vma_internal.h index 441feb21aa5a..4505b1c31be1 100644 --- a/tools/testing/vma/vma_internal.h +++ b/tools/testing/vma/vma_internal.h @@ -932,6 +932,8 @@ static inline void vma_adjust_trans_huge(struct vm_area_struct *vma, (void)next; } +static inline void hugetlb_split(struct vm_area_struct *, unsigned long) {} + static inline void vma_iter_free(struct vma_iterator *vmi) { mas_destroy(&vmi->mas); |