diff --git a/.mailmap b/.mailmap index 074082ce9299e7511a57fea11caacc2f6bd28f7e..b77cd34cf8525b18a6f1777673f67bd75261aa27 100644 --- a/.mailmap +++ b/.mailmap @@ -21,7 +21,8 @@ Adam Radford Adriana Reus Adrian Bunk Ajay Kaher -Akhil P Oommen +Akhil P Oommen +Akhil P Oommen Alan Cox Alan Cox Aleksandar Markovic @@ -106,7 +107,8 @@ Asahi Lina Ashok Raj Nagarajan Ashwin Chaugule Asutosh Das -Atish Patra +Atish Patra +Atish Patra Avaneesh Kumar Dwivedi Axel Dyks Axel Lin @@ -424,6 +426,9 @@ Krzysztof Wilczyński Krzysztof Wilczyński Kshitiz Godara Kuninori Morimoto +Kuniyuki Iwashima +Kuniyuki Iwashima +Kuniyuki Iwashima Kuogee Hsieh Lee Jones Lee Jones @@ -600,6 +605,12 @@ Paul Mackerras Paul Mackerras Paul Moore Paul Moore +Paulo Alcantara +Paulo Alcantara +Paulo Alcantara +Paulo Alcantara +Paulo Alcantara +Paulo Alcantara Pavankumar Kondeti Peter A Jonsson Peter Oruba @@ -640,6 +651,8 @@ Richard Genoud Richard Leitner Richard Leitner Richard Leitner +Rob Clark +Rob Clark Robert Foss Rocky Liao Rodrigo Siqueira @@ -709,6 +722,7 @@ Srinivas Ramana Sriram R Sriram Yagnaraman Stanislav Fomichev +Stanislav Fomichev Stefan Wahren Stéphane Witzmann Stephen Hemminger diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index 722aa989baac43f694076074b307d134867b4533..190bfcc1e836b69622692d7c056c0092e00f1a9b 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 a6e4003649327915a0050f9e69b9b7898f465cf3..faeae8fedb143bcbd668bdaac75ab3bea3d848d6 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 +Contact: Matthew Gerlach 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 +Contact: Matthew Gerlach 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 c69fd3894eb4588e29a14dc483ba2ca3fc14addd..3a6ca780c75c618c3057f0067e8710507d897a60 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 +Contact: Matthew Gerlach 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 +Contact: Matthew Gerlach 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 +Contact: Matthew Gerlach 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 +Contact: Matthew Gerlach 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 +Contact: Matthew Gerlach 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 +Contact: Matthew Gerlach 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 +Contact: Matthew Gerlach 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 4ca917ac6382dd3b80f272a3afd2df66c883db22..5a91dcccd3ac3fc663c1ebe621b7ed26fe1dc188 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/power2_crit -Date: February 2024 -KernelVersion: 6.8 +What: /sys/bus/pci/drivers/xe/.../hwmon/hwmon/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/curr2_crit -Date: February 2024 -KernelVersion: 6.8 +What: /sys/bus/pci/drivers/xe/.../hwmon/hwmon/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 d0502691dfa1af215880155b43649bacd44b0ee0..240fee618e06606a0cb531833c04ec18980ffd33 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= + TUNNEL_DETAILS=0:12 <-> 1:20 (USB3) + +Possible values for ```` 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 8c48bcff3df9d28703f35a7acd06c4af184c29bf..40ba53bed5dffd51507cac7077b897276d50ae45 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 f60bf599175597a42bd44cb802bd53b9e3ae7fea..2aa9be272d5de1c15559a978a956bc36c34de81c 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 854f823b46c2add01d0b65ba36aecd26c45bb65d..c368e1081b4111c581567058f87ecb52db08758b 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 06f766a6aab2446c6218e80fe2573aa79dc59ace..32fc73dc5529e8844c2ce2580987155bcd13cd09 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 . 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 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 a6f793ea03b6c193fc0ff72a45e0249a63a2ba3c..0c1017affbad2f03892b250ad864d9a5dc8d02f1 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 ff4f5c21c5482b77ee2774b01ad6d426e68cf207..8dae89ecb64d723dcf2b4af1e0505fc5db49595b 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 44c671eeda734d6120ff53f2d22f27aa03dc9116..d0cb32f136e58827358688ab43909e05d8f7eb90 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 52d3f1ce336783084d601d361779ebc766124f7a..29f12d650442b8ff2eb455306ce59a0e87867ddd 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 b0962a4583ac716edc0cd4e15bbbc6a331efd1a0..bb9825e7346dd0878325f9cc870301c42cce97cc 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 6168b44ea72cf6eedde042dc9c61c15f1cf54b19..b489c984c1bbff8f4ef835b8e886dcebd6a43294 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 06951ec5f5da381a9bb942d0ac7416128eebd3bc..3a69ec60edb915ae16312b94fddd32f5c87f37a7 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 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 0000000000000000000000000000000000000000..8ce7d415d956e3a4714673227c67500a244d2503 --- /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 + +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 + #include + + 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 0000000000000000000000000000000000000000..2a8ad4fdfc6b12573486e9ad5383c5edd39fb688 --- /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 + +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 + 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 0000000000000000000000000000000000000000..50328582337647e54c713b0a158f5199c2752a55 --- /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 + +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 + #include + 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 ef9dcc365eab5653531f4f355884471666d59eb0..17bb60e18a1c23879f2b3ebb003b51cea6f7d71b 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 - #include - adc12: adc@48003000 { + #include + #include + adc12: adc@48003000 { compatible = "st,stm32mp1-adc-core"; reg = <0x48003000 0x400>; interrupts = , @@ -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 - #include - adc122: adc@48003000 { + #include + #include + adc122: adc@48003000 { compatible = "st,stm32mp1-adc-core"; reg = <0x48003000 0x400>; interrupts = , @@ -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 0000000000000000000000000000000000000000..2a6ddb33f16392834aa2a6b8ee28966fd4611ec6 --- /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 + +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 0000000000000000000000000000000000000000..a355d52a9d641e488fe291b97bc95ed115e96afd --- /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 + +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 2d2561a526838db1a02be625b4a431dfc13e9f73..547044b8e246e928ef7b2feea611ef71ffaa8a0e 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 5ee80bf6aa11b48e1a65f541860606dcf4954ac2..f994c1ef6d4101eefdb383b4033338642597bdeb 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 33490853497b85882a7b63c2cf14b3a3af2e6012..1aece3392b77a0cced35caf3711ad363d01870e8 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 c8c434c1064348ef94e21b57c9e90b934b8083b8..3c8e5781e42cfbc3934f04f8e257c1531ec2858d 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 0dc577c339181da19b04b3e20af035467baaf1d1..26011b5639d877cf2f4c537677f66195d9f6d314 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 941a49c93943ed11372f7cc38c273d22588705db..c00fa50e42e84ce8057974bbd980ad8cff572a31 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 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 b77e855bd5946122de3cbf23aa845d5d7154b327..ff0cb553e8716c70be5e0f2bcf05736debf7c39f 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 a4c273c7a67ffe3126a8aa1a8150bc744f383c2f..cf5324de4fd663c7aa5297368ae46c12cfcbe85f 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 7e4492bbd0278a336587dc5ac04da7153453da29..d4d4e5c3d8562523872a737864610c26c8fccd82 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 1a88b3c253d5bb7cced4c368e8fe7257c8add508..9df81c271411b39a7049f1df975a97d5ab9dd28b 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 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 89977b9f01cfe1ef4dade090793d7058143130e6..412c7bcc310ff38d312124794280e1c8ca336bb1 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 6994b30015bdb69ac8e8d8cc847f93593bd029da..c756aa8631035cb4da1e2433f2394b1f333d2ffb 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 4b08be72bbd7da76a7fcb61dfa8ee83677c5f5db..534644cccdcb4251efe71f0cbdaedcea39d92cef 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 343ff62d7b65be0e2a8548c2ea96dde459b5fa24..56cdb77b369a8242de0dfbe839135f72a8a6f2c1 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 + #include - 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 8004c4baf3977c17219203fecdd33c976278db4b..95ce25ce1f7d4b6e169e9dc3cec368a1d44059e8 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 - - 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 + + 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 4ac0863205b3b30cdfcde6fe1bf5abc3b122a2f5..cd4bb912e0dc556b3b2125fb44531f9028133b23 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 5aaa92a7cef7c2789a66ab7e97c35658441eeb63..01d436d4a5532743751575fc169249c815ff89ac 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 + #include - 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 1b9164dc162f35e061a9e9048b33c0752548c05a..dad3ad2fd93b8c9c4ba8e92b5c67162aca3ced64 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 + #include - 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 71cf7e252bfc8a6d2b246d74b6b9cbc2b21e8608..4b5e9f9b07ec8fbbcf186bdf231cdf61ac05a637 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 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 0000000000000000000000000000000000000000..d8181b58c7816509032ab60e4571343f2a839e61 --- /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 + +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 b597c1f2c57723a3c106d3f3066a9f7ee40e16e9..ef7e33ec85d479ce57c5fe4a780f81a08a6ab6ba 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 0000000000000000000000000000000000000000..2769731e07083b14e2f7388858dcded92c442018 --- /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 + +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 + + 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 0000000000000000000000000000000000000000..80b5a6cdcec91c8eed8b66f745e91ee07ba9683d --- /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 + +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 + + 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/pinctrl/starfive,jh7110-aon-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/starfive,jh7110-aon-pinctrl.yaml index b470901f5f562215e06aeee9bf99e74cd2b32056..4dbef86bd9581135e8ef75539c29bd999eb06cd2 100644 --- a/Documentation/devicetree/bindings/pinctrl/starfive,jh7110-aon-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/starfive,jh7110-aon-pinctrl.yaml @@ -15,7 +15,7 @@ description: | Some peripherals such as PWM have their I/O go through the 4 "GPIOs". maintainers: - - Jianlong Huang + - Hal Feng properties: compatible: diff --git a/Documentation/devicetree/bindings/pinctrl/starfive,jh7110-sys-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/starfive,jh7110-sys-pinctrl.yaml index 222b9e240f8af9adb507834cde2dabd33029435f..e2a25a20f6a6e6cb86c4069bdedc6f6fe395f6f0 100644 --- a/Documentation/devicetree/bindings/pinctrl/starfive,jh7110-sys-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/starfive,jh7110-sys-pinctrl.yaml @@ -18,7 +18,7 @@ description: | any GPIO can be set up to be controlled by any of the peripherals. maintainers: - - Jianlong Huang + - Hal Feng properties: compatible: diff --git a/Documentation/devicetree/bindings/pwm/adi,axi-pwmgen.yaml b/Documentation/devicetree/bindings/pwm/adi,axi-pwmgen.yaml index 45e112d0efb4663bc7fbb3a25a12d66aa8b7492d..5575c58357d6e78a3c02bada54b7bdc3316fd81b 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 bcab59e0cc2e1d90e1bbc939422fbe1d8f3643e8..ede6a58ccf5347d92785dc085a011052c1aade14 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 dc0d52920575ff851a24e56b808e50ee3a14743b..33d2016b65090d0df257f9780ad8d5e05f7ce798 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 4b78de6b46a2079faeeb158d16a0ec3b2362bcaa..1859f71297ff297141e5cd455574fa9ccd9dd11c 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 0565fb7649c5b3f150c5066061f816b36ee023df..d8ad1bb6172da200b280c3db7b11eeada2b5e8c2 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 256cc150ca7e55fb2c077f5c72db964dfeb891bb..0000000000000000000000000000000000000000 --- 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 128cc6aed001081f32abd6a86da15b84e37e7282..0000000000000000000000000000000000000000 --- 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 0000000000000000000000000000000000000000..4a8df078e6f3286564ee38ffdc146ab5284f8a5e --- /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 + +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 0000000000000000000000000000000000000000..68e3fd64b1d82d407d9babeabc101061e16e6e4a --- /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 + +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 4163e7eb7763077ef674ce04ffe62f4f9a8867cf..0000000000000000000000000000000000000000 --- 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 f466c38518c4178367ed324de4056374da9e8723..087a8926f8b4ed366238f7bcde2d6a6222efd628 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 07013fa60a4849e795ebcd9dce5e0f119b2c11b0..0000000000000000000000000000000000000000 --- 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 0000000000000000000000000000000000000000..c9976e86872b719c5cd37709e7520ecc91da054f --- /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 + +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 + + 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 0000000000000000000000000000000000000000..7202294553302d10eda286ddb72111832154a807 --- /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 + +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 2d3ede66889ddc9949a35847389892b6ca5a5b0c..0000000000000000000000000000000000000000 --- 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 0000000000000000000000000000000000000000..96e8c79cb047869cd72771c23b0d9b88048d8780 --- /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 + - Songjun Wu + +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 + + serial@16600000 { + compatible = "lantiq,asc"; + reg = <0x16600000 0x100000>; + interrupts = , + , + ; + }; diff --git a/Documentation/devicetree/bindings/serial/lantiq_asc.txt b/Documentation/devicetree/bindings/serial/lantiq_asc.txt deleted file mode 100644 index 40e81a5818f6720166c21f8c5cf4836bf738fb67..0000000000000000000000000000000000000000 --- 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 = , - , - ; - 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 0000000000000000000000000000000000000000..6c7fa3d19369e3c8d91a72fd391288023fdd130b --- /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 + +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 + + serial@12000 { + compatible = "marvell,armada-3700-uart"; + reg = <0x12000 0x18>; + clocks = <&uartclk 0>; + interrupts = + , + , + ; + interrupt-names = "uart-sum", "uart-tx", "uart-rx"; + }; + + - | + #include + + serial@12200 { + compatible = "marvell,armada-3700-uart-ext"; + reg = <0x12200 0x30>; + clocks = <&uartclk 1>; + interrupts = + , + ; + 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 1b02f0b197ff46e3530372d1d9303210cca9c2d5..c55d9a0efa190ef3be23be40a941904a221f2c2d 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 c8dd440e97470b3f3c237545d2b7ba879caae411..0000000000000000000000000000000000000000 --- 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 0000000000000000000000000000000000000000..b176fd5b580ea3b0c77b514e764ba5699690298a --- /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 + - Purna Chandra Mandal + +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 + #include + + 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 3d2fb1a7ba94804eb946a0eb3a0b07327da8239e..0000000000000000000000000000000000000000 --- 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 a062bbca532c64678269741cf4d46b41680e4430..0000000000000000000000000000000000000000 --- 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 = - , - , - ; - interrupt-names = "uart-sum", "uart-tx", "uart-rx"; - }; - - uart1: serial@12200 { - compatible = "marvell,armada-3700-uart-ext"; - reg = <0x12200 0x30>; - clocks = <&uartclk 1>; - interrupts = - , - ; - 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 0000000000000000000000000000000000000000..ffa2ea59f25665b13a3f4dd7c329585a88f7b721 --- /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 + - Piotr Wojtaszczyk + +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 0d439dfc1aa5bad5215ec62ea583dbf97b34a5e4..0000000000000000000000000000000000000000 --- 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 0000000000000000000000000000000000000000..ea879db5f48502a2251855ccd6ea21182362c67c --- /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 + - Thierry Bultel + +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 + #include + + aliases { + serial0 = &sci0; + }; + + sci0: serial@80005000 { + compatible = "renesas,r9a09g077-rsci"; + reg = <0x80005000 0x400>; + interrupts = , + , + , + ; + 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 0000000000000000000000000000000000000000..dd3096fbfb6adbaeffdcb55e44b1ce0c2627f197 --- /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 + +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 1ee0aed5057d386658513e8705202942bc18f8fb..8f1b7f704c5bc7cb9552b7d4825d96199cbc6c4f 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 0000000000000000000000000000000000000000..34a997ca2e116b6f6c79137b57d9746964af94fa --- /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 + +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 22fe6814b7066b4115a391ff4a9e6561acbb7a9c..590eb177f57abd574ca0762adb90b151df196bee 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 948ff7a096433a8c3c64cba13fc1339d18f6c19d..66e54dedab140a167ad84c43f312f93af2bfa06a 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 0000000000000000000000000000000000000000..16bd7eb2b7af2c0b176f0e5b1970f4670af691da --- /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 + +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 + + 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 8dc81b1ca48eb1ddb2a8d75acc4adfdeb6eb9a8f..27930708ccd581e0cbda04d21c2598676e1812ab 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 d2a7d2ecf48a84af4dda36ef46bf4c7fa4730cbc..10020af15afc4a4458a9a7dc45c929e7749c7a4b 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 8f6136f5d72e16c7d43bb117995792906f97516f..51014955ab3cce78831405180272137aac47cd61 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 0a6e7ac1b37e28f2a7b284d37a9131eef9b7f0dc..019435540df0d43b2e98c73b3e71e5928acef041 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 223f2abd5e592ff8cc3ad97f9a325356ea57044a..508d958e698c2e8dad748a6fcdef65d6e883b97d 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 0000000000000000000000000000000000000000..10d002f09db8af11e38328585d796db6441c85ab --- /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 + +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 935d57f5d26fe597308f1200ace9559255bad1e4..aeb33667818eb0d116a3467d30220002a3b5df73 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 64137c1619a635a5a4f96fc49bd75c5fb757febb..a792434c59db2e6ba2b9b3b8498ca43f0f8d1ec4 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 +# 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 0000000000000000000000000000000000000000..8dac5eba61b45bc2ea78b23ff38678f909e21317 --- /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 + +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 + #include + #include + 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 = , + , + , + , + , + ; + 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 6577a61cc07531d56f1a02dec8cde5c14ae1160a..a020afaf2d6e7a0964cbe319e98dde5151677928 100644 --- a/Documentation/devicetree/bindings/usb/realtek,rts5411.yaml +++ b/Documentation/devicetree/bindings/usb/realtek,rts5411.yaml @@ -10,7 +10,7 @@ maintainers: - Matthias Kaehlcke 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 980f325341d43803759e51548e90f0dce62d0447..6f4d41ba6ca7f92517bce40c8b120ad54e21f6cb 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 256bee2a03ca189f360e2b677f101dce25a0f368..6d39e50669447917a2cd94dacee5822467eeb36e 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 @@ -79,6 +81,19 @@ allOf: required: - vdd10-supply + - if: + properties: + compatible: + contains: + const: samsung,exynos2200-dwusb3 + then: + properties: + clocks: + maxItems: 1 + clock-names: + items: + - const: link_aclk + - if: properties: compatible: @@ -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 6156dc26e65c7807495fcf1238f12c4592edb0ef..18e35122dc1fe7a056b04e6b5529ee5d2076c701 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 - - 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 + + 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 71249b6ba61683128df1e300a3700683b0db0e6a..6c0b8b6538246adf746fe7ccd6df936131c61444 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 bce730a5e237af0cb746addb9af72e1582971535..5e3eae9c2961c94f8f810b113a43600920d76cb9 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 @@ -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 c676956810331b81f11f3624340fc3e612c98315..09fceb469f10525e9dcdb91435b142b0d21964b8 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 0000000000000000000000000000000000000000..5238ab10576308fb3df7e535ff37a23f25dd37c2 --- /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 + +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 da76118e73a53c0e1c255ff115ff959d256816ba..89620191263023bec800dec114c0017c41b7c056 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 c01adbaacbbbcafa3e174153cdc5d2ca28cf703e..5d2a7a8d3ac6c666c8b557c2ef385918e5e97bf9 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 5d9500d21ecc425419dab992fcde74de0542cef4..790e2dc652c00c3a70bb2451579c195a114fcc43 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 c6cab9760d57ee61ca4cca7ca4213eedc6ffe46a..a3c24233eb9b9b200fb1ad8c27679915c54a8517 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 2db379b4b31eee0e27687918b45eb937c8948538..4133a336486d503a65fe4518569509a54e875759 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 1c8597a679ab74fe14beccd527b59ad5de45a9c7..6df23b0e45c86e661d7f344ade97bc0f09da73cb 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 0000000000000000000000000000000000000000..ca6927c0b2c08406eefa6ee8a2dbea84ee4f08e9 --- /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 ---> + SMB3 server support + [*] Support for SMB Direct protocol + + Client Setup + + .. code-block:: text + + Network File Systems ---> + 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 + `_. + 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 b2369561f24e18826b154adf3499c4b8a4594e2b..42ba6c263cd0d7bef0d4dd7b48cdd398aa2bdbd6 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 0000000000000000000000000000000000000000..c0811200e3275519da0e3adc22642c000b41d3bb --- /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 0000000000000000000000000000000000000000..f5d59e4e86c7ec8338f3f4e82d7a07587e3d8404 --- /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 `_ +* `AD3542R `_ +* `AD3551R `_ +* `AD3552R `_ + +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 de8fd3ae6e62052114fee4569ec98c2b00e746e9..c1d04d3436d2f32a31bc84e00539e9a14ac4e06d 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 `_ * `ADAQ4001 `_ * `ADAQ4003 `_ +* `AD7685 `_ +* `AD7686 `_ +* `AD7687 `_ +* `AD7688 `_ +* `AD7690 `_ +* `AD7691 `_ +* `AD7693 `_ +* `AD7942 `_ +* `AD7946 `_ +* `AD7980 `_ +* `AD7982 `_ +* `AD7983 `_ +* `AD7984 `_ +* `AD7988-1 `_ +* `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 24a92a1c4371db6b59ef47edf06cee860641ebbf..d51f9ee3e939c9d33515ce79701fc7c89f5094f2 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 `_ * `AD7387-4 `_ * `AD7388-4 `_ +* `AD7389-4 `_ * `ADAQ4370-4 `_ * `ADAQ4380-4 `_ * `ADAQ4381-4 `_ @@ -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 930199e03c67f68296ec83176f9e4f82741fb813..5e02516bab406b6b13d2ebd13a33433e3e86d943 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 bbb2edce8272e7483acca500d1a757bbcc11c1e0..2d6afc5a8ed54a90cd8d5723f0dc5212b8593d16 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 e4beaae7e456c9c72d146cd176a8996ec289ace9..ed366250a54eac3a72c2f529da94a9e803704ae4 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 `, 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 38cc656fac204df4448af168cf4b3ecac0bb1f3b..8aef3650c1f32b6b197e0dc777e26775d371a081 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 0000000000000000000000000000000000000000..5648fc6ec5726a9e44d979bb82a9a199e46fc31d --- /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 + +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 8c5b226d831365436efbdb27f40dfc87e0f52c1c..081e79415e3869eefb5316bc854a095f1500be54 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 959bd2b822cfa9008893b5331f235f78ffec6b94..6b3b7405ebdf6e22a61a91893d738dce6708ddd9 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 e57df2dab2fdf6c3b82fb938f72b38cedaab43fe..8bed8f8f48daee82ea11d278e55b41a59d52b6a8 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 0000000000000000000000000000000000000000..94c12f9d9dd1295d0a07c1bc43985e44a9bae1e5 --- /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 d087aae7d49286fc45d8232c25da4dccced4f2db..30be8932062130a4c22b9c7d186fb1cf083275c0 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 6ee71398853167a5d51648318c85fd58d1af933a..baa344f4523aae92db6f2002bbc54cf2bbd8dd0a 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 b1bec219912d5a2fcd6231e50437544175b1e298..d9477ccea98f099be51c4fc9e3c48989fd63404a 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 3d1171fd96c1eef9a1f5307f63b8a1e31eed10f5..bc91756bde733bc93ea5120d942e5d94821c2993 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 0xF8 all arch/x86/include/uapi/asm/amd_hsmp.h AMD HSMP EPYC system management interface driver +0xF9 00-0F uapi/misc/amd-apml.h AMD side band system management interface driver + 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 7195a7f911075cf9e2674249ce2971c8f55e240a..ea9b11a0bd89097fccf8a688f1120293fcb2f590 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 dd7366aafe6461c181bf8e836abbd6b148dd8098..507c5ff6f620a30d27e9b3f395dc4c5e7db78bdd 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 +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á 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 +M: Dragos Bogdan +R: Antoniu Miclaus +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 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 @@ -4532,6 +4555,7 @@ BPF [NETWORKING] (tcx & tc BPF, sock_addr) M: Martin KaFai Lau M: Daniel Borkmann R: John Fastabend +R: Stanislav Fomichev L: bpf@vger.kernel.org L: netdev@vger.kernel.org S: Maintained @@ -5963,7 +5987,7 @@ X: drivers/clk/clkdev.c COMMON INTERNET FILE SYSTEM CLIENT (CIFS and SMB3) M: Steve French M: Steve French -R: Paulo Alcantara (DFS, global name space) +R: Paulo Alcantara (DFS, global name space) R: Ronnie Sahlberg (directory leases, sparse files) R: Shyam Prasad N (multichannel) R: Tom Talpey (RDMA, smbdirect) @@ -6938,6 +6962,12 @@ L: linux-rtc@vger.kernel.org S: Maintained F: drivers/rtc/rtc-sd2405al.c +DFROBOT SEN0322 DRIVER +M: Tóth János +L: linux-iio@vger.kernel.org +S: Maintained +F: drivers/iio/chemical/sen0322.c + DH ELECTRONICS DHSOM SOM AND BOARD SUPPORT M: Christoph Niedermaier M: Marek Vasut @@ -7599,7 +7629,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 +M: Rob Clark R: Sean Paul R: Konrad Dybcio L: linux-arm-msm@vger.kernel.org @@ -7618,9 +7648,10 @@ F: drivers/gpu/drm/msm/registers/adreno/ F: include/uapi/drm/msm_drm.h DRM DRIVER for Qualcomm display hardware -M: Rob Clark -M: Abhinav Kumar +M: Rob Clark M: Dmitry Baryshkov +R: Abhinav Kumar +R: Jessica Zhang R: Sean Paul R: Marijn Suijten L: linux-arm-msm@vger.kernel.org @@ -8477,6 +8508,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 +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 L: ecryptfs@vger.kernel.org @@ -9134,9 +9177,10 @@ F: lib/fault-inject.c F: tools/testing/fault-injection/ FBTFT Framebuffer drivers +M: Andy Shevchenko 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 +9281,7 @@ F: include/linux/iomap.h FILESYSTEMS [NETFS LIBRARY] M: David Howells -M: Paulo Alcantara +M: Paulo Alcantara L: netfs@lists.linux.dev L: linux-fsdevel@vger.kernel.org S: Supported @@ -10923,7 +10967,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 +M: Yang Shen L: linux-spi@vger.kernel.org S: Maintained W: http://www.hisilicon.com @@ -10949,7 +10993,7 @@ S: Maintained F: drivers/crypto/hisilicon/trng/trng.c HISILICON V3XX SPI NOR FLASH Controller Driver -M: Jay Fang +M: Yang Shen S: Maintained W: http://www.hisilicon.com F: drivers/spi/spi-hisi-sfc-v3xx.c @@ -11107,6 +11151,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 +11675,13 @@ L: linux-media@vger.kernel.org S: Maintained F: drivers/media/rc/iguanair.c +IIO ADC HELPERS +M: Matti Vaittinen +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 R: Olivier Moysan @@ -11678,7 +11730,9 @@ F: drivers/iio/common/scmi_sensors/scmi_iio.c IIO SUBSYSTEM AND DRIVERS M: Jonathan Cameron -R: Lars-Peter Clausen +R: David Lechner +R: Nuno Sá +R: Andy Shevchenko L: linux-iio@vger.kernel.org S: Maintained T: git git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio.git @@ -12237,7 +12291,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 +M: Lixu Zhang M: Sakari Ailus S: Maintained F: drivers/gpio/gpio-ljca.c @@ -12271,7 +12325,7 @@ F: drivers/mfd/intel-m10-bmc* F: include/linux/mfd/intel-m10-bmc.h INTEL MAX10 BMC SECURE UPDATES -M: Peter Colberg +M: Matthew Gerlach L: linux-fpga@vger.kernel.org S: Maintained F: Documentation/ABI/testing/sysfs-driver-intel-m10-bmc-sec-update @@ -12617,7 +12671,6 @@ F: include/linux/iosys-map.h IO_URING M: Jens Axboe -M: Pavel Begunkov L: io-uring@vger.kernel.org S: Maintained T: git git://git.kernel.dk/linux-block @@ -13218,7 +13271,7 @@ F: arch/powerpc/kvm/ KERNEL VIRTUAL MACHINE FOR RISC-V (KVM/riscv) M: Anup Patel -R: Atish Patra +R: Atish Patra L: kvm@vger.kernel.org L: kvm-riscv@lists.infradead.org L: linux-riscv@lists.infradead.org @@ -14451,7 +14504,7 @@ MARVELL ARMADA 3700 SERIAL DRIVER M: Pali Rohár 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 +15819,7 @@ R: Rakie Kim R: Byungchul Park R: Gregory Price R: Ying Huang +R: Alistair Popple L: linux-mm@kvack.org S: Maintained W: http://www.linux-mm.org @@ -15837,6 +15891,25 @@ S: Maintained F: include/linux/secretmem.h F: mm/secretmem.c +MEMORY MANAGEMENT - SWAP +M: Andrew Morton +R: Kemeng Shi +R: Kairui Song +R: Nhat Pham +R: Baoquan He +R: Barry Song +R: Chris Li +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 M: David Hildenbrand @@ -16675,6 +16748,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 +16998,7 @@ F: include/uapi/linux/mmc/ MULTIPLEXER SUBSYSTEM M: Peter Rosin -S: Maintained +S: Odd Fixes F: Documentation/ABI/testing/sysfs-class-mux* F: Documentation/devicetree/bindings/mux/ F: drivers/mux/ @@ -17420,7 +17494,7 @@ F: tools/testing/selftests/net/srv6* NETWORKING [TCP] M: Eric Dumazet M: Neal Cardwell -R: Kuniyuki Iwashima +R: Kuniyuki Iwashima L: netdev@vger.kernel.org S: Maintained F: Documentation/networking/net_cachelines/tcp_sock.rst @@ -17450,7 +17524,7 @@ F: net/tls/* NETWORKING [SOCKETS] M: Eric Dumazet -M: Kuniyuki Iwashima +M: Kuniyuki Iwashima M: Paolo Abeni M: Willem de Bruijn S: Maintained @@ -17465,7 +17539,7 @@ F: net/core/scm.c F: net/socket.c NETWORKING [UNIX SOCKETS] -M: Kuniyuki Iwashima +M: Kuniyuki Iwashima S: Maintained F: include/net/af_unix.h F: include/net/netns/unix.h @@ -17701,6 +17775,13 @@ F: drivers/nubus/ F: include/linux/nubus.h F: include/uapi/linux/nubus.h +NUVOTON NCT7201 IIO DRIVER +M: Eason Yang +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 L: linux-fbdev@vger.kernel.org @@ -20384,7 +20465,7 @@ F: drivers/soc/qcom/icc-bwmon.c F: drivers/soc/qcom/trace_icc-bwmon.h QUALCOMM IOMMU -M: Rob Clark +M: Rob Clark L: iommu@lists.linux.dev L: linux-arm-msm@vger.kernel.org S: Maintained @@ -20427,7 +20508,7 @@ F: drivers/regulator/vqmmc-ipq4019-regulator.c QUALCOMM IRIS VIDEO ACCELERATOR DRIVER M: Vikash Garodia M: Dikshita Agarwal -R: Abhinav Kumar +R: Abhinav Kumar R: Bryan O'Donoghue L: linux-media@vger.kernel.org L: linux-arm-msm@vger.kernel.org @@ -21273,7 +21354,7 @@ F: arch/riscv/boot/dts/sifive/ F: arch/riscv/boot/dts/starfive/ RISC-V PMU DRIVERS -M: Atish Patra +M: Atish Patra R: Anup Patel L: linux-riscv@lists.infradead.org S: Supported @@ -21431,6 +21512,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 +S: Supported +F: drivers/iio/adc/rohm-bd79124.c + ROHM BH1745 COLOUR SENSOR M: Mudit Sharma L: linux-iio@vger.kernel.org @@ -23576,7 +23662,6 @@ F: include/dt-bindings/clock/starfive?jh71*.h STARFIVE JH71X0 PINCTRL DRIVERS M: Emil Renner Berthing -M: Jianlong Huang M: Hal Feng L: linux-gpio@vger.kernel.org S: Maintained @@ -24632,6 +24717,12 @@ M: Robert Richter S: Odd Fixes F: drivers/gpio/gpio-thunderx.c +TI ADC12xs and ROHM BD79104 ADC driver +M: Matti Vaittinen +S: Maintained +F: drivers/iio/adc/ti-adc128s052.c +L: linux-iio@vger.kernel.org + TI ADS1119 ADC DRIVER M: Francesco Dolcini M: João Paulo Gonçalves @@ -24943,10 +25034,8 @@ F: mm/shmem.c TOMOYO SECURITY MODULE M: Kentaro Takeda M: Tetsuo Handa -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/ @@ -26582,6 +26671,12 @@ M: David Härdeman S: Maintained F: drivers/media/rc/winbond-cir.c +WINSEN MHZ19B +M: Gyeyoung Baek +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 @@ -26873,6 +26968,7 @@ M: David S. Miller M: Jakub Kicinski M: Jesper Dangaard Brouer M: John Fastabend +R: Stanislav Fomichev L: netdev@vger.kernel.org L: bpf@vger.kernel.org S: Supported @@ -26894,6 +26990,7 @@ M: Björn Töpel M: Magnus Karlsson M: Maciej Fijalkowski R: Jonathan Lemon +R: Stanislav Fomichev L: netdev@vger.kernel.org L: bpf@vger.kernel.org S: Maintained @@ -27079,8 +27176,6 @@ M: Dragan Cvetic 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 diff --git a/Makefile b/Makefile index 3244c2a519e241f68d63a604d7db3ec7780d79d9..35e6e5240c61a8a329011929fcd0352b881dccdc 100644 --- a/Makefile +++ b/Makefile @@ -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/include/asm/pgtable.h b/arch/alpha/include/asm/pgtable.h index 2676017f42f1759483608e3a5c46beb8625763d0..44e7aedac6e87e9b390fd711ff985d1a235d93d8 100644 --- a/arch/alpha/include/asm/pgtable.h +++ b/arch/alpha/include/asm/pgtable.h @@ -327,7 +327,7 @@ extern inline pte_t mk_swap_pte(unsigned long type, unsigned long offset) #define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) #define __swp_entry_to_pte(x) ((pte_t) { (x).val }) -static inline int pte_swp_exclusive(pte_t pte) +static inline bool pte_swp_exclusive(pte_t pte) { return pte_val(pte) & _PAGE_SWP_EXCLUSIVE; } diff --git a/arch/alpha/kernel/Makefile b/arch/alpha/kernel/Makefile index b6c862dff1f647fb891188c125241bbc00a2adc7..187cd8df2fafe71b6ef6a3c3d2430991d2dbd027 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 a89ce84371f959caee64760a28bc0cc227102a64..d19e51ec711da7e2edcaa2caec29dc786711b355 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/include/asm/arcregs.h b/arch/arc/include/asm/arcregs.h index 005d9e4d187a0440246b131c1ee0852110336dc4..a31bbf5c8bbc8a18d1d90782d89460ce1cf575aa 100644 --- a/arch/arc/include/asm/arcregs.h +++ b/arch/arc/include/asm/arcregs.h @@ -144,7 +144,7 @@ #define ARC_AUX_AGU_MOD2 0x5E2 #define ARC_AUX_AGU_MOD3 0x5E3 -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #include diff --git a/arch/arc/include/asm/atomic.h b/arch/arc/include/asm/atomic.h index 592d7fffc223c923f4d63ccf27ad01fb9dc56e49..e615c42b93babd9496dbdb375d413cb90130d530 100644 --- a/arch/arc/include/asm/atomic.h +++ b/arch/arc/include/asm/atomic.h @@ -6,7 +6,7 @@ #ifndef _ASM_ARC_ATOMIC_H #define _ASM_ARC_ATOMIC_H -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #include #include @@ -31,6 +31,6 @@ #include #endif -#endif /* !__ASSEMBLY__ */ +#endif /* !__ASSEMBLER__ */ #endif diff --git a/arch/arc/include/asm/atomic64-arcv2.h b/arch/arc/include/asm/atomic64-arcv2.h index 9b5791b8547133b1d7ec4c53ab4a2f611857d165..73080a664369b447d8e67dc973e1fa9822e5af60 100644 --- a/arch/arc/include/asm/atomic64-arcv2.h +++ b/arch/arc/include/asm/atomic64-arcv2.h @@ -137,12 +137,9 @@ ATOMIC64_OPS(xor, xor, xor) #undef ATOMIC64_OP_RETURN #undef ATOMIC64_OP -static inline s64 -arch_atomic64_cmpxchg(atomic64_t *ptr, s64 expected, s64 new) +static inline u64 __arch_cmpxchg64_relaxed(volatile void *ptr, u64 old, u64 new) { - s64 prev; - - smp_mb(); + u64 prev; __asm__ __volatile__( "1: llockd %0, [%1] \n" @@ -152,14 +149,12 @@ arch_atomic64_cmpxchg(atomic64_t *ptr, s64 expected, s64 new) " bnz 1b \n" "2: \n" : "=&r"(prev) - : "r"(ptr), "ir"(expected), "r"(new) - : "cc"); /* memory clobber comes from smp_mb() */ - - smp_mb(); + : "r"(ptr), "ir"(old), "r"(new) + : "memory", "cc"); return prev; } -#define arch_atomic64_cmpxchg arch_atomic64_cmpxchg +#define arch_cmpxchg64_relaxed __arch_cmpxchg64_relaxed static inline s64 arch_atomic64_xchg(atomic64_t *ptr, s64 new) { diff --git a/arch/arc/include/asm/bitops.h b/arch/arc/include/asm/bitops.h index f5a936496f06007b94ee08f4b88426f532604796..5340c287139276a4baead9b2aacbcc6a0272ec57 100644 --- a/arch/arc/include/asm/bitops.h +++ b/arch/arc/include/asm/bitops.h @@ -10,7 +10,7 @@ #error only can be included directly #endif -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #include #include @@ -192,6 +192,6 @@ static inline __attribute__ ((const)) unsigned long __ffs(unsigned long x) #include #include -#endif /* !__ASSEMBLY__ */ +#endif /* !__ASSEMBLER__ */ #endif diff --git a/arch/arc/include/asm/bug.h b/arch/arc/include/asm/bug.h index 4c453ba96c51956a0314eaa87d0a92959c725e9a..171c16021f709663b8f78f8728b65d3ad0cdbe42 100644 --- a/arch/arc/include/asm/bug.h +++ b/arch/arc/include/asm/bug.h @@ -6,7 +6,7 @@ #ifndef _ASM_ARC_BUG_H #define _ASM_ARC_BUG_H -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #include @@ -29,6 +29,6 @@ void die(const char *str, struct pt_regs *regs, unsigned long address); #include -#endif /* !__ASSEMBLY__ */ +#endif /* !__ASSEMBLER__ */ #endif diff --git a/arch/arc/include/asm/cache.h b/arch/arc/include/asm/cache.h index f0f1fc5d62b662956a2dc42e70dae07f3cac17a3..040a97f4dd829dde90879ea8b9ad57f38cbcd767 100644 --- a/arch/arc/include/asm/cache.h +++ b/arch/arc/include/asm/cache.h @@ -23,7 +23,7 @@ */ #define ARC_UNCACHED_ADDR_SPACE 0xc0000000 -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #include @@ -65,7 +65,7 @@ extern int ioc_enable; extern unsigned long perip_base, perip_end; -#endif /* !__ASSEMBLY__ */ +#endif /* !__ASSEMBLER__ */ /* Instruction cache related Auxiliary registers */ #define ARC_REG_IC_BCR 0x77 /* Build Config reg */ diff --git a/arch/arc/include/asm/current.h b/arch/arc/include/asm/current.h index 06be89f6f2f052eb65fb76398d84e6fd77cd92c8..03ffd005f3fa6e10cb9ddfc16518f95a4fc61efa 100644 --- a/arch/arc/include/asm/current.h +++ b/arch/arc/include/asm/current.h @@ -9,7 +9,7 @@ #ifndef _ASM_ARC_CURRENT_H #define _ASM_ARC_CURRENT_H -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #ifdef CONFIG_ARC_CURR_IN_REG @@ -20,6 +20,6 @@ register struct task_struct *curr_arc asm("gp"); #include #endif /* ! CONFIG_ARC_CURR_IN_REG */ -#endif /* ! __ASSEMBLY__ */ +#endif /* ! __ASSEMBLER__ */ #endif /* _ASM_ARC_CURRENT_H */ diff --git a/arch/arc/include/asm/dsp-impl.h b/arch/arc/include/asm/dsp-impl.h index cd5636dfeb6f4119013ace57fa5662e129fe7947..fd5fdaad90c169819b93aa35358aced9feab2d93 100644 --- a/arch/arc/include/asm/dsp-impl.h +++ b/arch/arc/include/asm/dsp-impl.h @@ -11,7 +11,7 @@ #define DSP_CTRL_DISABLED_ALL 0 -#ifdef __ASSEMBLY__ +#ifdef __ASSEMBLER__ /* clobbers r5 register */ .macro DSP_EARLY_INIT diff --git a/arch/arc/include/asm/dsp.h b/arch/arc/include/asm/dsp.h index f496dbc4640b2461a7ca7696c21a19dcb6d2d6be..eeaaf4e4eabd31860cea96567f99cc121bb16613 100644 --- a/arch/arc/include/asm/dsp.h +++ b/arch/arc/include/asm/dsp.h @@ -7,7 +7,7 @@ #ifndef __ASM_ARC_DSP_H #define __ASM_ARC_DSP_H -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ /* * DSP-related saved registers - need to be saved only when you are @@ -24,6 +24,6 @@ struct dsp_callee_regs { #endif }; -#endif /* !__ASSEMBLY__ */ +#endif /* !__ASSEMBLER__ */ #endif /* __ASM_ARC_DSP_H */ diff --git a/arch/arc/include/asm/dwarf.h b/arch/arc/include/asm/dwarf.h index a0d5ebe1bc3f5f37280d9ff37ad3df4827af89fb..1524c5cf8b59e6aea8bda958c7e28650a5828d5a 100644 --- a/arch/arc/include/asm/dwarf.h +++ b/arch/arc/include/asm/dwarf.h @@ -6,7 +6,7 @@ #ifndef _ASM_ARC_DWARF_H #define _ASM_ARC_DWARF_H -#ifdef __ASSEMBLY__ +#ifdef __ASSEMBLER__ #ifdef ARC_DW2_UNWIND_AS_CFI @@ -38,6 +38,6 @@ #endif /* !ARC_DW2_UNWIND_AS_CFI */ -#endif /* __ASSEMBLY__ */ +#endif /* __ASSEMBLER__ */ #endif /* _ASM_ARC_DWARF_H */ diff --git a/arch/arc/include/asm/entry.h b/arch/arc/include/asm/entry.h index 38c35722cebf0312899bf8ac63562550a779dd4e..f453af251a1a1324cb1fc4e2db23d0bea9c29c53 100644 --- a/arch/arc/include/asm/entry.h +++ b/arch/arc/include/asm/entry.h @@ -13,7 +13,7 @@ #include /* For VMALLOC_START */ #include -#ifdef __ASSEMBLY__ +#ifdef __ASSEMBLER__ #ifdef CONFIG_ISA_ARCOMPACT #include /* ISA specific bits */ @@ -146,7 +146,7 @@ #endif /* CONFIG_ARC_CURR_IN_REG */ -#else /* !__ASSEMBLY__ */ +#else /* !__ASSEMBLER__ */ extern void do_signal(struct pt_regs *); extern void do_notify_resume(struct pt_regs *); diff --git a/arch/arc/include/asm/irqflags-arcv2.h b/arch/arc/include/asm/irqflags-arcv2.h index fb3c21f1a2383d718857dfdd66da4fd3a8ccd2bf..30aea562f8aa6f3154548408ac486debcd336b91 100644 --- a/arch/arc/include/asm/irqflags-arcv2.h +++ b/arch/arc/include/asm/irqflags-arcv2.h @@ -50,7 +50,7 @@ #define ISA_INIT_STATUS_BITS (STATUS_IE_MASK | __AD_ENB | \ (ARCV2_IRQ_DEF_PRIO << 1)) -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ /* * Save IRQ state and disable IRQs @@ -170,6 +170,6 @@ static inline void arc_softirq_clear(int irq) seti .endm -#endif /* __ASSEMBLY__ */ +#endif /* __ASSEMBLER__ */ #endif diff --git a/arch/arc/include/asm/irqflags-compact.h b/arch/arc/include/asm/irqflags-compact.h index 936a2f21f315ed881ff9a972ac8e68d6d93170e2..85c2f6bcde0c1e7fa5d21f5f4eeeb129beff640e 100644 --- a/arch/arc/include/asm/irqflags-compact.h +++ b/arch/arc/include/asm/irqflags-compact.h @@ -40,7 +40,7 @@ #define ISA_INIT_STATUS_BITS STATUS_IE_MASK -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ /****************************************************************** * IRQ Control Macros @@ -196,6 +196,6 @@ static inline int arch_irqs_disabled(void) flag \scratch .endm -#endif /* __ASSEMBLY__ */ +#endif /* __ASSEMBLER__ */ #endif diff --git a/arch/arc/include/asm/jump_label.h b/arch/arc/include/asm/jump_label.h index a339223d9e052b35ea678d6a3e60faf6e5673671..66ead75784d973ba57cc39f6dc0b81a9ca16af1e 100644 --- a/arch/arc/include/asm/jump_label.h +++ b/arch/arc/include/asm/jump_label.h @@ -2,7 +2,7 @@ #ifndef _ASM_ARC_JUMP_LABEL_H #define _ASM_ARC_JUMP_LABEL_H -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #include #include @@ -68,5 +68,5 @@ struct jump_entry { jump_label_t key; }; -#endif /* __ASSEMBLY__ */ +#endif /* __ASSEMBLER__ */ #endif diff --git a/arch/arc/include/asm/linkage.h b/arch/arc/include/asm/linkage.h index 8a3fb71e9cfad2a31c92218611b6a7256e67e2f5..ba3cb65b5eaa44f63261099c4ed64d405cfd255b 100644 --- a/arch/arc/include/asm/linkage.h +++ b/arch/arc/include/asm/linkage.h @@ -12,7 +12,7 @@ #define __ALIGN .align 4 #define __ALIGN_STR __stringify(__ALIGN) -#ifdef __ASSEMBLY__ +#ifdef __ASSEMBLER__ .macro ST2 e, o, off #ifdef CONFIG_ARC_HAS_LL64 @@ -61,7 +61,7 @@ CFI_ENDPROC ASM_NL \ .size name, .-name -#else /* !__ASSEMBLY__ */ +#else /* !__ASSEMBLER__ */ #ifdef CONFIG_ARC_HAS_ICCM #define __arcfp_code __section(".text.arcfp") @@ -75,6 +75,6 @@ #define __arcfp_data __section(".data") #endif -#endif /* __ASSEMBLY__ */ +#endif /* __ASSEMBLER__ */ #endif diff --git a/arch/arc/include/asm/mmu-arcv2.h b/arch/arc/include/asm/mmu-arcv2.h index 41412642f27963f704b601896096737e689e27d5..5e5482026ac9007b2f6de080b7288de5d0092e04 100644 --- a/arch/arc/include/asm/mmu-arcv2.h +++ b/arch/arc/include/asm/mmu-arcv2.h @@ -69,7 +69,7 @@ #define PTE_BITS_NON_RWX_IN_PD1 (PAGE_MASK_PHYS | _PAGE_CACHEABLE) -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ struct mm_struct; extern int pae40_exist_but_not_enab(void); @@ -100,6 +100,6 @@ static inline void mmu_setup_pgd(struct mm_struct *mm, void *pgd) sr \reg, [ARC_REG_PID] .endm -#endif /* !__ASSEMBLY__ */ +#endif /* !__ASSEMBLER__ */ #endif diff --git a/arch/arc/include/asm/mmu.h b/arch/arc/include/asm/mmu.h index 4ae2db59d494cb7932f129a349aff16ca967dc3d..e3b35ceab582b626b6a13c2a393e84dd316c61d8 100644 --- a/arch/arc/include/asm/mmu.h +++ b/arch/arc/include/asm/mmu.h @@ -6,7 +6,7 @@ #ifndef _ASM_ARC_MMU_H #define _ASM_ARC_MMU_H -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #include /* NR_CPUS */ diff --git a/arch/arc/include/asm/page.h b/arch/arc/include/asm/page.h index def0dfb95b4369710fa1aac67aa920893fcd92c8..9720fe6b2c24577ef1a12aab1184b957c72d8a20 100644 --- a/arch/arc/include/asm/page.h +++ b/arch/arc/include/asm/page.h @@ -19,7 +19,7 @@ #endif /* CONFIG_ARC_HAS_PAE40 */ -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #define clear_page(paddr) memset((paddr), 0, PAGE_SIZE) #define copy_user_page(to, from, vaddr, pg) copy_page(to, from) @@ -136,6 +136,6 @@ static inline unsigned long virt_to_pfn(const void *kaddr) #include /* page_to_pfn, pfn_to_page */ #include -#endif /* !__ASSEMBLY__ */ +#endif /* !__ASSEMBLER__ */ #endif diff --git a/arch/arc/include/asm/pgtable-bits-arcv2.h b/arch/arc/include/asm/pgtable-bits-arcv2.h index 8ebec1b21d246e61aa688c152dba9b5e2e564104..4630c5acca05d4a758e380f55c495330807ee90e 100644 --- a/arch/arc/include/asm/pgtable-bits-arcv2.h +++ b/arch/arc/include/asm/pgtable-bits-arcv2.h @@ -75,7 +75,7 @@ * This is to enable COW mechanism */ /* xwr */ -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #define pte_write(pte) (pte_val(pte) & _PAGE_WRITE) #define pte_dirty(pte) (pte_val(pte) & _PAGE_DIRTY) @@ -130,7 +130,7 @@ void update_mmu_cache_range(struct vm_fault *vmf, struct vm_area_struct *vma, #define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) #define __swp_entry_to_pte(x) ((pte_t) { (x).val }) -static inline int pte_swp_exclusive(pte_t pte) +static inline bool pte_swp_exclusive(pte_t pte) { return pte_val(pte) & _PAGE_SWP_EXCLUSIVE; } @@ -142,6 +142,6 @@ PTE_BIT_FUNC(swp_clear_exclusive, &= ~(_PAGE_SWP_EXCLUSIVE)); #include #endif -#endif /* __ASSEMBLY__ */ +#endif /* __ASSEMBLER__ */ #endif diff --git a/arch/arc/include/asm/pgtable-levels.h b/arch/arc/include/asm/pgtable-levels.h index d1ce4b0f1071b69d794ba1375945ff4691434d7c..c8f9273372c073a2e42517ac0a62b5ea868b5da3 100644 --- a/arch/arc/include/asm/pgtable-levels.h +++ b/arch/arc/include/asm/pgtable-levels.h @@ -85,7 +85,7 @@ #define PTRS_PER_PTE BIT(PMD_SHIFT - PAGE_SHIFT) -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #if CONFIG_PGTABLE_LEVELS > 3 #include @@ -181,6 +181,6 @@ #define pmd_leaf(x) (pmd_val(x) & _PAGE_HW_SZ) #endif -#endif /* !__ASSEMBLY__ */ +#endif /* !__ASSEMBLER__ */ #endif diff --git a/arch/arc/include/asm/pgtable.h b/arch/arc/include/asm/pgtable.h index 4cf45a99fd792a5e1b528c96a610cfdd9120f14e..bd580e2b62d7c073ef82a9ed1a93755996b67643 100644 --- a/arch/arc/include/asm/pgtable.h +++ b/arch/arc/include/asm/pgtable.h @@ -19,7 +19,7 @@ */ #define USER_PTRS_PER_PGD (TASK_SIZE / PGDIR_SIZE) -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ extern char empty_zero_page[PAGE_SIZE]; #define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page)) @@ -29,6 +29,6 @@ extern pgd_t swapper_pg_dir[] __aligned(PAGE_SIZE); /* to cope with aliasing VIPT cache */ #define HAVE_ARCH_UNMAPPED_AREA -#endif /* __ASSEMBLY__ */ +#endif /* __ASSEMBLER__ */ #endif diff --git a/arch/arc/include/asm/processor.h b/arch/arc/include/asm/processor.h index d606658e2fe73149ef3afd35cd2e50b08f1d5edd..7f7901ac6643c395b08cd2d275753abd7f0d71f7 100644 --- a/arch/arc/include/asm/processor.h +++ b/arch/arc/include/asm/processor.h @@ -11,7 +11,7 @@ #ifndef __ASM_ARC_PROCESSOR_H #define __ASM_ARC_PROCESSOR_H -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #include #include @@ -66,7 +66,7 @@ extern void start_thread(struct pt_regs * regs, unsigned long pc, extern unsigned int __get_wchan(struct task_struct *p); -#endif /* !__ASSEMBLY__ */ +#endif /* !__ASSEMBLER__ */ /* * Default System Memory Map on ARC diff --git a/arch/arc/include/asm/ptrace.h b/arch/arc/include/asm/ptrace.h index cf79df0b257053494fcc20ba48c6105828bd4318..f6c052af8f4d308000a1ede319be057f89731619 100644 --- a/arch/arc/include/asm/ptrace.h +++ b/arch/arc/include/asm/ptrace.h @@ -10,7 +10,7 @@ #include #include -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ typedef union { struct { @@ -172,6 +172,6 @@ static inline unsigned long regs_get_register(struct pt_regs *regs, extern int syscall_trace_enter(struct pt_regs *); extern void syscall_trace_exit(struct pt_regs *); -#endif /* !__ASSEMBLY__ */ +#endif /* !__ASSEMBLER__ */ #endif /* __ASM_PTRACE_H */ diff --git a/arch/arc/include/asm/switch_to.h b/arch/arc/include/asm/switch_to.h index 1f85de8288b17ba72d3f1f88fb9848ded86e8d0f..5806106a65f9016b270727f3ef8c121eab2a66fd 100644 --- a/arch/arc/include/asm/switch_to.h +++ b/arch/arc/include/asm/switch_to.h @@ -6,7 +6,7 @@ #ifndef _ASM_ARC_SWITCH_TO_H #define _ASM_ARC_SWITCH_TO_H -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #include #include diff --git a/arch/arc/include/asm/thread_info.h b/arch/arc/include/asm/thread_info.h index 12daaf3a61eaf613dcbb259643107558092db1c2..255d2c7742190075c0207c1ba6ef7883bff666c6 100644 --- a/arch/arc/include/asm/thread_info.h +++ b/arch/arc/include/asm/thread_info.h @@ -24,7 +24,7 @@ #define THREAD_SIZE (PAGE_SIZE << THREAD_SIZE_ORDER) #define THREAD_SHIFT (PAGE_SHIFT << THREAD_SIZE_ORDER) -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #include @@ -62,7 +62,7 @@ static inline __attribute_const__ struct thread_info *current_thread_info(void) return (struct thread_info *)(sp & ~(THREAD_SIZE - 1)); } -#endif /* !__ASSEMBLY__ */ +#endif /* !__ASSEMBLER__ */ /* * thread information flags diff --git a/arch/arc/include/uapi/asm/ptrace.h b/arch/arc/include/uapi/asm/ptrace.h index 2a6eff57f6dd814c9fa4797c366e228d7a397502..3ae832db278cd4bc66d6d9d2f022477c2c5d454e 100644 --- a/arch/arc/include/uapi/asm/ptrace.h +++ b/arch/arc/include/uapi/asm/ptrace.h @@ -14,7 +14,7 @@ #define PTRACE_GET_THREAD_AREA 25 -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ /* * Userspace ABI: Register state needed by * -ptrace (gdbserver) @@ -53,6 +53,6 @@ struct user_regs_arcv2 { unsigned long r30, r58, r59; }; -#endif /* !__ASSEMBLY__ */ +#endif /* !__ASSEMBLER__ */ #endif /* _UAPI__ASM_ARC_PTRACE_H */ diff --git a/arch/arc/kernel/Makefile b/arch/arc/kernel/Makefile index 95fbf9364c6734a8f730befa272ebac0e2ab54a6..fa94fff02419b3fb4615cb1304419f43e1ff874c 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/arc/kernel/unwind.c b/arch/arc/kernel/unwind.c index d8969dab12d42d515a3bf53d763d268ca1a16134..789cfb9ea14ed8607b5bb5e31f21a3cc47314fc5 100644 --- a/arch/arc/kernel/unwind.c +++ b/arch/arc/kernel/unwind.c @@ -241,15 +241,6 @@ static int cmp_eh_frame_hdr_table_entries(const void *p1, const void *p2) return (e1->start > e2->start) - (e1->start < e2->start); } -static void swap_eh_frame_hdr_table_entries(void *p1, void *p2, int size) -{ - struct eh_frame_hdr_table_entry *e1 = p1; - struct eh_frame_hdr_table_entry *e2 = p2; - - swap(e1->start, e2->start); - swap(e1->fde, e2->fde); -} - static void init_unwind_hdr(struct unwind_table *table, void *(*alloc) (unsigned long)) { @@ -345,7 +336,7 @@ static void init_unwind_hdr(struct unwind_table *table, sort(header->table, n, sizeof(*header->table), - cmp_eh_frame_hdr_table_entries, swap_eh_frame_hdr_table_entries); + cmp_eh_frame_hdr_table_entries, NULL); table->hdrsz = hdrSize; smp_wmb(); diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h index 7f1c3b4e3e0449cc26d41062c4e59c7a42376c41..86378eec77573bf840b0e8aed6c3d7c9d18ada23 100644 --- a/arch/arm/include/asm/pgtable.h +++ b/arch/arm/include/asm/pgtable.h @@ -301,7 +301,7 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) #define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) #define __swp_entry_to_pte(swp) __pte((swp).val) -static inline int pte_swp_exclusive(pte_t pte) +static inline bool pte_swp_exclusive(pte_t pte) { return pte_isset(pte, L_PTE_SWP_EXCLUSIVE); } diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index b3333d070390a8ff366a306931614b1b260647bd..afc9de7ef9a1adf8582399c98c5d79388248f824 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/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h index 88db8a0c0b3716ae8d4287a5fc6348c14330983a..192d86e1cc76ea3459f9851bc316cb039e5b8734 100644 --- a/arch/arm64/include/asm/pgtable.h +++ b/arch/arm64/include/asm/pgtable.h @@ -563,7 +563,7 @@ static inline pte_t pte_swp_mkexclusive(pte_t pte) return set_pte_bit(pte, __pgprot(PTE_SWP_EXCLUSIVE)); } -static inline int pte_swp_exclusive(pte_t pte) +static inline bool pte_swp_exclusive(pte_t pte) { return pte_val(pte) & PTE_SWP_EXCLUSIVE; } diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile index 71c29a2a2f190f70a101b6ff7e82c14e3c3cb994..2920b0a51403787562476e3c6abc9ab0a84248c0 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/include/asm/pgtable.h b/arch/csky/include/asm/pgtable.h index b8378431aeff7c5e1705d8fac2981a7123f39c2f..5a394be09c35b6b3117d8b2c26297ec7c7339cf2 100644 --- a/arch/csky/include/asm/pgtable.h +++ b/arch/csky/include/asm/pgtable.h @@ -200,7 +200,7 @@ static inline pte_t pte_mkyoung(pte_t pte) return pte; } -static inline int pte_swp_exclusive(pte_t pte) +static inline bool pte_swp_exclusive(pte_t pte) { return pte_val(pte) & _PAGE_SWP_EXCLUSIVE; } diff --git a/arch/csky/kernel/Makefile b/arch/csky/kernel/Makefile index de1c3472e8f07afe0a025ad8cd3996d7ffdfaa84..a406a4ac237867211940904637305645fb0f2a30 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/include/asm/pgtable.h b/arch/hexagon/include/asm/pgtable.h index 9fbdfdbc539f8539b0377a601b8a1027d6a26212..fbf24d1d1ca6aafc95179cac6af720bf29f10231 100644 --- a/arch/hexagon/include/asm/pgtable.h +++ b/arch/hexagon/include/asm/pgtable.h @@ -387,7 +387,7 @@ static inline unsigned long pmd_page_vaddr(pmd_t pmd) (((type & 0x1f) << 1) | \ ((offset & 0x3ffff8) << 10) | ((offset & 0x7) << 7)) }) -static inline int pte_swp_exclusive(pte_t pte) +static inline bool pte_swp_exclusive(pte_t pte) { return pte_val(pte) & _PAGE_SWP_EXCLUSIVE; } diff --git a/arch/hexagon/kernel/Makefile b/arch/hexagon/kernel/Makefile index 3fdf937eb572e23f415aeb57d5e481335157d58d..8e0fb4a623153df301646805bb1beda61994d6b3 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 1a2cf012b8f2f564fecf6115f3d346caab627ef8..4b19f93379a15336e0d13626accf57a5884306a3 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 0304eabbe60661570bf8f0787acec9ab1113618a..b0703a4e02a25301d670d3436406a42b8c18fd85 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 3b38ff8853a7d935d5d8cd42118fa08fda6529b0..760c60eebb896c103abf98d2641e429757140efb 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 3514ea78f525651050f58765f9606fb675e3daac..78ea995abf1c6570f6c4086aaca7e248b006c08a 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 8dff2aa5241717b0fb2a31637bd5f6a56c8ea902..1da3beb00f0ec1d672d3c3c68d71faf6ee9d2079 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 b4ff55a33e90b993bc58c618760c67b81b0b021e..9e0411f2754c9b5d77610089bfd094dcbebc04a0 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 0000000000000000000000000000000000000000..daac197d33151277a77fc9af4b524b0c222ed030 --- /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 313f66f7913af362f91e91355886258d0ae4237e..7376840fa9f78a657188da556d31b12ce89ef194 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 0fe2a098ded96caec4e556d53552392a9fba2e60..099132980dc9d0e6f16a3b2366284bfba0ab12be 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 -#include - -static inline bool on_thread_stack(void) -{ - return !(((unsigned long)(current->stack) ^ current_stack_pointer) & ~(THREAD_SIZE - 1)); -} +#include /* For on_thread_stack() */ #endif diff --git a/arch/loongarch/include/asm/irqflags.h b/arch/loongarch/include/asm/irqflags.h index 319a8c616f1f5b60097c30a24f9f24682b9282cc..003172b8406be723e518fa637169e3370ea68b13 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 52651aa0e5834da8e64231511c7574be999003ad..d84dac88a58465242ec6d4c6147bc6af278aa0e0 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 b5f9de9f102e444bcb4e563bddc704f52f3a940e..bbf9f70bd25f45bf7edd042092890dfa5b066490 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/pgtable.h b/arch/loongarch/include/asm/pgtable.h index a3f17914dbab1c54f7adf7f6d9b503de75aaf314..b30185302c07127504e0e26ba3e6ad2d5c4b39ec 100644 --- a/arch/loongarch/include/asm/pgtable.h +++ b/arch/loongarch/include/asm/pgtable.h @@ -301,7 +301,7 @@ static inline pte_t mk_swap_pte(unsigned long type, unsigned long offset) #define __pmd_to_swp_entry(pmd) ((swp_entry_t) { pmd_val(pmd) }) #define __swp_entry_to_pmd(x) ((pmd_t) { (x).val | _PAGE_HUGE }) -static inline int pte_swp_exclusive(pte_t pte) +static inline bool pte_swp_exclusive(pte_t pte) { return pte_val(pte) & _PAGE_SWP_EXCLUSIVE; } diff --git a/arch/loongarch/include/asm/smp.h b/arch/loongarch/include/asm/smp.h index b87d1d5e5890528decfc8f06ebf1f9a1001570e0..ad0bd234a0f1f2450ee7fd7ee402c54ebe08cff8 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 8d4af6aff8a8f1e149f59b4a9b34b80bf7197db2..4501efac1a87611a81a4e5ecc082e8c29a3e2c46 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 66736837085b61cd7c6d62461e5beb237e982fec..3eda298702b19941dcb85892153a688c632aba41 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 fc8b64773794a9e118e4276b3a2dd774cc69292a..5c8be156567cdbb4cb3b3e8e38ccda7b54a738ec 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 50273c9187d020430008e31d2489a5c9978b62c1..f06e7ff25bb7cbe14d79e91ee97b1afd78f13b44 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 48c43f55b039b42168698614d0479b7a872d20f3..a81724b69f291ee49dd1f46b12d6893fc18442b8 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 88cfcf13311630ed5f1a734d23a2bc3f65d79a88..f15503e3336ca1bdc9675ec6e17bbb77abc35ef4 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 f9dcaa60033d95c77ad7b8337b204aa2eccad886..6f5a4574a911d5b7ca68a2e67d52625d4637906f 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 1120ac2824f6e8f3ad5b8ad9ed70b1e6a3b8c14d..a54cd6fd37964b5599a49066cabd7cfea47f54d5 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 2abc29e573810e000f2fef4646ddca0dbb80eabe..47e1db9a1ce47b7835c3acfc9e253d806d349da4 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 30a72fd528c0e7f99a1ddf8bd050f8815eb15f4d..d6e73e8f9c0b66554c10e6533742dc4e1d94ef8a 100644 --- a/arch/loongarch/kernel/numa.c +++ b/arch/loongarch/kernel/numa.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -27,10 +28,6 @@ #include 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 4b24589c0b5653658a7174266bba35e0ef07f720..46036d98da75bd43e9c5413b4b001db9d304cebd 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 10cf1608c7b32f8e03bc2c942b51413cf8b9c505..7b888d9085a014062c82cf129892fa668d8c1a3d 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 cea84d7f2b91a1806e42e0f9c7a0c13d252ee961..02dad4624fe32941766988ea954e5b9ed8d36ff8 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 06f11d9e4ec113f545bf7e583ef7f671f01f0608..c3e4586a7975783b7eadbd6883c849d6446f8c8f 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 1da4dc46df43e5b77bb0666cb849d00f0443d7f8..50c9016641a48d45274bb401c1c02ebad4b8021a 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/include/asm/mcf_pgtable.h b/arch/m68k/include/asm/mcf_pgtable.h index f5c596b211d422f8f7c4d9d7387e5cf8203d252d..d79fef609194d6ce92a5a3a8e2ff994a679b10d5 100644 --- a/arch/m68k/include/asm/mcf_pgtable.h +++ b/arch/m68k/include/asm/mcf_pgtable.h @@ -268,7 +268,7 @@ extern pgd_t kernel_pg_dir[PTRS_PER_PGD]; #define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) #define __swp_entry_to_pte(x) (__pte((x).val)) -static inline int pte_swp_exclusive(pte_t pte) +static inline bool pte_swp_exclusive(pte_t pte) { return pte_val(pte) & _PAGE_SWP_EXCLUSIVE; } diff --git a/arch/m68k/include/asm/motorola_pgtable.h b/arch/m68k/include/asm/motorola_pgtable.h index 040ac3bad713cd2a5e9d3b930f4c47c321937fdf..14fee64d3e605c979d62851bf3d61c2a514f5e10 100644 --- a/arch/m68k/include/asm/motorola_pgtable.h +++ b/arch/m68k/include/asm/motorola_pgtable.h @@ -185,7 +185,7 @@ extern pgd_t kernel_pg_dir[128]; #define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) #define __swp_entry_to_pte(x) ((pte_t) { (x).val }) -static inline int pte_swp_exclusive(pte_t pte) +static inline bool pte_swp_exclusive(pte_t pte) { return pte_val(pte) & _PAGE_SWP_EXCLUSIVE; } diff --git a/arch/m68k/include/asm/sun3_pgtable.h b/arch/m68k/include/asm/sun3_pgtable.h index 73745dc0ec0e0f4ba8f86cce875492273617c3ce..858cbe936f5b3f69d6ec1a970bcc7f9ce03b9dd2 100644 --- a/arch/m68k/include/asm/sun3_pgtable.h +++ b/arch/m68k/include/asm/sun3_pgtable.h @@ -169,7 +169,7 @@ extern pgd_t kernel_pg_dir[PTRS_PER_PGD]; #define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) #define __swp_entry_to_pte(x) ((pte_t) { (x).val }) -static inline int pte_swp_exclusive(pte_t pte) +static inline bool pte_swp_exclusive(pte_t pte) { return pte_val(pte) & _PAGE_SWP_EXCLUSIVE; } diff --git a/arch/m68k/kernel/Makefile b/arch/m68k/kernel/Makefile index 6c732ed3998b714a4842ee29c977550a61979779..57c1b3e8d60e4ce78c0d618e5b10d20b05452e6f 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/include/asm/pgtable.h b/arch/microblaze/include/asm/pgtable.h index b1bb2c65dd047e0d412a6b81db1447d2b0846060..bae1abfa6f6b863924de9f0cc954ebdb4d09a778 100644 --- a/arch/microblaze/include/asm/pgtable.h +++ b/arch/microblaze/include/asm/pgtable.h @@ -398,7 +398,7 @@ extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; #define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) >> 2 }) #define __swp_entry_to_pte(x) ((pte_t) { (x).val << 2 }) -static inline int pte_swp_exclusive(pte_t pte) +static inline bool pte_swp_exclusive(pte_t pte) { return pte_val(pte) & _PAGE_SWP_EXCLUSIVE; } diff --git a/arch/microblaze/kernel/Makefile b/arch/microblaze/kernel/Makefile index 85c4d29ef43e9e3435619b4702c4d96f7c23bbec..241e466e7333b921bb5900f24832e67f9b178200 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 bca37ddf974b80c3c2df215feac72c4b5d990f2b..41a00fa860c18d5c8a3f20e921c949302022960d 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 fc0772c1bad4ab736d440a18b972faf66a610783..1e48184ecf1ec8e29c0a25de6452ece5da835e30 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 1b16daaa86aeefcad956b480de3502fb5a955d7f..411f70ceb762ae4cedef24cd60ced92b64e31d01 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 9cc8fbf218a596d558c68812c2a52d508a03a278..c5617b889b1c6b8ed091dfd00eafa428801c8185 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 5c4a233db55ff9c2e755aa45fa7c071b69e85232..e7a53cd0dec55a39cc4f4330f48363cdbc2d8a9f 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 db618e72a0c42a9da610a881eeb851c1b357c745..529e77a6487c1d30af3000d13c355aca14dafe37 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 ff468439a8c4e9652fbac35b62906d1a7846d018..7375c6ced82b461f0bfaabd3b48632dd2e87606f 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 0000000000000000000000000000000000000000..b467d5624e3986e014723cef8721b2058a264b0e --- /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 0000000000000000000000000000000000000000..66197e73d4f04be9030c9bbd45be2c4ab19d16d0 --- /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 0000000000000000000000000000000000000000..8223c5bce67f22da349944efc45970cd32702702 --- /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 c7ea4f1c0bb21f806610734521e9e425df4fa7ca..6c277ab83d4b94d838b851486a968df74866667f 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 fdc721b414a88a12050497cd2ddf98ae2fbce035..feca35ba56a47adac0e2a906f4fe9c7a4e89cd4f 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 f2e57ea3a60ceaed8079a42b6af9b1e80785d4a7..101bab72a95f43c534a738facd0ecf8d81d2355a 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 0000000000000000000000000000000000000000..fd69884cc9a85eea9d17c9dd79c999d8beeb9602 --- /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 0000000000000000000000000000000000000000..7e4529e7d3d79ae4197c1e1db54d246f42d9c15e --- /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 0000000000000000000000000000000000000000..ea5616447bcd5f008b07c986f1a7d7ef285ccca2 --- /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 0000000000000000000000000000000000000000..6f43ffb209cb9690b812e4ade1736fa9de5104cf --- /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 + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#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 a0d4b752899eeb9388f647fed712a047ad42d124..5dbc9b13d15b3049bd12b1d691e5150bc9882380 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 #include #include 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 ca039b8dcde37f0aec4b57a10ac13ccd20df3b31..4a098fb10232518be6e0c99d8bfa02977ca9d43d 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/pgtable.h b/arch/mips/include/asm/pgtable.h index 4852b005a72d3689f216b31c61f2f4e5dafacf22..ae73ecf4c41aacf9bd01911e62b451d115692c42 100644 --- a/arch/mips/include/asm/pgtable.h +++ b/arch/mips/include/asm/pgtable.h @@ -534,7 +534,7 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) #endif #if defined(CONFIG_PHYS_ADDR_T_64BIT) && defined(CONFIG_CPU_MIPS32) -static inline int pte_swp_exclusive(pte_t pte) +static inline bool pte_swp_exclusive(pte_t pte) { return pte.pte_low & _PAGE_SWP_EXCLUSIVE; } @@ -551,7 +551,7 @@ static inline pte_t pte_swp_clear_exclusive(pte_t pte) return pte; } #else -static inline int pte_swp_exclusive(pte_t pte) +static inline bool pte_swp_exclusive(pte_t pte) { return pte_val(pte) & _PAGE_SWP_EXCLUSIVE; } diff --git a/arch/mips/include/asm/topology.h b/arch/mips/include/asm/topology.h index 0673d2d0f2e6dd02ed14d650e5af7b8a3c162b6f..5158c802eb6574d292f6ad2512cc7772fece4aae 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 ecf3278a32f7077f29bee3b5f1b535eb8b2c5d06..95a1e674fd6785ea91d3fb2d21bf2a944593ece7 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 8c083612df9d00a88257ef93af8c2d4a7c315ede..027fb57d0d79adf0f203894fd9a72a762f313c4e 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 f7107479c7fa9ad0757ef7609d757bef4b7966e7..b890d64d352ca2daf4fcafce764afec6110f7bb0 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 cc26d56f3ab61a693b47e8bdfd791b52fda5d6e7..7b0e69af4097025196b93115139a5e89c1d71fcc 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 39e193cad2b9e4f877e920b71bbbb210e52607d0..4868e79f3b30e9d80fe6390785b297c35d8c02a3 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 737d0d4fdcd35161bfd8865ef5de057a7c3da14a..2b67c44adab9b9cf9b28b0a2e99edae5d7b2b58e 100644 --- a/arch/mips/kernel/vpe.c +++ b/arch/mips/kernel/vpe.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -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 ea6ebfea4a672cd0b86723132be9c0f6a5433e15..0e47cd59b6cbdab5c2024c5c9655d0d10a27d489 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 1e67fecd466ec060c3dcaa22da2a5ac074f1081a..0586ca7668b42eaa269c1f3e772eea3fdad694d1 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 fb4c493aaffa904d51f68b483ab83256a2e358e4..69d4593f64fee593c9ea5b030eabdea40b39b89a 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/include/asm/pgtable.h b/arch/nios2/include/asm/pgtable.h index e98578e27e26bcb127a66cfc00d11b2197934a1c..844dce55569f34b8a324470d32a9e43ab9b666b3 100644 --- a/arch/nios2/include/asm/pgtable.h +++ b/arch/nios2/include/asm/pgtable.h @@ -259,7 +259,7 @@ static inline unsigned long pmd_page_vaddr(pmd_t pmd) #define __swp_entry_to_pte(swp) ((pte_t) { (swp).val }) #define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) -static inline int pte_swp_exclusive(pte_t pte) +static inline bool pte_swp_exclusive(pte_t pte) { return pte_val(pte) & _PAGE_SWP_EXCLUSIVE; } diff --git a/arch/nios2/kernel/Makefile b/arch/nios2/kernel/Makefile index 78a913181fa19dece7f9b746f6a22435315c3b61..4dce965a7b73c68d8522bf022554c60c485c6f64 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/include/asm/pgtable.h b/arch/openrisc/include/asm/pgtable.h index 71bfb8c8c482a3b3c31ea48e4311f45c86558307..5bd6463bd514497c56456713eaed3611bb2d0f01 100644 --- a/arch/openrisc/include/asm/pgtable.h +++ b/arch/openrisc/include/asm/pgtable.h @@ -411,7 +411,7 @@ static inline void update_mmu_cache_range(struct vm_fault *vmf, #define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) #define __swp_entry_to_pte(x) ((pte_t) { (x).val }) -static inline int pte_swp_exclusive(pte_t pte) +static inline bool pte_swp_exclusive(pte_t pte) { return pte_val(pte) & _PAGE_SWP_EXCLUSIVE; } diff --git a/arch/openrisc/kernel/Makefile b/arch/openrisc/kernel/Makefile index e4c7d9bdd598d20ddab81793c311258e8d22c8ec..58e6a1b525b7b1bfed82150bd2614432805a94ac 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/include/asm/pgtable.h b/arch/parisc/include/asm/pgtable.h index 80f5e2a2841314e1ee3110e99dfddc46f5db7eeb..1a86a4370b298af1c6904c2f8b37d327b3438076 100644 --- a/arch/parisc/include/asm/pgtable.h +++ b/arch/parisc/include/asm/pgtable.h @@ -425,7 +425,7 @@ static inline void set_ptes(struct mm_struct *mm, unsigned long addr, #define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) #define __swp_entry_to_pte(x) ((pte_t) { (x).val }) -static inline int pte_swp_exclusive(pte_t pte) +static inline bool pte_swp_exclusive(pte_t pte) { return pte_val(pte) & _PAGE_SWP_EXCLUSIVE; } diff --git a/arch/parisc/kernel/Makefile b/arch/parisc/kernel/Makefile index 5ab0467be70ae30ab6921218844ef1b764672a02..d5055ba33722883d4f9ba7e5276144a22b47c30d 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/include/asm/book3s/32/pgtable.h b/arch/powerpc/include/asm/book3s/32/pgtable.h index 42c3af90d1f0ff8f23ddd6511a98a68f5751c1d7..92d21c6faf1e57665f7078b8ca3f2c267e1ce9d4 100644 --- a/arch/powerpc/include/asm/book3s/32/pgtable.h +++ b/arch/powerpc/include/asm/book3s/32/pgtable.h @@ -365,7 +365,7 @@ static inline void __ptep_set_access_flags(struct vm_area_struct *vma, #define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) >> 3 }) #define __swp_entry_to_pte(x) ((pte_t) { (x).val << 3 }) -static inline int pte_swp_exclusive(pte_t pte) +static inline bool pte_swp_exclusive(pte_t pte) { return pte_val(pte) & _PAGE_SWP_EXCLUSIVE; } diff --git a/arch/powerpc/include/asm/book3s/64/pgtable.h b/arch/powerpc/include/asm/book3s/64/pgtable.h index 6ed93e290c2feda820f7e47d3d58b862295b6c53..a2ddcbb3fcb94f119de7b9c7afa566985443da80 100644 --- a/arch/powerpc/include/asm/book3s/64/pgtable.h +++ b/arch/powerpc/include/asm/book3s/64/pgtable.h @@ -693,7 +693,7 @@ static inline pte_t pte_swp_mkexclusive(pte_t pte) return __pte_raw(pte_raw(pte) | cpu_to_be64(_PAGE_SWP_EXCLUSIVE)); } -static inline int pte_swp_exclusive(pte_t pte) +static inline bool pte_swp_exclusive(pte_t pte) { return !!(pte_raw(pte) & cpu_to_be64(_PAGE_SWP_EXCLUSIVE)); } diff --git a/arch/powerpc/include/asm/nohash/pgtable.h b/arch/powerpc/include/asm/nohash/pgtable.h index 8d1f0b7062eb2f11805b6e0f8c9e1202fd6e6723..7d6b9e5b286ef93f49823ee15c5ff93e10b7f159 100644 --- a/arch/powerpc/include/asm/nohash/pgtable.h +++ b/arch/powerpc/include/asm/nohash/pgtable.h @@ -286,7 +286,7 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) return __pte((pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot)); } -static inline int pte_swp_exclusive(pte_t pte) +static inline bool pte_swp_exclusive(pte_t pte) { return pte_val(pte) & _PAGE_SWP_EXCLUSIVE; } diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index 9d1ab3971694aec670547252b314f100a7da5aec..fb2b95267022ccb9653f2956b39491e9ac3f706b 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 791d1942a0581ebf63bce6d9dbeb7ea22bf69484..3401b96be475ef9230890dc09a8949df15003776 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/book3s/vas-api.c b/arch/powerpc/platforms/book3s/vas-api.c index 0b6365d85d11714a87174dc8ebfee854eb3442c8..dc6f75d3ac6ef76b272fbd3997d0511abb9204df 100644 --- a/arch/powerpc/platforms/book3s/vas-api.c +++ b/arch/powerpc/platforms/book3s/vas-api.c @@ -521,6 +521,15 @@ static int coproc_mmap(struct file *fp, struct vm_area_struct *vma) return -EINVAL; } + /* + * Map complete page to the paste address. So the user + * space should pass 0ULL to the offset parameter. + */ + if (vma->vm_pgoff) { + pr_debug("Page offset unsupported to map paste address\n"); + return -EINVAL; + } + /* Ensure instance has an open send window */ if (!txwin) { pr_err("No send window open?\n"); diff --git a/arch/powerpc/platforms/powermac/low_i2c.c b/arch/powerpc/platforms/powermac/low_i2c.c index a0ae58636e1021a306425a99f2a57f9faa455123..02474e27df9b2176625266590e46a2da74c82d03 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/powerpc/platforms/powernv/memtrace.c b/arch/powerpc/platforms/powernv/memtrace.c index 4ac9808e55a44d13a97de03168ce0d95f60d1bb4..2ea30b34335415be91d0aa44ec4f7bf96c4e6d71 100644 --- a/arch/powerpc/platforms/powernv/memtrace.c +++ b/arch/powerpc/platforms/powernv/memtrace.c @@ -48,11 +48,15 @@ static ssize_t memtrace_read(struct file *filp, char __user *ubuf, static int memtrace_mmap(struct file *filp, struct vm_area_struct *vma) { struct memtrace_entry *ent = filp->private_data; + unsigned long ent_nrpages = ent->size >> PAGE_SHIFT; + unsigned long vma_nrpages = vma_pages(vma); - if (ent->size < vma->vm_end - vma->vm_start) + /* The requested page offset should be within object's page count */ + if (vma->vm_pgoff >= ent_nrpages) return -EINVAL; - if (vma->vm_pgoff << PAGE_SHIFT >= ent->size) + /* The requested mapping range should remain within the bounds */ + if (vma_nrpages > ent_nrpages - vma->vm_pgoff) return -EINVAL; vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index bbec87b7930999748b33df7a92aecdefcdfe624b..36061f4732b7496a9c68a9a10f9959849dc2a95c 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 b096548fe0ffdd5468d8daf3aa57ba11e7800f34..e14f26368963c178e3271e0f716b27fff7671e78 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 539d2aef5cab98c72289b8e3d153689a32fea595..df57654a615e0010f9ec3cf2843751f592357692 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 eea825ee58e17a9070429af1c69d827dd4ae77e0..fe8bd8afb4183ce871020fb2992a21a13bccbc87 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 bfc8ea5f9319b19449ec59493b45b926df888832..a9988bf21ec8e6e68ced81a4b32a76434c137629 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 e1d9bf1deca6852e962816af066c13f29c734231..b8c5726d86acb1e2e5c6b9fb63bcdf305b01b4f9 100644 --- a/arch/riscv/include/asm/barrier.h +++ b/arch/riscv/include/asm/barrier.h @@ -14,11 +14,6 @@ #include #include -#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 b59ffeb668d6a50149457079a967a4b6c25fa557..6086b38d54279d4227c04fe0628f598f9941832f 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 2ec119eb147bb64039e78b3a83828f80be7980fe..0b749e7102162477432f7cf9a34768fbdf2e8cc7 100644 --- a/arch/riscv/include/asm/cmpxchg.h +++ b/arch/riscv/include/asm/cmpxchg.h @@ -13,6 +13,7 @@ #include #include #include +#include #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 f56b409361fbe07e2a95094bfb3f1a4450b1e4d2..fbd0e4306c93478470daf270dfeec8bd7a024437 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 d627f63ee289c7964b1a5e481add02125376bcd3..22ebea3c2b26c16f166d60f46dfbb43c64a602cc 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 (). The second instruction is patched to jalr to + * start the trace. + * + *: + * 0: nop + * 4: nop + * *: - * 0: auipc t0/ra, 0x? - * 4: jalr t0/ra, ?(t0/ra) + * 0: auipc t0, 0x? + * 4: jalr t0, ?(t0) * *: - * 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 e3cbf203cdde7fd6803671e126d272adff10e056..affd63e11b0a344c33a73647351ac02a94e42981 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 1f690fea0e03de6a6f7a59f9b6495df3675efdfc..7fe0a379474ae2c64d300d6fee4a012173f6a6d7 100644 --- a/arch/riscv/include/asm/hwprobe.h +++ b/arch/riscv/include/asm/hwprobe.h @@ -8,7 +8,7 @@ #include -#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 e0b319af3681a6bdf42ed49504b95e1b873122b8..8927a6ea1127e25543be4c850fa96e682d2c6383 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 71060a2f838e24200e3eb4ad8dfb32ef6bd2f57a..d5adbaec1d010d26c8c41a5b48c682d9efa3eb75 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 @@ -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 @@ -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 2b56769cb530cbcc164206a1fe0361a6a9fa013f..b9ee8346cc8c9a459d71d2df75f0efccd5416da0 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 188fadc1c21f9480acaf82638554bf3345df34a1..7de05db7d3bd86d9dd8b70db4f30d6d443e0c5f3 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 f19240fd018e165ba0d1f3ab4651b0013afbfb7a..438ce7df24c39707e4ad5fa1c8b33b0d827ed8f9 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 */ /* @@ -931,7 +1028,7 @@ extern pmd_t pmdp_collapse_flush(struct vm_area_struct *vma, #define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) #define __swp_entry_to_pte(x) ((pte_t) { (x).val }) -static inline int pte_swp_exclusive(pte_t pte) +static inline bool pte_swp_exclusive(pte_t pte) { return pte_val(pte) & _PAGE_SWP_EXCLUSIVE; } diff --git a/arch/riscv/include/asm/processor.h b/arch/riscv/include/asm/processor.h index 5f56eb9d114a95fc1c1ecbe2de30abea5aebf73b..24d3af4d3807e37396744ef26533ac4661abcb4f 100644 --- a/arch/riscv/include/asm/processor.h +++ b/arch/riscv/include/asm/processor.h @@ -13,6 +13,9 @@ #include #include +#include +#include +#include #define arch_get_mmap_end(addr, len, flags) \ ({ \ @@ -52,7 +55,6 @@ #endif #ifndef __ASSEMBLY__ -#include 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 2910231977cb71dac3cc42f2dc32590284204057..a7dc0e33075796843bfdcafa2925afbcc2f85019 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 3d250824178bd5af79c3f658854a735822f7fb3b..341e74238aa04e23e737d8436134b90fc58bd6cb 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 ce0dd0fed7646a56dea6010ec6082c5c1476783f..1a20dd746a49f3445c7eab42f2cc3af8ef469699 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 fee56b0c8058655fa5215d5934b73e2c9936a7d9..d472da4450e6fd1e000a0e324c8c2671780d1b58 100644 --- a/arch/riscv/include/asm/uaccess.h +++ b/arch/riscv/include/asm/uaccess.h @@ -61,6 +61,19 @@ static inline unsigned long __untagged_addr_remote(struct mm_struct *mm, unsigne #define __disable_user_access() \ __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 @@ -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 #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 0000000000000000000000000000000000000000..8dc92441702a9391a4dd1363ecb14e8bb129cf35 --- /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 . All Rights Reserved. + */ +#ifndef __ASM_VDSO_GETRANDOM_H +#define __ASM_VDSO_GETRANDOM_H + +#ifndef __ASSEMBLY__ + +#include + +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 e8a83f55be2ba58cac81be53fd781c319a40207c..45c9b426fcc52321d55d1a4a42030c3b988e53c0 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 0000000000000000000000000000000000000000..ac00e500361c243bd946411b5b2698f9734ca70c --- /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 + +#include + +#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 0000000000000000000000000000000000000000..90a61abd033ce74a6f39baa5df1741f88ce549a5 --- /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 + +#include + +#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 3c2fce939673b9e7cf05a20793e6dae79edf73f0..aaf6ad97049931381f9542bb9316c873ec6ab9f6 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 0000000000000000000000000000000000000000..9f3278a4b298a7f9b2c8a50b0416975b92c9c96a --- /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 f7480c9c6f8d73be6652eba46343b9dcf22b8a53..c7b542573407c813a4a45fe9bf78a676599c0503 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 16490755304e0c275a9600281d5975de74a585a1..6e8c0d6feae9e9b79e529fc86e3dd42467fea6ad 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 2054f6c4b0ae1fd27a160e64a452cd755d7852c0..743d53415572e071fb22851161bd079ef3158b7c 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 e783a72d051f438494962ffb89891b0e06ba5aec..0000000000000000000000000000000000000000 --- 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 -#include -#include -#include -#include -#include -#include -#include -#include - -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= 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 0fb338000c6dc0358742cd03497fa54b9e9d1aec..75656afa2d6be8ca5f2c4711455567c7f8fc0b97 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 674dcdfae7a149c339f1e791adb450535f22991b..4c6c24380cfd9d6c51f0e4340cd674160b83a610 100644 --- a/arch/riscv/kernel/ftrace.c +++ b/arch/riscv/kernel/ftrace.c @@ -8,98 +8,129 @@ #include #include #include +#include #include #include #include #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 0000000000000000000000000000000000000000..f4755d49b89eda76f70c52aae851b37ededacec5 --- /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 +#include +#include +#include +#include +#include +#include +#include + +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 0000000000000000000000000000000000000000..26a81774a78a36f05f3252d71edba16fd2d3b96f --- /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 +#include +#include +#include +#include +#include +#include +#include + +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 b0bf8c1722c0ccf2e5fd0f95d7345ef7f15e98ad..e36104af2e247fc0acb88eb5558d07ac49c713e4 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 +#include +#include +#include +#include +#include +#include +#include +#include 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= 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 745dd4c4a69c3571d539fa7a92107647a9dc3dba..48f6c4f7dca0cc59972abe295b548fb2b7eb4021 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. + *: + * 0: auipc t0/ra, 0x? + * 4: jalr t0/ra, ?(t0/ra) + * + * -8: &ftrace_nop_ops + *: + * 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 91d0b355ceeff62e63e8d24ca8d935b9e17d25f7..75551ac6504c5da36fb7adb7f4bd2192fe5438ba 100644 --- a/arch/riscv/kernel/module-sections.c +++ b/arch/riscv/kernel/module-sections.c @@ -9,6 +9,7 @@ #include #include #include +#include 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 bbf7ec6a75c08fe13002613571ed0686b7c08987..a0a40889d79a53a0b090567581761002f1facccb 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 1989b8cade1b98c0ff0cb131359d7e29955b56c9..53836a9235e320a35bb5ef04e1f39926d753e438 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 249aec8594a92a80159424c29e803f04c893014d..0b170e18a2beba576f4f8787d6ef6aa67c5c3d0e 100644 --- a/arch/riscv/kernel/sys_hwprobe.c +++ b/arch/riscv/kernel/sys_hwprobe.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -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 77c788660223b3db8eb651f6511c813a7c879233..dd8e4af6583f47d2cce8cab61bcd92e7d642a11f 100644 --- a/arch/riscv/kernel/traps_misaligned.c +++ b/arch/riscv/kernel/traps_misaligned.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #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 b8ba13819d05e526ee993e289a90a53efe21b5a1..ae2068425fbcd207fb1c172dc701127857864155 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 cc2895d1fbc2fe752b3edc94f4e28a6a8fca7a3b..3a8e038b10a2dce9ee159232440b4c5ea0cba46b 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 ad73607abc2808af2cd1aaf839b227c78d7a1769..9ebb5e590f93a3228c451dca58e6d5cfbbc03ff7 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 0000000000000000000000000000000000000000..f21922e8cebd3b35b6d9309ef86b1e4eb0e56212 --- /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 . All Rights Reserved. + */ +#include + +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 8e86965a8aae4d7c5a36d0f26026cd1c8680b339..7c15b0f4ee3b0a0e91d6b1f9dae227112209011f 100644 --- a/arch/riscv/kernel/vdso/vdso.lds.S +++ b/arch/riscv/kernel/vdso/vdso.lds.S @@ -79,6 +79,9 @@ VERSION __vdso_flush_icache; #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 0000000000000000000000000000000000000000..5f0dad8f2373e04b17a9f8efb8028ce2fcc0de87 --- /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 . All Rights Reserved. + * + * Based on arch/loongarch/vdso/vgetrandom-chacha.S. + */ + +#include +#include + +.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 9feb7f67a0a3905587b0070d4a194b4edd5efec6..92d8ff81f42c9ceba63bef0170ab134564a24a4e 100644 --- a/arch/riscv/kernel/vendor_extensions.c +++ b/arch/riscv/kernel/vendor_extensions.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -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 866414c81a9f5e7a34043918daba46e3aa54f0ec..a4eca96d1c8a2fd165220f6439a3884cf90a9593 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 0000000000000000000000000000000000000000..1411337dc1e61aba0b844902f356625048c85abc --- /dev/null +++ b/arch/riscv/kernel/vendor_extensions/sifive.c @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include +#include +#include + +#include +#include + +/* 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 0000000000000000000000000000000000000000..1f77f6309763594f55556325534583afe9786ab9 --- /dev/null +++ b/arch/riscv/kernel/vendor_extensions/sifive_hwprobe.c @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include +#include +#include + +#include +#include + +#include +#include + +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 be38a93cedaec5dafcd15d2f855df11474d2f383..7bbdfc6d4552d402300bbe1354dce7214cda5169 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 6a9f116bb5459304cd2478ebe7c4755ebf612242..4efea1b3326c8dd65fee9e0e626c72b975c2c17f 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 7c45f26de4f79b75f5235e3bdb64658aa6bafbce..03b5560609a2206fd495751e19ee1d9d42075920 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 b8e96dfff19dde15659f3b124ebb466490f8a1d2..4ca5aafce22eb5fdad36d73f699a5780fb4ad564 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 4ae67324f99233a97cb9758fd68cbe2bd7d14bec..8b6c0a112a8db4e91de54c3bd3bd527a605a6197 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 f9e27ba1df99ffeb5d4d450e933c15eb4aeeb92e..e737ba7949b12a3647275c53d17275a215abccca 100644 --- a/arch/riscv/mm/tlbflush.c +++ b/arch/riscv/mm/tlbflush.c @@ -7,6 +7,27 @@ #include #include #include +#include + +#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/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h index 1c661ac62ce81b7d57963c6a1f0766b530eec103..6d8bc27a366e4f17abc0e04d01dff5fcf20eb2e7 100644 --- a/arch/s390/include/asm/pgtable.h +++ b/arch/s390/include/asm/pgtable.h @@ -915,7 +915,7 @@ static inline int pmd_protnone(pmd_t pmd) } #endif -static inline int pte_swp_exclusive(pte_t pte) +static inline bool pte_swp_exclusive(pte_t pte) { return pte_val(pte) & _PAGE_SWP_EXCLUSIVE; } diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile index db5f3a3faefbb3637e53c6bdbbe9fca8c660499c..ea5ed6654050941c0d53b2899b639e09fa1c0830 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 e23670e1949cfe3b2b3f54fe68c4c1b642f56e60..21c2e61fece439a92cd690cc28b4ba54e8079270 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 3829521450ddeff364fe583b63b54ff8f2156ee8..e1ad05bfd28ad40e217a6bddb0819a3f018ece30 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 6f13557eecd6bb218bcc165b8f74360d19f4a705..a641e26f8fdf736975f0a4d4a39a3a640a24c93e 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 24391b444b286deb848a6afd2b97b94d1e50119d..42103038a7d02bb89eb6574295857b450a33e04a 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 5442475d132ef4b7ba013d42cd30c7e40452d320..9633b6147a05c89f691675d69a4eb6c4f21baaa8 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 2b51ad9d5586a42ea16f314aa3f72461bec6c6a7..443cc6fd26a8020ef8099cf7c1f0b1d338beb8e5 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 b38dbc9755811c221d6a435b8e6e5a89935da85f..e7ac9c9502751a351c06f6d1fa87f08b3a94b269 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 57195447412212c3ce7a4724a98c3ae4f09477e3..f46d18b84833ff848d61c917b86a86b2aa7962d1 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 #include @@ -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 0379f4cce5ed25fbd2826439bb60a01b02b9154f..a086e38b70eefb4d9ec37ae71d4cdef2666552ac 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 @@ -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 1c10e106639098fc32d274663d6fd84f9796e5fd..d35781ab716ef62a6febbd65f7d0a3d868b1255b 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 172e329fd92d024258f113ea15f6ada8fa9fbee6..b9c9f91e66165a8fe039062159a712a26fab91b3 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 #include #include @@ -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 3990cbd9aa0442392e2585030fbf2bf805e03b5f..def4205491ec98588a8824556f4ab3be561006a7 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 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 729f5c6225fbb4157257c1b3069d49f4ed1c139a..10fa8f2bb8d1f399d9602ceecaf7092de6bad473 100644 --- a/arch/sh/include/asm/pgtable.h +++ b/arch/sh/include/asm/pgtable.h @@ -17,7 +17,7 @@ #include #include -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #include #include @@ -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 db2e48366e0d5d52b309b172ca123c06a2bdbdf0..5f51af18997b57ff531d13aed53f9119882a0f6c 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 @@ -470,7 +470,7 @@ static inline unsigned long pmd_page_vaddr(pmd_t pmd) /* In both cases, we borrow bit 6 to store the exclusive marker in swap PTEs. */ #define _PAGE_SWP_EXCLUSIVE _PAGE_USER -static inline int pte_swp_exclusive(pte_t pte) +static inline bool pte_swp_exclusive(pte_t pte) { return pte.pte_low & _PAGE_SWP_EXCLUSIVE; } @@ -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 73fba7c922f929646a88c439bd827101738b6b94..2a0b5713ab80e6a6d8dbe7a6c5bb46beaa026980 100644 --- a/arch/sh/include/asm/processor.h +++ b/arch/sh/include/asm/processor.h @@ -5,7 +5,7 @@ #include #include -#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 diff --git a/arch/sh/include/asm/smc37c93x.h b/arch/sh/include/asm/smc37c93x.h index 891f2f8f2fd03ae782eb4dbbe87550696e2008f5..caf4cd8dd24117090f665219936bf095d0e98bc6 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 47db17520261e888887f7394ecf0f6b216284f2f..0f991babc559775b2a21e6da7bcc82329cfce132 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 #include diff --git a/arch/sh/include/asm/thread_info.h b/arch/sh/include/asm/thread_info.h index 9f19a682d315fcf7e8fd096f15e2e24706961eac..471db51730361706441e2ae84a710ea6804896c7 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 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 ddf324bfb9a097211f43e2716975550f1cb49a72..39df40d0ebc294d47be3bdeb50ec6a738f90d3bf 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 #include @@ -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 9b3fc923ee28701ce2176f1071e9d94a469b7eaf..fec3e89df0b1085d5cb5a9b9d1aae75d3661d4bd 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 1915714263aab001b0a0c77e64e3c5c2b85843ba..22fb47ec9b15253c4eb6cef4145fb3cfc49f9188 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 2da6ff326cbd0aad5ec9cae8fbf7ff31bf5d71c1..f93d494736c3de23d55ac8fcdb85c68ad8cde69e 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 209275872ff06e43b053aea98ff496273170fb5e..f68bb480d378455ffbc067d6ef1168f78e1ec026 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 7b453592adafb002b87c7e2eceb908ca7a70b1f1..5ef123bc63f8876ccfec59d7ff1711fd4aa7a0bc 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 49c4ffd782d6d6c583dd4de1f4021898fc303381..a250fb1b9420f9e070b728ba1fad35ef01545700 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/include/asm/pgtable_32.h b/arch/sparc/include/asm/pgtable_32.h index 1454ebe915393e7c574b238c9836edac104db03c..7c199c003ffe3b402644407ea6f63b07352e0c19 100644 --- a/arch/sparc/include/asm/pgtable_32.h +++ b/arch/sparc/include/asm/pgtable_32.h @@ -348,7 +348,7 @@ static inline swp_entry_t __swp_entry(unsigned long type, unsigned long offset) #define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) #define __swp_entry_to_pte(x) ((pte_t) { (x).val }) -static inline int pte_swp_exclusive(pte_t pte) +static inline bool pte_swp_exclusive(pte_t pte) { return pte_val(pte) & SRMMU_SWP_EXCLUSIVE; } diff --git a/arch/sparc/include/asm/pgtable_64.h b/arch/sparc/include/asm/pgtable_64.h index 4af03e3c161b4bdacda6e075bb0c68dc6793f6f3..669cd02469a1d94dd1b0f5941af17afbc690da48 100644 --- a/arch/sparc/include/asm/pgtable_64.h +++ b/arch/sparc/include/asm/pgtable_64.h @@ -1023,7 +1023,7 @@ pgtable_t pgtable_trans_huge_withdraw(struct mm_struct *mm, pmd_t *pmdp); #define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) #define __swp_entry_to_pte(x) ((pte_t) { (x).val }) -static inline int pte_swp_exclusive(pte_t pte) +static inline bool pte_swp_exclusive(pte_t pte) { return pte_val(pte) & _PAGE_SWP_EXCLUSIVE; } diff --git a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile index 3453f330e363cffe430806cd00a32b06202088b3..36f2727e1445d0ea6e1c1a9ed716e04338a0c9a6 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 e27afd233bf52628f89e471638673f81842eaa4b..8fb2e7ca501573f084ab2b1d562528c82fefd7d3 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 5226d2c52e6ab67500a295ecce03878a94b3f75f..f292e0b4ff8b7314b80b648a5e11a3011261911d 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/include/asm/pgtable.h b/arch/um/include/asm/pgtable.h index ca2a519d53ab1d0fd6b537384c56cd451286bac1..24fdea6f88c37f4672876f76e9d5067610a87c2f 100644 --- a/arch/um/include/asm/pgtable.h +++ b/arch/um/include/asm/pgtable.h @@ -314,7 +314,7 @@ extern pte_t *virt_to_pte(struct mm_struct *mm, unsigned long addr); ((swp_entry_t) { pte_val(pte_mkuptodate(pte)) }) #define __swp_entry_to_pte(x) ((pte_t) { (x).val }) -static inline int pte_swp_exclusive(pte_t pte) +static inline bool pte_swp_exclusive(pte_t pte) { return pte_get_bits(pte, _PAGE_SWP_EXCLUSIVE); } diff --git a/arch/um/kernel/Makefile b/arch/um/kernel/Makefile index 4669db2aa9be6d00d87d108a556736766cffe69a..b8f4e92815992b2019253d0f5a71fc7a1df67107 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 4662833266302980b5499ea861156f9d9a63f256..741b229f07184e779b97f9749363d860803374ce 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/pgtable.h b/arch/x86/include/asm/pgtable.h index 774430c3abff21074865f47b6b608cb81ed3264b..97954c936c5480f2cc7cb22ea62c6fe8a8f772dd 100644 --- a/arch/x86/include/asm/pgtable.h +++ b/arch/x86/include/asm/pgtable.h @@ -1561,7 +1561,7 @@ static inline pte_t pte_swp_mkexclusive(pte_t pte) return pte_set_flags(pte, _PAGE_SWP_EXCLUSIVE); } -static inline int pte_swp_exclusive(pte_t pte) +static inline bool pte_swp_exclusive(pte_t pte) { return pte_flags(pte) & _PAGE_SWP_EXCLUSIVE; } diff --git a/arch/x86/include/asm/trace/fpu.h b/arch/x86/include/asm/trace/fpu.h index 0454d5e60e5d75344a9f20e93627fb1955557d9c..721b408d9a6736dc14ca81a090b789aacd88a5a9 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 99a783fd46913a3a9fc73c134ae844eec16a77d6..0d2a6d953be9116feb6d136cb7dcc2bcdee56209 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 6290dd120f5e45add01d32813044c8672d398ef7..ff40f09ad9116ceba4dc9048d7f07086220b121a 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 c1d2dac72b9cb6d136a28dfd4ae7092f343ac405..704883c21f3a178dbc5ec24f9a8f4da2077f558e 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 38b33cdd4232d94d23066524e3823b5b75be26c9..9b029bb29a16f1c53cf29b20aa8aab0d97f9367b 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/include/asm/pgtable.h b/arch/xtensa/include/asm/pgtable.h index cb1725c40e369200656e034c8a493064dd074780..d62aa1c316fcb1d8cef18c4734bbe7748276fbbe 100644 --- a/arch/xtensa/include/asm/pgtable.h +++ b/arch/xtensa/include/asm/pgtable.h @@ -349,7 +349,7 @@ ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, pte_t *ptep) #define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) #define __swp_entry_to_pte(x) ((pte_t) { (x).val }) -static inline int pte_swp_exclusive(pte_t pte) +static inline bool pte_swp_exclusive(pte_t pte) { return pte_val(pte) & _PAGE_SWP_EXCLUSIVE; } diff --git a/arch/xtensa/kernel/Makefile b/arch/xtensa/kernel/Makefile index f28b8e3d717eee087bad79ee1db79bf1d9928507..d3ef0407401f637ba6ed426413886856f5d95fc8 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 c6d8c62695e1ad6cea9fe87171007ed5ec1576cd..f0a63b2f85ccae405d03eeca94b51a2a0379d59e 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 cb94e9be26dc21d7231ee1cd8f29cd4680b402af..10912988c8f5c735249f1228530ef1b8cafe85fa 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 b862c66018f25b857e34e97e12660453c09b073a..fdac48aec5efb3de81e5a46ebc9099e7f8ec6b4d 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 a1678f0a9f81f9bd47c70e1d07fc095669a0978e..e4e2567061f9dbefbffe4e8c0fe61e58aa0966dc 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 42c1e0b9a68f2e5fcc87ba8b1c00e3653ccc1759..2f8fdecdd7a9b1994ebe1b510c4160094326211e 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 46449da856f808f2556ace4cd4718701d7ef8ce3..682a8ddb11734ae544bae03afa9f4b570f999806 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 bd15357f23bd6c7ff93855c6964cec6c688e421b..397b6a410f9e505a3b97448b9275e539e863a67e 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 0f0f8452609a1139f8cfd2c080fca254edc6acd6..4dba8405bd015d18baf77ea37ef06d9a0ce9fd59 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 ccaaf6c100c022e3e876ee0c1ee8f717008f73fa..9db741695401e7e6a608ff105cdeeac35afda90e 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 e0d242d9f3e506bd37c33c9549507cf43f18ef6f..59cfcf3eaded967c314e68271f297734b1f19c3d 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 a222a9ec9d61139884dfd4ec432b5479d3786160..aa8ff14f7aae1aa85e96344dd7c34ecba320a319 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 b28da35c30b6758b22fb7228481da13ead15bc07..fae8351aa330908d9acbd7636c98a6a6a5215486 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 219ab8afefabde6945f1766aab8baa5f40e4459d..0256b2dfefc10cb2eb6b3d136c2a7e3dc9fdd2d2 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 972833fabcfcacc88f39e34aa419f92c9aa5a2a7..3fac540f8e03d776b48076284d839b0f45872b4b 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 0f3c663c1b0a3391179ab1e47b66f56e8a73f64d..f0584ccad451915a2679c17f2367461c141663c5 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 5fc2c8ee61b19b6f9ec8b76c4c697ea75219d94f..c463ca4a8fff81967ea7d8d83930ae19dc34ce6b 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[] = { @@ -6900,6 +6955,12 @@ const struct binder_debugfs_entry binder_debugfs_entries[] = { .fops = &state_fops, .data = NULL, }, + { + .name = "state_hashed", + .mode = 0444, + .fops = &state_hashed_fops, + .data = NULL, + }, { .name = "stats", .mode = 0444, @@ -6912,6 +6973,12 @@ const struct binder_debugfs_entry binder_debugfs_entries[] = { .fops = &transactions_fops, .data = NULL, }, + { + .name = "transactions_hashed", + .mode = 0444, + .fops = &transactions_hashed_fops, + .data = NULL, + }, { .name = "transaction_log", .mode = 0444, @@ -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 6a66c9769c6cd4a64deac9e59b9c1e255b20ae31..1ba5caf1d88d9d8cd16ff692b68ab8cb2b68f8a0 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 98da8c4eea59dce8fe7aa8cb01a93297ce65d5f5..024275dbfdd8944462e3939c97cc9ab88f3ea80b 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 22afa4ff860d18561e1f0100857e001aa51a27f1..4e9c82f36df17f37e17c5e7704f8477ebaa71ed3 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 c11d8e634bf7793f182ec167cdc6c2801486d5c0..1f90fcd2b3c49b688d4511e7d3a919ad32365b50 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 a876024d8a05f964fb79fb04bd5447b67f28f20c..1206ab764ba92a293552b9f70cf8a98deb249d10 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 00fe25b5b6a3392f1a617263148e9c64c42ff89d..2a1fe30807120228e310fb626f23e9bb028b3b66 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 b6808c4f89b64721799c8b14001f259b4af04225..8590a4cd21e069c992649102aae34004a04e3337 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 19fd55b8ac77b154d7853753a65d0f60f615f5d3..eebe699fdf4f6c744d481d570ed9bac66a36da71 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; @@ -637,6 +637,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 f7c96a3bf7194a1a23978672758595939c10c35d..d1283ff1080bbdb9fec1ff3e213f6036cda6c969 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 805f75b35115ff48353af3f2d80f8bad12b74b06..f626d5bbe8067d042b81a65d52daf342eae2891e 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 92b06d1de4cc7b7c4ea6f5fad6aa6c4518c1001b..50cc90f6ab35a8be4fef44db519bb35ec5de74e5 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 141b2a0e03f2cbf5c2a352b225072fae8771753c..bba05f0c5bbd5b785aab9e70e4f2ceddb5fd4fd1 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 ced2cc5f46f2bef2339ece057517442b9d167959..52724b79be30134584b004b29c4cdce41e147f48 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 380e6584a4ee7638e4bb61e189edd1c61f733391..d15826f6ee81d48e3fee05ee873c566f9e4d90b4 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 4352a50fbb3f8fc966734a7d79e5cb0b311dcb68..a6ea737b3b7125b0bfe847a4f269a2115c368396 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 e2b1f377f58563f3dc5476a1f6da1c54a050d64b..f8d136684109aa72ac1a897bb4340fcc3907f198 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 ee6cade70222acbd46ae70cae1f03d396207ffca..01f7aef3fcfbc43ad6ea656af10f2abe2d485c68 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 6f51072776f1d74a7125c627d7461521ed63bc01..c637ea010d3474d40a4bf465afa0017c17e8b30e 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 1c7f89e134b3df2c492365e26e06fd9c1d65a1a7..1e3a56e9b13991316da7f32b10130cf1273844bb 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/btintel_pcie.c b/drivers/bluetooth/btintel_pcie.c index 50fe17f1e1d182236a9a0e9255cb6961002fd937..563165c5efae33b7840107c7e550f56ee3df01c9 100644 --- a/drivers/bluetooth/btintel_pcie.c +++ b/drivers/bluetooth/btintel_pcie.c @@ -396,8 +396,13 @@ static int btintel_pcie_submit_rx(struct btintel_pcie_data *data) static int btintel_pcie_start_rx(struct btintel_pcie_data *data) { int i, ret; + struct rxq *rxq = &data->rxq; + + /* Post (BTINTEL_PCIE_RX_DESCS_COUNT - 3) buffers to overcome the + * hardware issues leading to race condition at the firmware. + */ - for (i = 0; i < BTINTEL_PCIE_RX_MAX_QUEUE; i++) { + for (i = 0; i < rxq->count - 3; i++) { ret = btintel_pcie_submit_rx(data); if (ret) return ret; @@ -1782,8 +1787,8 @@ static int btintel_pcie_alloc(struct btintel_pcie_data *data) * + size of index * Number of queues(2) * type of index array(4) * + size of context information */ - total = (sizeof(struct tfd) + sizeof(struct urbd0) + sizeof(struct frbd) - + sizeof(struct urbd1)) * BTINTEL_DESCS_COUNT; + total = (sizeof(struct tfd) + sizeof(struct urbd0)) * BTINTEL_PCIE_TX_DESCS_COUNT; + total += (sizeof(struct frbd) + sizeof(struct urbd1)) * BTINTEL_PCIE_RX_DESCS_COUNT; /* Add the sum of size of index array and size of ci struct */ total += (sizeof(u16) * BTINTEL_PCIE_NUM_QUEUES * 4) + sizeof(struct ctx_info); @@ -1808,36 +1813,36 @@ static int btintel_pcie_alloc(struct btintel_pcie_data *data) data->dma_v_addr = v_addr; /* Setup descriptor count */ - data->txq.count = BTINTEL_DESCS_COUNT; - data->rxq.count = BTINTEL_DESCS_COUNT; + data->txq.count = BTINTEL_PCIE_TX_DESCS_COUNT; + data->rxq.count = BTINTEL_PCIE_RX_DESCS_COUNT; /* Setup tfds */ data->txq.tfds_p_addr = p_addr; data->txq.tfds = v_addr; - p_addr += (sizeof(struct tfd) * BTINTEL_DESCS_COUNT); - v_addr += (sizeof(struct tfd) * BTINTEL_DESCS_COUNT); + p_addr += (sizeof(struct tfd) * BTINTEL_PCIE_TX_DESCS_COUNT); + v_addr += (sizeof(struct tfd) * BTINTEL_PCIE_TX_DESCS_COUNT); /* Setup urbd0 */ data->txq.urbd0s_p_addr = p_addr; data->txq.urbd0s = v_addr; - p_addr += (sizeof(struct urbd0) * BTINTEL_DESCS_COUNT); - v_addr += (sizeof(struct urbd0) * BTINTEL_DESCS_COUNT); + p_addr += (sizeof(struct urbd0) * BTINTEL_PCIE_TX_DESCS_COUNT); + v_addr += (sizeof(struct urbd0) * BTINTEL_PCIE_TX_DESCS_COUNT); /* Setup FRBD*/ data->rxq.frbds_p_addr = p_addr; data->rxq.frbds = v_addr; - p_addr += (sizeof(struct frbd) * BTINTEL_DESCS_COUNT); - v_addr += (sizeof(struct frbd) * BTINTEL_DESCS_COUNT); + p_addr += (sizeof(struct frbd) * BTINTEL_PCIE_RX_DESCS_COUNT); + v_addr += (sizeof(struct frbd) * BTINTEL_PCIE_RX_DESCS_COUNT); /* Setup urbd1 */ data->rxq.urbd1s_p_addr = p_addr; data->rxq.urbd1s = v_addr; - p_addr += (sizeof(struct urbd1) * BTINTEL_DESCS_COUNT); - v_addr += (sizeof(struct urbd1) * BTINTEL_DESCS_COUNT); + p_addr += (sizeof(struct urbd1) * BTINTEL_PCIE_RX_DESCS_COUNT); + v_addr += (sizeof(struct urbd1) * BTINTEL_PCIE_RX_DESCS_COUNT); /* Setup data buffers for txq */ err = btintel_pcie_setup_txq_bufs(data, &data->txq); diff --git a/drivers/bluetooth/btintel_pcie.h b/drivers/bluetooth/btintel_pcie.h index 21b964b15c1c924c86a2d639b41f2c0fcf1e96df..7dad4523236c9fcc1fdb0d057ce902c16a5d8029 100644 --- a/drivers/bluetooth/btintel_pcie.h +++ b/drivers/bluetooth/btintel_pcie.h @@ -154,8 +154,11 @@ enum msix_mbox_int_causes { /* Default interrupt timeout in msec */ #define BTINTEL_DEFAULT_INTR_TIMEOUT_MS 3000 -/* The number of descriptors in TX/RX queues */ -#define BTINTEL_DESCS_COUNT 16 +/* The number of descriptors in TX queues */ +#define BTINTEL_PCIE_TX_DESCS_COUNT 32 + +/* The number of descriptors in RX queues */ +#define BTINTEL_PCIE_RX_DESCS_COUNT 64 /* Number of Queue for TX and RX * It indicates the index of the IA(Index Array) @@ -177,9 +180,6 @@ enum { /* Doorbell vector for TFD */ #define BTINTEL_PCIE_TX_DB_VEC 0 -/* Number of pending RX requests for downlink */ -#define BTINTEL_PCIE_RX_MAX_QUEUE 6 - /* Doorbell vector for FRBD */ #define BTINTEL_PCIE_RX_DB_VEC 513 diff --git a/drivers/bluetooth/btnxpuart.c b/drivers/bluetooth/btnxpuart.c index 6b13feed06df4e10aaa8cda4744efe53261454e1..1088db6056a4a2af6a3698f682c95ebd125b1170 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 610d0e3c36d48ead7ee2449e844a57c368f5ba4b..664d82d1e6139a194ae3a0701caed2065b8bc27a 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 edafa228bf8325f3731a9fe61c85af42b379cbc1..d0d4420c1a0f9afa749e6934fc85343bb3220ac1 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 a2dc39c005f4f8e8bc7658891e880fadbc60c18e..5fe5879881f59d1875759b06ddf38f95727d1c01 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 aeb53b2c34a8cd859393529d0c8860462bc687ed..26357ee68dee984d70ae5bf39f8f09f2cbcafe30 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 03aa887952098661a488650053a357f883d1559b..589cb672231643c427f8d5aba30be8170516c274 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 2fb27e6f8f88ebc701dad56dd60844d8470dd418..33d92bf2fc3ed48db5f7fe80e4f0ef9fe2d2f2ab 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 06d7239782327b99816b85aeeaaee3b6475d20a0..3388a5d1462c742f225c3351e6cd191c7f32e216 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 8fb33c90482f797c382e0ca25abef56ccf704b95..ae61967605563cbe41b6ce68eddcfaf563376c75 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 e795390b070fa5668f92e39251fb1a65782d78ae..53ce352f7197d486630798357e4a8d11f2b73302 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 e110857824fcb5cdc9fd55117168f6547358d2a6..0713ea2b2a51cc302a91e4c4b7e6692abe557b68 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 a1a751074f7e75c148039f6bcf6e8b9949b3e4cf..709a36507145a3bf9a584b1c54f04c2f9c9f1dea 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 77146b5c762bfc15e7553c1d6474484bc012193a..a179d479701171359cce0d5005490d58d57d0a09 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 7fe891783a378c053c19fa1c36e5fcb1f47177a0..bb42dfe1c6a8444573dc5e1a5bc49409b1154162 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 5bf038e620c75f9474c6cb044012ce6ffb973d4a..1bc42830444dd08cfdeffed721dbd4fbc6235ed2 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 e4bd74585d4d20db8aa82bf37595e33bd4babdcf..7a52e3ea49ed8ba9fe0023c1cd390ead9e0c09c4 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 dda466f9181acf76564b5e41ed6e858928e56182..d5accc10a110098f7090dd0f900bc5fae5f75f74 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 11deaf538e873982bdba2caafb60901f7fdea3b1..f2a5e09257ddddea54469f8f9b504e29ef745642 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 11b7c47492742ebc2d38e29557cd1ec71978ef26..efb1ae834265ad10ab6f4ea4eb87ac7cdc022e85 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 393966c097405d16717d6712bd5673699f08407e..002c0e76baff26ed435e378f20e4b4a43e74e5ba 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 b9df9b19d4bd97cdbc7a594ae928a8c4821f871f..3383a7ce27ff55b79c662467c38494045bcd2d9f 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 a76e2666d583bccf9c6f1ef39c123cb5737def5c..67c663892e4814cd58ad82a350507afc5195b869 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 da17d891f0e5d21f83e89689f139fb9c74b9bf7d..9747e6d1f6eb80d5bf8dfde412e9f7bfbf2ade6f 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 f5ca6c0d4d0c2269d5dc65bda1a3a61392241662..1f85572c21b46fd24f23057926687657abc4583f 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 75dce1ff24193b00d82d060b50ea277bb4391a35..61792d940a3dd43e4f7c6f76e569b5239f7e5946 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 330ae1c5880079eaf4f3f6b8914f56b03b0675c5..b4e759e5703fd3b4f9fcdff7c106c727c7603bff 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 2d58e83420e852fa5b5538a0367c02806af376bf..2c7bb9c1ea5bd90e00bcade2862b5b467ee4fd88 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 949598d51575a1a2e575095f298d7fe8fae3e14c..6c0c1d2d7027d5b57878e86587f8f8399e2b7675 100644 --- a/drivers/counter/interrupt-cnt.c +++ b/drivers/counter/interrupt-cnt.c @@ -3,22 +3,25 @@ * Copyright (c) 2021 Pengutronix, Oleksij Rempel */ +#include #include #include #include #include #include #include +#include #include #include #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 1de3c50b98043897b92a91c9cd78ec77e925326e..1a299d1f350b840dae1417571739ee07c6fb2659 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 e75b69476a00a818ad7c4fa627ea7868e4df57c4..3d3384cbea873b827afaf84609c156773662419f 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 afe5abf89d33869bbd6f30eaa2f6e00c36c0d767..a8943e2a93be6aa37cb0551f18628b202812d613 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 5686369779be01738f9ccbcfccc3710e81c02a19..9f8a3a5bed7ec032724477ae95e23789f400fa0d 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 f8d50bd227a6771feb124ed0546e257f0b4bba9d..75ee065da1ec3156ab42630321a848c705116da5 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 261b388162264779e00d59ba4c9563de9b157ae8..27a36045410b376b3f0f962d8c2240069cf5243d 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 b96cc0a8387297c3266ca462bf9e8913e85cebd5..ba434657059a8b984849a058afa501a89320d494 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 06a813cc764178e2317e00ec7915d4e7a5c3c48b..b8fff8333aef1b3dca4cde839de6bc6da661a59e 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 a1dd0eaec2d46fd1ce83d21851eb1bc56ec89a0e..552bd9478340b333fcfcf363bb0455508da3c675 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 cb586a3629444d64e5abf424a0e69caaf44d2431..edceea083b98041e43d5425a88763861eb8d42da 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 18cacb9edbbce47750b21f3700b6f666a01b1861..2bd5deb9054ed3d148ed09650821ee4def29b8d6 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 934d40a4d7098a6241a9bf1ee98337269a6bd436..5e1d5a810afeab84c05777375b0995b68d5dfc9c 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 83386cc978e3f8a7f8800faff364a941aac25bc0..ebca3a4ab0f1ad3a37a0025223828500ff0df4ad 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 2f173391b63d2674541e844c87d8244c0fca8ffe..939a4955e00badde3ab0bd66cfc4e864c6489bc6 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 7c5c03f274b951af84a8f69689d55aa7a5448c77..889e5b05c739ce4141b48bec26172de6fd83db18 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 8748babb050458298a68876ec12a6b1c36297433..62975a39ee14e40f9a1ca59796207e82b6ebe13c 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 058e3b3ad5203eb6115642d6dc2ce506f4948b66..1acfed2f92efb762230192f8a93f014644fe6386 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 836ea081088af3675961f89cbf40953126ee91a3..a5ccd0ada16ab03241f9e61d55fb2a312fd21f31 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 707e131f89d237610d63585467abc778a08b472b..f5466c592d9479b0375e36e5e86189288b9b128a 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 4cec3a873995c869dbaba95fd7364d92bf3b9b14..d8ac4b1051a81cc4d9a38bbc959f896f6deaea3f 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 c43d1b6e5d66b283056d672f17cec756ee265ca1..85567d0d9545cf514a66560f333080ceb36c45d7 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 85376baaa92f2bf6db23366d8d4d36b771923fa9..090dfe86f75ba0d36f1814b5b403ff806492bda1 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 4d1b54f58495a54777ec234a87c77cb71ffc3d16..e1bab6a96cb67df049d52ca6601fea565783c27c 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 9e738fae2b74f1e7318a54c2cd7d9439ed03d291..a0e9bf9b27108c372623e10292dcdcabea69f1de 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 4ddd08ce888523498755da25f4f6fcea2c6ff588..4db92e0a60da7b37ad0be30fbc4c6f0d30836153 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 73b629b5f56fc97b1c2d09c388e2bc60b70e5156..8b919ad3af29ea99aa28585ef3a7eae8dcfd9d59 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 5f5c00ace96ba4f94eb2fbe26f02f0f5d15e6222..8cecf25996edc19146fa851c9abae14ac9965011 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 2c68118fe9fd6abc85e1c8872382af618322f6f6..0ecc88df72088ca496662cc96217e2ffd628673d 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 1db1e6ec0184fcd93dd8f2f8f9a365d08e91d0f6..c5646af055abcbce1db22aa61295d9a0f5e06165 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 9fbb04aee97bcd580146ec39abcda0b20eb1eee6..d2ce7d86dbc8e9ce97f5125e14095cfebced4b7f 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 2febb63ab2322668d41e1c899a2919110c99f127..6fa9fa11c8f31dfd04bb12a3548e92790db7098d 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 a41f65b4f733a51e8e9c9a4bed718de593d55a0c..c0d2c195fe2ed4db09ab6369c621e20440b98986 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 dc07936d2fcb2c443f86be0baab30fd7b536d0d9..de0944947eaf1e52c9f544fc3096fd9cc383d7d1 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 03ed14663107a10e009a85045394a28b8b11d9c4..7e7d6c3865bcd6d8e00f3ab376e7be7134b1aeca 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 5605921212f04e60647f17d8aa5ae1cb72a11bc1..e5f8951bbb6f49534732460c8a02ad09909f0b44 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 3939761be31c9a5d2d9c073bff11712010ffab9d..d45ebfb642ca94f630f7bdbf436b946138668015 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 4a72c2bbd49e9d25f6b053f0373b800d2984b440..2505c46a9c3dec63f420e0c34b9d1e920627ea3a 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 8c6e55b5b967931a2e7247a2e39d4b5ff84026af..c92b8794aa73dab53424b98b31d5c624ed44fcc2 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 29ce6b1d214a6c6b44f6a4a76aaa5c77692bcfd5..ec203f9e5ffab7a768c4c15fa6acf4ccf384d2e9 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 fc4d0d42e2238f71d970b9fb81c23c36c7e7ef07..a86616c6deeff9926a9ae6605b8ea2550a161a00 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 2d7f82e98df92c95b5cb3fb78486c19314163aa8..abdc52b0895a60136cf6beb567bc9d20f8ca114b 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 b03c3895897bf94285ddaf46e33fc5d38308eb8a..322816805bfbad593ed476d9c091aea7694e6727 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.c @@ -27,6 +27,9 @@ #include #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 b63f53242c573420ff88d99e3322c6e8d437b20e..454b33f889fb65d018cc4f17e7be00b91696a317 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 f51ef4cf16e085efcb4089805ef10d2ee7bf0259..d9ad37711c3eb460de921df4e04009ea459e9c8e 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 32dabba4062fac8a1efb15af595f90f426f91c1c..f994be985f42da8c94ff06faf0183b0d9a62a2d4 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 5255378af53c0a2d8941aea9226996542c356a24..f67569ccf9f60940b7327e20105501a7c37251de 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 9ba3359253c95d15802f0d9de6899827efc79813..54f7ed9e2801c5d6b9ab6e4935b05823267bfbac 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 f09d96bfee16def4cfa3719b75e0ce808bb6addc..1234c8d64e20d9e8d929bab7440ab9861acc44a4 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 69dd92f6e86d11232265df024a56192ba67458a4..574880d67009953d25435acb9a4b82ebbb8ae003 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 #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 a8ccae361ec78c30cf6ba91c529c8edc5d4f4cd8..79e342d5ab28d87f39e43afdc9dd0c0e97bf937d 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 a90bf370a00259fb80a9531b5ccc5b3ca5f8e6b6..2e110d04af84f219e99ada608743840feca6633e 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 cb94bd71300f0fef766ac18cc55e4b2f3dc0658b..3b6f65a256464a949788ebaae7b1dda727de1c97 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 efdab57324e440101e0f86d1cff94536f7cf5b09..a7e58d5fb2465e78c77f9d03d5db56f66d12d115 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 da5b5d64f137472d0d713d801b8846a7ef356d23..5a70ae17be04e4c18112f67ba2b75e828f2a86c0 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 befe013b11a7826585c93a430585295048a75807..ad47d0bdf77752884319c41673f032ae2915b74b 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 21b57c29bf7d74af43e3ab4c53238289fbc68227..c74947705d77800a7b286c715303957c1f4b37a1 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 b8d835c9e17eda68df9cefd3831ae196d82c19f7..148b651be7ca7cfe8b43936d89f453532831f8de 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 3eec1b8feaeea4d358f63435b5676079417a1a34..58b527a6b795fc0c2d58c308baf0328a6cfcd3a3 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 0b19f0ab4480da979c3c0eaffe2797397d95f900..9fb0d53805892df3e46470868f46e5cf5266ae3e 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 8fff470bce8738abca455f66ea260cae1d09fbb9..b5071f77f78d233510587f8e9013d7e194b67cd0 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 712e1fba33ce6c7b28621889fbdae159aef5a127..5a33140f5723519ac9d2b3b6726a92aee3b57d7c 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 03572a1d0c9cb751b631c81f8587fc04cdf3db5f..aeab89853a923aedeb04c235108310f2cbb9933d 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 a09f9a2dd4716c3d6d5afaba91b663b31d89785f..16ade84facc789e1311c8bf08e54b0a3b046f121 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 27dcc6f37a73025d32830791ace93cc93e63e48c..f8e3f0b882da563f614c60f9df2a04e9b512791c 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 8e843011703cf9f23cd66f9f952778b4377bd08d..338cf43c45fe7ad6e8cbf3888712932553e477fb 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 8fd90bd108072af6ff9a26efd8722c12f043a84d..b72e4da68317535a2c4e234f6a56dc786a265d2d 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 d3c3d3ab72255060ae2cbad0d9187e990e92c59c..62e88e5362e9599ab18f6cbd05ecb473b89518e0 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 981d9adcc5e1d23217305069b9f7556cfd8fd343..73acbe0b7c2124d1d4d543dd03d6e9c92d6e1a45 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 1e9dd00620bf4104a8ab0354656fc0db07d618f6..a2149afa5803e2fe4f0320315848ff1d9a7e038c 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 e54e708ed82de1d429ee7754d70e5841ed3afdbc..2b294ada3ec0576804e332c188b4b500084c5f28 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 6d5fa57d4a233aa5e90374e28e769d5b5af3ef58..c643e0ccec52b02cf3301ae334ee126917cfc2b6 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 72be6e152e881e6475ec9a9fe4c9b6a52270e76b..865dca2547de5b6557925a2d2411dff8a3d65898 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 6ea23c78009ce1b0a3a2c9b6647f56e991cc5049..01c7a487790444ef6451c255f43935b6a2a61915 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 742b10881112c58a7741895d47e9831ecec17bdb..d3100f641ac6e5d0e439bf2e01a0cde16939d674 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 e8bdd7f0c4607999cbd0d6a55e839b550034c0da..87058271b00cc493737e60004ce3d5548f8c89b3 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 681799468487c7ddffb8f46be8ac1f895274cbd6..d897f8a30edee58eb7dac3225fb8b861ad84f628 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 3f13a744d07da634ec02219aa70fa9cd99094274..01ec451004f72aab448c5c33ff9e0fd912ce5af0 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 23bec5d25ed6c8928138b5e965ff6a5b0714f7b6..e8730cc40edbe865e60cbb59d65e2942d66c124a 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 858288c3b1acb3ce9964b59d62dbf41b07613675..c277df12c8172e4db9832d9fe14b71712a62f0d8 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 e89ebfda4873ddbc4b20865df16b0c5cf029d0f6..37a239219dfe053670efd00ea81bfdb21910cd7d 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 f38340aa3f159db97ee697887e4de5857aca6858..5ba3999991b095639df440538d1a935414bcefaf 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 09bc65c2fa23b2eb829c2474e0a39a0d1e9f5937..1e2d247fbbacde380fccdfa245b90f4d57ad5246 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 8f79881ad9f1a9e15f246a98662c740da06855fd..a5127c2d47efb81a0bf988340bc6649d00e72faa 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 81857ce6d68d71b83281b29f77a0324bcda5f80f..e7a90a437fffb7db668ddc55c18d3992fe7b5374 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 f2415eebdc099901be0f8608e536f5138742eb1f..772a8bfb949c12d134b05ce7bce6522c209bbad4 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 78b58a449fa4de7e5add54b63258b949d40926a9..ee4665aa49e9f009cb9ea5e1dd33749b5570f353 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 65e9089b7f31cb528b110f6d8d8198b44ff2df17..38f85bc2681aea5f80561bfac0c08989114e8886 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 ef536f37b4ed8a42ed3477cebd16ab3c3d8a1ba7..4f1830ba619f03f02993efd9dd7fdff3e822fbbd 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 0e603bad0d1228d71c63d39f3c3aa0d94536f672..4a2caca372556a96a0756a3c53731e3905fe8798 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 2cdd19ba634ba329aaf25e006d331cec23352052..b2b226bcd871c3fea5df6e409befb96852f3ff94 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 4cfc6c0fa147f0a501b5cedf3bd87868daf38e19..72bff94cb57da1ce01006f722d551465435f9554 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 382ac18e78545533f5b24d18c83a9c40a2b3b542..ff79c38287df1f85615c0693987afb937692ae3f 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 e0e32975ca34c7e9bb9b0b3dbc37f1e7bfa9ab12..f420c4dafa03c42afe410e125f2efad4a0a28428 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 57fa05bddb4580e899937b2f1e0f9618080fe27e..b66bd10cdc9b836bfcf0d4e7dba0ac552caaa88c 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) */ @@ -2152,22 +2147,6 @@ struct dmub_rb_cmd_fams2 { union dmub_cmd_fams2_config config; }; -/** - * 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. */ @@ -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 813463ffe15c52febad7e0cb8834b399968097ce..cc467031651daa0e3d9fa96031ba3576845a6548 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 8c137d7c032e1ffa5d4e2ac288424ba4edba3008..e58e7b93810be7271812b493fce921b4a7295ec5 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 c8eccee9b023b6f9f9989f4a81ab337fdfb93283..11374a2cbab87eb06329b573cbf7e0bfe8a76389 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 15e5a65cf4927e9d2da2655d54937a16bb70892e..70ee6be94a9bba32a5219a5747cbebad602f7520 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 5d9d5fea6e06b5a620cfa30f6ad5ef7d4f9d9418..e3d841b2e9af5d688bd919ea9971bd3d07bcca36 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 c4aaa86a95e2b2c82fb8c3b558983abff8b89e7c..72a118b2af69aed6f560f374a955b80f4da9c461 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 bd7242e4e9c68829f2f09f947e24422d59eceeb7..c78b09d6fbae4b8c66d8856ea7376d6f56c4e23d 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 52bac19fb40492bab0802f3885a1c0b349a5184a..b344acefc60668e783f742a055e482b2005174cc 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 2d1135bdc4b9c6c75847f9a98537d7ad431d2e10..5c86423c2e92f75fcd5c7c4f56123418eb72133b 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 3a4670bc4449d85a0837d30cace3ee492097716b..b98b7ae551b5d01db0b10d24cc9c1aef01b8fdf7 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 0000000000000000000000000000000000000000..467897ec2e6568e1b8d3178bc4c477904dc60782 --- /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 0f7542d7074ba155cb9faafab2a3a34cefcc13af..f4d914dc731f8e078b72086ed3c824e18b49acfc 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 2148c8db5a5904ebc555e591046666b916ac901d..5c1cbdc122d24a2134cab411e5adb2b33ee26a93 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 2c3c97587dd5e39b407ab3a008823baea2ea8e08..768317ee1486b98f6d06332880167f79bd8e529a 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 59fae668dc3f6f4eb4375a54554ecb5535510302..34e71727b27d76effb229c5d92e07734ee2b132a 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 9d3b33446adc9e53890fd83c43b0233d526a0cfc..9b20076e26c0fd6cedbd8ac7aff0e8a87d42b19c 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 f24a1d8c77db58eb903a2c8f2d5c4d6271a6a640..d79a1d94661a5407b36caa75132bb1b77d278c2a 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 d47e32ae467181cd338a8e5104f257fe46b5bfc3..9aacc7bc1c6978fd3e1bf9d2311e214426f2a2bd 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 3d9e5e967c9405c3032ef59d6bf57721bb5c8bb2..01790a927930e997d1334c5414c8cc981ebcfa4a 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 533d58e57d05063062c31fd5ae1f43f586d0dd31..e0d356f93ab064058cba3573d0776c705d8b6466 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 7d4ff09be7e834a33eaf64d377e6ce092b3e588c..f00ef7f3f3551a58e3e76aeb0ed004707c456659 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 d151bcd0cca74abf9ea20b671085caee35133663..d38d6d76b1e79861345810f467131f2b2a61eaff 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 80eb1a03b3cac1218c9d354d2c45505a65f82bc4..7eaf58fd7f9ae509280b9b2c087b1d938190b0e1 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 a020277dec3e96bf5d367add675e684faa0f5b89..7473672abd2a91c8a4d278643b3b81a3d000d351 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 a761941bc3c24f788e32bd16ff1b7732b36598f8..505eec6b819bb26c6984a0cda4013fa40e44b674 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 850909f78a7bc0fab54a60880f9a0657e99056f3..e636459d91857a8b4022fcdc97cc431ab9666ed2 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 05afc9f0bdd6b6f00d74223a9d8875e6d16aea5f..ae8a0cf595fc6fb11eecd820c7e8c5b75a746e18 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 78958ddf84858cccc6c65cd289baedfb313e306d..46f59883183d97d3fb2ef14cdebe4937cc3dc9cf 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 e644e2382d77f4e64460b3c33be476e013264b95..e094b8bbc0f12412e2d087d811b9fbc419e170d4 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 feff73cc0005dad9f68a437b7e1a40b35639af8f..adadd526641d2ab994b867533d8f7e60248953e1 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 40d8bbd8107d65dee35b9b4c5ad572b526a4d652..55af3a553c58a1abe25bd5265a26d4654310793b 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 ad49eefa7182c3160c720d50b4e554392f7fc18d..42cf886f3d24fe940fe3e7fa57a78ad3aa24a857 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 74132c1d63858c8b18ac9add118622bccee72d6a..d58f8fc3732658d6b7cc2914dd8f57b3a046f4d6 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 06f4ad8de591e61ddcccc41ab5b984fe3b9ed3a0..e1501b13f08fb6946886d8bd47aeef341bac8358 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 795e6b9cc575c802221bc95527b013909c524134..248136456048e363345d49d7d290dce47eb7673c 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 c6321dafef4f3cc2159bc828a46d03118982dd1c..74bb3bedf30f5d6eee70a63ababb4f9e3ca72bcf 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 5abc5fcc251492bc6acb773ed1a7c1554d80b286..eb89948cc1121dd479c03f3465f25e6606ce5ee1 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 64315b714743addc62385558b1654a97819f9f95..79741f043f03be050132397a5bd1b70b360dc98b 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 32c762eb79edd5c7bdb0c6b80547b596e903dcbf..54bc447efce0b3605054c730cbbb73622a70296b 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 f8cb7c630d5b832b49ce97ff9298e72763e97bc3..127316d2c8aa9979edc453d0fca2f383e09e1ac0 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 1d4cc91c0e40d588df58bfaca5b26f0117cf2c0f..a4902ee08b6e14e4646b83db1721e6e1d14e5013 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 07e81be4d3920febece34709c63a63204a41583c..51561b190b93124a82fbe0e0c961d6bfcde55538 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 522ad49406ce267abe60a9832fbe943a6cd888d3..d79e4defb71ddeac6a2c2bb1d0a591372294ddb3 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 b2408abb9d491bf25773d4dcc1be73c89cf208ce..58279ddaab3ca91548ec545aef7f1246c86dbc25 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 36f72c43eae84d1e57001a7ae1b208ca6dfdfd72..b5f9d40687d59bb973ca646e5471dbf092c4af8b 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 9b5e27d2373c68d98af928e767f6d7450dac7f7b..3b17fd2dba89115a8e48ba9469e52e4305b0cdbb 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 7020098360e474ee149824a488d912a7ad8ed06a..c0ed110a7d30fa1282676e3ae4c9f1316a3a3bf1 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 c380d9d9f5af10b90ef733b05f5b0295c0445f38..197871fdf508b7477e09fb52beb650c031bf4801 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 9446049642e1c60249e6967865fbde895f7d8e3a..d294844d9eaed151d027fe5c53d475ef39f272c0 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 721581d425b4472e7544caad0dd0a7c9b38e71ec..cfebb08e8a62680a14a500d28decfafc2daf743a 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 84d367eab058bdddf5a40feb6a75f29ec62dd9f2..d6a37d7e0cc63d2d62e4195c95fc3cc10fb38239 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 82ee2f12b8d2973255c244cb19c9d4684c33239f..0a3b26bb4d731c54614e24e38018c308acd5367a 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 a7caac5b8ac8a1ed35198263a218c211fe310937..1afa7056698510e4806b9f9f4894766028284c31 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 55dbf450bd9ca35bf42e7354dab22bfb432d84d1..4aa0503852847a2a97e2d4b5382cea94c03fdf07 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 bd39db7bb2408763d0388b62c108b1702e7a1e81..e671aa241720684ec4f8d7b118f8e3d37114724c 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 560d12e50e9e6bd9ca595dedcca3ac564e780b67..6c77550c51af14b8930beaadc89d5c3bb5b0bc16 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 7125773889f1b7b514125f6925d7a44a8b06e528..4aaa587be3a5e6f74eb3db9b1b0e5a0e6f1f5bd3 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 8125f87edc609fbc5dc9272e0a5a4e1cbdeb73db..255e5817618e33023ec34faaf176b0d6a9e3b218 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 b611c7c8ca2da2e946a3fb8978f2643c369e06d2..fd76730fd38c072f37b41b98223d8c15642f55f1 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 2169bc969ea16dc1e54c94590c6e15513f970083..fcc2677a4229dcc6da1d3090db9928960da1873b 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 f5e5234857c1914000b533e800c6d0694c824f74..5394a1373a6bbf0d886bef784ee7a5e7211d4ea1 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 c7d5d782e3f95c5f461d4091d5942b57bf1d4849..c556a04670eef74ebbc864e4c478ea62cce3fb08 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 d99d91fe8aa98a2bfc901a998c9fc78fcb146e15..7aa2c17825da9abce0dea946b94e12dc6b522c8c 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 2e657692e5b5f41543cff08c317172d8424ae3ae..b9440f8c781e3b22ec686f802049646a31b31319 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 c8fa2c011666b1ed01373b5d6d09e3cc8bcb52bd..6383a1c0d4784748746bf8293e667ba6ee8eec9e 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 ce78cee5dec684269251efef99a58d123c543b4c..fee22358cc09be80f5a86609bc41c589f70e7946 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 c250ea773491ec9ef8586b1fecd9cd3ef76ae2f7..308061f0cf372aaffaaf6df342ee7a431f3e3bf1 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 868a5d2c1a52f377de4a78fb1bc2ec9e7c5c7693..60d9354e7dbf4baeaaac6b1f56192f116ce6a6d1 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/_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/_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 2ad38f6b103efbcfd369692a36767c44cbe1dd4c..6d84a52b660acfa1eeb33ecc9b7021dac5fc280f 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 eb293aec36a0fb9ee96cf752c9da85fd5491c943..74f31639b37f997892d274078f2988fcca24e04f 100644 --- a/drivers/gpu/drm/xe/xe_hwmon.c +++ b/drivers/gpu/drm/xe/xe_hwmon.c @@ -51,6 +51,14 @@ enum xe_fan_channel { FAN_MAX, }; +/* + * 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. */ @@ -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 61a2e87990a9de62f04d0b35cc5709d9cc16ff56..63d74e27f54cf11bb5032bb1bbfcc892842ea253 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 024175cfe61e664374f992d9b721ee9d5ec552a0..ac4beaed58ffb669128f1ec4fc28297f9bf8c4d3 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 cf955b3ed52cd0704e499d60de7374b71db6f6d8..9189117fe825b6db305bcb7d52a0373d91fb2309 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 ba33991d72a769126c7a3a2d12fd55133ecad081..de38f44f3201496ccb09907f6ce8a3972d8dc7ff 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 127d4d26c4cfde9fb6d6a849f91fbf57dc7ebec4..0befdea77db15d20918f9cc31ce57239fa63abb2 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 454ea7dc08ac839362e693d567c2c3afd6f211e0..b5bc15f436fa2da64f101b20aaf8595b49ba2911 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 79323c78130f3fee3a2806aab3817da61c8fbeea..8615777469293b11c991a181712423a7ca68a5b0 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 0ef811fc2bdeeed5513c3df1efeae2f4a74206b4..494af6bdc646b4b331d3c3b4306e37c1f13f5390 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 1662604c4486d667c6c5b148bcfc06f3f903bfc8..1979e9bdbdf36b57c43c3bf06f4e83858a095ac0 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 f6beeebf974c29f73113406028a3f7edb2128f7c..54ccc434a1f7386bad34178854b6474695331eef 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 ed34f5cd5a91459bd027ca56fe47e22f41b0e215..0639b1f43d884e198ada39fd5b42d617dd1fb17e 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 bb7db9ae41c249ec820cda922204a83e0710e2d9..5e8ced7bc05a3acca29c6102105e7fbf78d56975 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 ef51b2c06872d04329f1b2208a7aaaca19a73888..6f251b284018744b9863ce968fea96d1d5cac6f3 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 8602c63ed9c6ce4e3bba36edb55811f8e9b44a2f..11e21f98872327ecb1d4870c5a60c521d95d92e8 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 d4d91e49bbe8a919e1d1359db5d50aecadb889b0..36f034ac605dcb6039d890a1db07904ab83a1e7b 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 ded0fef7d8c7be85c0711102b8e6e390182c7d0c..b41001e02da7e02d492bd85743b359ed7ec16e7f 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 c6b922c2adbaa8fd693044b9fcfd04c029d0801c..74bddb2c3e82eb50964e22352d3d5f12b3953ae0 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 a2be652b7bbd1a0e7ddf9ad0e606d51dfc84a0ba..b966e4044238cf73d978eda134170e250da72a92 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 61a4019ddc74300499510210aeb513fac2a3e71b..af98398d924756c5091d94d8a589828664f2c568 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 8080083121d36c090cd9ddb9c565552b9548577b..5b5fc460a4c53ff5cd104b77de2f37833d6f1a38 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 d4cbecc668ec023ef6ee0c631fdb0cdb5e92a1f8..aac0051a2cf6554a23e82c23432187dedd12ea68 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 5107a676e24fc3b6a97fb46b753799b4842868ca..955b39d2252442708e87c62bfcbfb13ca263fe4a 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 cbc5e72857de8ee403b9292a0671b1833e0c3d89..d10a01f3eb9e41b559850654b8720f5f18a0fd97 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 1b1d644939093d8b7f033ca44e834a6b3fd08e01..079620dd42862ef5e026697e9e1b1fcd5b8be298 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 db3b551828ebd2aadfd5c53bc168ba5656e0f92f..802c73def428beb30fada90dc54a27e6e46aa8a3 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 2df294793f6eebe11dff7622d82576644d802293..d0fe53451bdf8b1ae57cff0c4575734c330dc9c6 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 d48d8e5460ff6e3cc4538bdd88ddb648da53078b..0000000000000000000000000000000000000000 --- 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 -#include -#include -#include -#include -#include -#include -#include - -/* 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 "); -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 ecd7086a5b83e86b6bc8ea039d6d26a628334ed3..f064e3d172b3d630515bb3a11450e883a6b5b4bf 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 8e62c3150aebd1e82b445fafc97a0a9b44397b0e..4e7cc3c5bf994d4066adc3b6c203edd19e88a823 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 fa170c966bc3be8a86c16b366106c8e84b1d5d99..5058432233da1932f1965008fc1b98b560490414 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 141feac1c14b0850671f92261c56844a1f772592..755776cd19c5bb724845ca586ace1e0b29e72556 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 b9ebc9fcfb7f204ad76d99801c5f752223addd5b..90fd937d3bd8376d7927c408e762f4dad0c9641a 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 fb43ef6a3b1f0d6d9740e729e7eeb86a5d77ba4a..fa758cc21827552a5c97b6bdd05d22dec4994b22 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 342c3aaf414dd88e36b1c1adb944b6ddc872d50d..a871d997330b09bdb741f35c59108b0b3252cc54 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 80f6265e3740ca92e014aa22d33219611e6716a7..8fb30dd73fd20ae613a45b1a467f457a046a9412 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 16e310e7e9d48a205847de924aafd5bbc0d449bc..8362a47c939c60399d7f2f3f599f72de4983a6e1 100644 --- a/drivers/hwtracing/coresight/coresight-cti.h +++ b/drivers/hwtracing/coresight/coresight-cti.h @@ -9,7 +9,6 @@ #include #include -#include #include #include #include @@ -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 7948597d483d2bb6b3bd4e644de78133206df2c3..d5efb085b30d36b51ca591c1b595ef82481f5569 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 f4cccd68e6256f0127d798b83bc03018f86c0d44..f1551c08ecb20ebd7feab82dbaee3176e6bcc999 100644 --- a/drivers/hwtracing/coresight/coresight-etm-perf.c +++ b/drivers/hwtracing/coresight/coresight-etm-perf.c @@ -365,6 +365,18 @@ static void *etm_setup_aux(struct perf_event *event, void **pages, continue; } + /* + * 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. @@ -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 171f1384f7c03492dfff8fc777fb8f5c0e0ee683..1d753cca294392ec3f3052e5407de07d4e5cc7f1 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 8927bfaf3af2197fcf74388b89219934d266745f..1c6204e1442211be6f3d7ca34bd2251ba796601b 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 b9006451f515f7dc51327d2b69ee161daa8a6889..762109307b869fc59ef0a6dca097ed59622d2a2d 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 2b8f10463840209a603d89f1e5d8fce3a2286db1..42e5d37403addc6ec81f2e3184522d67d1677c04 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.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 fdd0956fecb36d88a5ed4b11ea634db9d4f3df02..ab251865b893d8f24544b1fe302163025d6382b7 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 bd7db36ba197bdb68ac915bfab71ff0860615639..ac649515054d905fa365203bd35f1d839b03292f 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 0541712b2bcb69e0c08bfcf8cddc940d46edf044..b1922dbe9292b02c91ca5730998e59ecdb08fdc7 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 0000000000000000000000000000000000000000..c8f361767c4508aba7f62b4098ec744e3defbc0f --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-kunit-tests.c @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include +#include + +#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 "); +MODULE_DESCRIPTION("Arm CoreSight KUnit tests"); diff --git a/drivers/hwtracing/coresight/coresight-platform.c b/drivers/hwtracing/coresight/coresight-platform.c index 8192ba3279f0e25aca464757c200c9c003fe32de..0db64c5f499592e1985141161b4f90fa1f0410b4 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 82644aff8d2b78a90100186e79cd9d557fbc7f82..33e22b1ba043264ad50acac69ece1ea6de25893b 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 ee7ee79f6cf7750c41d5d53c5120c32e3c683066..06efd2b01a0f71620eac71166567d14655b58403 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 26f9339f38b938a90440463b74e924d5102e319d..e45c6c7204b4491e0f879bc7d5d445aa1d3118be 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 213b4159b062966295eb8dfcb83a4ebe73dea20d..2b40e556be872f5aef1aa313aafda97df5294ded 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 a70c1454b4106c8847e85b8dae981608b762c030..83dad24e0116d449e402f188dcab3b11ab4d0606 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 a7814e8e657b211da77bbfede63b29c482621d77..88afb16bb6bec395ba535155228d176250f38625 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 d858740001c27d19bbdc52065a171eff84b53e43..0f45ab5e5249933ce7059dfee7fe7376ab33ed2d 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 76a8cb29b68ae19cb7da8e15a5debad0581ae2a5..b07fcdb3fe1a8c1f0ef1946d8a524ae321ffa1d2 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 97ef36f03ec20716fbf4e058398e873671bde0c4..3e01592884280819c16398cbb5e09cbaee5d3efb 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 fff67aac841819693d4a1a1375110ecebc11b6d1..8267dd1a2130d37d9507791620ea7bc8cbcd675c 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 5d8b82ae6fd60f4259224927e60fe9450f79b70f..3278707bb8856ccc5b85391d9b315b3fe0a3fcef 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 bc6d634bd85c5f741a0d8e043b81b93bee1e6445..7d482dd595fac348c4dd3cc55fd874bba9b3c52c 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 375c27d1682730b4faf34aafac3037e032d72d2f..2e5fdd479e8da3ebe254dc7a59197d9f7f7f3913 100644 --- a/drivers/iio/accel/adxl345_core.c +++ b/drivers/iio/accel/adxl345_core.c @@ -8,6 +8,7 @@ */ #include +#include #include #include #include @@ -17,6 +18,7 @@ #include #include #include +#include #include #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 8c385dd6c01dc558866ca239295f7c7a95b4bb7b..af84c0043c6c8c6066683444b69311da8b2801c8 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 7e518aea17bf9f9d4196bfc366290e7fb0b1b3f6..0315f4bfd69a7cb9b75a5a98c8019894692c0556 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 cbac622ef82117ab04a97fab69a52811ee341bdb..2e00fd51b4d51cb33ea0c788286965c210b88ada 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 80f0b642b9b0a593ff8c7565c42aebf1675f83fe..1c7d2eb054a21ff1fd222a0d12af501af7f37b01 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 49d7c8fbe8edc8ee21daf2acb005e39cc613fb7a..3fed56bb905454b0fb0fea2355d9167c60916ba8 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 43d5fd921be7b9d531976a81aff4bc1068361718..186d4fe9a556a0713bfa3c22c06ca1a4ea427678 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 1ab1997a55b1f828a1cc2b3be2243c6efb35ea6f..39941b519c3bba7b46b1ebd3a3a9d0fb04ced891 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 aa664a923f916004eb00560006365c3775cd89ba..93a868678722ab4c17602f7b2a2592e3343e41f1 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 96ba028157ee50bc4edfc6e6ed4801a0ca3bfee5..38f7498431ee7ae4f5497e826fb0b1d1a59c4ba6 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 23f5e1ce9cc4baf47d21c4e6aabc72a45cb4790d..85e23badf73318f3041fc5812dfed910d17b8a00 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 0d4ce6c389317209f1b3cdf5cec913dafc876023..b4604f441553b259a9285d478f9cb0c02cbb4581 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 70b3642656abcd6120807ae8f34a4e65a78dc884..26ce50b37716cab2aac1303e2e7f28909ea3d3f3 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 bd22bd0d3c250da8e2e161685cf0a8d7926eb42c..310f863029bb1fd05f87d9ee8bfe338246e371ea 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 c9d51a74c07fbbc214d704eb804a09d85ac08929..44cb50c76cb1beac198630d92c95d0321e6ca188 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 9922868288449cc9f85cf6cf53a351d84c5acc49..c2dd123b90219799ddbbb1a1a340b2b945524137 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 94f827acdd1c9fc7245287417b6a32567a995ea1..e1df7b009d895c8276e856f72727191f78dd3786 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 35c0eefb741e997fe9f533c441327e57ec5c1ff8..71cd1928baa62cb0d50eeb0f478dace789391930 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 bf1d3923a181798a1c884ee08b62d86ab5aed26f..12598feaa6933989635640033e3486d1a79bc40c 100644 --- a/drivers/iio/accel/fxls8962af-core.c +++ b/drivers/iio/accel/fxls8962af-core.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -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 1b9156b6b2e3093f433961a41dbbfdde15616000..106198a12474490da3685e826830c5fcefc856ef 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 46fc6e002714f6893c5e22b11de315465a26a17f..bdafd1f615d90f4837cdfe1b0d650fe14032f18e 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 078fab2abb68bfcfd073b2cc9443f7a2ae85cc5a..2ff591b3458f76d3f840450847ea868a6bd96791 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 f2496cad8ec25fd4df029348737d76e4e0e3440d..910d7b5716e194835d6e5b644e68cc263f8d51cd 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 3857d2edf25075381a8872bc973861ab500f9e13..1fa88b99149e7f3c8051859a98c360e8d8209ee6 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 a05f4467d94a4a8bc0a0139183600ecc444a8fc9..cbb6c64126654a95209d79b004328aea25e746b0 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 0ededf8cfdca6bf390ace701ca11433a92549758..cfc31265cdd0f15de3473897b1d76ae5159ba200 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 30746621052c7e09990828355a537c3e455cebf8..a2b5bdf14ddea718df8f94d70bf14b5d238b03b7 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 2894aff80161fac32f2ccc00e45c577c7546476d..d0a16f227903531ed968408e884a53149505fb7e 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 05f5482f366efba8f5c496385c1ad7003fb79bc2..aba444a980d9dd822eaf95bff9f343fdbd50ae10 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 1b96687da01a695d9fce7ff7fd9afcd4d9b5fbbb..b89bad9e6fe6224a7c2c73d34b80d1e4be838138 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 00e224efc8ed2d03d08a22fb0eb51b7dc1b1ddcc..1bbe660b254fcfc426fe07d25082098caf440e57 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 d31c11fbbe688a862f34b2a7f5c68cbf83611d7d..c31c53abc3d09f29d01efb7cfd31955cd88b9409 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 cb5c4e354fc044bacd6a468a2f544bdac62b987c..1075c8ce0e37e1821904ec4211f0977d38f371ef 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 3fb0f386c3db603714a746c28be36ee78d1b2a6a..aabe4491efd727613b058b009b45187062b19a32 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 ca0ce83e42b2cec52219b91f3c5d513c9f80d55e..67416a406e2f43e4e417210410904d44c93111d2 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 ab4fdba75a0a904970f7280dd31ee5acc8ad20a8..f24449500533af7c2d081ba24fee6cac972c2621 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 6146754fe47f706aff8760e39cf1d7f32678fcd5..d8ec0555f42a5956464f663aefc2fa734a32aca8 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 471c154c3631b03bcdba01004dd172e7b3578e89..dfac2e44191fa5af76c7045f4621eedd455e737d 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 cab592a68622566408834cd401283378081ab7b4..05d4fd540eb2d15aca2a7990e25b71b66f757b8a 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 6529df1a498c2c3b32b3640b5c3a90d8fff33788..ea3ba139739281de82848e25fd2b6ca479a939dc 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 3e918c3eec69d947a0087d7385a298f5f50f0bcc..09ae6edb26504991f011def6618efc3f4cf4df4c 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 4fe8dee48da9a4107e514d70f1f0ec5ce41e44b0..5609a7845b6f50b5818613170df6b234f8f0c496 100644 --- a/drivers/iio/adc/ad4000.c +++ b/drivers/iio/adc/ad4000.c @@ -15,12 +15,14 @@ #include #include #include +#include #include #include #include -#include +#include #include +#include #include #include @@ -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; @@ -554,6 +689,9 @@ static int ad4000_read_raw(struct iio_dev *indio_dev, if (st->span_comp) *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 "); 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 9a020680885d93f4da8922e5cfeecc0c7ce23f4d..1bc2f9a2247081e166680232aa6d4aebc5f41b89 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 0f4c9cd6c102f399327c191a68793bdedb519a46..6cf790ff3eb5b7c442d733d693351d0d25e9442a 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 8222c8ab294021b5f3639238f0f16b734f3705de..cda419638d9a88debb3501d05a513b17a4ecde95 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 98ebc853db79629d577a8884105a279427eb67f6..f1d2e2896f2a2d51fd98f59aea75c65e789e7dce 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 931ff71b2888d4244c7c8198c992f7f58f9c83dd..647a7852dd8dbe46d74f46cda040d06aefbccc77 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 3ea81a98e4553431388139f64d1e426bf0c72988..92596f15e797378329d2072bff71e392664c69db 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 69de5886474ce2f700bf277ce707b15637113564..b3e6bd2a55d717d5384616d9a8a160c57a8f1948 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 7fef2727f89e98aeb1a7938e3bc5a5dbb30f1ed4..3364ac6c4631f57c5e23b5d20ac2bd062d6676da 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 f9f32737db8079a5b96847442a64fea811438363..dda2986ccda075fbfa04851a1ceac7a186b47537 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 28b88092b4aa2d5b3f3c0abbad9fab9da14b8505..7c0538ea15c87812b8239a82d5c301fc7b4345e9 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 aef85093eb16cbe9cc062f8cb4239e955c8a21b6..d96bd12dfea632b62475d6537c8d6601b042de1f 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 37b0515cf4fc2ef49d58673c4eee78a97b7a5149..ddb607ac186033bb1f5218d18898f1882a1849e4 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 703556eb7257ea0647135c4b268a8ead93115c6f..185243dee86ed2e9ebc43b578003d0c010e97a9f 100644 --- a/drivers/iio/adc/ad7606.c +++ b/drivers/iio/adc/ad7606.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -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 71a30525eaab512fa811f28fa79268a1a976bc8c..441e62c521bcbea69b4f70bb2d55f65334d22276 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 335fb481bfde15b79331eabdcbc970d70880338c..634852c4bbd2c531d6c0e02d2f1e62db9008cad9 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 179115e909888b78330ee37b857ba6e355411055..f28e4ca3770763d703ce7162ed353ff90476fbbe 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 #include +#include #include +#include +#include +#include #include #include +#include +#include #include -#include "ad7606.h" -#define MAX_SPI_FREQ_HZ 23500000 /* VDRIVE above 4.75 V */ +#include -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 "); 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 5e0be36af0c5c26f9332a779c27c38479f3af167..51134023534a5b5b10bd69ba087ac1cdef98d072 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 #include #include +#include #include #include #include #include -#include +#include #include +#include #include #include #include @@ -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 a5d87faa5e12763856326ce74361eb520071b537..845adc510239c42db67e8860ddc9e2bc859af632 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 597c2686ffa4855a0fdd9a18edbefe4dc1a164f2..041fc25e3209bdd6908df27f25aa77e78574c992 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 87945efb940b3618fcbd6a9ec1c4251b1dad633e..0369151c7db1e142823bf0ad7d61994aa7c2d0ff 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 2f949fe5587318957f2e423029294ced0a6f803d..7722cf9e82143c7f8f76df0335317f831b71eac7 100644 --- a/drivers/iio/adc/ad7944.c +++ b/drivers/iio/adc/ad7944.c @@ -189,11 +189,6 @@ static int ad7944_3wire_cs_mode_init_msg(struct device *dev, struct ad7944_adc * : adc->timing_spec->conv_ns; 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; @@ -227,11 +221,6 @@ static int ad7944_4wire_mode_init_msg(struct device *dev, struct ad7944_adc *adc : adc->timing_spec->conv_ns; 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 993f4651b73a72fd4edb5f1e835ed735ab60c58a..9c02f919913940ebbc66f4967d6d175fa7d3bc67 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 6c37f8e21120b8927a9588f9db77a03957d171d9..4c5f8d29a559fea7226b84141bcb148fb801f62c 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 cf942c043457ccea49207c3900153ee371b3774f..4116c44197b8d03bcd62fa6328f21a55fc3e0da2 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 414610afcb2c4128a63cf76767803c32cb01ac5e..c3450246730e08cdacc975ed19f46044dc76848f 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 9fd7027623d0c2ed49d91b25d1e9cfea59caa929..71584ffd36324800e23945df7984ac98ba88b793 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 45542efc3ece0c1ca28becba494b8f9826ee43bd..c8283279c47756880e368c62e4c443e345f95067 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 c218acf6c9c6067afdea20468508d06f4a0e9d01..ba7cbd3b48222543aa82f14054b4e20e260e8d69 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 0290345ade84176addb53eae2c6d8630faa504f1..b99291ce2a45ff235feeff19f329ba4505dd1a52 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 359e26e3f5bcfe16d723f621bdfc01df2dfcf6a9..9dbd2c87938c23d91fc93269763263fe73ed5206 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 e911c25d106d470566675c951b3d3fcc70af4a59..5b16fe737659bc70f4ec13112859a34400c9e7be 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 b3f037510e35c51c3b516d3834906979b0a25fe9..f8c220f6a7b47d90d181bc16deb623125bf17c52 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 689e34f069877ec525c5f9ee7258d5140d4bba70..b4562aae84770d11c281d9ed2886f7ab1d2aff75 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 8da0419ecfa3575aa54a93707c681ec8ced28be8..7235fa9e13d57c693751757c5d40e8a799622f17 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 828d3fea6d43ebb0b347e82b0d332ef07567db92..09ce71f6e941e5676cbea3c49bbae74122085304 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 3d19d7d744aa46d8bfaeb2c36503297f56ebd36f..be13a6ed7e00b986ad4984d6582298d8d817f4d9 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 002eb19587d679789a9affa1f9514a720998c470..7feaafd2316f246bd0c32fea99309900b5c65099 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 40d14faa71c50b3b6b54b4bedb754f77a6ae3687..857e1b69d6cd4d65d7ebe5de222fe92875eccdcc 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 0000000000000000000000000000000000000000..b4057230e749cb673cd91aa33b93a03137437c1c --- /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 + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +/** + * 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 "); +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 c178850eaaab103bba5729ada102e0e2408bf4de..101c1a0ce591eb66a65b35e965b2529b825db61d 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 450a243d1f7c0111d99364e031e9f95e0797f880..7e5d181ff7021e6adeb8e152d1d577c83b7a101f 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 97c417c3a4eb066cc8181df7b6ff916f10a7c541..a579107fd5c9e5ab66fe29f1f37bd0001352e626 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 565ca2e21c0c23e02f191f03f4ac66666d727b3f..7d7001e8e3d96d1065171ced8f40066c756b857c 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 437d9f24b5a1dc658f6c9878ab5c3f73d8c408fd..511b2f14dfaf70721f269c5ca7bdf55107753b27 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 35717ec082cedbb3300a873256bc147d37439ed1..a7e9912fb44af8584a658ae8ff3b6dd3ee317785 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 21d024bde16ba00332ee7ae77f87425f169dec20..0aa04d143ad4cc3a46cb28924f7652851bbbb449 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 6748b44d568db68120172a950bbfffb6adc7cfa3..a6f21791c68591f67898a4165d90dc48a64b426e 100644 --- a/drivers/iio/adc/mcp3911.c +++ b/drivers/iio/adc/mcp3911.c @@ -6,11 +6,13 @@ * Copyright (C) 2018 Kent Gustavsson */ #include -#include +#include #include #include #include +#include #include +#include #include #include #include @@ -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 997def4a4d2f5723280f31341b85ab3a3c5f34f8..4ff88603e4fcac0873ad67954a4257d48a573e91 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", @@ -1298,6 +1329,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 a4970cfb49a5d4e14e6d8e6dd2f0013327e6687e..eecf88b05c6fa6acdcf8c8ba07bab11a6df4cdb0 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 4eb2455d6ffacb8f09a404df4490b5a11e49660d..f8e98b6fa7e923c6b73bedf9ca1c466e7a9c3c47 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 0bc112135bca1e5922ae19a7bd591f555e863240..7c71fe5e8d313f8e6cc8d66e1a6b5b1b26e8b9dc 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 152cbe265e1a2ea9acf934f3a9ccef2da2628c40..92baf3f5f5601b863c694eb03b6d8f287e4fe6ab 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 0000000000000000000000000000000000000000..d87824e5490f749687c3d13ef21a31bacad38ea0 --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#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 "); +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 7c1511ee3a4b4a3278e0390f59809ccd9ef9722f..c8283873cdee676a287b2661f04556197a9ef239 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 beb5511c4504006171c56139b928cc4f1f9be77b..72aa4ca2e5a46b295305ee3295ad0135a13ab3b2 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 20802b7f49ea84c00dd6e8c717d956cb20448f4a..09fe88eb3fb04578137403a020d9befaa75610a6 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 d283ee8fb1d2f219674ece7faa5492503671ac94..7c01e33be04c4cc89c3749706515f214336ec495 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 11170b5852d17f52e5a088de47605d5c83ddca74..cc326f21d398271ca3c37d2c0c39209c766eb9f0 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 b33536157adc998668d4d0c6d6a3e806d28381a1..d6f6b351f2af85b2102b8f6fd51c3975e44a1ffa 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 5e28bd28b81a9a9dc4b0d4f7ea56dc02ea0e19fe..325e3747a1345c84cddcfe9a455da6ccf655447b 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 0000000000000000000000000000000000000000..bb7c93ae40558157c0965df6021e4261cfff6f9a --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#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 "); +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 54239df61d86dd8470b820b19e8ee77af1e88268..6ff47415a2221436b1fd548aa0bc070ba5fbb774 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 883c167c0670e2745d68bbca4ad1201737dc2a33..9674d48074c9a7d88b0378159ad3659754a884d7 100644 --- a/drivers/iio/adc/rzg2l_adc.c +++ b/drivers/iio/adc/rzg2l_adc.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -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 "); 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 b6dd096391c11ab62afee6b9e25f11e01c7cc2cc..e3a865c79686ebf73dafddabdc6822dfcff3df51 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 73b2c2e91c088c2e0fb2035ce63f24d05b3894d6..db50a9f3b92208fa8fff37b6dd220c7c92f8179f 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 +#include + /* * 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 5dbf5f136768ef119e308c449469a5f97c863412..e84babf433853977b77aa283025f446353510a21 100644 --- a/drivers/iio/adc/stm32-adc.c +++ b/drivers/iio/adc/stm32-adc.c @@ -6,6 +6,7 @@ * Author: Fabrice Gasnier . */ +#include #include #include #include @@ -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 726ddafc9f6d296f4584bce4a3e43e96aae8fbef..f583924eb16bb100aa669d9e7b1d61f592a99200 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 136b8d9c294f4679adf813316eae19c2926a2742..e4dfe76e636267253adab2a32b6fa541b494d6f0 100644 --- a/drivers/iio/adc/sun20i-gpadc-iio.c +++ b/drivers/iio/adc/sun20i-gpadc-iio.c @@ -15,6 +15,7 @@ #include #include +#include #include #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 "); 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 8b27458dcd661bb6cd9958d2ea0c5746ee68f35c..6b8d6bee18737e4e0b851835c034b13ba33f91ec 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 1af9be071d8deab3bcd8cae676008962bf875f07..4f514db5c26ea803660087ae02b2cf8ec71911e4 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 e2dbd070c7c4f2d86afe586ba44124fb384069fd..cfcdafbe284b103a069857028886411bc72dea4f 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 9c845ee01697c3527c1c198a3f39870e0de37d32..50a474f4d9f55f6a85673d7c5f429b8c656be8d9 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 7f065f457b3617c8672579c9f988a4ee204c5371..9dc465a10ffc8d9f596e34215af685999235d690 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 a456ea78462f3d8422126092c7932c509e299316..1b46a8155803c72f8a21e7da54788709435eb71c 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 #include #include #include @@ -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 4355726b373af5aa50b684b829816a1ecbd8035e..21181cc3bd852ba3bb05b295c98b3530d8c07d3d 100644 --- a/drivers/iio/adc/ti-ads1015.c +++ b/drivers/iio/adc/ti-ads1015.c @@ -12,6 +12,7 @@ */ #include +#include #include #include #include @@ -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 1e46f07a9ca6a805ea65d51e636caa30bb59e3b1..b0790e300b18f7edd697ae515439b2150a73fe13 100644 --- a/drivers/iio/adc/ti-ads1100.c +++ b/drivers/iio/adc/ti-ads1100.c @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -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 f120e7e21cff5fc465744679ebd18047c79d7a8c..d280c949cf476c7bcbc1e046755619ac31d97c63 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 77c299bb4ebcc1652780f947208afe1d5e75764b..8ea1269f74db09427a4a8d434ba1d63e7c63d038 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 c6096b64664e67351e7d2a54da7c4b51adb019ea..085f0d6fb39e695dbc53218f8336ed2ff75861d5 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 af28672aa8039d59ec6fcef7e507534e6ab4cfdb..0356ccf23fea5af1b23ae6fee532eb62e5fa6f89 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 a31658b760a4ae79d1504d6af288470d0cc6d348..b0bf46cae0b69eb1fe8d7734c8a32ac642c5d0cd 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 1e4a78677fe5cfb7d1c3c45bba619880a1e5a765..3f375c1f586c4153caf9b47c34a0dcf6d5c48266 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 5a138be983ede197b2a85b022b6faa9e9e5be297..f67945c62c99f231cdf91c30ecbb64ff859de9ac 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 49560059f4b7b9add55cce97f65ca2c40ec92ce6..c2d2aada6772aae6fc8d01c3878d6e869d413bc7 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 ef7430e6877dcd160a644a4a72bd1e79fdb42be0..3ac774ebf678478b9bdc83f702c3a5c9e05c36bd 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 513365d42aa5b1c1650c0503ab01f98a33f60ae4..6404b015234a4dea0ae3404d31739d1f0d74916b 100644 --- a/drivers/iio/adc/vf610_adc.c +++ b/drivers/iio/adc/vf610_adc.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -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 e1f8740ae688b0aeda7e6adf74944be17ed08399..e257c1b94a5f747c44729583da77cf012c36024c 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 a7e480f2472db972536de3d77d4aabefb8353027..4d8b64048e4f3ae1d7d173e392545bec38239f8a 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 f14d12b03da6673443c479abaa66bee65670bbad..a0bb1dbcb7ad9d02337d0990e5a3f90be7eaa4ac 100644 --- a/drivers/iio/addac/ad74413r.c +++ b/drivers/iio/addac/ad74413r.c @@ -4,7 +4,6 @@ * Author: Cosmin Tanislav */ -#include #include #include #include @@ -24,6 +23,8 @@ #include #include #include +#include +#include #include @@ -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 b6a46036d5eadfcb9487d2eaaab1eb68d820096a..ecaf59278c6feebbb0f4d8d9947433ba55ee186a 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 31564afb13a2028f018926663387b47bfc967199..e73c9b9833959e498fd03b37f9bedf2226b2f42a 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 566f0e1c98a5728f083c42380ee160045f7e2dba..74f8429d652b17b4d1f38366e23ce6a2b3e9b218 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 d9a359e1388a0f3eb5909bf668ff82102286542b..4dbf894c7e3b55d0aedacd24b4d625e001240333 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 e64a41bae32c67e43fc9021c186170c4bacb2ae3..427d32e398b36068188011f8e934a94ca7650b15 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 ba18dbbe0940ab1ea501e76b57409d6ccb30550d..8a306d55c72a84b8fd14abb12bb4b3aca7d0345b 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 330fe0af946f753a45ef02a79355645119bd1e8a..b22afa1f6d594c4edd893d7d0fb50ce1cfe52289 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 4866db06bdc95d61ea5fb2e97c95b1f4a342c46e..2287a00a6b7514760c8eb1644aabbe60603dc473 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 8fcd80946543638957fd7bb2ba5bab0388b66629..151178d4e8f49e8e26ee1d824788d8ff38495ac8 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 761a853a4d17e5cd0eda956d91edd2ce36476e24..de0b87edd1887f5cf28cc50a36542f65f9d77dc5 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 baf93e5e3ca798cbe36d01b401e9ed0f047b3a47..cb6662b9213740f4a88b8412e6a0f01bc5a314d6 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 9d73fd2cf52cbf4a6e48a8109c1a4c729fbf6c60..3e850562ab001f3ef7415d69c4fd3b7adb9ab32f 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 ac7763f98a6ab3e95bec342414f50728b1f9443b..5560ea708b3614e06ee906dd69c87d5e0c40c7a7 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 ecb24ba0ebc9a75b530056e12dee9b641329f38b..aa97645ba539f6a591112d6554b893814d1ac418 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 451fb65dbe605610a8df94a5a228f668b5ea1e49..998c9239c4c7f4832c5120f58fae2431622a99eb 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 #include #include #include @@ -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 152f81ff57e31223e5c446e4f3c5947d4decea79..6cec600748272dbfa1772dc25536722907d08e37 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 0000000000000000000000000000000000000000..3c64154918b19712516c0de15536113e98f56c9d --- /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 + * + * Datasheet: + * https://www.winsen-sensor.com/d/files/infrared-gas-sensor/mh-z19b-co2-ver1_0.pdf + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * 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 e05ce1f12065c65d14b66ab86e291fab47805dec..656d4a12c58ff75172debb8d018cb295c874ad13 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 3fed6b63710f0c57591e33dd43dfb1762301dff4..8316720b1fa32b9746b4aeefe7aedc77b3ba57e6 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 50e3ac44422bdff129eacf0eaf4d37058fe7bd85..2463149519b6d82caede9c9b253942fa421fdd3c 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 0000000000000000000000000000000000000000..96c6fc1203ad1ddced5f6e57e21e4237bbf0be7a --- /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 + */ + +#include +#include + +#include + +#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 "); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("SEN0322 oxygen sensor driver"); diff --git a/drivers/iio/chemical/sps30.c b/drivers/iio/chemical/sps30.c index a7888146188d09ddbf376b398ee24dab7f0e2611..a934bf0298dd5837223da8a90adea72a75548c35 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 cdb8696a4e814ef3e4089c3e74abe437ca8ce7e9..af79efde37e89170128ef9351bf1ad8b993d4a2d 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 119acb078af3bfdb33bcca905cc2e4822f92bbd6..2d3d148b420687c4ad4adc7ca0931193f1bb2dc0 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 66153b1850f109916d2ccb25f82d9977f2f0f24c..82cef4a124427239137038d63a9bf8a7f4a78b07 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 7751d6f69b124145f56f4bb892fa9ab514a52909..700ebcd68ff47306d3b55f92341ae64782c77db1 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 ed15dcbf4cf6b1e49eb506972f00d40e0c3dd6c4..da516c46e057b8be283d534720b4958d4dee5162 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 22ea10eb48ae71b369b20568938ba102e1b46a6b..1e167dc673caec68e7bbbb9587f11b73ff5e825a 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 f32b04b63ea16f3a5f016b32abb38ab495358da4..b7f093d7345ba5d26a6c515a47a4866bc79eb785 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 e4f5a7ff7e74c95882e772fed510538be76fa462..8ce1dccfea4f5aaff45d3d40f6542323dd1f0b09 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 4811ea973125a0dea1f8a9cdee1e0c045bc21981..e0996dc014a3d538ab6b4e0d50ff54ede50f1527 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 8dd6cce81ed1152be4cf0af9ef877b5482ceb347..3684cd52b7fa9bc0ad9f855323dcbb2e4965c404 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 0000000000000000000000000000000000000000..f9752a571aa53ca0d7e199ed6a78550358185bf9 --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 "); +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 b8807e54fa057fe02afd9734ad67a4eb0a498e3a..38baaea0e6c85cba7ac6f334a3c31c7be88ac780 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 cd8dabb60c5548780f0fce5d1b68c494cd71321d..41b96b48ba98b6009723c6a7c0c39071083852f8 100644 --- a/drivers/iio/dac/ad3552r-hs.c +++ b/drivers/iio/dac/ad3552r-hs.c @@ -7,6 +7,7 @@ */ #include +#include #include #include #include @@ -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 768fa264d39e9e6d517aeb4098382e072f153543..9bb46a9e07a586d407a400094f1872ea79836dc3 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 905988724f2731f164f99be11d6a7a70d13d61a7..84be5174babd965e7b8fa74dc5b356ca97237f72 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 e0b7f658d61196c191ade50dcba22d7ec2d5cc49..a57b0a093112bc14404c7e1fcc27b4d4b136cdce 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 392a1c7aee03b515e9e068a1fc9bb4e594bef267..f63af704b77e3dc60d11bda7ac44d3a4ed6a7ec4 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 6ad99f97eed55ff4ff4be22f3d6ef3a858dcf87e..ad304b0fec08352d51c3ef25c53897c03b10ab56 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 1c996016756a8bdfde2375a4b044997433b514fb..d8c32526025936465b9ef490186a7e78c3c17b46 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 ff0765c8af47f89659a0cd5756b97f6d6c0462ed..355bcb6a8ba0bc931d5eca8cf07093cf2a586c0a 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 50d19304bacbc6e0b0ced51e0fdf948b603d04e6..5f2cd51723f6fdee58aa9eb0cdc3a12baabc4aa2 100644 --- a/drivers/iio/dac/ad5592r-base.c +++ b/drivers/iio/dac/ad5592r-base.c @@ -7,6 +7,7 @@ */ #include +#include #include #include #include @@ -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 fd82d8701322c4ec5b3bcb5d413e369e7c5a26b8..92d1b629b85dca18c21820cd1a7c2588fb36cea4 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 ddd13ad821a794ad501d101c36c651d82119cabb..9a8525c61173ba5d992e4a1b21a08c10cf4a1bc1 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 2fd38ac8f698856910d186099f8ffa2c34ebe5d1..13aefe769bad893069ec4f5158f9c60bf296bc9f 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 9c727aa6ea189a7ed6353392bcb73e113e5d5bdb..df8619e0c09286cf70ae3f4f17a83f9256ea530e 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 763af690c444399a620fd0e55c1e916b1beb8b39..d9cae9555e5df4211634d2b90b0c5a70dc1a8525 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 0156f32c12c88edb46303cf8a3b79c7ed7624036..d3327bca0e077a301a8e4ed2092e8835e75279c0 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 05e80b6ae2cc3fe2be68e5477e95047889e3ef83..d0e5f35462b1b811c32f39a47d855729928df679 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 98771e37a7b52cf9a16a664e5510f903c53f49a6..4ed4fda76ea97fb1a18f81856f367c0a4f0d397b 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 0aa5ba7f465482edffdc5b23bbf79fb210075913..b5d20f04f070a170d911aff65c88600bd2de5428 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 f658ac8086aaa488540855c849daf46abc21275f..f6a0a0d84fefd268b4693ecca1e2cc0e8f241fef 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 25cf11d0471b60071a7912d3886b6d8baac9dc0e..6eb4027a44fba20a9a789428f3ed278054c65497 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 07848be3f8d5654418ebbac7b33c14fd1014a2c8..41582f2b90fb9d83ff82ccb27a0eea92d9d9b431 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 d3f49b5337d2f512363d50b434d99d4e9b95059f..c3797e40cdd9f5f6335dd4d4b2fe52d56eb4075a 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 bff6bf697d9c17ba220ded7f1f2e3f909b77a1fa..a88cc639047df2f98da2f89f5ccd3b6b7a35677b 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 8a362fae2ecac109d0c7ac3abeacf946b4d55882..60e663af1cc18fed102918e184cb56f859e5e891 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 b6a65359b0b47669b4dbe7cf4e49d3f7426efbc6..d77b46d83bd4ce46cb38c56f790f9d63b2564e15 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 892d770aec69c4259de777058801c9ab33c79923..33faba4b02c279885470cd61f58d7ecd3cd50c2f 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 f36f10bfb6be7863a56b911b5f58671ef530c977..d1b8441051ae192d495808ed8566503477850211 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 e89e4c0546531f186563da3c5e312e1811e8a79a..a26a99753418db66d013f31bcad7072bcff60813 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 2332b0c22691522d44407a51544d60292a833de0..aa1c73f8429d31a77e42ee469c40ac9477464ec5 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 2758fc8a5ad5cade6c03a50e13a13f9407b31b51..6e80b49f466552579f32e33ef1562c197ef2e9b3 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 999348836d877dfaf21a2cccde4589c303f19af1..105f939f7e540771af9d31c978215085fbed02bd 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 bdc857c7fa6d8d33cbb81e2d498ea24196a27c13..1f24f07d1ad24ac1730da0e03b65207ca5f07884 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 9f72155dcbc7850f90c13e289b93639f5eed68c5..1b8fe6b8d26ef37757621cbc15a726fab228f927 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 b062a18be5e7967f4d96f4b2f37719c2bd93c60e..e7e29359f8fe5a5c33c29a100b2ce381f2321f71 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 1337fb02ccf5594e19e1a836c60480b99708ebba..62972494a2291af62fd62ae893b4cefd6f00c227 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 192175dc6419eaea475a3edbfb31cee047c6a607..4f30b99110b790d902786503324a118970f27a29 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 c1a59bbbba3cc1634f5c70be07dea9b6a1a282ed..748bdca9a964dd39386295f347d52aa8c217c616 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 26aa9905981340d8248ba93b0d339ce47c6f393e..74f338afcab98d78d961b9cf0ae6cb6626329ebe 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 e998ab51052eede44a00ae10ee9bcb5e5195a822..a35c37d2261dc0144ca7c4a4ced567a3372e68d8 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 95ed5197d16f563ab68eefebec41a30f8c191b02..8ef702917060963005c19021959e983b41611df3 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 3bfb368b3a234022ef88ee25e8d19fb2dbc7531e..344388338d9b029009ba2f04a2bae05ee43c64d0 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 8e1590e3cc8b28c3b669aac8a0f578784adb9aab..715870c8a9c4a8940d5e932b6555d2be341b43c1 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 c5162b72951af6c4d0a56a93cf3f3d65ead8aa12..bdc3f94aef98dea64341996430c3dbfaf56a3abf 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 6f4aa4794a0cabe07ea5a73522826891f23e04c1..3d2ce61f0db653db9ea0f23a94ffd4ff5e3192a2 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 8195815de26feabc96102abcca851a82476b2b41..c308eca02b88bd23ff3c91dcb39caf9789dd7b66 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 82a078fa98ad9a86d1d09b456a93321d197b3d0e..b30ff7bb44002d4f02c5eb4ac7633774d16b7813 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 288880346707a2b5b58332ddc4c4d7ef5701ba4b..e35e0596cbfb406d893ac1b557ab0a23dc63467f 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 d85b7d3de86604b0cfc9d4e2aab566819f96b4b3..19f823446cdad9176beee4949f0466bf51d6f126 100644 --- a/drivers/iio/filter/admv8818.c +++ b/drivers/iio/filter/admv8818.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -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 b1554ced7a26b8c331e833f3125a9927e8ace289..63c485e9e44cdd598418b8c89c71102643a1ad1a 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 61828e61e27589b68ca729cac9cfa9c3b83da9a1..47f1c7e9efa9f425a4c7cf82be930234e2c18434 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 9a84e81787b1120a12467a5375a0777a0ef7f7ec..d6dc7827fb410da487610e1203f5e19da79f8a30 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 45ceeb828d6b683d8e28cf6df74be25854e2cbec..08833b7035e4babee0aa167005a762c0f0b0b6c1 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 8ef583680ad0b18959225a8129ca1fcd7f4b0db0..d8e8d541990f874785d7d8ae2d555908d9c2c573 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 986b87a72577e596645448a4969b4e1fa5842a28..7a8f92ec80a2e8f699e90550379b8c99ec9ebffd 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 57ee908fc747e153347ced3d87af515716d90efc..a7a21f929970d4ee947fe22a3ad81a5e3b6f226a 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 14b3abf6dce95294e9b0f35ee049757675fe30ce..178bba95a70943d40ed7ca875aa05ec4a290eb1b 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 c151fbb59ffe884a3ecefa8e1004e518e46c93c0..586e6cfa14a95437ea38197d4213566cc652ef4d 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 223fc181109c989fcfd965ef6acf15cb7ad762e6..8fcb41f45baac5da6740b4b01c055c0c77a1b14f 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 f84438e0c42c5840217680496e1aa5f43326d4d9..a1d8d3cb301b26a1b15fca2f6bb9bb1494ffce79 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 e6caab49f98a7048d64eef2fe6f9731d38dafbdc..1fb8a7969c25d32473f9289f0951e974b60570fa 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 ac04b3b1b554a80c40a42896a42f5cee910613a8..6aecc5eb83472ee515c33315d78668bd9a753957 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 54b6f6fbdcaa12abac3bab53c72c14464eeaa568..c43990c518f7756e1269dac61c791d34e2704ff0 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 d66224bed8e3aba5f9805b837ab25ca7b74b5548..16553948c5c3a40b79cb2c9663e2d42e18782fa6 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 29ecfa6fd633505ae0e9aa1653d90bb5f73dcb1e..8e284f47242c5c281769beda824652db4cda2b43 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 d4b11bdba66693cf1343d20fedad32450ebee3be..aef5ec8f9deef2e9e39837377b1348768455f875 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 811f712711f5ef7725a96422c81ab31d4dcdbb49..f645da157372b5dc106bc451ea0b4dee263d6fc7 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 13e1dd4dd62cad0023ed0b4268a4b0deda5a207a..1582cfc03579d29bb830896517d92104df900bab 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 d49e1572a439f8b861e937e2903e9726924a17be..99ff68aed27c8ac512fb8f6d1acb5e588e46f6e4 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 e08d143a707c0b26f2ea3c75fad87f9f4a6884a1..846664a4ee905caabb146ffd08b6a474d61064a0 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 1d074eb6a8c5e97e50bfc452a4af3026e563372c..f5f29d2fec574357f2287991c954a3caa501a624 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 2323974b805c55f3b4cdcc6cae18bdeef7f729e8..f021c3e6d88691de58084e83e0c5c5b03a1bb893 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 a303f704b7ed25a4a81dc5da3b6e3018b7ef8928..c2b36e682e06f2a962c67a08269715e38fb5ddbd 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 #include #include #include @@ -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 f5867659e00fcea0f866191dbd7f234da88f4ab8..894a8b4ab193ca6fa0f0fa8c2e126d87bf766f4c 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 a40e1eb6e98c26dce76c188542a70eec7d0f872e..be2338d5f407086d3d5d8645ba30d9e3a46da627 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 0be11470730c6cac9aeadd4aa9878f35cd8bbecd..bfeb0a60d3afe8311b1f326ac5d592eaa458ef0a 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 87a8e3c8d277275c065f081c19e6e620cbfef8f5..cbaa7d1af6c4e7988348ef70074791b4f2fda237 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 00154b9d66b5d590b4484786174b407a222bfa11..e6fef2acd523ecbba26d2e3c103f95bfdc358a40 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 6402e393edb875771c9313dd9ff33d7d9c74ce0f..7f1775bd26fdb2f2c08235a7544d8e5a7f893e4a 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 0ea072a4c966994ff8b1a6c7572bfe979ada43a1..d160147cce0ba7586ac7df69af58816b413bbd46 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 3086dd53620382d25c5b0c35aa1b3aeea8cc722d..90ed3f9bb39c502996161d9df3addcb093ccd11a 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 ecf74046fde1f87a69fc2d57268fc64ab7c9a9ef..ba1887d36577c8f4078ede762b8b98dd373d1046 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 df8c6cd911694a29f6e68dd6eedeb16f497d732e..924395b7e3b45dd3a6459d6eb788fa2ec86c4a29 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 727e0a11eac14771b1052aee4e301ab0bb9c4870..543d5c4bfb114eff00b230ffdc36f6a34c00ce72 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 fdfc0538734c5e781be9fd5b7183f3dfb51830b9..cd3db2388164b558b82c5da67423bd2ca142858b 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 214503fa4af56ea9b2640b0e2b1c4aa01269426b..9fa3a19a8977f7292e48a5ec165986997f60b206 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 8fbaab22db812369a66564fff698653c1e0e32d0..ebb586904215bad67c615de9f299df294d0f83ef 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 18787a43477b89db12caee597ab040af5c8f52d5..f893dbe6996506a33eb5d3be47e6765a923665c9 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 388520ec60b5c5d21b16717978ebf330e38aa1fe..e6cd9dcb0687d19554e63a69dc60f065c58d70ee 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 ef9875d3b79db116f9fb4f6d881a7979292c1792..63d46619ebfaa1372171129fca96381ef4606b2e 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 591ed78a55bb5b80c2ee656aebecef75a7c1f75d..b4d7ce1432a4f4d096599877040a89ede0625e0b 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 04e440fe023aa3869529b0f0be003ea0544bfb8d..7e4d3ea68721a8c3d69b7b26360e6e45148265a2 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 2bd2c4c8e50c3fe081e882aca6c64736510b474c..13e2e7d38638869d42530f5fbb3461dc49027860 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 213cce1c31110e669e7191c8b42c9524c0d3e5db..988f227f6563dadfd935ecbac259802f534c2b3a 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 373e59f6d91a5b058e739023b2c46c5826e88ec0..a9bcf02e5b43fac0e210c6f78816a3c042b52f3d 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 5bcd5e7970468d0279aa81f104d1355d8ed3c648..b8656c02354a6a02624fba28a55778e76ef30496 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 91d77f94d2046aa141eaf33c17d0d5391fe606eb..8dc61812a8fc46c907ba7019965444a29d551e63 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 20de6eb5cd35568623ed3e6ae6aac49a632a681a..1f4c62142b606688a80476f83c9538b614dfa544 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 e19c5d3137c6fd96ec5f9314c183c11835dea0af..2bdfb2619137c353c2659f554f4ff84b612e1718 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 4492c4d013bd6a22c76f51a427c6fa0e240edf3b..d159ee59acdd45102c2877ece812847bbebaa8ac 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 96c6106b95eef60b43eb41fef67889d44d5836db..c65ad49829e7da3716825626d9cd25fdfae32ac0 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 25e1de89b6e49fe28b337c1d79087c491a25878b..7c933218036b840ccb7e4ed424968c7e5adb7d38 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 f968f32890d17447ae9579c433c4a3eb6a84740b..cb5c5d7e1f3db26fcd97521aabd830e0b27ea790 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 c1b444520d2a1b2c9a0792784bc61045da33bd8e..3c5e65dc0f971f4dad8d1156f6de9fd6be3fc0b6 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 4b4b6d45524fb8779039e123c1f2a5ed1d7cf846..3389b15df0bc0678fe613f0dbe20a84919600b46 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 8cc071463249d42b66cf91b93c66a244c5db8992..4232a9d800fc97c2c3139157dd931a47d1022449 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 806e55f75f656d861b9414ce8eaebdbebbb95ec4..acea8a0757d73b4f50456b29a7f05308b4fc734f 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 a43c8d1bb3d0f4dda4277cac94b0ea9232c071e4..c1eb9ef9db08aec8437d0d00cf77914ad6611b72 100644 --- a/drivers/iio/industrialio-backend.c +++ b/drivers/iio/industrialio-backend.c @@ -380,6 +380,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 diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index b9f4113ae5fc3ee1ef76be6808cc437286690dae..178e99b111debc59a247fcc3a6037e429db3bebf 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -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 2d91caf24dd0ae77f72ad7573d28d8532ba6f984..032e6cae8b80535ff29599c47bbcc1de55072673 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 9240983a6cc47d0fd8a564f2d71c133c15b9af2e..e321f89c534042c417dbe26cabb35a7dde9ae42b 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 e2fbb1270040f43d9f0a97838861818a8eaef813..6f301c0670454e2f729e1b2545e6203cdbc91c11 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 7cbb8b203300907a88f4a0ab87da89cabdd087f3..0932fa2b49fa7cd99f10c7b4dbbbb51f111618c6 100644 --- a/drivers/iio/light/al3010.c +++ b/drivers/iio/light/al3010.c @@ -17,13 +17,12 @@ #include #include #include +#include #include #include #include -#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 497ea3fe337775b07efdfc56c80beb1aa55e394c..63f5a85912fc9a72858c49f6c207e385fbd2cde7 100644 --- a/drivers/iio/light/al3320a.c +++ b/drivers/iio/light/al3320a.c @@ -15,13 +15,12 @@ #include #include #include +#include #include #include #include -#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 5ed7e17f49e76206609aba83c85e8144c536d17d..e9b237de180a97d6541e2a491ed45381123d4945 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 d30441d3370309fce9d6c717d42b829ff1db3174..0003a29bf264e93ee4e0949f65ffaf31fed17ce7 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 37fffce35dd112099bb2ea3c613b4ee18f5b2770..68f60dc3c79d530bb5f203c6623aeaf528dc2a99 100644 --- a/drivers/iio/light/as73211.c +++ b/drivers/iio/light/as73211.c @@ -16,6 +16,7 @@ */ #include +#include #include #include #include @@ -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 4b869fa9e5b17ed179b2c357fff1cb244e9172f2..764f88826fcbc2c14ed7093eaaf18a70808b54a6 100644 --- a/drivers/iio/light/bh1750.c +++ b/drivers/iio/light/bh1750.c @@ -22,12 +22,16 @@ #include #include #include +#include #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 475f44954f61106260d9de0939e59bb3c34ef65e..c7c877d2fe67f7391207c860e844bb8184d96bf8 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 5b00ad2a014e9945d92b14ce5ea141ba6ac4e743..e864d2ef036e87b7a3ca286770594681eacd8e58 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 79a64e2ff812460a765112c2cd49ef17c6c1ac5c..79ad6e2209cab6350caf70e1f9b0ec45b97e92b3 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 675c0fd44db45a7c32b98c21be61e1d5d4a0e081..0c17378e27d19e8a829cdcbebbbcf402278ffbab 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 19e529c84e957a13f02b2a15a9fc1333d5308cc7..815806ceb5c89dde841d4f9d551a02ece51c6c5d 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 d56ee217fe538c8babb5df510932bd6e67c59ea6..42859e5b1089daf97bbb793e43fc8844ca10301a 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 1a352c88598e5d701256aa8659a7f9683bce56f9..c7df4b258e2c269a84f5767568fb4a5c7ae1484d 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 aa4c72d4849e1339416688b9d167382b15e08210..830e5ae7f34a75bb1bc4b71debc68f83dc6d612d 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 4c65b32d34ce41e4b2d73096f05add0bb9c765eb..efa904a70d0efb2a2f1218cd6fd6c5781fecf7d1 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 201eae1c45892b5941265593b0a76caffe8b0c77..1b4c184230489eb8b0de6c43751120d03dc31a06 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 95bfb3ffa519a10261320afd6065822a957c70f8..609ebf0f73134008f7fbfaa1b81a88f9faaa5d51 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 326dc39e79291d06a36b18c8274fd4e352f227ae..6bc23b164cc5546feb7bf5c31883e19404a0aabe 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 e7ba934c8e693d2122bb77b7d862bf6763976329..fa4677c2893133a74f4b83225b945a647a91b0b1 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 df664f36090301e21d6e2f92035198e15e018712..ee59bbb8aa09e9d8973bc92e002592dbe527114d 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 669da0840eba0884548a4c44d7522480b975aa1a..8d8051cf6927c65521171ddbd13871993ee4e6b4 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 dbec1e7cfeb8636c1204f7b23103b7a8ad1a51ed..61f57a82b8727978a7a8ff6b6ff73a76f20da217 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 6cf60151b3d8b5530e71908f629c89bc012becf0..ba4eb82d9bc259b240052efaa0d5442d7e4614c5 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 ab55f8d2ea0cfb6b3a890cdf53932a17591070f9..f4085020e03ebadb2b91db3212449db82d738ebd 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 b920bf82c102186ab7954133de28a5b35016eb11..8885852bef22d72262b1b715c9503e2adf2eb94e 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 cc25596cb248ab43c9b4d5c9d312fd8ba4cbd612..7cec5e9433736648922c66ef8ef35c32d8098b0c 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 2ba917c5c1389c420c6b479c8da70dd8890eb5b8..92e7552f3e39222c93f0bc55e7cbb172fe185a9b 100644 --- a/drivers/iio/light/rpr0521.c +++ b/drivers/iio/light/rpr0521.c @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -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 66abda021696a6ee41854cedf0ed68f0a9b6dbdb..4aa02afd853e90b51e803bc23a5b9fde4435e9d4 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 40a810000df0662dab89bcb8b1531a3435cdd967..124a8f9204a99c7ae2987bf89bc405326830fb2b 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 f54282476d11d60db7b991c428cd5a2084ede2cb..5d9bb4d9be6316c5a81954a1787d93cd56bda645 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 18edc6a5a4a4fe98a62727e4ec02997abe13a756..a5aad74ce73e8ea7f759b0305f4113958ed27584 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 b81cc44db43c377ad8a8cc61c4430decb187181d..deada9ba47489eb723120d80931753adb8e26775 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 884e43e4cda4af5dd38329d06ba440b69e7246f1..39268f855c77d9a0b93183d6d14f20b3f10afe62 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 2bd36a344ea5c7f93d1d2e3827b84d7d61412afa..0f8bf8503edd96a3ddfea0b2e661de7dce2b004c 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 f1fe7640fce63bddad57fbe7809ee60bbfd44e1f..f2af1cd7c2d1ffb58b8b80a20540a35c3d621488 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 02ad11611b9c576afa7e09515ed6fbeb8c4f0db2..fc3b0c4226be876f87115f1e36abaa8a92376a17 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 b81ca6f73f92732dc66a9be35c9dbed5088e8da1..08476f193a443f7e513bf342157ff4dce9fc3460 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 349afdcbe30dd0c4c0fbabaa16ff7832e407e8ee..0b171106441ab61dca6bec57867678e36f3c83d7 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 c83114aed6b23f1d68068105b7c145bedf005b36..61a0957317a1aa7fde67f5911de276efd55653f0 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 e19199b17f2ef7ebd022c211605418711b8220d2..90e7d4421abf20d1b2104c7932e9383e5d43229c 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 67c94be0201897f0ff9ded5c2be62e2fe4c7b497..b2bede9d3daa621a602ac6bd9940fea21a8a5ee5 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 216e271001a850072f2e93e9f133ec32de286f82..71a594b2ec8588046562417f2a84d7114efe71f1 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 859891e8f115217819ce1d3ebbc50032745aa63a..edbb4340705435b77a49e4889fe20e58ca12b368 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 6e2183a4243e55b95840cf2e0f0069b3b6e11502..cc4f2e5404aadef42b749ae1734fd09a173f9cb5 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 604be60e92acae020acdbd274a599726e31983f8..1e5e9bf2935f63f9af4cdbf29f825b218ec477be 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 c1fc339e85b4fb0a55aff45d309da482ac54693e..192ba2da94e299d9a223a33bf15f9d6e6c29f6c7 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 7bc341c696976229f78d0228b150036ca12393ea..947fe8a475f28817a1972db6498aa7258d5cad60 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 ef1363126cc2d4ce2a1dc1ccb916c2ad069544d8..a1e92b2abffdddb4b79a1b03594e4b2167cdac9d 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 87b60c4e81fa1c9d8d6e8b083c5bcb605baf8ee9..f72af829715f71709a2b5948a419fd7516bb9b0f 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 88bb673e40d82b1aa78d7a567e9f3c08fcdf8617..f9c51ceae0110b8def19b5f421d09a9bb00fa5b6 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 8cbeda924bdaa343f2a0507032d169a1010c70ea..b110791f688a71d883a77d830203a32b65d57bbe 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 2d4b8cba32f1428c6595de44b4e47eb29f60f026..896b1d2807311c57c41fabf68f9a2ec7aa9e0d2d 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 97ddaa2a03f698e1e2a53356eec3b2cbb496a5af..c673f9323e4762b5c0f150bf020d7c5add1d505c 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 ffd669b1ee7c02b3bba5538ea29ea32b6e74762d..7a3faf7ffed43c7bdfb51f8e8669f6a093d32059 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 2fc84310e2ccb237deca1262abbc81ced3f5a88e..fc16ebd314f74478ebf2fa10f31aba4b1bc45cdb 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 657a309e2bd57898d7a15b0a01c1851281515842..b41709959e2b0665a8425efe9b4467e61c371fa0 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 b7fde331069d6a3d2f5cd2ecd636318d1e276222..6a55c1559b0d8c0c73b4360a9517707651df49b3 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 2fe8e97f2cf86385b9bb342171b85a857e2151c3..ff09250a06e7596d4cb3e50c098ae5f0ea2f3512 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 #include #include #include @@ -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 dd480a4a5f98577242eb6d278758b8093638ccfe..e08a57cd6de264a4f1a3b8b070c7846144694bc7 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 c99694a77a1418bcc5a8bd047552e7604e9ae559..2b28844257460f385d260dc26b1312b37ac53741 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 dd6d48043740c12a45f1d10aa26c732128c7db27..2f60a41c07f7dfdc5e4a083f51b244f677547af8 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 1672b274768d4d6e9d609c7494d82d89e5d4ebff..ed70e782af5ea78ec553d787ff6981eeb44bceea 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 fe4d0e63133c03c8fff68c37a23dce2ea2ad4e7b..68816362bb95276ad9beecd7ae1d54fed059108a 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 4187abe12784d532b6bfbe393f6b1c859c7255a5..2ca5c26f00917426dacb4835fc9684d0710d98c9 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 28012b20c64fd19e5b31022fe4b23377de022798..340607111d9ad8b9258b7fd416a232f386f157b8 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 c309d991490c63ba4299f1cda7102f10dcf54982..b742ca9a99d122d7bfdab74967e205da5b05d1ed 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 429035b65c657acf5558ed10d289f56512fe2d28..4e23a598a3fb956ab893354507e5fab9385bd371 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 96f03988640c3148e7e66abd0ffe786f9b5b3b61..e759f91a710a2cdec8b708faab49c557e3418146 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 423bbb8a3b38f27fbc3a8c843504c8381c94a6d6..bff7039690ac33bcc9747add8055023dd5a1f3ab 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 b17941e4c2f7c543e64e4eedde642520e0d3e405..672b1ca3a920c517016142ebab15ed2978502990 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 e0526dd0e3cbb02243f271a4ee3ddec2a043776e..5761f69c538ab32f37734fab7dfeb970a7163187 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 c8e2481dadb5330fed5ba0eaa5d29121296c4cc2..26390be79d029db0cc057f342de8c090f1f80e53 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 4838d2e72f53def3b388cba135cf62835a6dc89d..3b11b991940b491ac32d0203c3cd98cd516ab871 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 44678d37212616eaa331cf260ed93d7475defb6a..a88bb2231850d81b3630dd36b51ffde06fd50038 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 2b73c75402094ba0e3ba18ff6a5ac94b8c507cef..f35fc4a6c55bd92fc54f617126c5c5b6c9245307 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 7890c0993ec48e72efba206034451fcc65fb573e..9082b559d02960cc023aa292a2176ea3da0d5d5e 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 f28880ebd7588e5d889bf91ebc0d44a5c311ec76..9912e91ff7b4c176fe0694c16f10e36d51f85ba0 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 8923ccb0fc4f793c64e01c5b6c2143255e27ab5c..a42b5773336388d2e56b86d828faeb2948ecb22f 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 c2c6b2b298675bbae7fda6cf8b4b99b43d0b1f8d..030498d0b7638081ea865d01a6398b608f2f143d 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 752a63c06b44c11c1d935732d00ffac41e5ff591..a0d956c3e2543f353ff0c157e01312645653573a 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 d44ab65c94cbe095efc60724d5cea8be3ebdb01d..f37f20776c89173b0b2a8e28be0ef9aa30ceea53 100644 --- a/drivers/iio/pressure/bmp280-core.c +++ b/drivers/iio/pressure/bmp280-core.c @@ -46,6 +46,7 @@ #include #include #include +#include #include #include @@ -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 868e1b2ec7112add5ec892f8be19e1b148985438..8e459b6c97ff7632be880d4ceb117b251c9cc19c 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 0e6e27892f99a89380728a0f0f86b9b6b192b343..3b90384f17d735777d4aaefbaca085aa0ed20db4 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 5b2ee1d0ee464797d1d9993a014d8f84c37d5596..25bb9c743a05a19c5d2396969f0f4e0fef6ddcd0 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 2649c2f89e8982320dfa7bfb6340b3809fdeec24..c6b950c596c1b7a4879b2ca96185dd9259c3d2e3 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 e99e97ea630051fcc026634957c86a47c2cbb021..48afe5c94000b44eb324d7631f3c0db8e3d0079e 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 c6f44f0f4d2e630892e44993225484b1ebe68caa..8edaa4d10a70ec01efadbaad616525a81745fe43 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 f7273d30c5f085dda08aaea521631a777dec860a..5f1d6abda3e408e652fc22e9681ca7ea9d7d6c40 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 6f7a16787143ce0896b2b1d07eb73e96768dbd89..cbb4aaf45e2cd208befbb42c988a0f9819fa532b 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 44274094193379bdad8647d79aaf7e599484bca0..abe10ccb677061ff482a67fb61720bffc1afec7f 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 168245818cfe364d71a9d67c3a3f250e658387b2..2d00c0656259ec8ee809b03a4e25fbca21f551d2 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 7f2398aa815525951818b9f0bab3cc3f442c60ef..a34ef4653f342a3265b3a88d0f7291586a89a0ec 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 60768726e9ad82aac86773a5433f5126a64f06c9..5d331b3b6da8eeb2cde2f9d006633b40206532e5 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 3e0bf5d31ad7a48a1df37361153819e5e81e6e53..1951c1cc84cf51a856dbabc0654801713046b0da 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 888cfa6662381e5b8d59d628fb2158bb2504052b..4e1d24beff94987964332ad2b3c543b0b3b8b7bc 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 71ded2eee060f8d3be9c793d3e48a717eda1803e..d6715997f13727e22346a76819cb7dc58a96614e 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 48b23a4256ced00f02d41853e6c0eb976124be8c..1a48f8d43d716b28b8fceb8e1a06d63a73a74a86 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 09f724c76d706e3167e0e7e34333cafac6bbd978..d04102f8a4a03567f14839eb8c505373f7c25071 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 00c077b2a2a44a9b9665118733452c5e4c8d0298..bdac27bd5a5ddf159fdb8b2520a4549b05dc7de9 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 b5a91e885793543bcd2e8f231a21ba91b8eac6c4..25c7bd2d8fdfd56a425a7cf3a82885962c097b7c 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 a1767a17fdce9174878e21f07001098d676937ba..59705a6669798ee5d711cfdd5dffc17317f2789f 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 9c1197f0e742d847568a81c2c43780c97eef6f9c..dac27fd359ad1b25927d8175be2306ad3784aeeb 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 b7b66ddc3a7307bda2ee35503c35592de63b29bb..0f50bac1fb4d284247b7f026928cb5df783c0c3a 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 1a4bd1a0f78745505cca1c12bf242d80c9770afa..39827e6841ca731aa4c709f1b7f07d6b1092ef91 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 9db1c94dfc188f21854c6ec636dd9f37ab391578..1640aa3717eddc135dfac9d5e45d899ae2579f64 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 c678f5b96266f37c69fac4af01d4fc58654cf119..af756e2b0f313ab749ac0e83c6915912db0ff333 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 9d3caf2bef18d9bab32443e6ed12582f925ef64d..f1018b14aecfd92497fe7b20eb4df2129529736d 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 667369be05553ea668bfcd79695645dbf1e56a25..1f9de7066ebf5704d2a57726e7baad166196f446 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 5aa8e5a22f32604c1c50d776c712a8212ce504cd..33781c3147286fb3e2f022201ccf7e908d0b6b12 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 b0ffd357401360c10b7e0fc2c3577bf0473b1582..0d30b91dbcbc20c8837a61ca9b4db631f80b263d 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 dc66ca9bba6b4676bebaa7f6a7582d9667cfc70a..d1510fe2405088adc0998e28aa9f36e0186fafae 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 cfc75d001f20e3186829ca5d0bcce462a5e1257d..01783486bc7df34ec3b38b1d0ad5f52e3eae6c92 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 2ad69b1509020f32affbf20a7ce4ac1a3f274b17..c5b4e1378b7d1b40db0c851af461fbef2e19e786 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 f3d054b06b4c87949192837c09771d9219a41aad..1deaf70e92ceb788ad8a5b82ea0bd1c28faadf1a 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 71ad29e441b23773afb18724df53769eea1d1733..b059bac1078bd09211fbee7bbd5ff7f3cb47e153 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 86cab113ef3da5c123a4e04c2089ad81f580edb1..6e32fdfd161b93a5624f757d5b7de579415b1055 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 b60707eba39d05d3ad44dc9789d658ea68379f9d..fb02eac78ed4eb51dc545d4920ca7c08c681dc4c 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 73d972416c01856dd219300b9165e9c60e25dffb..c7b2d03c23bced8539f0014c48e9ce6c426a2b96 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 c4e94d0fb163740e5acb9bd1a3afd694023b04fa..8913da59dc731b0ecef4594ba8674766fde491ca 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 f70198a1f0d1452b5ff210e35d5703beabd08799..59b35e40739b0d931dbac076ca5c83ba421ba766 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 bb6c9cc88b358de098543df8a0da7d22914c5e47..31e77d9e0c90e503e5e337f1ae7f17587624a785 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 87d10faaff9b11eb37d22a9372187425072976a7..ef4aa7b2835e3c9e177f3e03b24a141ac45c3825 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 9d95241bdf8f2a82cdd94e8fb18b650c8c318ef8..0bc84f12cb341a4c1a30fd2211f46565f8466cc6 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 ab860cedecd14d5f085de38257406348cf93f2bc..9b028c8bb1db142e2afd743aa3ace1d6d3230ae5 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 be6836e55376f4c91b46973bd397ef04d6a1a9ac..18f1c905eeacfb75cd6a3a5ee83d641403a5a7de 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 692520e1c497bbeda538e217b6a09f43ee26aadc..9f628a8e5cfbe9f1509e5c27d230e390842b5cfe 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 f8ea2219ab48b31c18d2ff22dcf103fb4d114f09..7dd40d69cce68a6293a42de389153f459b396ae3 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 555a61e2f3fdd179b551183aa5a6de445f6cc20a..cae8e84821d7fd521d59432580d51def939fa4d1 100644 --- a/drivers/iio/temperature/maxim_thermocouple.c +++ b/drivers/iio/temperature/maxim_thermocouple.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include @@ -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 c2447860adfd6f4b1a9f4d61e3de301271fe05d9..6e9108d5cf75f3b7a3c45ada1537c446c6853392 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 b5c94b7492f5d5fd59b7c4d6a8b7b8b1e68dbc03..29bff9d8859d017e1b59536c531f732a2d749631 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 fd4d389ce1dfec031652d4f7881ec0b72a015998..043283b02c4d78caa9fa6592d1c727a849f51ade 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 cfaa16f46a3fde699f5d635c691702656eb7ebfa..334bba6fdae6cb87d81d697f265eb5649cd00bb9 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 ef34b3c58f262b0c41a1f9642a846d14f99d55a1..0cad27205667e9f55d683ae39e1ee01bdc6ea960 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 fc67e6b73df7a4efbcbb29c31aa5520f5586e396..872dd8582003f40490fa8dd2454cee0340c4efcc 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 1eceec9d477f4c54925e6a14a28a99b882fa32fe..11250bc905c9b041e60f410bce8242bd67e616e9 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 bbc6a2e1c2c1d036a32aaa7d73a93bc1327f9cc0..ac6942cf1e448a7c28671cdd8506c138ea842edb 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 f1e18913236aef54d0fbb037c508af5b283bee5a..2505ace440b46f29f3f322416c82a32177fea859 100644 --- a/drivers/iio/trigger/stm32-lptimer-trigger.c +++ b/drivers/iio/trigger/stm32-lptimer-trigger.c @@ -16,16 +16,43 @@ #include #include -/* 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 e41cb741253b8410cfa6734f7e4c82d220160a97..925b864facca1b61919ed84f9343a1180f51bd00 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 e02721a9e28875e897b5ae00836dca80573545ef..b3b45c49077d5fe26e90499d77c764f7c9e4d359 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 9b508eaf441d824e92e2212fe19281c3494c4a1a..79990d09522bcbd1313008335f0b3398e4941812 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 e908f529335dd543059cd95b2903fb1947cd2a94..0781ab756d44164c6ee4ec2c9bcd8420ab67b3cd 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 3da90f2eb8e7b1a4cd9bc195859be128a507eaa2..06487e20f72370fdf41cbf543136c997e49b270e 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 b39f63ce6dfcd160331aedb626246f56a3f4e307..961fa07116f076e44c22321b8a756f9c067f8f16 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 16a749d16ee954ccc2a09f870d26ceba295e1eb7..719b7c34e238f10a9641bda1d345dd30ae02faac 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 78bf4a48c03550a671ea146ebc52cbc6ee614ae4..eafd2f157e32fb693ef709785df26e3fc1d60033 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 49e0f79b950c72d81dc2a70c9b66b5a2daeaabcb..3cbbfccdd8cdd148695a5aef5648db8bb9e947e8 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 23207f13ac1bcd51e711df876876ec5703c68700..c6a0a661d6e7eeeeab212fc6e435a964a9ed7731 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 d66b4f7a84ec95863fbd1a52122c50150ab3be66..b510ef747399b38d0f11ddd11f651d08c13e5687 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 6dd813bac5b2c392a31109232f6465ab656d001d..57f9bc2a4a3ac127cb4138d2a944e56af5a915f4 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 6eabef9aa2110005346a8e9fd60d873230a10728..f1d79968c985547c537a709c2f4cba66d56e2cc4 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 bdd724add147699b028b8621c42f78f61f8bb2f6..91fa5e160c0d71e0e8b10a6f2fbd4bca95cb26ce 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 277769fa97452c5dd5760d378a54126a0d3441c1..2640d283eee6af27e72d4c98df319a58858136f1 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 302c0d19f57dcc5a3b4dc73bc9444537b12bc368..0b347d1129face6ed1d58e4664bfb94bae424ed3 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 7b4bf06c3b38631159254bcf0590f9dbbe6c2301..781b6a4fb002af02d66827e021d2c216f6eb03dc 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 33c23adec101a73d3449c5e94614e4b8cc512167..1c45814f5646b0a5ac9c7df056f16fcb6e583d4c 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 85c3187d796d9edf6548a4ebef8abf07fa4789c9..93357823c6c05a16d9bfc97c2722ea3d145960f1 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 568deb77ab4dea0526e27b3d88fa887c97f30d0a..d99932b2ce217f8a95fd7c830e3764639ee695c8 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 c4ee120ac7fb7ecceb7520d4fd7c3a0819168048..40bc0a34273e54be49b6550fe8b235c4a8b7a939 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 1325110237cd9ae4cea2c752dc6999dfdd3f1cbe..397928c80f7c709c68672d8a975edd7afc640db6 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 9832567a8bb80d82dd4a03782c111f744ab6124c..bab657f93084d47d9819dadb993d31ab7fa72a78 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 583debe4b9a207bff1e3bdbfbb9e6338fd94947d..e825e2ef7966b37c01aac1f6f7c2a4329e372ce8 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 d48af218074588cfb7c16594d162e62b4174f7d1..a5b2b62f596b05162c9e84b34b0a7d14cef8dd05 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 9d0392df8a92f8c2abca5acc43e31c5081a9b916..373b03f223bebce8502d98892bb5484da4c000bd 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 009822fa61b844f487be1bdb9b28dbcceadd3f38..91636479ee3cb893e905532fbe97866eaa5404a8 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 ae51f108bfae024dec72b8ba68bf9ffb77885ffb..a832bc46bc928257570ea7c316acbd780ab747ad 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 ec4346f20efdd00395777de80d95318865148e4d..44887e51e04972b169285c460a4e8b3a0e98b967 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 d7a253835889a6c65b9df736fc76900dc1c4c26d..d5c67a927404b68aea31f8dce355d606c29d39b6 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 9fc629ad58b86cb926ef32713893121cb5442ec4..ae95cb3d0ae9ed6aa66448ebefd3e8d78ebff2bf 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 aa3e7d471b96e1e48d0fc0d273ac0d5bf79449b8..5f69aef01791451637884cc5340b0aeee6db1879 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 3cd47fa44efc419fbbc749777582771f9633a6a5..069c1d6376e1823c8b72674e088c71cda98578ff 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 c501a93a4417862824f0ea4d4c8efd4214fed793..58d4f2096cf95f12add72919c735b097a0d0e2e6 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 fe7398eeb828a6e96684f8e4552303c8ac6e6e18..954055aaf6e29527f22f8129fd47ca17722e2bc9 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 32a676f0de5397a06da430eacdb3a6ea991f1bdb..bc1c80a456f2aee3fac115ad2a0bb3155297dc75 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 7ba8d166d68c18b396e616f6f9074ae98c4629b7..0c7b8f8ef4a5500a4fa4990563f778267673111a 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 0bd7b09b0aa3b099518e3fbd8e01ab2239ff7ef2..be734d65ea721f310acf758dbc07d7b0f3a94a92 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 4ee084e00a7cea713cd95da399d9f396cf7dbf5e..71aa23dd7d8d038467b24f6d4b58ea834256721f 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 8d8392ce7005a9b38377a13ad9fb71039f3039a5..c9aa1847265a27737aa05c40f744af27496ac209 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 f661e199b63c1700814cef12a230d59043637f6d..f9db5cefb25bca45e18e80fafc9cad5dd78f4f68 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 3c997fba7048afc6588050194ba9ff4053856a27..64f474e67312f0cb7873817b4064ca41bff5088b 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 9a5977d8cad2b980264c414f095d88a03bb6bcdb..28da7ba55a4bbfd305fcf34e95b075a530eac33f 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 e59b8d0ed19e70d16ce815b07765251e3213c121..5fa47a1a6fdce42c193b3696ca4848b7263bb7e1 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 252a93753ee5aa24a7899959da06eaabe0d0a04d..82d7d1cf5010937f7ae29a51792c994b930bc7df 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 9d5404a07e8aa56fb5a85665ce9f043b125415f5..1a41e59c77f85a811f78986e98401625f4cadfa3 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); @@ -838,6 +845,25 @@ static struct icc_node *icc_node_create_nolock(int id) return node; } +/** + * 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 @@ -884,6 +910,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 @@ -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 f2d63745be54c489061e29803ac64d22de88a848..41bfc6e7ee1d53d34b919dd8afa97698bc69d79c 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 82344c734091eae78350c00ef8f05f8998739cce..bd8d730249b1c9e5b37afbee485b9500a8028c2e 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 6a656ed44d49ba2985d106ee28fff5af159e6444..baecbf2533f76cbf92bb2451979c4db57f8e4a2b 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 @@ -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 e2826af3ea2e1e34eaedc2c56715809938926553..04b4abbf44875c767ac67c552b36a8c64a06b2c3 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 20ac5bc5e1fbafe74800ad6f22839bac006ca7db..b7c321f4e4b51cbcb138e906e561325393e3e14e 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 de35c956fe4995aba9e962e52f47bf773b2211c1..b6610225b38acce12c47046769bb0460a1ae4229 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 6c708fec48d194d6dd2861ebced4d70bfeb44742..ea2ef53bd4fef0d78403cf81b6b4a777884e8a49 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 e3870d9426994c07f44cbe396a5f66bb1a5da56b..2b05722d4dbe8b07bb52d2b6f6e00f2775f8ad9e 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 165a63994f0477c6021aecb3e50bd3b890edf352..a34ea6058960550b93d6a4e486734a9ab85d227a 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 e48f89cbecf88b8c85101253fdccaabe3a9567bc..dace91ba412b705a59036deed3af2908c27c96c2 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 da933f4bdf4e769fa70cd095b49b4ae15134a989..168fc345dcdcc841318751675d06bf02d50f0c72 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 456b313bfa764cd7f9585d2dcae38e5fa71b4f9b..fa7813ae8d976186f80ece4bdbf2e672e545a23b 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 5ed0a611068765b2855b56a1435b49330b975e2c..825b686496d23ea4371ed251a0bb9644c94242ad 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 a5ad88a960d0ec5c18fe7d0142abe49eababad49..f732f6614d3707bfc8699ae25a6400d89e00720a 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 7cfa8c61dba0a6adfe66b7cd473bd57336ec7786..df98144a953946df0fc8669ae3e446d043b98155 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 32ba397a33d22596aef33e1c20543f751ca771d2..6af0d2c7fc56e3d00f95663a4d50ce2f50e77aee 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 48fb8a9ec70329b0f9296a2a0ef33443270f4a33..3e83200675f266063dd7ea2c7c64a30e46487127 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 1a59a4f384791477848982601a033513ffd7dc0b..59473f286b31f1ccbf6131e1b1da42f5b9144f68 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 b3ee33aed36e2bf75ca4e845ba3622a814a2694e..c973246a57f946f8b6bd6a41e3a2085bb82054f1 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 393b3ae832f49f257e05334f93f53ebef3ebea52..40eb61b6d54e0d8623f014e45dacc00365fde2ea 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 06d052957d373e088205f1da0d5476f61d3fa6db..9af3c18f14f4bd586c4b0052226774e335a6566b 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 e103c7ed830b81e01d72b87f021bd03d4948ac84..20f1351464b106f062612293979b08453c49e37b 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 748128661892d2465d1f91137cf7b6db3db8aba0..17278c2571d3415cabeccafa89e6c7e9f27bd691 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 2cc2eb24dc8af60596bef3143db6deaaa2daeb22..1d01006773573081aaf5b6bf3b58874d6bd076db 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 d39dec34b7a3f472a2d85d631a865dad6815fe42..0056106495a7c75d470144cc475326c46b8048b6 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 1a2ce1a4b4566a0e76865c4d5ccaba70d49b66af..1efb768b289058ffb72fc2c6eedafb26c545149e 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 16d3d454fb0a007ba2947673782a4e2deca6ed89..4bb6553278c74630c8c015f963ebd8e1f7e86bcb 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 1f626066e8cc6e082f9cf1172ec1ab0f2dddf1e9..4395657fa5838efbc96d98f7420986b0544d9847 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 81fec2e1e0ef3510e26acfadc28d4a25d88807c8..aaf4a0a4b0ebb66fb5f2427d1f504c9a1b11502e 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 127138c61be58ab12ba560bd7def1e56432f78d3..d296770478b299abb0e81372c27278a90d946bb4 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 785af481658406a9d41f43ec0e38d8ac9d2c39ee..268f734ca9c38ab8f4d1110ff60fa279613fdaba 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 3c58b941e0678937f31a2dfef998287e53ae2a66..4d983092a15224f56cbc3871c9ac3ec34e66f948 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 d6a04a57472d8067ef20b286587bb71939cb95f0..a428e1cacf07fbdb388d3eec8a892e5c049dbdb0 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 37b08f26c62f5d97b256733ee06b59a055318fe1..bd694910b01b0b5ed27712c468d31070afb2284b 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 31c93019c76bf33e4e502e7d72455d7da996342b..59e9dd45cfdec51be1816722d8b35d1ed2dd1dae 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 0fde115e921ff946844fc233ce19e54a55a36619..0f03b21e66e45468d6cbcc014d339de3a100d885 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 c7efd8aab675cc6b1ba97ae4af43468c88829cca..b8b3a90697012c610a2dc0e4c7210dcd3a1021b6 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 657d481525be68fc82bfdb632e660b0b97ce36fb..19c5a0ce5a408f82855718acc47999e2d23f6cfd 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 dce06bf65016fb2164be3bde65f5d0b3da28e217..b74780af4c220db77d1c3d502366faed9fb71590 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 2952678cce458dcae432f7fac702c1852e86cc8c..9d0362a75ecd5e6ef064c6449b70201f7ac05556 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 6c324a683be9404841f57aa0ea6b5cf50fbeaefb..1ffcc025d1a46d68c2da3642723a9abe8adfac1e 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 1e985f9439449e44f1b87584c74c010069f940fe..151177e5a06d8fa58385acf458c6ab04cbdae259 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 dcef93e1a3bcdf2874844ba2a5128d94f1a651ae..3d6703b75bfa5418d0b8e84708136633fb49c00b 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 42115118a0bdefc7103273eb00a227e565d35c49..6267e9ad39c01b9d2c673d8114de1f43b2ab7043 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 377a7e7f0499037fbaf8b2ef5c719888b1f39564..9ce67f5158434b9704c79fc3559f14e494ec0a7d 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 9eb7a5356b4c821af5cc8be566fc14ae6b9cb6b7..84aa269248fd368a738670f49cdb62d8101f5a70 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 7e742733391b6f69870f16115768bc5c733da860..315577d71d95e7dd69b12f5e6fca493ff3ea1a98 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 b3b670b6ef70ee223ae218f09a2b96d1d6d31346..748c14e879632ae6f62c3cc1981a168b01ed060d 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 16338d13d9c8c8ca2fbb713c7f3ac49aad6cf463..9f2ac33cffa7ffd765319218e2739d58070b8f26 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 84295bdb8ce4e0d829bacddee05318a021716871..537aa65acdc8e081dd43d6e5403c3fbbd56dbbf7 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 d7d97c7d4a2b85e91dcf99ae268a2f45fb97b628..468dbe8d552f8241989abd3206ed2cdcff2391d2 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 80bd268926cc6173fa7b9b711d4d07cb20d573fb..f39e0e34deb6847e722c91733a5c977d9fffde3d 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 9f89bd2620c70a09922e5b4117978f7b2d9225b3..73fdcd362265ad123b3633b832e40fd3ca70c227 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 87a817dda4a9cc7d7ab1bfd59792bd15a667c81f..602c37cbe177e2dfd6b66c1637c6646ef12abb10 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 2ddf1dfa05223877b43e344a036d6471e7528a90..5110754e1a31782b74d4c9dcbfa79642a532543a 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 9435cba3f4d9028448d57f05d8227df16df24f85..d6c54a3bccc26d62156ca5cb1fcc897f2ded885e 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 bfe86588c69be4ac4a7368f5df78dbe8d0665ad5..e034c93d57cf03221f420febb87d2470b63da7ea 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 da89ddf771c322ccaa1d248aafcfcfa15ab4d79f..63f6f5b36838d095406570e1d31d3c0e84e0a7eb 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 669f3309e237f8ca9046159c07b8aa044b1fb97c..92fb7b555a0f65f2360a81f8a560eca8c3f4d75c 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 cb6f36ebe5c8e9bf8cf2003a5894c4da71fea443..f5221b01880813c8f15657a81662fad0774716a0 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 817030fb50c9560eb0bf57c3a6cbd2eb2127c0b3..bb2d7c37c263694fbbebb6d8bbd05a4384423239 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 aa4ac43c66fa049275fc8a115687091497bbdb6a..5dafe11f61c6b170e813a9de9be08c0aed7d15c8 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 e46358fb8ac0daf7dac768beccc30a4f71b67a76..b9bf5cdcde4ae3477f2da6a6eb4d9638cdfc2e6a 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 3666f4452d119bda06dca8f44006978af61e7a9d..5d0447ff7d06ed2d6bde86ceabaef401ae74d809 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 33d1fad0f7b8b0773e977b1845f14763a5b475f8..e5dff969ed57e5c214bdc4b522ca8beabfa9c1e8 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 e23b0de1e0aabb25b5a19f5b0defa178690d8096..f21c2806eb9fe3966e2c8ea01b4d965b5016a312 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 899a7a67e2baf16012719006c7cbbf0504462608..8332f2c5aed7067035ef6475e0b3d528e7fc804f 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 e63f6269057106ded054dea94d92d96cb9c13c06..e96ca4157d48182574310f8caf72687bed7cc16a 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 7dc2c9987982351c9bf04daf7ef0b71c2cd47b5d..d34892782f6e47e1a8bde3d5e77a3fbc4101078d 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 a5a9bb3f16be9c4d53fe45ebb009015d62d49212..cddddb3a5a27f56d3a8c515c2ae6ae9e5f10733c 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 488ef8eecb26c4319e0b251a0f42edb5b26b5da5..605b2265536fbc8d1b25fe8702cd4afbb0bdfe8a 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 676348eee0150c54f874d2e5d5a4e606b261358d..db7f3a088fb093c12e354898acec329ea9cf2977 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 c161546d728fe22fbec7ab8708b0d0bc4d49dfb9..b9ca56930003bf01f198cc38093f0553e32b8a45 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 054cee9b08a4cea71be96758de2965b025adf337..917b9a7183aa1db63cc4049c042c3437f6756a1a 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 0000000000000000000000000000000000000000..4840831c84ca481a24f802874cf632280e682b44 --- /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 0000000000000000000000000000000000000000..38eaaa651fd99f6cc43e692098f481aeaaca1360 --- /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 0000000000000000000000000000000000000000..b653a21a909ef672e6177335b82b36432c5ec3d6 --- /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 +#include +#include +#include +#include +#include +#include +#include +#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 0000000000000000000000000000000000000000..975ae858e9fd9584cd69d732833514a06b061cbe --- /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 +#include +#include +#include +#include +#include + +/* 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 0000000000000000000000000000000000000000..f4f015605daae9783df2f5b131bf57b004530bd4 --- /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 +#include +#include +#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 0000000000000000000000000000000000000000..f891f5af4bc6d0e5f9ab840fa913a73dad97ea43 --- /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 +#include +#include +#include +#include +#include +#include +#include +#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 "); +MODULE_AUTHOR("Naveen Krishna Chatradhi "); +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 386884c2a26360146478a1d111d77deffa95e204..9344c2366a4bcd39a487cdddeeafd82ab730a18e 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 44a2dd80054dc01ebc77fb7150966295d5572c7b..e6c42b772e966f03efab196779a9656c4a8953db 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 a5549eaf52d089c5c572bac1323b2ab650f24665..8e7ea2c9142d9f7b5f7e21e3fc7ce52faa84d3aa 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 8be4ed7d9d473ad3dfcaaa381581e0f2381c1ab7..06d7a8a95fd6edf3ff8425d05dc5312ade8e8b27 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 be3d4e0e50ccd60cae77f983776fccc8e2a566a3..a7b066c487400fc7f7d44c5225522edfee1a95e3 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 9215d66de00cc06c1985bb96823467c4d627087c..8e5951b6114353cbbb7d9a384f391bf742c21709 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 7314c8d9ae75a761728c6d06bf92aea22af79aa3..148107a4547c39badcb9a1de3f4271b126efaf1c 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 ce0a37a47fc14c2f21bcb78f03c220a0be087786..0000000000000000000000000000000000000000 --- 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 5b97467ffb7d019948682a9534c72030a94521d7..0000000000000000000000000000000000000000 --- 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 3c4eaba86576ed6b27dce96e509888bdb9e25c30..0000000000000000000000000000000000000000 --- 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 - * and David Rowe - * - * 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 -#include -#include - -#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 56b4b95fd0206ae3e41daf2c21295b101ffb7700..0000000000000000000000000000000000000000 --- 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 - * and David Rowe - * - * 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 4d0821025223dec8c8cb2fa8452cfe92f4b01e9b..0000000000000000000000000000000000000000 --- 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 - * - * 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 f1adac143b90a09f23eb4be5301309103ff4d978..0000000000000000000000000000000000000000 --- 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 - * and David Rowe - * - * 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 1fc632ebf22f560088084519e5ad8e8b37958368..60c42170d1477ffef98a626d89c9cae73ba55a2d 100644 --- a/drivers/misc/eeprom/idt_89hpesx.c +++ b/drivers/misc/eeprom/idt_89hpesx.c @@ -60,11 +60,6 @@ MODULE_VERSION(IDT_89HPESX_VER); 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") @@ -1324,35 +1319,6 @@ static void idt_remove_sysfs_files(struct idt_89hpesx_dev *pdev) sysfs_remove_bin_file(&dev->kobj, pdev->ee_file); } -/* - * 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 */ @@ -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 7b7a22c91fe44d9348238cbde16b102eca5bf8f5..378923594f02491917bee0f7acc89c81c6361b62 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 bb2fec4b5880bfe792018e607c600cdc86a0a862..56005243a230d5ada6fb0a6a235829b8d399529c 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 98d3d123004c887bb8e28655a5558a102935f1fc..ff8f4404d10fb1d072f22e2c4b142854a9ce25c0 100644 --- a/drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gpio.c +++ b/drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gpio.c @@ -7,12 +7,14 @@ #include #include #include +#include #include #include #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 b09b79fedaba06677281446cba18dc4b333e8a81..c484f416fae419641cfd9ed5d8a37f18298dfa29 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 da26a080916c54a20cab29fdd16ef3bcf2d07a20..267d0de5fade83f85ef229691cf0c100924c9927 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 697a008c14d39a98b56bbe19a063c32e6698f80c..9fe816bf3957af4500a7d37dd13ba24e72f8c04b 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 0a24ce44cc37c412165b71a36a2bc2c6c111ef52..6db1c9d48f8fcf267b34d95974a361aff5c41962 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 abe79f6fd2a79b043bd6cce0de66a35bb76ed8bf..b64944367ac5337c65636a9cb0b01c7bcdee4c5b 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 dacb5bd9bb714dd39e1cd883ed9eeadc79361f68..f14671ea571628be81c705f64520e1f01882e5be 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 14e981b834b672c6eb3f27e0c82640bfaa3e2751..0e0666c0bb6ee835868572be8ef47a5b0579051a 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 2bfcc47dcf3e4bc575a4421b809ebd60402d68be..988492237707882e2fef23cba1a8ad5a326394f9 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 bd1662e275d490f63aeda733db93a9b882bea262..0fbbf57db52e39e51dbe2926d0b747b285ad9f69 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 e0ae5a0c967042016faaa305fcd1d9b7e2ee1ae4..8a49c32fd3f9999bd1f2cdd1c953ff53c05c5e41 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 912ffacbad881aea91c6863da9d5b362056bceaf..101f36de7b63bd77a066dc862a778250239903e1 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 95d8d40a06a86264a764e71c20dcb4456a084773..e588e24256cc87fe3026d6b4e21e02830f0f0f70 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 c50617d03709b6b958e051b93b8851e129930e88..c2be0f04439dc6d7ab95920c1be466afae491371 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 32fa0b2bb912107fbb02fb579440148182475ea3..f008167d186387baeaac2682379532b7a9f31606 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 713223f2d377071297356caca8addb3c7b192c51..5e5ec92f80e6c84c742fa49ba920d8d239a040d2 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 909d80a02824cae34ca9b925e8c09a4718132c25..9903966c2f5478c458a585f34d96464e0dec5078 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 dd71e5b8e1a5275f45a64a3c067cf34da06f55eb..f498fe11ecdf195d9f11af00f3809ab84aea91e2 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 d5974b355a5a79d6147d1f644d863d557cbc1a53..2ae787d966de1975315262ea42064a14e2ff871a 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 2199ba821922b6f6e40046cfc869fe19d79854a2..cf5be9c449a55819e2807a26984b5726a779004a 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 d28d4f1790f5715d507997b876fccfd80655ded5..abc7b186353ff8b3fddcaecb3561868b8888bcba 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 4da5aecb9fc62bc38c4ab67e839a8f86fa7be5e2..a5afe29e3cf1058db6e35e436f6346040c2c6569 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 22ed051eb1a4a5c89f3ad1fa8cd46d576ab24564..5eaf07d09ac910fb5653d99056e19b3ffe10659a 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 5710879cd47f89b6ef4458d6b4419a1fe9ad349f..4cc3202c58f364e80ad9f632763f568d184d4173 100644 --- a/drivers/mux/gpio.c +++ b/drivers/mux/gpio.c @@ -15,6 +15,7 @@ #include #include #include +#include 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 30a952c34365f4957a9fdc2acef7009673200898..9993ce38a818de12237cd700e4c19359ea7f4c29 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 602e6e1adf00a2a816b87a49396e517722186105..882972604c82db41754fba17a8028d9d4621057e 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 adf3970f070fd57f34b9a17c49d85515619f9637..c5784d9779ef518ac253e66923ef542d52584373 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 52301511ed1b0bbd71d0edd8ac6847c660496742..09510663988c7e7af4b9519c73140940d40b4236 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 6c7b1c58f85fa191ad59cf0d4f362aab50e52946..ce18e9e56059f7c97df5f952e24387b822c6a2bd 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 c75df1755b3b9529c9231e107ad58778a5e734a9..6b293a9056c2d9a6600096ac79f2fb18f55ad46a 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/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c index 862bdccb743976f028742f6d600410c289914247..dc2f4adac9bc968db8d85ab4c487bb76641d8c96 100644 --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c @@ -2034,9 +2034,6 @@ int b53_br_join(struct dsa_switch *ds, int port, struct dsa_bridge bridge, b53_get_vlan_entry(dev, pvid, vl); vl->members &= ~BIT(port); - if (vl->members == BIT(cpu_port)) - vl->members &= ~BIT(cpu_port); - vl->untag = vl->members; b53_set_vlan_entry(dev, pvid, vl); } @@ -2115,8 +2112,7 @@ void b53_br_leave(struct dsa_switch *ds, int port, struct dsa_bridge bridge) } b53_get_vlan_entry(dev, pvid, vl); - vl->members |= BIT(port) | BIT(cpu_port); - vl->untag |= BIT(port) | BIT(cpu_port); + vl->members |= BIT(port); b53_set_vlan_entry(dev, pvid, vl); } } diff --git a/drivers/net/dsa/mv88e6xxx/phy.c b/drivers/net/dsa/mv88e6xxx/phy.c index b6d249eb64e736d62073d91a2080bcb3bdd2e3c4..4e7827ee684a7209aa50850bdddf479b871edf7e 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 5889759b8d8390f2e447e8d73c819bd54a0f4062..9ba10efd3794911eb5770d704f9f5417119163fb 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 8ba2ed87fe7c5904e675c106246e5ff6ebcfecde..ecdea58e6a21f838675ba7ddb5b9023f6befa731 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 b295d528a2375a6ace3d433907502892133545a0..1f2070497a75b74d7e268efc55ae1d94e4883c70 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 ff331a3bde734672ad0aacea9fa2295d118b5d3b..ea49be43b8c3a8ce4a27edc21171fc08b54ac242 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 1a10f5dbc4d7e5bcdc20bffcd185ed256ee265e6..8c9cc97efd4eefbf2a110da48301526db0f143b1 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 e5be5044e1d4e82f5cce6302d327f8ffb4f05444..7c8213011b5cfe78c682d0f5b7b2d2959a469f1c 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 a326f25dda09d92d5baddc6264209c29ca241633..19f9c5db3f3ba797e418394ec57a7a23b5947aef 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 b398adacda915e3844dc91f8610a2bd08f5c8e6c..678eddb3617294511c2246f992a2dc71e73fc1d9 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/airoha/airoha_regs.h b/drivers/net/ethernet/airoha/airoha_regs.h index 04187eb40ec674ec5a4ccfc968bb4bd579a53095..150c85995cc1a71d2d7eac58b75f27c19d26e2b5 100644 --- a/drivers/net/ethernet/airoha/airoha_regs.h +++ b/drivers/net/ethernet/airoha/airoha_regs.h @@ -614,8 +614,9 @@ RX19_DONE_INT_MASK | RX18_DONE_INT_MASK | \ RX17_DONE_INT_MASK | RX16_DONE_INT_MASK) -#define RX_DONE_INT_MASK (RX_DONE_HIGH_INT_MASK | RX_DONE_LOW_INT_MASK) #define RX_DONE_HIGH_OFFSET fls(RX_DONE_HIGH_INT_MASK) +#define RX_DONE_INT_MASK \ + ((RX_DONE_HIGH_INT_MASK << RX_DONE_HIGH_OFFSET) | RX_DONE_LOW_INT_MASK) #define INT_RX2_MASK(_n) \ ((RX_NO_CPU_DSCP_HIGH_INT_MASK & (_n)) | \ diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c index 7d9ee9867a400e78ba9c46d808c00de10101c4c1..86fd08f375df1ceeeb54f06f58d1aedae2917649 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 b923ad9e15819f55aa6f86c57d96c903d0518ff3..ce94454250453bf6ad956b7769cdef6cabaef162 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 86522e8574cb8d8c69fc63f18b992c01395c6d92..76e8c13d59857cfaf79f32760aa13ce782d1ab3d 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 b072ca5930fca071a83ec83871f1a11ffcd19334..8d05a0c5f2d5d1870ee2970d34f44b6a9550fd0d 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 e5adafecc686fe855ebcab440bf95f65ab9f2400..9eaefa0f5e80c5af308fe6a1b39b992b12353b12 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 4843f9249a31d7cdd35720c93792d839ca3d92f9..9b81e1c260c2fc56972c2a747d43da177e53f873 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 3cd31855a5f6c3c9504a54cc3d23b068c3794516..0b273327f5a61388f20794b4303ebd908e23f4ae 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 76c328721fcd5a9f7ee015f5573ee8ae12f9eb21..65447f9a0a59d90babede08da8655c769891ff63 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 b50052c25a916150eb73160b1e0a2023878b94cf..b3bf8d6f88e84af93b845f524b5e0e01d5ad217f 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 1fed112f4e6841780ee00ac03ff455ba8ce45b30..af26905e44e3a9c004c2aecd1f608746ccf5cb27 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 e71cd10e4e1f14f3dfcc612b7d32a25f221d6e9b..b24eaa5283fa195c0ebccc32c07a2cf8abb0d975 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 67b654889caed0b4d0ea685181edbd72eca6d2ea..d8e6f23e143201618f0a54f265b68f3aa3edfd48 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 82137f9deae94d6b499c3363b9a1f4c3a205992c..ef1a51347351bc734afd7ec9a5a3c23907bcc274 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 f664a0edbc49000fa7514f13564a893af3cabdb6..40290028580ba34463ec43353d83e3af337332d0 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 38cd84b7677cfd2b03c68bcd8ac853f64b8ccd3f..cfdb546a09e7c156faf93fe66ec808a7addb81d1 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 88f65f8cf4d3499e8f66b311d2a8611d28dbd973..280e2f5f4aa54ccc05818f981d652297cccd7577 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 c91884373429a92f4109e1e8d52c466d53b2f2f0..8267417b3750a39f563f97ed79199a8adcc0a959 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 19611bdd86e65eedac29b1a2689d7000266cf7c3..92204fea1f08b6fc8e5b79ca2626db7b978907ff 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 ec0c9584f3bbfb5e1b0705ef86c02cf12f3f8efc..cb1011f6fd30729e5041ab3368269d337695d3b7 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 f522ca8ff66bb49fd141389e273de16c3fa5e359..c9a1a1d504c0f3ebad4197b42ea30f3db76864dc 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 d5495762c945b6b24db92779799714a7d82bcb3c..869580b6f70ddf10f0f9b92c69c435b00bcec895 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 ff47e96b912485c252e3bc54a3b5cf5c8aa4dfd5..91104cc2c2385d43564f992a588b3fc5ed5846fa 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 50eb54ecf1bad00938b458e33650008689e70130..9bed332958394fe56d62f68f6abc3fae39fe24fc 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 a10923c7e25cf27ecbc06f584b29ad7d247660fc..5f354cf62cdddd377753ddd2a4fab56102447312 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 bd5c3b3fa5e38f3332c00b0edb1d6ba963383438..b59735d0e065fc6ec8b2ba1927d6b911bb0a5d61 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 69d045d769c4b03fecddb4d5c43e469e95b47836..0765d000eaef08c5082a0d0a945d26679f2d97cc 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 f2d533acb056fcb4df5545b479771930c3eea8dd..64402e3646b3c440b4e4e57ba3f846dc0aebb1b7 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 f42af01f41140af3839bfd70a2144549d2d709c2..4e6ecb9c8dccf055ca81c9c3db2e8d0a8588c175 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 9900993b6aea66ea6abef2b05425af0a8bafa838..837f954873eef623afd68e57ab192a31910b18e9 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 6ef8a0d90bce38781d931f62518cf9bafb223288..773f5ad972a249ac78df08d2e6164ba683ba8ca5 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 f9339d0772b5803d9b71c33c841e23f40f9cafe5..f9504f340c4aead1cbcf6c11231ac1950882531a 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 ae34b95ed676bb2303a9d9d095b9d4fa323168be..2d3bd343b6e63be20e6fa98699166b94fe6789b0 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 2d926a26fbb9332c0c1dcab4b89d0367b5ff5e6d..0a12cb9b3ba78491999bb90471b0984e92c90e8d 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 653bde48ef444b55d3ecfed2dc7e712898804b6a..1de5ed967070dd424054344d4233c1fd7ede7c81 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 2e3bdc0fcdc0fcb0ead76f3ab399cafceb0e8d06..39c410bf224ecf08a283a47362882a64fca33357 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 642e9dfc54515a9f7598ef15c8bce62791f791d7..ca0c509b601c470ba158975b17f27608e8894091 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 bec76e7bf5dd14f94e8fb720436d304678ee94ab..5b7e6eb080f32c8280243426b9ad7fe8d143183f 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 3f1bd670700bc82fcd3d55b821a32d7a0ca13e06..6e4d8d31aba908b7a89ee5bb8610d94d0bc00daa 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 e593273b28675082f547bda247a20c6f544e7097..a24a25a5f73d54d332163510dad8d2a03e560aa7 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 ea8361ba6cad0dc147c3d3fd6c493ee27c510885..cc60ee454bf9bee88b2d61e23edda640ebe9f799 100644 --- a/drivers/net/ethernet/dlink/dl2k.c +++ b/drivers/net/ethernet/dlink/dl2k.c @@ -661,7 +661,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 670b682013764fd7d0a2488a3bdab2f343aabc60..6ac8547ef9b8dc13d31f4611527ddbfa11207ff4 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/freescale/enetc/Kconfig b/drivers/net/ethernet/freescale/enetc/Kconfig index e917132d37149d7adc6d7441bffd8cc9c81de25e..54b0f0a5a6bb12161fff590e864d315042eebd1b 100644 --- a/drivers/net/ethernet/freescale/enetc/Kconfig +++ b/drivers/net/ethernet/freescale/enetc/Kconfig @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 config FSL_ENETC_CORE tristate + select NXP_NETC_LIB if NXP_NTMP help This module supports common functionality between the PF and VF drivers for the NXP ENETC controller. @@ -22,6 +23,9 @@ config NXP_NETC_LIB Switch, such as NETC Table Management Protocol (NTMP) 2.0, common tc flower and debugfs interfaces and so on. +config NXP_NTMP + bool + config FSL_ENETC tristate "ENETC PF driver" depends on PCI_MSI @@ -45,7 +49,7 @@ config NXP_ENETC4 select FSL_ENETC_CORE select FSL_ENETC_MDIO select NXP_ENETC_PF_COMMON - select NXP_NETC_LIB + select NXP_NTMP select PHYLINK select DIMLIB help diff --git a/drivers/net/ethernet/google/gve/gve_main.c b/drivers/net/ethernet/google/gve/gve_main.c index 7cd1eda0b4499eb090d0f3b3015bb872d85bee88..dc35a23ec47fdd06d0e39378de98142ea5d7db03 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 d98f8d3ce7c8b7a0c116ca2d7ac6b29a95ef1779..e905f10b894e88d19f9142e519e23376b7bc28f8 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 3e28a08934abd2e180d0f16b98723cc93c11d44d..a7de67699a013c1d48c48081d847478f029f11bc 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 dada42e7e0ec96a4e346dadb5045c72a73956615..c4f35e8e217760ff57ed680b81ad604cf405df18 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 c0ead54ea1860ff6fa3e6fc3b314f53fad338616..5c56c1edd492857e666f6fb7c355fcb3fe5ef70f 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/e1000/e1000_main.c b/drivers/net/ethernet/intel/e1000/e1000_main.c index 3f089c3d47b23b9e5c040de110d6e92df6820c01..d8595e84326dbc757da18318bcb3b1458bb3f9ff 100644 --- a/drivers/net/ethernet/intel/e1000/e1000_main.c +++ b/drivers/net/ethernet/intel/e1000/e1000_main.c @@ -477,10 +477,6 @@ static void e1000_down_and_stop(struct e1000_adapter *adapter) cancel_delayed_work_sync(&adapter->phy_info_task); cancel_delayed_work_sync(&adapter->fifo_stall_task); - - /* Only kill reset task if adapter is not resetting */ - if (!test_bit(__E1000_RESETTING, &adapter->flags)) - cancel_work_sync(&adapter->reset_task); } void e1000_down(struct e1000_adapter *adapter) @@ -1266,6 +1262,10 @@ static void e1000_remove(struct pci_dev *pdev) unregister_netdev(netdev); + /* Only kill reset task if adapter is not resetting */ + if (!test_bit(__E1000_RESETTING, &adapter->flags)) + cancel_work_sync(&adapter->reset_task); + e1000_phy_hw_reset(hw); kfree(adapter->tx_ring); diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index e0f492a6723face756cd02a3e475902c60690f63..a96f4cfa6e17218f49f63ee1a4623fd8364dc8b5 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 21267ab603ef16d622ae7d4763e3f4d9da9418c1..ae5fe34659cfb1ed63432f95a9258d7b819e3bfd 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 fcfa2162a3dddb542b9f1eb2b1141eeabe3dd6c4..1156a5b3055ceed5251269e285eb94bb1dfb00e5 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -11416,7 +11416,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/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index 2d9b7e51bbe1f497a3eca9dc10e818ac591b9c5b..b232edf68ab192fb56b5d4d4f26995a843621e5c 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -1547,8 +1547,8 @@ static void i40e_cleanup_reset_vf(struct i40e_vf *vf) * @vf: pointer to the VF structure * @flr: VFLR was issued or not * - * Returns true if the VF is in reset, resets successfully, or resets - * are disabled and false otherwise. + * Return: True if reset was performed successfully or if resets are disabled. + * False if reset is already in progress. **/ bool i40e_reset_vf(struct i40e_vf *vf, bool flr) { @@ -1567,7 +1567,7 @@ bool i40e_reset_vf(struct i40e_vf *vf, bool flr) /* If VF is being reset already we don't need to continue. */ if (test_and_set_bit(I40E_VF_STATE_RESETTING, &vf->vf_states)) - return true; + return false; i40e_trigger_vf_reset(vf, flr); @@ -4330,7 +4330,10 @@ int i40e_vc_process_vflr_event(struct i40e_pf *pf) reg = rd32(hw, I40E_GLGEN_VFLRSTAT(reg_idx)); if (reg & BIT(bit_idx)) /* i40e_reset_vf will clear the bit in GLGEN_VFLRSTAT */ - i40e_reset_vf(vf, true); + if (!i40e_reset_vf(vf, true)) { + /* At least one VF did not finish resetting, retry next time */ + set_bit(__I40E_VFLR_EVENT_PENDING, pf->state); + } } return 0; diff --git a/drivers/net/ethernet/intel/iavf/iavf_main.c b/drivers/net/ethernet/intel/iavf/iavf_main.c index 2f501c8264b4d3a2280b74d4d071c6dc3a9d56d5..c859a096de9f8e5f28ab8f1ce33f10bd0ad9c908 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_main.c +++ b/drivers/net/ethernet/intel/iavf/iavf_main.c @@ -3171,6 +3171,17 @@ static void iavf_reset_task(struct work_struct *work) } continue_reset: + /* If we are still early in the state machine, just restart. */ + if (adapter->state <= __IAVF_INIT_FAILED) { + iavf_shutdown_adminq(hw); + iavf_change_state(adapter, __IAVF_STARTUP); + iavf_startup(adapter); + queue_delayed_work(adapter->wq, &adapter->watchdog_task, + msecs_to_jiffies(30)); + netdev_unlock(netdev); + return; + } + /* We don't use netif_running() because it may be true prior to * ndo_open() returning, so we can't assume it means all our open * tasks have finished, since we're not holding the rtnl_lock here. diff --git a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c index 1815cf3e28f48b1227cb795efbf905f61b6e57b5..31a4289fc0ee1e183428d9726bfb255b3bcc02b5 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c +++ b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c @@ -79,6 +79,23 @@ iavf_poll_virtchnl_msg(struct iavf_hw *hw, struct iavf_arq_event_info *event, return iavf_status_to_errno(status); received_op = (enum virtchnl_ops)le32_to_cpu(event->desc.cookie_high); + + if (received_op == VIRTCHNL_OP_EVENT) { + struct iavf_adapter *adapter = hw->back; + struct virtchnl_pf_event *vpe = + (struct virtchnl_pf_event *)event->msg_buf; + + if (vpe->event != VIRTCHNL_EVENT_RESET_IMPENDING) + continue; + + dev_info(&adapter->pdev->dev, "Reset indication received from the PF\n"); + if (!(adapter->flags & IAVF_FLAG_RESET_PENDING)) + iavf_schedule_reset(adapter, + IAVF_FLAG_RESET_PENDING); + + return -EIO; + } + if (op_to_poll == received_op) break; } diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 4e04721467bf72339f662df000852542d0a718ee..7a4b302d356b142660b572e460098e154ca77a92 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -1746,7 +1746,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_ptp.c b/drivers/net/ethernet/intel/ice/ice_ptp.c index b948a6d9226c41858faa3fea1b8ebd68a73b8897..9a2606dcdf484b1ce810e3a5428c6bb179124172 100644 --- a/drivers/net/ethernet/intel/ice/ice_ptp.c +++ b/drivers/net/ethernet/intel/ice/ice_ptp.c @@ -2137,6 +2137,7 @@ static int ice_capture_crosststamp(ktime_t *device, ts = ((u64)ts_hi << 32) | ts_lo; system->cycles = ts; system->cs_id = CSID_X86_ART; + system->use_nsecs = true; /* Read Device source clock time */ ts_lo = rd32(hw, cfg->dev_time_l[tmr_idx]); diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl_fdir.c b/drivers/net/ethernet/intel/ice/ice_virtchnl_fdir.c index 1cca9b2262e866dfba4fd382922afdb73dc1fef3..ae83c3914e29f7b874051bb66e03c89d698a57dc 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 9e9a5900e6e5a0f70f5ef34d3b4c7decb02d660c..b76a154e635e0007911875e097f35acdcedaba76 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 beb01248600f4ccf74a70fb32223edc06d1ee40a..e55dd93458334e63e20866037cced728a0cb55b6 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 27575a1e1777fae67348499acdc36b8227e742cc..686793c539f272c97510384edd0324bc7b90412d 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 1982314aaf3c114e7bc3d8d6b392a27a4dab15dc..6eccfba51fac976fbb8bb281a38af048886e7050 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -8312,7 +8312,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 a217c5c048041cf6c9217eefbbeb0f6ffa439d0c..535d0f71f521491bd579ed5eea07d9ab690a4dbb 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 1e2ac1a5f0994c9ad15fab78bcb38af6301e47b9..891a94d89f4b00f9cec5023889528734318c538c 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 8cc888bf6094a7aec429ee512096bb999d12ee8c..0ab52c57c648094d0fbcbb37b71f2ed395b59d17 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 72c1967768f4ca89e6b1e4bf10c8c5f3dcd7c91f..e4cfdc8bc05524bea548b0243a2ec84fbac21242 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 b2081d6e34f0eb015bb1c48f50c8677aa323bbb7..05349a0b2db1c1000c4ff31a3d5b41a7d9efbb5c 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 e2a9aae8bc9b03642d245513410ffc2e64b3ddf2..3831f533b9db13e4fcca99a4e6a5cd646e76640f 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 33ba0a5c38aced063233d5a0103e1b329d0aef1d..edcc6f6626180610a6f43aac8babf5b7a9a894db 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/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c index ea078c9f5d154aabb9bbf1b26cce24331ee748cf..3cb8d3bf9044ca7e4baa358f3e15260b73e184e3 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c @@ -43,7 +43,6 @@ #include "en/fs_ethtool.h" #define LANES_UNKNOWN 0 -#define MAX_LANES 8 void mlx5e_ethtool_get_drvinfo(struct mlx5e_priv *priv, struct ethtool_drvinfo *drvinfo) @@ -1098,10 +1097,8 @@ static void get_link_properties(struct net_device *netdev, speed = info->speed; lanes = info->lanes; duplex = DUPLEX_FULL; - } else if (data_rate_oper) { + } else if (data_rate_oper) speed = 100 * data_rate_oper; - lanes = MAX_LANES; - } out: link_ksettings->base.duplex = duplex; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c index f1d908f611349ff1df1f7785bc7c38294c9d2746..fef418e1ed1a0832fe6e23044c8bb63ec92a23f6 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c @@ -2028,9 +2028,8 @@ err_out: return err; } -static bool mlx5_flow_has_geneve_opt(struct mlx5e_tc_flow *flow) +static bool mlx5_flow_has_geneve_opt(struct mlx5_flow_spec *spec) { - struct mlx5_flow_spec *spec = &flow->attr->parse_attr->spec; void *headers_v = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters_3); @@ -2069,7 +2068,7 @@ static void mlx5e_tc_del_fdb_flow(struct mlx5e_priv *priv, } complete_all(&flow->del_hw_done); - if (mlx5_flow_has_geneve_opt(flow)) + if (mlx5_flow_has_geneve_opt(&attr->parse_attr->spec)) mlx5_geneve_tlv_option_del(priv->mdev->geneve); if (flow->decap_route) @@ -2574,12 +2573,13 @@ static int parse_tunnel_attr(struct mlx5e_priv *priv, err = mlx5e_tc_tun_parse(filter_dev, priv, tmp_spec, f, match_level); if (err) { - kvfree(tmp_spec); NL_SET_ERR_MSG_MOD(extack, "Failed to parse tunnel attributes"); netdev_warn(priv->netdev, "Failed to parse tunnel attributes"); - return err; + } else { + err = mlx5e_tc_set_attr_rx_tun(flow, tmp_spec); } - err = mlx5e_tc_set_attr_rx_tun(flow, tmp_spec); + if (mlx5_flow_has_geneve_opt(tmp_spec)) + mlx5_geneve_tlv_option_del(priv->mdev->geneve); kvfree(tmp_spec); if (err) return err; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c index 7fb8a3381f849e63b33bd9a8510f1e65d109b5ce..4917d185d0c352ceba9b94095dc8f8b5954f0a8c 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c @@ -1295,12 +1295,15 @@ mlx5_eswitch_enable_pf_vf_vports(struct mlx5_eswitch *esw, ret = mlx5_eswitch_load_pf_vf_vport(esw, MLX5_VPORT_ECPF, enabled_events); if (ret) goto ecpf_err; - if (mlx5_core_ec_sriov_enabled(esw->dev)) { - ret = mlx5_eswitch_load_ec_vf_vports(esw, esw->esw_funcs.num_ec_vfs, - enabled_events); - if (ret) - goto ec_vf_err; - } + } + + /* Enable ECVF vports */ + if (mlx5_core_ec_sriov_enabled(esw->dev)) { + ret = mlx5_eswitch_load_ec_vf_vports(esw, + esw->esw_funcs.num_ec_vfs, + enabled_events); + if (ret) + goto ec_vf_err; } /* Enable VF vports */ @@ -1331,9 +1334,11 @@ void mlx5_eswitch_disable_pf_vf_vports(struct mlx5_eswitch *esw) { mlx5_eswitch_unload_vf_vports(esw, esw->esw_funcs.num_vfs); + if (mlx5_core_ec_sriov_enabled(esw->dev)) + mlx5_eswitch_unload_ec_vf_vports(esw, + esw->esw_funcs.num_ec_vfs); + if (mlx5_ecpf_vport_exists(esw->dev)) { - if (mlx5_core_ec_sriov_enabled(esw->dev)) - mlx5_eswitch_unload_ec_vf_vports(esw, esw->esw_funcs.num_vfs); mlx5_eswitch_unload_pf_vf_vport(esw, MLX5_VPORT_ECPF); } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c index 23a7e8e7adfabe2c8a7ac4fe2b219182550cec26..a8046200d376d3b99f57b815cefbad14507700b1 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c @@ -2228,6 +2228,7 @@ try_add_to_existing_fg(struct mlx5_flow_table *ft, struct mlx5_flow_handle *rule; struct match_list *iter; bool take_write = false; + bool try_again = false; struct fs_fte *fte; u64 version = 0; int err; @@ -2292,6 +2293,7 @@ skip_search: nested_down_write_ref_node(&g->node, FS_LOCK_PARENT); if (!g->node.active) { + try_again = true; up_write_ref_node(&g->node, false); continue; } @@ -2313,7 +2315,8 @@ skip_search: tree_put_node(&fte->node, false); return rule; } - rule = ERR_PTR(-ENOENT); + err = try_again ? -EAGAIN : -ENOENT; + rule = ERR_PTR(err); out: kmem_cache_free(steering->ftes_cache, fte); return rule; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c b/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c index 5442a02c409731bf9fabe29551af58874c4d564e..69933addd921e64aa8cd4e586828f12e6978a218 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 624452ddebc0b2093161f1bcb610389728ed2fd4..cf7a1edd0530a35e207b231ce6d691ff8f6620a2 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/mellanox/mlx5/core/pagealloc.c b/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c index 972e8e9df585badd38fa0f7a787cc7513e03edd7..9bc9bd83c2324c75d4bc40ad97fc298902f8c232 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c @@ -291,7 +291,7 @@ static void free_4k(struct mlx5_core_dev *dev, u64 addr, u32 function) static int alloc_system_page(struct mlx5_core_dev *dev, u32 function) { struct device *device = mlx5_core_dma_dev(dev); - int nid = dev_to_node(device); + int nid = dev->priv.numa_node; struct page *page; u64 zero_addr = 1; u64 addr; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/action.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/action.c index fb62f3bc4bd4f67a5fcea014fa7a18546d92a4f1..447ea3f8722ce4202b77cdb46c8052a4c1862d7c 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/action.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/action.c @@ -1370,8 +1370,8 @@ mlx5hws_action_create_dest_array(struct mlx5hws_context *ctx, struct mlx5hws_cmd_set_fte_attr fte_attr = {0}; struct mlx5hws_cmd_forward_tbl *fw_island; struct mlx5hws_action *action; - u32 i /*, packet_reformat_id*/; - int ret; + int ret, last_dest_idx = -1; + u32 i; if (num_dest <= 1) { mlx5hws_err(ctx, "Action must have multiple dests\n"); @@ -1401,11 +1401,8 @@ mlx5hws_action_create_dest_array(struct mlx5hws_context *ctx, dest_list[i].destination_id = dests[i].dest->dest_obj.obj_id; fte_attr.action_flags |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST; fte_attr.ignore_flow_level = ignore_flow_level; - /* ToDo: In SW steering we have a handling of 'go to WIRE' - * destination here by upper layer setting 'is_wire_ft' flag - * if the destination is wire. - * This is because uplink should be last dest in the list. - */ + if (dests[i].is_wire_ft) + last_dest_idx = i; break; case MLX5HWS_ACTION_TYP_VPORT: dest_list[i].destination_type = MLX5_FLOW_DESTINATION_TYPE_VPORT; @@ -1429,6 +1426,9 @@ mlx5hws_action_create_dest_array(struct mlx5hws_context *ctx, } } + if (last_dest_idx != -1) + swap(dest_list[last_dest_idx], dest_list[num_dest - 1]); + fte_attr.dests_num = num_dest; fte_attr.dests = dest_list; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/bwc_complex.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/bwc_complex.c index 70768953a4f6f3ac2948a1cdf89c7bbe15252e6a..ca7501c5746886efceb40c637528b512729702b1 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/bwc_complex.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/bwc_complex.c @@ -1070,7 +1070,7 @@ hws_bwc_rule_complex_hash_node_get(struct mlx5hws_bwc_rule *bwc_rule, struct mlx5hws_bwc_matcher *bwc_matcher = bwc_rule->bwc_matcher; struct mlx5hws_bwc_complex_rule_hash_node *node, *old_node; struct rhashtable *refcount_hash; - int i; + int ret, i; bwc_rule->complex_hash_node = NULL; @@ -1078,7 +1078,11 @@ hws_bwc_rule_complex_hash_node_get(struct mlx5hws_bwc_rule *bwc_rule, if (unlikely(!node)) return -ENOMEM; - node->tag = ida_alloc(&bwc_matcher->complex->metadata_ida, GFP_KERNEL); + ret = ida_alloc(&bwc_matcher->complex->metadata_ida, GFP_KERNEL); + if (ret < 0) + goto err_free_node; + node->tag = ret; + refcount_set(&node->refcount, 1); /* Clear match buffer - turn off all the unrelated fields @@ -1094,6 +1098,11 @@ hws_bwc_rule_complex_hash_node_get(struct mlx5hws_bwc_rule *bwc_rule, old_node = rhashtable_lookup_get_insert_fast(refcount_hash, &node->hash_node, hws_refcount_hash); + if (IS_ERR(old_node)) { + ret = PTR_ERR(old_node); + goto err_free_ida; + } + if (old_node) { /* Rule with the same tag already exists - update refcount */ refcount_inc(&old_node->refcount); @@ -1112,6 +1121,12 @@ hws_bwc_rule_complex_hash_node_get(struct mlx5hws_bwc_rule *bwc_rule, bwc_rule->complex_hash_node = node; return 0; + +err_free_ida: + ida_free(&bwc_matcher->complex->metadata_ida, node->tag); +err_free_node: + kfree(node); + return ret; } static void diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/definer.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/definer.c index 5cc0dc002ac1c646969d4412f59ec904948be488..d45e1145d1979ac58c2a780c63d24ff5348a6b56 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/definer.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/definer.c @@ -785,6 +785,9 @@ hws_definer_conv_outer(struct mlx5hws_definer_conv_data *cd, HWS_SET_HDR(fc, match_param, IP_PROTOCOL_O, outer_headers.ip_protocol, eth_l3_outer.protocol_next_header); + HWS_SET_HDR(fc, match_param, IP_VERSION_O, + outer_headers.ip_version, + eth_l3_outer.ip_version); HWS_SET_HDR(fc, match_param, IP_TTL_O, outer_headers.ttl_hoplimit, eth_l3_outer.time_to_live_hop_limit); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/fs_hws.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/fs_hws.c index 9d1c0e4b224ad1d3c8b71be1e387b8ff9702b794..bf4643d0ce17900a9a46832013b59e62dda50ef2 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/fs_hws.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/fs_hws.c @@ -966,6 +966,9 @@ static int mlx5_fs_fte_get_hws_actions(struct mlx5_flow_root_namespace *ns, switch (attr->type) { case MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE: dest_action = mlx5_fs_get_dest_action_ft(fs_ctx, dst); + if (dst->dest_attr.ft->flags & + MLX5_FLOW_TABLE_UPLINK_VPORT) + dest_actions[num_dest_actions].is_wire_ft = true; break; case MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE_NUM: dest_action = mlx5_fs_get_dest_action_table_num(fs_ctx, @@ -1357,6 +1360,7 @@ mlx5_cmd_hws_packet_reformat_alloc(struct mlx5_flow_root_namespace *ns, pkt_reformat->fs_hws_action.pr_data = pr_data; } + mutex_init(&pkt_reformat->fs_hws_action.lock); pkt_reformat->owner = MLX5_FLOW_RESOURCE_OWNER_HWS; pkt_reformat->fs_hws_action.hws_action = hws_action; return 0; @@ -1503,7 +1507,6 @@ static int mlx5_cmd_hws_modify_header_alloc(struct mlx5_flow_root_namespace *ns, err = -ENOMEM; goto release_mh; } - mutex_init(&modify_hdr->fs_hws_action.lock); modify_hdr->fs_hws_action.mh_data = mh_data; modify_hdr->fs_hws_action.fs_pool = pool; modify_hdr->owner = MLX5_FLOW_RESOURCE_OWNER_SW; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws.h index 9bbadc4d8a0b680f4974220b281c993f14330ef1..d8ac6c196211c9e782c5ab609e0aea15d6528085 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws.h @@ -213,6 +213,7 @@ struct mlx5hws_action_dest_attr { struct mlx5hws_action *dest; /* Optional reformat action */ struct mlx5hws_action *reformat; + bool is_wire_ft; }; /** diff --git a/drivers/net/ethernet/micrel/ksz884x.c b/drivers/net/ethernet/micrel/ksz884x.c index 1302aa8e0853656a4527b044fab179419610c657..cdde19b8edc46967d7427d41d4b24a54f660ebbd 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 7c501a758325fc0ba352bd509c90e6e2ab2816df..e611ff7fa3fabad1e0060c2befa280aa2f7f21d2 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 dd279788cf9eb65ff9c4f02761e81e82f97933ec..b253734dbc8054b48b4cccdb031742e08d0429e1 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 bf0347715a059e76fa5189ead4726850b873dd32..56d5464222d97a00de32e74cc9effded9ef3f388 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 3e55e8dc664cef9541ebd4df470d2e98fb5900d2..27443e346f9f7baadd8e8502fe8bb72556905d9f 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 28997ddab9664a8ea9bfdde98e8602e68954a7b9..932f59d70f41134c3a0deeb66259c958171c03f4 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 29cb74ccb25a6df40434fe4983d22bdea136aa17..19aa1f1538aa3b2d63acdd2de499a143b1cd27a2 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 1651df8a7c2114dd4b8ec083351af85ef94a7aed..e5a6f59af0b63dcd39f2134024853235b37f5029 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 26bc8b3b1ec8f92465a7c615087cee4883fb5563..b0de7e9f12a5da84da3297d1280dc60805c17384 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 21b760e65d73e61a6674ab67daedac1950f56469..1e25ac13a7d8a6868295df6771fb44e722ebbf78 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 8013807290468aefbac5884f3b87358dfff9d3b8..fe58024b5901d3ca95d70cf3a0d280bf2f82333f 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 57edcde9e6f8c64dd9bfb0f2db7fcf6f3f1d529c..18b9c8a810aecc763be42c3e7ef4164ccec0ddbe 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 bf5bf8c95c85510dc0b641ded2e74838537bd31e..aee4e63b4b8291c3273e9d1e03ba9cae00a3845e 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 c73a57e4a144de46c5e86cc8a1627897f8c51808..0d65434982a24dab5081565dfc55928cdf24ea28 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 19985d13e2434e54555d0d64390d22ecb525b435..61e50517c05b1bcd6e5bb9f009e4f596b00051f4 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 36b63bf343a91d53bfcfa9b10f74962b01ad53b0..75bad561b352580b409c76f8455a2ac2de91f59a 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 1d65113fab76c1945d73ccec59566457b34eaf43..20dad39b5ab94759c8c41ea6ff2fc534a0a72795 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 b865275beb661c23d2762d1e0b90737eaa7e43a9..c44df8e4dd30693422acbcce6059236e99902f6c 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 38ad7ac07726036bb3b5b05734823641fae444b7..f69fcf6caca8c4493bf569cf5ef2ff2128616dd4 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 dcef0588be9649a54a42a2ee61ee9a9ec1d10ede..5e9b8def5e423ca5da61077d71101fb65b6caf6b 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 8eb272ba674bf6d3bfb4027648c27cfa28902d8e..f4f75299dfa948e942b356c2cd2fbf1ce81ac2b4 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 99ab5f2946915240f81c262c0fa91ec286f29032..c8f0fb43e2855cb769e79b4664bf8b95a98912cc 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 ab493e529d5cc7eae61972df49216ef00cad6abe..98d27174015d4d7966b31ab0d99d4249b0effec3 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 7196e1c607f36c35573af217dc36a96ca4ce3c0b..39731069d99e0beedeabee3ec5ce49652c11de30 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 d10b14787607562f03d3b17e6e81b84326964193..15e46e6ac262b19fcb341bfc597304e1cae72b3c 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 df869f82cae8a28650cef1a2ddc3f6ca57006cab..b461918dc5f49109968cfe2c71c72e769abee61a 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 ca0ab3a35b73ed7bbdab031f42a6f76555c43bb2..45f703fe0e5ad8f8c8f26ca06dcf912b49e0f203 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 6fa957fb523bc9f482959f821895e5cdd186615f..cc0c7569435131e9d313220b6446592ae9978b13 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 1369fa70bc587e5c9e22fc33f69bc9ca0774be86..b948df1bff9a84966e6e7a43831585b81ca3748a 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 b777e5a099ebbf600a88adb12b2cef130b5fe1d4..acfb523214b9e739aedff0586ec20a4ba7758abb 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 379b6e90121d9f5f39645089306dc0d94a09b14c..ddca8fc7883eda13acbe4e853cd071da38b004b3 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 d2c82102133c24439c101f1c931d08c50568fa1a..edb2fd3a6551b76cc25e00cb74e4b0eeb39508dd 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 06579d7b5220b335da6c290587117615e18b9297..8e69d917d827caf6bd14b8156bd66be566b8bc1d 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 9a7586623318a8cce83fd4a7023ce0b91d5c6b6a..4bc0e114d5ee71a134694c167cc03b9325117fba 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 ddc6d46a7a868ea8f51b9c6b17fd382ac16e46ce..0212853c94300627f80076faf9b512689212fcd5 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 24e4b246f25fb4f9ebb96dd486ef3f664064bed4..37101dc50d04c36f38364fade631aee688ebbf99 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 7f77694ecfbaf2ce28b20c6164f99c43943e084a..fbe35af615a6f05861683032873fb6c30b2e057c 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 fd2b7450898074b370f9eb825c1fb3baa61a84f3..55a1a96cd83499ea004f38911dc790b6a82ec57a 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 d9240fb917470bd721c113b605f38a86f3254a2a..a55b0f951181f92fdb9a6abd9a9381bb5b0c77d4 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 7ec0e3c13d54a309b9f153122c54e4ef68e316a4..7e0b3d694ac0ed7621a95a939dfb64093a10de8a 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 5c747509d56baebe48482dbcc550a656db055dc9..7f2e6cddfeb1063d51e0ea86d312b76e69d462bc 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 54b7f24f381039fed082ae9775eb3ddd8a1a594d..2098c3068d34f7b479d353301ab1eb1f9475d17f 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 b33d84ed5bbfaa21c9daae1ecd9c62be0026246c..c5e5423e18633a25e3c5d9925ba6a7c10cf531bf 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 f88721dec6817c7cf6f13457c5da59616b5c38de..ae5048efde686afd25eb0e4a9f8c26f603f05b79 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 6342c319c0e4470b0c2969f0e671f8c9cadd67e8..7b7e7a47a75e1bcdf2fb2b2fc8d86761f71c0a31 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/macsec.c b/drivers/net/macsec.c index 3d315e30ee472549e46e90235fa850c0aabf85b8..7edbe76b5455a8486c9505bfb258c25a81096395 100644 --- a/drivers/net/macsec.c +++ b/drivers/net/macsec.c @@ -247,15 +247,39 @@ static sci_t make_sci(const u8 *addr, __be16 port) return sci; } -static sci_t macsec_frame_sci(struct macsec_eth_header *hdr, bool sci_present) +static sci_t macsec_active_sci(struct macsec_secy *secy) { - sci_t sci; + struct macsec_rx_sc *rx_sc = rcu_dereference_bh(secy->rx_sc); + + /* Case single RX SC */ + if (rx_sc && !rcu_dereference_bh(rx_sc->next)) + return (rx_sc->active) ? rx_sc->sci : 0; + /* Case no RX SC or multiple */ + else + return 0; +} + +static sci_t macsec_frame_sci(struct macsec_eth_header *hdr, bool sci_present, + struct macsec_rxh_data *rxd) +{ + struct macsec_dev *macsec; + sci_t sci = 0; - if (sci_present) + /* SC = 1 */ + if (sci_present) { memcpy(&sci, hdr->secure_channel_id, sizeof(hdr->secure_channel_id)); - else + /* SC = 0; ES = 0 */ + } else if ((!(hdr->tci_an & (MACSEC_TCI_ES | MACSEC_TCI_SC))) && + (list_is_singular(&rxd->secys))) { + /* Only one SECY should exist on this scenario */ + macsec = list_first_or_null_rcu(&rxd->secys, struct macsec_dev, + secys); + if (macsec) + return macsec_active_sci(&macsec->secy); + } else { sci = make_sci(hdr->eth.h_source, MACSEC_PORT_ES); + } return sci; } @@ -1109,7 +1133,7 @@ static rx_handler_result_t macsec_handle_frame(struct sk_buff **pskb) struct macsec_rxh_data *rxd; struct macsec_dev *macsec; unsigned int len; - sci_t sci; + sci_t sci = 0; u32 hdr_pn; bool cbit; struct pcpu_rx_sc_stats *rxsc_stats; @@ -1156,11 +1180,14 @@ static rx_handler_result_t macsec_handle_frame(struct sk_buff **pskb) macsec_skb_cb(skb)->has_sci = !!(hdr->tci_an & MACSEC_TCI_SC); macsec_skb_cb(skb)->assoc_num = hdr->tci_an & MACSEC_AN_MASK; - sci = macsec_frame_sci(hdr, macsec_skb_cb(skb)->has_sci); rcu_read_lock(); rxd = macsec_data_rcu(skb->dev); + sci = macsec_frame_sci(hdr, macsec_skb_cb(skb)->has_sci, rxd); + if (!sci) + goto drop_nosc; + list_for_each_entry_rcu(macsec, &rxd->secys, secys) { struct macsec_rx_sc *sc = find_rx_sc(&macsec->secy, sci); @@ -1283,6 +1310,7 @@ drop: macsec_rxsa_put(rx_sa); drop_nosa: macsec_rxsc_put(rx_sc); +drop_nosc: rcu_read_unlock(); drop_direct: kfree_skb(skb); diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index 21077aff061c525169c4ae183e6a41b2e3db0f49..1eb678e07dd05db31b2a79817e0921734be26e77 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -1298,7 +1298,6 @@ static int sysdata_append_release(struct netconsole_target *nt, int offset) */ static int prepare_extradata(struct netconsole_target *nt) { - u32 fields = SYSDATA_CPU_NR | SYSDATA_TASKNAME; int extradata_len; /* userdata was appended when configfs write helper was called @@ -1306,7 +1305,7 @@ static int prepare_extradata(struct netconsole_target *nt) */ extradata_len = nt->userdata_length; - if (!(nt->sysdata_fields & fields)) + if (!nt->sysdata_fields) goto out; if (nt->sysdata_fields & SYSDATA_CPU_NR) diff --git a/drivers/net/netdevsim/netdev.c b/drivers/net/netdevsim/netdev.c index af545d42961c3cb8c0ffcd78ac2fe54453bd27f0..fa5fbd97ad69e39399ef39a7de6f807a10efe213 100644 --- a/drivers/net/netdevsim/netdev.c +++ b/drivers/net/netdevsim/netdev.c @@ -371,7 +371,8 @@ static int nsim_poll(struct napi_struct *napi, int budget) int done; done = nsim_rcv(rq, budget); - napi_complete(napi); + if (done < budget) + napi_complete_done(napi, done); return done; } diff --git a/drivers/net/ntb_netdev.c b/drivers/net/ntb_netdev.c index ef4204638392d4d5ae6c8efa9d4ccc1679b28db7..fbeae05817e9ff05692e2ac6fb16a804b853fb36 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/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index a6bcb0fee8630964015b5d825c0036784584eea6..fda2e27c18105cff83292a2b6fbc4d989d1db576 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c @@ -445,6 +445,9 @@ int __mdiobus_read(struct mii_bus *bus, int addr, u32 regnum) lockdep_assert_held_once(&bus->mdio_lock); + if (addr >= PHY_MAX_ADDR) + return -ENXIO; + if (bus->read) retval = bus->read(bus, addr, regnum); else @@ -474,6 +477,9 @@ int __mdiobus_write(struct mii_bus *bus, int addr, u32 regnum, u16 val) lockdep_assert_held_once(&bus->mdio_lock); + if (addr >= PHY_MAX_ADDR) + return -ENXIO; + if (bus->write) err = bus->write(bus, addr, regnum, val); else @@ -535,6 +541,9 @@ int __mdiobus_c45_read(struct mii_bus *bus, int addr, int devad, u32 regnum) lockdep_assert_held_once(&bus->mdio_lock); + if (addr >= PHY_MAX_ADDR) + return -ENXIO; + if (bus->read_c45) retval = bus->read_c45(bus, addr, devad, regnum); else @@ -566,6 +575,9 @@ int __mdiobus_c45_write(struct mii_bus *bus, int addr, int devad, u32 regnum, lockdep_assert_held_once(&bus->mdio_lock); + if (addr >= PHY_MAX_ADDR) + return -ENXIO; + if (bus->write_c45) err = bus->write_c45(bus, addr, devad, regnum, val); else diff --git a/drivers/net/phy/phy_caps.c b/drivers/net/phy/phy_caps.c index 7033216897264e31d7bd3c85bdec066cc983497c..38417e2886118c9eafeed0b72a20f41eb9f6234f 100644 --- a/drivers/net/phy/phy_caps.c +++ b/drivers/net/phy/phy_caps.c @@ -188,6 +188,9 @@ phy_caps_lookup_by_linkmode_rev(const unsigned long *linkmodes, bool fdx_only) * When @exact is not set, we return either an exact match, or matching capabilities * at lower speed, or the lowest matching speed, or NULL. * + * Non-exact matches will try to return an exact speed and duplex match, but may + * return matching capabilities with same speed but a different duplex. + * * Returns: a matched link_capabilities according to the above process, NULL * otherwise. */ @@ -195,7 +198,7 @@ const struct link_capabilities * phy_caps_lookup(int speed, unsigned int duplex, const unsigned long *supported, bool exact) { - const struct link_capabilities *lcap, *last = NULL; + const struct link_capabilities *lcap, *match = NULL, *last = NULL; for_each_link_caps_desc_speed(lcap) { if (linkmode_intersects(lcap->linkmodes, supported)) { @@ -204,16 +207,19 @@ phy_caps_lookup(int speed, unsigned int duplex, const unsigned long *supported, if (lcap->speed == speed && lcap->duplex == duplex) { return lcap; } else if (!exact) { - if (lcap->speed <= speed) - return lcap; + if (!match && lcap->speed <= speed) + match = lcap; + + if (lcap->speed < speed) + break; } } } - if (!exact) - return last; + if (!match && !exact) + match = last; - return NULL; + return match; } EXPORT_SYMBOL_GPL(phy_caps_lookup); diff --git a/drivers/net/slip/slip.c b/drivers/net/slip/slip.c index 3cfa17cd5073f523a142eef9d48e1984771e6549..c889fb3747030b72e207aa24e633319faccdab53 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 1207196cbbedbf41c7bdd16a17a9dfffc87c8ebe..f8c5e2fd04dfa0a9543f322ae570b68cf993da43 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 fc5e441aa7c30885f1a76c2bca38769738e69e19..6759388692f8e98937ff39e002fcf332c90065f0 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 17c23eada645fa70c5444cde0fd5a265f9c824a2..3edcf96cc7a54c26df723cd981f99083dfc2bd6a 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/r8152.c b/drivers/net/usb/r8152.c index d6589b24c68d01e987a24e86041c68915d3e3de2..44cba7acfe7d9bfbcc96a1e974762657bd1c3c33 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -10054,6 +10054,7 @@ static const struct usb_device_id rtl8152_table[] = { { USB_DEVICE(VENDOR_ID_LINKSYS, 0x0041) }, { USB_DEVICE(VENDOR_ID_NVIDIA, 0x09ff) }, { USB_DEVICE(VENDOR_ID_TPLINK, 0x0601) }, + { USB_DEVICE(VENDOR_ID_TPLINK, 0x0602) }, { USB_DEVICE(VENDOR_ID_DLINK, 0xb301) }, { USB_DEVICE(VENDOR_ID_DELL, 0xb097) }, { USB_DEVICE(VENDOR_ID_ASUS, 0x1976) }, diff --git a/drivers/net/usb/sierra_net.c b/drivers/net/usb/sierra_net.c index dec6e82eb0e03356d0020c439fca2d8e6ac33c5d..c30ca415d1d3df141982a834722bb4a5655477ac 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 c39dfa17813a3fc49b80ea89ae63c98d33073c72..c04e715a4c2ade3bc5587b0df71643a25cf88c55 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/veth.c b/drivers/net/veth.c index e58a0f1b5c5b7c3d2c6cc2fa3baa3d912fa34109..a3046142cb8e2658a30041129f8d298e5e0a5822 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -909,7 +909,7 @@ static int veth_xdp_rcv(struct veth_rq *rq, int budget, /* NAPI functions as RCU section */ peer_dev = rcu_dereference_check(priv->peer, rcu_read_lock_bh_held()); - peer_txq = netdev_get_tx_queue(peer_dev, queue_idx); + peer_txq = peer_dev ? netdev_get_tx_queue(peer_dev, queue_idx) : NULL; for (i = 0; i < budget; i++) { void *ptr = __ptr_ring_consume(&rq->xdp_ring); @@ -959,7 +959,7 @@ static int veth_xdp_rcv(struct veth_rq *rq, int budget, rq->stats.vs.xdp_packets += done; u64_stats_update_end(&rq->stats.syncp); - if (unlikely(netif_tx_queue_stopped(peer_txq))) + if (peer_txq && unlikely(netif_tx_queue_stopped(peer_txq))) netif_tx_wake_queue(peer_txq); return done; diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c index a56d7239b1273481160314defc9d20c41dc65d50..97792de896b72f4516feed496ad52710d3efde77 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 7e653432c1399118c684973a476d2788c00b44d7..bfc978b15bc2ac677b615878322effb7b16847f5 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 34014f427060f64fe43c929e60c8b52ceacc3888..08a0ba5ca471a37b1a10f09de645895afe2b8d90 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 19921b02846ddb3ccbcb52cae1cd0dc0ebdcf29d..7496a2e9a28203e4610efc141d2e5fdaac08b35c 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 a9e0890c2f7769e155cb5a1595d59e72072b0c16..4016a306560205ccfd63cca4f07a8d364ad0f83b 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 96dc2778022ab2cf77f56a038d028a38f70570ab..343c9de2749c08eea83c7550f9fd82027e5e3166 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 52981052e211a0e23271779f8589618e0b9c8de4..fb0d5d4cae3a1c1bcb82c3bf83d57d79c3661f07 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/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 8c7ffea0fa44b5d3c03f2fd7191fb757a4966ad6..07fe05384cdfb13924a956f7d672042b782e166f 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -4,6 +4,7 @@ * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include "mac.h" @@ -1022,6 +1023,26 @@ static inline int ath10k_vdev_setup_sync(struct ath10k *ar) return ar->last_wmi_vdev_start_status; } +static inline int ath10k_vdev_delete_sync(struct ath10k *ar) +{ + unsigned long time_left; + + lockdep_assert_held(&ar->conf_mutex); + + if (!test_bit(WMI_SERVICE_SYNC_DELETE_CMDS, ar->wmi.svc_map)) + return 0; + + if (test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags)) + return -ESHUTDOWN; + + time_left = wait_for_completion_timeout(&ar->vdev_delete_done, + ATH10K_VDEV_DELETE_TIMEOUT_HZ); + if (time_left == 0) + return -ETIMEDOUT; + + return 0; +} + static int ath10k_monitor_vdev_start(struct ath10k *ar, int vdev_id) { struct cfg80211_chan_def *chandef = NULL; @@ -5900,7 +5921,6 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw, struct ath10k *ar = hw->priv; struct ath10k_vif *arvif = (void *)vif->drv_priv; struct ath10k_peer *peer; - unsigned long time_left; int ret; int i; @@ -5940,13 +5960,10 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw, ath10k_warn(ar, "failed to delete WMI vdev %i: %d\n", arvif->vdev_id, ret); - if (test_bit(WMI_SERVICE_SYNC_DELETE_CMDS, ar->wmi.svc_map)) { - time_left = wait_for_completion_timeout(&ar->vdev_delete_done, - ATH10K_VDEV_DELETE_TIMEOUT_HZ); - if (time_left == 0) { - ath10k_warn(ar, "Timeout in receiving vdev delete response\n"); - goto out; - } + ret = ath10k_vdev_delete_sync(ar); + if (ret) { + ath10k_warn(ar, "Error in receiving vdev delete response: %d\n", ret); + goto out; } /* Some firmware revisions don't notify host about self-peer removal diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 20ec0a6d0f71c4fee3bf1a3d48b512ebcdfba856..1e6d43285138ece619b9d7dc49f113a439e2085d 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 f3212eab56a17c685d9b2c2e0e03225b9e87c63c..c06d50db40b8185e3b5c22088b57801852810725 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 866bad2db3348787b8778a3c9429c0bc2acf1157..d51f2e5a79a401e0e3821a1a9f251e2569a1d7b1 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); @@ -937,7 +938,9 @@ static int ath10k_snoc_hif_start(struct ath10k *ar) dev_set_threaded(ar->napi_dev, true); ath10k_core_napi_enable(ar); - ath10k_snoc_irq_enable(ar); + /* IRQs are left enabled when we restart due to a firmware crash */ + if (!test_bit(ATH10K_SNOC_FLAG_RECOVERY, &ar_snoc->flags)) + ath10k_snoc_irq_enable(ar); ath10k_snoc_rx_post(ar); clear_bit(ATH10K_SNOC_FLAG_RECOVERY, &ar_snoc->flags); diff --git a/drivers/net/wireless/ath/ath11k/ce.c b/drivers/net/wireless/ath/ath11k/ce.c index 9d8efec46508a1bda1c4345fe352517fa287586a..746038006eb46586c0e47fdeb89faf1ccc4f0c28 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/core.c b/drivers/net/wireless/ath/ath11k/core.c index 2e9f8a5e61e4c0cba476403764f42541948edd30..22a10113613503bb2cf97185d2f6ccd7921e243d 100644 --- a/drivers/net/wireless/ath/ath11k/core.c +++ b/drivers/net/wireless/ath/ath11k/core.c @@ -990,6 +990,7 @@ void ath11k_fw_stats_init(struct ath11k *ar) INIT_LIST_HEAD(&ar->fw_stats.bcn); init_completion(&ar->fw_stats_complete); + init_completion(&ar->fw_stats_done); } void ath11k_fw_stats_free(struct ath11k_fw_stats *stats) @@ -2134,6 +2135,20 @@ int ath11k_core_qmi_firmware_ready(struct ath11k_base *ab) { int ret; + switch (ath11k_crypto_mode) { + case ATH11K_CRYPT_MODE_SW: + set_bit(ATH11K_FLAG_HW_CRYPTO_DISABLED, &ab->dev_flags); + set_bit(ATH11K_FLAG_RAW_MODE, &ab->dev_flags); + break; + case ATH11K_CRYPT_MODE_HW: + clear_bit(ATH11K_FLAG_HW_CRYPTO_DISABLED, &ab->dev_flags); + clear_bit(ATH11K_FLAG_RAW_MODE, &ab->dev_flags); + break; + default: + ath11k_info(ab, "invalid crypto_mode: %d\n", ath11k_crypto_mode); + return -EINVAL; + } + ret = ath11k_core_start_firmware(ab, ab->fw_mode); if (ret) { ath11k_err(ab, "failed to start firmware: %d\n", ret); @@ -2152,20 +2167,6 @@ int ath11k_core_qmi_firmware_ready(struct ath11k_base *ab) goto err_firmware_stop; } - switch (ath11k_crypto_mode) { - case ATH11K_CRYPT_MODE_SW: - set_bit(ATH11K_FLAG_HW_CRYPTO_DISABLED, &ab->dev_flags); - set_bit(ATH11K_FLAG_RAW_MODE, &ab->dev_flags); - break; - case ATH11K_CRYPT_MODE_HW: - clear_bit(ATH11K_FLAG_HW_CRYPTO_DISABLED, &ab->dev_flags); - clear_bit(ATH11K_FLAG_RAW_MODE, &ab->dev_flags); - break; - default: - ath11k_info(ab, "invalid crypto_mode: %d\n", ath11k_crypto_mode); - return -EINVAL; - } - if (ath11k_frame_mode == ATH11K_HW_TXRX_RAW) set_bit(ATH11K_FLAG_RAW_MODE, &ab->dev_flags); diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h index 339d4fca1ed5fbddd8f386589529f0febba98ecb..6b2f207975e33a1a593e3090882b1bf7656b1c2f 100644 --- a/drivers/net/wireless/ath/ath11k/core.h +++ b/drivers/net/wireless/ath/ath11k/core.h @@ -600,6 +600,8 @@ struct ath11k_fw_stats { struct list_head pdevs; struct list_head vdevs; struct list_head bcn; + u32 num_vdev_recvd; + u32 num_bcn_recvd; }; struct ath11k_dbg_htt_stats { @@ -784,7 +786,7 @@ struct ath11k { u8 alpha2[REG_ALPHA2_LEN + 1]; struct ath11k_fw_stats fw_stats; struct completion fw_stats_complete; - bool fw_stats_done; + struct completion fw_stats_done; /* protected by conf_mutex */ bool ps_state_enable; diff --git a/drivers/net/wireless/ath/ath11k/debugfs.c b/drivers/net/wireless/ath/ath11k/debugfs.c index bf192529e3fe26a91e72105a77b4c6f849b905ec..5d46f8e4c231fb75577d997e24730f8c87033ec7 100644 --- a/drivers/net/wireless/ath/ath11k/debugfs.c +++ b/drivers/net/wireless/ath/ath11k/debugfs.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2020 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -93,57 +93,14 @@ void ath11k_debugfs_add_dbring_entry(struct ath11k *ar, spin_unlock_bh(&dbr_data->lock); } -static void ath11k_debugfs_fw_stats_reset(struct ath11k *ar) -{ - spin_lock_bh(&ar->data_lock); - ar->fw_stats_done = false; - ath11k_fw_stats_pdevs_free(&ar->fw_stats.pdevs); - ath11k_fw_stats_vdevs_free(&ar->fw_stats.vdevs); - spin_unlock_bh(&ar->data_lock); -} - void ath11k_debugfs_fw_stats_process(struct ath11k *ar, struct ath11k_fw_stats *stats) { struct ath11k_base *ab = ar->ab; - struct ath11k_pdev *pdev; - bool is_end; - static unsigned int num_vdev, num_bcn; - size_t total_vdevs_started = 0; - int i; - - /* WMI_REQUEST_PDEV_STAT request has been already processed */ - - if (stats->stats_id == WMI_REQUEST_RSSI_PER_CHAIN_STAT) { - ar->fw_stats_done = true; - return; - } - - if (stats->stats_id == WMI_REQUEST_VDEV_STAT) { - if (list_empty(&stats->vdevs)) { - ath11k_warn(ab, "empty vdev stats"); - return; - } - /* FW sends all the active VDEV stats irrespective of PDEV, - * hence limit until the count of all VDEVs started - */ - for (i = 0; i < ab->num_radios; i++) { - pdev = rcu_dereference(ab->pdevs_active[i]); - if (pdev && pdev->ar) - total_vdevs_started += ar->num_started_vdevs; - } - - is_end = ((++num_vdev) == total_vdevs_started); - - list_splice_tail_init(&stats->vdevs, - &ar->fw_stats.vdevs); - - if (is_end) { - ar->fw_stats_done = true; - num_vdev = 0; - } - return; - } + bool is_end = true; + /* WMI_REQUEST_PDEV_STAT, WMI_REQUEST_RSSI_PER_CHAIN_STAT and + * WMI_REQUEST_VDEV_STAT requests have been already processed. + */ if (stats->stats_id == WMI_REQUEST_BCN_STAT) { if (list_empty(&stats->bcn)) { ath11k_warn(ab, "empty bcn stats"); @@ -152,97 +109,18 @@ void ath11k_debugfs_fw_stats_process(struct ath11k *ar, struct ath11k_fw_stats * /* Mark end until we reached the count of all started VDEVs * within the PDEV */ - is_end = ((++num_bcn) == ar->num_started_vdevs); + if (ar->num_started_vdevs) + is_end = ((++ar->fw_stats.num_bcn_recvd) == + ar->num_started_vdevs); list_splice_tail_init(&stats->bcn, &ar->fw_stats.bcn); - if (is_end) { - ar->fw_stats_done = true; - num_bcn = 0; - } + if (is_end) + complete(&ar->fw_stats_done); } } -static int ath11k_debugfs_fw_stats_request(struct ath11k *ar, - struct stats_request_params *req_param) -{ - struct ath11k_base *ab = ar->ab; - unsigned long timeout, time_left; - int ret; - - lockdep_assert_held(&ar->conf_mutex); - - /* FW stats can get split when exceeding the stats data buffer limit. - * In that case, since there is no end marking for the back-to-back - * received 'update stats' event, we keep a 3 seconds timeout in case, - * fw_stats_done is not marked yet - */ - timeout = jiffies + secs_to_jiffies(3); - - ath11k_debugfs_fw_stats_reset(ar); - - reinit_completion(&ar->fw_stats_complete); - - ret = ath11k_wmi_send_stats_request_cmd(ar, req_param); - - if (ret) { - ath11k_warn(ab, "could not request fw stats (%d)\n", - ret); - return ret; - } - - time_left = wait_for_completion_timeout(&ar->fw_stats_complete, 1 * HZ); - - if (!time_left) - return -ETIMEDOUT; - - for (;;) { - if (time_after(jiffies, timeout)) - break; - - spin_lock_bh(&ar->data_lock); - if (ar->fw_stats_done) { - spin_unlock_bh(&ar->data_lock); - break; - } - spin_unlock_bh(&ar->data_lock); - } - return 0; -} - -int ath11k_debugfs_get_fw_stats(struct ath11k *ar, u32 pdev_id, - u32 vdev_id, u32 stats_id) -{ - struct ath11k_base *ab = ar->ab; - struct stats_request_params req_param; - int ret; - - mutex_lock(&ar->conf_mutex); - - if (ar->state != ATH11K_STATE_ON) { - ret = -ENETDOWN; - goto err_unlock; - } - - req_param.pdev_id = pdev_id; - req_param.vdev_id = vdev_id; - req_param.stats_id = stats_id; - - ret = ath11k_debugfs_fw_stats_request(ar, &req_param); - if (ret) - ath11k_warn(ab, "failed to request fw stats: %d\n", ret); - - ath11k_dbg(ab, ATH11K_DBG_WMI, - "debug get fw stat pdev id %d vdev id %d stats id 0x%x\n", - pdev_id, vdev_id, stats_id); - -err_unlock: - mutex_unlock(&ar->conf_mutex); - - return ret; -} - static int ath11k_open_pdev_stats(struct inode *inode, struct file *file) { struct ath11k *ar = inode->i_private; @@ -268,7 +146,7 @@ static int ath11k_open_pdev_stats(struct inode *inode, struct file *file) req_param.vdev_id = 0; req_param.stats_id = WMI_REQUEST_PDEV_STAT; - ret = ath11k_debugfs_fw_stats_request(ar, &req_param); + ret = ath11k_mac_fw_stats_request(ar, &req_param); if (ret) { ath11k_warn(ab, "failed to request fw pdev stats: %d\n", ret); goto err_free; @@ -339,7 +217,7 @@ static int ath11k_open_vdev_stats(struct inode *inode, struct file *file) req_param.vdev_id = 0; req_param.stats_id = WMI_REQUEST_VDEV_STAT; - ret = ath11k_debugfs_fw_stats_request(ar, &req_param); + ret = ath11k_mac_fw_stats_request(ar, &req_param); if (ret) { ath11k_warn(ar->ab, "failed to request fw vdev stats: %d\n", ret); goto err_free; @@ -415,7 +293,7 @@ static int ath11k_open_bcn_stats(struct inode *inode, struct file *file) continue; req_param.vdev_id = arvif->vdev_id; - ret = ath11k_debugfs_fw_stats_request(ar, &req_param); + ret = ath11k_mac_fw_stats_request(ar, &req_param); if (ret) { ath11k_warn(ar->ab, "failed to request fw bcn stats: %d\n", ret); goto err_free; diff --git a/drivers/net/wireless/ath/ath11k/debugfs.h b/drivers/net/wireless/ath/ath11k/debugfs.h index a39e458637b01366b430e138bbc53126196b512f..ed7fec177588f69659b0dd9bdf66d83b511f36f0 100644 --- a/drivers/net/wireless/ath/ath11k/debugfs.h +++ b/drivers/net/wireless/ath/ath11k/debugfs.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2022, 2025 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _ATH11K_DEBUGFS_H_ @@ -273,8 +273,6 @@ void ath11k_debugfs_unregister(struct ath11k *ar); void ath11k_debugfs_fw_stats_process(struct ath11k *ar, struct ath11k_fw_stats *stats); void ath11k_debugfs_fw_stats_init(struct ath11k *ar); -int ath11k_debugfs_get_fw_stats(struct ath11k *ar, u32 pdev_id, - u32 vdev_id, u32 stats_id); static inline bool ath11k_debugfs_is_pktlog_lite_mode_enabled(struct ath11k *ar) { @@ -381,12 +379,6 @@ static inline int ath11k_debugfs_rx_filter(struct ath11k *ar) return 0; } -static inline int ath11k_debugfs_get_fw_stats(struct ath11k *ar, - u32 pdev_id, u32 vdev_id, u32 stats_id) -{ - return 0; -} - static inline void ath11k_debugfs_add_dbring_entry(struct ath11k *ar, enum wmi_direct_buffer_module id, diff --git a/drivers/net/wireless/ath/ath11k/dp.c b/drivers/net/wireless/ath/ath11k/dp.c index 3a544e5fefca13fc5b8ec65ebed7d25a00c41534..bf3928ada995fe015ddbe455083f4125fa136749 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 ea2959305dec65f7edd930c7751f49eecfef827c..9230a965f6f0eb99fa147d90e28679838209efef 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/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index 08d7b136851fabb0a1c1032abcf9c01550e9f4f5..13301ca317a532b86cc6003d33306672307ea193 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -8997,6 +8997,81 @@ static void ath11k_mac_put_chain_rssi(struct station_info *sinfo, } } +static void ath11k_mac_fw_stats_reset(struct ath11k *ar) +{ + spin_lock_bh(&ar->data_lock); + ath11k_fw_stats_pdevs_free(&ar->fw_stats.pdevs); + ath11k_fw_stats_vdevs_free(&ar->fw_stats.vdevs); + ar->fw_stats.num_vdev_recvd = 0; + ar->fw_stats.num_bcn_recvd = 0; + spin_unlock_bh(&ar->data_lock); +} + +int ath11k_mac_fw_stats_request(struct ath11k *ar, + struct stats_request_params *req_param) +{ + struct ath11k_base *ab = ar->ab; + unsigned long time_left; + int ret; + + lockdep_assert_held(&ar->conf_mutex); + + ath11k_mac_fw_stats_reset(ar); + + reinit_completion(&ar->fw_stats_complete); + reinit_completion(&ar->fw_stats_done); + + ret = ath11k_wmi_send_stats_request_cmd(ar, req_param); + + if (ret) { + ath11k_warn(ab, "could not request fw stats (%d)\n", + ret); + return ret; + } + + time_left = wait_for_completion_timeout(&ar->fw_stats_complete, 1 * HZ); + if (!time_left) + return -ETIMEDOUT; + + /* FW stats can get split when exceeding the stats data buffer limit. + * In that case, since there is no end marking for the back-to-back + * received 'update stats' event, we keep a 3 seconds timeout in case, + * fw_stats_done is not marked yet + */ + time_left = wait_for_completion_timeout(&ar->fw_stats_done, 3 * HZ); + if (!time_left) + return -ETIMEDOUT; + + return 0; +} + +static int ath11k_mac_get_fw_stats(struct ath11k *ar, u32 pdev_id, + u32 vdev_id, u32 stats_id) +{ + struct ath11k_base *ab = ar->ab; + struct stats_request_params req_param; + int ret; + + lockdep_assert_held(&ar->conf_mutex); + + if (ar->state != ATH11K_STATE_ON) + return -ENETDOWN; + + req_param.pdev_id = pdev_id; + req_param.vdev_id = vdev_id; + req_param.stats_id = stats_id; + + ret = ath11k_mac_fw_stats_request(ar, &req_param); + if (ret) + ath11k_warn(ab, "failed to request fw stats: %d\n", ret); + + ath11k_dbg(ab, ATH11K_DBG_WMI, + "debug get fw stat pdev id %d vdev id %d stats id 0x%x\n", + pdev_id, vdev_id, stats_id); + + return ret; +} + static void ath11k_mac_op_sta_statistics(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, @@ -9031,11 +9106,12 @@ static void ath11k_mac_op_sta_statistics(struct ieee80211_hw *hw, ath11k_mac_put_chain_rssi(sinfo, arsta, "ppdu", false); + mutex_lock(&ar->conf_mutex); if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL)) && arsta->arvif->vdev_type == WMI_VDEV_TYPE_STA && ar->ab->hw_params.supports_rssi_stats && - !ath11k_debugfs_get_fw_stats(ar, ar->pdev->pdev_id, 0, - WMI_REQUEST_RSSI_PER_CHAIN_STAT)) { + !ath11k_mac_get_fw_stats(ar, ar->pdev->pdev_id, 0, + WMI_REQUEST_RSSI_PER_CHAIN_STAT)) { ath11k_mac_put_chain_rssi(sinfo, arsta, "fw stats", true); } @@ -9043,9 +9119,10 @@ static void ath11k_mac_op_sta_statistics(struct ieee80211_hw *hw, if (!signal && arsta->arvif->vdev_type == WMI_VDEV_TYPE_STA && ar->ab->hw_params.supports_rssi_stats && - !(ath11k_debugfs_get_fw_stats(ar, ar->pdev->pdev_id, 0, - WMI_REQUEST_VDEV_STAT))) + !(ath11k_mac_get_fw_stats(ar, ar->pdev->pdev_id, 0, + WMI_REQUEST_VDEV_STAT))) signal = arsta->rssi_beacon; + mutex_unlock(&ar->conf_mutex); ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "sta statistics db2dbm %u rssi comb %d rssi beacon %d\n", @@ -9380,38 +9457,6 @@ exit: return ret; } -static int ath11k_fw_stats_request(struct ath11k *ar, - struct stats_request_params *req_param) -{ - struct ath11k_base *ab = ar->ab; - unsigned long time_left; - int ret; - - lockdep_assert_held(&ar->conf_mutex); - - spin_lock_bh(&ar->data_lock); - ar->fw_stats_done = false; - ath11k_fw_stats_pdevs_free(&ar->fw_stats.pdevs); - spin_unlock_bh(&ar->data_lock); - - reinit_completion(&ar->fw_stats_complete); - - ret = ath11k_wmi_send_stats_request_cmd(ar, req_param); - if (ret) { - ath11k_warn(ab, "could not request fw stats (%d)\n", - ret); - return ret; - } - - time_left = wait_for_completion_timeout(&ar->fw_stats_complete, - 1 * HZ); - - if (!time_left) - return -ETIMEDOUT; - - return 0; -} - static int ath11k_mac_op_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif, unsigned int link_id, @@ -9419,7 +9464,6 @@ static int ath11k_mac_op_get_txpower(struct ieee80211_hw *hw, { struct ath11k *ar = hw->priv; struct ath11k_base *ab = ar->ab; - struct stats_request_params req_param = {0}; struct ath11k_fw_stats_pdev *pdev; int ret; @@ -9431,9 +9475,6 @@ static int ath11k_mac_op_get_txpower(struct ieee80211_hw *hw, */ mutex_lock(&ar->conf_mutex); - if (ar->state != ATH11K_STATE_ON) - goto err_fallback; - /* Firmware doesn't provide Tx power during CAC hence no need to fetch * the stats. */ @@ -9442,10 +9483,8 @@ static int ath11k_mac_op_get_txpower(struct ieee80211_hw *hw, return -EAGAIN; } - req_param.pdev_id = ar->pdev->pdev_id; - req_param.stats_id = WMI_REQUEST_PDEV_STAT; - - ret = ath11k_fw_stats_request(ar, &req_param); + ret = ath11k_mac_get_fw_stats(ar, ar->pdev->pdev_id, 0, + WMI_REQUEST_PDEV_STAT); if (ret) { ath11k_warn(ab, "failed to request fw pdev stats: %d\n", ret); goto err_fallback; diff --git a/drivers/net/wireless/ath/ath11k/mac.h b/drivers/net/wireless/ath/ath11k/mac.h index f5800fbecff89e0a8e509cdbee005f3858d6b97a..5e61eea1bb0378a071c81b0b27133d75643a1d3b 100644 --- a/drivers/net/wireless/ath/ath11k/mac.h +++ b/drivers/net/wireless/ath/ath11k/mac.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023, 2025 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH11K_MAC_H @@ -179,4 +179,6 @@ int ath11k_mac_vif_set_keepalive(struct ath11k_vif *arvif, void ath11k_mac_fill_reg_tpc_info(struct ath11k *ar, struct ieee80211_vif *vif, struct ieee80211_chanctx_conf *ctx); +int ath11k_mac_fw_stats_request(struct ath11k *ar, + struct stats_request_params *req_param); #endif diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c index d7f852bebf4aa23a4bf85661cfdf38d919e12e0d..56af2e9634f422bbbc6a317fcf02cd36357f1a73 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -8158,6 +8158,11 @@ static void ath11k_peer_assoc_conf_event(struct ath11k_base *ab, struct sk_buff static void ath11k_update_stats_event(struct ath11k_base *ab, struct sk_buff *skb) { struct ath11k_fw_stats stats = {}; + size_t total_vdevs_started = 0; + struct ath11k_pdev *pdev; + bool is_end = true; + int i; + struct ath11k *ar; int ret; @@ -8184,25 +8189,57 @@ static void ath11k_update_stats_event(struct ath11k_base *ab, struct sk_buff *sk spin_lock_bh(&ar->data_lock); - /* WMI_REQUEST_PDEV_STAT can be requested via .get_txpower mac ops or via + /* WMI_REQUEST_PDEV_STAT, WMI_REQUEST_VDEV_STAT and + * WMI_REQUEST_RSSI_PER_CHAIN_STAT can be requested via mac ops or via * debugfs fw stats. Therefore, processing it separately. */ if (stats.stats_id == WMI_REQUEST_PDEV_STAT) { list_splice_tail_init(&stats.pdevs, &ar->fw_stats.pdevs); - ar->fw_stats_done = true; + complete(&ar->fw_stats_done); + goto complete; + } + + if (stats.stats_id == WMI_REQUEST_RSSI_PER_CHAIN_STAT) { + complete(&ar->fw_stats_done); goto complete; } - /* WMI_REQUEST_VDEV_STAT, WMI_REQUEST_BCN_STAT and WMI_REQUEST_RSSI_PER_CHAIN_STAT - * are currently requested only via debugfs fw stats. Hence, processing these - * in debugfs context + if (stats.stats_id == WMI_REQUEST_VDEV_STAT) { + if (list_empty(&stats.vdevs)) { + ath11k_warn(ab, "empty vdev stats"); + goto complete; + } + /* FW sends all the active VDEV stats irrespective of PDEV, + * hence limit until the count of all VDEVs started + */ + for (i = 0; i < ab->num_radios; i++) { + pdev = rcu_dereference(ab->pdevs_active[i]); + if (pdev && pdev->ar) + total_vdevs_started += ar->num_started_vdevs; + } + + if (total_vdevs_started) + is_end = ((++ar->fw_stats.num_vdev_recvd) == + total_vdevs_started); + + list_splice_tail_init(&stats.vdevs, + &ar->fw_stats.vdevs); + + if (is_end) + complete(&ar->fw_stats_done); + + goto complete; + } + + /* WMI_REQUEST_BCN_STAT is currently requested only via debugfs fw stats. + * Hence, processing it in debugfs context */ ath11k_debugfs_fw_stats_process(ar, &stats); complete: complete(&ar->fw_stats_complete); - rcu_read_unlock(); spin_unlock_bh(&ar->data_lock); + rcu_read_unlock(); /* Since the stats's pdev, vdev and beacon list are spliced and reinitialised * at this point, no need to free the individual list. diff --git a/drivers/net/wireless/ath/ath12k/ce.c b/drivers/net/wireless/ath/ath12k/ce.c index 47821a3b060bfeb6e8bf70100707863adf0f4845..3f3439262cf47eb2d315c04f8f5bcaecb63a4675 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/core.c b/drivers/net/wireless/ath/ath12k/core.c index 31d851d8e68838162e7663ad6464b80a7392df12..ebc0560d40e3419130e4caf01c9b91bd9affb3bd 100644 --- a/drivers/net/wireless/ath/ath12k/core.c +++ b/drivers/net/wireless/ath/ath12k/core.c @@ -2129,7 +2129,8 @@ int ath12k_core_init(struct ath12k_base *ab) if (!ag) { mutex_unlock(&ath12k_hw_group_mutex); ath12k_warn(ab, "unable to get hw group\n"); - return -ENODEV; + ret = -ENODEV; + goto err_unregister_notifier; } mutex_unlock(&ath12k_hw_group_mutex); @@ -2144,7 +2145,7 @@ int ath12k_core_init(struct ath12k_base *ab) if (ret) { mutex_unlock(&ag->mutex); ath12k_warn(ab, "unable to create hw group\n"); - goto err; + goto err_destroy_hw_group; } } @@ -2152,9 +2153,12 @@ int ath12k_core_init(struct ath12k_base *ab) return 0; -err: +err_destroy_hw_group: ath12k_core_hw_group_destroy(ab->ag); ath12k_core_hw_group_unassign(ab); +err_unregister_notifier: + ath12k_core_panic_notifier_unregister(ab); + return ret; } diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c index 7e1a8f29c7b6f0bd05f22ef2c2336b22bd7d25a0..57648febc4a4fc5dc7cff7b0a9bd83208290819d 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/ath12k/hal.h b/drivers/net/wireless/ath/ath12k/hal.h index 0ee9c6b26dab4ef597c95fea6fdb58d9cf1a0941..c1750b5dc03cbc9e7038df2fc81d0b576165e89b 100644 --- a/drivers/net/wireless/ath/ath12k/hal.h +++ b/drivers/net/wireless/ath/ath12k/hal.h @@ -585,7 +585,8 @@ enum hal_reo_cmd_type { * or cache was blocked * @HAL_REO_CMD_FAILED: Command execution failed, could be due to * invalid queue desc - * @HAL_REO_CMD_RESOURCE_BLOCKED: + * @HAL_REO_CMD_RESOURCE_BLOCKED: Command could not be executed because + * one or more descriptors were blocked * @HAL_REO_CMD_DRAIN: */ enum hal_reo_cmd_status { diff --git a/drivers/net/wireless/ath/ath12k/hw.c b/drivers/net/wireless/ath/ath12k/hw.c index 7e2cf0fb2085ab014fc14a5c81074802674b154e..8254dc10b53bbfb54a44c7ff2f705c72461d1031 100644 --- a/drivers/net/wireless/ath/ath12k/hw.c +++ b/drivers/net/wireless/ath/ath12k/hw.c @@ -951,6 +951,8 @@ static const struct ath12k_hw_regs qcn9274_v1_regs = { .hal_umac_ce0_dest_reg_base = 0x01b81000, .hal_umac_ce1_src_reg_base = 0x01b82000, .hal_umac_ce1_dest_reg_base = 0x01b83000, + + .gcc_gcc_pcie_hot_rst = 0x1e38338, }; static const struct ath12k_hw_regs qcn9274_v2_regs = { @@ -1042,6 +1044,8 @@ static const struct ath12k_hw_regs qcn9274_v2_regs = { .hal_umac_ce0_dest_reg_base = 0x01b81000, .hal_umac_ce1_src_reg_base = 0x01b82000, .hal_umac_ce1_dest_reg_base = 0x01b83000, + + .gcc_gcc_pcie_hot_rst = 0x1e38338, }; static const struct ath12k_hw_regs ipq5332_regs = { @@ -1215,6 +1219,8 @@ static const struct ath12k_hw_regs wcn7850_regs = { .hal_umac_ce0_dest_reg_base = 0x01b81000, .hal_umac_ce1_src_reg_base = 0x01b82000, .hal_umac_ce1_dest_reg_base = 0x01b83000, + + .gcc_gcc_pcie_hot_rst = 0x1e40304, }; static const struct ath12k_hw_hal_params ath12k_hw_hal_params_qcn9274 = { diff --git a/drivers/net/wireless/ath/ath12k/hw.h b/drivers/net/wireless/ath/ath12k/hw.h index 0fbc17649df463334aa0ebb3da407115985335ca..0a75bc5abfa2410ab3c7b6ce038f4d5f6445ecf9 100644 --- a/drivers/net/wireless/ath/ath12k/hw.h +++ b/drivers/net/wireless/ath/ath12k/hw.h @@ -375,6 +375,8 @@ struct ath12k_hw_regs { u32 hal_reo_cmd_ring_base; u32 hal_reo_status_ring_base; + + u32 gcc_gcc_pcie_hot_rst; }; static inline const char *ath12k_bd_ie_type_str(enum ath12k_bd_ie_type type) diff --git a/drivers/net/wireless/ath/ath12k/pci.c b/drivers/net/wireless/ath/ath12k/pci.c index 489d546390fcdab8f615cc9184006a958d9f140a..1f3cfd9b89fdcfd84731ec90c9c678b0c477a2af 100644 --- a/drivers/net/wireless/ath/ath12k/pci.c +++ b/drivers/net/wireless/ath/ath12k/pci.c @@ -292,10 +292,10 @@ static void ath12k_pci_enable_ltssm(struct ath12k_base *ab) ath12k_dbg(ab, ATH12K_DBG_PCI, "pci ltssm 0x%x\n", val); - val = ath12k_pci_read32(ab, GCC_GCC_PCIE_HOT_RST); + val = ath12k_pci_read32(ab, GCC_GCC_PCIE_HOT_RST(ab)); val |= GCC_GCC_PCIE_HOT_RST_VAL; - ath12k_pci_write32(ab, GCC_GCC_PCIE_HOT_RST, val); - val = ath12k_pci_read32(ab, GCC_GCC_PCIE_HOT_RST); + ath12k_pci_write32(ab, GCC_GCC_PCIE_HOT_RST(ab), val); + val = ath12k_pci_read32(ab, GCC_GCC_PCIE_HOT_RST(ab)); ath12k_dbg(ab, ATH12K_DBG_PCI, "pci pcie_hot_rst 0x%x\n", val); diff --git a/drivers/net/wireless/ath/ath12k/pci.h b/drivers/net/wireless/ath/ath12k/pci.h index 0b4c459d6d8eabb0773162e6bb3ca666c0a8f15a..d1ec8aad7f6c3b6f5cbdf8ce57a4106733686521 100644 --- a/drivers/net/wireless/ath/ath12k/pci.h +++ b/drivers/net/wireless/ath/ath12k/pci.h @@ -28,7 +28,9 @@ #define PCIE_PCIE_PARF_LTSSM 0x1e081b0 #define PARM_LTSSM_VALUE 0x111 -#define GCC_GCC_PCIE_HOT_RST 0x1e38338 +#define GCC_GCC_PCIE_HOT_RST(ab) \ + ((ab)->hw_params->regs->gcc_gcc_pcie_hot_rst) + #define GCC_GCC_PCIE_HOT_RST_VAL 0x10 #define PCIE_PCIE_INT_ALL_CLEAR 0x1e08228 diff --git a/drivers/net/wireless/ath/ath6kl/main.c b/drivers/net/wireless/ath/ath6kl/main.c index 867089a3c096748b5508cb5e265aa6bcd4a47fb6..d62b9645975116ddedb2bf9eaf80935d77b6d4cf 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 fd2dceb8b63dc0ed169865e41f7ac0190146ebd3..43186c193df1a200e82a2d027eecbf1160bdecf4 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 3a6f0b647e17ae3ce4effd1c485a9afe34fa6b3a..c3b06b515c4f410d5ab2dc2492a5d7b98ab79d01 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 3787b9fb0075599cfd9baf291bf94932cb6bf350..84317afe4651e4fb5bc36c00aed4afe0a7fa8b70 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 799be0be24f46638da559471df68f24d4c8cdc4b..121e51ce1bc0ea09dd005188151f2a2cbb06ce88 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 5a26f1d05f045e6a26fbd30707968e648831bb57..2dbc7efdd637aa939303103a70b61f7655f433d9 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 ce9c04e418b8d7d8cfc23e9e5d40968022d73daa..ee5945cfc10ebc00a95b871ab3e724591aa1a9bb 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 7f890997bb53102daa014949f2bb2db0468186cf..5d7e3ddb6dbc93287000faeaee045bad683aa79c 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 92fc5e3d756ef9c00d3fd372f034a35262cb9e31..c56f4f3b89907707ca6efca573a8058632a5be29 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 cc2a033e87f53ef6d4b8a6c44932c3f2bc94d340..0f4df5585fd92d3748ec99e638dc5ec433c7b7c4 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/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c index 67172385a5d66715b183b5bc9ed23c355ee0c781..89d4394cedcff7a912c93b85ad074b50c6ebf376 100644 --- a/drivers/net/wireless/ath/wil6210/interrupt.c +++ b/drivers/net/wireless/ath/wil6210/interrupt.c @@ -179,9 +179,11 @@ void wil_mask_irq(struct wil6210_priv *wil) wil_dbg_irq(wil, "mask_irq\n"); wil6210_mask_irq_tx(wil); - wil6210_mask_irq_tx_edma(wil); + if (wil->use_enhanced_dma_hw) + wil6210_mask_irq_tx_edma(wil); wil6210_mask_irq_rx(wil); - wil6210_mask_irq_rx_edma(wil); + if (wil->use_enhanced_dma_hw) + wil6210_mask_irq_rx_edma(wil); wil6210_mask_irq_misc(wil, true); wil6210_mask_irq_pseudo(wil); } @@ -190,10 +192,12 @@ void wil_unmask_irq(struct wil6210_priv *wil) { wil_dbg_irq(wil, "unmask_irq\n"); - wil_w(wil, RGF_DMA_EP_RX_ICR + offsetof(struct RGF_ICR, ICC), - WIL_ICR_ICC_VALUE); - wil_w(wil, RGF_DMA_EP_TX_ICR + offsetof(struct RGF_ICR, ICC), - WIL_ICR_ICC_VALUE); + if (wil->use_enhanced_dma_hw) { + wil_w(wil, RGF_DMA_EP_RX_ICR + offsetof(struct RGF_ICR, ICC), + WIL_ICR_ICC_VALUE); + wil_w(wil, RGF_DMA_EP_TX_ICR + offsetof(struct RGF_ICR, ICC), + WIL_ICR_ICC_VALUE); + } wil_w(wil, RGF_DMA_EP_MISC_ICR + offsetof(struct RGF_ICR, ICC), WIL_ICR_ICC_MISC_VALUE); wil_w(wil, RGF_INT_GEN_TX_ICR + offsetof(struct RGF_ICR, ICC), @@ -845,10 +849,12 @@ void wil6210_clear_irq(struct wil6210_priv *wil) offsetof(struct RGF_ICR, ICR)); wil_clear32(wil->csr + HOSTADDR(RGF_DMA_EP_TX_ICR) + offsetof(struct RGF_ICR, ICR)); - wil_clear32(wil->csr + HOSTADDR(RGF_INT_GEN_RX_ICR) + - offsetof(struct RGF_ICR, ICR)); - wil_clear32(wil->csr + HOSTADDR(RGF_INT_GEN_TX_ICR) + - offsetof(struct RGF_ICR, ICR)); + if (wil->use_enhanced_dma_hw) { + wil_clear32(wil->csr + HOSTADDR(RGF_INT_GEN_RX_ICR) + + offsetof(struct RGF_ICR, ICR)); + wil_clear32(wil->csr + HOSTADDR(RGF_INT_GEN_TX_ICR) + + offsetof(struct RGF_ICR, ICR)); + } wil_clear32(wil->csr + HOSTADDR(RGF_DMA_EP_MISC_ICR) + offsetof(struct RGF_ICR, ICR)); wmb(); /* make sure write completed */ diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c index 59884e8e376522e3172b7d08db95e45e69dfc62e..55c267ab2893b7c48579bb16cbe005440f61a2a8 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 e0de34a3e43a1ce736d9752e1aab594231b16a9d..69ef8cf203d24f1f2b268e19b908a6023cd62055 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 dc2383faddd1229bd46b092cc21e074ef47a808c..b94c3619526cfafa4c3decd22c8bf01694a9ff64 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 9f1854b3d1a58b9df6e528dd2380a3b1b347a479..8f97562811d7fcb9d705611327452e217461104d 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 93727b9a5f0d776bd9fa63beb275cc06be250da1..cf26ab15ee0c806b8e95eace86ce3a033526df98 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 dfcc12aa8620a76315b50160c0615043d6e0a079..243d0c5928a263e08f53d5e663cb44700691d7aa 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 df1b8ec8665145d47e73c44957ea3b9b9a713934..1826c37c090c91b39229a8b2021bd908a97b4ef4 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 dc8c408902e6a635c9f97285bf697067247d26b7..8e58e97a148f8ca0aae88f4b57041a3d3d5f5d6f 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 09fb4b758704a97148e875dcd196ce1cd0a18f46..9a86688aea67594001f3233cb22d2636537d606b 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 1d619384c629dd76468a6f6fa6aced8d8dcfbb33..dbfd45948e8b84383361aade29a4ca245264609c 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 98f0949b36835ae294faa90c2be870d10a413d06..96831ce8da6f16097704d8778190bf5e40c0b92e 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 5c8f6dc9a3e00e9f9d951644a8062ed8f01088da..5240dacf13607b25db96f8e0da838708845c935e 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 bda488ae9eec24567a3a53ac17925b7c7b16edf7..6b349270481d45dee07829f97bbc2181d89415c8 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 8ec4a007b4b07a43c395213405ebeb107324ebcc..5f67975989981379be437971aad7f743acddbd4c 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/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index 656f8b06c27b579b21e9db29dc0cde4721475eea..0a9e0dbb58fbf7826bc2599afe8b9efa51c7ac51 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -1501,11 +1501,27 @@ static int _iwl_pci_resume(struct device *device, bool restore) * Scratch value was altered, this means the device was powered off, we * need to reset it completely. * Note: MAC (bits 0:7) will be cleared upon suspend even with wowlan, - * so assume that any bits there mean that the device is usable. + * but not bits [15:8]. So if we have bits set in lower word, assume + * the device is alive. + * For older devices, just try silently to grab the NIC. */ - if (trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_BZ && - !iwl_read32(trans, CSR_FUNC_SCRATCH)) - device_was_powered_off = true; + if (trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_BZ) { + if (!(iwl_read32(trans, CSR_FUNC_SCRATCH) & + CSR_FUNC_SCRATCH_POWER_OFF_MASK)) + device_was_powered_off = true; + } else { + /* + * bh are re-enabled by iwl_trans_pcie_release_nic_access, + * so re-enable them if _iwl_trans_pcie_grab_nic_access fails. + */ + local_bh_disable(); + if (_iwl_trans_pcie_grab_nic_access(trans, true)) { + iwl_trans_pcie_release_nic_access(trans); + } else { + device_was_powered_off = true; + local_bh_enable(); + } + } if (restore || device_was_powered_off) { trans->state = IWL_TRANS_NO_FW; diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c index 7abd7c7daa89f61cb9dbe508c4084cdd75c77dd2..bb467e2b1779b52754f0cf83d03d7843e184c97d 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 ea3cc2eaec36cbebdaa2d4cbf253f7a9f854382d..b3c4040257a6708bba4bbb39db740a2590eab542 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 26d13e9b3c952da06dc28af2e49f8dcc360d432c..d44e02c6fe3852ca987543fad44dce6ec6d59e99 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 7c413dc81f9ac88fd9dd8e14a268dcb2b36a1859..5662a244f82a81d79f17b858134d6ef16c13e757 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 a57a11be57d86fd6a1f2b5c892ce2955900d3e0e..50c0f6179e2da28d9d22b8acaf44f76031bc599e 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.c b/drivers/net/wireless/marvell/mwifiex/11n.c index 738bafc3749b0ad874e8c7f4f3e67548ed76e199..66f0f5377ac1819463e1a7ff2938327e661b1e47 100644 --- a/drivers/net/wireless/marvell/mwifiex/11n.c +++ b/drivers/net/wireless/marvell/mwifiex/11n.c @@ -403,14 +403,12 @@ mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv, if (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 && bss_desc->bcn_ht_oper->ht_param & - IEEE80211_HT_PARAM_CHAN_WIDTH_ANY) { - chan_list->chan_scan_param[0].radio_type |= - CHAN_BW_40MHZ << 2; + IEEE80211_HT_PARAM_CHAN_WIDTH_ANY) SET_SECONDARYCHAN(chan_list->chan_scan_param[0]. radio_type, (bss_desc->bcn_ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET)); - } + *buffer += struct_size(chan_list, chan_scan_param, 1); ret_len += struct_size(chan_list, chan_scan_param, 1); } diff --git a/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c b/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c index 8aff1df09b40db1818b23e419bb20003bb0ee10b..354c5ce66045503cb4c60697d6206bfb887785ec 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 3bf27efe4537027c338779c728ad7429b7e76a0c..0f466c31337fa929489261a1c27b69069dd0f705 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 32c374e4779436f1ca95561ed963b8086b1ddbb5..4820010a86f6b1833c2886bcd27cd674700e3409 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 18e8c04d14c4eda45fbf70856d47d10506e2703e..77a9a6de636d1f748cfa859de8bf373bee0a5054 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 2f565397cf3622f5ee841f1619c66157db28b1a9..947ecb0a7b4050b759301edc9facac9118ab2f9d 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 c54005df08ca0669b0efd630b2ddd19e8b1db82a..8a37fb37f77d2488b78ffeb7b3f2c8c03702c646 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 38dd58f6e49321ad3a40d5d338ee9e715e39101a..a50c1723ca290e001bf31ed1f081684a2ca1b82c 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 cb46a39ef7579692670521f8aa2d9b30c41ec75f..a229c6cab3322decd1c698bc16ef2fe983660c0a 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 c2a1234b59db6c1c9e65a1f1594bc43a40edbd1a..d8b0b79dea1ac47eeea5d2073bb9fe63ed821e69 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 6189edc1d8d77b0276dc62ad2c4a0e1b29b0a06e..e26feb8de6589a9d143560800dd9896fcbacd906 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 5a34894a533bee1a1868882aad12a0e062a36b13..f749d19ec5f56b6c906a37ee0ce436a44b0b0f37 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 27f6c35ba0f9fdabe0286d68a334a8da02cb34f3..d122f1eb345e5699028a9cfc1225f30634c49d38 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 6ed470dd6f221ad58854017bac0701f2ce096a3e..2ab440cb2d67bbb689c43f6dc50582e96fafdd82 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 53827657abb20d20c9ab36af3cdcf1c58c3873ec..7d26314a3e76a87d75efa527bb49d6f202f095ad 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 9db08200f4fa13e37344f1d0f6301da3c52c0435..0e115b428f96f1e9a71d2d3cf8cc5c72de5033ff 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 4fd76183c368b5cdf739c8d5e928895a4b1ddc0c..a933e2c7dc2c0ab8b7222f3aca25824ab1a9be08 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 444272caf124cd5e533f60f2b37721732411c1f0..5dd7f6a389006db4f15ec8c2b757ee9b5487e12d 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 ea9bc4717a85e470173b8a045e236200adbdb67a..f93c95edd9915e0c8f83a61065911806f9961e56 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 5836995d6774bc3c9e810bf5c14492f8df248b3f..c759ebc564570276fa23b896e0136e218556295d 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 5091e1fa4a0df63358c93c0a18bbba62bd097d3a..9bac50963477f1ce3fd36e9c2a062394a3ad4a6d 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 43ce0c9b23550dfc1f02af777fbf9dd1c92995ff..a9b03dcc410067ace4a4537d7882465ff7310d0c 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 34c40d10e2602aee3fe0041e5db31b3e31032789..14661249c690281a406d8ae0fa7f3382bf55316f 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 580c9193e4a79b02210558349ee976789bac1c49..a081bce61c29f6c159eb1b5ab604d88f4c487a85 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 8feac119a4bcba7d710b11da013d349b118cb20c..be4808859cfa9fffa5d9cac4e617e54d901102e1 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 8cfe5405bae626987a9809a7b4e60f7e961217fd..607ec768eb7b4cf51d1af0a6ef29dc5ccf7e454d 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 9a50f3c03bd461733e1b06b3e045ab699fd15942..7154bc1d644ae9ea60318b02ed63b8bcbb516bf9 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 3b6d759bcdf26cd6416680bb38d68f6b0d4144d5..91e273b89fea3860f521aaa4127eb23f7f09bc60 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 7dca58f0a237bc91a1ec04d66c5856b668a2b997..31974c7dd20c9174961eac91e3823e939d325daa 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 2b9e6cfaf2a80ab86e7a537e04570d6c81841a6d..1a0058be5821044c9b98d2bcae0c1ad0ed4589ec 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 f69a232a000ac8125788db29f9dd50fdc442c412..92697f98c601d4b89a1681bdfa1adca45e86af4a 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 93e9041b9657eb9de836a60ba5bf0c28a351cb44..2e58a7ce109052ecdda433f13162911459a81fb3 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 9cf5b020adba27b73535590ed159c594a02e107a..1b58ee7d0dcee420a1cf7d1a4b8e7e558b69ecae 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 fdafa3e9e66fa9b8954209efa14d3b207cb8653c..014b387f1e8b1f1df1b9fcaaaf3fbff879abb564 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 ca86d3bf7ea49d0ec812640a6c0267a5aad40b79..0b50da2f1175316950af37fd7cf3c89594107474 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 878ea8b1a0acf72cca9b4aa5006e6a2181adbd72..e040e467f9fa08dcd344a842ea83549df09cce1d 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 ad0c1f834f09eb72ce58ed15244e11034c759a6b..a468cdc5b5cb7b97346559b8610e86d8454d29b3 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 e0bfe04a2bc2a7eda6002299263a74824b5fa6f4..8ff12e415cb5d1529d760b33f3e0cf3b8d1555f1 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 cf2d2c5039ddbf411d1515c6c3687d5f3c681695..ca6a74607b139795687217e3827beaf761f62057 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 b5a0295b5bf457628812401e5c6d509f776f70d6..9bd3646568d03c23d02cb9096d05479aaf3f8f37 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 f6379aa33d77fa1a5a00ed489d563e8bf17f450d..d924008c39491fb109a3e529c79e6fec23dd34e7 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 c7317299078d3a173aed19b28b37570b5575c6ac..3e378153a78174a10d3dc9bb6e17b5074faf146b 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 db7b17d1094e8b4ceb19d81c3ef380f343fb6f0f..175c5b6d4dd587f92b36d522f9e579c943b246dd 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 254537b93e633cea9746101d9c2389bf08fffcab..25598a46bf0d66789d4ce38869400b2885059281 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 83be0657e6df4ebc2ed6e30c451ad47229c30e0e..eba42df2f8215e41277102a922d2a67a72243f1e 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 26e2907ce8bb09b6a50848eb345ca76e76ecc3b3..b7515c53829b89d960ce182f7b09bbdfad89d627 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 3de07ef524906ad24a89e58abdfe93529a83c80f..d370b2ad11e7eb3a3549a75edaada2d84c1e8dd7 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 a9d03cfbbd27e68d40f8c330e72e20378b12a481..2021d59688dbd58ee6895d36610fe670d9479ef5 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 0000000000000000000000000000000000000000..88614005d5ce1dc2d1cafcb89ac66d8376ffcc96 --- /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 +#include +#include +#include +#include +#include + +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 "); +MODULE_DESCRIPTION("Apple SPMI NVMEM driver"); diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index e206efc29a0044739f9d56e1b131af2809365201..fd2a9698d1c93ee52a4d86f6e0a19d2dfb6efb54 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) @@ -2151,32 +2109,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 * diff --git a/drivers/nvmem/zynqmp_nvmem.c b/drivers/nvmem/zynqmp_nvmem.c index 8682adaacd692dd14d03b451ab24c5f43a8ce922..7da717d6c7faf3536c0a4e31ba9d3f21ea0ab577 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 474515d27e9c38fd9bde115219fbe403f4235d5b..4035010249cd599634d204e473f76a0133362e17 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 20529d1a3c44a96d7494fab9ca3b4dc0ac3f79e2..760a5dec04316d2dc04b8e7b458cccc7575296ae 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 387b85585263d0017ad0f86d26258f9c58c0ecfb..183bf43510a10768a45657bc20ad9df9d2d4cb9d 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 d7ba8795d60f81622744c58f44db6dada5e8d7e9..c05152733993b8e3bc9551a10e2e31132e46b198 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 d6ce04054702008fe0055116c88f531ff4204978..6ede55a7c5e652c80b51b10e58f0290eb6556430 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 fc70b601e9424f5d1ad565135bce3cf897da93bd..0b420b319f50ffc6ee1230eb076218dd69c2f461 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 85874b7a9f36853028d187079eb1dbde9f9b758b..d3baed44464662cdc4f6c5c187a365adabddffab 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 3bdd939dd2f4a54808ddc2c554dbb7d455caf3c7..2530079d38f48fc503e2e1d754830001386de22b 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 f0ccf479f36e52232225eee65eb5b7a3f7b0ecf4..1b1dff56ec7b11f3e7acb6bc16f5d80bac46a94f 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 a0a2e7f18356c5f09e2551a33e30ebf77c3c36b7..6868b60fd3258bd5002b1add0e8ce9501528f88b 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 d361124db9931765e240f5bc1f5d5d5a92220feb..87aa3f6671170b33e14695d2032ffad2a6a80a88 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 020ea86c24ec9b86186e07f10c3364fb559b1490..923ed23570a0ca11d0b074697c9dd4d9af3721e8 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/pinctrl/pinctrl-st.c b/drivers/pinctrl/pinctrl-st.c index fe2d52e434db8cdc03d61ef3f4df95cbcc9c513e..8a2ef74862d34a67889370f3aceaa697addabc28 100644 --- a/drivers/pinctrl/pinctrl-st.c +++ b/drivers/pinctrl/pinctrl-st.c @@ -374,11 +374,6 @@ static struct st_pio_control *st_get_pio_control( } /* Low level functions.. */ -static inline int st_gpio_bank(int gpio) -{ - return gpio/ST_GPIO_PINS_PER_BANK; -} - static inline int st_gpio_pin(int gpio) { return gpio%ST_GPIO_PINS_PER_BANK; diff --git a/drivers/pinctrl/pinctrl-tb10x.c b/drivers/pinctrl/pinctrl-tb10x.c index d6bb8f58978df1577db24f96c2174f47962b5520..4edb20e619510b2f52c7cde41c2540328ec4e95d 100644 --- a/drivers/pinctrl/pinctrl-tb10x.c +++ b/drivers/pinctrl/pinctrl-tb10x.c @@ -823,7 +823,7 @@ static struct platform_driver tb10x_pinctrl_pdrv = { .remove = tb10x_pinctrl_remove, .driver = { .name = "tb10x_pinctrl", - .of_match_table = of_match_ptr(tb10x_pinctrl_dt_ids), + .of_match_table = tb10x_pinctrl_dt_ids, } }; diff --git a/drivers/pinctrl/qcom/pinctrl-apq8064.c b/drivers/pinctrl/qcom/pinctrl-apq8064.c index 20c3b9025044515477f39bc25f0202dcca561743..3654913f1ae584394f5d08305f49e72a9b49fe5a 100644 --- a/drivers/pinctrl/qcom/pinctrl-apq8064.c +++ b/drivers/pinctrl/qcom/pinctrl-apq8064.c @@ -629,7 +629,6 @@ static struct platform_driver apq8064_pinctrl_driver = { .of_match_table = apq8064_pinctrl_of_match, }, .probe = apq8064_pinctrl_probe, - .remove = msm_pinctrl_remove, }; static int __init apq8064_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-apq8084.c b/drivers/pinctrl/qcom/pinctrl-apq8084.c index 3fc0a40762b631ad3dc15c9a7624ab705f367e74..27693cd648818bbcf6236cffad2efcd31c92018b 100644 --- a/drivers/pinctrl/qcom/pinctrl-apq8084.c +++ b/drivers/pinctrl/qcom/pinctrl-apq8084.c @@ -1207,7 +1207,6 @@ static struct platform_driver apq8084_pinctrl_driver = { .of_match_table = apq8084_pinctrl_of_match, }, .probe = apq8084_pinctrl_probe, - .remove = msm_pinctrl_remove, }; static int __init apq8084_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-ipq4019.c b/drivers/pinctrl/qcom/pinctrl-ipq4019.c index 1f7944dd829d1b9cb8c445ee075e0e29a12294b9..6ede3149b6e1730ea432a1636152abcbf0fa73b2 100644 --- a/drivers/pinctrl/qcom/pinctrl-ipq4019.c +++ b/drivers/pinctrl/qcom/pinctrl-ipq4019.c @@ -710,7 +710,6 @@ static struct platform_driver ipq4019_pinctrl_driver = { .of_match_table = ipq4019_pinctrl_of_match, }, .probe = ipq4019_pinctrl_probe, - .remove = msm_pinctrl_remove, }; static int __init ipq4019_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-ipq5018.c b/drivers/pinctrl/qcom/pinctrl-ipq5018.c index e2951f81c3eeb3f4d52c3941ab6f591da0254a23..10b99d5d8a11db644e974a80b9d7d04ffc09bd4c 100644 --- a/drivers/pinctrl/qcom/pinctrl-ipq5018.c +++ b/drivers/pinctrl/qcom/pinctrl-ipq5018.c @@ -754,7 +754,6 @@ static struct platform_driver ipq5018_pinctrl_driver = { .of_match_table = ipq5018_pinctrl_of_match, }, .probe = ipq5018_pinctrl_probe, - .remove = msm_pinctrl_remove, }; static int __init ipq5018_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-ipq5332.c b/drivers/pinctrl/qcom/pinctrl-ipq5332.c index 625f8014051f6acf8e6f91d48d0406b8c2bd8caf..1ac2fc09c11923cd716495b16a7f4af5686ce398 100644 --- a/drivers/pinctrl/qcom/pinctrl-ipq5332.c +++ b/drivers/pinctrl/qcom/pinctrl-ipq5332.c @@ -834,7 +834,6 @@ static struct platform_driver ipq5332_pinctrl_driver = { .of_match_table = ipq5332_pinctrl_of_match, }, .probe = ipq5332_pinctrl_probe, - .remove = msm_pinctrl_remove, }; static int __init ipq5332_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-ipq5424.c b/drivers/pinctrl/qcom/pinctrl-ipq5424.c index 0d610b076da3bb7940c99cfaf4c69261f9509390..7ff1f8acc1a3a81037298464130fda59f329d53e 100644 --- a/drivers/pinctrl/qcom/pinctrl-ipq5424.c +++ b/drivers/pinctrl/qcom/pinctrl-ipq5424.c @@ -791,7 +791,6 @@ static struct platform_driver ipq5424_pinctrl_driver = { .of_match_table = ipq5424_pinctrl_of_match, }, .probe = ipq5424_pinctrl_probe, - .remove = msm_pinctrl_remove, }; static int __init ipq5424_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-ipq6018.c b/drivers/pinctrl/qcom/pinctrl-ipq6018.c index 0ad08647dbcdf0b1fa21a618310f150a1bde2fae..a4ba980252e187879947e7057004fa48815f2620 100644 --- a/drivers/pinctrl/qcom/pinctrl-ipq6018.c +++ b/drivers/pinctrl/qcom/pinctrl-ipq6018.c @@ -1080,7 +1080,6 @@ static struct platform_driver ipq6018_pinctrl_driver = { .of_match_table = ipq6018_pinctrl_of_match, }, .probe = ipq6018_pinctrl_probe, - .remove = msm_pinctrl_remove, }; static int __init ipq6018_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-ipq8064.c b/drivers/pinctrl/qcom/pinctrl-ipq8064.c index e2bb94e86aef6e0055860794a1c64649c722aebc..0a9e357e64c60d61a094000f167defc80503e649 100644 --- a/drivers/pinctrl/qcom/pinctrl-ipq8064.c +++ b/drivers/pinctrl/qcom/pinctrl-ipq8064.c @@ -631,7 +631,6 @@ static struct platform_driver ipq8064_pinctrl_driver = { .of_match_table = ipq8064_pinctrl_of_match, }, .probe = ipq8064_pinctrl_probe, - .remove = msm_pinctrl_remove, }; static int __init ipq8064_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-ipq8074.c b/drivers/pinctrl/qcom/pinctrl-ipq8074.c index 337f3a1c92c19285f16f59a79f3e2b20561ae19a..482f13282fc2be951032cbe6dc5100bf9129ea5f 100644 --- a/drivers/pinctrl/qcom/pinctrl-ipq8074.c +++ b/drivers/pinctrl/qcom/pinctrl-ipq8074.c @@ -1041,7 +1041,6 @@ static struct platform_driver ipq8074_pinctrl_driver = { .of_match_table = ipq8074_pinctrl_of_match, }, .probe = ipq8074_pinctrl_probe, - .remove = msm_pinctrl_remove, }; static int __init ipq8074_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-ipq9574.c b/drivers/pinctrl/qcom/pinctrl-ipq9574.c index e2491617b2364a64169297426351e723c37f030c..89c05d8eb55034dea3e1c7299ede6567c20e0159 100644 --- a/drivers/pinctrl/qcom/pinctrl-ipq9574.c +++ b/drivers/pinctrl/qcom/pinctrl-ipq9574.c @@ -799,7 +799,6 @@ static struct platform_driver ipq9574_pinctrl_driver = { .of_match_table = ipq9574_pinctrl_of_match, }, .probe = ipq9574_pinctrl_probe, - .remove = msm_pinctrl_remove, }; static int __init ipq9574_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-mdm9607.c b/drivers/pinctrl/qcom/pinctrl-mdm9607.c index e7cd3ef1cf3e815ae25aa9e0c6872fbbd2c8ac79..3e18ba124fede923f56eab1aec5aaf875f06e343 100644 --- a/drivers/pinctrl/qcom/pinctrl-mdm9607.c +++ b/drivers/pinctrl/qcom/pinctrl-mdm9607.c @@ -1059,7 +1059,6 @@ static struct platform_driver mdm9607_pinctrl_driver = { .of_match_table = mdm9607_pinctrl_of_match, }, .probe = mdm9607_pinctrl_probe, - .remove = msm_pinctrl_remove, }; static int __init mdm9607_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-mdm9615.c b/drivers/pinctrl/qcom/pinctrl-mdm9615.c index 0a2ae383d3d57bd4101efb7a2093b68b8920b426..bea1ca3d1b7f84c28c23af2a52cc464da44a90b0 100644 --- a/drivers/pinctrl/qcom/pinctrl-mdm9615.c +++ b/drivers/pinctrl/qcom/pinctrl-mdm9615.c @@ -446,7 +446,6 @@ static struct platform_driver mdm9615_pinctrl_driver = { .of_match_table = mdm9615_pinctrl_of_match, }, .probe = mdm9615_pinctrl_probe, - .remove = msm_pinctrl_remove, }; static int __init mdm9615_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c index f012ea88aa22ca3e184b05c39da9a1f7c2b3c74f..5c4687de1464a60355e6cb1e456b487ad368275a 100644 --- a/drivers/pinctrl/qcom/pinctrl-msm.c +++ b/drivers/pinctrl/qcom/pinctrl-msm.c @@ -1442,7 +1442,7 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl) girq->handler = handle_bad_irq; girq->parents[0] = pctrl->irq; - ret = gpiochip_add_data(&pctrl->chip, pctrl); + ret = devm_gpiochip_add_data(pctrl->dev, &pctrl->chip, pctrl); if (ret) { dev_err(pctrl->dev, "Failed register gpiochip\n"); return ret; @@ -1463,7 +1463,6 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl) dev_name(pctrl->dev), 0, 0, chip->ngpio); if (ret) { dev_err(pctrl->dev, "Failed to add pin range\n"); - gpiochip_remove(&pctrl->chip); return ret; } } @@ -1599,13 +1598,5 @@ int msm_pinctrl_probe(struct platform_device *pdev, } EXPORT_SYMBOL(msm_pinctrl_probe); -void msm_pinctrl_remove(struct platform_device *pdev) -{ - struct msm_pinctrl *pctrl = platform_get_drvdata(pdev); - - gpiochip_remove(&pctrl->chip); -} -EXPORT_SYMBOL(msm_pinctrl_remove); - MODULE_DESCRIPTION("Qualcomm Technologies, Inc. TLMM driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/pinctrl/qcom/pinctrl-msm.h b/drivers/pinctrl/qcom/pinctrl-msm.h index 63852ed702957b8111b364267af17737b7a582a1..d7dc0947bb161868c8f433dc2536719b8afc8bd8 100644 --- a/drivers/pinctrl/qcom/pinctrl-msm.h +++ b/drivers/pinctrl/qcom/pinctrl-msm.h @@ -171,6 +171,5 @@ extern const struct dev_pm_ops msm_pinctrl_dev_pm_ops; int msm_pinctrl_probe(struct platform_device *pdev, const struct msm_pinctrl_soc_data *soc_data); -void msm_pinctrl_remove(struct platform_device *pdev); #endif diff --git a/drivers/pinctrl/qcom/pinctrl-msm8226.c b/drivers/pinctrl/qcom/pinctrl-msm8226.c index 64fee70f1772c41f5d8e20deb270ed66cb20a151..f9a957347340813f87e58d3bcbea81faa9d6255e 100644 --- a/drivers/pinctrl/qcom/pinctrl-msm8226.c +++ b/drivers/pinctrl/qcom/pinctrl-msm8226.c @@ -654,7 +654,6 @@ static struct platform_driver msm8226_pinctrl_driver = { .of_match_table = msm8226_pinctrl_of_match, }, .probe = msm8226_pinctrl_probe, - .remove = msm_pinctrl_remove, }; static int __init msm8226_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-msm8660.c b/drivers/pinctrl/qcom/pinctrl-msm8660.c index 999a5f867eb5081232443a893773d73c8dc65d1b..4dbc19ffd80efcdab059a253904e1ffe95fd36f7 100644 --- a/drivers/pinctrl/qcom/pinctrl-msm8660.c +++ b/drivers/pinctrl/qcom/pinctrl-msm8660.c @@ -981,7 +981,6 @@ static struct platform_driver msm8660_pinctrl_driver = { .of_match_table = msm8660_pinctrl_of_match, }, .probe = msm8660_pinctrl_probe, - .remove = msm_pinctrl_remove, }; static int __init msm8660_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-msm8909.c b/drivers/pinctrl/qcom/pinctrl-msm8909.c index 756856d20d6b5f2d4e764ff32f2493de24ca677c..0aa4f77b774f45947ffade7d167dd25cc4da5297 100644 --- a/drivers/pinctrl/qcom/pinctrl-msm8909.c +++ b/drivers/pinctrl/qcom/pinctrl-msm8909.c @@ -929,7 +929,6 @@ static struct platform_driver msm8909_pinctrl_driver = { .of_match_table = msm8909_pinctrl_of_match, }, .probe = msm8909_pinctrl_probe, - .remove = msm_pinctrl_remove, }; static int __init msm8909_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-msm8916.c b/drivers/pinctrl/qcom/pinctrl-msm8916.c index cea5c54f92fec1829c5378a8441eb8710fd500f0..0dfc6dd33d58b2d9df7a5cc3f7ff8890976207d3 100644 --- a/drivers/pinctrl/qcom/pinctrl-msm8916.c +++ b/drivers/pinctrl/qcom/pinctrl-msm8916.c @@ -969,7 +969,6 @@ static struct platform_driver msm8916_pinctrl_driver = { .of_match_table = msm8916_pinctrl_of_match, }, .probe = msm8916_pinctrl_probe, - .remove = msm_pinctrl_remove, }; static int __init msm8916_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-msm8917.c b/drivers/pinctrl/qcom/pinctrl-msm8917.c index 350636807b07d9ab0e207368de63837bc5fa5502..2e1a94ab18b219f818c591ff3b07280578822d1a 100644 --- a/drivers/pinctrl/qcom/pinctrl-msm8917.c +++ b/drivers/pinctrl/qcom/pinctrl-msm8917.c @@ -1607,7 +1607,6 @@ static struct platform_driver msm8917_pinctrl_driver = { .of_match_table = msm8917_pinctrl_of_match, }, .probe = msm8917_pinctrl_probe, - .remove = msm_pinctrl_remove, }; static int __init msm8917_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-msm8953.c b/drivers/pinctrl/qcom/pinctrl-msm8953.c index 998351bdfee1369fe0f369648d66a1a05493c8fb..956383341a7a777edf28c710353dc6deab124ef9 100644 --- a/drivers/pinctrl/qcom/pinctrl-msm8953.c +++ b/drivers/pinctrl/qcom/pinctrl-msm8953.c @@ -1816,7 +1816,6 @@ static struct platform_driver msm8953_pinctrl_driver = { .of_match_table = msm8953_pinctrl_of_match, }, .probe = msm8953_pinctrl_probe, - .remove = msm_pinctrl_remove, }; static int __init msm8953_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-msm8960.c b/drivers/pinctrl/qcom/pinctrl-msm8960.c index ebe230b3b437ccc63535fdf51639e64a67fe05eb..a937ea867de709326a2aea77f980cae1d8480f35 100644 --- a/drivers/pinctrl/qcom/pinctrl-msm8960.c +++ b/drivers/pinctrl/qcom/pinctrl-msm8960.c @@ -1246,7 +1246,6 @@ static struct platform_driver msm8960_pinctrl_driver = { .of_match_table = msm8960_pinctrl_of_match, }, .probe = msm8960_pinctrl_probe, - .remove = msm_pinctrl_remove, }; static int __init msm8960_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-msm8976.c b/drivers/pinctrl/qcom/pinctrl-msm8976.c index c30d80e4e98ca68ccede66001445967a47d6ec8f..3bcb03387781f803bf7e0251496a88a43b562b8d 100644 --- a/drivers/pinctrl/qcom/pinctrl-msm8976.c +++ b/drivers/pinctrl/qcom/pinctrl-msm8976.c @@ -1096,7 +1096,6 @@ static struct platform_driver msm8976_pinctrl_driver = { .of_match_table = msm8976_pinctrl_of_match, }, .probe = msm8976_pinctrl_probe, - .remove = msm_pinctrl_remove, }; static int __init msm8976_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-msm8994.c b/drivers/pinctrl/qcom/pinctrl-msm8994.c index b1a6759ab4a5e70501aba4325e80db2359251204..7a3b6cbccb687c8b5040ee6bf372f092f21aa872 100644 --- a/drivers/pinctrl/qcom/pinctrl-msm8994.c +++ b/drivers/pinctrl/qcom/pinctrl-msm8994.c @@ -1343,7 +1343,6 @@ static struct platform_driver msm8994_pinctrl_driver = { .of_match_table = msm8994_pinctrl_of_match, }, .probe = msm8994_pinctrl_probe, - .remove = msm_pinctrl_remove, }; static int __init msm8994_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-msm8996.c b/drivers/pinctrl/qcom/pinctrl-msm8996.c index 1b5d80eaab83c7e2c81c96019e8b0cc6f5461c69..d86d83106d3ba12343a4685e5b87c661f823c35b 100644 --- a/drivers/pinctrl/qcom/pinctrl-msm8996.c +++ b/drivers/pinctrl/qcom/pinctrl-msm8996.c @@ -1920,7 +1920,6 @@ static struct platform_driver msm8996_pinctrl_driver = { .of_match_table = msm8996_pinctrl_of_match, }, .probe = msm8996_pinctrl_probe, - .remove = msm_pinctrl_remove, }; static int __init msm8996_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-msm8998.c b/drivers/pinctrl/qcom/pinctrl-msm8998.c index b7cbf32b3125a91081c6644cd3d343e08499dd1f..1daee815888f54b711505dfacefd614df83affc0 100644 --- a/drivers/pinctrl/qcom/pinctrl-msm8998.c +++ b/drivers/pinctrl/qcom/pinctrl-msm8998.c @@ -1535,7 +1535,6 @@ static struct platform_driver msm8998_pinctrl_driver = { .of_match_table = msm8998_pinctrl_of_match, }, .probe = msm8998_pinctrl_probe, - .remove = msm_pinctrl_remove, }; static int __init msm8998_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-msm8x74.c b/drivers/pinctrl/qcom/pinctrl-msm8x74.c index 238c83f6ec4f41ff2dc572fd910c1c9aef9d290a..8253aa25775b247dc54a377c9781094e465e22b6 100644 --- a/drivers/pinctrl/qcom/pinctrl-msm8x74.c +++ b/drivers/pinctrl/qcom/pinctrl-msm8x74.c @@ -1083,7 +1083,6 @@ static struct platform_driver msm8x74_pinctrl_driver = { .of_match_table = msm8x74_pinctrl_of_match, }, .probe = msm8x74_pinctrl_probe, - .remove = msm_pinctrl_remove, }; static int __init msm8x74_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-qcm2290.c b/drivers/pinctrl/qcom/pinctrl-qcm2290.c index f885af571ec93d66533f4909e935e5c7a2dd0511..eeeec6434f6a68a588ff58641b7c25c261b5749a 100644 --- a/drivers/pinctrl/qcom/pinctrl-qcm2290.c +++ b/drivers/pinctrl/qcom/pinctrl-qcm2290.c @@ -167,6 +167,10 @@ static const struct pinctrl_pin_desc qcm2290_pins[] = { PINCTRL_PIN(62, "GPIO_62"), PINCTRL_PIN(63, "GPIO_63"), PINCTRL_PIN(64, "GPIO_64"), + PINCTRL_PIN(65, "GPIO_65"), + PINCTRL_PIN(66, "GPIO_66"), + PINCTRL_PIN(67, "GPIO_67"), + PINCTRL_PIN(68, "GPIO_68"), PINCTRL_PIN(69, "GPIO_69"), PINCTRL_PIN(70, "GPIO_70"), PINCTRL_PIN(71, "GPIO_71"), @@ -181,12 +185,17 @@ static const struct pinctrl_pin_desc qcm2290_pins[] = { PINCTRL_PIN(80, "GPIO_80"), PINCTRL_PIN(81, "GPIO_81"), PINCTRL_PIN(82, "GPIO_82"), + PINCTRL_PIN(83, "GPIO_83"), + PINCTRL_PIN(84, "GPIO_84"), + PINCTRL_PIN(85, "GPIO_85"), PINCTRL_PIN(86, "GPIO_86"), PINCTRL_PIN(87, "GPIO_87"), PINCTRL_PIN(88, "GPIO_88"), PINCTRL_PIN(89, "GPIO_89"), PINCTRL_PIN(90, "GPIO_90"), PINCTRL_PIN(91, "GPIO_91"), + PINCTRL_PIN(92, "GPIO_92"), + PINCTRL_PIN(93, "GPIO_93"), PINCTRL_PIN(94, "GPIO_94"), PINCTRL_PIN(95, "GPIO_95"), PINCTRL_PIN(96, "GPIO_96"), @@ -1125,7 +1134,6 @@ static struct platform_driver qcm2290_pinctrl_driver = { .of_match_table = qcm2290_pinctrl_of_match, }, .probe = qcm2290_pinctrl_probe, - .remove = msm_pinctrl_remove, }; static int __init qcm2290_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-qcs404.c b/drivers/pinctrl/qcom/pinctrl-qcs404.c index ae7224012f8aa00a41350b3ce670511aa8ce18bd..54e3b44353494e9398a88702945b7a85ff901b4d 100644 --- a/drivers/pinctrl/qcom/pinctrl-qcs404.c +++ b/drivers/pinctrl/qcom/pinctrl-qcs404.c @@ -1644,7 +1644,6 @@ static struct platform_driver qcs404_pinctrl_driver = { .of_match_table = qcs404_pinctrl_of_match, }, .probe = qcs404_pinctrl_probe, - .remove = msm_pinctrl_remove, }; static int __init qcs404_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-qcs615.c b/drivers/pinctrl/qcom/pinctrl-qcs615.c index 17ca743c2210fc2d8fc52b8f06912325ff82d63b..2a943bc46a6299899abd87523f24e7e291f24c57 100644 --- a/drivers/pinctrl/qcom/pinctrl-qcs615.c +++ b/drivers/pinctrl/qcom/pinctrl-qcs615.c @@ -1087,7 +1087,6 @@ static struct platform_driver qcs615_tlmm_driver = { .of_match_table = qcs615_tlmm_of_match, }, .probe = qcs615_tlmm_probe, - .remove = msm_pinctrl_remove, }; static int __init qcs615_tlmm_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-qcs8300.c b/drivers/pinctrl/qcom/pinctrl-qcs8300.c index 5f5f7c4ac644c4d80b87b4384b0a40ba90fadf04..d6437e26392b60f5d345f2591e98516a9d933a0f 100644 --- a/drivers/pinctrl/qcom/pinctrl-qcs8300.c +++ b/drivers/pinctrl/qcom/pinctrl-qcs8300.c @@ -1227,7 +1227,6 @@ static struct platform_driver qcs8300_pinctrl_driver = { .of_match_table = qcs8300_pinctrl_of_match, }, .probe = qcs8300_pinctrl_probe, - .remove = msm_pinctrl_remove, }; static int __init qcs8300_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-qdf2xxx.c b/drivers/pinctrl/qcom/pinctrl-qdf2xxx.c index b5808fcfb13cdebd04c0c71b24043b924094a683..9ecc4d40e4dc4f36aafc70309102b9e66ce024c0 100644 --- a/drivers/pinctrl/qcom/pinctrl-qdf2xxx.c +++ b/drivers/pinctrl/qcom/pinctrl-qdf2xxx.c @@ -145,7 +145,6 @@ static struct platform_driver qdf2xxx_pinctrl_driver = { .acpi_match_table = qdf2xxx_acpi_ids, }, .probe = qdf2xxx_pinctrl_probe, - .remove = msm_pinctrl_remove, }; static int __init qdf2xxx_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-qdu1000.c b/drivers/pinctrl/qcom/pinctrl-qdu1000.c index 47bc529ef550d2ab9a13341295eacc08faed24c4..eacb89fa388850ef39ceb50497df9e5cca54191c 100644 --- a/drivers/pinctrl/qcom/pinctrl-qdu1000.c +++ b/drivers/pinctrl/qcom/pinctrl-qdu1000.c @@ -1248,7 +1248,6 @@ static struct platform_driver qdu1000_tlmm_driver = { .of_match_table = qdu1000_tlmm_of_match, }, .probe = qdu1000_tlmm_probe, - .remove = msm_pinctrl_remove, }; static int __init qdu1000_tlmm_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-sa8775p.c b/drivers/pinctrl/qcom/pinctrl-sa8775p.c index a5b38221aea851ce09448eb7eb71f7f94721443a..1b62eb3e6620c978225c5fd2ab541451cbe93093 100644 --- a/drivers/pinctrl/qcom/pinctrl-sa8775p.c +++ b/drivers/pinctrl/qcom/pinctrl-sa8775p.c @@ -1540,7 +1540,6 @@ static struct platform_driver sa8775p_pinctrl_driver = { .of_match_table = sa8775p_pinctrl_of_match, }, .probe = sa8775p_pinctrl_probe, - .remove = msm_pinctrl_remove, }; static int __init sa8775p_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-sar2130p.c b/drivers/pinctrl/qcom/pinctrl-sar2130p.c index 19a2e37826c7b25f6d37f130a0fb5ef4cdadb61c..3dd1b5e5cfee489ec34b16ee2ae1c8d2c2756553 100644 --- a/drivers/pinctrl/qcom/pinctrl-sar2130p.c +++ b/drivers/pinctrl/qcom/pinctrl-sar2130p.c @@ -1486,7 +1486,6 @@ static struct platform_driver sar2130p_tlmm_driver = { .of_match_table = sar2130p_tlmm_of_match, }, .probe = sar2130p_tlmm_probe, - .remove = msm_pinctrl_remove, }; static int __init sar2130p_tlmm_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-sc7180.c b/drivers/pinctrl/qcom/pinctrl-sc7180.c index 6eb0c73791c0bc9883bf0b740b8930fe7c7fced0..c43fe10b71add7d6294c90e86578ed472b8759a3 100644 --- a/drivers/pinctrl/qcom/pinctrl-sc7180.c +++ b/drivers/pinctrl/qcom/pinctrl-sc7180.c @@ -1159,7 +1159,6 @@ static struct platform_driver sc7180_pinctrl_driver = { .of_match_table = sc7180_pinctrl_of_match, }, .probe = sc7180_pinctrl_probe, - .remove = msm_pinctrl_remove, }; static int __init sc7180_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-sc7280.c b/drivers/pinctrl/qcom/pinctrl-sc7280.c index 0c10eeb60b55e742a73dfd43d647f7009471b1b0..1b070e9d41f5972470d245edb821d202ca24522b 100644 --- a/drivers/pinctrl/qcom/pinctrl-sc7280.c +++ b/drivers/pinctrl/qcom/pinctrl-sc7280.c @@ -1505,7 +1505,6 @@ static struct platform_driver sc7280_pinctrl_driver = { .of_match_table = sc7280_pinctrl_of_match, }, .probe = sc7280_pinctrl_probe, - .remove = msm_pinctrl_remove, }; static int __init sc7280_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-sc8180x.c b/drivers/pinctrl/qcom/pinctrl-sc8180x.c index d6a79ad41a40a804c503d97a6279db4b533f0047..26dd165d154348a8659720335ec16c3e5ace30ef 100644 --- a/drivers/pinctrl/qcom/pinctrl-sc8180x.c +++ b/drivers/pinctrl/qcom/pinctrl-sc8180x.c @@ -1720,7 +1720,6 @@ static struct platform_driver sc8180x_pinctrl_driver = { .acpi_match_table = sc8180x_pinctrl_acpi_match, }, .probe = sc8180x_pinctrl_probe, - .remove = msm_pinctrl_remove, }; static int __init sc8180x_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-sc8280xp.c b/drivers/pinctrl/qcom/pinctrl-sc8280xp.c index 96f4fb5a5d297f784e63f4335e294ebdee5f487f..6ccd7e5648d420072f7ce467d92ef0764a6d7764 100644 --- a/drivers/pinctrl/qcom/pinctrl-sc8280xp.c +++ b/drivers/pinctrl/qcom/pinctrl-sc8280xp.c @@ -1926,7 +1926,6 @@ static struct platform_driver sc8280xp_pinctrl_driver = { .of_match_table = sc8280xp_pinctrl_of_match, }, .probe = sc8280xp_pinctrl_probe, - .remove = msm_pinctrl_remove, }; static int __init sc8280xp_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-sdm660.c b/drivers/pinctrl/qcom/pinctrl-sdm660.c index 907e4ffca5e7df48aed8f917455f35c0da8c6265..1a78288f1bc832837d5c72d9eb1659f397d79b94 100644 --- a/drivers/pinctrl/qcom/pinctrl-sdm660.c +++ b/drivers/pinctrl/qcom/pinctrl-sdm660.c @@ -1442,7 +1442,6 @@ static struct platform_driver sdm660_pinctrl_driver = { .of_match_table = sdm660_pinctrl_of_match, }, .probe = sdm660_pinctrl_probe, - .remove = msm_pinctrl_remove, }; static int __init sdm660_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-sdm670.c b/drivers/pinctrl/qcom/pinctrl-sdm670.c index c76183ba95e17473d1ed313090e8cc3546431348..0fe1fa94cd6da13591397442a63ce8daec9f4674 100644 --- a/drivers/pinctrl/qcom/pinctrl-sdm670.c +++ b/drivers/pinctrl/qcom/pinctrl-sdm670.c @@ -1337,7 +1337,6 @@ static struct platform_driver sdm670_pinctrl_driver = { .of_match_table = sdm670_pinctrl_of_match, }, .probe = sdm670_pinctrl_probe, - .remove = msm_pinctrl_remove, }; static int __init sdm670_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-sdm845.c b/drivers/pinctrl/qcom/pinctrl-sdm845.c index cc05c415ed15512f1f99a598650d3adfdc795a6d..0446e291aa4831da439af12b7934fbda5915ee5a 100644 --- a/drivers/pinctrl/qcom/pinctrl-sdm845.c +++ b/drivers/pinctrl/qcom/pinctrl-sdm845.c @@ -1351,7 +1351,6 @@ static struct platform_driver sdm845_pinctrl_driver = { .acpi_match_table = ACPI_PTR(sdm845_pinctrl_acpi_match), }, .probe = sdm845_pinctrl_probe, - .remove = msm_pinctrl_remove, }; static int __init sdm845_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-sdx55.c b/drivers/pinctrl/qcom/pinctrl-sdx55.c index 8826db9d21d04cecca844b0607984e21a500f15b..2c17bf889146362edf9f482d33b17d35a255882e 100644 --- a/drivers/pinctrl/qcom/pinctrl-sdx55.c +++ b/drivers/pinctrl/qcom/pinctrl-sdx55.c @@ -990,7 +990,6 @@ static struct platform_driver sdx55_pinctrl_driver = { .of_match_table = sdx55_pinctrl_of_match, }, .probe = sdx55_pinctrl_probe, - .remove = msm_pinctrl_remove, }; static int __init sdx55_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-sdx65.c b/drivers/pinctrl/qcom/pinctrl-sdx65.c index f6f319c997fc7a39d672872c0df1fa2ea821b2d9..85b5c0206dbd199c6efc15aad10784d20c1addde 100644 --- a/drivers/pinctrl/qcom/pinctrl-sdx65.c +++ b/drivers/pinctrl/qcom/pinctrl-sdx65.c @@ -939,7 +939,6 @@ static struct platform_driver sdx65_pinctrl_driver = { .of_match_table = sdx65_pinctrl_of_match, }, .probe = sdx65_pinctrl_probe, - .remove = msm_pinctrl_remove, }; static int __init sdx65_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-sdx75.c b/drivers/pinctrl/qcom/pinctrl-sdx75.c index 3cfe8c7f04df816a93252a162ccfa502854411fe..ab13a3a57a830781f35916ff508ca65d6699271d 100644 --- a/drivers/pinctrl/qcom/pinctrl-sdx75.c +++ b/drivers/pinctrl/qcom/pinctrl-sdx75.c @@ -1124,7 +1124,6 @@ static struct platform_driver sdx75_pinctrl_driver = { .of_match_table = sdx75_pinctrl_of_match, }, .probe = sdx75_pinctrl_probe, - .remove = msm_pinctrl_remove, }; static int __init sdx75_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-sm4450.c b/drivers/pinctrl/qcom/pinctrl-sm4450.c index 622f20e6f6f859ee4f132809304bc3f0685e8ff3..1ecdf1ab4f275ede7cb629321f9c37d3f81a25e9 100644 --- a/drivers/pinctrl/qcom/pinctrl-sm4450.c +++ b/drivers/pinctrl/qcom/pinctrl-sm4450.c @@ -994,7 +994,6 @@ static struct platform_driver sm4450_tlmm_driver = { .of_match_table = sm4450_tlmm_of_match, }, .probe = sm4450_tlmm_probe, - .remove = msm_pinctrl_remove, }; MODULE_DEVICE_TABLE(of, sm4450_tlmm_of_match); diff --git a/drivers/pinctrl/qcom/pinctrl-sm6115.c b/drivers/pinctrl/qcom/pinctrl-sm6115.c index 4e91c75ad952487e755e0abdf861b1f118bf4de5..c273efa4399630a2187845382e231fe150d997fd 100644 --- a/drivers/pinctrl/qcom/pinctrl-sm6115.c +++ b/drivers/pinctrl/qcom/pinctrl-sm6115.c @@ -907,7 +907,6 @@ static struct platform_driver sm6115_tlmm_driver = { .of_match_table = sm6115_tlmm_of_match, }, .probe = sm6115_tlmm_probe, - .remove = msm_pinctrl_remove, }; static int __init sm6115_tlmm_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-sm6125.c b/drivers/pinctrl/qcom/pinctrl-sm6125.c index c188842047aae054929e124f650290034cfad979..5092f20e0c1bdee2e99b768f12cfbec31972c24c 100644 --- a/drivers/pinctrl/qcom/pinctrl-sm6125.c +++ b/drivers/pinctrl/qcom/pinctrl-sm6125.c @@ -1266,7 +1266,6 @@ static struct platform_driver sm6125_tlmm_driver = { .of_match_table = sm6125_tlmm_of_match, }, .probe = sm6125_tlmm_probe, - .remove = msm_pinctrl_remove, }; static int __init sm6125_tlmm_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-sm6350.c b/drivers/pinctrl/qcom/pinctrl-sm6350.c index f3828c07b134500e4307db1d42aabae389a03360..ba4686c86c54b8c1dc32522c83587521e149a5ae 100644 --- a/drivers/pinctrl/qcom/pinctrl-sm6350.c +++ b/drivers/pinctrl/qcom/pinctrl-sm6350.c @@ -1373,7 +1373,6 @@ static struct platform_driver sm6350_tlmm_driver = { .of_match_table = sm6350_tlmm_of_match, }, .probe = sm6350_tlmm_probe, - .remove = msm_pinctrl_remove, }; static int __init sm6350_tlmm_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-sm6375.c b/drivers/pinctrl/qcom/pinctrl-sm6375.c index c82c8516932ea2e1880284fa86bdaf3683f024cc..49031571e65ee3291fb1e5269e071a08a77c87de 100644 --- a/drivers/pinctrl/qcom/pinctrl-sm6375.c +++ b/drivers/pinctrl/qcom/pinctrl-sm6375.c @@ -1516,7 +1516,6 @@ static struct platform_driver sm6375_tlmm_driver = { .of_match_table = sm6375_tlmm_of_match, }, .probe = sm6375_tlmm_probe, - .remove = msm_pinctrl_remove, }; static int __init sm6375_tlmm_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-sm7150.c b/drivers/pinctrl/qcom/pinctrl-sm7150.c index 3c7fd8af6635b94df107f44e3e0e68a2778a25e7..6e89966cd70e34bcb74cfb50e80e110e40655b0e 100644 --- a/drivers/pinctrl/qcom/pinctrl-sm7150.c +++ b/drivers/pinctrl/qcom/pinctrl-sm7150.c @@ -1255,7 +1255,6 @@ static struct platform_driver sm7150_tlmm_driver = { .of_match_table = sm7150_tlmm_of_match, }, .probe = sm7150_tlmm_probe, - .remove = msm_pinctrl_remove, }; static int __init sm7150_tlmm_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-sm8150.c b/drivers/pinctrl/qcom/pinctrl-sm8150.c index 01aea9c70b7a78168ee063f5ac88afc0d7290bcb..794ed99463f76032f56be9464a4aa3018537df94 100644 --- a/drivers/pinctrl/qcom/pinctrl-sm8150.c +++ b/drivers/pinctrl/qcom/pinctrl-sm8150.c @@ -1542,7 +1542,6 @@ static struct platform_driver sm8150_pinctrl_driver = { .of_match_table = sm8150_pinctrl_of_match, }, .probe = sm8150_pinctrl_probe, - .remove = msm_pinctrl_remove, }; static int __init sm8150_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-sm8250.c b/drivers/pinctrl/qcom/pinctrl-sm8250.c index e9961a49ff9811bfa3ed3c6c1a8f1cf90afa1d29..fb6f005d64f53f318d58e69681f07e36404439cf 100644 --- a/drivers/pinctrl/qcom/pinctrl-sm8250.c +++ b/drivers/pinctrl/qcom/pinctrl-sm8250.c @@ -1351,7 +1351,6 @@ static struct platform_driver sm8250_pinctrl_driver = { .of_match_table = sm8250_pinctrl_of_match, }, .probe = sm8250_pinctrl_probe, - .remove = msm_pinctrl_remove, }; static int __init sm8250_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-sm8350.c b/drivers/pinctrl/qcom/pinctrl-sm8350.c index 9c69458bd9109119e7a88d1a92f633bbf188ed0c..c8a3f39ce6f1b8565a783f04100269b3cadb9bcc 100644 --- a/drivers/pinctrl/qcom/pinctrl-sm8350.c +++ b/drivers/pinctrl/qcom/pinctrl-sm8350.c @@ -1642,7 +1642,6 @@ static struct platform_driver sm8350_tlmm_driver = { .of_match_table = sm8350_tlmm_of_match, }, .probe = sm8350_tlmm_probe, - .remove = msm_pinctrl_remove, }; static int __init sm8350_tlmm_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-sm8450.c b/drivers/pinctrl/qcom/pinctrl-sm8450.c index d11bb1ee9e3d8dfbb1e810051d5c854a959b428b..f2e52d5a0f9369d21922d0651539908d592301e5 100644 --- a/drivers/pinctrl/qcom/pinctrl-sm8450.c +++ b/drivers/pinctrl/qcom/pinctrl-sm8450.c @@ -1677,7 +1677,6 @@ static struct platform_driver sm8450_tlmm_driver = { .of_match_table = sm8450_tlmm_of_match, }, .probe = sm8450_tlmm_probe, - .remove = msm_pinctrl_remove, }; static int __init sm8450_tlmm_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-sm8550.c b/drivers/pinctrl/qcom/pinctrl-sm8550.c index 3c847d9cb5d93bbc7bb5a9b0b2ee707e14de6387..1b4496cb39eb46b2b660ef213e1f3c8fdac2b21e 100644 --- a/drivers/pinctrl/qcom/pinctrl-sm8550.c +++ b/drivers/pinctrl/qcom/pinctrl-sm8550.c @@ -1762,7 +1762,6 @@ static struct platform_driver sm8550_tlmm_driver = { .of_match_table = sm8550_tlmm_of_match, }, .probe = sm8550_tlmm_probe, - .remove = msm_pinctrl_remove, }; static int __init sm8550_tlmm_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-sm8650.c b/drivers/pinctrl/qcom/pinctrl-sm8650.c index 104708252d12a82a887aa2bdaecf31d3308a102c..449a0077f4b10666ecd9dfaae8e0057a91e181a6 100644 --- a/drivers/pinctrl/qcom/pinctrl-sm8650.c +++ b/drivers/pinctrl/qcom/pinctrl-sm8650.c @@ -1742,7 +1742,6 @@ static struct platform_driver sm8650_tlmm_driver = { .of_match_table = sm8650_tlmm_of_match, }, .probe = sm8650_tlmm_probe, - .remove = msm_pinctrl_remove, }; static int __init sm8650_tlmm_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-sm8750.c b/drivers/pinctrl/qcom/pinctrl-sm8750.c index b94fb4ee0ec38013d8cde7e45a7d6088a20e3b28..8516693d1db51d3e890e298ea6500ae62333bc69 100644 --- a/drivers/pinctrl/qcom/pinctrl-sm8750.c +++ b/drivers/pinctrl/qcom/pinctrl-sm8750.c @@ -1711,7 +1711,6 @@ static struct platform_driver sm8750_tlmm_driver = { .of_match_table = sm8750_tlmm_of_match, }, .probe = sm8750_tlmm_probe, - .remove = msm_pinctrl_remove, }; static int __init sm8750_tlmm_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-x1e80100.c b/drivers/pinctrl/qcom/pinctrl-x1e80100.c index 419cb8facb2f3d261558593800a26694eddb4817..d4b215f34c39bf67a0656a3f894b8639491e898b 100644 --- a/drivers/pinctrl/qcom/pinctrl-x1e80100.c +++ b/drivers/pinctrl/qcom/pinctrl-x1e80100.c @@ -1861,7 +1861,6 @@ static struct platform_driver x1e80100_pinctrl_driver = { .of_match_table = x1e80100_pinctrl_of_match, }, .probe = x1e80100_pinctrl_probe, - .remove = msm_pinctrl_remove, }; static int __init x1e80100_pinctrl_init(void) diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi-dt.c b/drivers/pinctrl/sunxi/pinctrl-sunxi-dt.c index 1833078f68776ca0c4b9fe49e3f0fe9e6b385eb7..4e34b0cd3b73aad2ba99a9e87d83f5003c32a214 100644 --- a/drivers/pinctrl/sunxi/pinctrl-sunxi-dt.c +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi-dt.c @@ -143,7 +143,7 @@ static struct sunxi_desc_pin *init_pins_table(struct device *dev, */ static int prepare_function_table(struct device *dev, struct device_node *pnode, struct sunxi_desc_pin *pins, int npins, - const u8 *irq_bank_muxes) + unsigned pin_base, const u8 *irq_bank_muxes) { struct device_node *node; struct property *prop; @@ -166,7 +166,7 @@ static int prepare_function_table(struct device *dev, struct device_node *pnode, */ for (i = 0; i < npins; i++) { struct sunxi_desc_pin *pin = &pins[i]; - int bank = pin->pin.number / PINS_PER_BANK; + int bank = (pin->pin.number - pin_base) / PINS_PER_BANK; if (irq_bank_muxes[bank]) { pin->variant++; @@ -211,7 +211,7 @@ static int prepare_function_table(struct device *dev, struct device_node *pnode, last_bank = 0; for (i = 0; i < npins; i++) { struct sunxi_desc_pin *pin = &pins[i]; - int bank = pin->pin.number / PINS_PER_BANK; + int bank = (pin->pin.number - pin_base) / PINS_PER_BANK; int lastfunc = pin->variant + 1; int irq_mux = irq_bank_muxes[bank]; @@ -353,7 +353,7 @@ int sunxi_pinctrl_dt_table_init(struct platform_device *pdev, return PTR_ERR(pins); ret = prepare_function_table(&pdev->dev, pnode, pins, desc->npins, - irq_bank_muxes); + desc->pin_base, irq_bank_muxes); if (ret) return ret; diff --git a/drivers/platform/loongarch/loongson-laptop.c b/drivers/platform/loongarch/loongson-laptop.c index 99203584949daa2af9e5013c7a8ed7d64b60bf0f..61b18ac206c9ee4546450e59b6e35f208812221e 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 9506f28fb7d86e56ac7aa434267a959c950db37a..b1b2d9caba7b384647f61402769d6aed26c55e25 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 374ceefd6f2a405f5762aa10326f4c7ac419a140..47d9891de368bd78bfbd1aa73c9d737dbcbe1f78 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 ce804438c32d18572de220340aac4d5e2e495788..1e7f72e57557601be37702472716e43397991fd0 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/ptp/ptp_private.h b/drivers/ptp/ptp_private.h index 18934e28469ee6e3bf9c9e6d1a1adb82808d88e6..528d86a33f37dedea0852f04f940f7c61c45bd92 100644 --- a/drivers/ptp/ptp_private.h +++ b/drivers/ptp/ptp_private.h @@ -98,17 +98,7 @@ static inline int queue_cnt(const struct timestamp_event_queue *q) /* Check if ptp virtual clock is in use */ static inline bool ptp_vclock_in_use(struct ptp_clock *ptp) { - bool in_use = false; - - if (mutex_lock_interruptible(&ptp->n_vclocks_mux)) - return true; - - if (!ptp->is_virtual_clock && ptp->n_vclocks) - in_use = true; - - mutex_unlock(&ptp->n_vclocks_mux); - - return in_use; + return !ptp->is_virtual_clock; } /* Check if ptp clock shall be free running */ diff --git a/drivers/pwm/pwm-axi-pwmgen.c b/drivers/pwm/pwm-axi-pwmgen.c index 4337c8f5acf055fc87dc134f2a70b99b0cb5ede6..60dcd354237316bced2d951b7f0b116c8291bb0d 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 5e7171b9065ae7a2e82253ae3ac23ea99975fccc..41fd15adfd1fddef1c296cc1489300a758732381 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 0eeae5bcc3aa93596e08a6a5c7a2bd805c2f1e1d..baf1a8ca8b2b1ea806c56b06926a03975b3636a8 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 a9f5b9466fb5e2f9a2ee1c7019f48ac828b60bf7..94f995febe5b4b747927af503b967f80e479e750 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 cf36d3bafeca178cccb07b4f888bdd91aa5549ea..b16efecfde4b029f0438a4e3675ba5faf0de5445 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 6a61c0a595d9b314de87fa60444dd179735616a4..56e43d43c713bb0c19ba3938e67f41d806d135da 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 8402a0042c0d378e59f41ed2ec811b7e07605c8c..b78b86e8f2812bcceb5fe658c5166a43fd0cf5ba 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 48e8417a5cff634c82ad28595e4e3deb498ea050..fa063e84eafc15016f1470397aec384330e492c7 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 b760386328837dd06d9b68adac7fee8b29ba9d4b..7ff177406bc324dc2ad7b3886d83338708a7b688 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 e1b1fbdabb1b2dba5f3e4156730f96e39a64232c..e849d3271b0e55fe11487cfe31107da05b52ca7a 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 ac382355dc04e24114bb00563a1418e7a4083602..37ea30be710c0f753151c42e807ad0c9a79abc2a 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 288734cd8f4b953d7a523954212e37b4cd8c865b..bd95bd390b5c4d3d7cbf4f36b5c96f571f818192 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 5fcdce116862151716f4f2161cc74d981c1c64e9..6a12d2422540ccd7ff08f56e59e70f7659d8ca05 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 f5cfaebfb7c97801697f8e27f33de22c5e211864..fe9f48c315d9473d76f30c7930185a635cc1f179 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 78d52a4c55f526fb085ff9f0599da9e71a6b5aab..ffd9944169959170728e553b5c0dfc385c0200ee 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 d5f5f563881e41f7214d0e8c8963e9fd7dccbcb1..c5bba1be88f4ae58cae4c78455a922cee1f7c647 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 0957e3f8b46e90ae807ad7882fa540a4b3f04824..f2410bc44ad3f679bfbbe131e131faed9270a24e 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 8c384c25dca179d82e91a7892195c4f2a430787b..0a5888b53d6d33078e6808a4dcec4bcae3d41907 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 ffef61c4aa0159f38f6069c610116372d8adf0f3..7d9a4dce236bdfe6b020b8de7d86dd88743e05db 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 f9372a81cd4ea1f64ff8f40bbc12ddf54088787b..6b87ea004e5372e39ecd5e96274f6f9ee3e67271 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 68214a58b16015ea80436aa1daf5928ee76c7830..08c8dad9ad6215763ad7858ef390a4ddb5f19637 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 d45dbf98f25e9e1aa22ff6ccb1c01851a6210cda..28ac92b041fe3bee3efea10ed1ba6d984755e619 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 b450b1fc6bbb481052217e34a3eab303d431ad1f..fb57343a97bd502540c038278598148fef37b5bf 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 e0b55d869a35a016684f7e8dc94c1192dfdf3c4d..b1a749ab18f84dcd086156f640251a96cec0ad2d 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 7d1b767d87fb40624cb4c44ef4d53ecb4434461f..dc88bc46dcc0711922b88bb89173ab82b273cc9b 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 598f2fc93ef2f3a4fcae038bbe296c55f2140657..ff9adfc0b332e27204aa60715f7bcdae81914d61 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 de6574cccf5859ab69f1e4394baea5615b82518d..58da993251e939fd413fd6ba6dd3ef89b733bf60 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 b8227cfef64f5fe03c41a402578e6a17597129d3..77dcdfc412b15b58af9b6521916d3b8374510f72 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 6c864b093ac94aad8d8182807101f4740ae272a9..40db5190a2225143ddf07ad272552ab1aadf4de4 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 beded091dff137f06f85afcea121da9d57454962..7aa418ebfe018509b086e88166fea935be8a20e0 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 461d38e2fb1990708aad4e6a5187c2bfe0068e42..69de9657f7cb92eb4470c6a02a3bb5a5d564ff3e 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 aaba294ecb588f62a927f26f15c8bc5327ffba9e..42676627c3af31180be598e34f7283bf7833ca6f 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 96b335c92603e98f142f66e176374326ea4642fb..386c8359e1cc8aca062acdd421dee2fe30904544 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 2aca60f6428e71ffc6269f8a658cca791ab78994..dfe05fab7b42ea1f64665dba0b129838e7f73857 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 84bc81d7ce7651cf43db1a94c56ac759ec57339b..1786cee08729e47d2912554832eb0846533c86c7 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 cf7e738c4edc6bce2ae0c8759ab632cc83e49780..4ed9f46ded65c4d2bd111cfdc4ad509adfe23ceb 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 44871746944ad0c0f30f28975ed40e0fde4e8d03..3f31875ff46eb0a25a9bb52e17b78a6a65a70a49 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 56d270526c9ccae7ae05e19d880d2da44528e4b6..8e4241c295e348946c5c55a2114dff8cc413d72d 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 a48d24af9ac3f27516e5fc19de076a9b5f9b10bc..2f478426f16ebc637150540915d8bf73c1332e6f 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 c2b6f4eb338e65001ee3dc046e479c18f2b38760..f8ab69c51dab5c21c9c0d325b57a7ea278306525 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 19395e2aee44d0710e5fd0c3e3bbd23071f9202b..ce62ab1180bd7511c2630277d30b5c56eab7dde0 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 9a357ff42085709f7fb377130c93f4a71033a750..4cc4077ea53c76c60c511c0d0a4b1cf94d36a942 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 4864e957be0b8abb8e0f687ba78ce3def35065f5..d1a4cc69d408f86517c1685ef642b119b12b085f 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 6d97339371fbc5e5ee201db08848d33950e85bad..fa94d7110714f9f2c28ee5da3c46585c62c70819 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 2adfedb8484c29e4add6f10e5c2f6d8692b8e718..24cd172905f337896219efa3415a88ac871cd95c 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 4c493b06062ac058ad85781a10f829d298de097f..862ab0fbc893a008d123b7f5c6a3441ecfc9d5b4 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 d65a45860b339899701524edfd565432b191efcd..3d65a498b70190985846c920ebbaa74c2edd92ce 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 d89135fb8faa6be0423d297cfbd02e7c50e18341..b29bec6abd72395a46f889abf131f11ee232aaf0 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 c108b5b940c3a324948db2ca1d134e923bd5b7a0..6d2f4c831df7475a4b678f621029b45d6ac03ff9 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 743a3c64b0da10b512449d6964e3bab8510d4e45..88237ec8b15f8ba7a55137ad7a1cdfa68f16ef1e 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 1609aba1c9c153eee39358b99dd15854a9bcce79..10bd2aac2cb426f650ff490da68d8f1760f67008 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 c382a257b51b94aa56b1cd2b5db5e79f32639fa3..3b4820defe63df94e7c2e9888e3d061aa75a5406 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 e705c30b4e1b8dfd32d55ddfd3a69328c3af683b..16d0f02af1e40c9c57a28630ae7bf339fd0bbbe7 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 1ddaf72283403ac2f72f59f13e67602e978e672d..392d57e054db337c1a5cd9dda8e42a5539569ed3 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 feb2461b90e88009a9ec45f3bff63f10229501e8..928723c90b7580cd485dab1b21c7070efb4868ea 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 12c67cdd7c199d6094ecd09de75a9eea32b336d2..530dddd39bab4914426198bd1999ae78bf60970f 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 375a879c31f108d85d87c007f91e96fb83f9eab2..b1a61eca82956261a4843898aab912b60bfe12aa 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 3d15a964f5c9824e6c5676ba6a82556fd234b9a2..b88e54a7e65c65218aaeb2cc2b93840da192de0a 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 2400602a8561137a52bcbfd8b4436dd1ffbd2101..20fa450def03b0783dd28304e797880ff47e9460 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 9edf80b14b1a0f8b087f5bb4f01ebe5bf2e57b41..8acb744febcdb35406260a871b976978cdc599ba 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 2ebb073e4ef3219d15b49943efe70258a11dcd3f..47bbcb78fb4d426b3b116ed93376b14cc3716641 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 b75f46c30759daf3a2a5ac77f5ab8b3e77c2bf57..b610cad83321dc719cc4303cf6249d44752342c7 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 fd7fa7640a5ea9eb47e715ecb80c4c5f094af272..87184e2538b07838ac6058400cb10a406a5e84f6 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 5e33d411fa3d8dcfc6208b3b693848d956965b8c..3aac0e17cb00612ed7b6fb4a2e8745c7120fc506 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 52ac10226cb08fcb6de4ee7e0909251922463b50..6c46654b9cd928738bcd4bd6cd90641d9168a487 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 14ac81ec0aa0e82a2aa5c0c7ed3af0435ff9f8c4..34ba9b137789aa91050d61eeb99e774dad9b4820 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 e0aeb206df8d926fe348276e7f35bf90e6f2ce88..33f403e307ebfbd84079765d982ea963556dda0c 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 078a9c80bce27d364d6a14ae96ab9f29d77f9317..6af018f1ca22658b7b9fc5693ca89d3238b09604 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 dcde55c8ee5deadd421b108087605c5c822c3b4c..91bbd3b75bff97b3fa6b08cb1c4f77150218cd98 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 0c2dd782b675632560d50d2aa222e9fdaa24b57c..514934dd6f80ed78bff40a4a8f9ef42f0e574bbc 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 288ce04fc2b1ae6135f919236b5dab232ec3533e..d4b484c0fd9d7ae01055cd610b01de4225982ccd 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 d540d66e6ffc4f774b735ed31f279c04402e3fd2..d4141656b20467d610d26901ed00a655a2a70c1c 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 a348df895dca6cf4b1b892e49ab813923f6c72a0..8ff679e67bbfc909145403a6176c5b4fc26247d8 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 1d784ee7671c509f9b658f9264a7b6fe5eb6a755..3d40a63e378d792ffc005c51cb2fdbb04e1acc5f 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 1a6eb72ca281019e80b2916a27308ee505a7d269..57637a81776d3d34fd6ad526fbed8908e073f4be 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 644b44d2aef24effb89b5c588ac30ed0369cca66..18261cbd413b496fc89909e0e0ecf5999203ea2d 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 c8f64ec69344afb81cd3640bebc6f7469836552a..b56210734caafccd1235401dec508c6b6b65fc8e 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 330078b1d50fd781578eb8c650b64e353531eea7..c6489e90b8b9cfb7cbd0c740549dba6b38287096 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 3f747fd61d19956ed5d898d6a402e8f68db15f27..77d9cc65477ad35a3da795d8f6d34d533b65bcc4 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 73780204631463631cabcbad5bf83e8dbbee94ce..a80cf4047b86e38d22d3750b30deacbb00e7059d 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 7f152167bb05b2c24a0f9669f60278152898eebb..38ac635645ba65aa46cb5e8a50072ed9771e229b 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 0000000000000000000000000000000000000000..697b3e8bb023566f17911fc222666d84f5e14c91 --- /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 + * Correllium support Copyright (C) 2021 Corellium LLC + * hisi-spmi-controller.c + * spmi-pmic-arb.c Copyright (c) 2021, The Linux Foundation. + */ + +#include +#include +#include +#include +#include +#include + +/* 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 "); +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 5c058db2182186e0e131a3f9605704c3a8375489..91581974ef84ea49f2b9c64846634ee2da8df2bb 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 dcf6a70455cc248e3a32b1d2cde737b384fcd7f0..c2655768209ac397195dddb8a90153b8e0a9f41a 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 445b9380ff98e8316662c26d626e6e490221f229..94bbb3b6576d9b8ed7c2e989e652905bb534d8b7 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 1573230c619d4bc95d4847a4c613186cba25fa10..ef841957297fc00b53361466401319cfb11d045b 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 da229965d98e9fc0813acceeb26c8db4be1bd0b4..b923dc606d1d36cb5c9fa01e105b00ba65125a49 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 cdbc3ec5d8bd07e7b23ed9388a9c0be590b631f0..23aa4799eb8628fe11e4d76381a4d85eb4dffb3a 100644 --- a/drivers/staging/gpib/agilent_82357a/agilent_82357a.h +++ b/drivers/staging/gpib/agilent_82357a/agilent_82357a.h @@ -6,7 +6,7 @@ #include #include -#include +#include #include #include #include @@ -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 6b22a33a8c4f5169c975ced32de4179448921f97..298ed306189df5c3eca2434485563b9a5c8866c5 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 2108fe7a8ce5dd63ca38bac718f2a3fea2205138..13f127563ab3a7e1ae1ba0068e4bf4badf19ba9b 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 a822fa428cd0c13d5b04cca398f1c3af51243de0..e8736cbf50e36401fe61109b8e302b03b566955f 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 8456b97290b80e0270dceeab9fb19a5a22ff4c9b..a193d64db0337e810720b151b184df126134dd63 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 432540e1bc9af871797000f926b8d8c537b6fb14..549280d9a6e965d22e3346fc3079cfcde7fe1fcb 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 19960af809c2e81f0e7d19a3551c67de3b37f5bc..e5a148f513a82645ad251525bf8dbd40c7bc538a 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 a6b1ac169f94a4766d0fff27bd608e214568c33b..491356433249ec2c715f251870d8d7f2a1196bbc 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 3e4348196b425548e6d4bb9a115912640e783698..493c200d0bbf7aef4f69301b7df14a3fee93b445 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 53f4b3fccc3c4865bee71d4d7132e3197f6bc84d..4138f3d2bae7f44bd6bc83ae89205c0457011980 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 "); 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 de6fd2164414dc99ec5f535fa8629c1d30aaa61d..e7602d7e14012dd51a2d709d43dbaf9002b0ca0c 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 86bdd381472a0bb973d4c58992a808ab04303e74..625fef24a0bfa61d7b79bce4a5807dfa19bc66a4 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 #include #include -#include 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 fd23b1cb80f9de6b1959d78080e6fe94a077dd40..d0e47ef77c87ef34cda864c923370957ee23a0f9 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 f52e673dc86990f036eb580431b4cdf515f6f234..1b0822b2a3b8e015bbf4b8e5e18fa447502ba1e9 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 0c71a038e4448293d92e08de99ce590bd0112a07..0af72934ce241f0791896d62939f254be5e52f81 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 #include #include -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 2c7dfc02f517135d29f193d7e49fdba185c30c53..42e736e3b7cdefaaf499a007bd8b8eab7cf047af 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 2d9b9be683f8a68bab64c0117c60b1b5583ccea4..db040c80d778416e92ff6a607217db356d4bb0ee 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 #include #include @@ -22,11 +17,10 @@ #include #include -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 069896456230eb89a26e3c4ba47371b83efc9cfa..312217b4580ea7b896622b83c7b21499b823286f 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 888803dd97f9e7ac2229bff5318e7b245cdff0e8..97c53ac8e8058057f48bd069010d7a3cba5d96b1 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 424c95ad85c6e924497b296ae42b05a3b4adfe5e..50a9d3b226190267c6661ff99af8e9114789bb61 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 ff27f055a0ff2dfe1016f96dcd9ebb1d11fbb55c..f0210ce2470da3a6978e448a07693e95c8275837 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 d93eb05dab903811f16a7347227e9f4aec047a4a..c851fd014f487c0a75a3e398b2cc567b37b69535 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 faf96e9cc4a1078b5650e8176466aa1fe3d28000..3cf5037c0cd2c98465192f9438a5b4093d148ba8 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 , . + * 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 , . * - * 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 846c0a3fa1dc31eaadb46a4d767cf271c50ef6b4..34a1cae4f4864e6e1ae2c74683d0d12ebd4d742e 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 9f1b9927f025cc833ada5635a5678676cc4ee95d..7cf25c95787f35e748fecb5789dadf06ee8e9eb0 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 4b297db09a9bf567e08209764bfe0eab7c2ad621..b011e131201c1927bbdaf82263ec96d1845e8de8 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 96d3c09f2273be7fe71d56da1a0163974aedae10..2282492025b78db6a966cbee5a4fb078f605bcfe 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 2abda9d7dfcbe8046109d01247648c8472fbd373..04d57108efc740b3084c4b8bbbecdb719e4934f1 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 c35b084b6fd0fbe003808e857f0e55ffc9fbe2c5..a17b69e349867942fbcad27823bed87e10ce6a4b 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 similarity index 50% rename from drivers/staging/gpib/uapi/gpib_user.h rename to drivers/staging/gpib/uapi/gpib.h index 5ff4588686fde328cb78448694988eaa792b3757..41500cee4029fdc08b42153f5d859110168102a5 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 6202865278ea7c9bf858d79b2bf2d84e8a662499..0fed5c0fa7f2aa4da9a3beb54718493121937f47 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 5d80ace41d8e9f3be0b89e5e30c6ac745a034c76..ec9fddfc0b14d5f0ff8ba72f5af8ae96d84abcf1 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 a4738517558246e7490391d4e081ce908b34eba2..152949c23d6594d1d443c425a15d18f57ea9e570 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 16bcf7fc8158659284dff900d33befa3b65fe7be..f81c34160f720b7dcb55b5f6acb9da890dbafce2 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 c1c73308800c50dbb84574df9e645a167e08c6fd..830ff38fda92e42e7c52f054d4ff69cfb2fd1bcd 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 081b17f498638b554633c9cd4d071b2690d5a51a..4774df778de949adfda55a2754ad746ea542bf06 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 e6ad088636f63b644715c14ffb92470a63fb8d3a..f45968ef94eaa59382a8cc70721f3cd56834b4e5 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 f4260786d50aa1f4a98a07eaa24348be0ffbc4d3..16f30c4f1aa083196e2bedc9a3b19defe9e0de86 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 db42810c7664b5b1e39f8556b2be58e3880b89b8..49388da5a684a530f2a4dda81a47d6122c789505 100644 --- a/drivers/staging/iio/frequency/ad9832.c +++ b/drivers/staging/iio/frequency/ad9832.c @@ -7,6 +7,8 @@ #include +#include +#include #include #include #include @@ -16,6 +18,7 @@ #include #include #include +#include #include #include @@ -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 98dfbd9289ab8cac38d868ba570465a58d34422c..d0d840edb8d276c85a71b13e4ae599da122b539a 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 50413da2aa652b8cf2a33047399bad5450b8a331..0038eb234d40920c77abac2472aa775ba62f0ed6 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 d5544fc2fe989b90bf7c1eb5fab60dd206754ae2..85a4223295cd06840b7f6095019b8d06abeb077f 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 2855ba2296ac1c6d28fe56146f28bbb89d2f3ddd..77360bfe081a4288970b2947528a8b98ab88098e 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 f1d7fce8c0204e3bc2d919f56012dc258258b95c..a7cd3ef95fc3f6eedd9d29c08820db1e88978af1 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 50022bb5911efeccd562134a6e3c23e2bd9c0a63..383a6f7c06f4453171e2be7f3e9a5f95010a4eff 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 d54095f501132024207bbbeaf35f7c03a4239f6b..f4b19ef7b34168795006c5c88b080a17beef309c 100644 --- a/drivers/staging/rtl8723bs/core/rtw_btcoex.c +++ b/drivers/staging/rtl8723bs/core/rtw_btcoex.c @@ -8,14 +8,14 @@ #include #include -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 1c9e8b01d9d862d560f6ce7909cd2965d761015d..437934dd255e922b45d5fade199dd5c861573bf2 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 0ed420f3d09628a5f73d4188b018d6cd27c8b59d..53d4c113b19c8c0a00435e678b6f0e79e917ecbd 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 58de0c2fdd68baca6bfce4d3d91ec989374d2ff7..6301dbbcc472061cbf9f66d00181762305a7609f 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 3d36b6f005e04f09346e67fba45434a73eeca835..bc980d21d50e245cf6edf81fda771e0d3dc2ef8c 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 c60e179bb2e196fcde02903cb9dd03e59d3d2826..6a2583d0d3ebe794b4ab8e4867beb229b50e69b1 100644 --- a/drivers/staging/rtl8723bs/core/rtw_pwrctrl.c +++ b/drivers/staging/rtl8723bs/core/rtw_pwrctrl.c @@ -8,7 +8,6 @@ #include #include - 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 895116e9f4e78d10e756ba5a23b959797b723d1f..8ae527b6e0d69f07be5171d4539381492ea8ff64 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 297c93d6531571d7989b4545f9cada8f09e002b3..026d58b4bd7feb1c4db083dcfd023b3d2e50314a 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 c1c7b5cc17a7e3bcfb8fa725378a0f7152b6182a..d32dbf94858faf9650b4663392f045fb342ee376 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 b72cf520d5768b8a5afdb4a0b94515c742e8fe15..9105594d2dde06ddd318725eeb97bd6d9507453c 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 1213a91cffffbd280b38f36e5af3b8365beb7c0f..d91e2461fd7e4e8f8405d5865c0b1157753a9e87 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 928c58be6c9b198c534990edf33cf35e73bdc67b..666a9f44012de7a2c23d345b234641c830b5c3e5 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 97a51546463a69ed536da25f1b503c88c55e3fec..1e2946a23bebdafdf3cdd76973fcd2eb63e7185f 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 e15ec6452fd0619b5e13a7f32f077436f1667003..893cab0532ed0b3ac25bea94fc7159abac8f1dfa 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<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 5dc1c12fe03e5727c325b779b159d616871e1f02..842e19b534217ab72171bddf7d90935d85e251ba 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 b93d74a5b9a5da4f73608420bcf3a7a0821acc37..48bf7f66a06ebd17c5b1dad45fd3fb8b29b6e7c5 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 b3535fed3de768b7e15da3f6c8b600b4711dd77b..63343998266ad5795eb0a375da497a89b76f357c 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 1904e82a24b5c273c757418365be41640f85947e..fd4ae870a617858efb7a3952d956c72bf6e8a7f6 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 ca808ded61ac0fd78a53b4804fb3ace386e81394..98d3e477721057d7a5f4659179b5575591d70cc2 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 b89aa4c12e9d9a7a1f4d6eeb582a641c3f50cd7a..f7e227df0e5482aead49843ccce9015a0384fbfd 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 9dd57c56625704f2b9f377706620e995c63c1aae..7ce632d040b3af11fe7d9bc45057cc89a7847171 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 64ef4d258a91265f5d1182e26764b54b47786cd1..8a32f8cf3a98fe084a861c5433e026eefff9dd0c 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 172624ff98b0668bda019bbf941197d4dd386637..4e390541a507e6edf3e26f62864742be6a276bc9 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 8b81e8642f9e00b1d0e3fe09c3543659e59a7fab..0000000000000000000000000000000000000000 --- 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 c2518b73bdbd077bf010dca738f7155adb912540..0000000000000000000000000000000000000000 --- 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 8482689b665b1306430abcfc7773e220b7c7bc18..0000000000000000000000000000000000000000 --- 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 337c6493ca61f30ba137973c055755f51b0d3955..0000000000000000000000000000000000000000 --- 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 63c9e8b6ffb3db92e493fc6e231487d279fc20f9..5cbb11986bb89e657dc8c7ac9cd6b19f2d136e12 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 2532b60245ac9d0dd9c75882f479b38fbcf99b05..0000000000000000000000000000000000000000 --- 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 71a7c1cb42c405fc6a44db74be6c794ac15b805a..0000000000000000000000000000000000000000 --- 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 04c1b32a22c5e1944687608227658f8f0d77d4b4..1d929aca399c16026dd96975c190147405864af8 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 aff69661c8e627353c567449ade429f324e6671a..9cf8b3d30aacfbc11442ca5ae66cdbd0b493ca38 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 eea4d1bd36ce7f7d62cc06292e4e0f5ad0b2b096..7ede144905c9239b041f31befc71f4cc99681a8e 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 b59643dd61ed120d8f9eaa137159549083ac3766..88fa02f6377a4250e1c4f112eda8e1da41f97b2b 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 4bc89218c11c81992f6429875403702c75c24477..7119b67efe11b3f5774dac2e716ac27dee779777 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 1c1f040122d76dd0b1cb8c42c3d4fd9a0f4d5566..7d0ddd5c8cce4f02210ceb0b9ede43db463cc22b 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 6bce45925bf1f9b552d04e95d86c5cdbe09b4745..e670226f1edf77a13e303e13dae783922175311b 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 f0d7eebfcad6b469d3a72a800775c0d8bce1357f..24db6b07493e628a354816f97090e5b6ed93452e 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 e7c3c4cdaae4eb249053cb85353445ca7f4b3730..d8ca06e697d63f3f8dc202085a075d2d965f9f2c 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 0bd62ab9a1cdec7f860f2c293beb57288ec7076f..5e6cf34929b55bf351d4cb2c050d22be5a6ea7c0 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 43872ccc07cc7eb5fd1683e97ab514b431e77c6a..3fd963612775892abc348372a6138169f0fd8531 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 cd15e84c47f475994e3b5d02a33d9a2c0ecd3431..1db2e951b53facf79bed849206e2d8997eb553fd 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 144d0232a70c11c530650d82c3d6b3acad6316d2..a3a7c8059eeeb7ad6b496a47c75630e8a1eb7d6a 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 7859bccc592dd3bfc6ca68a088838997d6695785..f213d9174dc57407667679921e20dda8447500b2 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 6a2116cbb06f92965028e01b51546903d6a0de56..28febb95f8fa1d3f67050f8d0437109a54d47436 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 8c527af989271cccc6e544af8c18dc75e2aa5ebf..c14ab1fbeeafd689e28c0f2c04fa195f194cdf86 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 b54147a1ba8778ab88320637988a093e843478ed..87afd5a7c504b542b77a1dcde83e366415489817 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 a1670a96cbdc63b37cba7385593a71208ea324c2..144f7332d5d23c6f63920d905953e9de7629771d 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 76254ed3f47f4bbe4416214134a0dee5628ebf7e..d52efe3f658ce6943200efa8e22790b0557feda8 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 8a0a0cb21a895e0290afd57336f036d88903b030..5e9fb73d52200fbe40206cf50f83e52f714191e1 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 e51d01671d8e7cb79494df458b7ecade04d3fce6..fce3c0f2354a793525bb36510fe75e1a09c8652f 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 5150879888cac7f2bfa8693fe43b4116829b6f61..852a45fcd19d12551fbeaa2591d5e74fde93ddd8 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 c13f52337035b40cdf6347faa978fa03db2486aa..e18848267be41579025260e0e5f32e89b73fdc1d 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 fa47bfcf9e862ac880eb21203cc45d80372c3f0a..ba7690c3e15e7ee22847bcf609d7434429d02336 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 4d45eca4929abdfd60e90f96160a8f8bb005d02e..2fc13cc02cc51b04081553be19479556bd244cf5 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 40a336ef8c7ebbdb83efdccbb67f4963d52e00b3..7fc535452c0b30ab34c14c725c2a65531c17b2f3 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 eb2a2e58fe78fbbdb5839232936a994bda86d0b4..0213381fa35876f43f2f10f6c444160cde73a686 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 b861585ca02acc7c47e164534e1c7b8226644558..18530c31a598158bec34199808adc110296401d6 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 392447038bfbbb8015658db970e642394d667f5f..26fc0464f1cc243ddcf1a4939babef6bd33d849f 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 5a56f853cf6d8c9a418280b60fa134ea30faa3bb..7a6050f1c094b3947415ee83fb053614b990fa75 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 84242292176570cd2c92afbd4755d303827a4abc..dc0371857ecbee7149d5f95277b756869bc80a66 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 b10a42d2ad633dabaf89413cceaa9014d3960f91..b0e44fb00b3a4df68ca1010d6f00429c4922705f 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 #include +#include +#include #include #include #include +#include #include +#include #include -#include +#include +#include #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 11c860ea80f60f3d24c368b4efcad35a5fcc3c67..d178b6c54ea18bae57dfd95bc3ce4c56ddd7380e 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 2a0ce11f405d2d23950c7e75132c609bdcc61859..72ae08d6204ff4c3a060140e7f4690175228b6bb 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 e9c51d4e447dd29bcb63f10b1244501e59aeeb02..4c149db846925f63b2c84ad93695e4e334076961 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 8ac452cea36c6ea0f3f0af5df99ac5ce10a8b1af..6d7b8c4667c9cd377593694133ac6a0badc1a4ad 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 82f2593b4c59b39e08022cd08d4e8a2fd649a708..4c8b9671bd41d77ee8790e01d7c96a35c7b9436f 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 bd3d636ff96205d0dda6360d962b6fad632f9f92..f64ef0819cd4e507918e5d409fea252a2995974b 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 011f38681131942f4100acece6fc9f35f5f9256d..837991dc4db9763424e44ce6b12ea77172c5a9a7 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 11d65097578cd335541e9c8d55cf3573b651fe8d..22939841b1de5a3f6d08466919ef4c3880bb0b5b 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 18dba502144d01430c7ae843177f030c7f3e3672..08dd8f88795605a7491205dacace4acc032fcae5 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 fe5aed99d55a664b5fa20f306ced712e41b6f408..2790b4078e7ed49399645ab2a2072b891d28c4b9 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 e4b6f1bfdc95cd1f3c7cc8748370b27e1a4de25c..bd02ee898f5da4481f7d6cbf6fbe9636757e166a 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 ce0fef7e2c665c24793f73d3fc1a38f33dcb4cac..be2f130696b3a0d9d0480f653da2289b4833ae9f 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 58a3ab030d6706315923622c49b3e9d7ab5cc516..62cd9e0bb377b858e6fefd45ba2e56950dddb8bf 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 3a0960c97c77b6b78154b3b4a9e9c68b2e45fe3f..6429e8f11f36fcb1a6e1a87411393fb904c648ba 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 f2dd83692b2c9daa8a1cbad7ce171a33050ff2b7..67d80f8f801e9a2a845fb426527c80c8415b6894 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 #include #include #include @@ -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 35369a2f77b29e0f62e8c847d7eb63facb4e7713..541c790c0109019e364a25106f9951179b7f694e 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 059bea18dbab569a610cb96a1f153a01ca9d362c..4e47dca2c4ed9ce650a21f8345aa445178a1c6ee 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 a80ce7aaf309d1754cbae6469259291b79854c2a..0293b6210aa67678b7b688fc64b82cd30a27600e 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 8587ebbe107375ddc1f88880a251d3ca2b768493..72b1bb76415c03fd2095b67355749ebd3123076d 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 210fff7164c138e315d20ccaa4a29ce6a7bb2dfe..2fb58c626daf354616a7ff96298099e92ea20533 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 560f45ed19aeba0f98134751f95731f21f0b81ed..5ea8aadb6e69c123c9ff5724ad1f4f2563ac8daa 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 553e3c1321ca01fe2a41ae1cb9032ba654e8b6a0..4ceca11ce6003c572861ceba76fae8ddc7cb099f 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 88669972d9a036ec2f8e13bf421fab6816512611..1f7708a91fc6d7238d0edbebd316811aba59263d 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 0000000000000000000000000000000000000000..bd9d9cfac1c831218f40e30a9da0d56c29b8c3e7 --- /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 + +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 7e7813ccda4117c51fd5968f12b4531d758d7281..1c356544a832a0c2c376671111b6da8c045fc87e 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 0b65563c4e9e3728c47c63f752e6ff464df82aed..951681aba586d196db0f7c57546b74a7010e3d72 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 054a8e630aceac4dd40d70b47bf9d5b2edc61618..110d676131922a6543b0b02b396c733616fc47d8 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 39b14fe813c94e5a6afe93fdd8d5e4834ec3758a..0c70d3e7b9b94d0222eede9bbc0e0f9c2b3411f0 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 a41e7fc373b7c61f4617d466a7db2024521023ce..39c1fd1ff9cedd55957a5ea1408d07a5da6edc8e 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 4c703f42680db79757b43e08e7f65275c5263df4..3865b10d2d43c5fe841d00972b3ca41b6afd6569 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 6853c4660e7c2586487fea83c12f0b7780db1ee1..d77c03d22227d8c9ab0d040ee7fa695acb49d50c 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 ca9b7d7bad2b6807b29d3768bb655528ea162816..e2d92cf70eb78ec6b2b93b55192e46781160c9dc 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 85de90eebc7bbf533e82df6a4ca3d83d0083afe6..90c70d8d14e3a0a64e4c070499d885d90698f08e 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 14cca33d226930f56ecbcce0d8ad8e90df8eee4f..4af1fbf73f51ca6eb321e7bf507a1cde74442b89 100644 --- a/drivers/tty/tty_port.c +++ b/drivers/tty/tty_port.c @@ -199,26 +199,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 diff --git a/drivers/tty/vcc.c b/drivers/tty/vcc.c index 7ac3048377d50907d1f48ea75b241064ff168721..2960031ace72309ebeea31399814db58de68ef94 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 0221709b177dff75d2e739958a247d41649f2b1f..a74859bab862d130563d6952b212c64627738029 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 2c8ce8b592ed2dc5ae60a5adf72311c058742053..ae746dcdeec8c8f10693350c6abbf2c75e1309d1 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 82d70083fead062c77b8cfb097c3d86dc2b56279..bb4bb272ebec566ec90b4dc5a89519116490d3d3 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 0000000000000000000000000000000000000000..6e09c1cb6d4b347a9c02b81654a7a140f83a885a --- /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 0000000000000000000000000000000000000000..4434a436ac9efc56a0382de7232ec3fd3490d66f --- /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 0000000000000000000000000000000000000000..76e80ebeff133c95bfec5288e7753baace6e6fa7 --- /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 ae92e6a50a65a0dcfd9b9713c6b318b8fb2b5b22..dc585079c2fb8c92d37284701f15905a24161768 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 791e2f1f7c0b65b5258e6b8f47a7a95576316710..24b0a53e5a796cb3cc61aa1b188c5b50cd8f7f92 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 0000000000000000000000000000000000000000..6ead622b77138bf7f8a09c47087369f090c9525f --- /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 +#include +#include +#include + +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 0000000000000000000000000000000000000000..2da5a8fe1cf1b511ce6877a06ea57d648eb5d0e5 --- /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 0000000000000000000000000000000000000000..bd91edde5d19bde6c19b898d658897cd732e5c05 --- /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 0000000000000000000000000000000000000000..6fcb8f1d577d3bec65ecf06c308037ea7a0deaf8 --- /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 f5642b3038e4dd81b9fabfa92cbe4e2d81317bf9..ed39d9cb4432cb48f5148deb0e3bc957e7a753de 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -104,7 +104,6 @@ #include #include #include -#include #include #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 4b91072f3a4e916a3acd9ef8841764ab4febb0c9..61342e06970a00c024d8eceec7915bf685a18cb6 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 76cedd30c2742c9e15585d0618cb384e582d46d1..4410e7d93b7d0645a6978648b704c130ca99cc9a 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 37887ec684127925e92e01d40f5ea6b8cdb7fc3c..18a9784520013e825df0c576070f6d768f4edf27 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 aac67a4413cea9026e36de5bf774972fb7846ae6..f19efad4d6f8d942caff9f84b1cfd9ebc70cbac1 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 b7f940486414ac9c08aa3a5944f2e02384ce416d..a12ab90b3db75b230dcf319a949e6d10dbac0363 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 27e3d35ee7ddfa4e3f09c417a4df50171005018b..773ac27255324cce5c45e2c8689d9097ac8b0148 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 a6a05e85ef8c26a688489de58ed68ab6be601be0..5f3ad9a99d9e7cd27b3ef660ebbefe459bda64ab 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 59ec505e198a4b37eb609c904dee34c680e97a08..735df88774e43d892772c36d809e3bcf85f2a31c 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 4824a10df07e7ca7e71c91760b0ea76a8c3ab894..55f95f41b3b4dd880c0aea0d1ab9eaeca2e93a45 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 12534be52f39dfddc87aec8d3359a9ba01203cc0..2afa3e558f85ca264511014de7698c2d4ca7dbdb 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 4f8bfd242b5953821b0069192e0bef8f4819f6a6..780f4d151345375735e3e3c0bb1b4c679511db06 100644 --- a/drivers/usb/chipidea/ci_hdrc_imx.c +++ b/drivers/usb/chipidea/ci_hdrc_imx.c @@ -6,6 +6,7 @@ */ #include +#include #include #include #include @@ -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 6243d8005f5dd0cdc5ca8689885ae7160ea18ea3..118b9a68496bd478824824d4bab8d5583badb9dd 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 16e7fa4d488d37ecdb288318bcc3f6ebea3016f1..ecd6d1f39e4984427bcdf8bc5b00cead1cf459e1 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 740d2d2b19fbe0ebb24eb63964f7122af24c05b4..75de29725a450cd17ad8f6da8794d7f619bd0c27 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 1e36be2a28fd5ca5e1495b7923e4d3e25d7cedef..421c3af38e06975259f4a1792aa3b3708a192d59 100644 --- a/drivers/usb/common/usb-conn-gpio.c +++ b/drivers/usb/common/usb-conn-gpio.c @@ -21,6 +21,9 @@ #include #include #include +#include + +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 13bd4ec4ea5f7a6fef615b6f50b1acb3bbe44ba4..fc0cfd94cbab22b642024924c9196455eb7602e3 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 a63c793bac21c7c5f91a396c6b031028212179c2..c22de97432a01be096849f7b2103f151bb5f5cbf 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 0e1dd6ef60a719f59a22d86caeb20f86991b5b29..770d1e91183ca537ee6cadd45fe14d916d4ade62 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 36d3df7d040c6323f590601cddb2c8f1af5a457b..53d68d20fb62e00995df449ea7da3b46d04e2f45 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 935c0efea0b640b448a5161b3d0555cf38530eed..ea1ce8beb0cbb27adea84f640c1625a75f5861be 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 0b4685aad2d50337f3cacb2198c95a68ae8eff86..118fa4c93a7956464428f38e736586e489cf7565 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 300ea4969f0cff9cae4d096f0c188405c122f4db..d5b622f78cf38c62d11dd044ccfdc0ded44bb413 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 60ef8092259a9d734f22df6c2c75029b6bac038e..30eb8506617c047b84f9e82e74248ed1928d51ab 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 b0098792dd22502f5f88d57d7cfce06e53004855..904fe0632b34e5c7284f7d2254525f10f9b4eee2 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 124eda2522d9c1f4caab222ec9770d0deaf655fc..830e6c9e5fe073c1f662ce34b6a4a2da34c407a2 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 66a08b5271653abd458f9ec85ca730afd7779d71..2bc775a747f200f6a7e5b7ba2771a9640dac5e98 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -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 27eae4cf223dfd92f3045cb1b2a5d0421966cfe1..d5b985fa12f4d9ee3f318ea5cce7c1b225cd3623 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 de686b9e64046be12e52c87d80282558ac5b5f52..e934f94e8fd8e518272557adc1d3d1718adb19c6 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, }, { @@ -197,6 +212,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 0000000000000000000000000000000000000000..d3fad0fcfdac33ffbd75933f4803a023423bc4f4 --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 58683bb672e9522deb321c38daffd856c0d9029c..7334de85ad10c7f680a794bd7818f1802b130440 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 #include #include #include @@ -14,7 +13,6 @@ #include #include #include -#include #include #include #include @@ -23,6 +21,7 @@ #include #include #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 0000000000000000000000000000000000000000..2efd00e763be4fc51911f32d43054059e61fb43a --- /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 +#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 b48e108fc8fe7343446946e7babf9ba3bc0d2dc3..1c513bf8002ec9ec91b41bfd096cbd0da1dd2d2e 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 ed5a92c474e509c23958ef9254130d841834f6c1..30016b805bfd6ea975b7c7b8631e7353a0d7ea92 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 c7a05f842745bc70bb80a7fa6cd0c8ecabf0ee27..97a62b9264150f4948a6f2dd4341d04299a3057b 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 3b8c4ce2a40a458898c12e333a18f005217c70a9..82ecd3fedb3a1f7b1bc191916782008b9c0fe7d2 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 8f7e7a2b2ff24dd604aba0811c5fdcd830d0f9b2..0f266bc067f5092c0e0cb03fd9aaede1a8225c68 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 5a2e1237f85c3f4a6ac223c229b38706c8cffaa0..6e8804f04baa774f5e6bed548b64769e93f6eb1c 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 84bb702928553923668d5c649c1f2f3979a9aff8..a9ed9720caeee6a544e226cce72444d101e81047 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 36fff45e8c9b7a5ddfa343d848bcedfeec957549..ab544f6824befa3a90922e9f16c8255a1d9d9fa9 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 2f78cd4f396f240e10f8db7e991253c8a1496d5d..9391614135e93292731d0bdfc3d4fe5fc4f7e235 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 a9544fea87237bf4be630ec784adce4a87dd6944..578556422ea3f1f3289f37382d03f1b5428de08e 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 b6a30d88a800347de9d8e274923bd24b58018b53..fcce84a726f2cfeb47acfc7620203b29b1e28815 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 aae1787320d4eb1b25e0c9dbf76ec9145d3d82d5..26460340fbc9715b65737f11b996c9d7d6a9b38e 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 b52f93e9c61d39691806d7cb564bfe3aadd4b0b8..1b9b1a4f9c574839cb7de363610abe4331575130 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 aa4c61094dc6fa379de04f08f3b771dcafe942b3..42b94d858e37303a7ff140ee0810ed946dcd2892 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 4b3d5075621aa060f3fce0c5d6f8d4d6afe08ad6..d709e24c1fd4228c47f877d097faf987975ac392 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 4f1b5db51ddae29a61f438ccc59c8b353e0f2477..27c9699365ab951256147094d8960be4d6732bbd 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 5e94a99b3e53932c92bb2ac0e4ab18aff056a95c..0000000000000000000000000000000000000000 --- 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 - */ -#include -#include -#include -#include -#include -#include -#include -#include - -#include "fusb300_udc.h" - -MODULE_DESCRIPTION("FUSB300 USB gadget driver"); -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Yuan-Hsin Chen, Feng-Hsin Chiang "); -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 eb3d6d379ba70065b6a22166527df0d0f045b1a5..0000000000000000000000000000000000000000 --- 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 - */ - - -#ifndef __FUSB300_UDC_H__ -#define __FUSB300_UDC_H__ - -#include - -#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 89d6daf2bda7a353e0297dbe7c25bbb1c7f56839..1a7d3c4f652fef2aad5cb4e0d0f1882ad03410c6 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 a938b2af0944bc4fe79d4acc5dfe24ce09a07558..715791737499306060d34ef0485cba0db66853f9 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 66b84f792f646bb9e492cea0e656e045308c75da..0000000000000000000000000000000000000000 --- 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 062f43e146aaac827522627ef90b13622bacbe81..0000000000000000000000000000000000000000 --- 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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 "); -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 b3f759c0962cb591ae0a303ca0b7b9587831e161..0000000000000000000000000000000000000000 --- 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 ff103e6b3048f53fe462e38839ddcd5a5036b6cd..0000000000000000000000000000000000000000 --- 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 - * Neil Zhang - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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 "); -MODULE_LICENSE("GPL"); diff --git a/drivers/usb/gadget/udc/net2272.c b/drivers/usb/gadget/udc/net2272.c deleted file mode 100644 index 7ecddbf5c90db5c393237ff8b74184d3afee3129..0000000000000000000000000000000000000000 --- 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#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 a9994f7375883bfe5d70d56307bd6437661658cd..0000000000000000000000000000000000000000 --- 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 c93ea210c17cbe3048f4910f201f8ba94b39bca2..062bf2b57d2eac86361c44140bf717b8207b95a0 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 24eb1ae78e459763a442b9761e56d9db44db8b24..f5d09a91e55469d69b5c864434ee586bfd7486b0 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 6c1d15b2250c83d4f1e5fd924824f710220d8a56..e5c2630e371141c689e2e0c050f4c67fd5a94c25 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 89b304cf6d032f5162abfd1b8c60a930f3a12694..3e4d5645759791e420798084cbcbd01844b4d7e4 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 ae2aeb2718977da854f523bd996fbfe6e66acbb9..fa94cc0652742f695db053cdda322d9e3ea14c5f 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 d011d6c753edfcb9c03b9c6277761f6ac740a470..109100cc77a32522d5cb7ddbe04d85b102987aa0 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 be4e5245c52fe903dd612447f111c24aeb818ad2..4df946c05ba0ee3fa28ca58d4d81a8d90e51ff18 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 26f13278d4d6982ae2ca50948f930189f1e911a9..6ed2fa5418a4e47cb780aa721c586260c3142643 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 150d2542cef088215ab42c8ae543ceb62fa0fc47..6aab45c8525c1f43ab3306fd993927a8bf9553c2 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 c7784bf8101dcd261806684df0a1a747cbe17bb3..9c7f3008646ed5eb130b8d035a1ea3da29a42b9d 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 d75b1b9b4db02ba3cd92344c9937f4617d9c8c6a..6b7c73eff081c70b90cc4acc50a5c768f244cddb 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 67e472116d11a15afc55321d12a50540e46858cd..d21a03cf5c17564115589d1d63df076be92f7090 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 718b1b7fe3663828a64f27da2dbadf8b8def9c5f..ea3cab99c5d409c5abb4bff09505b9d90022d051 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 45a8256a665f0448aeb2b68488e8d632e857c991..9480d4ff011105885a92fce9416fa1dd38611bf1 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 05943f2213e437c6d1316fafe4ca26559406f63b..1c2a95fe41e59145e348791b9e39ea829c3502fb 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 f6b9a00a0ab97423090e01835c74b55e8837eb3e..4b8ff481564429af5a4ce0f80ae6188c5886cd91 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 1f5ef174abeaf03d9080a285562a2eb36860e140..c6d44977193f02d75137361c4224ac97ffc7ce34 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 486347776cb29a2fef4cd12cb11127883480dd6d..92bb84f8132a971757edb250144c0b296d01a5cb 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 d698095fc88d3c0479f3d7865d214412534967c2..bd745a0f2f782e2a73b121a68836677dead37b3a 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 3155e3a842da9a979f29e5cad18a3b18d70cfdab..6dab142e72789be74d9f54226687122367e3517b 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 423bf36495705e8d5906ab00a3e4ebf0ba0d30e0..e038ad3375dc91244f5c9fd202cbbfb4188d12b6 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 @@ -3148,6 +3152,37 @@ static int xhci_handle_events(struct xhci_hcd *xhci, struct xhci_interrupter *ir return 0; } +/* + * 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 @@ -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 0000000000000000000000000000000000000000..d49f9886dd8488e675f843da4d1d2ee9ee53bd65 --- /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 +#include + +#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 90eb491267b584fa91f3dbd05e2c6d8bc51e2ea5..4e6dbd2375c3fcc057c47108e56f1779d5ad8afa 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -20,6 +20,7 @@ #include #include #include +#include #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 242ab9fbc8ae6b6d807e5984a7f13f1fed701cda..49887a303e43530de8629cbec6a3395d45cd037b 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 2af89ee28baac04b379fce678abf751b7b5225cf..65ac91d0595a35c88d8072b20ef923923b0e935a 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 f5372dfa241a9cee09fea95fd14b72727a149b2e..5b481876af1b2c10ce625fcf0fb8bfbe8905aa8c 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 933797a7e0841ceee655b80ee1c8d21bc2eaaa04..e017b8e22f936be66da73789abb4f620e6af4d6a 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 7c2041f61cde62f9f80ef4d6ca91f72e8c7126c6..5c92c8d8e28338de37852dbcd918b2bb34c10d6e 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 eebb24ab3ec8cec63e3dbffcba0766203efc3986..4209f438ba18401aa27bbf403a583a98618f4398 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 020348a9851490ad2ab861cb2c54664c657ed434..587127abd30a8e9835374ca7e88f7e8038575c61 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 cbbb271780246611e5b30c1ac012b8fbd01ed06f..c7234b2369716627cbb656e4b6c1c86b1bfc05f9 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 e5e813f97fac5b170075428582515c30e50bdd93..12f587ab8511758a86fb5c4fe47479ca2ade3806 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 abd2472da7f7885929fa5111d3aaaa5d3bf4d163..1d9571f24a5667ac9a0da93ffadc462f4304276a 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 5f629d7cad64648ce380886bcbff795b89421bce..b7acf3966cd7bcf1a05e9738d6a1bca669997329 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 e5d619b4d8f68bbf3ba5cbb834c82f803728312d..ceae46c5341dd4168bfe1067bf2a8ac6ad7d0cce 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 638fba58420c0f027e903dc7d9b0da5c5d3f1c18..0000000000000000000000000000000000000000 --- 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 - * Neil Zhang - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#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 4b35ef216125c7681be6594962bf61d6b20ead43..f52418fe3fd47dcd7f6414f77662fce713ea5910 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 2fea1b1db4a269c0929a0e8e2effebd9bad9d34e..9e2a18c0b21839b11d44be695c6bd9dda73dda8e 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 b97ba8ed6801dcd1754039788452c7932e327124..614de0c2f5f2e36d5c038863512de5884d2f109b 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 93710b76289374a8d3ec4ae2ccf305c3236e8569..9e9aca271c0a83717d34e1f830266ca27ee8cd3e 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 010688dd9e49ced5fdf9e5dd808604304b27452b..22579d0d8ab8aaf4fceb205860ccf879da53a993 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 a0c244bc77c094a52f838a14da1bb1ea1a47babe..d671189ecee279991ebd8b2c40a957d3226f2ee0 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 b387863c245f3e7046e5b568de848946608dad90..c18dfa2ca034e746c328e12df4d6aa147f71b8cb 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 d460d71b425783ba9731433b93d05deb1e315901..1477e31d776327d8ccd86dc2864e19c5f3fa0007 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 */ +UNUSUAL_DEV(0x0781, 0x55e8, 0x0000, 0x9999, + "SanDisk", + "", + USB_SC_DEVICE, USB_PR_DEVICE, NULL, + US_FL_IGNORE_UAS), + /* Reported-by: Hongling Zeng */ UNUSUAL_DEV(0x090c, 0x2000, 0x0000, 0x9999, "Hiksemi", diff --git a/drivers/usb/typec/altmodes/displayport.c b/drivers/usb/typec/altmodes/displayport.c index ac84a6d64c2fbb85e01da953e44a09c652566481..b09b58d7311de9003a0d2eff901da5d720cfab5d 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 ae90688d23e400d08f895d2744bd68c89edc1f21..a884cec9ab7e88ae2a9f971121470119a2584bff 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 49926d6e72c71b895072ec252e5e1200085f4d4e..182c902c42f61cb421013962172ee5c153ea510b 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 f71dba8bf07c981a97c71f04bb00aca3b3738dd5..c54e42c7e6a16e1c0c820fd2943abf8749cfdb2b 100644 --- a/drivers/usb/typec/mux/fsa4480.c +++ b/drivers/usb/typec/mux/fsa4480.c @@ -12,6 +12,7 @@ #include #include #include +#include #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 d42da5720a251da3dc0700baa2b2103a5c4a20cb..cdbb7c11d714223b684cf43469c6ceb136d13996 100644 --- a/drivers/usb/typec/port-mapper.c +++ b/drivers/usb/typec/port-mapper.c @@ -8,6 +8,7 @@ #include #include +#include #include #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 19ab6647af706b0112440dcfebb47c996a31438c..a56e31b20c214fc509423d2f8602d3599c1dd2c1 100644 --- a/drivers/usb/typec/tcpm/tcpci.c +++ b/drivers/usb/typec/tcpm/tcpci.c @@ -17,6 +17,7 @@ #include #include #include +#include #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 fd1b80593367641a6f997da2fb97a2b7238f6982..b5a5ed40faea9cfcceef5550263968148646eb44 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 5ea884ef36af7062345f88733aa799d0e6640e1b..1a1f9e1f8e4e26a647b4ceb45f07219ef760ba20 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 7ee721a877c12d9d0380cec8a04e4aa0ae6b22af..dcf141ada07812295a6f07e41d77f95f98116010 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 9b23e901745215431252e0fc8e118cf30c5f167a..cecb8d11d23972dab0d8c15458b4052af7510b03 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 0669cca12ea1d4d753fb51f5d60d69fc1032be49..bea383f2db9de5bbf1804fbad9ee6b134407b932 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 75559601fe8f2863959291663248dcb974968210..8bf8fefb4f07bccc4be90a4b7f771d91294386b0 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 be98a879104ddd8eedff18e6cb11891631574dd0..dbc571763eff671fbe9c2532ac0c7e747e1a7c55 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 eae2b18a2d8ae45e3d1e3440ec0ac3e2fc6f27fe..92ebf1a2defd20c51fcc5c75035d72808ac6bbc1 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 9c5278a0c5d4090eb1ba4f967bbc53b4b90b4573..5a8f947fcece29f98c0458f9eb05c0c5ede2d244 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 0000000000000000000000000000000000000000..7b5222081bbb54c5637ce165391ac78136d33cec --- /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 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 7e801fee33bfcf3703c6aacbd50f3c26fe4fef97..a4f02ea3e3ef06ec98fa277e596bef78480680c5 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 139049368fdcf86f8174208d950448d340dfee25..7d02470f19b932306bfcd2f46691de3d93c9e84d 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 c6c4753f64153e39d7e6aa717831867c26bce87b..0eef8c6b98c8cbac798e68b5e3395d9e789600be 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 6c58335171410029d22cc62f4bb1288352258ee9..66bfc1d0a6dc82547282aebac7c20452022a4d8c 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 b7da24ca147576664f97261d501d6ffd353e7921..64d32c8fbf79b8184c00eeb6c8baf119ff13a66e 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 f1674f3ed923f0ab905e1092fb4243b82a59986b..b177a534b6a4247b0df0a8baf758204924681d0f 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 691978cddab7c43ff6937a72138e1a4f6916d901..e6b59d92107661bab59250fd004888a733816abb 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 1b47a2fc7d179cdcc1c032a2ac1deb9ccb81f62a..aba66b8e9d0339b7f9dbb6f5b3124c31f8df078a 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 4c0951307421c87af99f2d77ceba08f3ff039426..e13ec0975bef352a5fbdd751f1ae99b4781626ed 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 28e3fc0df4c6546f92cd96100c00fc678b9aec4e..3e8e80bbcb93b9363356bbe8a7a0bd6efd5e3e02 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 95af9ad94d16afb8406a5ef4b453db9c52a03faa..719f100aae60ddff099de99407ba7fb4b3591cfc 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 b95c4cb21c13f0b4a3ae47aba2916b49c398b3fa..60a621b00c656dbcc4aa637a25c87a1a94c330ab 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 150076ced9374b71ab69acbc6c0aa8d9e373ef45..b2f2af1046791d8423c91b79556bde384a2fe627 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 851d70200c6b8f5746fe02fc667a802f70336a71..a7254cab44cc2e24186f5aa67169f11857e7b8de 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 f3951253e393a69babe4493af5b005aeabcde867..2b8438d8a32412126d70690fb5d1457bf5e810da 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 e01d5f29f4d2521bfa39bb613bdcb8d74b76dd29..6dd3a524cd3529480b785dcc1e321b64aba4f607 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 a7f80ca0117472434cd1bd0e7acf22a4035d655e..c7d39da7e733b13b2760da3341c8991401043a0b 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 6d5e768487338b685ee4cbe97e9ebf3ff4ff2ceb..d480b94117cd778595d5b1a5a44c9063c0169d20 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 ef3a1e1b6cb0652e9267110cb0a21032a4a18147..fda9f4d6093f941d1ae794347bba2fea2cbbd6d0 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 29671e33a1714c8ca5c1e272ac58821e00078ef1..62879c218d4b1122caba0a493b2ad978debb37f8 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 4fe64519870f1ac0845d771618607d0ce53335e8..d83372d3e1a07b0324be755f5ef46d6f08a2ce20 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 2f2e93927f46950391ee3e954d10b93377bbb386..e13d9ab4f56496060ea3d967d42ef9b7318b9a1a 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 61a4141f8d6b2dc7319d90759abbc43132eeab1b..f15ca6fc400d19ab39699cb948b7a7e52285c24c 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 43e652a2adafbb04c35d345ca004690b8e7ccac4..b05d4e9d13b284a928056535707afe64e82f5c7b 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 969b458100fe5efebf067e37b1945396a528db5c..dfea7bd800cb4b17c43f47ecd7dce57929b1d49b 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 bf722daf19a952ed75edd5e9f9cac9286ae5e50d..0b8b28392eb7c594499e7ebdae5ffafd4d5a440a 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 cb449ab310a7a89aafa0ee04ee7ff6c8141dd7d5..afb7762f873f66c72cc5aa795a51ab22c15106dc 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 6759f7d040c89d3b3c01572579c854a900411157..f42488c019572479d8fdcfc1efd62b21d2995875 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 44e208da417c06333e79769086189e92b3adcfa0..474c80d210d18a5b1c7dd3410ca0975b6588755e 100644 --- a/fs/overlayfs/readdir.c +++ b/fs/overlayfs/readdir.c @@ -13,6 +13,7 @@ #include #include #include +#include #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 0819c739cc2ffce0dfefa84d3ff8f9f103eec191..dcccb4b4a66c7adfa818af5a2c8908de2473a44f 100644 --- a/fs/overlayfs/util.c +++ b/fs/overlayfs/util.c @@ -15,6 +15,7 @@ #include #include #include +#include #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 cc37f58b47dd7145cb6fdb55827291b63c23c622..1beb124e25f6f56a903fa72bc769e3ed30a7c4c8 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 e03c890de0a0682d3d786d8aa5b44ade346b929d..c0196be0e65fc0c6a3b965d70068bf87ddd036fe 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 ca435a3841b8a7a78c97540109a6b2f9d77e7a9e..b9ec9fe16a9822381b2d5e449f0abc395fba6386 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 ad7dd16db3e91ebe6ee9cab78fbd7ffc86ceb20e..45e94e18f4d59a7cefad33b890865b0cd2c17b46 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 024817d40c5f51e20f5f2882ed96587ae1bb2d3b..28bc334966237ae8e1948fd96837dedc14e8a40c 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 bab9f567d9b7b378a859bb1dabff960156c3c487..1468c16ea9b80ce1678bf151c42ecac93026b645 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 0c320d06809ca4e147a00e94632ac14e8e62fa43..a717be1626a3cca0c73aef8b0e91dba56540eaa8 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 b0b7254661e926cff37f565c48b8df0788ee7fb8..5ae847919da57cf51e8fc52abb1a112075d4021f 100644 --- a/fs/smb/client/smbdirect.c +++ b/fs/smb/client/smbdirect.c @@ -7,6 +7,7 @@ #include #include #include +#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 c08e3665150d74c326cd49b307d4edc969c6e937..75b3f491c3ad65f88a49b1e6ee50177ffc12b71d 100644 --- a/fs/smb/client/smbdirect.h +++ b/fs/smb/client/smbdirect.h @@ -15,6 +15,9 @@ #include #include +#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 266af17aa7d99af7166910d01914381012305137..191783f553ce88a34c83b8175cc5b74120b82201 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 0000000000000000000000000000000000000000..b9a385344ff31ce549224494ccbf11418805a52e --- /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 0000000000000000000000000000000000000000..ae9fdb05ce23146c18b70161b2b9604c95ed942c --- /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 0000000000000000000000000000000000000000..e5b15cc44a7ba5f7d2a3a7c12a43f1f7b5b848a2 --- /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 ee954e64ce7fea3d990aa1d9a55fd66c599f4191..e28ab4395e5ca404d8e8d8f735c3113b58bcc941 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 0000000000000000000000000000000000000000..f38a6d72b6dc2d4067c07d6a5c0377e526219e5c --- /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 6c1eaf04e24103c9b82ff28811c058e5203c4079..1216aa352d55e095a9cdbd45102725768b01e78f 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 39f203256c4f6b96745f8200c0c806f5e22396c0..6d1ce7f5da51c684c028287dfb0ed06bebcf1fda 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 c8c7f01159fed5b73b15fdd4e46de0f16ff908e7..48830bf180427c6b558ed445c7e319adb081f7d2 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 0ee4c21c6dbc7cb838f79d8f62255a3824167a59..5f2b9a1f722c763d37192f12bd4f5d831d999f14 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 c08416a7364bc4ef12ebe3c704a7b1d794e86d16..4cb0400ad616de14ff35741c6c819ab3a30c0298 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 20f564e9855234308afc6768d67635435d6c5bed..59b4fec5f2548cb1814f94604bda81f1eb25e0b6 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 c35db4896c37bde7d685b3c0b0cc6a2851f44191..6180b803795c44300acb9cb531ac1f5e3f6ecfea 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 d79a242b271d6e1ed7021b7c3e156cafb82d2787..4ac65c68bbf44b98db22c3dad2d83a224ce5278e 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 f98200cae637a06b31ba3dfd9c0c984a2107b684..21a2ecc1e53895662b68bfecc16be563459f6bdc 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 a8c23d945634b3c29b6e76aa894c51d0fe91d250..f35d03b4113b19798036d2993d67eb932ad8ce6f 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 a4d3816d252a08568ec67dc0d06a548d82a3343f..b672ca15f265538442bf61c266d580feef571917 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 c27329e2a5ad57851c55cbdaefc382ae6512a350..e71056553108508c9ac51172f989a2d54872085b 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 0598f36931de843f2c74b3599a56d73a223a62a8..42f374e828a2ae462eefeb097c95bcceac934111 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 0000000000000000000000000000000000000000..56b092a2a4c40f9c7d610c14635b61c3e1a1603f --- /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 + */ + +#ifndef _INDUSTRIAL_IO_ADC_HELPERS_H_ +#define _INDUSTRIAL_IO_ADC_HELPERS_H_ + +#include + +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 e45b7dfbec35c094942a3034fc6057a7960b9772..e59d909cb65924b4872cadd4b7e5e894c13c189f 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 3b8d618bb3dfaa6e32c2c713b12d11af6bb22ec2..5c84ec4a981001dfba3b369f811368bab70a3117 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 07a0e8132e88278c82be740e12ca2d9078710206..d11668f14a3e17654fcf17a4e853d4b493205019 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 #include #include #include +#include #include #include /* 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 a34dcf6a6001e3f9ff3bfd6dc26759dbc1ddfc70..ce3cf0addb2e2bcc260c7f2b0e7fedfe15835423 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 f5aef8784692102d41f84132ba3f7bf9353c14c8..55cfebc658e6831659885adde2e97251efd13f77 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 97ac253df62c13a758e6dfbc55f90b380ee6cffe..e4b8808823ad87821887877b4033275a4a8896d7 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/key.h b/include/linux/key.h index ba05de8579ecc5ca31a428ef963bd4256403f5ea..81b8f05c68985c6f0a5c5bbe0f1fd6661912c618 100644 --- a/include/linux/key.h +++ b/include/linux/key.h @@ -236,7 +236,7 @@ struct key { #define KEY_FLAG_ROOT_CAN_INVAL 7 /* set if key can be invalidated by root without permission */ #define KEY_FLAG_KEEP 8 /* set if key should not be removed */ #define KEY_FLAG_UID_KEYRING 9 /* set if key is a user or user session keyring */ -#define KEY_FLAG_FINAL_PUT 10 /* set if final put has happened on key */ +#define KEY_FLAG_USER_ALIVE 10 /* set if final put has not happened on key yet */ /* the key type and key description string * - the desc is used to match a key against search criteria diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h index ebcee9328168b918df2e17ace0c94278e71ca053..6077972e8b45de3d07881c0226459d815dd1f83d 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 8050f77c3b64f8512afcb7ccde889a922ae89ab7..92e1420fccdffc9de9f49da9061546cc1e0c89d1 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 d3ee0e5162f0cc6b49d1d3e8fb3c850dfe01c081..4880f434c021c9ef11851f280f83bd0badca9874 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 51308f65b72fdd5514c84eac479abbcd0cd138e6..b65a1b9f2116c2a1d5c12bcf737d17965b678179 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 515676ebe59875fa0ab8a4e772542bdc90ead8e3..615a560d9edb84d1a5b8a1d8a374b8bf7c9c772e 100644 --- a/include/linux/nvmem-provider.h +++ b/include/linux/nvmem-provider.h @@ -137,25 +137,6 @@ struct nvmem_config { struct device *base_dev; }; -/** - * 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 * @@ -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 bc5bfc98176baad5a95d929f7fe5c51217aeb1b9..f718dd4789e51b6eedfcd5602e87bbe94836c273 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 98030accf641feecf33dfbe891a1236fb94f4ae3..72ff44cca864b6269f495b5d81452d0311bc248a 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 4612ef09a0c760bd303368a0fe4ad21c1f52e02e..3b4c36705a9b7ee365c62ee369cd4e8256785c84 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 743b4afaad4c89a6028e592be2cae2643614c89b..914b5e97e05647dfa02d8dfb0d231bfcd0c945f8 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 7d902d8c054b288eb7393a056dcaca893d47be57..75247486616bb7aed26442fc69a0d537b0cccd41 100644 --- a/include/linux/thunderbolt.h +++ b/include/linux/thunderbolt.h @@ -11,6 +11,13 @@ #ifndef THUNDERBOLT_H_ #define THUNDERBOLT_H_ +#include + +struct fwnode_handle; +struct device; + +#if IS_REACHABLE(CONFIG_USB4) + #include #include #include @@ -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 0b8b32bf0655109d368c5dacc23ca5efcbb5aa80..bb2c52f4fc9497881a436b4a0eb4773864faa2bc 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 f636f55c427d148e7ed0e6dd06852a5ebd220e99..0414d9e6b4fcd5cf41d99de50549693810b9b0d9 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 1b861f2100b69f120971c7dd503d6635db1fb468..08f89a59836621b2c8864c46c4ed8883b3f9045b 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 b46738701f8dc46085f251379873b6a8a008d99d..1b2545b4363bcf3ef97a53a004ebf456eb9d5d05 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 6e38fb9d21174a402485e5cc9acf209a5caceb65..d8c4e9f73839c433301623b32da060cc0b95146c 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 0000000000000000000000000000000000000000..45288c392f6e05bceb99b1904ea0551e87753555 --- /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 + */ +#ifndef __LINUX_XHCI_SIDEBAND_H +#define __LINUX_XHCI_SIDEBAND_H + +#include +#include + +#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/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 2b261e74e2c4cf355730699a92738111eab9bdc9..a760f05fa3fbf63c09e2ec2a9ca36c0561a4530e 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -242,6 +242,7 @@ struct adv_info { __u8 mesh; __u8 instance; __u8 handle; + __u8 sid; __u32 flags; __u16 timeout; __u16 remaining_time; @@ -546,6 +547,7 @@ struct hci_dev { struct hci_conn_hash conn_hash; struct list_head mesh_pending; + struct mutex mgmt_pending_lock; struct list_head mgmt_pending; struct list_head reject_list; struct list_head accept_list; @@ -1550,13 +1552,14 @@ struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, bdaddr_t *dst, u16 timeout); struct hci_conn *hci_bind_cis(struct hci_dev *hdev, bdaddr_t *dst, __u8 dst_type, struct bt_iso_qos *qos); -struct hci_conn *hci_bind_bis(struct hci_dev *hdev, bdaddr_t *dst, +struct hci_conn *hci_bind_bis(struct hci_dev *hdev, bdaddr_t *dst, __u8 sid, struct bt_iso_qos *qos, __u8 base_len, __u8 *base); struct hci_conn *hci_connect_cis(struct hci_dev *hdev, bdaddr_t *dst, __u8 dst_type, struct bt_iso_qos *qos); struct hci_conn *hci_connect_bis(struct hci_dev *hdev, bdaddr_t *dst, - __u8 dst_type, struct bt_iso_qos *qos, + __u8 dst_type, __u8 sid, + struct bt_iso_qos *qos, __u8 data_len, __u8 *data); struct hci_conn *hci_pa_create_sync(struct hci_dev *hdev, bdaddr_t *dst, __u8 dst_type, __u8 sid, struct bt_iso_qos *qos); @@ -1831,6 +1834,7 @@ int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, void hci_adv_instances_clear(struct hci_dev *hdev); struct adv_info *hci_find_adv_instance(struct hci_dev *hdev, u8 instance); +struct adv_info *hci_find_adv_sid(struct hci_dev *hdev, u8 sid); struct adv_info *hci_get_next_instance(struct hci_dev *hdev, u8 instance); struct adv_info *hci_add_adv_instance(struct hci_dev *hdev, u8 instance, u32 flags, u16 adv_data_len, u8 *adv_data, @@ -1838,7 +1842,7 @@ struct adv_info *hci_add_adv_instance(struct hci_dev *hdev, u8 instance, u16 timeout, u16 duration, s8 tx_power, u32 min_interval, u32 max_interval, u8 mesh_handle); -struct adv_info *hci_add_per_instance(struct hci_dev *hdev, u8 instance, +struct adv_info *hci_add_per_instance(struct hci_dev *hdev, u8 instance, u8 sid, u32 flags, u8 data_len, u8 *data, u32 min_interval, u32 max_interval); int hci_set_adv_instance_data(struct hci_dev *hdev, u8 instance, @@ -2400,7 +2404,6 @@ void mgmt_advertising_added(struct sock *sk, struct hci_dev *hdev, u8 instance); void mgmt_advertising_removed(struct sock *sk, struct hci_dev *hdev, u8 instance); -void mgmt_adv_monitor_removed(struct hci_dev *hdev, u16 handle); int mgmt_phy_configuration_changed(struct hci_dev *hdev, struct sock *skip); void mgmt_adv_monitor_device_lost(struct hci_dev *hdev, u16 handle, bdaddr_t *bdaddr, u8 addr_type); diff --git a/include/net/bluetooth/hci_sync.h b/include/net/bluetooth/hci_sync.h index 72558c826aa1b40feb2345230b0f1e324b369c27..5224f57f6af2c410b5ee1c737bb14e279ef4a309 100644 --- a/include/net/bluetooth/hci_sync.h +++ b/include/net/bluetooth/hci_sync.h @@ -115,8 +115,8 @@ int hci_enable_ext_advertising_sync(struct hci_dev *hdev, u8 instance); int hci_enable_advertising_sync(struct hci_dev *hdev); int hci_enable_advertising(struct hci_dev *hdev); -int hci_start_per_adv_sync(struct hci_dev *hdev, u8 instance, u8 data_len, - u8 *data, u32 flags, u16 min_interval, +int hci_start_per_adv_sync(struct hci_dev *hdev, u8 instance, u8 sid, + u8 data_len, u8 *data, u32 flags, u16 min_interval, u16 max_interval, u16 sync_interval); int hci_disable_per_advertising_sync(struct hci_dev *hdev, u8 instance); diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h index 629368ab2787f9ddeff8dbb0a825d9d30e5b0f0c..638948be4c50e2e6f5899ded17943de55d4f94f5 100644 --- a/include/net/sch_generic.h +++ b/include/net/sch_generic.h @@ -973,14 +973,6 @@ static inline void qdisc_qstats_qlen_backlog(struct Qdisc *sch, __u32 *qlen, *backlog = qstats.backlog; } -static inline void qdisc_tree_flush_backlog(struct Qdisc *sch) -{ - __u32 qlen, backlog; - - qdisc_qstats_qlen_backlog(sch, &qlen, &backlog); - qdisc_tree_reduce_backlog(sch, qlen, backlog); -} - static inline void qdisc_purge_queue(struct Qdisc *sch) { __u32 qlen, backlog; diff --git a/include/net/sock.h b/include/net/sock.h index 85e17da5c9db157d9b895f7fa5538ff75e4745f9..70c0b570a21f9ffb3b33705c9f531412610ff014 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -3009,8 +3009,11 @@ int sock_ioctl_inout(struct sock *sk, unsigned int cmd, int sk_ioctl(struct sock *sk, unsigned int cmd, void __user *arg); static inline bool sk_is_readable(struct sock *sk) { - if (sk->sk_prot->sock_is_readable) - return sk->sk_prot->sock_is_readable(sk); + const struct proto *prot = READ_ONCE(sk->sk_prot); + + if (prot->sock_is_readable) + return prot->sock_is_readable(sk); + return false; } #endif /* _SOCK_H */ diff --git a/include/sound/jack.h b/include/sound/jack.h index 36dc104c114537efbf882daa885508dd32361b76..715b95983188aa10b4563f6d40627eee69a731bb 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 0000000000000000000000000000000000000000..f7e2449fe1b3f1ffe8a459bdabcade908388d74f --- /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 0000000000000000000000000000000000000000..124acb1939e57f3d91882c8696312a14c475d1c4 --- /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 + +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 9253e83b9bb43319395e08121972b523bbe44799..6c631eec23e32b0f68085e6457612025be2d553a 100644 --- a/include/trace/events/power.h +++ b/include/trace/events/power.h @@ -337,53 +337,6 @@ DEFINE_EVENT(wakeup_source, wakeup_source_deactivate, TP_ARGS(name, state) ); -/* - * 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 */ diff --git a/include/uapi/drm/xe_drm.h b/include/uapi/drm/xe_drm.h index 9c08738c3b918ee387f51a68ba080057c6d5716f..6a702ba7817c38778cfea3506d682e22821623d4 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 5a199f3d4a26a22a94e51d4b53aeed3767c97bce..3b2524e4b667d1e7cc02ff5cb674e7c2ac069a66 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 b32acc229024b39cd2badda4112e9051745aeed5..88faba506c3d9e48ee8c08a5746112b9dd98f757 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 56c7e3fc666fc578a545d15a9767e58f3a4a2f3b..77d9d6af46da878cf30df6e3e31758a6f8f61afa 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 e9d39c48520af18b8a000c28e3e5b73155aa3d4a..e5b0c492aa184619df62d8a6fc790bfc11c66449 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 +#include /* * 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 0000000000000000000000000000000000000000..745b3338fc06f67073adeacbeb5345ae94d322c1 --- /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 + +/* 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 fa374afbaa51a287c3d42f6a853f715f96b338ee..692462d50c8c0c8eabfbcd75bf1323b0789f6031 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 c7a9cecf528ed1463bedc6486a9f76de498c4e67..cf759c172083c543207a24496042be5564a460f0 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 0ea7a435d1de55c133d38d9a733aec0e8e8df0aa..d59c12277d58ce35d072529697faec7dc7e7dd76 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 8cce3ebd813f31f308842cb7b757107cc93e0461..2ea65f3cef72253bffa991b50c336a97a4e4618b 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 4d2c209d1a4112d050bec6b1aa5be403da154176..5d83c7adc73996d914d6a96cb7fe46a772182a00 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 d13f3e8f6c72a7f0fe83a97873917b28232ca9d1..e16633fd663025305bd9523011fd4998fd220a23 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 1513431587a72d55632b5fa404840f396ec4e2a0..797247a34cb7ebc74caeb2212912d1698147aae9 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 b753695c5a8ff25a49c0efb90b3346e70e14309a..5dd0f0a34a73cabfbfa832359828a4186a86a212 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 77c44924cf54a34f5a2a238079b4521baf72c8c7..85fc068f0083dd6bb9777eef1fa61c7ea198c38b 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 3d64e69cc03e93e283e143beab50be83a0c7ca53..413ac6ea37021bc8ae260f624ca2745ed85333fc 100644 --- a/kernel/module/main.c +++ b/kernel/module/main.c @@ -169,6 +169,30 @@ static inline void add_taint_module(struct module *mod, unsigned flag, set_bit(flag, &mod->taints); } +/* + * 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 c0cc7ae41106296610f2d1bb2b8c6c3c13f4247a..f92443561d365a92e083e8890d11e14046765e1e 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 1596812f7f12138dd9b8cad029d763239030af17..b473ff056f493cef9b68b9993c7b0aabd76a40d2 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 56b21219442b65d4e37765ef802353c0fc6f9bfc..486c00536207d58a621ee97cf2e83834cdb186aa 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 1396674fa7227a54b0704edc46221830527b2f4e..ad04a5c3162a26ad6071775e5433b42b2105fa90 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 5aa38b2cf40a7216c1ee6a1cb660111222260b03..3c90574bd904f1c7c8ffc5956d7b7fc8740dd6cf 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 a7291685902e8c781b574363c2b9f6c33d08afd4..4203fad56b6c585d3ddaed32bf0f3ab8b5b730dd 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 e24509bd0af554ba7a8e738ac131c9368150ce17..00fc38d70e868adff3716f2a488ce4aea76c5609 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 2048560264bb485da2df1181b92152e4d74d5a8f..ea8b364b6818fae7e4fbc78ebfea948fa7e8cec1 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 3bef0754cf73602a11602b463ac9b6da170049d5..97f37b5bae669cfcf80363de052cd3d2265c108f 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 45dae7da70e17dc5b71fa0c9e41ae5442c689d1d..d48b80f3f007e1f4e35101de7ba68c78abf173ac 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 de332e98d6f5b5e6be53939bff2a8fd1d7862ff2..650d54d7e14da687cbeea54b0a610d5616f8f35e 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 969d4ad510df13b97320a531d15ea1749f066b85..f9193f952f49945297479483755d68a34c6d4ffe 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 29127dd05d636ad62fa9ae6c858b5e3821447a0e..5be0a4e60ab1ec2233463030c17b16578898cde6 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 dfd3f800ac9b9d1519c0814c7470e384335789b1..75ce3e134b7c7a825a69ea96d882af97c64c64c6 100644 --- a/lib/raid6/algos.c +++ b/lib/raid6/algos.c @@ -76,6 +76,12 @@ const struct raid6_calls * const raid6_algos[] = { #ifdef CONFIG_CPU_HAS_LSX &raid6_lsx, #endif +#endif +#ifdef CONFIG_RISCV_ISA_V + &raid6_rvvx1, + &raid6_rvvx2, + &raid6_rvvx4, + &raid6_rvvx8, #endif &raid6_intx8, &raid6_intx4, @@ -109,6 +115,9 @@ const struct raid6_recov_calls *const raid6_recov_algos[] = { #ifdef CONFIG_CPU_HAS_LSX &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 0000000000000000000000000000000000000000..f29303795ccfe2db5e7d53fd4939623cdd8980fd --- /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 + */ + +#include +#include +#include +#include + +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 0000000000000000000000000000000000000000..f0887344b274cb11cc6fd10a20f2c40549b43b43 --- /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 + * + * Based on neon.uc: + * Copyright 2002-2004 H. Peter Anvin + */ + +#include +#include +#include +#include +#include +#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 0000000000000000000000000000000000000000..94044a1b707b7a472cd44d4b68ff4f82ba392697 --- /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 f8bb8f070d0d8f47e5dd15205af9bcfbcf7177c9..781be3240e2163ed7d185dd9bd12cfa08d1c4f08 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/Kconfig b/mm/damon/Kconfig index 551745df011b757cd8fea532e51ece2459d6e082..c93d0c56b96390a16f017ad719aa7842e96b76e3 100644 --- a/mm/damon/Kconfig +++ b/mm/damon/Kconfig @@ -4,7 +4,6 @@ menu "Data Access Monitoring" config DAMON bool "DAMON: Data Access Monitoring Framework" - default y help This builds a framework that allows kernel subsystems to monitor access frequency of each memory region. The information can be useful diff --git a/mm/damon/modules-common.c b/mm/damon/modules-common.c index 7cf96574cde7585fedf7b0d9f3e4841aeda798e2..86d58f8c4f63585d528f29ebd1d5afddb97ecf14 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 */ diff --git a/mm/damon/modules-common.h b/mm/damon/modules-common.h index f49cdb4170051eb6cf8aa7a71846e2aee6c219f2..f103ad55636872b2bf61e1f526aad454ba9b02e7 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 */ diff --git a/mm/damon/ops-common.c b/mm/damon/ops-common.c index 0db1fc70c84dcbad04d49d7da84cc49d1e4419d5..b43620fee6bb21436b63998b70c8742dbc252217 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 */ diff --git a/mm/damon/ops-common.h b/mm/damon/ops-common.h index 18d837d11bcee96fd4190b3cac3f7895bb013801..cc9f5da9c012753f0fa2f3e708d498ee877ba33d 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 */ diff --git a/mm/damon/paddr.c b/mm/damon/paddr.c index e8464f7e0014102d58d87d4048716263364103d6..4102a8c5f9926ddfc32405072bca84dea80bdab0 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 */ diff --git a/mm/damon/sysfs-common.c b/mm/damon/sysfs-common.c index 70edf45c21740a19e5c8161b28047c294ba3d133..ffaf285e241a1e3733a53caf9ec5a2829d8da097 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 */ diff --git a/mm/damon/sysfs-common.h b/mm/damon/sysfs-common.h index 70d84bdc9f5fad5f21f6f1412152f481cdb8f975..2099adee11d0523f9752de722ac1ebea14e46563 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 */ diff --git a/mm/damon/vaddr.c b/mm/damon/vaddr.c index e6d99106a7f9ab6df097a66dac0e9a0ca535dfee..46554e49a478950bd69938cb07328ea3449df430 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 */ diff --git a/mm/hugetlb.c b/mm/hugetlb.c index f0b1d53079f9e072ba73ad1746f0e53510b9de8d..8746ed2fec135b646ba28536fbb4c816461a058a 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 9733a22c46c1d1e0a1a2917902810524cbb65e38..c6c5b2bbede0cc6c8b7ebe4198fc236f0ddf7d8e 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 "); +MODULE_DESCRIPTION("Test cases for KMSAN"); diff --git a/mm/madvise.c b/mm/madvise.c index 8433ac9b27e097727155e7998a138b293925470a..5f7a66a1617e39e3a9c133990fcdebd13e1fe654 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 72fd72e156b1a5dc8706126115c7f137358b6d01..3b1dfd08338bd322c6d71fff8dd0715d3a0006ba 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 83e359754961fb4fa7d279530bb78b2c48010ce7..60f6b8d0d5f0ba6abaec8c48c4229cb60d4371b3 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 b8eea5b3c06415375039bdb224d63a3eaa92fdcc..72b0ff0d4bae1e7be5c1f5963e2d7a4bbc7a05c0 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); } diff --git a/mm/vma.c b/mm/vma.c index 1c6595f282e5215861099da1e1b4e4bbfb688c9d..726b2a31ce59a9b70485c9f21132bbab862cf2e9 100644 --- a/mm/vma.c +++ b/mm/vma.c @@ -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 */ diff --git a/mm/vma.h b/mm/vma.h index 9a8af9be29a87ad2a74aa778913a3930aad1a094..0db066e7a45d408eb9a3993774eabc1e82354334 100644 --- a/mm/vma.h +++ b/mm/vma.h @@ -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 6f740f070b3dab920e5d7d77286e3eda8b7ee560..429ae5339bfef2ab86ec480d4cec48d924a0243f 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 27f0ab146026b475ba71093799fbe96d55bb2b4c..2d1ffc4d9462667ff97c141b3f745c1b6bff0e82 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 e0c96d0da8d599c60582c9fa020e1e3934fe2b47..23a88305f900cf405efd0808eb2a4e098a653617 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 b068651984fe3dec6c23337ae095a6f13a14ffa3..73ea7e67f05a7d67e283a70c6b6c50487d9e73fc 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 ded2f0df2ee66419a1e956e60ada45017193ae27..acef984f3367094ec6d30419166b8462c88181b3 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 b790bb92ed1c91050e7bd277979c8a69aab61a67..6ef8b2a57a9bf1a54ec3a767c92d41557beb00f1 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 8d9fba0690011d6225982462b419e28cd4cf813a..0c9e7775aa54e2848e0c14f1359c1614a4409874 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 3891a3923d6cb30a8157c1883b102d526f9ebf78..a69bfbc8b6790db057f3e947c71e86750aef66f5 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 adbadb436033c11e9e63f9abca90773fd3324eb5..350b149e48bebfb403572c10065d1a43b1b28851 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/eir.c b/net/bluetooth/eir.c index 1bc51e2b05a3474b12b25e7f396d3475cd6944dd..3f72111ba651f9c8be32a1a73c05258bec136b07 100644 --- a/net/bluetooth/eir.c +++ b/net/bluetooth/eir.c @@ -242,7 +242,7 @@ u8 eir_create_per_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr) return ad_len; } -u8 eir_create_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr) +u8 eir_create_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr, u8 size) { struct adv_info *adv = NULL; u8 ad_len = 0, flags = 0; @@ -286,7 +286,7 @@ u8 eir_create_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr) /* If flags would still be empty, then there is no need to * include the "Flags" AD field". */ - if (flags) { + if (flags && (ad_len + eir_precalc_len(1) <= size)) { ptr[0] = 0x02; ptr[1] = EIR_FLAGS; ptr[2] = flags; @@ -316,7 +316,8 @@ skip_flags: } /* Provide Tx Power only if we can provide a valid value for it */ - if (adv_tx_power != HCI_TX_POWER_INVALID) { + if (adv_tx_power != HCI_TX_POWER_INVALID && + (ad_len + eir_precalc_len(1) <= size)) { ptr[0] = 0x02; ptr[1] = EIR_TX_POWER; ptr[2] = (u8)adv_tx_power; @@ -366,17 +367,19 @@ u8 eir_create_scan_rsp(struct hci_dev *hdev, u8 instance, u8 *ptr) void *eir_get_service_data(u8 *eir, size_t eir_len, u16 uuid, size_t *len) { - while ((eir = eir_get_data(eir, eir_len, EIR_SERVICE_DATA, len))) { + size_t dlen; + + while ((eir = eir_get_data(eir, eir_len, EIR_SERVICE_DATA, &dlen))) { u16 value = get_unaligned_le16(eir); if (uuid == value) { if (len) - *len -= 2; + *len = dlen - 2; return &eir[2]; } - eir += *len; - eir_len -= *len; + eir += dlen; + eir_len -= dlen; } return NULL; diff --git a/net/bluetooth/eir.h b/net/bluetooth/eir.h index 5c89a05e8b290583529467e14193dbb68ddf49aa..9372db83f912fae1e797fce043216ecfa789a113 100644 --- a/net/bluetooth/eir.h +++ b/net/bluetooth/eir.h @@ -9,7 +9,7 @@ void eir_create(struct hci_dev *hdev, u8 *data); -u8 eir_create_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr); +u8 eir_create_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr, u8 size); u8 eir_create_scan_rsp(struct hci_dev *hdev, u8 instance, u8 *ptr); u8 eir_create_per_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr); diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 99efeed6a766c08e05234c4281ed6251e8a4d498..4f379184df5b1b6851ef57eeecf8768f4444213b 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -1501,8 +1501,8 @@ static int qos_set_bis(struct hci_dev *hdev, struct bt_iso_qos *qos) /* This function requires the caller holds hdev->lock */ static struct hci_conn *hci_add_bis(struct hci_dev *hdev, bdaddr_t *dst, - struct bt_iso_qos *qos, __u8 base_len, - __u8 *base) + __u8 sid, struct bt_iso_qos *qos, + __u8 base_len, __u8 *base) { struct hci_conn *conn; int err; @@ -1543,6 +1543,7 @@ static struct hci_conn *hci_add_bis(struct hci_dev *hdev, bdaddr_t *dst, return conn; conn->state = BT_CONNECT; + conn->sid = sid; hci_conn_hold(conn); return conn; @@ -2062,7 +2063,8 @@ static int create_big_sync(struct hci_dev *hdev, void *data) if (qos->bcast.bis) sync_interval = interval * 4; - err = hci_start_per_adv_sync(hdev, qos->bcast.bis, conn->le_per_adv_data_len, + err = hci_start_per_adv_sync(hdev, qos->bcast.bis, conn->sid, + conn->le_per_adv_data_len, conn->le_per_adv_data, flags, interval, interval, sync_interval); if (err) @@ -2134,7 +2136,7 @@ static void create_big_complete(struct hci_dev *hdev, void *data, int err) } } -struct hci_conn *hci_bind_bis(struct hci_dev *hdev, bdaddr_t *dst, +struct hci_conn *hci_bind_bis(struct hci_dev *hdev, bdaddr_t *dst, __u8 sid, struct bt_iso_qos *qos, __u8 base_len, __u8 *base) { @@ -2156,7 +2158,7 @@ struct hci_conn *hci_bind_bis(struct hci_dev *hdev, bdaddr_t *dst, base, base_len); /* We need hci_conn object using the BDADDR_ANY as dst */ - conn = hci_add_bis(hdev, dst, qos, base_len, eir); + conn = hci_add_bis(hdev, dst, sid, qos, base_len, eir); if (IS_ERR(conn)) return conn; @@ -2207,20 +2209,35 @@ static void bis_mark_per_adv(struct hci_conn *conn, void *data) } struct hci_conn *hci_connect_bis(struct hci_dev *hdev, bdaddr_t *dst, - __u8 dst_type, struct bt_iso_qos *qos, + __u8 dst_type, __u8 sid, + struct bt_iso_qos *qos, __u8 base_len, __u8 *base) { struct hci_conn *conn; int err; struct iso_list_data data; - conn = hci_bind_bis(hdev, dst, qos, base_len, base); + conn = hci_bind_bis(hdev, dst, sid, qos, base_len, base); if (IS_ERR(conn)) return conn; if (conn->state == BT_CONNECTED) return conn; + /* Check if SID needs to be allocated then search for the first + * available. + */ + if (conn->sid == HCI_SID_INVALID) { + u8 sid; + + for (sid = 0; sid <= 0x0f; sid++) { + if (!hci_find_adv_sid(hdev, sid)) { + conn->sid = sid; + break; + } + } + } + data.big = qos->bcast.big; data.bis = qos->bcast.bis; diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 3b49828160b739390d646ed793be8941fbdc02e3..07a8b4281a3975dd5d2ab12c3bb6662ea508a5e7 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1584,6 +1584,19 @@ struct adv_info *hci_find_adv_instance(struct hci_dev *hdev, u8 instance) return NULL; } +/* This function requires the caller holds hdev->lock */ +struct adv_info *hci_find_adv_sid(struct hci_dev *hdev, u8 sid) +{ + struct adv_info *adv; + + list_for_each_entry(adv, &hdev->adv_instances, list) { + if (adv->sid == sid) + return adv; + } + + return NULL; +} + /* This function requires the caller holds hdev->lock */ struct adv_info *hci_get_next_instance(struct hci_dev *hdev, u8 instance) { @@ -1736,7 +1749,7 @@ struct adv_info *hci_add_adv_instance(struct hci_dev *hdev, u8 instance, } /* This function requires the caller holds hdev->lock */ -struct adv_info *hci_add_per_instance(struct hci_dev *hdev, u8 instance, +struct adv_info *hci_add_per_instance(struct hci_dev *hdev, u8 instance, u8 sid, u32 flags, u8 data_len, u8 *data, u32 min_interval, u32 max_interval) { @@ -1748,6 +1761,7 @@ struct adv_info *hci_add_per_instance(struct hci_dev *hdev, u8 instance, if (IS_ERR(adv)) return adv; + adv->sid = sid; adv->periodic = true; adv->per_adv_data_len = data_len; @@ -1877,10 +1891,8 @@ void hci_free_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor) if (monitor->handle) idr_remove(&hdev->adv_monitors_idr, monitor->handle); - if (monitor->state != ADV_MONITOR_STATE_NOT_REGISTERED) { + if (monitor->state != ADV_MONITOR_STATE_NOT_REGISTERED) hdev->adv_monitors_cnt--; - mgmt_adv_monitor_removed(hdev, monitor->handle); - } kfree(monitor); } @@ -2487,6 +2499,7 @@ struct hci_dev *hci_alloc_dev_priv(int sizeof_priv) mutex_init(&hdev->lock); mutex_init(&hdev->req_lock); + mutex_init(&hdev->mgmt_pending_lock); ida_init(&hdev->unset_handle_ida); @@ -3417,23 +3430,18 @@ static void hci_link_tx_to(struct hci_dev *hdev, __u8 type) bt_dev_err(hdev, "link tx timeout"); - rcu_read_lock(); + hci_dev_lock(hdev); /* Kill stalled connections */ - list_for_each_entry_rcu(c, &h->list, list) { + list_for_each_entry(c, &h->list, list) { if (c->type == type && c->sent) { bt_dev_err(hdev, "killing stalled connection %pMR", &c->dst); - /* hci_disconnect might sleep, so, we have to release - * the RCU read lock before calling it. - */ - rcu_read_unlock(); hci_disconnect(c, HCI_ERROR_REMOTE_USER_TERM); - rcu_read_lock(); } } - rcu_read_unlock(); + hci_dev_unlock(hdev); } static struct hci_chan *hci_chan_sent(struct hci_dev *hdev, __u8 type, diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c index 62d1ff951ebe6058cca17f5b620980f366ae087a..6687f2a4d1eb44c154f471ed0c4cad7e8d437c88 100644 --- a/net/bluetooth/hci_sync.c +++ b/net/bluetooth/hci_sync.c @@ -1261,10 +1261,12 @@ int hci_setup_ext_adv_instance_sync(struct hci_dev *hdev, u8 instance) hci_cpu_to_le24(adv->min_interval, cp.min_interval); hci_cpu_to_le24(adv->max_interval, cp.max_interval); cp.tx_power = adv->tx_power; + cp.sid = adv->sid; } else { hci_cpu_to_le24(hdev->le_adv_min_interval, cp.min_interval); hci_cpu_to_le24(hdev->le_adv_max_interval, cp.max_interval); cp.tx_power = HCI_ADV_TX_POWER_NO_PREFERENCE; + cp.sid = 0x00; } secondary_adv = (flags & MGMT_ADV_FLAG_SEC_MASK); @@ -1559,7 +1561,8 @@ static int hci_enable_per_advertising_sync(struct hci_dev *hdev, u8 instance) static int hci_adv_bcast_annoucement(struct hci_dev *hdev, struct adv_info *adv) { u8 bid[3]; - u8 ad[4 + 3]; + u8 ad[HCI_MAX_EXT_AD_LENGTH]; + u8 len; /* Skip if NULL adv as instance 0x00 is used for general purpose * advertising so it cannot used for the likes of Broadcast Announcement @@ -1585,14 +1588,16 @@ static int hci_adv_bcast_annoucement(struct hci_dev *hdev, struct adv_info *adv) /* Generate Broadcast ID */ get_random_bytes(bid, sizeof(bid)); - eir_append_service_data(ad, 0, 0x1852, bid, sizeof(bid)); - hci_set_adv_instance_data(hdev, adv->instance, sizeof(ad), ad, 0, NULL); + len = eir_append_service_data(ad, 0, 0x1852, bid, sizeof(bid)); + memcpy(ad + len, adv->adv_data, adv->adv_data_len); + hci_set_adv_instance_data(hdev, adv->instance, len + adv->adv_data_len, + ad, 0, NULL); return hci_update_adv_data_sync(hdev, adv->instance); } -int hci_start_per_adv_sync(struct hci_dev *hdev, u8 instance, u8 data_len, - u8 *data, u32 flags, u16 min_interval, +int hci_start_per_adv_sync(struct hci_dev *hdev, u8 instance, u8 sid, + u8 data_len, u8 *data, u32 flags, u16 min_interval, u16 max_interval, u16 sync_interval) { struct adv_info *adv = NULL; @@ -1603,9 +1608,28 @@ int hci_start_per_adv_sync(struct hci_dev *hdev, u8 instance, u8 data_len, if (instance) { adv = hci_find_adv_instance(hdev, instance); - /* Create an instance if that could not be found */ - if (!adv) { - adv = hci_add_per_instance(hdev, instance, flags, + if (adv) { + if (sid != HCI_SID_INVALID && adv->sid != sid) { + /* If the SID don't match attempt to find by + * SID. + */ + adv = hci_find_adv_sid(hdev, sid); + if (!adv) { + bt_dev_err(hdev, + "Unable to find adv_info"); + return -EINVAL; + } + } + + /* Turn it into periodic advertising */ + adv->periodic = true; + adv->per_adv_data_len = data_len; + if (data) + memcpy(adv->per_adv_data, data, data_len); + adv->flags = flags; + } else if (!adv) { + /* Create an instance if that could not be found */ + adv = hci_add_per_instance(hdev, instance, sid, flags, data_len, data, sync_interval, sync_interval); @@ -1812,7 +1836,8 @@ static int hci_set_ext_adv_data_sync(struct hci_dev *hdev, u8 instance) return 0; } - len = eir_create_adv_data(hdev, instance, pdu->data); + len = eir_create_adv_data(hdev, instance, pdu->data, + HCI_MAX_EXT_AD_LENGTH); pdu->length = len; pdu->handle = adv ? adv->handle : instance; @@ -1843,7 +1868,7 @@ static int hci_set_adv_data_sync(struct hci_dev *hdev, u8 instance) memset(&cp, 0, sizeof(cp)); - len = eir_create_adv_data(hdev, instance, cp.data); + len = eir_create_adv_data(hdev, instance, cp.data, sizeof(cp.data)); /* There's nothing to do if the data hasn't changed */ if (hdev->adv_data_len == len && diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c index fc5af8639b1eff7d9efa8d88e52ec1d8b1f0a3ca..6724adce615b62f901b9da525bf3df94adbd5610 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/iso.c b/net/bluetooth/iso.c index 6e2c752aaa8fd5f978e79723dfe9d925092c1523..3c2c98eecc62675be10161ba40046be871bb3bb7 100644 --- a/net/bluetooth/iso.c +++ b/net/bluetooth/iso.c @@ -336,7 +336,7 @@ static int iso_connect_bis(struct sock *sk) struct hci_dev *hdev; int err; - BT_DBG("%pMR", &iso_pi(sk)->src); + BT_DBG("%pMR (SID 0x%2.2x)", &iso_pi(sk)->src, iso_pi(sk)->bc_sid); hdev = hci_get_route(&iso_pi(sk)->dst, &iso_pi(sk)->src, iso_pi(sk)->src_type); @@ -365,7 +365,7 @@ static int iso_connect_bis(struct sock *sk) /* Just bind if DEFER_SETUP has been set */ if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) { - hcon = hci_bind_bis(hdev, &iso_pi(sk)->dst, + hcon = hci_bind_bis(hdev, &iso_pi(sk)->dst, iso_pi(sk)->bc_sid, &iso_pi(sk)->qos, iso_pi(sk)->base_len, iso_pi(sk)->base); if (IS_ERR(hcon)) { @@ -375,12 +375,16 @@ static int iso_connect_bis(struct sock *sk) } else { hcon = hci_connect_bis(hdev, &iso_pi(sk)->dst, le_addr_type(iso_pi(sk)->dst_type), - &iso_pi(sk)->qos, iso_pi(sk)->base_len, - iso_pi(sk)->base); + iso_pi(sk)->bc_sid, &iso_pi(sk)->qos, + iso_pi(sk)->base_len, iso_pi(sk)->base); if (IS_ERR(hcon)) { err = PTR_ERR(hcon); goto unlock; } + + /* Update SID if it was not set */ + if (iso_pi(sk)->bc_sid == HCI_SID_INVALID) + iso_pi(sk)->bc_sid = hcon->sid; } conn = iso_conn_add(hcon); @@ -1337,10 +1341,13 @@ static int iso_sock_getname(struct socket *sock, struct sockaddr *addr, addr->sa_family = AF_BLUETOOTH; if (peer) { + struct hci_conn *hcon = iso_pi(sk)->conn ? + iso_pi(sk)->conn->hcon : NULL; + bacpy(&sa->iso_bdaddr, &iso_pi(sk)->dst); sa->iso_bdaddr_type = iso_pi(sk)->dst_type; - if (test_bit(BT_SK_PA_SYNC, &iso_pi(sk)->flags)) { + if (hcon && hcon->type == BIS_LINK) { sa->iso_bc->bc_sid = iso_pi(sk)->bc_sid; sa->iso_bc->bc_num_bis = iso_pi(sk)->bc_num_bis; memcpy(sa->iso_bc->bc_bis, iso_pi(sk)->bc_bis, diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 14a9462fced5e9a8f831f86a8e890c17b8c5671c..d540f7b4f75fbf29c4bd77b700ccec33b7006fd5 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1447,22 +1447,17 @@ static void settings_rsp(struct mgmt_pending_cmd *cmd, void *data) send_settings_rsp(cmd->sk, cmd->opcode, match->hdev); - list_del(&cmd->list); - if (match->sk == NULL) { match->sk = cmd->sk; sock_hold(match->sk); } - - mgmt_pending_free(cmd); } static void cmd_status_rsp(struct mgmt_pending_cmd *cmd, void *data) { u8 *status = data; - mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, *status); - mgmt_pending_remove(cmd); + mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, *status); } static void cmd_complete_rsp(struct mgmt_pending_cmd *cmd, void *data) @@ -1476,8 +1471,6 @@ static void cmd_complete_rsp(struct mgmt_pending_cmd *cmd, void *data) if (cmd->cmd_complete) { cmd->cmd_complete(cmd, match->mgmt_status); - mgmt_pending_remove(cmd); - return; } @@ -1486,13 +1479,13 @@ static void cmd_complete_rsp(struct mgmt_pending_cmd *cmd, void *data) static int generic_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status) { - return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status, + return mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, status, cmd->param, cmd->param_len); } static int addr_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status) { - return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status, + return mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, status, cmd->param, sizeof(struct mgmt_addr_info)); } @@ -1532,7 +1525,7 @@ static void mgmt_set_discoverable_complete(struct hci_dev *hdev, void *data, if (err) { u8 mgmt_err = mgmt_status(err); - mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err); + mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_err); hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE); goto done; } @@ -1707,7 +1700,7 @@ static void mgmt_set_connectable_complete(struct hci_dev *hdev, void *data, if (err) { u8 mgmt_err = mgmt_status(err); - mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err); + mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_err); goto done; } @@ -1943,8 +1936,8 @@ static void set_ssp_complete(struct hci_dev *hdev, void *data, int err) new_settings(hdev, NULL); } - mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp, - &mgmt_err); + mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, true, + cmd_status_rsp, &mgmt_err); return; } @@ -1954,7 +1947,7 @@ static void set_ssp_complete(struct hci_dev *hdev, void *data, int err) changed = hci_dev_test_and_clear_flag(hdev, HCI_SSP_ENABLED); } - mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match); + mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, true, settings_rsp, &match); if (changed) new_settings(hdev, match.sk); @@ -2074,12 +2067,12 @@ static void set_le_complete(struct hci_dev *hdev, void *data, int err) bt_dev_dbg(hdev, "err %d", err); if (status) { - mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp, - &status); + mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, true, cmd_status_rsp, + &status); return; } - mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match); + mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, true, settings_rsp, &match); new_settings(hdev, match.sk); @@ -2138,7 +2131,7 @@ static void set_mesh_complete(struct hci_dev *hdev, void *data, int err) struct sock *sk = cmd->sk; if (status) { - mgmt_pending_foreach(MGMT_OP_SET_MESH_RECEIVER, hdev, + mgmt_pending_foreach(MGMT_OP_SET_MESH_RECEIVER, hdev, true, cmd_status_rsp, &status); return; } @@ -2638,7 +2631,7 @@ static void mgmt_class_complete(struct hci_dev *hdev, void *data, int err) bt_dev_dbg(hdev, "err %d", err); - mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, + mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_status(err), hdev->dev_class, 3); mgmt_pending_free(cmd); @@ -3427,7 +3420,7 @@ static int pairing_complete(struct mgmt_pending_cmd *cmd, u8 status) bacpy(&rp.addr.bdaddr, &conn->dst); rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type); - err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, + err = mgmt_cmd_complete(cmd->sk, cmd->hdev->id, MGMT_OP_PAIR_DEVICE, status, &rp, sizeof(rp)); /* So we don't get further callbacks for this connection */ @@ -5108,24 +5101,14 @@ static void mgmt_adv_monitor_added(struct sock *sk, struct hci_dev *hdev, mgmt_event(MGMT_EV_ADV_MONITOR_ADDED, hdev, &ev, sizeof(ev), sk); } -void mgmt_adv_monitor_removed(struct hci_dev *hdev, u16 handle) +static void mgmt_adv_monitor_removed(struct sock *sk, struct hci_dev *hdev, + __le16 handle) { struct mgmt_ev_adv_monitor_removed ev; - struct mgmt_pending_cmd *cmd; - struct sock *sk_skip = NULL; - struct mgmt_cp_remove_adv_monitor *cp; - - cmd = pending_find(MGMT_OP_REMOVE_ADV_MONITOR, hdev); - if (cmd) { - cp = cmd->param; - - if (cp->monitor_handle) - sk_skip = cmd->sk; - } - ev.monitor_handle = cpu_to_le16(handle); + ev.monitor_handle = handle; - mgmt_event(MGMT_EV_ADV_MONITOR_REMOVED, hdev, &ev, sizeof(ev), sk_skip); + mgmt_event(MGMT_EV_ADV_MONITOR_REMOVED, hdev, &ev, sizeof(ev), sk); } static int read_adv_mon_features(struct sock *sk, struct hci_dev *hdev, @@ -5196,7 +5179,7 @@ static void mgmt_add_adv_patterns_monitor_complete(struct hci_dev *hdev, hci_update_passive_scan(hdev); } - mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, + mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_status(status), &rp, sizeof(rp)); mgmt_pending_remove(cmd); @@ -5227,8 +5210,7 @@ static int __add_adv_patterns_monitor(struct sock *sk, struct hci_dev *hdev, if (pending_find(MGMT_OP_SET_LE, hdev) || pending_find(MGMT_OP_ADD_ADV_PATTERNS_MONITOR, hdev) || - pending_find(MGMT_OP_ADD_ADV_PATTERNS_MONITOR_RSSI, hdev) || - pending_find(MGMT_OP_REMOVE_ADV_MONITOR, hdev)) { + pending_find(MGMT_OP_ADD_ADV_PATTERNS_MONITOR_RSSI, hdev)) { status = MGMT_STATUS_BUSY; goto unlock; } @@ -5398,8 +5380,7 @@ static void mgmt_remove_adv_monitor_complete(struct hci_dev *hdev, struct mgmt_pending_cmd *cmd = data; struct mgmt_cp_remove_adv_monitor *cp; - if (status == -ECANCELED || - cmd != pending_find(MGMT_OP_REMOVE_ADV_MONITOR, hdev)) + if (status == -ECANCELED) return; hci_dev_lock(hdev); @@ -5408,12 +5389,14 @@ static void mgmt_remove_adv_monitor_complete(struct hci_dev *hdev, rp.monitor_handle = cp->monitor_handle; - if (!status) + if (!status) { + mgmt_adv_monitor_removed(cmd->sk, hdev, cp->monitor_handle); hci_update_passive_scan(hdev); + } - mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, + mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_status(status), &rp, sizeof(rp)); - mgmt_pending_remove(cmd); + mgmt_pending_free(cmd); hci_dev_unlock(hdev); bt_dev_dbg(hdev, "remove monitor %d complete, status %d", @@ -5423,10 +5406,6 @@ static void mgmt_remove_adv_monitor_complete(struct hci_dev *hdev, static int mgmt_remove_adv_monitor_sync(struct hci_dev *hdev, void *data) { struct mgmt_pending_cmd *cmd = data; - - if (cmd != pending_find(MGMT_OP_REMOVE_ADV_MONITOR, hdev)) - return -ECANCELED; - struct mgmt_cp_remove_adv_monitor *cp = cmd->param; u16 handle = __le16_to_cpu(cp->monitor_handle); @@ -5445,14 +5424,13 @@ static int remove_adv_monitor(struct sock *sk, struct hci_dev *hdev, hci_dev_lock(hdev); if (pending_find(MGMT_OP_SET_LE, hdev) || - pending_find(MGMT_OP_REMOVE_ADV_MONITOR, hdev) || pending_find(MGMT_OP_ADD_ADV_PATTERNS_MONITOR, hdev) || pending_find(MGMT_OP_ADD_ADV_PATTERNS_MONITOR_RSSI, hdev)) { status = MGMT_STATUS_BUSY; goto unlock; } - cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_ADV_MONITOR, hdev, data, len); + cmd = mgmt_pending_new(sk, MGMT_OP_REMOVE_ADV_MONITOR, hdev, data, len); if (!cmd) { status = MGMT_STATUS_NO_RESOURCES; goto unlock; @@ -5462,7 +5440,7 @@ static int remove_adv_monitor(struct sock *sk, struct hci_dev *hdev, mgmt_remove_adv_monitor_complete); if (err) { - mgmt_pending_remove(cmd); + mgmt_pending_free(cmd); if (err == -ENOMEM) status = MGMT_STATUS_NO_RESOURCES; @@ -5792,7 +5770,7 @@ static void start_discovery_complete(struct hci_dev *hdev, void *data, int err) cmd != pending_find(MGMT_OP_START_SERVICE_DISCOVERY, hdev)) return; - mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(err), + mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_status(err), cmd->param, 1); mgmt_pending_remove(cmd); @@ -6013,7 +5991,7 @@ static void stop_discovery_complete(struct hci_dev *hdev, void *data, int err) bt_dev_dbg(hdev, "err %d", err); - mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(err), + mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_status(err), cmd->param, 1); mgmt_pending_remove(cmd); @@ -6238,7 +6216,7 @@ static void set_advertising_complete(struct hci_dev *hdev, void *data, int err) u8 status = mgmt_status(err); if (status) { - mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, + mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, true, cmd_status_rsp, &status); return; } @@ -6248,7 +6226,7 @@ static void set_advertising_complete(struct hci_dev *hdev, void *data, int err) else hci_dev_clear_flag(hdev, HCI_ADVERTISING); - mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp, + mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, true, settings_rsp, &match); new_settings(hdev, match.sk); @@ -6592,7 +6570,7 @@ static void set_bredr_complete(struct hci_dev *hdev, void *data, int err) */ hci_dev_clear_flag(hdev, HCI_BREDR_ENABLED); - mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err); + mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_err); } else { send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev); new_settings(hdev, cmd->sk); @@ -6729,7 +6707,7 @@ static void set_secure_conn_complete(struct hci_dev *hdev, void *data, int err) if (err) { u8 mgmt_err = mgmt_status(err); - mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err); + mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_err); goto done; } @@ -7176,7 +7154,7 @@ static void get_conn_info_complete(struct hci_dev *hdev, void *data, int err) rp.max_tx_power = HCI_TX_POWER_INVALID; } - mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_GET_CONN_INFO, status, + mgmt_cmd_complete(cmd->sk, cmd->hdev->id, MGMT_OP_GET_CONN_INFO, status, &rp, sizeof(rp)); mgmt_pending_free(cmd); @@ -7336,7 +7314,7 @@ static void get_clock_info_complete(struct hci_dev *hdev, void *data, int err) } complete: - mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status, &rp, + mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, status, &rp, sizeof(rp)); mgmt_pending_free(cmd); @@ -8586,10 +8564,10 @@ static void add_advertising_complete(struct hci_dev *hdev, void *data, int err) rp.instance = cp->instance; if (err) - mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, + mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_status(err)); else - mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, + mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_status(err), &rp, sizeof(rp)); add_adv_complete(hdev, cmd->sk, cp->instance, err); @@ -8777,10 +8755,10 @@ static void add_ext_adv_params_complete(struct hci_dev *hdev, void *data, hci_remove_adv_instance(hdev, cp->instance); - mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, + mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_status(err)); } else { - mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, + mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_status(err), &rp, sizeof(rp)); } @@ -8927,10 +8905,10 @@ static void add_ext_adv_data_complete(struct hci_dev *hdev, void *data, int err) rp.instance = cp->instance; if (err) - mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, + mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_status(err)); else - mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, + mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_status(err), &rp, sizeof(rp)); mgmt_pending_free(cmd); @@ -9089,10 +9067,10 @@ static void remove_advertising_complete(struct hci_dev *hdev, void *data, rp.instance = cp->instance; if (err) - mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, + mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_status(err)); else - mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, + mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, MGMT_STATUS_SUCCESS, &rp, sizeof(rp)); mgmt_pending_free(cmd); @@ -9364,7 +9342,7 @@ void mgmt_index_removed(struct hci_dev *hdev) if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks)) return; - mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &match); + mgmt_pending_foreach(0, hdev, true, cmd_complete_rsp, &match); if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) { mgmt_index_event(MGMT_EV_UNCONF_INDEX_REMOVED, hdev, NULL, 0, @@ -9402,7 +9380,8 @@ void mgmt_power_on(struct hci_dev *hdev, int err) hci_update_passive_scan(hdev); } - mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match); + mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, true, settings_rsp, + &match); new_settings(hdev, match.sk); @@ -9417,7 +9396,8 @@ void __mgmt_power_off(struct hci_dev *hdev) struct cmd_lookup match = { NULL, hdev }; u8 zero_cod[] = { 0, 0, 0 }; - mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match); + mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, true, settings_rsp, + &match); /* If the power off is because of hdev unregistration let * use the appropriate INVALID_INDEX status. Otherwise use @@ -9431,7 +9411,7 @@ void __mgmt_power_off(struct hci_dev *hdev) else match.mgmt_status = MGMT_STATUS_NOT_POWERED; - mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &match); + mgmt_pending_foreach(0, hdev, true, cmd_complete_rsp, &match); if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0) { mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, @@ -9672,7 +9652,6 @@ static void unpair_device_rsp(struct mgmt_pending_cmd *cmd, void *data) device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk); cmd->cmd_complete(cmd, 0); - mgmt_pending_remove(cmd); } bool mgmt_powering_down(struct hci_dev *hdev) @@ -9728,8 +9707,8 @@ void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, struct mgmt_cp_disconnect *cp; struct mgmt_pending_cmd *cmd; - mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp, - hdev); + mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, true, + unpair_device_rsp, hdev); cmd = pending_find(MGMT_OP_DISCONNECT, hdev); if (!cmd) @@ -9922,7 +9901,7 @@ void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status) if (status) { u8 mgmt_err = mgmt_status(status); - mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, + mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, true, cmd_status_rsp, &mgmt_err); return; } @@ -9932,8 +9911,8 @@ void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status) else changed = hci_dev_test_and_clear_flag(hdev, HCI_LINK_SECURITY); - mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp, - &match); + mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, true, + settings_rsp, &match); if (changed) new_settings(hdev, match.sk); @@ -9957,9 +9936,12 @@ void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class, { struct cmd_lookup match = { NULL, hdev, mgmt_status(status) }; - mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match); - mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match); - mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match); + mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, false, sk_lookup, + &match); + mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, false, sk_lookup, + &match); + mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, false, sk_lookup, + &match); if (!status) { mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class, diff --git a/net/bluetooth/mgmt_util.c b/net/bluetooth/mgmt_util.c index 3713ff490c65d516ad64e3a16c47eae648fd8e7c..a88a07da394734a4c6c9c0416dfd13b599b73942 100644 --- a/net/bluetooth/mgmt_util.c +++ b/net/bluetooth/mgmt_util.c @@ -217,30 +217,47 @@ int mgmt_cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status, struct mgmt_pending_cmd *mgmt_pending_find(unsigned short channel, u16 opcode, struct hci_dev *hdev) { - struct mgmt_pending_cmd *cmd; + struct mgmt_pending_cmd *cmd, *tmp; + + mutex_lock(&hdev->mgmt_pending_lock); - list_for_each_entry(cmd, &hdev->mgmt_pending, list) { + list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) { if (hci_sock_get_channel(cmd->sk) != channel) continue; - if (cmd->opcode == opcode) + + if (cmd->opcode == opcode) { + mutex_unlock(&hdev->mgmt_pending_lock); return cmd; + } } + mutex_unlock(&hdev->mgmt_pending_lock); + return NULL; } -void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev, +void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev, bool remove, void (*cb)(struct mgmt_pending_cmd *cmd, void *data), void *data) { struct mgmt_pending_cmd *cmd, *tmp; + mutex_lock(&hdev->mgmt_pending_lock); + list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) { if (opcode > 0 && cmd->opcode != opcode) continue; + if (remove) + list_del(&cmd->list); + cb(cmd, data); + + if (remove) + mgmt_pending_free(cmd); } + + mutex_unlock(&hdev->mgmt_pending_lock); } struct mgmt_pending_cmd *mgmt_pending_new(struct sock *sk, u16 opcode, @@ -254,7 +271,7 @@ struct mgmt_pending_cmd *mgmt_pending_new(struct sock *sk, u16 opcode, return NULL; cmd->opcode = opcode; - cmd->index = hdev->id; + cmd->hdev = hdev; cmd->param = kmemdup(data, len, GFP_KERNEL); if (!cmd->param) { @@ -280,7 +297,9 @@ struct mgmt_pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode, if (!cmd) return NULL; + mutex_lock(&hdev->mgmt_pending_lock); list_add_tail(&cmd->list, &hdev->mgmt_pending); + mutex_unlock(&hdev->mgmt_pending_lock); return cmd; } @@ -294,7 +313,10 @@ void mgmt_pending_free(struct mgmt_pending_cmd *cmd) void mgmt_pending_remove(struct mgmt_pending_cmd *cmd) { + mutex_lock(&cmd->hdev->mgmt_pending_lock); list_del(&cmd->list); + mutex_unlock(&cmd->hdev->mgmt_pending_lock); + mgmt_pending_free(cmd); } diff --git a/net/bluetooth/mgmt_util.h b/net/bluetooth/mgmt_util.h index f2ba994ab1d84766ff0a2a44f8bb2557d20926ca..024e51dd693756d29588d483802648bfa9fabc4a 100644 --- a/net/bluetooth/mgmt_util.h +++ b/net/bluetooth/mgmt_util.h @@ -33,7 +33,7 @@ struct mgmt_mesh_tx { struct mgmt_pending_cmd { struct list_head list; u16 opcode; - int index; + struct hci_dev *hdev; void *param; size_t param_len; struct sock *sk; @@ -54,7 +54,7 @@ int mgmt_cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status, struct mgmt_pending_cmd *mgmt_pending_find(unsigned short channel, u16 opcode, struct hci_dev *hdev); -void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev, +void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev, bool remove, void (*cb)(struct mgmt_pending_cmd *cmd, void *data), void *data); struct mgmt_pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode, diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index 20ea7dba0a9a1398cc3ae4355b98055fa2970793..3b8f39618d651e7aa0500dae726a89593b89b08a 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 fb6f7f2001c9b8cd34bbd2ba18b6bc732e9c8af5..0224ef3dfec0592f9306ea4deee7ffba07fa960a 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 c126aa4e75512f4d7f2883e64a25bc57019fb837..adfd74102019ed8ef62c1316b4c437c5f8c8bf53 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 27bf1979b9099b77d6038e96f613b9126a861c14..e5d453305381baa34225a144ac99e98f2a62d810 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 25fdf060e30d0d5133fc1d5e0c5cfd5c46233bb0..0938bf7dd646ac44220873358c242d489b394918 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 8a7ce640f74d8122667184980c7704ee6f51df53..60d31c2feed3e9ffabcdbde445512f9b02f1be76 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/filter.c b/net/core/filter.c index 327ca73f9cd7a4bb49c7f9f192c7f2e4fa2564a1..7a72f766aacfaf5e7b7b9445485419b608a5e2de 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -3233,6 +3233,13 @@ static const struct bpf_func_proto bpf_skb_vlan_pop_proto = { .arg1_type = ARG_PTR_TO_CTX, }; +static void bpf_skb_change_protocol(struct sk_buff *skb, u16 proto) +{ + skb->protocol = htons(proto); + if (skb_valid_dst(skb)) + skb_dst_drop(skb); +} + static int bpf_skb_generic_push(struct sk_buff *skb, u32 off, u32 len) { /* Caller already did skb_cow() with len as headroom, @@ -3329,7 +3336,7 @@ static int bpf_skb_proto_4_to_6(struct sk_buff *skb) } } - skb->protocol = htons(ETH_P_IPV6); + bpf_skb_change_protocol(skb, ETH_P_IPV6); skb_clear_hash(skb); return 0; @@ -3359,7 +3366,7 @@ static int bpf_skb_proto_6_to_4(struct sk_buff *skb) } } - skb->protocol = htons(ETH_P_IP); + bpf_skb_change_protocol(skb, ETH_P_IP); skb_clear_hash(skb); return 0; @@ -3550,10 +3557,10 @@ static int bpf_skb_net_grow(struct sk_buff *skb, u32 off, u32 len_diff, /* Match skb->protocol to new outer l3 protocol */ if (skb->protocol == htons(ETH_P_IP) && flags & BPF_F_ADJ_ROOM_ENCAP_L3_IPV6) - skb->protocol = htons(ETH_P_IPV6); + bpf_skb_change_protocol(skb, ETH_P_IPV6); else if (skb->protocol == htons(ETH_P_IPV6) && flags & BPF_F_ADJ_ROOM_ENCAP_L3_IPV4) - skb->protocol = htons(ETH_P_IP); + bpf_skb_change_protocol(skb, ETH_P_IP); } if (skb_is_gso(skb)) { @@ -3606,10 +3613,10 @@ static int bpf_skb_net_shrink(struct sk_buff *skb, u32 off, u32 len_diff, /* Match skb->protocol to new outer l3 protocol */ if (skb->protocol == htons(ETH_P_IP) && flags & BPF_F_ADJ_ROOM_DECAP_L3_IPV6) - skb->protocol = htons(ETH_P_IPV6); + bpf_skb_change_protocol(skb, ETH_P_IPV6); else if (skb->protocol == htons(ETH_P_IPV6) && flags & BPF_F_ADJ_ROOM_DECAP_L3_IPV4) - skb->protocol = htons(ETH_P_IP); + bpf_skb_change_protocol(skb, ETH_P_IP); if (skb_is_gso(skb)) { struct skb_shared_info *shinfo = skb_shinfo(skb); diff --git a/net/core/gen_estimator.c b/net/core/gen_estimator.c index 2b821b9a869977243a33dcb90fe262f068488f6a..7d426a8e29f30b67655cf706060bfc6c478f3123 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 a6e2c91ec3e75df1c819bf1efc643700dff73224..49dce9a82295b197b76b903a5a655c0c216260f9 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/ioctl.c b/net/ethtool/ioctl.c index 39ec920f5de72c151e2f526d6ffafbfc07d7b036..71c828d0bf314f47af3c87564ee94d6040818061 100644 --- a/net/ethtool/ioctl.c +++ b/net/ethtool/ioctl.c @@ -1083,7 +1083,8 @@ static noinline_for_stack int ethtool_set_rxnfc(struct net_device *dev, ethtool_get_flow_spec_ring(info.fs.ring_cookie)) return -EINVAL; - if (!xa_load(&dev->ethtool->rss_ctx, info.rss_context)) + if (info.rss_context && + !xa_load(&dev->ethtool->rss_ctx, info.rss_context)) return -EINVAL; } diff --git a/net/ethtool/mm.c b/net/ethtool/mm.c index ad9b4003400334ec2d3a6b2bf6390928c39f4b7f..29bbbc149375d467a6a40c3f26dd93892b3809e8 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 0d1e56965af0aca9a359cc38115c23a555ee26cc..88657255fec12b8cbf9edf4634899046381afc1d 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 4ce471a2f3870dc45f38c31ee427822ac6da5368..3a2a2fa7a0a3965ed66e97fce0ee9267c7a162c2 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 d4b983d170382e616ea58821b197da89885a6bb2..ddb6a5817d098eda6b22d802b5f59604b2145ff2 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 ca7d539b3846318ad421b586543ec146de57a69f..d1769034b6438bb5c994e1660b181e05109ab365 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 20915895bdaafb2a76b0b898b39980b0cb8db86b..6906bedad19a13d3f62100058d6a20debbf6a88e 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 67efe95015816bb82de9e3f31422c8d94f147748..875ff923a8ed05411628f55f788f33cbe3dee5b3 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 77f395b28ec748bcd85b8dfa0a8c0b8a74684103..64b3fb3208af65b569f37575467060797acf7002 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 2ff2f79c7351a79a2de7a8a554a9e5b4df617296..a7d09ae9d7616bfa07e4687116c16dac2cdce46a 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 e4c616bbd72714eee06b8363b504a5e3d14fd7b4..bb37e24b97a78de581e8192b52b78f83ba747446 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 43b19adfbf88e2d232599f397baefd9aef4e52e3..ba2ec7c870ccbab3c9a1650c578f23974b8b66b4 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 7094d77086868c44312d0d33c0e4f1839779c180..93578b2ec35fb55ca1f56c3e558661989568639e 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 3276cde5ebd70462e05a72f05a40e85f87f6ad42..9db31e5b998c1a9860abf0939f04710aaf5d20aa 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 d6bd8f7079bb74ec99030201163332ed5c6d2eec..64ab23ff559bb9e97b989d19802480c703cdbcbe 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 49740898bc1370ff0ca89928750c6de85a45303f..7d4bcf3fda5bac556b032e38934c6bc40d4f2ec9 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/ipv6/route.c b/net/ipv6/route.c index 0143262094b0a88d7f5889c292ad0a1b17b01753..79c8f1acf8a35e465ab1a21aca50a554ca6f513b 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -3737,6 +3737,53 @@ void fib6_nh_release_dsts(struct fib6_nh *fib6_nh) } } +static int fib6_config_validate(struct fib6_config *cfg, + struct netlink_ext_ack *extack) +{ + /* RTF_PCPU is an internal flag; can not be set by userspace */ + if (cfg->fc_flags & RTF_PCPU) { + NL_SET_ERR_MSG(extack, "Userspace can not set RTF_PCPU"); + goto errout; + } + + /* RTF_CACHE is an internal flag; can not be set by userspace */ + if (cfg->fc_flags & RTF_CACHE) { + NL_SET_ERR_MSG(extack, "Userspace can not set RTF_CACHE"); + goto errout; + } + + if (cfg->fc_type > RTN_MAX) { + NL_SET_ERR_MSG(extack, "Invalid route type"); + goto errout; + } + + if (cfg->fc_dst_len > 128) { + NL_SET_ERR_MSG(extack, "Invalid prefix length"); + goto errout; + } + +#ifdef CONFIG_IPV6_SUBTREES + if (cfg->fc_src_len > 128) { + NL_SET_ERR_MSG(extack, "Invalid source address length"); + goto errout; + } + + if (cfg->fc_nh_id && cfg->fc_src_len) { + NL_SET_ERR_MSG(extack, "Nexthops can not be used with source routing"); + goto errout; + } +#else + if (cfg->fc_src_len) { + NL_SET_ERR_MSG(extack, + "Specifying source address requires IPV6_SUBTREES to be enabled"); + goto errout; + } +#endif + return 0; +errout: + return -EINVAL; +} + static struct fib6_info *ip6_route_info_create(struct fib6_config *cfg, gfp_t gfp_flags, struct netlink_ext_ack *extack) @@ -3886,6 +3933,10 @@ int ip6_route_add(struct fib6_config *cfg, gfp_t gfp_flags, struct fib6_info *rt; int err; + err = fib6_config_validate(cfg, extack); + if (err) + return err; + rt = ip6_route_info_create(cfg, gfp_flags, extack); if (IS_ERR(rt)) return PTR_ERR(rt); @@ -4479,53 +4530,6 @@ void rt6_purge_dflt_routers(struct net *net) rcu_read_unlock(); } -static int fib6_config_validate(struct fib6_config *cfg, - struct netlink_ext_ack *extack) -{ - /* RTF_PCPU is an internal flag; can not be set by userspace */ - if (cfg->fc_flags & RTF_PCPU) { - NL_SET_ERR_MSG(extack, "Userspace can not set RTF_PCPU"); - goto errout; - } - - /* RTF_CACHE is an internal flag; can not be set by userspace */ - if (cfg->fc_flags & RTF_CACHE) { - NL_SET_ERR_MSG(extack, "Userspace can not set RTF_CACHE"); - goto errout; - } - - if (cfg->fc_type > RTN_MAX) { - NL_SET_ERR_MSG(extack, "Invalid route type"); - goto errout; - } - - if (cfg->fc_dst_len > 128) { - NL_SET_ERR_MSG(extack, "Invalid prefix length"); - goto errout; - } - -#ifdef CONFIG_IPV6_SUBTREES - if (cfg->fc_src_len > 128) { - NL_SET_ERR_MSG(extack, "Invalid source address length"); - goto errout; - } - - if (cfg->fc_nh_id && cfg->fc_src_len) { - NL_SET_ERR_MSG(extack, "Nexthops can not be used with source routing"); - goto errout; - } -#else - if (cfg->fc_src_len) { - NL_SET_ERR_MSG(extack, - "Specifying source address requires IPV6_SUBTREES to be enabled"); - goto errout; - } -#endif - return 0; -errout: - return -EINVAL; -} - static void rtmsg_to_fib6_config(struct net *net, struct in6_rtmsg *rtmsg, struct fib6_config *cfg) @@ -4563,10 +4567,6 @@ int ipv6_route_ioctl(struct net *net, unsigned int cmd, struct in6_rtmsg *rtmsg) switch (cmd) { case SIOCADDRT: - err = fib6_config_validate(&cfg, NULL); - if (err) - break; - /* Only do the default setting of fc_metric in route adding */ if (cfg.fc_metric == 0) cfg.fc_metric = IP6_RT_PRIO_USER; @@ -5402,6 +5402,10 @@ static int ip6_route_multipath_add(struct fib6_config *cfg, int nhn = 0; int err; + err = fib6_config_validate(cfg, extack); + if (err) + return err; + replace = (cfg->fc_nlinfo.nlh && (cfg->fc_nlinfo.nlh->nlmsg_flags & NLM_F_REPLACE)); @@ -5636,10 +5640,6 @@ static int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh, if (err < 0) return err; - err = fib6_config_validate(&cfg, extack); - if (err) - return err; - if (cfg.fc_metric == 0) cfg.fc_metric = IP6_RT_PRIO_USER; diff --git a/net/lapb/lapb_timer.c b/net/lapb/lapb_timer.c index 5b3f3b444d197b55b3d5995fb280f352a8791148..9fde6cf20f10b2545b7b057bf199338945a8f365 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 7e8fc710c59088678bc3c4a7f994468fa4a0d2fb..0779daa8aa8f3b5619470e8c9b3535563c418cea 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 85612234742ac57ef8f130651ab4fe5225759596..ee534797c0335f1b64eb6864a5aee704a96497c8 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 8dc8c3c96b9691236c2197f6e1ff56db256684e0..dbd9ad5f3992ca3b3331ec7ac667bc93830d1139 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 a6e7b7ba6a01942271fb36755806123886f40231..9ed87d6f50194b375c38cf721575d4d57293ce8d 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 885fa6aa3fc1a35cb674aa588d5eaf98771e9f9b..fabbffdd3ac2676e749f25c900ed2e5a9c60ce6e 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 5cc56d5780483e89ac0b09afc36aa378aed8bf0b..d00d9d413c5cff9b04cd7b3340a8b438b8edb89e 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 91444301a84a4c94633870a8a417a20a8d189086..9101858525dd88e34cd7a8f56897fb87883743e2 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 9c6a2b342170c8d5fbbcdfd618f4957e53682d9f..cb45a5d2009d24300c35e52213e731fe76b8ace0 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 948909a242d655e926f1319c9dc45f83207094fc..2d46d4af60d7bdc96b25d6e92a68271802deedd3 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 ece1e83c7b2faa252e2b84023fffb7061805f521..a5d4358f122ae485ad02151653e5724c8ef1a20d 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 84b18be1f0b16a0f2c156b48571439ad091d3152..61583173629e455531e354973cb72dfb58340811 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 1306d4dc287b842ebf7efd52d121b096d5cb43e0..feb01747d7d86b648fd928816af3b171258e31a7 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 0749733ea897bd0f0ec6f3165515166f145ae5ed..edf14c2c20622e38b697f3a291838282ef5a8ddb 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 b3694706378344c804e84490d0b2c3cbfaefd8b7..446e4e3b9553a0aea936801f545ebc8ca9cdb736 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 6ae042f702d20f3fc87577f54f45b4f99e8718e8..798c7993635e66db05c9e6d19f5893c2086ec3bc 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 db794fe1300e697ab53ecc64a03607679ce7b748..13c7a08aa868c0440525711c2c0947d4c42a2fa9 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 8699944c0baf377a743ea2e3c55a5229128ede6c..44b2ad695c1535cf9a2d832d17e7acf8d1e6160e 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 7d5b7418f8c72e89d7f7ea8aac494577fbdce79b..6a6fc44785337266005e0669a1176aa453cb7639 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 2423513d701d4c8a72793369ae35c7ee9b59781b..156181a3bacd7d6c8fa63d75112f3ddc2d14fb32 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 cdb1d4bf6761ca4b60071ec6eea382aaab06189e..a021e6aba3d7b628603aa76232153af0c8fb8a0e 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 21d22fa22e4e7a32196719393b4df816fb8204a3..cfc2daa3fc7f340937898b4bef0769fd31f801b5 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 882962f3c84db579034cba843f7a4fba045156fe..bfcb9cd335bff59fa4d0d09eb52943566e4098e7 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 9082155ee558933c640f51f1a6fec8ccdc1f0fa2..d73957592c9d9b2906ec26389f635eb04a9bcc9c 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 8a80fd76fe45b20e703321c106baf2fc8fe92756..90dcf088071a6ffc78bc1a311ed96faa1fb35276 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 6ee148f0e6d0425614518957dac2f58320d46b01..3331669d8e33a49959abe774bda49ccef5701249 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 5e3ca068f04e04bfa8578212b1d28c553fd78540..b3a62b1f3a09eb4ca57dcfbc969820a2775efe85 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 75ed8a9146baae1d126f6475d0badd40655e73f4..ae1c842f9c642724242ae867a202c6ec8a685541 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 aa493344d93e3c37699bcf87471b73767522a366..8618d57c23dae8c59f527fb3b4847148310bd880 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 ce9c683a3ead74bee0a56606467f6285975c63c1..4fc37894860c9e65cf8531d9c66be1814119fcf6 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 27e863f96ed1e2cb1707e47b04fed2ff8149105a..beeb3b4d28caba92166a44f2fbb2af27a40b5582 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 0171bf3c70162bd2c0c7b37fd8f0eae5d7cdd11b..fc921cd2cdffa5e5678d394cf5449b08bb0b8aaf 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 20be2c47cf4191f07073d6d66753563ba711072c..3d43f3eae7599ebc331bca46e5145fe4b43e8f5a 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 a4a668b88a8f27c77d2faa39ba9ad174e748966b..4e72b636a46a5fed572d31dc1355079d7c38c3b8 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 9f9629e6fdaea06b7b9a7743e8057aeade6aaa96..7746229fdc8cfc53853c265209f7a430f98e4487 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 1525773e94aa175dd2b73b27314259da0f1dc239..020369c49587f123d5db22159c8270b20f8c6875 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 e9e8f0ef3fd58ef01bfc3ee12eda618662df91c0..15067ff7b1f2caefb59069c598f6e118d1c0d4dd 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 5c2580a07530e4e0615a7df7ff9d0a35ae9e94b4..5693b41b093f3f5723bc3e780dcf20419dd9863e 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_ets.c b/net/sched/sch_ets.c index 2c069f0181c62b5387118822dfb7a51fc1b3033a..037f764822b96526329a4715bfcc22c502495f14 100644 --- a/net/sched/sch_ets.c +++ b/net/sched/sch_ets.c @@ -661,7 +661,7 @@ static int ets_qdisc_change(struct Qdisc *sch, struct nlattr *opt, for (i = q->nbands; i < oldbands; i++) { if (i >= q->nstrict && q->classes[i].qdisc->q.qlen) list_del_init(&q->classes[i].alist); - qdisc_tree_flush_backlog(q->classes[i].qdisc); + qdisc_purge_queue(q->classes[i].qdisc); } WRITE_ONCE(q->nstrict, nstrict); memcpy(q->prio2band, priomap, sizeof(priomap)); diff --git a/net/sched/sch_fq_pie.c b/net/sched/sch_fq_pie.c index df7fac95ab15138bc55cf73bad27fd2bf41d1da9..b0e34daf1f7517415fe2df316649e23a7380cb8b 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 08e0e3aff97636cde7bdcf42a2713e45b56329ca..16afb834fe4a95b20f4c48a65881302ec4a8a620 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 ff49a6c97033aa43f680657b7798d4da050d8e71..ad46ee3ed5a968ab26521b83fc6dc4f8a0c0997c 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_prio.c b/net/sched/sch_prio.c index cc30f7a32f1a786fa1c3937a1b9d5c96a52e56e7..9e2b9a490db23d858b27b7fc073b05a06535b05e 100644 --- a/net/sched/sch_prio.c +++ b/net/sched/sch_prio.c @@ -211,7 +211,7 @@ static int prio_tune(struct Qdisc *sch, struct nlattr *opt, memcpy(q->prio2band, qopt->priomap, TC_PRIO_MAX+1); for (i = q->bands; i < oldbands; i++) - qdisc_tree_flush_backlog(q->queues[i]); + qdisc_purge_queue(q->queues[i]); for (i = oldbands; i < q->bands; i++) { q->queues[i] = queues[i]; diff --git a/net/sched/sch_red.c b/net/sched/sch_red.c index 1ba3e0bba54f0cc8d797ab9a7ffab529481b2d4e..479c42d11083f016cc2993ae82245bbc8adcff12 100644 --- a/net/sched/sch_red.c +++ b/net/sched/sch_red.c @@ -285,7 +285,7 @@ static int __red_change(struct Qdisc *sch, struct nlattr **tb, q->userbits = userbits; q->limit = ctl->limit; if (child) { - qdisc_tree_flush_backlog(q->qdisc); + qdisc_purge_queue(q->qdisc); old_child = q->qdisc; q->qdisc = child; } @@ -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 b912ad99aa15d95b297fb28d0fd0baa9c21ab5cd..96eb2f122973ad5f38311e4669b01539fdbeaeda 100644 --- a/net/sched/sch_sfq.c +++ b/net/sched/sch_sfq.c @@ -310,7 +310,10 @@ drop: /* It is difficult to believe, but ALL THE SLOTS HAVE LENGTH 1. */ x = q->tail->next; slot = &q->slots[x]; - q->tail->next = slot->next; + if (slot->next == x) + q->tail = NULL; /* no more active slots */ + else + q->tail->next = slot->next; q->ht[slot->hash] = SFQ_EMPTY_SLOT; goto drop; } @@ -597,7 +600,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; @@ -653,6 +656,14 @@ static int sfq_change(struct Qdisc *sch, struct nlattr *opt, NL_SET_ERR_MSG_MOD(extack, "invalid quantum"); return -EINVAL; } + + if (ctl->perturb_period < 0 || + ctl->perturb_period > INT_MAX / HZ) { + NL_SET_ERR_MSG_MOD(extack, "invalid perturb period"); + return -EINVAL; + } + perturb_period = ctl->perturb_period * HZ; + if (ctl_v1 && !red_check_params(ctl_v1->qth_min, ctl_v1->qth_max, ctl_v1->Wlog, ctl_v1->Scell_log, NULL)) return -EINVAL; @@ -669,14 +680,12 @@ static int sfq_change(struct Qdisc *sch, struct nlattr *opt, headdrop = q->headdrop; maxdepth = q->maxdepth; maxflows = q->maxflows; - perturb_period = q->perturb_period; quantum = q->quantum; flags = q->flags; /* update and validate configuration */ if (ctl->quantum) quantum = ctl->quantum; - perturb_period = ctl->perturb_period * HZ; if (ctl->flows) maxflows = min_t(u32, ctl->flows, SFQ_MAX_FLOWS); if (ctl->divisor) { diff --git a/net/sched/sch_tbf.c b/net/sched/sch_tbf.c index dc26b22d53c73461c6f6d64f768136ad3f334143..4c977f049670a600eafd219c898e5f29597be2c1 100644 --- a/net/sched/sch_tbf.c +++ b/net/sched/sch_tbf.c @@ -452,7 +452,7 @@ static int tbf_change(struct Qdisc *sch, struct nlattr *opt, sch_tree_lock(sch); if (child) { - qdisc_tree_flush_backlog(q->qdisc); + qdisc_purge_queue(q->qdisc); old = q->qdisc; q->qdisc = child; } diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 8c3b80c4d40b80b1aa438ce8ed9a53dda8f72e2e..f402f90eb6b6717888698c4157d2d7ee9161c527 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 3aa5da5e3bbd211a00268165040646a67304f65f..424f10a6fdba9bdb0e735d0f315c7f3266cfc455 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 cb14d6ddac6c4b9b659784684f9c13dde537ae3d..8b1837228799c5e3ad052cfa831ff52ba12de6e1 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 d5e0cdcad9e0c9bc7ce1ec1534f0ed07254866eb..1023361845f9fe79329ec73238eac86276334541 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 685389d4b245eac3d30a61b6442d0044e928523f..775fd4f3f0725147381b7d339bdfdcfe0facae60 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 b45c5b91bc7afbba51c9f0fa1981517e976dc564..572b79bf76ce1b7a7fff313850028e3ea8729141 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 cb43f2016a708471e8047b00a8f7ab4c532339c7..a07fb073368cab1a022de5919d6f8eb60d3c3c4c 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 65dcbb54f55d966612f3ef7800ac3539305b1771..7c61d47ea2086058c6fe11a19383c3029f4acb52 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 621addab28349ec8a0b7fe7122ba1abab9b4ffc7..f8490d94e32364d9858033be07aa42c048bb03d0 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/unix/af_unix.c b/net/unix/af_unix.c index 2e2e9997a68e71177cc54016c56e0f42114b2527..22e170fb5dda7f9a4b40ac6406047780eecff3e1 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -1971,7 +1971,8 @@ static void unix_maybe_add_creds(struct sk_buff *skb, const struct sock *sk, if (UNIXCB(skb).pid) return; - if (unix_may_passcred(sk) || unix_may_passcred(other)) { + if (unix_may_passcred(sk) || unix_may_passcred(other) || + !other->sk_socket) { UNIXCB(skb).pid = get_pid(task_tgid(current)); current_uid_gid(&UNIXCB(skb).uid, &UNIXCB(skb).gid); } diff --git a/net/wireless/core.c b/net/wireless/core.c index dcce326fdb8ca99c762d7683974f610ff2ed0d77..5c3c72df0591c6e32d64f7d4e10c07339f3f72c7 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/wireless/nl80211.c b/net/wireless/nl80211.c index fd5f79266471e49d791f539391632ae3910ea620..85f139016da21c2bc77606ba22cd1c6e60d8fe31 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -1583,7 +1583,7 @@ nl80211_parse_connkeys(struct cfg80211_registered_device *rdev, return result; error: - kfree(result); + kfree_sensitive(result); return ERR_PTR(err); } diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c index 8dda4178497c970d1ae3cac220281b50ceb97d86..1f8ae9f4a3f1960d63557f34a3c9e8bbf55e8633 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 37b190499405e2c4fb895f7a0c3175756f9ea087..4608aa5b4f318c3bf136badc6744df941803fea8 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 e4c5ad5b070f5caf0f65b6a0bb943ed2d1a9af5b..2ec63a1f4c6d42e3fedb2ddfda57eed8cdab00de 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 d4134a18c65819ceb4aac593d7709b42640b0301..094d2454602e25e984819205bcb3dfdbfc1f527b 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 203b585c2ae28fa0bb05d02cbdd1f01e9106b833..77cc418ad69eaa2aac4d8ca63abca69808355648 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 f33c13c3ff97d0cca58cf6c7d4e3cb8a611a102c..939278bc7b03489a647b697012e09223871c90cd 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 557e725ab9328577d20a549f4cb147ee5071817d..a6461ea411f7a95a9dd156897bec43cb22ef1092 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 2b332645e0c2ac3f3f227bf42409df2b519e7739..1d581ba5df66f2b560e83d78bb8361bfef7e6bfc 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 eed247d8abfcb93b7d4141766dbd31a6a712d1d3..13ea7bf1ae7dcdd208d25fe54655f1c0fb041907 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 97a5669b083d760ab9b69dedea14bf2212a6eb03..170733a3fba477577ebaf5cace1d4418169b0c6d 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 { \ @@ -89,6 +92,20 @@ #define KABI_ENUMERATOR_VALUE(fqn, field, value) \ __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. diff --git a/scripts/gendwarfksyms/examples/kabi_ex.c b/scripts/gendwarfksyms/examples/kabi_ex.c index 0b7ffd830541d6ab57ce568ad8380f202711843b..1f799eb7c7568014c90bb304b4f670090966cf5f 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 1736e0f65208143843684c16ca832eadde5e25a8..785b211d9c58a98540723c1eff691ddfcca0ae6c 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 2feec168bf732a479d52062994b4d9778af57165..7dd03ffe0c5c829d32cadfe9ac9109ed7455dd92 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 66f01fcd1607950841807131f0ffe333ae9b3f3b..b3ade713778f1be725a70fd1209c7ccb4a387d0e 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 6f37289104ffdc52f393e0566e90924809bf7bb6..39ce1770e46364bafa275debf9327ec130b6bc4e 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 8b0d7ac73dbb093435190f92b06e466d100c4839..83e48670c2fcfb2ab5f95cb9a2f78a6a8832c39f 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 0000000000000000000000000000000000000000..e9b5940c0f2837895ffd88b0f540031c538d5436 --- /dev/null +++ b/scripts/git-resolve.sh @@ -0,0 +1,201 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 +# (c) 2025, Sasha Levin + +usage() { + echo "Usage: $(basename "$0") [--selftest] [--force] [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 21578dcd4292407ea7280766151db6297c9f8658..fe2231e0e6a4cdd149582b16a8dc74ee1b8d7deb 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 b8ebc3094a2347d609bece1caf7278f3d61e1303..fbc907f75eac7e764be777931f6a0b6fdc1a7ccd 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 6587ac86d0d52b53e14d619770a23de924fa62cd..7d48a692bd273ca98187d8a2c7a1d3e820b8efa4 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 68372d3ff32539cb5460807ca4369343eff4481d..e9c3c664e9251157a135bc78c0039665dd87b16d 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 d40d5484e0c50da1414c5628c9b4b58d68451bd0..a74450e799d1b6794896352a9b1c0375d50f3229 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 +# +# The rule for including is very simple: +# Include only when you use EXPORT_SYMBOL(). That's it. +# +# However, some headers include even though they are completely +# unrelated to EXPORT_SYMBOL(). +# +# One example is include/linux/module.h. Please note and +# are orthogonal. should be included by files +# that can be compiled as modules. In other words, should be +# included by EXPORT_SYMBOL consumers. In contrast, should be +# included from EXPORT_SYMBOL providers, which may or may not be modular. +# Hence, include/linux/module.h should *not* include . +# +# 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 , even though only some of them +# actually export symbols. Hence, include/linux/linkage.h should *not* include +# . +# +# Before fixing such headers, we must ensure that C files using EXPORT_SYMBOL() +# include directly, since many C files currently rely on +# being included indirectly (likely, via etc.). +# +# Therefore, this check. +# +# The problem is simple - the warned files use EXPORT_SYMBOL(), but do not +# include . Please add #include to them. +# +# If the included headers are sorted alphabetically, please insert +# in the appropriate position to maintain the sort order. +# For this reason, this script only checks missing , 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:]]*' | + xargs -r printf "%s: warning: EXPORT_SYMBOL() is used, but #include is missing\n" >&2 +} + +# If you do not use EXPORT_SYMBOL(), please do not include . +# Currently, this is checked for *.c files, but not for *.h files, because some +# *.c files rely on being included indirectly. +check_unnecessary_include_linux_export_h () { + + git -C "${srctree:-.}" grep --files-with-matches '#include[[:space:]]*' \ + -- '*.[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 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 be89921d60b61d1db0398313aeb00bc1888843b1..5ca7c268294ebb65acb0ba52a671eddca9279c61 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 98680e9cd7be30dc8caadb518bafbaac21a515fd..99ce427d9a69d92953554d81816c62664d142615 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/security/keys/gc.c b/security/keys/gc.c index f27223ea4578f1dcee16a68d51357e337e522a0a..748e83818a760425e5324751819ba8e58ab4aca1 100644 --- a/security/keys/gc.c +++ b/security/keys/gc.c @@ -218,8 +218,8 @@ continue_scanning: key = rb_entry(cursor, struct key, serial_node); cursor = rb_next(cursor); - if (test_bit(KEY_FLAG_FINAL_PUT, &key->flags)) { - smp_mb(); /* Clobber key->user after FINAL_PUT seen. */ + if (!test_bit_acquire(KEY_FLAG_USER_ALIVE, &key->flags)) { + /* Clobber key->user after final put seen. */ goto found_unreferenced_key; } diff --git a/security/keys/key.c b/security/keys/key.c index 7198cd2ac3a3a57dd17a34f4d174e54cf2b74558..3bbdde7786318b392af93f570a0ae7322602db88 100644 --- a/security/keys/key.c +++ b/security/keys/key.c @@ -298,6 +298,7 @@ struct key *key_alloc(struct key_type *type, const char *desc, key->restrict_link = restrict_link; key->last_used_at = ktime_get_real_seconds(); + key->flags |= 1 << KEY_FLAG_USER_ALIVE; if (!(flags & KEY_ALLOC_NOT_IN_QUOTA)) key->flags |= 1 << KEY_FLAG_IN_QUOTA; if (flags & KEY_ALLOC_BUILT_IN) @@ -658,8 +659,8 @@ void key_put(struct key *key) key->user->qnbytes -= key->quotalen; spin_unlock_irqrestore(&key->user->lock, flags); } - smp_mb(); /* key->user before FINAL_PUT set. */ - set_bit(KEY_FLAG_FINAL_PUT, &key->flags); + /* Mark key as safe for GC after key->user done. */ + clear_bit_unlock(KEY_FLAG_USER_ALIVE, &key->flags); schedule_work(&key_gc_work); } } diff --git a/sound/core/jack.c b/sound/core/jack.c index 850f8234027891abbd465d2e2f6dd57409d51b5c..93e357a23f1717ae3d2d8dfe465bea23d8fdec0d 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 1de4b90fd4d18f665e14c0238982a777145eb107..8072183c33d39374f548ee2a71d54b335ed6eb78 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 4b02ec127cc01b461d4e7ce47045abcae0b8ef35..6c318a5903abe9119035828b49f00b4eda5a91ef 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 1d923cbe8cd0848d6a88ea2a7e69334e9b2ffe5c..783fe3a22bc91cf258867b69a76b4c119e49d7f9 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 a63e7558ac07c86c26f91125b180d7f348a5a84e..670f8ba92c0843d3904a7a71241a4fef2ca1b7b4 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 dffcdf9e10d475c51bf346675cbaeaece477124d..851f34e2cdd08f85a94ba7b2789f7c29cb84ab76 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 9bee454441b07bcdd8a70222e9f1e37f49608384..de7449cb6515f1f081d10c75c9406c8f4a55b19d 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 72378f354fd01e198e3bd535d9e40b2cf8fb37ed..39f1e1fe4c446a0c1a594cd645dda3387b096f9a 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 1857a78f55d762521ebdffe29a58ff39ef4ea7d4..6d0656fcd574d325eb8c24a1870f310a1c713de4 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 657b331d7a79239313a933e0d7c5e364de4a69c7..cd380db195ef5ed653d4474093a2190619a1d99d 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 0162352099282584a6a2565d70f631184cf33275..215bbcd0360e6bf310655a7700b5bbd088646f17 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 57867e51d3670086e672853e575c8dd25f56d1b8..637079a2f02a4d835c24395f63ca26902e249923 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 fcc2a0d67792f15edc00e18f9f7abd0ea9d99fc2..494b21be665c8aa6dbe7d2de1cc57efae3b24322 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 7e5ce96954b9e91dba0620958604c3ce66ea0061..cbd964f87349e7df33254c5b6e200ef89a21b451 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 aa179644b5c9c0774c3ea8243b9357105661edd4..fa6867adb42b5b583406c73a82e1ef13b2406248 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 2ef59184249c5bdaec0a9c06ee9fee054d2b9215..c3f3c912956196569f7918b57d20aa18c2091ad8 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 d9c8872b1866a1b270eaa5c3324f83fb1997b362..d5bc81099d0d68b2f7fd2ae0b841b46f12a581be 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 1fef350d821ef07865b7e4f2dedc0f575cbf6acb..df8f88beddd0738b108be129b2a136141b3eae6b 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 e6df706f740d6e4a2d71903927687a13db2262c1..e5210ed48ddf1698769d2e3f112c202bc8367492 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 873b7eadfc501d12f829a7a4bae014c3cb4890f1..8df0f5bba0f60a22b3b45a930281a415daded44b 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 64de540899551773a54cb6a92b9c2bd63cd7428e..2041cf00cca0c1e1c7ee1e12c9c48ab67e423170 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 f88331a48638174d2ae25cbe6e2233126aec9001..40ea843113a7438cadab7b2e9d9f9a0e01331816 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 8b7d51266f8141eda21609b09d9c5f5680416221..1b983c7006f18dd12c1f9789502f2728df7ee20a 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 358e227c5ab61bf417253ed68562636936ed58f6..462322c38aa42d4c394736239de0317d5918d5a7 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 3d9da93d22ee84914a92cfdc1de7b977dfd3bfa4..7e62445e02c1d0632f5f5e35cf97265f42829ba0 100644 --- a/sound/soc/amd/yc/acp6x-mach.c +++ b/sound/soc/amd/yc/acp6x-mach.c @@ -311,6 +311,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "83AS"), } }, + { + .driver_data = &acp6x_card, + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_NAME, "83BS"), + } + }, { .driver_data = &acp6x_card, .matches = { diff --git a/sound/soc/codecs/es8375.c b/sound/soc/codecs/es8375.c index decc86c92427c0c61a1531fb0fed1d9b853449d5..00925963210750b976a382d62bb662822dc214c5 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 ddc00927313cfedd5f84772bc71ef9c5e2e830c6..dc7794c9ac44cedc43b4d37e2661ab6c10d8cade 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 f51ba345a16e641b954a3613b01dc844fa1728b6..015cc710e6dc08ae5e9b7a9ef765cdee15cd4f5e 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 dba78efadc85a3ad7d1035b5a19119cab1bbcf3f..08df87238eee95a2b71508b95dc9e8531a521d78 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 6c6e7ae07d80eeeefd0fdf713e09ec097ccda6a0..6bf37c77f0a77b11464a3560b1680fb89b0ed2dd 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 5340d3bec31dfdee0be234aa80dab27b44037304..2b3eff4023b9fb3193e55c0c970b3f71b7b7620b 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 8ee4360aff9293178e338e3ef300c37f6f2ac809..5e19e813748dfa0d065287494240007d60478dea 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 3b1a1518e7647366b4de0e90828b8d97b82c5bd5..b9df58b86ce953427e01ffb8c7eb7e52f9c2392a 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 8ed62d43ffd5e340c36e13e00cb62965104f3802..edab68ae836659a7081a16b4f32801945dafefa3 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 636315060eb47e1d2aa37e412bd79c9261b898a2..673ccf16202302d54592a0f5dfd80e9818709090 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 122b6c48fd807672bd3252fb71da667a07181d29..51648801710af1800efd0d65c71570adf3a7c41f 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 485842838025537d28912b5766842a3604d03e39..ec1b3f55cb5c9decb6a82e3c9aa2d5760a1a224a 100644 --- a/sound/soc/intel/avs/core.c +++ b/sound/soc/intel/avs/core.c @@ -945,14 +945,14 @@ MODULE_AUTHOR("Cezary Rojewski "); MODULE_AUTHOR("Amadeusz Slawinski "); 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 8c4edda97f757f864c97ddef59ece6c357857b60..c625cf879f170276a528938c1fa3a540c1f20dc3 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 08ed9d96738a05ea88c85c04c73d878b8da921af..0314f9d4ea5f40084bef73c8e065bf1ffe60d087 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 138e4e9de5e3095de153ef7d3760367537fb592e..353e343b1d2884064f056a990a66b14565c98cb9 100644 --- a/sound/soc/intel/avs/loader.c +++ b/sound/soc/intel/avs/loader.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include "avs.h" diff --git a/sound/soc/intel/avs/path.c b/sound/soc/intel/avs/path.c index ed8f0ea0e10dbb7907bc440dbd4b154fd56c5790..e8e6b1c7fc903bf62eeb0067764ee785a1ffabc7 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 405cfc1ab0cba63f25c8402f03fad9874cf8a3db..ccf90428126d8ca674277ba471512633cd777195 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 ca7a30ebd26ab1acaa827784d0c775ff415e021b..e86b4a03dd61d2d3ad6a4d9602f69effbaefaa83 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 16db7b53ddac7e4941f52f78cb753678e896afa9..985ce2ae286ba1860f338b37aaff0825e659f486 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 26b7c55c9c11eb57e0e2ec1b56f0c4c25862ba7a..67267304e7e920aa25f6ba7e34f859fa272f0d9b 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 7d9628cda87534dd3cad8bcb1e0faa7b8e5dd770..0f47aadaabe171bcab42de260609b832557f74f5 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 ef7557be5d66479ac9a3837edc16d36a0b2cbff7..7b59d514b432a2391bffba2c58691da72f2b361d 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) @@ -1290,6 +1382,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. * @@ -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 65d0676075e1361c9481319a682e51b544874b61..a29abe4ce436804cf79752264219e56503618e31 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 4919001de08b3eec87098c5280e3ee0702952b15..4eed54b071a5c48bc20675b7efd05cd1e1f5c105 100644 --- a/sound/soc/qcom/qdsp6/q6dsp-lpass-ports.c +++ b/sound/soc/qcom/qdsp6/q6dsp-lpass-ports.c @@ -97,6 +97,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", @@ -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 7f052c8a125777c557c30df210e4fdb1fa5723e9..d8dde6dd0aca7192769b246bdc42d26f776a075e 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 90228699ba7d490ae5abee3811b43f3131974eb4..f49243daa517f2f4d42e5e30e94ac1581118fd54 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 0000000000000000000000000000000000000000..ebe0c242592779672eaf53fa6246630aacd91320 --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#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 9039107972e2b34c5c4bfbb6e7da35878afaf38d..b70b2a5031dfbf69024666f8a1049c263efcde0a 100644 --- a/sound/soc/qcom/sm8250.c +++ b/sound/soc/qcom/sm8250.c @@ -13,6 +13,7 @@ #include #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 0000000000000000000000000000000000000000..0a24b278fcdfcaf2fc873dd13bd45ef2d1f00dd4 --- /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 +#include +#include +#include + +#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 0000000000000000000000000000000000000000..c3f411f565b0c1d5bd9656088716d37c849fbd51 --- /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 + +#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 43835197d1feea1f073ece824c8bbb758e437682..2c21fd528afd0fb7188f4bffadc477149aaae18b 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 0000000000000000000000000000000000000000..26baa66d29a87b2d0d4d77a6f272a1850b7ed2e3 --- /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 +#include + +#include +#include + +#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 cf43ac19c4a6d0db315503f8760c9b2704730f72..55e7cb96858fcaf7b51566718ad8bb465f07d37e 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 02e2c69d7f18e3dae4cb9fa26bc56c6959484409..cff6aba9bfc392bf9a20e1ac3b43c5bf9d2bcfce 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 4a9569a3a39a595b240f29855a5b5fff0c637adf..41c47301bc19c968906b57757b5dba1b9937e5b4 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 30bd5348477b173cbca8e210c2036ac3554ab4a1..e62794a87e73aa50a4a75fc34c66f520ce8c93fc 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 9c411b82a218dcea42a728429f9e7fc1ddcd4643..9fb8726a6c935fabc28bb53297c9b982adf87d7e 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 6ec95b2edf863e252fc7c3422bc274a7a0c9b564..94404c24d240d45ca0f4567282d0ac4b844bc1cf 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 f36ec98da4601d3284c5b39675520362ddeaf0c6..7b01e7b4e335fb1c36bc3d8aad11e4673f8940fa 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 0ba4641a0eb11d57c3297dbcbfa5f7d08450369b..8cd54f7bf33a198278e3071166a29f5f74eab0c6 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 72b671fb2c84ca42d11dc95f705ad1b7dc30a284..497d2b27fb59eff6b0f547c15b752c83c7620b74 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 4727043fd74580de6464e3076df0e997285a570e..77f06da93151e88d7a4a5547e2dd4b2c2b2174e8 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 3a8a977ed359c9f75b872c5a03a3d7358edd0edd..866e613fee4f17fb92b6cc71fc95aed4dfda300b 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 08bf535ed1632fcdffbb1d54843e6c5ae5581c0c..b24ee38fad7203fd73150d51cdf6b2e9163b3077 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 388fe2ba346d67fd0f616a21d64fb68478c1494a..c096021adb2b113aecde6e30742cd325fc0db3b9 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 0000000000000000000000000000000000000000..6567727b66f0e9568a3e5ddc88f60fa21934fb66 --- /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 0000000000000000000000000000000000000000..2adeb64f4d33f4c33a915d3a895a071fd8d0630c --- /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 + +#include +#include +#include + +#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 0000000000000000000000000000000000000000..cf20673f4dc9c2d7e1e152476e8f043247a7fc48 --- /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 0000000000000000000000000000000000000000..5bc27c82e0af5c4b6bf7a249e5531720a20fe841 --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 0000000000000000000000000000000000000000..50285761227746e3788f3711219f5d2948aa761e --- /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 + +#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 0000000000000000000000000000000000000000..a1298d75d9f880da3f92bad49036b4e358813ba5 --- /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 5ed523b13fadba30be73ad3bce33fc88269183bb..bd24f3a78ea9dbdea6686ffa9012a783b48cf6f2 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/bpf/resolve_btfids/Makefile b/tools/bpf/resolve_btfids/Makefile index afbddea3a39c64ffb2efc874a3637b6401791c5b..ce1b556dfa90f1c6b52fb186228ba776cf4027b1 100644 --- a/tools/bpf/resolve_btfids/Makefile +++ b/tools/bpf/resolve_btfids/Makefile @@ -17,7 +17,7 @@ endif # Overrides for the prepare step libraries. HOST_OVERRIDES := AR="$(HOSTAR)" CC="$(HOSTCC)" LD="$(HOSTLD)" ARCH="$(HOSTARCH)" \ - CROSS_COMPILE="" EXTRA_CFLAGS="$(HOSTCFLAGS)" + CROSS_COMPILE="" CLANG_CROSS_FLAGS="" EXTRA_CFLAGS="$(HOSTCFLAGS)" RM ?= rm HOSTCC ?= gcc diff --git a/tools/iio/iio_generic_buffer.c b/tools/iio/iio_generic_buffer.c index 9ef5ee087eda367ff2c01923802238421bdbf7eb..bc82bb6a7a2a9dbfaf7f8d3857ca6a20d1a78052 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/lib/bpf/btf.c b/tools/lib/bpf/btf.c index f1d495dc66bba234c7ff8abbb2027e9f6d7a8fd7..37682908cb0f3bd4703eb2ee811aa3da3673c33b 100644 --- a/tools/lib/bpf/btf.c +++ b/tools/lib/bpf/btf.c @@ -1384,12 +1384,12 @@ static struct btf *btf_parse_raw_mmap(const char *path, struct btf *base_btf) fd = open(path, O_RDONLY); if (fd < 0) - return libbpf_err_ptr(-errno); + return ERR_PTR(-errno); if (fstat(fd, &st) < 0) { err = -errno; close(fd); - return libbpf_err_ptr(err); + return ERR_PTR(err); } data = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); @@ -1397,7 +1397,7 @@ static struct btf *btf_parse_raw_mmap(const char *path, struct btf *base_btf) close(fd); if (data == MAP_FAILED) - return libbpf_err_ptr(err); + return ERR_PTR(err); btf = btf_new(data, st.st_size, base_btf, true); if (IS_ERR(btf)) diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c index 01818abd02df9e0663fb2ccbd0ae3ed55dd532bc..6d2c280a1730c5ef5a90e5448267e5f6c305b2b1 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 b74ed916057e0862c6dc36cab973d030b4ac38da..fb11108aaf42b93a4cd618956d9fd189bbe83f71 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 0170d3cc68194c9b8b820f7c0445967e242d29f6..5230e072e414c644cd9ba9833a23566e4a258320 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 \n"); + fprintf(outf, "turbostat version 2025.06.08 - Len Brown \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/drivers/net/hw/rss_ctx.py b/tools/testing/selftests/drivers/net/hw/rss_ctx.py index ca60ae325c22eb1d35a669f9fa33d384bfa70012..7bb552f8b1826989e60325c3dde88bbabeb0c581 100755 --- a/tools/testing/selftests/drivers/net/hw/rss_ctx.py +++ b/tools/testing/selftests/drivers/net/hw/rss_ctx.py @@ -747,6 +747,62 @@ def test_rss_ntuple_addition(cfg): 'noise' : (0,) }) +def test_rss_default_context_rule(cfg): + """ + Allocate a port, direct this port to context 0, then create a new RSS + context and steer all TCP traffic to it (context 1). Verify that: + * Traffic to the specific port continues to use queues of the main + context (0/1). + * Traffic to any other TCP port is redirected to the new context + (queues 2/3). + """ + + require_ntuple(cfg) + + queue_cnt = len(_get_rx_cnts(cfg)) + if queue_cnt < 4: + try: + ksft_pr(f"Increasing queue count {queue_cnt} -> 4") + ethtool(f"-L {cfg.ifname} combined 4") + defer(ethtool, f"-L {cfg.ifname} combined {queue_cnt}") + except Exception as exc: + raise KsftSkipEx("Not enough queues for the test") from exc + + # Use queues 0 and 1 for the main context + ethtool(f"-X {cfg.ifname} equal 2") + defer(ethtool, f"-X {cfg.ifname} default") + + # Create a new RSS context that uses queues 2 and 3 + ctx_id = ethtool_create(cfg, "-X", "context new start 2 equal 2") + defer(ethtool, f"-X {cfg.ifname} context {ctx_id} delete") + + # Generic low-priority rule: redirect all TCP traffic to the new context. + # Give it an explicit higher location number (lower priority). + flow_generic = f"flow-type tcp{cfg.addr_ipver} dst-ip {cfg.addr} context {ctx_id} loc 1" + ethtool(f"-N {cfg.ifname} {flow_generic}") + defer(ethtool, f"-N {cfg.ifname} delete 1") + + # Specific high-priority rule for a random port that should stay on context 0. + # Assign loc 0 so it is evaluated before the generic rule. + port_main = rand_port() + flow_main = f"flow-type tcp{cfg.addr_ipver} dst-ip {cfg.addr} dst-port {port_main} context 0 loc 0" + ethtool(f"-N {cfg.ifname} {flow_main}") + defer(ethtool, f"-N {cfg.ifname} delete 0") + + _ntuple_rule_check(cfg, 1, ctx_id) + + # Verify that traffic matching the specific rule still goes to queues 0/1 + _send_traffic_check(cfg, port_main, "context 0", + { 'target': (0, 1), + 'empty' : (2, 3) }) + + # And that traffic for any other port is steered to the new context + port_other = rand_port() + _send_traffic_check(cfg, port_other, f"context {ctx_id}", + { 'target': (2, 3), + 'noise' : (0, 1) }) + + def main() -> None: with NetDrvEpEnv(__file__, nsim_test=False) as cfg: cfg.context_cnt = None @@ -760,7 +816,8 @@ def main() -> None: test_rss_context_overlap, test_rss_context_overlap2, test_rss_context_out_of_order, test_rss_context4_create_with_cfg, test_flow_add_context_missing, - test_delete_rss_context_busy, test_rss_ntuple_addition], + test_delete_rss_context_busy, test_rss_ntuple_addition, + test_rss_default_context_rule], args=(cfg, )) ksft_exit() diff --git a/tools/testing/selftests/mm/ksm_tests.c b/tools/testing/selftests/mm/ksm_tests.c index dcdd5bb20f3d8c9bb00a8362ced323b2acbe18fb..e80deac1436be29dff4a442393da9e1570726f47 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 c76646cdf6e6f9bcc431f16a6046f94ae2575004..bbae66fc5038c3ce42bea5afeb9bf98ef54f5d64 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 #include #include #include #include +#include #include +#include #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 a41bc1234b375dae2f7d0c6329d6cf72e290523a..95b6f043a3cbd3a66655e899e9acdfc4ef50ec9e 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 61d7bf1f8c62ffd6b195b88c0aaee6907c639764..5492e3f784dfc39125feda0088d483da1e8c9cbd 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 adb5d294a2206cf4ecf07fdc9482333b879e202f..b8136d12a0f88597f8f84fc9529130c5323891bd 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 8b378c91debf5ceda8b84f03ebb9b832327e42db..b1e4618399be6720e92a2dba6e27947d5698dce3 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/net/Makefile b/tools/testing/selftests/net/Makefile index ea84b88bcb30f9b4a3d21b5ffbb1e4a09f3b46ac..ab996bd22a5fc04f2c6d54e1d595caa89c17f85a 100644 --- a/tools/testing/selftests/net/Makefile +++ b/tools/testing/selftests/net/Makefile @@ -27,6 +27,7 @@ TEST_PROGS += amt.sh TEST_PROGS += unicast_extensions.sh TEST_PROGS += udpgro_fwd.sh TEST_PROGS += udpgro_frglist.sh +TEST_PROGS += nat6to4.sh TEST_PROGS += veth.sh TEST_PROGS += ioam6.sh TEST_PROGS += gro.sh diff --git a/tools/testing/selftests/net/nat6to4.sh b/tools/testing/selftests/net/nat6to4.sh new file mode 100755 index 0000000000000000000000000000000000000000..0ee859b622a4bb9a0f5eb2003f5e483decbd72a4 --- /dev/null +++ b/tools/testing/selftests/net/nat6to4.sh @@ -0,0 +1,15 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +NS="ns-peer-$(mktemp -u XXXXXX)" + +ip netns add "${NS}" +ip -netns "${NS}" link set lo up +ip -netns "${NS}" route add default via 127.0.0.2 dev lo + +tc -n "${NS}" qdisc add dev lo ingress +tc -n "${NS}" filter add dev lo ingress prio 4 protocol ip \ + bpf object-file nat6to4.bpf.o section schedcls/egress4/snat4 direct-action + +ip netns exec "${NS}" \ + bash -c 'echo 012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789abc | socat - UDP4-DATAGRAM:224.1.0.1:6666,ip-multicast-loop=1' diff --git a/tools/testing/selftests/ublk/Makefile b/tools/testing/selftests/ublk/Makefile index 4dde8838261d660ba31a07d608332d1733a6321d..5d7f4ecfb81612f919a89eb442f948d6bfafe225 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 5421774d7867cb5b0edd96dc702a4f85a75f9e6f..6e60f7d9712593403ac5547334c86967f0eab8d3 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 509842df9beefa494a4130f5fb23fb022d7fa326..cfa59b631693793465f0e6909a6fbe1a364f4523 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 b5131a000795d6a8d589bd7ade6cce4216dbe182..e2d2042810d4bb472e48a0ed91317d2bdf6e2f2a 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 e34508bf5798b539f0290e21b37b591dc5689f59..6be601536b3d2c095654da5fba0cf13a51142052 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 44aca31cf2b05861b9378b5e2b38971754aabe3e..afe0b99d77eec74acae04952a9af5348252bc599 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 404a143bf3d69599aea3d7119e9ba50d6d739ba8..37d50bbf5f5e86a520efedc9228510f8e1273625 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 0145569ee7e9a45b41898c2c789842b4c8380f18..8a4dbd09feb0a885ec7539f1a285ed6f437fe3ab 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 0000000000000000000000000000000000000000..7abbb00d251df9403857b1c6f53aec8bf8eab176 --- /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 7d728ce507740d254568baa20fb3f351ede96042..6eef282d569f8712c5525860e88f0441644cb8d8 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 9bcfa64ea1f05c459c8139bb9ece8368426fdcbf..40d1437ca298f70aa48dab53b4990d1d9ce8639e 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 bcfc904cefc602f6e79c2c87ce63856b0b765b23..566cfd90d192ce8c1f98ca2539792d54a787b3d1 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 0000000000000000000000000000000000000000..f4aa63ff2938a4097c2b848f379dbc87fe898a7f --- /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 d6e09af7c0a927a875105ca3d5c9830fa2ca6dc4..a4a82e1c28a905a4b5f593375a09331c422f5c17 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 441feb21aa5a92b7edddb07258c7f368171de15b..4505b1c31be10430bd03c5af0503ae187535a3ac 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);