diff options
619 files changed, 9093 insertions, 3987 deletions
@@ -191,10 +191,11 @@ Gao Xiang <xiang@kernel.org> <gaoxiang25@huawei.com> Gao Xiang <xiang@kernel.org> <hsiangkao@aol.com> Gao Xiang <xiang@kernel.org> <hsiangkao@linux.alibaba.com> Gao Xiang <xiang@kernel.org> <hsiangkao@redhat.com> -Geliang Tang <geliang.tang@linux.dev> <geliang.tang@suse.com> -Geliang Tang <geliang.tang@linux.dev> <geliangtang@xiaomi.com> -Geliang Tang <geliang.tang@linux.dev> <geliangtang@gmail.com> -Geliang Tang <geliang.tang@linux.dev> <geliangtang@163.com> +Geliang Tang <geliang@kernel.org> <geliang.tang@linux.dev> +Geliang Tang <geliang@kernel.org> <geliang.tang@suse.com> +Geliang Tang <geliang@kernel.org> <geliangtang@xiaomi.com> +Geliang Tang <geliang@kernel.org> <geliangtang@gmail.com> +Geliang Tang <geliang@kernel.org> <geliangtang@163.com> Georgi Djakov <djakov@kernel.org> <georgi.djakov@linaro.org> Gerald Schaefer <gerald.schaefer@linux.ibm.com> <geraldsc@de.ibm.com> Gerald Schaefer <gerald.schaefer@linux.ibm.com> <gerald.schaefer@de.ibm.com> diff --git a/Documentation/ABI/testing/sysfs-class-net-statistics b/Documentation/ABI/testing/sysfs-class-net-statistics index 55db27815361..53e508c6936a 100644 --- a/Documentation/ABI/testing/sysfs-class-net-statistics +++ b/Documentation/ABI/testing/sysfs-class-net-statistics @@ -1,4 +1,4 @@ -What: /sys/class/<iface>/statistics/collisions +What: /sys/class/net/<iface>/statistics/collisions Date: April 2005 KernelVersion: 2.6.12 Contact: netdev@vger.kernel.org @@ -6,7 +6,7 @@ Description: Indicates the number of collisions seen by this network device. This value might not be relevant with all MAC layers. -What: /sys/class/<iface>/statistics/multicast +What: /sys/class/net/<iface>/statistics/multicast Date: April 2005 KernelVersion: 2.6.12 Contact: netdev@vger.kernel.org @@ -14,7 +14,7 @@ Description: Indicates the number of multicast packets received by this network device. -What: /sys/class/<iface>/statistics/rx_bytes +What: /sys/class/net/<iface>/statistics/rx_bytes Date: April 2005 KernelVersion: 2.6.12 Contact: netdev@vger.kernel.org @@ -23,7 +23,7 @@ Description: See the network driver for the exact meaning of when this value is incremented. -What: /sys/class/<iface>/statistics/rx_compressed +What: /sys/class/net/<iface>/statistics/rx_compressed Date: April 2005 KernelVersion: 2.6.12 Contact: netdev@vger.kernel.org @@ -32,7 +32,7 @@ Description: network device. This value might only be relevant for interfaces that support packet compression (e.g: PPP). -What: /sys/class/<iface>/statistics/rx_crc_errors +What: /sys/class/net/<iface>/statistics/rx_crc_errors Date: April 2005 KernelVersion: 2.6.12 Contact: netdev@vger.kernel.org @@ -41,7 +41,7 @@ Description: by this network device. Note that the specific meaning might depend on the MAC layer used by the interface. -What: /sys/class/<iface>/statistics/rx_dropped +What: /sys/class/net/<iface>/statistics/rx_dropped Date: April 2005 KernelVersion: 2.6.12 Contact: netdev@vger.kernel.org @@ -51,7 +51,7 @@ Description: packet processing. See the network driver for the exact meaning of this value. -What: /sys/class/<iface>/statistics/rx_errors +What: /sys/class/net/<iface>/statistics/rx_errors Date: April 2005 KernelVersion: 2.6.12 Contact: netdev@vger.kernel.org @@ -59,7 +59,7 @@ Description: Indicates the number of receive errors on this network device. See the network driver for the exact meaning of this value. -What: /sys/class/<iface>/statistics/rx_fifo_errors +What: /sys/class/net/<iface>/statistics/rx_fifo_errors Date: April 2005 KernelVersion: 2.6.12 Contact: netdev@vger.kernel.org @@ -68,7 +68,7 @@ Description: network device. See the network driver for the exact meaning of this value. -What: /sys/class/<iface>/statistics/rx_frame_errors +What: /sys/class/net/<iface>/statistics/rx_frame_errors Date: April 2005 KernelVersion: 2.6.12 Contact: netdev@vger.kernel.org @@ -78,7 +78,7 @@ Description: on the MAC layer protocol used. See the network driver for the exact meaning of this value. -What: /sys/class/<iface>/statistics/rx_length_errors +What: /sys/class/net/<iface>/statistics/rx_length_errors Date: April 2005 KernelVersion: 2.6.12 Contact: netdev@vger.kernel.org @@ -87,7 +87,7 @@ Description: error, oversized or undersized. See the network driver for the exact meaning of this value. -What: /sys/class/<iface>/statistics/rx_missed_errors +What: /sys/class/net/<iface>/statistics/rx_missed_errors Date: April 2005 KernelVersion: 2.6.12 Contact: netdev@vger.kernel.org @@ -96,7 +96,7 @@ Description: due to lack of capacity in the receive side. See the network driver for the exact meaning of this value. -What: /sys/class/<iface>/statistics/rx_nohandler +What: /sys/class/net/<iface>/statistics/rx_nohandler Date: February 2016 KernelVersion: 4.6 Contact: netdev@vger.kernel.org @@ -104,7 +104,7 @@ Description: Indicates the number of received packets that were dropped on an inactive device by the network core. -What: /sys/class/<iface>/statistics/rx_over_errors +What: /sys/class/net/<iface>/statistics/rx_over_errors Date: April 2005 KernelVersion: 2.6.12 Contact: netdev@vger.kernel.org @@ -114,7 +114,7 @@ Description: (e.g: larger than MTU). See the network driver for the exact meaning of this value. -What: /sys/class/<iface>/statistics/rx_packets +What: /sys/class/net/<iface>/statistics/rx_packets Date: April 2005 KernelVersion: 2.6.12 Contact: netdev@vger.kernel.org @@ -122,7 +122,7 @@ Description: Indicates the total number of good packets received by this network device. -What: /sys/class/<iface>/statistics/tx_aborted_errors +What: /sys/class/net/<iface>/statistics/tx_aborted_errors Date: April 2005 KernelVersion: 2.6.12 Contact: netdev@vger.kernel.org @@ -132,7 +132,7 @@ Description: a medium collision). See the network driver for the exact meaning of this value. -What: /sys/class/<iface>/statistics/tx_bytes +What: /sys/class/net/<iface>/statistics/tx_bytes Date: April 2005 KernelVersion: 2.6.12 Contact: netdev@vger.kernel.org @@ -143,7 +143,7 @@ Description: transmitted packets or all packets that have been queued for transmission. -What: /sys/class/<iface>/statistics/tx_carrier_errors +What: /sys/class/net/<iface>/statistics/tx_carrier_errors Date: April 2005 KernelVersion: 2.6.12 Contact: netdev@vger.kernel.org @@ -152,7 +152,7 @@ Description: because of carrier errors (e.g: physical link down). See the network driver for the exact meaning of this value. -What: /sys/class/<iface>/statistics/tx_compressed +What: /sys/class/net/<iface>/statistics/tx_compressed Date: April 2005 KernelVersion: 2.6.12 Contact: netdev@vger.kernel.org @@ -161,7 +161,7 @@ Description: this might only be relevant for devices that support compression (e.g: PPP). -What: /sys/class/<iface>/statistics/tx_dropped +What: /sys/class/net/<iface>/statistics/tx_dropped Date: April 2005 KernelVersion: 2.6.12 Contact: netdev@vger.kernel.org @@ -170,7 +170,7 @@ Description: See the driver for the exact reasons as to why the packets were dropped. -What: /sys/class/<iface>/statistics/tx_errors +What: /sys/class/net/<iface>/statistics/tx_errors Date: April 2005 KernelVersion: 2.6.12 Contact: netdev@vger.kernel.org @@ -179,7 +179,7 @@ Description: a network device. See the driver for the exact reasons as to why the packets were dropped. -What: /sys/class/<iface>/statistics/tx_fifo_errors +What: /sys/class/net/<iface>/statistics/tx_fifo_errors Date: April 2005 KernelVersion: 2.6.12 Contact: netdev@vger.kernel.org @@ -188,7 +188,7 @@ Description: FIFO error. See the driver for the exact reasons as to why the packets were dropped. -What: /sys/class/<iface>/statistics/tx_heartbeat_errors +What: /sys/class/net/<iface>/statistics/tx_heartbeat_errors Date: April 2005 KernelVersion: 2.6.12 Contact: netdev@vger.kernel.org @@ -197,7 +197,7 @@ Description: reported as heartbeat errors. See the driver for the exact reasons as to why the packets were dropped. -What: /sys/class/<iface>/statistics/tx_packets +What: /sys/class/net/<iface>/statistics/tx_packets Date: April 2005 KernelVersion: 2.6.12 Contact: netdev@vger.kernel.org @@ -206,7 +206,7 @@ Description: device. See the driver for whether this reports the number of all attempted or successful transmissions. -What: /sys/class/<iface>/statistics/tx_window_errors +What: /sys/class/net/<iface>/statistics/tx_window_errors Date: April 2005 KernelVersion: 2.6.12 Contact: netdev@vger.kernel.org diff --git a/Documentation/ABI/testing/sysfs-nvmem-cells b/Documentation/ABI/testing/sysfs-nvmem-cells index 7af70adf3690..c7c9444f92a8 100644 --- a/Documentation/ABI/testing/sysfs-nvmem-cells +++ b/Documentation/ABI/testing/sysfs-nvmem-cells @@ -4,18 +4,18 @@ KernelVersion: 6.5 Contact: Miquel Raynal <miquel.raynal@bootlin.com> Description: The "cells" folder contains one file per cell exposed by the - NVMEM device. The name of the file is: <name>@<where>, with - <name> being the cell name and <where> its location in the NVMEM - device, in hexadecimal (without the '0x' prefix, to mimic device - tree node names). The length of the file is the size of the cell - (when known). The content of the file is the binary content of - the cell (may sometimes be ASCII, likely without trailing - character). + NVMEM device. The name of the file is: "<name>@<byte>,<bit>", + with <name> being the cell name and <where> its location in + the NVMEM device, in hexadecimal bytes and bits (without the + '0x' prefix, to mimic device tree node names). The length of + the file is the size of the cell (when known). The content of + the file is the binary content of the cell (may sometimes be + ASCII, likely without trailing character). Note: This file is only present if CONFIG_NVMEM_SYSFS is enabled. Example:: - hexdump -C /sys/bus/nvmem/devices/1-00563/cells/product-name@d + hexdump -C /sys/bus/nvmem/devices/1-00563/cells/product-name@d,0 00000000 54 4e 34 38 4d 2d 50 2d 44 4e |TN48M-P-DN| 0000000a diff --git a/Documentation/arch/arm64/silicon-errata.rst b/Documentation/arch/arm64/silicon-errata.rst index e8c2ce1f9df6..45a7f4932fe0 100644 --- a/Documentation/arch/arm64/silicon-errata.rst +++ b/Documentation/arch/arm64/silicon-errata.rst @@ -243,3 +243,10 @@ stable kernels. +----------------+-----------------+-----------------+-----------------------------+ | ASR | ASR8601 | #8601001 | N/A | +----------------+-----------------+-----------------+-----------------------------+ ++----------------+-----------------+-----------------+-----------------------------+ +| Microsoft | Azure Cobalt 100| #2139208 | ARM64_ERRATUM_2139208 | ++----------------+-----------------+-----------------+-----------------------------+ +| Microsoft | Azure Cobalt 100| #2067961 | ARM64_ERRATUM_2067961 | ++----------------+-----------------+-----------------+-----------------------------+ +| Microsoft | Azure Cobalt 100| #2253138 | ARM64_ERRATUM_2253138 | ++----------------+-----------------+-----------------+-----------------------------+ diff --git a/Documentation/devicetree/bindings/Makefile b/Documentation/devicetree/bindings/Makefile index 2323fd5b7cda..129cf698fa8a 100644 --- a/Documentation/devicetree/bindings/Makefile +++ b/Documentation/devicetree/bindings/Makefile @@ -28,7 +28,10 @@ $(obj)/%.example.dts: $(src)/%.yaml check_dtschema_version FORCE find_all_cmd = find $(srctree)/$(src) \( -name '*.yaml' ! \ -name 'processed-schema*' \) -find_cmd = $(find_all_cmd) | sed 's|^$(srctree)/$(src)/||' | grep -F -e "$(subst :," -e ",$(DT_SCHEMA_FILES))" | sed 's|^|$(srctree)/$(src)/|' +find_cmd = $(find_all_cmd) | \ + sed 's|^$(srctree)/||' | \ + grep -F -e "$(subst :," -e ",$(DT_SCHEMA_FILES))" | \ + sed 's|^|$(srctree)/|' CHK_DT_DOCS := $(shell $(find_cmd)) quiet_cmd_yamllint = LINT $(src) diff --git a/Documentation/devicetree/bindings/ata/ceva,ahci-1v84.yaml b/Documentation/devicetree/bindings/ata/ceva,ahci-1v84.yaml index b29ce598f9aa..9952e0ef7767 100644 --- a/Documentation/devicetree/bindings/ata/ceva,ahci-1v84.yaml +++ b/Documentation/devicetree/bindings/ata/ceva,ahci-1v84.yaml @@ -7,7 +7,8 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# title: Ceva AHCI SATA Controller maintainers: - - Piyush Mehta <piyush.mehta@amd.com> + - Mubin Sayyed <mubin.sayyed@amd.com> + - Radhey Shyam Pandey <radhey.shyam.pandey@amd.com> description: | The Ceva SATA controller mostly conforms to the AHCI interface with some diff --git a/Documentation/devicetree/bindings/display/bridge/nxp,tda998x.yaml b/Documentation/devicetree/bindings/display/bridge/nxp,tda998x.yaml index 21d995f29a1e..b8e9cf6ce4e6 100644 --- a/Documentation/devicetree/bindings/display/bridge/nxp,tda998x.yaml +++ b/Documentation/devicetree/bindings/display/bridge/nxp,tda998x.yaml @@ -29,19 +29,22 @@ properties: audio-ports: description: - Array of 8-bit values, 2 values per DAI (Documentation/sound/soc/dai.rst). + Array of 2 values per DAI (Documentation/sound/soc/dai.rst). The implementation allows one or two DAIs. If two DAIs are defined, they must be of different type. $ref: /schemas/types.yaml#/definitions/uint32-matrix + minItems: 1 + maxItems: 2 items: - minItems: 1 items: - description: | The first value defines the DAI type: TDA998x_SPDIF or TDA998x_I2S (see include/dt-bindings/display/tda998x.h). + enum: [ 1, 2 ] - description: The second value defines the tda998x AP_ENA reg content when the DAI in question is used. + maximum: 0xff '#sound-dai-cells': enum: [ 0, 1 ] diff --git a/Documentation/devicetree/bindings/gpio/xlnx,zynqmp-gpio-modepin.yaml b/Documentation/devicetree/bindings/gpio/xlnx,zynqmp-gpio-modepin.yaml index b1fd632718d4..bb93baa88879 100644 --- a/Documentation/devicetree/bindings/gpio/xlnx,zynqmp-gpio-modepin.yaml +++ b/Documentation/devicetree/bindings/gpio/xlnx,zynqmp-gpio-modepin.yaml @@ -12,7 +12,8 @@ description: PS_MODE). Every pin can be configured as input/output. maintainers: - - Piyush Mehta <piyush.mehta@amd.com> + - Mubin Sayyed <mubin.sayyed@amd.com> + - Radhey Shyam Pandey <radhey.shyam.pandey@amd.com> properties: compatible: diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad9467.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad9467.yaml index 7aa748d6b7a0..eecd5fbab695 100644 --- a/Documentation/devicetree/bindings/iio/adc/adi,ad9467.yaml +++ b/Documentation/devicetree/bindings/iio/adc/adi,ad9467.yaml @@ -44,6 +44,9 @@ properties: Pin that controls the powerdown mode of the device. maxItems: 1 + io-backends: + maxItems: 1 + reset-gpios: description: Reset pin for the device. @@ -68,6 +71,7 @@ examples: reg = <0>; clocks = <&adc_clk>; clock-names = "adc-clk"; + io-backends = <&iio_backend>; }; }; ... diff --git a/Documentation/devicetree/bindings/iio/adc/adi,axi-adc.yaml b/Documentation/devicetree/bindings/iio/adc/adi,axi-adc.yaml index 9996dd93f84b..3d49d21ad33d 100644 --- a/Documentation/devicetree/bindings/iio/adc/adi,axi-adc.yaml +++ b/Documentation/devicetree/bindings/iio/adc/adi,axi-adc.yaml @@ -39,12 +39,15 @@ properties: $ref: /schemas/types.yaml#/definitions/phandle description: A reference to a the actual ADC to which this FPGA ADC interfaces to. + deprecated: true + + '#io-backend-cells': + const: 0 required: - compatible - dmas - reg - - adi,adc-dev additionalProperties: false @@ -55,7 +58,6 @@ examples: reg = <0x44a00000 0x10000>; dmas = <&rx_dma 0>; dma-names = "rx"; - - adi,adc-dev = <&spi_adc>; + #io-backend-cells = <0>; }; ... diff --git a/Documentation/devicetree/bindings/iio/adc/richtek,rtq6056.yaml b/Documentation/devicetree/bindings/iio/adc/richtek,rtq6056.yaml index 88e008629ea8..af2c3a67f888 100644 --- a/Documentation/devicetree/bindings/iio/adc/richtek,rtq6056.yaml +++ b/Documentation/devicetree/bindings/iio/adc/richtek,rtq6056.yaml @@ -25,7 +25,14 @@ description: | properties: compatible: - const: richtek,rtq6056 + oneOf: + - enum: + - richtek,rtq6056 + - richtek,rtq6059 + - items: + - enum: + - richtek,rtq6053 + - const: richtek,rtq6056 reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/iio/adc/ti,ads1298.yaml b/Documentation/devicetree/bindings/iio/adc/ti,ads1298.yaml new file mode 100644 index 000000000000..bf5a43a81d59 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/ti,ads1298.yaml @@ -0,0 +1,80 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/adc/ti,ads1298.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Texas Instruments' ads1298 medical ADC chips + +description: | + Datasheet at: https://www.ti.com/product/ADS1298 + Bindings for this chip aren't complete. + +maintainers: + - Mike Looijmans <mike.looijmans@topic.nl> + +properties: + compatible: + enum: + - ti,ads1298 + + reg: + maxItems: 1 + + spi-cpha: true + + reset-gpios: + maxItems: 1 + + avdd-supply: + description: + Analog power supply, voltage between AVDD and AVSS. When providing a + symmetric +/- 2.5V, the regulator should report 5V. + + vref-supply: + description: + Optional reference voltage. If omitted, internal reference is used, + which is 2.4V when analog supply is below 4.4V, 4V otherwise. + + clocks: + description: Optional 2.048 MHz external source clock on CLK pin + maxItems: 1 + + interrupts: + description: Interrupt on DRDY pin, triggers on falling edge + maxItems: 1 + + label: true + +required: + - compatible + - reg + - avdd-supply + - interrupts + +allOf: + - $ref: /schemas/spi/spi-peripheral-props.yaml# + +unevaluatedProperties: false + +examples: + - | + #include <dt-bindings/gpio/gpio.h> + #include <dt-bindings/interrupt-controller/irq.h> + spi { + #address-cells = <1>; + #size-cells = <0>; + + adc@1 { + reg = <1>; + compatible = "ti,ads1298"; + label = "ads1298-1-ecg"; + avdd-supply = <®_iso_5v_a>; + clocks = <&clk_ads1298>; + interrupt-parent = <&gpio0>; + interrupts = <78 IRQ_TYPE_EDGE_FALLING>; + spi-max-frequency = <20000000>; + spi-cpha; + }; + }; +... diff --git a/Documentation/devicetree/bindings/iio/afe/voltage-divider.yaml b/Documentation/devicetree/bindings/iio/afe/voltage-divider.yaml index dddf97b50549..4151f99b42aa 100644 --- a/Documentation/devicetree/bindings/iio/afe/voltage-divider.yaml +++ b/Documentation/devicetree/bindings/iio/afe/voltage-divider.yaml @@ -39,6 +39,17 @@ properties: description: | Channel node of a voltage io-channel. + '#io-channel-cells': + description: + In addition to consuming the measurement services of a voltage + output channel, the voltage divider can act as a provider of + measurement services to other devices. This is particularly + useful in scenarios wherein an ADC has an analog frontend, + such as a voltage divider, and then consuming its raw value + isn't interesting. In this case, the voltage before the divider + is desired. + const: 1 + output-ohms: description: Resistance Rout over which the output voltage is measured. See full-ohms. diff --git a/Documentation/devicetree/bindings/iio/frequency/adi,admfm2000.yaml b/Documentation/devicetree/bindings/iio/frequency/adi,admfm2000.yaml new file mode 100644 index 000000000000..2bcf4bbc12e4 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/frequency/adi,admfm2000.yaml @@ -0,0 +1,127 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +# Copyright 2024 Analog Devices Inc. +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/frequency/adi,admfm2000.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ADMFM2000 Dual Microwave Down Converter + +maintainers: + - Kim Seer Paller <kimseer.paller@analog.com> + +description: + Dual microwave down converter module with input RF and LO frequency ranges + from 0.5 to 32 GHz and an output IF frequency range from 0.1 to 8 GHz. + It consists of a LNA, mixer, IF filter, DSA, and IF amplifier for each down + conversion path. + +properties: + compatible: + enum: + - adi,admfm2000 + + '#address-cells': + const: 1 + + '#size-cells': + const: 0 + +patternProperties: + "^channel@[0-1]$": + type: object + description: Represents a channel of the device. + + additionalProperties: false + + properties: + reg: + description: + The channel number. + minimum: 0 + maximum: 1 + + adi,mixer-mode: + description: + Enable mixer mode for the channel. It downconverts RF between 5 GHz + and 32 GHz to IF between 0.5 GHz and 8 GHz. If not present, the channel + is in direct IF mode which bypasses the mixer and downconverts RF + between 2 GHz and 8 GHz to IF between 0.5 GHz and 8 GHz. + type: boolean + + switch-gpios: + description: | + GPIOs to select the RF path for the channel. The same state of CTRL-A + and CTRL-B GPIOs is not permitted. + CTRL-A CTRL-B CH1 Status CH2 Status + 1 0 Direct IF mode Mixer mode + 0 1 Mixer mode Direct IF mode + + items: + - description: CTRL-A GPIO + - description: CTRL-B GPIO + + attenuation-gpios: + description: | + Choice of attenuation: + DSA-V4 DSA-V3 DSA-V2 DSA-V1 DSA-V0 + 1 1 1 1 1 0 dB + 1 1 1 1 0 -1 dB + 1 1 1 0 1 -2 dB + 1 1 0 1 1 -4 dB + 1 0 1 1 1 -8 dB + 0 1 1 1 1 -16 dB + 0 0 0 0 0 -31 dB + + items: + - description: DSA-V0 GPIO + - description: DSA-V1 GPIO + - description: DSA-V2 GPIO + - description: DSA-V3 GPIO + - description: DSA-V4 GPIO + + required: + - reg + - switch-gpios + - attenuation-gpios + +required: + - compatible + +additionalProperties: false + +examples: + - | + #include <dt-bindings/gpio/gpio.h> + converter { + compatible = "adi,admfm2000"; + + #address-cells = <1>; + #size-cells = <0>; + + channel@0 { + reg = <0>; + switch-gpios = <&gpio 1 GPIO_ACTIVE_LOW>, + <&gpio 2 GPIO_ACTIVE_HIGH>; + + attenuation-gpios = <&gpio 17 GPIO_ACTIVE_LOW>, + <&gpio 22 GPIO_ACTIVE_LOW>, + <&gpio 23 GPIO_ACTIVE_LOW>, + <&gpio 24 GPIO_ACTIVE_LOW>, + <&gpio 25 GPIO_ACTIVE_LOW>; + }; + + channel@1 { + reg = <1>; + adi,mixer-mode; + switch-gpios = <&gpio 3 GPIO_ACTIVE_LOW>, + <&gpio 4 GPIO_ACTIVE_HIGH>; + + attenuation-gpios = <&gpio 0 GPIO_ACTIVE_LOW>, + <&gpio 5 GPIO_ACTIVE_LOW>, + <&gpio 6 GPIO_ACTIVE_LOW>, + <&gpio 16 GPIO_ACTIVE_LOW>, + <&gpio 26 GPIO_ACTIVE_LOW>; + }; + }; +... diff --git a/Documentation/devicetree/bindings/iio/humidity/ti,hdc3020.yaml b/Documentation/devicetree/bindings/iio/humidity/ti,hdc3020.yaml index 7f6d0f9edc75..8b5dedd1a598 100644 --- a/Documentation/devicetree/bindings/iio/humidity/ti,hdc3020.yaml +++ b/Documentation/devicetree/bindings/iio/humidity/ti,hdc3020.yaml @@ -43,6 +43,7 @@ additionalProperties: false examples: - | + #include <dt-bindings/interrupt-controller/irq.h> i2c { #address-cells = <1>; #size-cells = <0>; @@ -51,5 +52,7 @@ examples: compatible = "ti,hdc3021", "ti,hdc3020"; reg = <0x47>; vdd-supply = <&vcc_3v3>; + interrupt-parent = <&gpio3>; + interrupts = <23 IRQ_TYPE_EDGE_RISING>; }; }; diff --git a/Documentation/devicetree/bindings/iio/imu/st,lsm6dsx.yaml b/Documentation/devicetree/bindings/iio/imu/st,lsm6dsx.yaml index 28b667a9cb76..c48a96d17f51 100644 --- a/Documentation/devicetree/bindings/iio/imu/st,lsm6dsx.yaml +++ b/Documentation/devicetree/bindings/iio/imu/st,lsm6dsx.yaml @@ -35,7 +35,9 @@ properties: - st,lsm6dsv - st,lsm6dso16is - items: - - const: st,asm330lhhx + - enum: + - st,asm330lhhx + - st,asm330lhhxg1 - const: st,lsm6dsr - items: - const: st,lsm6dstx diff --git a/Documentation/devicetree/bindings/iio/light/ams,as73211.yaml b/Documentation/devicetree/bindings/iio/light/ams,as73211.yaml index 0e8cd02759b3..062a038aa0ff 100644 --- a/Documentation/devicetree/bindings/iio/light/ams,as73211.yaml +++ b/Documentation/devicetree/bindings/iio/light/ams,as73211.yaml @@ -4,19 +4,22 @@ $id: http://devicetree.org/schemas/iio/light/ams,as73211.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: AMS AS73211 JENCOLOR(R) Digital XYZ Sensor +title: AMS AS73211 JENCOLOR(R) Digital XYZ Sensor and AMS AS7331 UV Sensor maintainers: - Christian Eggers <ceggers@arri.de> description: | - XYZ True Color Sensor with I2C Interface + AMS AS73211 XYZ True Color Sensor with I2C Interface https://ams.com/documents/20143/36005/AS73211_DS000556_3-01.pdf/a65474c0-b302-c2fd-e30a-c98df87616df + AMS AS7331 UVA, UVB and UVC Sensor with I2C Interface + https://ams.com/documents/20143/9106314/AS7331_DS001047_4-00.pdf properties: compatible: enum: - ams,as73211 + - ams,as7331 reg: description: diff --git a/Documentation/devicetree/bindings/iio/pressure/honeywell,hsc030pa.yaml b/Documentation/devicetree/bindings/iio/pressure/honeywell,hsc030pa.yaml index 65a24ed67b3c..89977b9f01cf 100644 --- a/Documentation/devicetree/bindings/iio/pressure/honeywell,hsc030pa.yaml +++ b/Documentation/devicetree/bindings/iio/pressure/honeywell,hsc030pa.yaml @@ -99,6 +99,9 @@ required: - honeywell,transfer-function - honeywell,pressure-triplet +allOf: + - $ref: /schemas/spi/spi-peripheral-props.yaml + additionalProperties: false dependentSchemas: diff --git a/Documentation/devicetree/bindings/iio/pressure/honeywell,mprls0025pa.yaml b/Documentation/devicetree/bindings/iio/pressure/honeywell,mprls0025pa.yaml index d9e903fbfd99..6994b30015bd 100644 --- a/Documentation/devicetree/bindings/iio/pressure/honeywell,mprls0025pa.yaml +++ b/Documentation/devicetree/bindings/iio/pressure/honeywell,mprls0025pa.yaml @@ -8,25 +8,28 @@ title: Honeywell mprls0025pa pressure sensor maintainers: - Andreas Klinger <ak@it-klinger.de> + - Petre Rodan <petre.rodan@subdimension.ro> description: | Honeywell pressure sensor of model mprls0025pa. - This sensor has an I2C and SPI interface. Only the I2C interface is - implemented. + This sensor has an I2C and SPI interface. There are many models with different pressure ranges available. The vendor calls them "mpr series". All of them have the identical programming model and differ in the pressure range, unit and transfer function. - To support different models one need to specify the pressure range as well as - the transfer function. Pressure range needs to be converted from its unit to - pascal. + To support different models one need to specify its pressure triplet as well + as the transfer function. + + For custom silicon chips not covered by the Honeywell MPR series datasheet, + the pressure values can be specified manually via honeywell,pmin-pascal and + honeywell,pmax-pascal. + The minimal range value stands for the minimum pressure and the maximum value + also for the maximum pressure with linear relation inside the range. The transfer function defines the ranges of numerical values delivered by the - sensor. The minimal range value stands for the minimum pressure and the - maximum value also for the maximum pressure with linear relation inside the - range. + sensor. Specifications about the devices can be found at: https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/ @@ -42,6 +45,10 @@ properties: maxItems: 1 interrupts: + description: + Optional interrupt for indicating End-of-conversion. + If not present, the driver loops for a while until the received status + byte indicates correct measurement. maxItems: 1 reset-gpios: @@ -50,14 +57,6 @@ properties: If not present the device is not reset during the probe. maxItems: 1 - honeywell,pmin-pascal: - description: - Minimum pressure value the sensor can measure in pascal. - - honeywell,pmax-pascal: - description: - Maximum pressure value the sensor can measure in pascal. - honeywell,transfer-function: description: | Transfer function which defines the range of valid values delivered by the @@ -65,19 +64,57 @@ properties: 1 - A, 10% to 90% of 2^24 (1677722 .. 15099494) 2 - B, 2.5% to 22.5% of 2^24 (419430 .. 3774874) 3 - C, 20% to 80% of 2^24 (3355443 .. 13421773) + enum: [1, 2, 3] $ref: /schemas/types.yaml#/definitions/uint32 + honeywell,pressure-triplet: + description: | + Case-sensitive five character string that defines pressure range, unit + and type as part of the device nomenclature. In the unlikely case of a + custom chip, unset and provide pmin-pascal and pmax-pascal instead. + enum: [0001BA, 01.6BA, 02.5BA, 0060MG, 0100MG, 0160MG, 0250MG, 0400MG, + 0600MG, 0001BG, 01.6BG, 02.5BG, 0100KA, 0160KA, 0250KA, 0006KG, + 0010KG, 0016KG, 0025KG, 0040KG, 0060KG, 0100KG, 0160KG, 0250KG, + 0015PA, 0025PA, 0030PA, 0001PG, 0005PG, 0015PG, 0030PG, 0300YG] + $ref: /schemas/types.yaml#/definitions/string + + honeywell,pmin-pascal: + description: + Minimum pressure value the sensor can measure in pascal. + + honeywell,pmax-pascal: + description: + Maximum pressure value the sensor can measure in pascal. + + spi-max-frequency: + maximum: 800000 + vdd-supply: description: provide VDD power to the sensor. required: - compatible - reg - - honeywell,pmin-pascal - - honeywell,pmax-pascal - honeywell,transfer-function - vdd-supply +oneOf: + - required: + - honeywell,pressure-triplet + - required: + - honeywell,pmin-pascal + - honeywell,pmax-pascal + +allOf: + - $ref: /schemas/spi/spi-peripheral-props.yaml + - if: + required: + - honeywell,pressure-triplet + then: + properties: + honeywell,pmin-pascal: false + honeywell,pmax-pascal: false + additionalProperties: false examples: @@ -93,10 +130,29 @@ examples: reg = <0x18>; reset-gpios = <&gpio3 19 GPIO_ACTIVE_HIGH>; interrupt-parent = <&gpio3>; - interrupts = <21 IRQ_TYPE_EDGE_FALLING>; - honeywell,pmin-pascal = <0>; - honeywell,pmax-pascal = <172369>; + interrupts = <21 IRQ_TYPE_EDGE_RISING>; + + honeywell,pressure-triplet = "0025PA"; + honeywell,transfer-function = <1>; + vdd-supply = <&vcc_3v3>; + }; + }; + - | + spi { + #address-cells = <1>; + #size-cells = <0>; + + pressure@0 { + compatible = "honeywell,mprls0025pa"; + reg = <0>; + spi-max-frequency = <800000>; + reset-gpios = <&gpio1 28 GPIO_ACTIVE_HIGH>; + interrupt-parent = <&gpio0>; + interrupts = <30 IRQ_TYPE_EDGE_RISING>; + + honeywell,pressure-triplet = "0015PA"; honeywell,transfer-function = <1>; vdd-supply = <&vcc_3v3>; }; }; +... diff --git a/Documentation/devicetree/bindings/net/marvell,prestera.yaml b/Documentation/devicetree/bindings/net/marvell,prestera.yaml index 5ea8b73663a5..16ff892f7bbd 100644 --- a/Documentation/devicetree/bindings/net/marvell,prestera.yaml +++ b/Documentation/devicetree/bindings/net/marvell,prestera.yaml @@ -78,8 +78,8 @@ examples: pcie@0 { #address-cells = <3>; #size-cells = <2>; - ranges = <0x0 0x0 0x0 0x0 0x0 0x0>; - reg = <0x0 0x0 0x0 0x0 0x0 0x0>; + ranges = <0x02000000 0x0 0x100000 0x10000000 0x0 0x0>; + reg = <0x0 0x1000>; device_type = "pci"; switch@0,0 { diff --git a/Documentation/devicetree/bindings/reset/xlnx,zynqmp-reset.yaml b/Documentation/devicetree/bindings/reset/xlnx,zynqmp-reset.yaml index 49db66801429..1f1b42dde94d 100644 --- a/Documentation/devicetree/bindings/reset/xlnx,zynqmp-reset.yaml +++ b/Documentation/devicetree/bindings/reset/xlnx,zynqmp-reset.yaml @@ -7,7 +7,8 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# title: Zynq UltraScale+ MPSoC and Versal reset maintainers: - - Piyush Mehta <piyush.mehta@amd.com> + - Mubin Sayyed <mubin.sayyed@amd.com> + - Radhey Shyam Pandey <radhey.shyam.pandey@amd.com> description: | The Zynq UltraScale+ MPSoC and Versal has several different resets. diff --git a/Documentation/devicetree/bindings/sound/google,sc7280-herobrine.yaml b/Documentation/devicetree/bindings/sound/google,sc7280-herobrine.yaml index ec4b6e547ca6..cdcd7c6f21eb 100644 --- a/Documentation/devicetree/bindings/sound/google,sc7280-herobrine.yaml +++ b/Documentation/devicetree/bindings/sound/google,sc7280-herobrine.yaml @@ -7,7 +7,6 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# title: Google SC7280-Herobrine ASoC sound card driver maintainers: - - Srinivasa Rao Mandadapu <srivasam@codeaurora.org> - Judy Hsiao <judyhsiao@chromium.org> description: diff --git a/Documentation/devicetree/bindings/tpm/tpm-common.yaml b/Documentation/devicetree/bindings/tpm/tpm-common.yaml index 90390624a8be..3c1241b2a43f 100644 --- a/Documentation/devicetree/bindings/tpm/tpm-common.yaml +++ b/Documentation/devicetree/bindings/tpm/tpm-common.yaml @@ -42,7 +42,7 @@ properties: resets: description: Reset controller to reset the TPM - $ref: /schemas/types.yaml#/definitions/phandle + maxItems: 1 reset-gpios: description: Output GPIO pin to reset the TPM diff --git a/Documentation/devicetree/bindings/ufs/samsung,exynos-ufs.yaml b/Documentation/devicetree/bindings/ufs/samsung,exynos-ufs.yaml index 88cc1e3a0c88..b2b509b3944d 100644 --- a/Documentation/devicetree/bindings/ufs/samsung,exynos-ufs.yaml +++ b/Documentation/devicetree/bindings/ufs/samsung,exynos-ufs.yaml @@ -55,9 +55,12 @@ properties: samsung,sysreg: $ref: /schemas/types.yaml#/definitions/phandle-array - description: Should be phandle/offset pair. The phandle to the syscon node - which indicates the FSYSx sysreg interface and the offset of - the control register for UFS io coherency setting. + items: + - items: + - description: phandle to FSYSx sysreg node + - description: offset of the control register for UFS io coherency setting + description: + Phandle and offset to the FSYSx sysreg for UFS io coherency setting. dma-coherent: true diff --git a/Documentation/devicetree/bindings/usb/dwc3-xilinx.yaml b/Documentation/devicetree/bindings/usb/dwc3-xilinx.yaml index bb373eb025a5..00f87a558c7d 100644 --- a/Documentation/devicetree/bindings/usb/dwc3-xilinx.yaml +++ b/Documentation/devicetree/bindings/usb/dwc3-xilinx.yaml @@ -7,7 +7,8 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# title: Xilinx SuperSpeed DWC3 USB SoC controller maintainers: - - Piyush Mehta <piyush.mehta@amd.com> + - Mubin Sayyed <mubin.sayyed@amd.com> + - Radhey Shyam Pandey <radhey.shyam.pandey@amd.com> properties: compatible: diff --git a/Documentation/devicetree/bindings/usb/microchip,usb5744.yaml b/Documentation/devicetree/bindings/usb/microchip,usb5744.yaml index 6d4cfd943f58..445183d9d6db 100644 --- a/Documentation/devicetree/bindings/usb/microchip,usb5744.yaml +++ b/Documentation/devicetree/bindings/usb/microchip,usb5744.yaml @@ -16,8 +16,9 @@ description: USB 2.0 traffic. maintainers: - - Piyush Mehta <piyush.mehta@amd.com> - Michal Simek <michal.simek@amd.com> + - Mubin Sayyed <mubin.sayyed@amd.com> + - Radhey Shyam Pandey <radhey.shyam.pandey@amd.com> properties: compatible: diff --git a/Documentation/devicetree/bindings/usb/xlnx,usb2.yaml b/Documentation/devicetree/bindings/usb/xlnx,usb2.yaml index 868dffe314bc..a7f75fe36665 100644 --- a/Documentation/devicetree/bindings/usb/xlnx,usb2.yaml +++ b/Documentation/devicetree/bindings/usb/xlnx,usb2.yaml @@ -7,7 +7,8 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# title: Xilinx udc controller maintainers: - - Piyush Mehta <piyush.mehta@amd.com> + - Mubin Sayyed <mubin.sayyed@amd.com> + - Radhey Shyam Pandey <radhey.shyam.pandey@amd.com> properties: compatible: diff --git a/Documentation/kbuild/Kconfig.recursion-issue-01 b/Documentation/kbuild/Kconfig.recursion-issue-01 index e8877db0461f..ac49836d8ecf 100644 --- a/Documentation/kbuild/Kconfig.recursion-issue-01 +++ b/Documentation/kbuild/Kconfig.recursion-issue-01 @@ -16,13 +16,13 @@ # that are possible for CORE. So for example if CORE_BELL_A_ADVANCED is 'y', # CORE must be 'y' too. # -# * What influences CORE_BELL_A_ADVANCED ? +# * What influences CORE_BELL_A_ADVANCED? # # As the name implies CORE_BELL_A_ADVANCED is an advanced feature of # CORE_BELL_A so naturally it depends on CORE_BELL_A. So if CORE_BELL_A is 'y' # we know CORE_BELL_A_ADVANCED can be 'y' too. # -# * What influences CORE_BELL_A ? +# * What influences CORE_BELL_A? # # CORE_BELL_A depends on CORE, so CORE influences CORE_BELL_A. # @@ -34,7 +34,7 @@ # the "recursive dependency detected" error. # # Reading the Documentation/kbuild/Kconfig.recursion-issue-01 file it may be -# obvious that an easy to solution to this problem should just be the removal +# obvious that an easy solution to this problem should just be the removal # of the "select CORE" from CORE_BELL_A_ADVANCED as that is implicit already # since CORE_BELL_A depends on CORE. Recursive dependency issues are not always # so trivial to resolve, we provide another example below of practical diff --git a/Documentation/netlink/specs/dpll.yaml b/Documentation/netlink/specs/dpll.yaml index b14aed18065f..3dcc9ece272a 100644 --- a/Documentation/netlink/specs/dpll.yaml +++ b/Documentation/netlink/specs/dpll.yaml @@ -384,8 +384,6 @@ operations: - type dump: - pre: dpll-lock-dumpit - post: dpll-unlock-dumpit reply: *dev-attrs - @@ -473,8 +471,6 @@ operations: - fractional-frequency-offset dump: - pre: dpll-lock-dumpit - post: dpll-unlock-dumpit request: attributes: - id diff --git a/Documentation/networking/devlink/devlink-port.rst b/Documentation/networking/devlink/devlink-port.rst index e33ad2401ad7..562f46b41274 100644 --- a/Documentation/networking/devlink/devlink-port.rst +++ b/Documentation/networking/devlink/devlink-port.rst @@ -126,7 +126,7 @@ Users may also set the RoCE capability of the function using `devlink port function set roce` command. Users may also set the function as migratable using -'devlink port function set migratable' command. +`devlink port function set migratable` command. Users may also set the IPsec crypto capability of the function using `devlink port function set ipsec_crypto` command. diff --git a/Documentation/networking/net_cachelines/net_device.rst b/Documentation/networking/net_cachelines/net_device.rst index e75a53593bb9..dceb49d56a91 100644 --- a/Documentation/networking/net_cachelines/net_device.rst +++ b/Documentation/networking/net_cachelines/net_device.rst @@ -136,8 +136,8 @@ struct_netpoll_info* npinfo - possible_net_t nd_net - read_mostly (dev_net)napi_busy_loop,tcp_v(4/6)_rcv,ip(v6)_rcv,ip(6)_input,ip(6)_input_finish void* ml_priv enum_netdev_ml_priv_type ml_priv_type -struct_pcpu_lstats__percpu* lstats -struct_pcpu_sw_netstats__percpu* tstats +struct_pcpu_lstats__percpu* lstats read_mostly dev_lstats_add() +struct_pcpu_sw_netstats__percpu* tstats read_mostly dev_sw_netstats_tx_add() struct_pcpu_dstats__percpu* dstats struct_garp_port* garp_port struct_mrp_port* mrp_port diff --git a/Documentation/networking/net_cachelines/tcp_sock.rst b/Documentation/networking/net_cachelines/tcp_sock.rst index 97d7a5c8e01c..1c154cbd1848 100644 --- a/Documentation/networking/net_cachelines/tcp_sock.rst +++ b/Documentation/networking/net_cachelines/tcp_sock.rst @@ -38,13 +38,13 @@ u32 max_window read_mostly - u32 mss_cache read_mostly read_mostly tcp_rate_check_app_limited,tcp_current_mss,tcp_sync_mss,tcp_sndbuf_expand,tcp_tso_should_defer(tx);tcp_update_pacing_rate,tcp_clean_rtx_queue(rx) u32 window_clamp read_mostly read_write tcp_rcv_space_adjust,__tcp_select_window u32 rcv_ssthresh read_mostly - __tcp_select_window -u82 scaling_ratio +u8 scaling_ratio read_mostly read_mostly tcp_win_from_space struct tcp_rack u16 advmss - read_mostly tcp_rcv_space_adjust u8 compressed_ack u8:2 dup_ack_counter u8:1 tlp_retrans -u8:1 tcp_usec_ts +u8:1 tcp_usec_ts read_mostly read_mostly u32 chrono_start read_write - tcp_chrono_start/stop(tcp_write_xmit,tcp_cwnd_validate,tcp_send_syn_data) u32[3] chrono_stat read_write - tcp_chrono_start/stop(tcp_write_xmit,tcp_cwnd_validate,tcp_send_syn_data) u8:2 chrono_type read_write - tcp_chrono_start/stop(tcp_write_xmit,tcp_cwnd_validate,tcp_send_syn_data) diff --git a/Documentation/process/cve.rst b/Documentation/process/cve.rst new file mode 100644 index 000000000000..5e2753eff729 --- /dev/null +++ b/Documentation/process/cve.rst @@ -0,0 +1,121 @@ +==== +CVEs +==== + +Common Vulnerabilities and Exposure (CVE®) numbers were developed as an +unambiguous way to identify, define, and catalog publicly disclosed +security vulnerabilities. Over time, their usefulness has declined with +regards to the kernel project, and CVE numbers were very often assigned +in inappropriate ways and for inappropriate reasons. Because of this, +the kernel development community has tended to avoid them. However, the +combination of continuing pressure to assign CVEs and other forms of +security identifiers, and ongoing abuses by individuals and companies +outside of the kernel community has made it clear that the kernel +community should have control over those assignments. + +The Linux kernel developer team does have the ability to assign CVEs for +potential Linux kernel security issues. This assignment is independent +of the :doc:`normal Linux kernel security bug reporting +process<../process/security-bugs>`. + +A list of all assigned CVEs for the Linux kernel can be found in the +archives of the linux-cve mailing list, as seen on +https://lore.kernel.org/linux-cve-announce/. To get notice of the +assigned CVEs, please `subscribe +<https://subspace.kernel.org/subscribing.html>`_ to that mailing list. + +Process +======= + +As part of the normal stable release process, kernel changes that are +potentially security issues are identified by the developers responsible +for CVE number assignments and have CVE numbers automatically assigned +to them. These assignments are published on the linux-cve-announce +mailing list as announcements on a frequent basis. + +Note, due to the layer at which the Linux kernel is in a system, almost +any bug might be exploitable to compromise the security of the kernel, +but the possibility of exploitation is often not evident when the bug is +fixed. Because of this, the CVE assignment team is overly cautious and +assign CVE numbers to any bugfix that they identify. This +explains the seemingly large number of CVEs that are issued by the Linux +kernel team. + +If the CVE assignment team misses a specific fix that any user feels +should have a CVE assigned to it, please email them at <cve@kernel.org> +and the team there will work with you on it. Note that no potential +security issues should be sent to this alias, it is ONLY for assignment +of CVEs for fixes that are already in released kernel trees. If you +feel you have found an unfixed security issue, please follow the +:doc:`normal Linux kernel security bug reporting +process<../process/security-bugs>`. + +No CVEs will be automatically assigned for unfixed security issues in +the Linux kernel; assignment will only automatically happen after a fix +is available and applied to a stable kernel tree, and it will be tracked +that way by the git commit id of the original fix. If anyone wishes to +have a CVE assigned before an issue is resolved with a commit, please +contact the kernel CVE assignment team at <cve@kernel.org> to get an +identifier assigned from their batch of reserved identifiers. + +No CVEs will be assigned for any issue found in a version of the kernel +that is not currently being actively supported by the Stable/LTS kernel +team. A list of the currently supported kernel branches can be found at +https://kernel.org/releases.html + +Disputes of assigned CVEs +========================= + +The authority to dispute or modify an assigned CVE for a specific kernel +change lies solely with the maintainers of the relevant subsystem +affected. This principle ensures a high degree of accuracy and +accountability in vulnerability reporting. Only those individuals with +deep expertise and intimate knowledge of the subsystem can effectively +assess the validity and scope of a reported vulnerability and determine +its appropriate CVE designation. Any attempt to modify or dispute a CVE +outside of this designated authority could lead to confusion, inaccurate +reporting, and ultimately, compromised systems. + +Invalid CVEs +============ + +If a security issue is found in a Linux kernel that is only supported by +a Linux distribution due to the changes that have been made by that +distribution, or due to the distribution supporting a kernel version +that is no longer one of the kernel.org supported releases, then a CVE +can not be assigned by the Linux kernel CVE team, and must be asked for +from that Linux distribution itself. + +Any CVE that is assigned against the Linux kernel for an actively +supported kernel version, by any group other than the kernel assignment +CVE team should not be treated as a valid CVE. Please notify the +kernel CVE assignment team at <cve@kernel.org> so that they can work to +invalidate such entries through the CNA remediation process. + +Applicability of specific CVEs +============================== + +As the Linux kernel can be used in many different ways, with many +different ways of accessing it by external users, or no access at all, +the applicability of any specific CVE is up to the user of Linux to +determine, it is not up to the CVE assignment team. Please do not +contact us to attempt to determine the applicability of any specific +CVE. + +Also, as the source tree is so large, and any one system only uses a +small subset of the source tree, any users of Linux should be aware that +large numbers of assigned CVEs are not relevant for their systems. + +In short, we do not know your use case, and we do not know what portions +of the kernel that you use, so there is no way for us to determine if a +specific CVE is relevant for your system. + +As always, it is best to take all released kernel changes, as they are +tested together in a unified whole by many community members, and not as +individual cherry-picked changes. Also note that for many bugs, the +solution to the overall problem is not found in a single change, but by +the sum of many fixes on top of each other. Ideally CVEs will be +assigned to all fixes for all issues, but sometimes we will fail to +notice fixes, therefore assume that some changes without a CVE assigned +might be relevant to take. + diff --git a/Documentation/process/index.rst b/Documentation/process/index.rst index 6cb732dfcc72..de9cbb7bd7eb 100644 --- a/Documentation/process/index.rst +++ b/Documentation/process/index.rst @@ -81,6 +81,7 @@ of special classes of bugs: regressions and security problems. handling-regressions security-bugs + cve embargoed-hardware-issues Maintainer information diff --git a/Documentation/process/security-bugs.rst b/Documentation/process/security-bugs.rst index 692a3ba56cca..56c560a00b37 100644 --- a/Documentation/process/security-bugs.rst +++ b/Documentation/process/security-bugs.rst @@ -99,9 +99,8 @@ CVE assignment The security team does not assign CVEs, nor do we require them for reports or fixes, as this can needlessly complicate the process and may delay the bug handling. If a reporter wishes to have a CVE identifier -assigned, they should find one by themselves, for example by contacting -MITRE directly. However under no circumstances will a patch inclusion -be delayed to wait for a CVE identifier to arrive. +assigned for a confirmed issue, they can contact the :doc:`kernel CVE +assignment team<../process/cve>` to obtain one. Non-disclosure agreements ------------------------- diff --git a/Documentation/sphinx/kernel_feat.py b/Documentation/sphinx/kernel_feat.py index b9df61eb4501..03ace5f01b5c 100644 --- a/Documentation/sphinx/kernel_feat.py +++ b/Documentation/sphinx/kernel_feat.py @@ -109,7 +109,7 @@ class KernelFeat(Directive): else: out_lines += line + "\n" - nodeList = self.nestedParse(out_lines, fname) + nodeList = self.nestedParse(out_lines, self.arguments[0]) return nodeList def nestedParse(self, lines, fname): diff --git a/MAINTAINERS b/MAINTAINERS index 73d898383e51..d59d52ec8b06 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1144,7 +1144,7 @@ L: linux-iio@vger.kernel.org S: Supported W: http://ez.analog.com/community/linux-device-drivers F: Documentation/devicetree/bindings/iio/adc/adi,ad7091r* -F: drivers/iio/adc/drivers/iio/adc/ad7091r* +F: drivers/iio/adc/ad7091r* ANALOG DEVICES INC AD7192 DRIVER M: Alexandru Tachici <alexandru.tachici@analog.com> @@ -1267,6 +1267,14 @@ W: https://ez.analog.com/linux-software-drivers F: Documentation/devicetree/bindings/hwmon/adi,adm1177.yaml F: drivers/hwmon/adm1177.c +ANALOG DEVICES INC ADMFM2000 DRIVER +M: Kim Seer Paller <kimseer.paller@analog.com> +L: linux-iio@vger.kernel.org +S: Supported +W: https://ez.analog.com/linux-software-drivers +F: Documentation/devicetree/bindings/iio/frequency/adi,admfm2000.yaml +F: drivers/iio/frequency/admfm2000.c + ANALOG DEVICES INC ADMV1013 DRIVER M: Antoniu Miclaus <antoniu.miclaus@analog.com> L: linux-iio@vger.kernel.org @@ -5610,6 +5618,11 @@ S: Maintained F: Documentation/devicetree/bindings/net/can/ctu,ctucanfd.yaml F: drivers/net/can/ctucanfd/ +CVE ASSIGNMENT CONTACT +M: CVE Assignment Team <cve@kernel.org> +S: Maintained +F: Documentation/process/cve.rst + CW1200 WLAN driver S: Orphan F: drivers/net/wireless/st/cw1200/ @@ -9791,10 +9804,11 @@ F: drivers/iio/pressure/hsc030pa* HONEYWELL MPRLS0025PA PRESSURE SENSOR SERIES IIO DRIVER M: Andreas Klinger <ak@it-klinger.de> +M: Petre Rodan <petre.rodan@subdimension.ro> L: linux-iio@vger.kernel.org S: Maintained F: Documentation/devicetree/bindings/iio/pressure/honeywell,mprls0025pa.yaml -F: drivers/iio/pressure/mprls0025pa.c +F: drivers/iio/pressure/mprls0025pa* HP BIOSCFG DRIVER M: Jorge Lopez <jorge.lopez2@hp.com> @@ -10383,6 +10397,14 @@ L: linux-media@vger.kernel.org S: Maintained F: drivers/media/rc/iguanair.c +IIO BACKEND FRAMEWORK +M: Nuno Sa <nuno.sa@analog.com> +R: Olivier Moysan <olivier.moysan@foss.st.com> +L: linux-iio@vger.kernel.org +S: Maintained +F: drivers/iio/industrialio-backend.c +F: include/linux/iio/backend.h + IIO DIGITAL POTENTIOMETER DAC M: Peter Rosin <peda@axentia.se> L: linux-iio@vger.kernel.org @@ -10405,6 +10427,7 @@ L: linux-iio@vger.kernel.org S: Maintained F: drivers/iio/industrialio-gts-helper.c F: include/linux/iio/iio-gts-helper.h +F: drivers/iio/test/iio-test-gts.c IIO MULTIPLEXER M: Peter Rosin <peda@axentia.se> @@ -15324,7 +15347,7 @@ K: \bmdo_ NETWORKING [MPTCP] M: Matthieu Baerts <matttbe@kernel.org> M: Mat Martineau <martineau@kernel.org> -R: Geliang Tang <geliang.tang@linux.dev> +R: Geliang Tang <geliang@kernel.org> L: netdev@vger.kernel.org L: mptcp@lists.linux.dev S: Maintained @@ -16837,6 +16860,7 @@ F: drivers/pci/controller/dwc/*designware* PCI DRIVER FOR TI DRA7XX/J721E M: Vignesh Raghavendra <vigneshr@ti.com> +R: Siddharth Vadapalli <s-vadapalli@ti.com> L: linux-omap@vger.kernel.org L: linux-pci@vger.kernel.org L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) @@ -22009,6 +22033,14 @@ F: Documentation/devicetree/bindings/media/i2c/ti,ds90* F: drivers/media/i2c/ds90* F: include/media/i2c/ds90* +TI HDC302X HUMIDITY DRIVER +M: Javier Carrasco <javier.carrasco.cruz@gmail.com> +M: Li peiyu <579lpy@gmail.com> +L: linux-iio@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/iio/humidity/ti,hdc3020.yaml +F: drivers/iio/humidity/hdc3020.c + TI ICSSG ETHERNET DRIVER (ICSSG) R: MD Danish Anwar <danishanwar@ti.com> R: Roger Quadros <rogerq@kernel.org> @@ -2,7 +2,7 @@ VERSION = 6 PATCHLEVEL = 8 SUBLEVEL = 0 -EXTRAVERSION = -rc4 +EXTRAVERSION = -rc5 NAME = Hurr durr I'ma ninja sloth # *DOCUMENTATION* @@ -294,15 +294,15 @@ may-sync-config := 1 single-build := ifneq ($(filter $(no-dot-config-targets), $(MAKECMDGOALS)),) - ifeq ($(filter-out $(no-dot-config-targets), $(MAKECMDGOALS)),) + ifeq ($(filter-out $(no-dot-config-targets), $(MAKECMDGOALS)),) need-config := - endif + endif endif ifneq ($(filter $(no-sync-config-targets), $(MAKECMDGOALS)),) - ifeq ($(filter-out $(no-sync-config-targets), $(MAKECMDGOALS)),) + ifeq ($(filter-out $(no-sync-config-targets), $(MAKECMDGOALS)),) may-sync-config := - endif + endif endif need-compiler := $(may-sync-config) @@ -323,9 +323,9 @@ endif # We cannot build single targets and the others at the same time ifneq ($(filter $(single-targets), $(MAKECMDGOALS)),) single-build := 1 - ifneq ($(filter-out $(single-targets), $(MAKECMDGOALS)),) + ifneq ($(filter-out $(single-targets), $(MAKECMDGOALS)),) mixed-build := 1 - endif + endif endif # For "make -j clean all", "make -j mrproper defconfig all", etc. diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h index 21c824edf8ce..bd8d4ca81a48 100644 --- a/arch/arm64/include/asm/cpufeature.h +++ b/arch/arm64/include/asm/cpufeature.h @@ -83,7 +83,7 @@ struct arm64_ftr_bits { * to full-0 denotes that this field has no override * * A @mask field set to full-0 with the corresponding @val field set - * to full-1 denotes thath this field has an invalid override. + * to full-1 denotes that this field has an invalid override. */ struct arm64_ftr_override { u64 val; diff --git a/arch/arm64/include/asm/cputype.h b/arch/arm64/include/asm/cputype.h index 7c7493cb571f..52f076afeb96 100644 --- a/arch/arm64/include/asm/cputype.h +++ b/arch/arm64/include/asm/cputype.h @@ -61,6 +61,7 @@ #define ARM_CPU_IMP_HISI 0x48 #define ARM_CPU_IMP_APPLE 0x61 #define ARM_CPU_IMP_AMPERE 0xC0 +#define ARM_CPU_IMP_MICROSOFT 0x6D #define ARM_CPU_PART_AEM_V8 0xD0F #define ARM_CPU_PART_FOUNDATION 0xD00 @@ -135,6 +136,8 @@ #define AMPERE_CPU_PART_AMPERE1 0xAC3 +#define MICROSOFT_CPU_PART_AZURE_COBALT_100 0xD49 /* Based on r0p0 of ARM Neoverse N2 */ + #define MIDR_CORTEX_A53 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A53) #define MIDR_CORTEX_A57 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A57) #define MIDR_CORTEX_A72 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A72) @@ -193,6 +196,7 @@ #define MIDR_APPLE_M2_BLIZZARD_MAX MIDR_CPU_MODEL(ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M2_BLIZZARD_MAX) #define MIDR_APPLE_M2_AVALANCHE_MAX MIDR_CPU_MODEL(ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M2_AVALANCHE_MAX) #define MIDR_AMPERE1 MIDR_CPU_MODEL(ARM_CPU_IMP_AMPERE, AMPERE_CPU_PART_AMPERE1) +#define MIDR_MICROSOFT_AZURE_COBALT_100 MIDR_CPU_MODEL(ARM_CPU_IMP_MICROSOFT, MICROSOFT_CPU_PART_AZURE_COBALT_100) /* Fujitsu Erratum 010001 affects A64FX 1.0 and 1.1, (v0r0 and v1r0) */ #define MIDR_FUJITSU_ERRATUM_010001 MIDR_FUJITSU_A64FX diff --git a/arch/arm64/include/asm/fpsimd.h b/arch/arm64/include/asm/fpsimd.h index 50e5f25d3024..481d94416d69 100644 --- a/arch/arm64/include/asm/fpsimd.h +++ b/arch/arm64/include/asm/fpsimd.h @@ -62,13 +62,13 @@ static inline void cpacr_restore(unsigned long cpacr) * When we defined the maximum SVE vector length we defined the ABI so * that the maximum vector length included all the reserved for future * expansion bits in ZCR rather than those just currently defined by - * the architecture. While SME follows a similar pattern the fact that - * it includes a square matrix means that any allocations that attempt - * to cover the maximum potential vector length (such as happen with - * the regset used for ptrace) end up being extremely large. Define - * the much lower actual limit for use in such situations. + * the architecture. Using this length to allocate worst size buffers + * results in excessively large allocations, and this effect is even + * more pronounced for SME due to ZA. Define more suitable VLs for + * these situations. */ -#define SME_VQ_MAX 16 +#define ARCH_SVE_VQ_MAX ((ZCR_ELx_LEN_MASK >> ZCR_ELx_LEN_SHIFT) + 1) +#define SME_VQ_MAX ((SMCR_ELx_LEN_MASK >> SMCR_ELx_LEN_SHIFT) + 1) struct task_struct; diff --git a/arch/arm64/include/asm/jump_label.h b/arch/arm64/include/asm/jump_label.h index 6aafbb789991..b360c4c2b5e7 100644 --- a/arch/arm64/include/asm/jump_label.h +++ b/arch/arm64/include/asm/jump_label.h @@ -15,6 +15,10 @@ #define JUMP_LABEL_NOP_SIZE AARCH64_INSN_SIZE +/* + * Prefer the constraint "S" to support PIC with GCC. Clang before 19 does not + * support "S" on a symbol with a constant offset, so we use "i" as a fallback. + */ static __always_inline bool arch_static_branch(struct static_key * const key, const bool branch) { @@ -23,9 +27,9 @@ static __always_inline bool arch_static_branch(struct static_key * const key, " .pushsection __jump_table, \"aw\" \n\t" " .align 3 \n\t" " .long 1b - ., %l[l_yes] - . \n\t" - " .quad %c0 - . \n\t" + " .quad (%[key] - .) + %[bit0] \n\t" " .popsection \n\t" - : : "i"(&((char *)key)[branch]) : : l_yes); + : : [key]"Si"(key), [bit0]"i"(branch) : : l_yes); return false; l_yes: @@ -40,9 +44,9 @@ static __always_inline bool arch_static_branch_jump(struct static_key * const ke " .pushsection __jump_table, \"aw\" \n\t" " .align 3 \n\t" " .long 1b - ., %l[l_yes] - . \n\t" - " .quad %c0 - . \n\t" + " .quad (%[key] - .) + %[bit0] \n\t" " .popsection \n\t" - : : "i"(&((char *)key)[branch]) : : l_yes); + : : [key]"Si"(key), [bit0]"i"(branch) : : l_yes); return false; l_yes: diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c index 967c7c7a4e7d..76b8dd37092a 100644 --- a/arch/arm64/kernel/cpu_errata.c +++ b/arch/arm64/kernel/cpu_errata.c @@ -374,6 +374,7 @@ static const struct midr_range erratum_1463225[] = { static const struct midr_range trbe_overwrite_fill_mode_cpus[] = { #ifdef CONFIG_ARM64_ERRATUM_2139208 MIDR_ALL_VERSIONS(MIDR_NEOVERSE_N2), + MIDR_ALL_VERSIONS(MIDR_MICROSOFT_AZURE_COBALT_100), #endif #ifdef CONFIG_ARM64_ERRATUM_2119858 MIDR_ALL_VERSIONS(MIDR_CORTEX_A710), @@ -387,6 +388,7 @@ static const struct midr_range trbe_overwrite_fill_mode_cpus[] = { static const struct midr_range tsb_flush_fail_cpus[] = { #ifdef CONFIG_ARM64_ERRATUM_2067961 MIDR_ALL_VERSIONS(MIDR_NEOVERSE_N2), + MIDR_ALL_VERSIONS(MIDR_MICROSOFT_AZURE_COBALT_100), #endif #ifdef CONFIG_ARM64_ERRATUM_2054223 MIDR_ALL_VERSIONS(MIDR_CORTEX_A710), @@ -399,6 +401,7 @@ static const struct midr_range tsb_flush_fail_cpus[] = { static struct midr_range trbe_write_out_of_range_cpus[] = { #ifdef CONFIG_ARM64_ERRATUM_2253138 MIDR_ALL_VERSIONS(MIDR_NEOVERSE_N2), + MIDR_ALL_VERSIONS(MIDR_MICROSOFT_AZURE_COBALT_100), #endif #ifdef CONFIG_ARM64_ERRATUM_2224489 MIDR_ALL_VERSIONS(MIDR_CORTEX_A710), diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c index a5dc6f764195..25ceaee6b025 100644 --- a/arch/arm64/kernel/fpsimd.c +++ b/arch/arm64/kernel/fpsimd.c @@ -1635,7 +1635,7 @@ void fpsimd_preserve_current_state(void) void fpsimd_signal_preserve_current_state(void) { fpsimd_preserve_current_state(); - if (test_thread_flag(TIF_SVE)) + if (current->thread.fp_type == FP_STATE_SVE) sve_to_fpsimd(current); } diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c index dc6cf0e37194..e3bef38fc2e2 100644 --- a/arch/arm64/kernel/ptrace.c +++ b/arch/arm64/kernel/ptrace.c @@ -1500,7 +1500,8 @@ static const struct user_regset aarch64_regsets[] = { #ifdef CONFIG_ARM64_SVE [REGSET_SVE] = { /* Scalable Vector Extension */ .core_note_type = NT_ARM_SVE, - .n = DIV_ROUND_UP(SVE_PT_SIZE(SVE_VQ_MAX, SVE_PT_REGS_SVE), + .n = DIV_ROUND_UP(SVE_PT_SIZE(ARCH_SVE_VQ_MAX, + SVE_PT_REGS_SVE), SVE_VQ_BYTES), .size = SVE_VQ_BYTES, .align = SVE_VQ_BYTES, diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c index 0e8beb3349ea..425b1bc17a3f 100644 --- a/arch/arm64/kernel/signal.c +++ b/arch/arm64/kernel/signal.c @@ -242,7 +242,7 @@ static int preserve_sve_context(struct sve_context __user *ctx) vl = task_get_sme_vl(current); vq = sve_vq_from_vl(vl); flags |= SVE_SIG_FLAG_SM; - } else if (test_thread_flag(TIF_SVE)) { + } else if (current->thread.fp_type == FP_STATE_SVE) { vq = sve_vq_from_vl(vl); } @@ -878,7 +878,7 @@ static int setup_sigframe_layout(struct rt_sigframe_user_layout *user, if (system_supports_sve() || system_supports_sme()) { unsigned int vq = 0; - if (add_all || test_thread_flag(TIF_SVE) || + if (add_all || current->thread.fp_type == FP_STATE_SVE || thread_sm_enabled(¤t->thread)) { int vl = max(sve_max_vl(), sme_max_vl()); diff --git a/arch/arm64/kvm/Kconfig b/arch/arm64/kvm/Kconfig index 6c3c8ca73e7f..27ca89b628a0 100644 --- a/arch/arm64/kvm/Kconfig +++ b/arch/arm64/kvm/Kconfig @@ -3,7 +3,6 @@ # KVM configuration # -source "virt/lib/Kconfig" source "virt/kvm/Kconfig" menuconfig VIRTUALIZATION diff --git a/arch/arm64/kvm/hyp/pgtable.c b/arch/arm64/kvm/hyp/pgtable.c index c651df904fe3..ab9d05fcf98b 100644 --- a/arch/arm64/kvm/hyp/pgtable.c +++ b/arch/arm64/kvm/hyp/pgtable.c @@ -1419,7 +1419,6 @@ kvm_pte_t *kvm_pgtable_stage2_create_unlinked(struct kvm_pgtable *pgt, level + 1); if (ret) { kvm_pgtable_stage2_free_unlinked(mm_ops, pgtable, level); - mm_ops->put_page(pgtable); return ERR_PTR(ret); } @@ -1502,7 +1501,6 @@ static int stage2_split_walker(const struct kvm_pgtable_visit_ctx *ctx, if (!stage2_try_break_pte(ctx, mmu)) { kvm_pgtable_stage2_free_unlinked(mm_ops, childp, level); - mm_ops->put_page(childp); return -EAGAIN; } diff --git a/arch/arm64/kvm/pkvm.c b/arch/arm64/kvm/pkvm.c index 8350fb8fee0b..b7be96a53597 100644 --- a/arch/arm64/kvm/pkvm.c +++ b/arch/arm64/kvm/pkvm.c @@ -101,6 +101,17 @@ void __init kvm_hyp_reserve(void) hyp_mem_base); } +static void __pkvm_destroy_hyp_vm(struct kvm *host_kvm) +{ + if (host_kvm->arch.pkvm.handle) { + WARN_ON(kvm_call_hyp_nvhe(__pkvm_teardown_vm, + host_kvm->arch.pkvm.handle)); + } + + host_kvm->arch.pkvm.handle = 0; + free_hyp_memcache(&host_kvm->arch.pkvm.teardown_mc); +} + /* * Allocates and donates memory for hypervisor VM structs at EL2. * @@ -181,7 +192,7 @@ static int __pkvm_create_hyp_vm(struct kvm *host_kvm) return 0; destroy_vm: - pkvm_destroy_hyp_vm(host_kvm); + __pkvm_destroy_hyp_vm(host_kvm); return ret; free_vm: free_pages_exact(hyp_vm, hyp_vm_sz); @@ -194,23 +205,19 @@ int pkvm_create_hyp_vm(struct kvm *host_kvm) { int ret = 0; - mutex_lock(&host_kvm->lock); + mutex_lock(&host_kvm->arch.config_lock); if (!host_kvm->arch.pkvm.handle) ret = __pkvm_create_hyp_vm(host_kvm); - mutex_unlock(&host_kvm->lock); + mutex_unlock(&host_kvm->arch.config_lock); return ret; } void pkvm_destroy_hyp_vm(struct kvm *host_kvm) { - if (host_kvm->arch.pkvm.handle) { - WARN_ON(kvm_call_hyp_nvhe(__pkvm_teardown_vm, - host_kvm->arch.pkvm.handle)); - } - - host_kvm->arch.pkvm.handle = 0; - free_hyp_memcache(&host_kvm->arch.pkvm.teardown_mc); + mutex_lock(&host_kvm->arch.config_lock); + __pkvm_destroy_hyp_vm(host_kvm); + mutex_unlock(&host_kvm->arch.config_lock); } int pkvm_init_host_vm(struct kvm *host_kvm) diff --git a/arch/m68k/Makefile b/arch/m68k/Makefile index 76ef1a67c361..0abcf994ce55 100644 --- a/arch/m68k/Makefile +++ b/arch/m68k/Makefile @@ -15,10 +15,10 @@ KBUILD_DEFCONFIG := multi_defconfig ifdef cross_compiling - ifeq ($(CROSS_COMPILE),) + ifeq ($(CROSS_COMPILE),) CROSS_COMPILE := $(call cc-cross-prefix, \ m68k-linux-gnu- m68k-linux- m68k-unknown-linux-gnu-) - endif + endif endif # diff --git a/arch/mips/include/asm/checksum.h b/arch/mips/include/asm/checksum.h index 4044eaf989ac..0921ddda11a4 100644 --- a/arch/mips/include/asm/checksum.h +++ b/arch/mips/include/asm/checksum.h @@ -241,7 +241,8 @@ static __inline__ __sum16 csum_ipv6_magic(const struct in6_addr *saddr, " .set pop" : "=&r" (sum), "=&r" (tmp) : "r" (saddr), "r" (daddr), - "0" (htonl(len)), "r" (htonl(proto)), "r" (sum)); + "0" (htonl(len)), "r" (htonl(proto)), "r" (sum) + : "memory"); return csum_fold(sum); } diff --git a/arch/mips/include/asm/ptrace.h b/arch/mips/include/asm/ptrace.h index daf3cf244ea9..d14d0e37ad02 100644 --- a/arch/mips/include/asm/ptrace.h +++ b/arch/mips/include/asm/ptrace.h @@ -60,6 +60,7 @@ static inline void instruction_pointer_set(struct pt_regs *regs, unsigned long val) { regs->cp0_epc = val; + regs->cp0_cause &= ~CAUSEF_BD; } /* Query offset/name of register from its name/offset */ @@ -154,6 +155,8 @@ static inline long regs_return_value(struct pt_regs *regs) } #define instruction_pointer(regs) ((regs)->cp0_epc) +extern unsigned long exception_ip(struct pt_regs *regs); +#define exception_ip(regs) exception_ip(regs) #define profile_pc(regs) instruction_pointer(regs) extern asmlinkage long syscall_trace_enter(struct pt_regs *regs, long syscall); diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c index d9df543f7e2c..59288c13b581 100644 --- a/arch/mips/kernel/ptrace.c +++ b/arch/mips/kernel/ptrace.c @@ -31,6 +31,7 @@ #include <linux/seccomp.h> #include <linux/ftrace.h> +#include <asm/branch.h> #include <asm/byteorder.h> #include <asm/cpu.h> #include <asm/cpu-info.h> @@ -48,6 +49,12 @@ #define CREATE_TRACE_POINTS #include <trace/events/syscalls.h> +unsigned long exception_ip(struct pt_regs *regs) +{ + return exception_epc(regs); +} +EXPORT_SYMBOL(exception_ip); + /* * Called by kernel/ptrace.c when detaching.. * diff --git a/arch/parisc/Makefile b/arch/parisc/Makefile index 7486b3b30594..316f84f1d15c 100644 --- a/arch/parisc/Makefile +++ b/arch/parisc/Makefile @@ -50,12 +50,12 @@ export CROSS32CC # Set default cross compiler for kernel build ifdef cross_compiling - ifeq ($(CROSS_COMPILE),) + ifeq ($(CROSS_COMPILE),) CC_SUFFIXES = linux linux-gnu unknown-linux-gnu suse-linux CROSS_COMPILE := $(call cc-cross-prefix, \ $(foreach a,$(CC_ARCHES), \ $(foreach s,$(CC_SUFFIXES),$(a)-$(s)-))) - endif + endif endif ifdef CONFIG_DYNAMIC_FTRACE diff --git a/arch/powerpc/include/asm/ftrace.h b/arch/powerpc/include/asm/ftrace.h index 1ebd2ca97f12..107fc5a48456 100644 --- a/arch/powerpc/include/asm/ftrace.h +++ b/arch/powerpc/include/asm/ftrace.h @@ -20,14 +20,6 @@ #ifndef __ASSEMBLY__ extern void _mcount(void); -static inline unsigned long ftrace_call_adjust(unsigned long addr) -{ - if (IS_ENABLED(CONFIG_ARCH_USING_PATCHABLE_FUNCTION_ENTRY)) - addr += MCOUNT_INSN_SIZE; - - return addr; -} - unsigned long prepare_ftrace_return(unsigned long parent, unsigned long ip, unsigned long sp); @@ -142,8 +134,10 @@ static inline u8 this_cpu_get_ftrace_enabled(void) { return 1; } #ifdef CONFIG_FUNCTION_TRACER extern unsigned int ftrace_tramp_text[], ftrace_tramp_init[]; void ftrace_free_init_tramp(void); +unsigned long ftrace_call_adjust(unsigned long addr); #else static inline void ftrace_free_init_tramp(void) { } +static inline unsigned long ftrace_call_adjust(unsigned long addr) { return addr; } #endif #endif /* !__ASSEMBLY__ */ diff --git a/arch/powerpc/include/asm/papr-sysparm.h b/arch/powerpc/include/asm/papr-sysparm.h index 0dbbff59101d..c3cd5b131033 100644 --- a/arch/powerpc/include/asm/papr-sysparm.h +++ b/arch/powerpc/include/asm/papr-sysparm.h @@ -32,7 +32,7 @@ typedef struct { */ struct papr_sysparm_buf { __be16 len; - char val[PAPR_SYSPARM_MAX_OUTPUT]; + u8 val[PAPR_SYSPARM_MAX_OUTPUT]; }; struct papr_sysparm_buf *papr_sysparm_buf_alloc(void); diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h index 7fd09f25452d..bb47af9054a9 100644 --- a/arch/powerpc/include/asm/reg.h +++ b/arch/powerpc/include/asm/reg.h @@ -617,6 +617,8 @@ #endif #define SPRN_HID2 0x3F8 /* Hardware Implementation Register 2 */ #define SPRN_HID2_GEKKO 0x398 /* Gekko HID2 Register */ +#define SPRN_HID2_G2_LE 0x3F3 /* G2_LE HID2 Register */ +#define HID2_G2_LE_HBE (1<<18) /* High BAT Enable (G2_LE) */ #define SPRN_IABR 0x3F2 /* Instruction Address Breakpoint Register */ #define SPRN_IABR2 0x3FA /* 83xx */ #define SPRN_IBCR 0x135 /* 83xx Insn Breakpoint Control Reg */ diff --git a/arch/powerpc/include/asm/sections.h b/arch/powerpc/include/asm/sections.h index ea26665f82cf..f43f3a6b0051 100644 --- a/arch/powerpc/include/asm/sections.h +++ b/arch/powerpc/include/asm/sections.h @@ -14,6 +14,7 @@ typedef struct func_desc func_desc_t; extern char __head_end[]; extern char __srwx_boundary[]; +extern char __exittext_begin[], __exittext_end[]; /* Patch sites */ extern s32 patch__call_flush_branch_caches1; diff --git a/arch/powerpc/include/asm/thread_info.h b/arch/powerpc/include/asm/thread_info.h index bf5dde1a4114..15c5691dd218 100644 --- a/arch/powerpc/include/asm/thread_info.h +++ b/arch/powerpc/include/asm/thread_info.h @@ -14,7 +14,7 @@ #ifdef __KERNEL__ -#ifdef CONFIG_KASAN +#if defined(CONFIG_KASAN) && CONFIG_THREAD_SHIFT < 15 #define MIN_THREAD_SHIFT (CONFIG_THREAD_SHIFT + 1) #else #define MIN_THREAD_SHIFT CONFIG_THREAD_SHIFT diff --git a/arch/powerpc/include/uapi/asm/papr-sysparm.h b/arch/powerpc/include/uapi/asm/papr-sysparm.h index 9f9a0f267ea5..f733467b1534 100644 --- a/arch/powerpc/include/uapi/asm/papr-sysparm.h +++ b/arch/powerpc/include/uapi/asm/papr-sysparm.h @@ -14,7 +14,7 @@ enum { struct papr_sysparm_io_block { __u32 parameter; __u16 length; - char data[PAPR_SYSPARM_MAX_OUTPUT]; + __u8 data[PAPR_SYSPARM_MAX_OUTPUT]; }; /** diff --git a/arch/powerpc/kernel/cpu_setup_6xx.S b/arch/powerpc/kernel/cpu_setup_6xx.S index f29ce3dd6140..bfd3f442e5eb 100644 --- a/arch/powerpc/kernel/cpu_setup_6xx.S +++ b/arch/powerpc/kernel/cpu_setup_6xx.S @@ -26,6 +26,15 @@ BEGIN_FTR_SECTION bl __init_fpu_registers END_FTR_SECTION_IFCLR(CPU_FTR_FPU_UNAVAILABLE) bl setup_common_caches + + /* + * This assumes that all cores using __setup_cpu_603 with + * MMU_FTR_USE_HIGH_BATS are G2_LE compatible + */ +BEGIN_MMU_FTR_SECTION + bl setup_g2_le_hid2 +END_MMU_FTR_SECTION_IFSET(MMU_FTR_USE_HIGH_BATS) + mtlr r5 blr _GLOBAL(__setup_cpu_604) @@ -115,6 +124,16 @@ SYM_FUNC_START_LOCAL(setup_604_hid0) blr SYM_FUNC_END(setup_604_hid0) +/* Enable high BATs for G2_LE and derivatives like e300cX */ +SYM_FUNC_START_LOCAL(setup_g2_le_hid2) + mfspr r11,SPRN_HID2_G2_LE + oris r11,r11,HID2_G2_LE_HBE@h + mtspr SPRN_HID2_G2_LE,r11 + sync + isync + blr +SYM_FUNC_END(setup_g2_le_hid2) + /* 7400 <= rev 2.7 and 7410 rev = 1.0 suffer from some * erratas we work around here. * Moto MPC710CE.pdf describes them, those are errata @@ -495,4 +514,3 @@ _GLOBAL(__restore_cpu_setup) mtcr r7 blr _ASM_NOKPROBE_SYMBOL(__restore_cpu_setup) - diff --git a/arch/powerpc/kernel/cpu_specs_e500mc.h b/arch/powerpc/kernel/cpu_specs_e500mc.h index ceb06b109f83..2ae8e9a7b461 100644 --- a/arch/powerpc/kernel/cpu_specs_e500mc.h +++ b/arch/powerpc/kernel/cpu_specs_e500mc.h @@ -8,7 +8,8 @@ #ifdef CONFIG_PPC64 #define COMMON_USER_BOOKE (PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | \ - PPC_FEATURE_HAS_FPU | PPC_FEATURE_64) + PPC_FEATURE_HAS_FPU | PPC_FEATURE_64 | \ + PPC_FEATURE_BOOKE) #else #define COMMON_USER_BOOKE (PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | \ PPC_FEATURE_BOOKE) diff --git a/arch/powerpc/kernel/interrupt_64.S b/arch/powerpc/kernel/interrupt_64.S index bd863702d812..1ad059a9e2fe 100644 --- a/arch/powerpc/kernel/interrupt_64.S +++ b/arch/powerpc/kernel/interrupt_64.S @@ -52,7 +52,8 @@ _ASM_NOKPROBE_SYMBOL(system_call_vectored_\name) mr r10,r1 ld r1,PACAKSAVE(r13) std r10,0(r1) - std r11,_NIP(r1) + std r11,_LINK(r1) + std r11,_NIP(r1) /* Saved LR is also the next instruction */ std r12,_MSR(r1) std r0,GPR0(r1) std r10,GPR1(r1) @@ -70,7 +71,6 @@ _ASM_NOKPROBE_SYMBOL(system_call_vectored_\name) std r9,GPR13(r1) SAVE_NVGPRS(r1) std r11,_XER(r1) - std r11,_LINK(r1) std r11,_CTR(r1) li r11,\trapnr diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c index d71eac3b2887..a9bebfd56b3b 100644 --- a/arch/powerpc/kernel/iommu.c +++ b/arch/powerpc/kernel/iommu.c @@ -1289,8 +1289,10 @@ spapr_tce_platform_iommu_attach_dev(struct iommu_domain *platform_domain, struct iommu_table_group *table_group; /* At first attach the ownership is already set */ - if (!domain) + if (!domain) { + iommu_group_put(grp); return 0; + } table_group = iommu_group_get_iommudata(grp); /* diff --git a/arch/powerpc/kernel/trace/ftrace.c b/arch/powerpc/kernel/trace/ftrace.c index 82010629cf88..d8d6b4fd9a14 100644 --- a/arch/powerpc/kernel/trace/ftrace.c +++ b/arch/powerpc/kernel/trace/ftrace.c @@ -27,10 +27,22 @@ #include <asm/ftrace.h> #include <asm/syscall.h> #include <asm/inst.h> +#include <asm/sections.h> #define NUM_FTRACE_TRAMPS 2 static unsigned long ftrace_tramps[NUM_FTRACE_TRAMPS]; +unsigned long ftrace_call_adjust(unsigned long addr) +{ + if (addr >= (unsigned long)__exittext_begin && addr < (unsigned long)__exittext_end) + return 0; + + if (IS_ENABLED(CONFIG_ARCH_USING_PATCHABLE_FUNCTION_ENTRY)) + addr += MCOUNT_INSN_SIZE; + + return addr; +} + static ppc_inst_t ftrace_create_branch_inst(unsigned long ip, unsigned long addr, int link) { ppc_inst_t op; diff --git a/arch/powerpc/kernel/trace/ftrace_64_pg.c b/arch/powerpc/kernel/trace/ftrace_64_pg.c index 7b85c3b460a3..12fab1803bcf 100644 --- a/arch/powerpc/kernel/trace/ftrace_64_pg.c +++ b/arch/powerpc/kernel/trace/ftrace_64_pg.c @@ -37,6 +37,11 @@ #define NUM_FTRACE_TRAMPS 8 static unsigned long ftrace_tramps[NUM_FTRACE_TRAMPS]; +unsigned long ftrace_call_adjust(unsigned long addr) +{ + return addr; +} + static ppc_inst_t ftrace_call_replace(unsigned long ip, unsigned long addr, int link) { diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S index 1c5970df3233..f420df7888a7 100644 --- a/arch/powerpc/kernel/vmlinux.lds.S +++ b/arch/powerpc/kernel/vmlinux.lds.S @@ -281,7 +281,9 @@ SECTIONS * to deal with references from __bug_table */ .exit.text : AT(ADDR(.exit.text) - LOAD_OFFSET) { + __exittext_begin = .; EXIT_TEXT + __exittext_end = .; } . = ALIGN(PAGE_SIZE); diff --git a/arch/powerpc/mm/kasan/init_32.c b/arch/powerpc/mm/kasan/init_32.c index a70828a6d935..aa9aa11927b2 100644 --- a/arch/powerpc/mm/kasan/init_32.c +++ b/arch/powerpc/mm/kasan/init_32.c @@ -64,6 +64,7 @@ int __init __weak kasan_init_region(void *start, size_t size) if (ret) return ret; + k_start = k_start & PAGE_MASK; block = memblock_alloc(k_end - k_start, PAGE_SIZE); if (!block) return -ENOMEM; diff --git a/arch/powerpc/platforms/85xx/mpc8536_ds.c b/arch/powerpc/platforms/85xx/mpc8536_ds.c index e966b2ad8ecd..b3327a358eb4 100644 --- a/arch/powerpc/platforms/85xx/mpc8536_ds.c +++ b/arch/powerpc/platforms/85xx/mpc8536_ds.c @@ -27,7 +27,7 @@ #include "mpc85xx.h" -void __init mpc8536_ds_pic_init(void) +static void __init mpc8536_ds_pic_init(void) { struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN, 0, 256, " OpenPIC "); diff --git a/arch/powerpc/platforms/85xx/mvme2500.c b/arch/powerpc/platforms/85xx/mvme2500.c index 1b59e45a0c64..19122daadb55 100644 --- a/arch/powerpc/platforms/85xx/mvme2500.c +++ b/arch/powerpc/platforms/85xx/mvme2500.c @@ -21,7 +21,7 @@ #include "mpc85xx.h" -void __init mvme2500_pic_init(void) +static void __init mvme2500_pic_init(void) { struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN | MPIC_SINGLE_DEST_CPU, diff --git a/arch/powerpc/platforms/85xx/p1010rdb.c b/arch/powerpc/platforms/85xx/p1010rdb.c index 10d6f1fa3327..491895ac8bcf 100644 --- a/arch/powerpc/platforms/85xx/p1010rdb.c +++ b/arch/powerpc/platforms/85xx/p1010rdb.c @@ -24,7 +24,7 @@ #include "mpc85xx.h" -void __init p1010_rdb_pic_init(void) +static void __init p1010_rdb_pic_init(void) { struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN | MPIC_SINGLE_DEST_CPU, diff --git a/arch/powerpc/platforms/85xx/p1022_ds.c b/arch/powerpc/platforms/85xx/p1022_ds.c index 0dd786a061a6..adc3a2ee1415 100644 --- a/arch/powerpc/platforms/85xx/p1022_ds.c +++ b/arch/powerpc/platforms/85xx/p1022_ds.c @@ -370,7 +370,7 @@ exit: * * @pixclock: the wavelength, in picoseconds, of the clock */ -void p1022ds_set_pixel_clock(unsigned int pixclock) +static void p1022ds_set_pixel_clock(unsigned int pixclock) { struct device_node *guts_np = NULL; struct ccsr_guts __iomem *guts; @@ -418,7 +418,7 @@ void p1022ds_set_pixel_clock(unsigned int pixclock) /** * p1022ds_valid_monitor_port: set the monitor port for sysfs */ -enum fsl_diu_monitor_port +static enum fsl_diu_monitor_port p1022ds_valid_monitor_port(enum fsl_diu_monitor_port port) { switch (port) { @@ -432,7 +432,7 @@ p1022ds_valid_monitor_port(enum fsl_diu_monitor_port port) #endif -void __init p1022_ds_pic_init(void) +static void __init p1022_ds_pic_init(void) { struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN | MPIC_SINGLE_DEST_CPU, diff --git a/arch/powerpc/platforms/85xx/p1022_rdk.c b/arch/powerpc/platforms/85xx/p1022_rdk.c index 25ab6e9c1470..6198299d95b1 100644 --- a/arch/powerpc/platforms/85xx/p1022_rdk.c +++ b/arch/powerpc/platforms/85xx/p1022_rdk.c @@ -40,7 +40,7 @@ * * @pixclock: the wavelength, in picoseconds, of the clock */ -void p1022rdk_set_pixel_clock(unsigned int pixclock) +static void p1022rdk_set_pixel_clock(unsigned int pixclock) { struct device_node *guts_np = NULL; struct ccsr_guts __iomem *guts; @@ -88,7 +88,7 @@ void p1022rdk_set_pixel_clock(unsigned int pixclock) /** * p1022rdk_valid_monitor_port: set the monitor port for sysfs */ -enum fsl_diu_monitor_port +static enum fsl_diu_monitor_port p1022rdk_valid_monitor_port(enum fsl_diu_monitor_port port) { return FSL_DIU_PORT_DVI; @@ -96,7 +96,7 @@ p1022rdk_valid_monitor_port(enum fsl_diu_monitor_port port) #endif -void __init p1022_rdk_pic_init(void) +static void __init p1022_rdk_pic_init(void) { struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN | MPIC_SINGLE_DEST_CPU, diff --git a/arch/powerpc/platforms/85xx/socrates_fpga_pic.c b/arch/powerpc/platforms/85xx/socrates_fpga_pic.c index baa12eff6d5d..60e0b8947ce6 100644 --- a/arch/powerpc/platforms/85xx/socrates_fpga_pic.c +++ b/arch/powerpc/platforms/85xx/socrates_fpga_pic.c @@ -8,6 +8,8 @@ #include <linux/of_irq.h> #include <linux/io.h> +#include "socrates_fpga_pic.h" + /* * The FPGA supports 9 interrupt sources, which can be routed to 3 * interrupt request lines of the MPIC. The line to be used can be diff --git a/arch/powerpc/platforms/85xx/xes_mpc85xx.c b/arch/powerpc/platforms/85xx/xes_mpc85xx.c index 45f257fc1ade..2582427d8d01 100644 --- a/arch/powerpc/platforms/85xx/xes_mpc85xx.c +++ b/arch/powerpc/platforms/85xx/xes_mpc85xx.c @@ -37,7 +37,7 @@ #define MPC85xx_L2CTL_L2I 0x40000000 /* L2 flash invalidate */ #define MPC85xx_L2CTL_L2SIZ_MASK 0x30000000 /* L2 SRAM size (R/O) */ -void __init xes_mpc85xx_pic_init(void) +static void __init xes_mpc85xx_pic_init(void) { struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN, 0, 256, " OpenPIC "); diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c index 4561667832ed..4e9916bb03d7 100644 --- a/arch/powerpc/platforms/pseries/lpar.c +++ b/arch/powerpc/platforms/pseries/lpar.c @@ -662,8 +662,12 @@ u64 pseries_paravirt_steal_clock(int cpu) { struct lppaca *lppaca = &lppaca_of(cpu); - return be64_to_cpu(READ_ONCE(lppaca->enqueue_dispatch_tb)) + - be64_to_cpu(READ_ONCE(lppaca->ready_enqueue_tb)); + /* + * VPA steal time counters are reported at TB frequency. Hence do a + * conversion to ns before returning + */ + return tb_to_ns(be64_to_cpu(READ_ONCE(lppaca->enqueue_dispatch_tb)) + + be64_to_cpu(READ_ONCE(lppaca->ready_enqueue_tb))); } #endif diff --git a/arch/powerpc/sysdev/udbg_memcons.c b/arch/powerpc/sysdev/udbg_memcons.c index 5020044400dc..4de57ba52236 100644 --- a/arch/powerpc/sysdev/udbg_memcons.c +++ b/arch/powerpc/sysdev/udbg_memcons.c @@ -41,7 +41,7 @@ struct memcons memcons = { .input_end = &memcons_input[CONFIG_PPC_MEMCONS_INPUT_SIZE], }; -void memcons_putc(char c) +static void memcons_putc(char c) { char *new_output_pos; @@ -54,7 +54,7 @@ void memcons_putc(char c) memcons.output_pos = new_output_pos; } -int memcons_getc_poll(void) +static int memcons_getc_poll(void) { char c; char *new_input_pos; @@ -77,7 +77,7 @@ int memcons_getc_poll(void) return -1; } -int memcons_getc(void) +static int memcons_getc(void) { int c; diff --git a/arch/riscv/kernel/paravirt.c b/arch/riscv/kernel/paravirt.c index 8e114f5930ce..0d6225fd3194 100644 --- a/arch/riscv/kernel/paravirt.c +++ b/arch/riscv/kernel/paravirt.c @@ -41,7 +41,7 @@ static int __init parse_no_stealacc(char *arg) early_param("no-steal-acc", parse_no_stealacc); -DEFINE_PER_CPU(struct sbi_sta_struct, steal_time) __aligned(64); +static DEFINE_PER_CPU(struct sbi_sta_struct, steal_time) __aligned(64); static bool __init has_pv_steal_clock(void) { @@ -91,8 +91,8 @@ static int pv_time_cpu_down_prepare(unsigned int cpu) static u64 pv_time_steal_clock(int cpu) { struct sbi_sta_struct *st = per_cpu_ptr(&steal_time, cpu); - u32 sequence; - u64 steal; + __le32 sequence; + __le64 steal; /* * Check the sequence field before and after reading the steal diff --git a/arch/riscv/kvm/vcpu_sbi_sta.c b/arch/riscv/kvm/vcpu_sbi_sta.c index 01f09fe8c3b0..d8cf9ca28c61 100644 --- a/arch/riscv/kvm/vcpu_sbi_sta.c +++ b/arch/riscv/kvm/vcpu_sbi_sta.c @@ -26,8 +26,12 @@ void kvm_riscv_vcpu_record_steal_time(struct kvm_vcpu *vcpu) { gpa_t shmem = vcpu->arch.sta.shmem; u64 last_steal = vcpu->arch.sta.last_steal; - u32 *sequence_ptr, sequence; - u64 *steal_ptr, steal; + __le32 __user *sequence_ptr; + __le64 __user *steal_ptr; + __le32 sequence_le; + __le64 steal_le; + u32 sequence; + u64 steal; unsigned long hva; gfn_t gfn; @@ -47,22 +51,22 @@ void kvm_riscv_vcpu_record_steal_time(struct kvm_vcpu *vcpu) return; } - sequence_ptr = (u32 *)(hva + offset_in_page(shmem) + + sequence_ptr = (__le32 __user *)(hva + offset_in_page(shmem) + offsetof(struct sbi_sta_struct, sequence)); - steal_ptr = (u64 *)(hva + offset_in_page(shmem) + + steal_ptr = (__le64 __user *)(hva + offset_in_page(shmem) + offsetof(struct sbi_sta_struct, steal)); - if (WARN_ON(get_user(sequence, sequence_ptr))) + if (WARN_ON(get_user(sequence_le, sequence_ptr))) return; - sequence = le32_to_cpu(sequence); + sequence = le32_to_cpu(sequence_le); sequence += 1; if (WARN_ON(put_user(cpu_to_le32(sequence), sequence_ptr))) return; - if (!WARN_ON(get_user(steal, steal_ptr))) { - steal = le64_to_cpu(steal); + if (!WARN_ON(get_user(steal_le, steal_ptr))) { + steal = le64_to_cpu(steal_le); vcpu->arch.sta.last_steal = READ_ONCE(current->sched_info.run_delay); steal += vcpu->arch.sta.last_steal - last_steal; WARN_ON(put_user(cpu_to_le64(steal), steal_ptr)); diff --git a/arch/x86/Makefile b/arch/x86/Makefile index 2264db14a25d..da8f3caf2781 100644 --- a/arch/x86/Makefile +++ b/arch/x86/Makefile @@ -112,13 +112,13 @@ ifeq ($(CONFIG_X86_32),y) # temporary until string.h is fixed KBUILD_CFLAGS += -ffreestanding - ifeq ($(CONFIG_STACKPROTECTOR),y) - ifeq ($(CONFIG_SMP),y) + ifeq ($(CONFIG_STACKPROTECTOR),y) + ifeq ($(CONFIG_SMP),y) KBUILD_CFLAGS += -mstack-protector-guard-reg=fs -mstack-protector-guard-symbol=__stack_chk_guard - else + else KBUILD_CFLAGS += -mstack-protector-guard=global - endif endif + endif else BITS := 64 UTS_MACHINE := x86_64 diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c index a6216c874729..315c7c2ba89b 100644 --- a/arch/x86/kvm/vmx/pmu_intel.c +++ b/arch/x86/kvm/vmx/pmu_intel.c @@ -71,7 +71,7 @@ static int fixed_pmc_events[] = { static void reprogram_fixed_counters(struct kvm_pmu *pmu, u64 data) { struct kvm_pmc *pmc; - u8 old_fixed_ctr_ctrl = pmu->fixed_ctr_ctrl; + u64 old_fixed_ctr_ctrl = pmu->fixed_ctr_ctrl; int i; pmu->fixed_ctr_ctrl = data; diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index bf10a9073a09..48a61d283406 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -1704,22 +1704,17 @@ static int do_get_msr_feature(struct kvm_vcpu *vcpu, unsigned index, u64 *data) struct kvm_msr_entry msr; int r; + /* Unconditionally clear the output for simplicity */ + msr.data = 0; msr.index = index; r = kvm_get_msr_feature(&msr); - if (r == KVM_MSR_RET_INVALID) { - /* Unconditionally clear the output for simplicity */ - *data = 0; - if (kvm_msr_ignored_check(index, 0, false)) - r = 0; - } - - if (r) - return r; + if (r == KVM_MSR_RET_INVALID && kvm_msr_ignored_check(index, 0, false)) + r = 0; *data = msr.data; - return 0; + return r; } static bool __kvm_valid_efer(struct kvm_vcpu *vcpu, u64 efer) @@ -2511,7 +2506,7 @@ static u64 compute_guest_tsc(struct kvm_vcpu *vcpu, s64 kernel_ns) } #ifdef CONFIG_X86_64 -static inline int gtod_is_based_on_tsc(int mode) +static inline bool gtod_is_based_on_tsc(int mode) { return mode == VDSO_CLOCKMODE_TSC || mode == VDSO_CLOCKMODE_HVCLOCK; } @@ -5458,7 +5453,8 @@ static int kvm_vcpu_ioctl_x86_set_vcpu_events(struct kvm_vcpu *vcpu, if (events->flags & KVM_VCPUEVENT_VALID_NMI_PENDING) { vcpu->arch.nmi_pending = 0; atomic_set(&vcpu->arch.nmi_queued, events->nmi.pending); - kvm_make_request(KVM_REQ_NMI, vcpu); + if (events->nmi.pending) + kvm_make_request(KVM_REQ_NMI, vcpu); } static_call(kvm_x86_set_nmi_mask)(vcpu, events->nmi.masked); diff --git a/arch/x86/mm/ident_map.c b/arch/x86/mm/ident_map.c index 968d7005f4a7..f50cc210a981 100644 --- a/arch/x86/mm/ident_map.c +++ b/arch/x86/mm/ident_map.c @@ -26,18 +26,31 @@ static int ident_pud_init(struct x86_mapping_info *info, pud_t *pud_page, for (; addr < end; addr = next) { pud_t *pud = pud_page + pud_index(addr); pmd_t *pmd; + bool use_gbpage; next = (addr & PUD_MASK) + PUD_SIZE; if (next > end) next = end; - if (info->direct_gbpages) { - pud_t pudval; + /* if this is already a gbpage, this portion is already mapped */ + if (pud_large(*pud)) + continue; + + /* Is using a gbpage allowed? */ + use_gbpage = info->direct_gbpages; - if (pud_present(*pud)) - continue; + /* Don't use gbpage if it maps more than the requested region. */ + /* at the begining: */ + use_gbpage &= ((addr & ~PUD_MASK) == 0); + /* ... or at the end: */ + use_gbpage &= ((next & ~PUD_MASK) == 0); + + /* Never overwrite existing mappings */ + use_gbpage &= !pud_present(*pud); + + if (use_gbpage) { + pud_t pudval; - addr &= PUD_MASK; pudval = __pud((addr - info->offset) | info->page_flag); set_pud(pud, pudval); continue; diff --git a/arch/x86/xen/smp.c b/arch/x86/xen/smp.c index 4b0d6fff88de..1fb9a1644d94 100644 --- a/arch/x86/xen/smp.c +++ b/arch/x86/xen/smp.c @@ -65,6 +65,8 @@ int xen_smp_intr_init(unsigned int cpu) char *resched_name, *callfunc_name, *debug_name; resched_name = kasprintf(GFP_KERNEL, "resched%d", cpu); + if (!resched_name) + goto fail_mem; per_cpu(xen_resched_irq, cpu).name = resched_name; rc = bind_ipi_to_irqhandler(XEN_RESCHEDULE_VECTOR, cpu, @@ -77,6 +79,8 @@ int xen_smp_intr_init(unsigned int cpu) per_cpu(xen_resched_irq, cpu).irq = rc; callfunc_name = kasprintf(GFP_KERNEL, "callfunc%d", cpu); + if (!callfunc_name) + goto fail_mem; per_cpu(xen_callfunc_irq, cpu).name = callfunc_name; rc = bind_ipi_to_irqhandler(XEN_CALL_FUNCTION_VECTOR, cpu, @@ -90,6 +94,9 @@ int xen_smp_intr_init(unsigned int cpu) if (!xen_fifo_events) { debug_name = kasprintf(GFP_KERNEL, "debug%d", cpu); + if (!debug_name) + goto fail_mem; + per_cpu(xen_debug_irq, cpu).name = debug_name; rc = bind_virq_to_irqhandler(VIRQ_DEBUG, cpu, xen_debug_interrupt, @@ -101,6 +108,9 @@ int xen_smp_intr_init(unsigned int cpu) } callfunc_name = kasprintf(GFP_KERNEL, "callfuncsingle%d", cpu); + if (!callfunc_name) + goto fail_mem; + per_cpu(xen_callfuncsingle_irq, cpu).name = callfunc_name; rc = bind_ipi_to_irqhandler(XEN_CALL_FUNCTION_SINGLE_VECTOR, cpu, @@ -114,6 +124,8 @@ int xen_smp_intr_init(unsigned int cpu) return 0; + fail_mem: + rc = -ENOMEM; fail: xen_smp_intr_free(cpu); return rc; diff --git a/drivers/accel/ivpu/ivpu_hw_37xx.c b/drivers/accel/ivpu/ivpu_hw_37xx.c index 77accd029c4a..89af1006df55 100644 --- a/drivers/accel/ivpu/ivpu_hw_37xx.c +++ b/drivers/accel/ivpu/ivpu_hw_37xx.c @@ -510,16 +510,6 @@ static int ivpu_boot_pwr_domain_enable(struct ivpu_device *vdev) return ret; } -static int ivpu_boot_pwr_domain_disable(struct ivpu_device *vdev) -{ - ivpu_boot_dpu_active_drive(vdev, false); - ivpu_boot_pwr_island_isolation_drive(vdev, true); - ivpu_boot_pwr_island_trickle_drive(vdev, false); - ivpu_boot_pwr_island_drive(vdev, false); - - return ivpu_boot_wait_for_pwr_island_status(vdev, 0x0); -} - static void ivpu_boot_no_snoop_enable(struct ivpu_device *vdev) { u32 val = REGV_RD32(VPU_37XX_HOST_IF_TCU_PTW_OVERRIDES); @@ -616,12 +606,37 @@ static int ivpu_hw_37xx_info_init(struct ivpu_device *vdev) return 0; } +static int ivpu_hw_37xx_ip_reset(struct ivpu_device *vdev) +{ + int ret; + u32 val; + + if (IVPU_WA(punit_disabled)) + return 0; + + ret = REGB_POLL_FLD(VPU_37XX_BUTTRESS_VPU_IP_RESET, TRIGGER, 0, TIMEOUT_US); + if (ret) { + ivpu_err(vdev, "Timed out waiting for TRIGGER bit\n"); + return ret; + } + + val = REGB_RD32(VPU_37XX_BUTTRESS_VPU_IP_RESET); + val = REG_SET_FLD(VPU_37XX_BUTTRESS_VPU_IP_RESET, TRIGGER, val); + REGB_WR32(VPU_37XX_BUTTRESS_VPU_IP_RESET, val); + + ret = REGB_POLL_FLD(VPU_37XX_BUTTRESS_VPU_IP_RESET, TRIGGER, 0, TIMEOUT_US); + if (ret) + ivpu_err(vdev, "Timed out waiting for RESET completion\n"); + + return ret; +} + static int ivpu_hw_37xx_reset(struct ivpu_device *vdev) { int ret = 0; - if (ivpu_boot_pwr_domain_disable(vdev)) { - ivpu_err(vdev, "Failed to disable power domain\n"); + if (ivpu_hw_37xx_ip_reset(vdev)) { + ivpu_err(vdev, "Failed to reset NPU\n"); ret = -EIO; } @@ -661,6 +676,11 @@ static int ivpu_hw_37xx_power_up(struct ivpu_device *vdev) { int ret; + /* PLL requests may fail when powering down, so issue WP 0 here */ + ret = ivpu_pll_disable(vdev); + if (ret) + ivpu_warn(vdev, "Failed to disable PLL: %d\n", ret); + ret = ivpu_hw_37xx_d0i3_disable(vdev); if (ret) ivpu_warn(vdev, "Failed to disable D0I3: %d\n", ret); diff --git a/drivers/accel/ivpu/ivpu_pm.c b/drivers/accel/ivpu/ivpu_pm.c index f501f27ebafd..5f73854234ba 100644 --- a/drivers/accel/ivpu/ivpu_pm.c +++ b/drivers/accel/ivpu/ivpu_pm.c @@ -58,11 +58,14 @@ static int ivpu_suspend(struct ivpu_device *vdev) { int ret; + /* Save PCI state before powering down as it sometimes gets corrupted if NPU hangs */ + pci_save_state(to_pci_dev(vdev->drm.dev)); + ret = ivpu_shutdown(vdev); - if (ret) { + if (ret) ivpu_err(vdev, "Failed to shutdown VPU: %d\n", ret); - return ret; - } + + pci_set_power_state(to_pci_dev(vdev->drm.dev), PCI_D3hot); return ret; } @@ -71,6 +74,9 @@ static int ivpu_resume(struct ivpu_device *vdev) { int ret; + pci_set_power_state(to_pci_dev(vdev->drm.dev), PCI_D0); + pci_restore_state(to_pci_dev(vdev->drm.dev)); + retry: ret = ivpu_hw_power_up(vdev); if (ret) { @@ -120,15 +126,20 @@ static void ivpu_pm_recovery_work(struct work_struct *work) ivpu_fw_log_dump(vdev); -retry: - ret = pci_try_reset_function(to_pci_dev(vdev->drm.dev)); - if (ret == -EAGAIN && !drm_dev_is_unplugged(&vdev->drm)) { - cond_resched(); - goto retry; - } + atomic_inc(&vdev->pm->reset_counter); + atomic_set(&vdev->pm->reset_pending, 1); + down_write(&vdev->pm->reset_lock); + + ivpu_suspend(vdev); + ivpu_pm_prepare_cold_boot(vdev); + ivpu_jobs_abort_all(vdev); + + ret = ivpu_resume(vdev); + if (ret) + ivpu_err(vdev, "Failed to resume NPU: %d\n", ret); - if (ret && ret != -EAGAIN) - ivpu_err(vdev, "Failed to reset VPU: %d\n", ret); + up_write(&vdev->pm->reset_lock); + atomic_set(&vdev->pm->reset_pending, 0); kobject_uevent_env(&vdev->drm.dev->kobj, KOBJ_CHANGE, evt); pm_runtime_mark_last_busy(vdev->drm.dev); @@ -200,9 +211,6 @@ int ivpu_pm_suspend_cb(struct device *dev) ivpu_suspend(vdev); ivpu_pm_prepare_warm_boot(vdev); - pci_save_state(to_pci_dev(dev)); - pci_set_power_state(to_pci_dev(dev), PCI_D3hot); - ivpu_dbg(vdev, PM, "Suspend done.\n"); return 0; @@ -216,9 +224,6 @@ int ivpu_pm_resume_cb(struct device *dev) ivpu_dbg(vdev, PM, "Resume..\n"); - pci_set_power_state(to_pci_dev(dev), PCI_D0); - pci_restore_state(to_pci_dev(dev)); - ret = ivpu_resume(vdev); if (ret) ivpu_err(vdev, "Failed to resume: %d\n", ret); diff --git a/drivers/base/arch_topology.c b/drivers/base/arch_topology.c index 018ac202de34..024b78a0cfc1 100644 --- a/drivers/base/arch_topology.c +++ b/drivers/base/arch_topology.c @@ -431,9 +431,6 @@ init_cpu_capacity_callback(struct notifier_block *nb, struct cpufreq_policy *policy = data; int cpu; - if (!raw_capacity) - return 0; - if (val != CPUFREQ_CREATE_POLICY) return 0; @@ -450,9 +447,11 @@ init_cpu_capacity_callback(struct notifier_block *nb, } if (cpumask_empty(cpus_to_visit)) { - topology_normalize_cpu_scale(); - schedule_work(&update_topology_flags_work); - free_raw_capacity(); + if (raw_capacity) { + topology_normalize_cpu_scale(); + schedule_work(&update_topology_flags_work); + free_raw_capacity(); + } pr_debug("cpu_capacity: parsing done\n"); schedule_work(&parsing_done_work); } @@ -472,7 +471,7 @@ static int __init register_cpufreq_notifier(void) * On ACPI-based systems skip registering cpufreq notifier as cpufreq * information is not needed for cpu capacity initialization. */ - if (!acpi_disabled || !raw_capacity) + if (!acpi_disabled) return -EINVAL; if (!alloc_cpumask_var(&cpus_to_visit, GFP_KERNEL)) diff --git a/drivers/base/core.c b/drivers/base/core.c index 14d46af40f9a..9828da9b933c 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -125,7 +125,7 @@ static void __fwnode_link_del(struct fwnode_link *link) */ static void __fwnode_link_cycle(struct fwnode_link *link) { - pr_debug("%pfwf: Relaxing link with %pfwf\n", + pr_debug("%pfwf: cycle: depends on %pfwf\n", link->consumer, link->supplier); link->flags |= FWLINK_FLAG_CYCLE; } @@ -284,10 +284,12 @@ static bool device_is_ancestor(struct device *dev, struct device *target) return false; } +#define DL_MARKER_FLAGS (DL_FLAG_INFERRED | \ + DL_FLAG_CYCLE | \ + DL_FLAG_MANAGED) static inline bool device_link_flag_is_sync_state_only(u32 flags) { - return (flags & ~(DL_FLAG_INFERRED | DL_FLAG_CYCLE)) == - (DL_FLAG_SYNC_STATE_ONLY | DL_FLAG_MANAGED); + return (flags & ~DL_MARKER_FLAGS) == DL_FLAG_SYNC_STATE_ONLY; } /** @@ -1943,6 +1945,7 @@ static bool __fw_devlink_relax_cycles(struct device *con, /* Termination condition. */ if (sup_dev == con) { + pr_debug("----- cycle: start -----\n"); ret = true; goto out; } @@ -1974,8 +1977,11 @@ static bool __fw_devlink_relax_cycles(struct device *con, else par_dev = fwnode_get_next_parent_dev(sup_handle); - if (par_dev && __fw_devlink_relax_cycles(con, par_dev->fwnode)) + if (par_dev && __fw_devlink_relax_cycles(con, par_dev->fwnode)) { + pr_debug("%pfwf: cycle: child of %pfwf\n", sup_handle, + par_dev->fwnode); ret = true; + } if (!sup_dev) goto out; @@ -1991,6 +1997,8 @@ static bool __fw_devlink_relax_cycles(struct device *con, if (__fw_devlink_relax_cycles(con, dev_link->supplier->fwnode)) { + pr_debug("%pfwf: cycle: depends on %pfwf\n", sup_handle, + dev_link->supplier->fwnode); fw_devlink_relax_link(dev_link); dev_link->flags |= DL_FLAG_CYCLE; ret = true; @@ -2058,13 +2066,19 @@ static int fw_devlink_create_devlink(struct device *con, /* * SYNC_STATE_ONLY device links don't block probing and supports cycles. - * So cycle detection isn't necessary and shouldn't be done. + * So, one might expect that cycle detection isn't necessary for them. + * However, if the device link was marked as SYNC_STATE_ONLY because + * it's part of a cycle, then we still need to do cycle detection. This + * is because the consumer and supplier might be part of multiple cycles + * and we need to detect all those cycles. */ - if (!(flags & DL_FLAG_SYNC_STATE_ONLY)) { + if (!device_link_flag_is_sync_state_only(flags) || + flags & DL_FLAG_CYCLE) { device_links_write_lock(); if (__fw_devlink_relax_cycles(con, sup_handle)) { __fwnode_link_cycle(link); flags = fw_devlink_get_flags(link->flags); + pr_debug("----- cycle: end -----\n"); dev_info(con, "Fixed dependency cycle(s) with %pfwf\n", sup_handle); } diff --git a/drivers/base/regmap/regmap-kunit.c b/drivers/base/regmap/regmap-kunit.c index 026bdcb45127..0d957c5f1bcc 100644 --- a/drivers/base/regmap/regmap-kunit.c +++ b/drivers/base/regmap/regmap-kunit.c @@ -9,6 +9,23 @@ #define BLOCK_TEST_SIZE 12 +static void get_changed_bytes(void *orig, void *new, size_t size) +{ + char *o = orig; + char *n = new; + int i; + + get_random_bytes(new, size); + + /* + * This could be nicer and more efficient but we shouldn't + * super care. + */ + for (i = 0; i < size; i++) + while (n[i] == o[i]) + get_random_bytes(&n[i], 1); +} + static const struct regmap_config test_regmap_config = { .max_register = BLOCK_TEST_SIZE, .reg_stride = 1, @@ -1202,7 +1219,8 @@ static void raw_noinc_write(struct kunit *test) struct regmap *map; struct regmap_config config; struct regmap_ram_data *data; - unsigned int val, val_test, val_last; + unsigned int val; + u16 val_test, val_last; u16 val_array[BLOCK_TEST_SIZE]; config = raw_regmap_config; @@ -1251,7 +1269,7 @@ static void raw_sync(struct kunit *test) struct regmap *map; struct regmap_config config; struct regmap_ram_data *data; - u16 val[2]; + u16 val[3]; u16 *hw_buf; unsigned int rval; int i; @@ -1265,17 +1283,13 @@ static void raw_sync(struct kunit *test) hw_buf = (u16 *)data->vals; - get_random_bytes(&val, sizeof(val)); + get_changed_bytes(&hw_buf[2], &val[0], sizeof(val)); /* Do a regular write and a raw write in cache only mode */ regcache_cache_only(map, true); - KUNIT_EXPECT_EQ(test, 0, regmap_raw_write(map, 2, val, sizeof(val))); - if (config.val_format_endian == REGMAP_ENDIAN_BIG) - KUNIT_EXPECT_EQ(test, 0, regmap_write(map, 6, - be16_to_cpu(val[0]))); - else - KUNIT_EXPECT_EQ(test, 0, regmap_write(map, 6, - le16_to_cpu(val[0]))); + KUNIT_EXPECT_EQ(test, 0, regmap_raw_write(map, 2, val, + sizeof(u16) * 2)); + KUNIT_EXPECT_EQ(test, 0, regmap_write(map, 4, val[2])); /* We should read back the new values, and defaults for the rest */ for (i = 0; i < config.max_register + 1; i++) { @@ -1284,24 +1298,34 @@ static void raw_sync(struct kunit *test) switch (i) { case 2: case 3: - case 6: if (config.val_format_endian == REGMAP_ENDIAN_BIG) { KUNIT_EXPECT_EQ(test, rval, - be16_to_cpu(val[i % 2])); + be16_to_cpu(val[i - 2])); } else { KUNIT_EXPECT_EQ(test, rval, - le16_to_cpu(val[i % 2])); + le16_to_cpu(val[i - 2])); } break; + case 4: + KUNIT_EXPECT_EQ(test, rval, val[i - 2]); + break; default: KUNIT_EXPECT_EQ(test, config.reg_defaults[i].def, rval); break; } } + + /* + * The value written via _write() was translated by the core, + * translate the original copy for comparison purposes. + */ + if (config.val_format_endian == REGMAP_ENDIAN_BIG) + val[2] = cpu_to_be16(val[2]); + else + val[2] = cpu_to_le16(val[2]); /* The values should not appear in the "hardware" */ - KUNIT_EXPECT_MEMNEQ(test, &hw_buf[2], val, sizeof(val)); - KUNIT_EXPECT_MEMNEQ(test, &hw_buf[6], val, sizeof(u16)); + KUNIT_EXPECT_MEMNEQ(test, &hw_buf[2], &val[0], sizeof(val)); for (i = 0; i < config.max_register + 1; i++) data->written[i] = false; @@ -1312,8 +1336,7 @@ static void raw_sync(struct kunit *test) KUNIT_EXPECT_EQ(test, 0, regcache_sync(map)); /* The values should now appear in the "hardware" */ - KUNIT_EXPECT_MEMEQ(test, &hw_buf[2], val, sizeof(val)); - KUNIT_EXPECT_MEMEQ(test, &hw_buf[6], val, sizeof(u16)); + KUNIT_EXPECT_MEMEQ(test, &hw_buf[2], &val[0], sizeof(val)); regmap_exit(map); } diff --git a/drivers/bus/mhi/common.h b/drivers/bus/mhi/common.h index f794b9c8049e..dda340aaed95 100644 --- a/drivers/bus/mhi/common.h +++ b/drivers/bus/mhi/common.h @@ -297,30 +297,30 @@ struct mhi_ring_element { __le32 dword[2]; }; +#define MHI_STATE_LIST \ + mhi_state(RESET, "RESET") \ + mhi_state(READY, "READY") \ + mhi_state(M0, "M0") \ + mhi_state(M1, "M1") \ + mhi_state(M2, "M2") \ + mhi_state(M3, "M3") \ + mhi_state(M3_FAST, "M3_FAST") \ + mhi_state(BHI, "BHI") \ + mhi_state_end(SYS_ERR, "SYS ERROR") + +#undef mhi_state +#undef mhi_state_end + +#define mhi_state(a, b) case MHI_STATE_##a: return b; +#define mhi_state_end(a, b) case MHI_STATE_##a: return b; + static inline const char *mhi_state_str(enum mhi_state state) { switch (state) { - case MHI_STATE_RESET: - return "RESET"; - case MHI_STATE_READY: - return "READY"; - case MHI_STATE_M0: - return "M0"; - case MHI_STATE_M1: - return "M1"; - case MHI_STATE_M2: - return "M2"; - case MHI_STATE_M3: - return "M3"; - case MHI_STATE_M3_FAST: - return "M3 FAST"; - case MHI_STATE_BHI: - return "BHI"; - case MHI_STATE_SYS_ERR: - return "SYS ERROR"; + MHI_STATE_LIST default: return "Unknown state"; } -}; +} #endif /* _MHI_COMMON_H */ diff --git a/drivers/bus/mhi/ep/main.c b/drivers/bus/mhi/ep/main.c index 65fc1d738bec..f8f674adf1d4 100644 --- a/drivers/bus/mhi/ep/main.c +++ b/drivers/bus/mhi/ep/main.c @@ -1149,8 +1149,9 @@ int mhi_ep_power_up(struct mhi_ep_cntrl *mhi_cntrl) mhi_ep_mmio_mask_interrupts(mhi_cntrl); mhi_ep_mmio_init(mhi_cntrl); - mhi_cntrl->mhi_event = kzalloc(mhi_cntrl->event_rings * (sizeof(*mhi_cntrl->mhi_event)), - GFP_KERNEL); + mhi_cntrl->mhi_event = kcalloc(mhi_cntrl->event_rings, + sizeof(*mhi_cntrl->mhi_event), + GFP_KERNEL); if (!mhi_cntrl->mhi_event) return -ENOMEM; @@ -1496,7 +1497,7 @@ int mhi_ep_register_controller(struct mhi_ep_cntrl *mhi_cntrl, mhi_cntrl->ring_item_cache = kmem_cache_create("mhi_ep_ring_item", sizeof(struct mhi_ep_ring_item), 0, 0, NULL); - if (!mhi_cntrl->ev_ring_el_cache) { + if (!mhi_cntrl->ring_item_cache) { ret = -ENOMEM; goto err_destroy_tre_buf_cache; } diff --git a/drivers/bus/mhi/host/boot.c b/drivers/bus/mhi/host/boot.c index edc0ec5a0933..dedd29ca8db3 100644 --- a/drivers/bus/mhi/host/boot.c +++ b/drivers/bus/mhi/host/boot.c @@ -395,7 +395,7 @@ void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl) void *buf; dma_addr_t dma_addr; size_t size, fw_sz; - int i, ret; + int ret; if (MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state)) { dev_err(dev, "Device MHI is not in valid state\n"); @@ -408,15 +408,6 @@ void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl) if (ret) dev_err(dev, "Could not capture serial number via BHI\n"); - for (i = 0; i < ARRAY_SIZE(mhi_cntrl->oem_pk_hash); i++) { - ret = mhi_read_reg(mhi_cntrl, mhi_cntrl->bhi, BHI_OEMPKHASH(i), - &mhi_cntrl->oem_pk_hash[i]); - if (ret) { - dev_err(dev, "Could not capture OEM PK HASH via BHI\n"); - break; - } - } - /* wait for ready on pass through or any other execution environment */ if (!MHI_FW_LOAD_CAPABLE(mhi_cntrl->ee)) goto fw_load_ready_state; diff --git a/drivers/bus/mhi/host/init.c b/drivers/bus/mhi/host/init.c index 65ceac1837f9..44f934981de8 100644 --- a/drivers/bus/mhi/host/init.c +++ b/drivers/bus/mhi/host/init.c @@ -20,50 +20,49 @@ #include <linux/wait.h> #include "internal.h" +#define CREATE_TRACE_POINTS +#include "trace.h" + static DEFINE_IDA(mhi_controller_ida); +#undef mhi_ee +#undef mhi_ee_end + +#define mhi_ee(a, b) [MHI_EE_##a] = b, +#define mhi_ee_end(a, b) [MHI_EE_##a] = b, + const char * const mhi_ee_str[MHI_EE_MAX] = { - [MHI_EE_PBL] = "PRIMARY BOOTLOADER", - [MHI_EE_SBL] = "SECONDARY BOOTLOADER", - [MHI_EE_AMSS] = "MISSION MODE", - [MHI_EE_RDDM] = "RAMDUMP DOWNLOAD MODE", - [MHI_EE_WFW] = "WLAN FIRMWARE", - [MHI_EE_PTHRU] = "PASS THROUGH", - [MHI_EE_EDL] = "EMERGENCY DOWNLOAD", - [MHI_EE_FP] = "FLASH PROGRAMMER", - [MHI_EE_DISABLE_TRANSITION] = "DISABLE", - [MHI_EE_NOT_SUPPORTED] = "NOT SUPPORTED", + MHI_EE_LIST }; +#undef dev_st_trans +#undef dev_st_trans_end + +#define dev_st_trans(a, b) [DEV_ST_TRANSITION_##a] = b, +#define dev_st_trans_end(a, b) [DEV_ST_TRANSITION_##a] = b, + const char * const dev_state_tran_str[DEV_ST_TRANSITION_MAX] = { - [DEV_ST_TRANSITION_PBL] = "PBL", - [DEV_ST_TRANSITION_READY] = "READY", - [DEV_ST_TRANSITION_SBL] = "SBL", - [DEV_ST_TRANSITION_MISSION_MODE] = "MISSION MODE", - [DEV_ST_TRANSITION_FP] = "FLASH PROGRAMMER", - [DEV_ST_TRANSITION_SYS_ERR] = "SYS ERROR", - [DEV_ST_TRANSITION_DISABLE] = "DISABLE", + DEV_ST_TRANSITION_LIST }; +#undef ch_state_type +#undef ch_state_type_end + +#define ch_state_type(a, b) [MHI_CH_STATE_TYPE_##a] = b, +#define ch_state_type_end(a, b) [MHI_CH_STATE_TYPE_##a] = b, + const char * const mhi_ch_state_type_str[MHI_CH_STATE_TYPE_MAX] = { - [MHI_CH_STATE_TYPE_RESET] = "RESET", - [MHI_CH_STATE_TYPE_STOP] = "STOP", - [MHI_CH_STATE_TYPE_START] = "START", + MHI_CH_STATE_TYPE_LIST }; +#undef mhi_pm_state +#undef mhi_pm_state_end + +#define mhi_pm_state(a, b) [MHI_PM_STATE_##a] = b, +#define mhi_pm_state_end(a, b) [MHI_PM_STATE_##a] = b, + static const char * const mhi_pm_state_str[] = { - [MHI_PM_STATE_DISABLE] = "DISABLE", - [MHI_PM_STATE_POR] = "POWER ON RESET", - [MHI_PM_STATE_M0] = "M0", - [MHI_PM_STATE_M2] = "M2", - [MHI_PM_STATE_M3_ENTER] = "M?->M3", - [MHI_PM_STATE_M3] = "M3", - [MHI_PM_STATE_M3_EXIT] = "M3->M0", - [MHI_PM_STATE_FW_DL_ERR] = "Firmware Download Error", - [MHI_PM_STATE_SYS_ERR_DETECT] = "SYS ERROR Detect", - [MHI_PM_STATE_SYS_ERR_PROCESS] = "SYS ERROR Process", - [MHI_PM_STATE_SHUTDOWN_PROCESS] = "SHUTDOWN Process", - [MHI_PM_STATE_LD_ERR_FATAL_DETECT] = "Linkdown or Error Fatal Detect", + MHI_PM_STATE_LIST }; const char *to_mhi_pm_state_str(u32 state) @@ -97,11 +96,19 @@ static ssize_t oem_pk_hash_show(struct device *dev, { struct mhi_device *mhi_dev = to_mhi_device(dev); struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl; - int i, cnt = 0; + u32 hash_segment[MHI_MAX_OEM_PK_HASH_SEGMENTS]; + int i, cnt = 0, ret; - for (i = 0; i < ARRAY_SIZE(mhi_cntrl->oem_pk_hash); i++) - cnt += sysfs_emit_at(buf, cnt, "OEMPKHASH[%d]: 0x%x\n", - i, mhi_cntrl->oem_pk_hash[i]); + for (i = 0; i < MHI_MAX_OEM_PK_HASH_SEGMENTS; i++) { + ret = mhi_read_reg(mhi_cntrl, mhi_cntrl->bhi, BHI_OEMPKHASH(i), &hash_segment[i]); + if (ret) { + dev_err(dev, "Could not capture OEM PK HASH\n"); + return ret; + } + } + + for (i = 0; i < MHI_MAX_OEM_PK_HASH_SEGMENTS; i++) + cnt += sysfs_emit_at(buf, cnt, "OEMPKHASH[%d]: 0x%x\n", i, hash_segment[i]); return cnt; } @@ -907,7 +914,6 @@ int mhi_register_controller(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan; struct mhi_cmd *mhi_cmd; struct mhi_device *mhi_dev; - u32 soc_info; int ret, i; if (!mhi_cntrl || !mhi_cntrl->cntrl_dev || !mhi_cntrl->regs || @@ -982,17 +988,6 @@ int mhi_register_controller(struct mhi_controller *mhi_cntrl, mhi_cntrl->unmap_single = mhi_unmap_single_no_bb; } - /* Read the MHI device info */ - ret = mhi_read_reg(mhi_cntrl, mhi_cntrl->regs, - SOC_HW_VERSION_OFFS, &soc_info); - if (ret) - goto err_destroy_wq; - - mhi_cntrl->family_number = FIELD_GET(SOC_HW_VERSION_FAM_NUM_BMSK, soc_info); - mhi_cntrl->device_number = FIELD_GET(SOC_HW_VERSION_DEV_NUM_BMSK, soc_info); - mhi_cntrl->major_version = FIELD_GET(SOC_HW_VERSION_MAJOR_VER_BMSK, soc_info); - mhi_cntrl->minor_version = FIELD_GET(SOC_HW_VERSION_MINOR_VER_BMSK, soc_info); - mhi_cntrl->index = ida_alloc(&mhi_controller_ida, GFP_KERNEL); if (mhi_cntrl->index < 0) { ret = mhi_cntrl->index; diff --git a/drivers/bus/mhi/host/internal.h b/drivers/bus/mhi/host/internal.h index 30ac415a3000..5fe49311b8eb 100644 --- a/drivers/bus/mhi/host/internal.h +++ b/drivers/bus/mhi/host/internal.h @@ -15,12 +15,6 @@ extern struct bus_type mhi_bus_type; #define MHI_SOC_RESET_REQ_OFFSET 0xb0 #define MHI_SOC_RESET_REQ BIT(0) -#define SOC_HW_VERSION_OFFS 0x224 -#define SOC_HW_VERSION_FAM_NUM_BMSK GENMASK(31, 28) -#define SOC_HW_VERSION_DEV_NUM_BMSK GENMASK(27, 16) -#define SOC_HW_VERSION_MAJOR_VER_BMSK GENMASK(15, 8) -#define SOC_HW_VERSION_MINOR_VER_BMSK GENMASK(7, 0) - struct mhi_ctxt { struct mhi_event_ctxt *er_ctxt; struct mhi_chan_ctxt *chan_ctxt; @@ -42,6 +36,11 @@ enum mhi_ch_state_type { MHI_CH_STATE_TYPE_MAX, }; +#define MHI_CH_STATE_TYPE_LIST \ + ch_state_type(RESET, "RESET") \ + ch_state_type(STOP, "STOP") \ + ch_state_type_end(START, "START") + extern const char * const mhi_ch_state_type_str[MHI_CH_STATE_TYPE_MAX]; #define TO_CH_STATE_TYPE_STR(state) (((state) >= MHI_CH_STATE_TYPE_MAX) ? \ "INVALID_STATE" : \ @@ -50,6 +49,18 @@ extern const char * const mhi_ch_state_type_str[MHI_CH_STATE_TYPE_MAX]; #define MHI_INVALID_BRSTMODE(mode) (mode != MHI_DB_BRST_DISABLE && \ mode != MHI_DB_BRST_ENABLE) +#define MHI_EE_LIST \ + mhi_ee(PBL, "PRIMARY BOOTLOADER") \ + mhi_ee(SBL, "SECONDARY BOOTLOADER") \ + mhi_ee(AMSS, "MISSION MODE") \ + mhi_ee(RDDM, "RAMDUMP DOWNLOAD MODE")\ + mhi_ee(WFW, "WLAN FIRMWARE") \ + mhi_ee(PTHRU, "PASS THROUGH") \ + mhi_ee(EDL, "EMERGENCY DOWNLOAD") \ + mhi_ee(FP, "FLASH PROGRAMMER") \ + mhi_ee(DISABLE_TRANSITION, "DISABLE") \ + mhi_ee_end(NOT_SUPPORTED, "NOT SUPPORTED") + extern const char * const mhi_ee_str[MHI_EE_MAX]; #define TO_MHI_EXEC_STR(ee) (((ee) >= MHI_EE_MAX) ? \ "INVALID_EE" : mhi_ee_str[ee]) @@ -72,6 +83,15 @@ enum dev_st_transition { DEV_ST_TRANSITION_MAX, }; +#define DEV_ST_TRANSITION_LIST \ + dev_st_trans(PBL, "PBL") \ + dev_st_trans(READY, "READY") \ + dev_st_trans(SBL, "SBL") \ + dev_st_trans(MISSION_MODE, "MISSION MODE") \ + dev_st_trans(FP, "FLASH PROGRAMMER") \ + dev_st_trans(SYS_ERR, "SYS ERROR") \ + dev_st_trans_end(DISABLE, "DISABLE") + extern const char * const dev_state_tran_str[DEV_ST_TRANSITION_MAX]; #define TO_DEV_STATE_TRANS_STR(state) (((state) >= DEV_ST_TRANSITION_MAX) ? \ "INVALID_STATE" : dev_state_tran_str[state]) @@ -88,11 +108,27 @@ enum mhi_pm_state { MHI_PM_STATE_FW_DL_ERR, MHI_PM_STATE_SYS_ERR_DETECT, MHI_PM_STATE_SYS_ERR_PROCESS, + MHI_PM_STATE_SYS_ERR_FAIL, MHI_PM_STATE_SHUTDOWN_PROCESS, MHI_PM_STATE_LD_ERR_FATAL_DETECT, MHI_PM_STATE_MAX }; +#define MHI_PM_STATE_LIST \ + mhi_pm_state(DISABLE, "DISABLE") \ + mhi_pm_state(POR, "POWER ON RESET") \ + mhi_pm_state(M0, "M0") \ + mhi_pm_state(M2, "M2") \ + mhi_pm_state(M3_ENTER, "M?->M3") \ + mhi_pm_state(M3, "M3") \ + mhi_pm_state(M3_EXIT, "M3->M0") \ + mhi_pm_state(FW_DL_ERR, "Firmware Download Error") \ + mhi_pm_state(SYS_ERR_DETECT, "SYS ERROR Detect") \ + mhi_pm_state(SYS_ERR_PROCESS, "SYS ERROR Process") \ + mhi_pm_state(SYS_ERR_FAIL, "SYS ERROR Failure") \ + mhi_pm_state(SHUTDOWN_PROCESS, "SHUTDOWN Process") \ + mhi_pm_state_end(LD_ERR_FATAL_DETECT, "Linkdown or Error Fatal Detect") + #define MHI_PM_DISABLE BIT(0) #define MHI_PM_POR BIT(1) #define MHI_PM_M0 BIT(2) @@ -104,14 +140,16 @@ enum mhi_pm_state { #define MHI_PM_FW_DL_ERR BIT(7) #define MHI_PM_SYS_ERR_DETECT BIT(8) #define MHI_PM_SYS_ERR_PROCESS BIT(9) -#define MHI_PM_SHUTDOWN_PROCESS BIT(10) +#define MHI_PM_SYS_ERR_FAIL BIT(10) +#define MHI_PM_SHUTDOWN_PROCESS BIT(11) /* link not accessible */ -#define MHI_PM_LD_ERR_FATAL_DETECT BIT(11) +#define MHI_PM_LD_ERR_FATAL_DETECT BIT(12) #define MHI_REG_ACCESS_VALID(pm_state) ((pm_state & (MHI_PM_POR | MHI_PM_M0 | \ MHI_PM_M2 | MHI_PM_M3_ENTER | MHI_PM_M3_EXIT | \ MHI_PM_SYS_ERR_DETECT | MHI_PM_SYS_ERR_PROCESS | \ - MHI_PM_SHUTDOWN_PROCESS | MHI_PM_FW_DL_ERR))) + MHI_PM_SYS_ERR_FAIL | MHI_PM_SHUTDOWN_PROCESS | \ + MHI_PM_FW_DL_ERR))) #define MHI_PM_IN_ERROR_STATE(pm_state) (pm_state >= MHI_PM_FW_DL_ERR) #define MHI_PM_IN_FATAL_STATE(pm_state) (pm_state == MHI_PM_LD_ERR_FATAL_DETECT) #define MHI_DB_ACCESS_VALID(mhi_cntrl) (mhi_cntrl->pm_state & mhi_cntrl->db_access) diff --git a/drivers/bus/mhi/host/main.c b/drivers/bus/mhi/host/main.c index abb561db9ae1..15d657af9b5b 100644 --- a/drivers/bus/mhi/host/main.c +++ b/drivers/bus/mhi/host/main.c @@ -15,6 +15,7 @@ #include <linux/skbuff.h> #include <linux/slab.h> #include "internal.h" +#include "trace.h" int __must_check mhi_read_reg(struct mhi_controller *mhi_cntrl, void __iomem *base, u32 offset, u32 *out) @@ -493,11 +494,8 @@ irqreturn_t mhi_intvec_threaded_handler(int irq_number, void *priv) state = mhi_get_mhi_state(mhi_cntrl); ee = mhi_get_exec_env(mhi_cntrl); - dev_dbg(dev, "local ee: %s state: %s device ee: %s state: %s\n", - TO_MHI_EXEC_STR(mhi_cntrl->ee), - mhi_state_str(mhi_cntrl->dev_state), - TO_MHI_EXEC_STR(ee), mhi_state_str(state)); + trace_mhi_intvec_states(mhi_cntrl, ee, state); if (state == MHI_STATE_SYS_ERR) { dev_dbg(dev, "System error detected\n"); pm_state = mhi_tryset_pm_state(mhi_cntrl, @@ -838,6 +836,8 @@ int mhi_process_ctrl_ev_ring(struct mhi_controller *mhi_cntrl, while (dev_rp != local_rp) { enum mhi_pkt_type type = MHI_TRE_GET_EV_TYPE(local_rp); + trace_mhi_ctrl_event(mhi_cntrl, local_rp); + switch (type) { case MHI_PKT_TYPE_BW_REQ_EVENT: { @@ -1003,6 +1003,8 @@ int mhi_process_data_event_ring(struct mhi_controller *mhi_cntrl, while (dev_rp != local_rp && event_quota > 0) { enum mhi_pkt_type type = MHI_TRE_GET_EV_TYPE(local_rp); + trace_mhi_data_event(mhi_cntrl, local_rp); + chan = MHI_TRE_GET_EV_CHID(local_rp); WARN_ON(chan >= mhi_cntrl->max_chan); @@ -1243,6 +1245,7 @@ int mhi_gen_tre(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan, mhi_tre->dword[0] = MHI_TRE_DATA_DWORD0(info->len); mhi_tre->dword[1] = MHI_TRE_DATA_DWORD1(bei, eot, eob, chain); + trace_mhi_gen_tre(mhi_cntrl, mhi_chan, mhi_tre); /* increment WP */ mhi_add_ring_element(mhi_cntrl, tre_ring); mhi_add_ring_element(mhi_cntrl, buf_ring); @@ -1337,9 +1340,7 @@ static int mhi_update_channel_state(struct mhi_controller *mhi_cntrl, enum mhi_cmd_type cmd = MHI_CMD_NOP; int ret; - dev_dbg(dev, "%d: Updating channel state to: %s\n", mhi_chan->chan, - TO_CH_STATE_TYPE_STR(to_state)); - + trace_mhi_channel_command_start(mhi_cntrl, mhi_chan, to_state, TPS("Updating")); switch (to_state) { case MHI_CH_STATE_TYPE_RESET: write_lock_irq(&mhi_chan->lock); @@ -1406,9 +1407,7 @@ static int mhi_update_channel_state(struct mhi_controller *mhi_cntrl, write_unlock_irq(&mhi_chan->lock); } - dev_dbg(dev, "%d: Channel state change to %s successful\n", - mhi_chan->chan, TO_CH_STATE_TYPE_STR(to_state)); - + trace_mhi_channel_command_end(mhi_cntrl, mhi_chan, to_state, TPS("Updated")); exit_channel_update: mhi_cntrl->runtime_put(mhi_cntrl); mhi_device_put(mhi_cntrl->mhi_dev); diff --git a/drivers/bus/mhi/host/pci_generic.c b/drivers/bus/mhi/host/pci_generic.c index cd6cd14b3d29..51639bfcfec7 100644 --- a/drivers/bus/mhi/host/pci_generic.c +++ b/drivers/bus/mhi/host/pci_generic.c @@ -538,7 +538,7 @@ static struct mhi_event_config mhi_telit_fn980_hw_v1_events[] = { MHI_EVENT_CONFIG_HW_DATA(2, 2048, 101) }; -static struct mhi_controller_config modem_telit_fn980_hw_v1_config = { +static const struct mhi_controller_config modem_telit_fn980_hw_v1_config = { .max_channels = 128, .timeout_ms = 20000, .num_channels = ARRAY_SIZE(mhi_telit_fn980_hw_v1_channels), diff --git a/drivers/bus/mhi/host/pm.c b/drivers/bus/mhi/host/pm.c index a2f2feef1476..8b40d3f01acc 100644 --- a/drivers/bus/mhi/host/pm.c +++ b/drivers/bus/mhi/host/pm.c @@ -15,6 +15,7 @@ #include <linux/slab.h> #include <linux/wait.h> #include "internal.h" +#include "trace.h" /* * Not all MHI state transitions are synchronous. Transitions like Linkdown, @@ -36,7 +37,10 @@ * M0 <--> M0 * M0 -> FW_DL_ERR * M0 -> M3_ENTER -> M3 -> M3_EXIT --> M0 - * L1: SYS_ERR_DETECT -> SYS_ERR_PROCESS --> POR + * L1: SYS_ERR_DETECT -> SYS_ERR_PROCESS + * SYS_ERR_PROCESS -> SYS_ERR_FAIL + * SYS_ERR_FAIL -> SYS_ERR_DETECT + * SYS_ERR_PROCESS --> POR * L2: SHUTDOWN_PROCESS -> LD_ERR_FATAL_DETECT * SHUTDOWN_PROCESS -> DISABLE * L3: LD_ERR_FATAL_DETECT <--> LD_ERR_FATAL_DETECT @@ -93,7 +97,12 @@ static const struct mhi_pm_transitions dev_state_transitions[] = { }, { MHI_PM_SYS_ERR_PROCESS, - MHI_PM_POR | MHI_PM_SHUTDOWN_PROCESS | + MHI_PM_POR | MHI_PM_SYS_ERR_FAIL | MHI_PM_SHUTDOWN_PROCESS | + MHI_PM_LD_ERR_FATAL_DETECT + }, + { + MHI_PM_SYS_ERR_FAIL, + MHI_PM_SYS_ERR_DETECT | MHI_PM_SHUTDOWN_PROCESS | MHI_PM_LD_ERR_FATAL_DETECT }, /* L2 States */ @@ -123,6 +132,7 @@ enum mhi_pm_state __must_check mhi_tryset_pm_state(struct mhi_controller *mhi_cn if (unlikely(!(dev_state_transitions[index].to_states & state))) return cur_state; + trace_mhi_tryset_pm_state(mhi_cntrl, state); mhi_cntrl->pm_state = state; return mhi_cntrl->pm_state; } @@ -629,7 +639,13 @@ static void mhi_pm_sys_error_transition(struct mhi_controller *mhi_cntrl) !in_reset, timeout); if (!ret || in_reset) { dev_err(dev, "Device failed to exit MHI Reset state\n"); - goto exit_sys_error_transition; + write_lock_irq(&mhi_cntrl->pm_lock); + cur_state = mhi_tryset_pm_state(mhi_cntrl, + MHI_PM_SYS_ERR_FAIL); + write_unlock_irq(&mhi_cntrl->pm_lock); + /* Shutdown may have occurred, otherwise cleanup now */ + if (cur_state != MHI_PM_SYS_ERR_FAIL) + goto exit_sys_error_transition; } /* @@ -758,7 +774,6 @@ void mhi_pm_st_worker(struct work_struct *work) struct mhi_controller *mhi_cntrl = container_of(work, struct mhi_controller, st_worker); - struct device *dev = &mhi_cntrl->mhi_dev->dev; spin_lock_irq(&mhi_cntrl->transition_lock); list_splice_tail_init(&mhi_cntrl->transition_list, &head); @@ -766,8 +781,8 @@ void mhi_pm_st_worker(struct work_struct *work) list_for_each_entry_safe(itr, tmp, &head, node) { list_del(&itr->node); - dev_dbg(dev, "Handling state transition: %s\n", - TO_DEV_STATE_TRANS_STR(itr->state)); + + trace_mhi_pm_st_transition(mhi_cntrl, itr->state); switch (itr->state) { case DEV_ST_TRANSITION_PBL: diff --git a/drivers/bus/mhi/host/trace.h b/drivers/bus/mhi/host/trace.h new file mode 100644 index 000000000000..368515dcb22d --- /dev/null +++ b/drivers/bus/mhi/host/trace.h @@ -0,0 +1,282 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM mhi_host + +#if !defined(_TRACE_EVENT_MHI_HOST_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_EVENT_MHI_HOST_H + +#include <linux/tracepoint.h> +#include <linux/trace_seq.h> +#include "../common.h" +#include "internal.h" + +#undef mhi_state +#undef mhi_state_end + +#define mhi_state(a, b) TRACE_DEFINE_ENUM(MHI_STATE_##a); +#define mhi_state_end(a, b) TRACE_DEFINE_ENUM(MHI_STATE_##a); + +MHI_STATE_LIST + +#undef mhi_state +#undef mhi_state_end + +#define mhi_state(a, b) { MHI_STATE_##a, b }, +#define mhi_state_end(a, b) { MHI_STATE_##a, b } + +#undef mhi_pm_state +#undef mhi_pm_state_end + +#define mhi_pm_state(a, b) TRACE_DEFINE_ENUM(MHI_PM_STATE_##a); +#define mhi_pm_state_end(a, b) TRACE_DEFINE_ENUM(MHI_PM_STATE_##a); + +MHI_PM_STATE_LIST + +#undef mhi_pm_state +#undef mhi_pm_state_end + +#define mhi_pm_state(a, b) { MHI_PM_STATE_##a, b }, +#define mhi_pm_state_end(a, b) { MHI_PM_STATE_##a, b } + +#undef mhi_ee +#undef mhi_ee_end + +#define mhi_ee(a, b) TRACE_DEFINE_ENUM(MHI_EE_##a); +#define mhi_ee_end(a, b) TRACE_DEFINE_ENUM(MHI_EE_##a); + +MHI_EE_LIST + +#undef mhi_ee +#undef mhi_ee_end + +#define mhi_ee(a, b) { MHI_EE_##a, b }, +#define mhi_ee_end(a, b) { MHI_EE_##a, b } + +#undef ch_state_type +#undef ch_state_type_end + +#define ch_state_type(a, b) TRACE_DEFINE_ENUM(MHI_CH_STATE_TYPE_##a); +#define ch_state_type_end(a, b) TRACE_DEFINE_ENUM(MHI_CH_STATE_TYPE_##a); + +MHI_CH_STATE_TYPE_LIST + +#undef ch_state_type +#undef ch_state_type_end + +#define ch_state_type(a, b) { MHI_CH_STATE_TYPE_##a, b }, +#define ch_state_type_end(a, b) { MHI_CH_STATE_TYPE_##a, b } + +#undef dev_st_trans +#undef dev_st_trans_end + +#define dev_st_trans(a, b) TRACE_DEFINE_ENUM(DEV_ST_TRANSITION_##a); +#define dev_st_trans_end(a, b) TRACE_DEFINE_ENUM(DEV_ST_TRANSITION_##a); + +DEV_ST_TRANSITION_LIST + +#undef dev_st_trans +#undef dev_st_trans_end + +#define dev_st_trans(a, b) { DEV_ST_TRANSITION_##a, b }, +#define dev_st_trans_end(a, b) { DEV_ST_TRANSITION_##a, b } + +#define TPS(x) tracepoint_string(x) + +TRACE_EVENT(mhi_gen_tre, + + TP_PROTO(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan, + struct mhi_ring_element *mhi_tre), + + TP_ARGS(mhi_cntrl, mhi_chan, mhi_tre), + + TP_STRUCT__entry( + __string(name, mhi_cntrl->mhi_dev->name) + __field(int, ch_num) + __field(void *, wp) + __field(__le64, tre_ptr) + __field(__le32, dword0) + __field(__le32, dword1) + ), + + TP_fast_assign( + __assign_str(name, mhi_cntrl->mhi_dev->name); + __entry->ch_num = mhi_chan->chan; + __entry->wp = mhi_tre; + __entry->tre_ptr = mhi_tre->ptr; + __entry->dword0 = mhi_tre->dword[0]; + __entry->dword1 = mhi_tre->dword[1]; + ), + + TP_printk("%s: Chan: %d TRE: 0x%p TRE buf: 0x%llx DWORD0: 0x%08x DWORD1: 0x%08x\n", + __get_str(name), __entry->ch_num, __entry->wp, __entry->tre_ptr, + __entry->dword0, __entry->dword1) +); + +TRACE_EVENT(mhi_intvec_states, + + TP_PROTO(struct mhi_controller *mhi_cntrl, int dev_ee, int dev_state), + + TP_ARGS(mhi_cntrl, dev_ee, dev_state), + + TP_STRUCT__entry( + __string(name, mhi_cntrl->mhi_dev->name) + __field(int, local_ee) + __field(int, state) + __field(int, dev_ee) + __field(int, dev_state) + ), + + TP_fast_assign( + __assign_str(name, mhi_cntrl->mhi_dev->name); + __entry->local_ee = mhi_cntrl->ee; + __entry->state = mhi_cntrl->dev_state; + __entry->dev_ee = dev_ee; + __entry->dev_state = dev_state; + ), + + TP_printk("%s: Local EE: %s State: %s Device EE: %s Dev State: %s\n", + __get_str(name), + __print_symbolic(__entry->local_ee, MHI_EE_LIST), + __print_symbolic(__entry->state, MHI_STATE_LIST), + __print_symbolic(__entry->dev_ee, MHI_EE_LIST), + __print_symbolic(__entry->dev_state, MHI_STATE_LIST)) +); + +TRACE_EVENT(mhi_tryset_pm_state, + + TP_PROTO(struct mhi_controller *mhi_cntrl, int pm_state), + + TP_ARGS(mhi_cntrl, pm_state), + + TP_STRUCT__entry( + __string(name, mhi_cntrl->mhi_dev->name) + __field(int, pm_state) + ), + + TP_fast_assign( + __assign_str(name, mhi_cntrl->mhi_dev->name); + if (pm_state) + pm_state = __fls(pm_state); + __entry->pm_state = pm_state; + ), + + TP_printk("%s: PM state: %s\n", __get_str(name), + __print_symbolic(__entry->pm_state, MHI_PM_STATE_LIST)) +); + +DECLARE_EVENT_CLASS(mhi_process_event_ring, + + TP_PROTO(struct mhi_controller *mhi_cntrl, struct mhi_ring_element *rp), + + TP_ARGS(mhi_cntrl, rp), + + TP_STRUCT__entry( + __string(name, mhi_cntrl->mhi_dev->name) + __field(__le32, dword0) + __field(__le32, dword1) + __field(int, state) + __field(__le64, ptr) + __field(void *, rp) + ), + + TP_fast_assign( + __assign_str(name, mhi_cntrl->mhi_dev->name); + __entry->rp = rp; + __entry->ptr = rp->ptr; + __entry->dword0 = rp->dword[0]; + __entry->dword1 = rp->dword[1]; + __entry->state = MHI_TRE_GET_EV_STATE(rp); + ), + + TP_printk("%s: TRE: 0x%p TRE buf: 0x%llx DWORD0: 0x%08x DWORD1: 0x%08x State: %s\n", + __get_str(name), __entry->rp, __entry->ptr, __entry->dword0, + __entry->dword1, __print_symbolic(__entry->state, MHI_STATE_LIST)) +); + +DEFINE_EVENT(mhi_process_event_ring, mhi_data_event, + + TP_PROTO(struct mhi_controller *mhi_cntrl, struct mhi_ring_element *rp), + + TP_ARGS(mhi_cntrl, rp) +); + +DEFINE_EVENT(mhi_process_event_ring, mhi_ctrl_event, + + TP_PROTO(struct mhi_controller *mhi_cntrl, struct mhi_ring_element *rp), + + TP_ARGS(mhi_cntrl, rp) +); + +DECLARE_EVENT_CLASS(mhi_update_channel_state, + + TP_PROTO(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan, int state, + const char *reason), + + TP_ARGS(mhi_cntrl, mhi_chan, state, reason), + + TP_STRUCT__entry( + __string(name, mhi_cntrl->mhi_dev->name) + __field(int, ch_num) + __field(int, state) + __field(const char *, reason) + ), + + TP_fast_assign( + __assign_str(name, mhi_cntrl->mhi_dev->name); + __entry->ch_num = mhi_chan->chan; + __entry->state = state; + __entry->reason = reason; + ), + + TP_printk("%s: chan%d: %s state to: %s\n", + __get_str(name), __entry->ch_num, __entry->reason, + __print_symbolic(__entry->state, MHI_CH_STATE_TYPE_LIST)) +); + +DEFINE_EVENT(mhi_update_channel_state, mhi_channel_command_start, + + TP_PROTO(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan, int state, + const char *reason), + + TP_ARGS(mhi_cntrl, mhi_chan, state, reason) +); + +DEFINE_EVENT(mhi_update_channel_state, mhi_channel_command_end, + + TP_PROTO(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan, int state, + const char *reason), + + TP_ARGS(mhi_cntrl, mhi_chan, state, reason) +); + +TRACE_EVENT(mhi_pm_st_transition, + + TP_PROTO(struct mhi_controller *mhi_cntrl, int state), + + TP_ARGS(mhi_cntrl, state), + + TP_STRUCT__entry( + __string(name, mhi_cntrl->mhi_dev->name) + __field(int, state) + ), + + TP_fast_assign( + __assign_str(name, mhi_cntrl->mhi_dev->name); + __entry->state = state; + ), + + TP_printk("%s: Handling state transition: %s\n", __get_str(name), + __print_symbolic(__entry->state, DEV_ST_TRANSITION_LIST)) +); + +#endif +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH ../../drivers/bus/mhi/host +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_FILE trace + +#include <trace/define_trace.h> diff --git a/drivers/comedi/drivers/das08.c b/drivers/comedi/drivers/das08.c index 5d5b9174f88a..49944ce1f813 100644 --- a/drivers/comedi/drivers/das08.c +++ b/drivers/comedi/drivers/das08.c @@ -177,7 +177,6 @@ static int das08_ai_insn_read(struct comedi_device *dev, int ret; chan = CR_CHAN(insn->chanspec); - range = CR_RANGE(insn->chanspec); /* clear crap */ inb(dev->iobase + DAS08_AI_LSB_REG); diff --git a/drivers/connector/cn_proc.c b/drivers/connector/cn_proc.c index 3d5e6d705fc6..44b19e696176 100644 --- a/drivers/connector/cn_proc.c +++ b/drivers/connector/cn_proc.c @@ -108,9 +108,8 @@ static inline void send_msg(struct cn_msg *msg) filter_data[1] = 0; } - if (cn_netlink_send_mult(msg, msg->len, 0, CN_IDX_PROC, GFP_NOWAIT, - cn_filter, (void *)filter_data) == -ESRCH) - atomic_set(&proc_event_num_listeners, 0); + cn_netlink_send_mult(msg, msg->len, 0, CN_IDX_PROC, GFP_NOWAIT, + cn_filter, (void *)filter_data); local_unlock(&local_event.lock); } diff --git a/drivers/dpll/dpll_netlink.c b/drivers/dpll/dpll_netlink.c index 314bb3775465..4ca9ad16cd95 100644 --- a/drivers/dpll/dpll_netlink.c +++ b/drivers/dpll/dpll_netlink.c @@ -1199,6 +1199,7 @@ int dpll_nl_pin_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb) unsigned long i; int ret = 0; + mutex_lock(&dpll_lock); xa_for_each_marked_start(&dpll_pin_xa, i, pin, DPLL_REGISTERED, ctx->idx) { if (!dpll_pin_available(pin)) @@ -1218,6 +1219,8 @@ int dpll_nl_pin_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb) } genlmsg_end(skb, hdr); } + mutex_unlock(&dpll_lock); + if (ret == -EMSGSIZE) { ctx->idx = i; return skb->len; @@ -1373,6 +1376,7 @@ int dpll_nl_device_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb) unsigned long i; int ret = 0; + mutex_lock(&dpll_lock); xa_for_each_marked_start(&dpll_device_xa, i, dpll, DPLL_REGISTERED, ctx->idx) { hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, @@ -1389,6 +1393,8 @@ int dpll_nl_device_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb) } genlmsg_end(skb, hdr); } + mutex_unlock(&dpll_lock); + if (ret == -EMSGSIZE) { ctx->idx = i; return skb->len; @@ -1439,20 +1445,6 @@ dpll_unlock_doit(const struct genl_split_ops *ops, struct sk_buff *skb, mutex_unlock(&dpll_lock); } -int dpll_lock_dumpit(struct netlink_callback *cb) -{ - mutex_lock(&dpll_lock); - - return 0; -} - -int dpll_unlock_dumpit(struct netlink_callback *cb) -{ - mutex_unlock(&dpll_lock); - - return 0; -} - int dpll_pin_pre_doit(const struct genl_split_ops *ops, struct sk_buff *skb, struct genl_info *info) { diff --git a/drivers/dpll/dpll_nl.c b/drivers/dpll/dpll_nl.c index eaee5be7aa64..1e95f5397cfc 100644 --- a/drivers/dpll/dpll_nl.c +++ b/drivers/dpll/dpll_nl.c @@ -95,9 +95,7 @@ static const struct genl_split_ops dpll_nl_ops[] = { }, { .cmd = DPLL_CMD_DEVICE_GET, - .start = dpll_lock_dumpit, .dumpit = dpll_nl_device_get_dumpit, - .done = dpll_unlock_dumpit, .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DUMP, }, { @@ -129,9 +127,7 @@ static const struct genl_split_ops dpll_nl_ops[] = { }, { .cmd = DPLL_CMD_PIN_GET, - .start = dpll_lock_dumpit, .dumpit = dpll_nl_pin_get_dumpit, - .done = dpll_unlock_dumpit, .policy = dpll_pin_get_dump_nl_policy, .maxattr = DPLL_A_PIN_ID, .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DUMP, diff --git a/drivers/dpll/dpll_nl.h b/drivers/dpll/dpll_nl.h index 92d4c9c4f788..f491262bee4f 100644 --- a/drivers/dpll/dpll_nl.h +++ b/drivers/dpll/dpll_nl.h @@ -30,8 +30,6 @@ dpll_post_doit(const struct genl_split_ops *ops, struct sk_buff *skb, void dpll_pin_post_doit(const struct genl_split_ops *ops, struct sk_buff *skb, struct genl_info *info); -int dpll_lock_dumpit(struct netlink_callback *cb); -int dpll_unlock_dumpit(struct netlink_callback *cb); int dpll_nl_device_id_get_doit(struct sk_buff *skb, struct genl_info *info); int dpll_nl_device_get_doit(struct sk_buff *skb, struct genl_info *info); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 6dce81a061ab..79827a6dcd7f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -200,6 +200,7 @@ extern uint amdgpu_dc_debug_mask; extern uint amdgpu_dc_visual_confirm; extern uint amdgpu_dm_abm_level; extern int amdgpu_backlight; +extern int amdgpu_damage_clips; extern struct amdgpu_mgpu_info mgpu_info; extern int amdgpu_ras_enable; extern uint amdgpu_ras_mask; @@ -1549,9 +1550,11 @@ static inline int amdgpu_acpi_smart_shift_update(struct drm_device *dev, #if defined(CONFIG_ACPI) && defined(CONFIG_SUSPEND) bool amdgpu_acpi_is_s3_active(struct amdgpu_device *adev); bool amdgpu_acpi_is_s0ix_active(struct amdgpu_device *adev); +void amdgpu_choose_low_power_state(struct amdgpu_device *adev); #else static inline bool amdgpu_acpi_is_s0ix_active(struct amdgpu_device *adev) { return false; } static inline bool amdgpu_acpi_is_s3_active(struct amdgpu_device *adev) { return false; } +static inline void amdgpu_choose_low_power_state(struct amdgpu_device *adev) { } #endif #if defined(CONFIG_DRM_AMD_DC) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c index 2deebece810e..cc21ed67a330 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c @@ -1519,4 +1519,19 @@ bool amdgpu_acpi_is_s0ix_active(struct amdgpu_device *adev) #endif /* CONFIG_AMD_PMC */ } +/** + * amdgpu_choose_low_power_state + * + * @adev: amdgpu_device_pointer + * + * Choose the target low power state for the GPU + */ +void amdgpu_choose_low_power_state(struct amdgpu_device *adev) +{ + if (amdgpu_acpi_is_s0ix_active(adev)) + adev->in_s0ix = true; + else if (amdgpu_acpi_is_s3_active(adev)) + adev->in_s3 = true; +} + #endif /* CONFIG_SUSPEND */ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index fdde7488d0ed..94bdb5fa6ebc 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -4514,13 +4514,15 @@ int amdgpu_device_prepare(struct drm_device *dev) struct amdgpu_device *adev = drm_to_adev(dev); int i, r; + amdgpu_choose_low_power_state(adev); + if (dev->switch_power_state == DRM_SWITCH_POWER_OFF) return 0; /* Evict the majority of BOs before starting suspend sequence */ r = amdgpu_device_evict_resources(adev); if (r) - return r; + goto unprepare; for (i = 0; i < adev->num_ip_blocks; i++) { if (!adev->ip_blocks[i].status.valid) @@ -4529,10 +4531,15 @@ int amdgpu_device_prepare(struct drm_device *dev) continue; r = adev->ip_blocks[i].version->funcs->prepare_suspend((void *)adev); if (r) - return r; + goto unprepare; } return 0; + +unprepare: + adev->in_s0ix = adev->in_s3 = false; + + return r; } /** @@ -4569,7 +4576,6 @@ int amdgpu_device_suspend(struct drm_device *dev, bool fbcon) drm_fb_helper_set_suspend_unlocked(adev_to_drm(adev)->fb_helper, true); cancel_delayed_work_sync(&adev->delayed_init_work); - flush_delayed_work(&adev->gfx.gfx_off_delay_work); amdgpu_ras_suspend(adev); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c index 211501ea9169..586f4d03039d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c @@ -211,6 +211,7 @@ int amdgpu_seamless = -1; /* auto */ uint amdgpu_debug_mask; int amdgpu_agp = -1; /* auto */ int amdgpu_wbrf = -1; +int amdgpu_damage_clips = -1; /* auto */ static void amdgpu_drv_delayed_reset_work_handler(struct work_struct *work); @@ -860,6 +861,18 @@ MODULE_PARM_DESC(backlight, "Backlight control (0 = pwm, 1 = aux, -1 auto (defau module_param_named(backlight, amdgpu_backlight, bint, 0444); /** + * DOC: damageclips (int) + * Enable or disable damage clips support. If damage clips support is disabled, + * we will force full frame updates, irrespective of what user space sends to + * us. + * + * Defaults to -1 (where it is enabled unless a PSR-SU display is detected). + */ +MODULE_PARM_DESC(damageclips, + "Damage clips support (0 = disable, 1 = enable, -1 auto (default))"); +module_param_named(damageclips, amdgpu_damage_clips, int, 0444); + +/** * DOC: tmz (int) * Trusted Memory Zone (TMZ) is a method to protect data being written * to or read from memory. diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c index b9674c57c436..6ddc8e3360e2 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c @@ -723,8 +723,15 @@ void amdgpu_gfx_off_ctrl(struct amdgpu_device *adev, bool enable) if (adev->gfx.gfx_off_req_count == 0 && !adev->gfx.gfx_off_state) { - schedule_delayed_work(&adev->gfx.gfx_off_delay_work, + /* If going to s2idle, no need to wait */ + if (adev->in_s0ix) { + if (!amdgpu_dpm_set_powergating_by_smu(adev, + AMD_IP_BLOCK_TYPE_GFX, true)) + adev->gfx.gfx_off_state = true; + } else { + schedule_delayed_work(&adev->gfx.gfx_off_delay_work, delay); + } } } else { if (adev->gfx.gfx_off_req_count == 0) { diff --git a/drivers/gpu/drm/amd/amdgpu/soc21.c b/drivers/gpu/drm/amd/amdgpu/soc21.c index 48c6efcdeac9..4d7188912edf 100644 --- a/drivers/gpu/drm/amd/amdgpu/soc21.c +++ b/drivers/gpu/drm/amd/amdgpu/soc21.c @@ -50,13 +50,13 @@ static const struct amd_ip_funcs soc21_common_ip_funcs; /* SOC21 */ static const struct amdgpu_video_codec_info vcn_4_0_0_video_codecs_encode_array_vcn0[] = { {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4_AVC, 4096, 2304, 0)}, - {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_HEVC, 4096, 2304, 0)}, + {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_HEVC, 8192, 4352, 0)}, {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_AV1, 8192, 4352, 0)}, }; static const struct amdgpu_video_codec_info vcn_4_0_0_video_codecs_encode_array_vcn1[] = { {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4_AVC, 4096, 2304, 0)}, - {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_HEVC, 4096, 2304, 0)}, + {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_HEVC, 8192, 4352, 0)}, }; static const struct amdgpu_video_codecs vcn_4_0_0_video_codecs_encode_vcn0 = { diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c index d722cbd31783..826bc4f6c8a7 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c @@ -55,8 +55,8 @@ static void update_cu_mask(struct mqd_manager *mm, void *mqd, m = get_mqd(mqd); if (has_wa_flag) { - uint32_t wa_mask = minfo->update_flag == UPDATE_FLAG_DBG_WA_ENABLE ? - 0xffff : 0xffffffff; + uint32_t wa_mask = + (minfo->update_flag & UPDATE_FLAG_DBG_WA_ENABLE) ? 0xffff : 0xffffffff; m->compute_static_thread_mgmt_se0 = wa_mask; m->compute_static_thread_mgmt_se1 = wa_mask; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c index 42d881809dc7..697b6d530d12 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c @@ -303,6 +303,15 @@ static void update_mqd(struct mqd_manager *mm, void *mqd, update_cu_mask(mm, mqd, minfo, 0); set_priority(m, q); + if (minfo && KFD_GC_VERSION(mm->dev) >= IP_VERSION(9, 4, 2)) { + if (minfo->update_flag & UPDATE_FLAG_IS_GWS) + m->compute_resource_limits |= + COMPUTE_RESOURCE_LIMITS__FORCE_SIMD_DIST_MASK; + else + m->compute_resource_limits &= + ~COMPUTE_RESOURCE_LIMITS__FORCE_SIMD_DIST_MASK; + } + q->is_active = QUEUE_IS_ACTIVE(*q); } diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h index 677281c0793e..80320b8603fc 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h @@ -532,6 +532,7 @@ struct queue_properties { enum mqd_update_flag { UPDATE_FLAG_DBG_WA_ENABLE = 1, UPDATE_FLAG_DBG_WA_DISABLE = 2, + UPDATE_FLAG_IS_GWS = 4, /* quirk for gfx9 IP */ }; struct mqd_update_info { 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 43eff221eae5..4858112f9a53 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c @@ -95,6 +95,7 @@ void kfd_process_dequeue_from_device(struct kfd_process_device *pdd) int pqm_set_gws(struct process_queue_manager *pqm, unsigned int qid, void *gws) { + struct mqd_update_info minfo = {0}; struct kfd_node *dev = NULL; struct process_queue_node *pqn; struct kfd_process_device *pdd; @@ -146,9 +147,10 @@ int pqm_set_gws(struct process_queue_manager *pqm, unsigned int qid, } pdd->qpd.num_gws = gws ? dev->adev->gds.gws_size : 0; + minfo.update_flag = gws ? UPDATE_FLAG_IS_GWS : 0; return pqn->q->device->dqm->ops.update_queue(pqn->q->device->dqm, - pqn->q, NULL); + pqn->q, &minfo); } void kfd_process_dequeue_from_all_devices(struct kfd_process *p) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c index e5f7c92eebcb..6ed2ec381aaa 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c @@ -1638,12 +1638,10 @@ static int fill_in_l2_l3_pcache(struct kfd_cache_properties **props_ext, else mode = UNKNOWN_MEMORY_PARTITION_MODE; - if (pcache->cache_level == 2) - pcache->cache_size = pcache_info[cache_type].cache_size * num_xcc; - else if (mode) - pcache->cache_size = pcache_info[cache_type].cache_size / mode; - else - pcache->cache_size = pcache_info[cache_type].cache_size; + pcache->cache_size = pcache_info[cache_type].cache_size; + /* Partition mode only affects L3 cache size */ + if (mode && pcache->cache_level == 3) + pcache->cache_size /= mode; if (pcache_info[cache_type].flags & CRAT_CACHE_FLAGS_DATA_CACHE) pcache->cache_type |= HSA_CACHE_TYPE_DATA; 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 59d2eee72a32..cf875751971f 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -1956,7 +1956,7 @@ static void amdgpu_dm_fini(struct amdgpu_device *adev) &adev->dm.dmub_bo_gpu_addr, &adev->dm.dmub_bo_cpu_addr); - if (adev->dm.hpd_rx_offload_wq) { + if (adev->dm.hpd_rx_offload_wq && adev->dm.dc) { for (i = 0; i < adev->dm.dc->caps.max_links; i++) { if (adev->dm.hpd_rx_offload_wq[i].wq) { destroy_workqueue(adev->dm.hpd_rx_offload_wq[i].wq); @@ -5219,6 +5219,7 @@ static void fill_dc_dirty_rects(struct drm_plane *plane, struct drm_plane_state *new_plane_state, struct drm_crtc_state *crtc_state, struct dc_flip_addrs *flip_addrs, + bool is_psr_su, bool *dirty_regions_changed) { struct dm_crtc_state *dm_crtc_state = to_dm_crtc_state(crtc_state); @@ -5243,6 +5244,10 @@ static void fill_dc_dirty_rects(struct drm_plane *plane, num_clips = drm_plane_get_damage_clips_count(new_plane_state); clips = drm_plane_get_damage_clips(new_plane_state); + if (num_clips && (!amdgpu_damage_clips || (amdgpu_damage_clips < 0 && + is_psr_su))) + goto ffu; + if (!dm_crtc_state->mpo_requested) { if (!num_clips || num_clips > DC_MAX_DIRTY_RECTS) goto ffu; @@ -6194,7 +6199,9 @@ create_stream_for_sink(struct drm_connector *connector, if (recalculate_timing) { freesync_mode = get_highest_refresh_rate_mode(aconnector, false); drm_mode_copy(&saved_mode, &mode); + saved_mode.picture_aspect_ratio = mode.picture_aspect_ratio; drm_mode_copy(&mode, freesync_mode); + mode.picture_aspect_ratio = saved_mode.picture_aspect_ratio; } else { decide_crtc_timing_for_drm_display_mode( &mode, preferred_mode, scale); @@ -8298,6 +8305,8 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, fill_dc_dirty_rects(plane, old_plane_state, new_plane_state, new_crtc_state, &bundle->flip_addrs[planes_count], + acrtc_state->stream->link->psr_settings.psr_version == + DC_PSR_VERSION_SU_1, &dirty_rects_changed); /* 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 f2dfa96f9ef5..39530b2ea495 100644 --- a/drivers/gpu/drm/amd/display/dc/basics/dce_calcs.c +++ b/drivers/gpu/drm/amd/display/dc/basics/dce_calcs.c @@ -94,7 +94,7 @@ static void calculate_bandwidth( const uint32_t s_high = 7; const uint32_t dmif_chunk_buff_margin = 1; - uint32_t max_chunks_fbc_mode; + uint32_t max_chunks_fbc_mode = 0; int32_t num_cursor_lines; int32_t i, j, k; diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c index 960c4b4f6ddf..05f392501c0a 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c +++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c @@ -1850,19 +1850,21 @@ static enum bp_result get_firmware_info_v3_2( /* Vega12 */ smu_info_v3_2 = GET_IMAGE(struct atom_smu_info_v3_2, DATA_TABLES(smu_info)); - DC_LOG_BIOS("gpuclk_ss_percentage (unit of 0.001 percent): %d\n", smu_info_v3_2->gpuclk_ss_percentage); if (!smu_info_v3_2) return BP_RESULT_BADBIOSTABLE; + DC_LOG_BIOS("gpuclk_ss_percentage (unit of 0.001 percent): %d\n", smu_info_v3_2->gpuclk_ss_percentage); + info->default_engine_clk = smu_info_v3_2->bootup_dcefclk_10khz * 10; } else if (revision.minor == 3) { /* Vega20 */ smu_info_v3_3 = GET_IMAGE(struct atom_smu_info_v3_3, DATA_TABLES(smu_info)); - DC_LOG_BIOS("gpuclk_ss_percentage (unit of 0.001 percent): %d\n", smu_info_v3_3->gpuclk_ss_percentage); if (!smu_info_v3_3) return BP_RESULT_BADBIOSTABLE; + DC_LOG_BIOS("gpuclk_ss_percentage (unit of 0.001 percent): %d\n", smu_info_v3_3->gpuclk_ss_percentage); + info->default_engine_clk = smu_info_v3_3->bootup_dcefclk_10khz * 10; } @@ -2422,10 +2424,11 @@ static enum bp_result get_integrated_info_v11( info_v11 = GET_IMAGE(struct atom_integrated_system_info_v1_11, DATA_TABLES(integratedsysteminfo)); - DC_LOG_BIOS("gpuclk_ss_percentage (unit of 0.001 percent): %d\n", info_v11->gpuclk_ss_percentage); if (info_v11 == NULL) return BP_RESULT_BADBIOSTABLE; + DC_LOG_BIOS("gpuclk_ss_percentage (unit of 0.001 percent): %d\n", info_v11->gpuclk_ss_percentage); + info->gpu_cap_info = le32_to_cpu(info_v11->gpucapinfo); /* @@ -2637,11 +2640,12 @@ static enum bp_result get_integrated_info_v2_1( info_v2_1 = GET_IMAGE(struct atom_integrated_system_info_v2_1, DATA_TABLES(integratedsysteminfo)); - DC_LOG_BIOS("gpuclk_ss_percentage (unit of 0.001 percent): %d\n", info_v2_1->gpuclk_ss_percentage); if (info_v2_1 == NULL) return BP_RESULT_BADBIOSTABLE; + DC_LOG_BIOS("gpuclk_ss_percentage (unit of 0.001 percent): %d\n", info_v2_1->gpuclk_ss_percentage); + info->gpu_cap_info = le32_to_cpu(info_v2_1->gpucapinfo); /* @@ -2799,11 +2803,11 @@ static enum bp_result get_integrated_info_v2_2( info_v2_2 = GET_IMAGE(struct atom_integrated_system_info_v2_2, DATA_TABLES(integratedsysteminfo)); - DC_LOG_BIOS("gpuclk_ss_percentage (unit of 0.001 percent): %d\n", info_v2_2->gpuclk_ss_percentage); - if (info_v2_2 == NULL) return BP_RESULT_BADBIOSTABLE; + DC_LOG_BIOS("gpuclk_ss_percentage (unit of 0.001 percent): %d\n", info_v2_2->gpuclk_ss_percentage); + info->gpu_cap_info = le32_to_cpu(info_v2_2->gpucapinfo); /* diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn301/vg_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn301/vg_clk_mgr.c index a5489fe6875f..aa9fd1dc550a 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn301/vg_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn301/vg_clk_mgr.c @@ -546,6 +546,8 @@ static unsigned int find_dcfclk_for_voltage(const struct vg_dpm_clocks *clock_ta int i; for (i = 0; i < VG_NUM_SOC_VOLTAGE_LEVELS; i++) { + if (i >= VG_NUM_DCFCLK_DPM_LEVELS) + break; if (clock_table->SocVoltage[i] == voltage) return clock_table->DcfClocks[i]; } diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c index 14cec1c7b718..e64890259235 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c @@ -655,10 +655,13 @@ static void dcn35_clk_mgr_helper_populate_bw_params(struct clk_mgr_internal *clk struct clk_limit_table_entry def_max = bw_params->clk_table.entries[bw_params->clk_table.num_entries - 1]; uint32_t max_fclk = 0, min_pstate = 0, max_dispclk = 0, max_dppclk = 0; uint32_t max_pstate = 0, max_dram_speed_mts = 0, min_dram_speed_mts = 0; + uint32_t num_memps, num_fclk, num_dcfclk; int i; /* Determine min/max p-state values. */ - for (i = 0; i < clock_table->NumMemPstatesEnabled; i++) { + num_memps = (clock_table->NumMemPstatesEnabled > NUM_MEM_PSTATE_LEVELS) ? NUM_MEM_PSTATE_LEVELS : + clock_table->NumMemPstatesEnabled; + for (i = 0; i < num_memps; i++) { uint32_t dram_speed_mts = calc_dram_speed_mts(&clock_table->MemPstateTable[i]); if (is_valid_clock_value(dram_speed_mts) && dram_speed_mts > max_dram_speed_mts) { @@ -670,7 +673,7 @@ static void dcn35_clk_mgr_helper_populate_bw_params(struct clk_mgr_internal *clk min_dram_speed_mts = max_dram_speed_mts; min_pstate = max_pstate; - for (i = 0; i < clock_table->NumMemPstatesEnabled; i++) { + for (i = 0; i < num_memps; i++) { uint32_t dram_speed_mts = calc_dram_speed_mts(&clock_table->MemPstateTable[i]); if (is_valid_clock_value(dram_speed_mts) && dram_speed_mts < min_dram_speed_mts) { @@ -699,9 +702,13 @@ static void dcn35_clk_mgr_helper_populate_bw_params(struct clk_mgr_internal *clk /* Base the clock table on dcfclk, need at least one entry regardless of pmfw table */ ASSERT(clock_table->NumDcfClkLevelsEnabled > 0); - max_fclk = find_max_clk_value(clock_table->FclkClocks_Freq, clock_table->NumFclkLevelsEnabled); + num_fclk = (clock_table->NumFclkLevelsEnabled > NUM_FCLK_DPM_LEVELS) ? NUM_FCLK_DPM_LEVELS : + clock_table->NumFclkLevelsEnabled; + max_fclk = find_max_clk_value(clock_table->FclkClocks_Freq, num_fclk); - for (i = 0; i < clock_table->NumDcfClkLevelsEnabled; i++) { + num_dcfclk = (clock_table->NumFclkLevelsEnabled > NUM_DCFCLK_DPM_LEVELS) ? NUM_DCFCLK_DPM_LEVELS : + clock_table->NumDcfClkLevelsEnabled; + for (i = 0; i < num_dcfclk; i++) { int j; /* First search defaults for the clocks we don't read using closest lower or equal default dcfclk */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dpp_cm.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dpp_cm.c index e43f77c11c00..5f97a868ada3 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dpp_cm.c +++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dpp_cm.c @@ -56,16 +56,13 @@ static void dpp3_enable_cm_block( static enum dc_lut_mode dpp30_get_gamcor_current(struct dpp *dpp_base) { - enum dc_lut_mode mode; + enum dc_lut_mode mode = LUT_BYPASS; uint32_t state_mode; uint32_t lut_mode; struct dcn3_dpp *dpp = TO_DCN30_DPP(dpp_base); REG_GET(CM_GAMCOR_CONTROL, CM_GAMCOR_MODE_CURRENT, &state_mode); - if (state_mode == 0) - mode = LUT_BYPASS; - if (state_mode == 2) {//Programmable RAM LUT REG_GET(CM_GAMCOR_CONTROL, CM_GAMCOR_SELECT_CURRENT, &lut_mode); if (lut_mode == 0) diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c index ba76dd4a2ce2..a0a65e099104 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c @@ -2760,7 +2760,7 @@ static int build_synthetic_soc_states(bool disable_dc_mode_overwrite, struct clk struct _vcs_dpi_voltage_scaling_st entry = {0}; struct clk_limit_table_entry max_clk_data = {0}; - unsigned int min_dcfclk_mhz = 399, min_fclk_mhz = 599; + unsigned int min_dcfclk_mhz = 199, min_fclk_mhz = 299; static const unsigned int num_dcfclk_stas = 5; unsigned int dcfclk_sta_targets[DC__VOLTAGE_STATES] = {199, 615, 906, 1324, 1564}; diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn21/dcn21_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn21/dcn21_hwseq.c index 5c7f380a84f9..7252f5f781f0 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn21/dcn21_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn21/dcn21_hwseq.c @@ -211,7 +211,7 @@ void dcn21_set_pipe(struct pipe_ctx *pipe_ctx) struct dmcu *dmcu = pipe_ctx->stream->ctx->dc->res_pool->dmcu; uint32_t otg_inst; - if (!abm && !tg && !panel_cntl) + if (!abm || !tg || !panel_cntl) return; otg_inst = tg->inst; @@ -245,7 +245,7 @@ bool dcn21_set_backlight_level(struct pipe_ctx *pipe_ctx, struct panel_cntl *panel_cntl = pipe_ctx->stream->link->panel_cntl; uint32_t otg_inst; - if (!abm && !tg && !panel_cntl) + if (!abm || !tg || !panel_cntl) return false; otg_inst = tg->inst; diff --git a/drivers/gpu/drm/amd/display/dc/link/link_validation.c b/drivers/gpu/drm/amd/display/dc/link/link_validation.c index 8fe66c367850..5b0bc7f6a188 100644 --- a/drivers/gpu/drm/amd/display/dc/link/link_validation.c +++ b/drivers/gpu/drm/amd/display/dc/link/link_validation.c @@ -361,7 +361,7 @@ bool link_validate_dpia_bandwidth(const struct dc_stream_state *stream, const un struct dc_link *dpia_link[MAX_DPIA_NUM] = {0}; int num_dpias = 0; - for (uint8_t i = 0; i < num_streams; ++i) { + for (unsigned int i = 0; i < num_streams; ++i) { if (stream[i].signal == SIGNAL_TYPE_DISPLAY_PORT) { /* new dpia sst stream, check whether it exceeds max dpia */ if (num_dpias >= MAX_DPIA_NUM) diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training.c index 5a0b04518956..16a62e018712 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training.c +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training.c @@ -517,6 +517,7 @@ enum link_training_result dp_check_link_loss_status( { enum link_training_result status = LINK_TRAINING_SUCCESS; union lane_status lane_status; + union lane_align_status_updated dpcd_lane_status_updated; uint8_t dpcd_buf[6] = {0}; uint32_t lane; @@ -532,10 +533,12 @@ enum link_training_result dp_check_link_loss_status( * check lanes status */ lane_status.raw = dp_get_nibble_at_index(&dpcd_buf[2], lane); + dpcd_lane_status_updated.raw = dpcd_buf[4]; if (!lane_status.bits.CHANNEL_EQ_DONE_0 || !lane_status.bits.CR_DONE_0 || - !lane_status.bits.SYMBOL_LOCKED_0) { + !lane_status.bits.SYMBOL_LOCKED_0 || + !dp_is_interlane_aligned(dpcd_lane_status_updated)) { /* if one of the channel equalization, clock * recovery or symbol lock is dropped * consider it as (link has been diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_dpia.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_dpia.c index e8dda44b23cb..5d36bab0029c 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_dpia.c +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_dpia.c @@ -619,7 +619,7 @@ static enum link_training_result dpia_training_eq_non_transparent( uint32_t retries_eq = 0; enum dc_status status; enum dc_dp_training_pattern tr_pattern; - uint32_t wait_time_microsec; + uint32_t wait_time_microsec = 0; enum dc_lane_count lane_count = lt_settings->link_settings.lane_count; union lane_align_status_updated dpcd_lane_status_updated = {0}; union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0}; diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c index 1c3d89264ef7..5fdcda8f8602 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c @@ -780,7 +780,7 @@ static const struct dc_debug_options debug_defaults_drv = { .disable_z10 = false, .ignore_pg = true, .psp_disabled_wa = true, - .ips2_eval_delay_us = 1650, + .ips2_eval_delay_us = 2000, .ips2_entry_delay_us = 800, .static_screen_wait_frames = 2, }; diff --git a/drivers/gpu/drm/drm_buddy.c b/drivers/gpu/drm/drm_buddy.c index f57e6d74fb0e..c1a99bf4dffd 100644 --- a/drivers/gpu/drm/drm_buddy.c +++ b/drivers/gpu/drm/drm_buddy.c @@ -539,6 +539,12 @@ static int __alloc_range(struct drm_buddy *mm, } while (1); list_splice_tail(&allocated, blocks); + + if (total_allocated < size) { + err = -ENOSPC; + goto err_free; + } + return 0; err_undo: diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index cb90e70d85e8..65f9f66933bb 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -904,6 +904,7 @@ out: connector_set = NULL; fb = NULL; mode = NULL; + num_connectors = 0; DRM_MODESET_LOCK_ALL_END(dev, ctx, ret); diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c index 834a5e28abbe..7352bde299d5 100644 --- a/drivers/gpu/drm/drm_prime.c +++ b/drivers/gpu/drm/drm_prime.c @@ -820,7 +820,7 @@ struct sg_table *drm_prime_pages_to_sg(struct drm_device *dev, if (max_segment == 0) max_segment = UINT_MAX; err = sg_alloc_table_from_pages_segment(sg, pages, nr_pages, 0, - nr_pages << PAGE_SHIFT, + (unsigned long)nr_pages << PAGE_SHIFT, max_segment, GFP_KERNEL); if (err) { kfree(sg); diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index f5ef95da5534..ae647d03af25 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -2355,6 +2355,9 @@ intel_dp_compute_config_limits(struct intel_dp *intel_dp, limits->min_rate = intel_dp_common_rate(intel_dp, 0); limits->max_rate = intel_dp_max_link_rate(intel_dp); + /* FIXME 128b/132b SST support missing */ + limits->max_rate = min(limits->max_rate, 810000); + limits->min_lane_count = 1; limits->max_lane_count = intel_dp_max_lane_count(intel_dp); diff --git a/drivers/gpu/drm/i915/display/intel_vdsc_regs.h b/drivers/gpu/drm/i915/display/intel_vdsc_regs.h index 64f440fdc22b..8b21dc8e26d5 100644 --- a/drivers/gpu/drm/i915/display/intel_vdsc_regs.h +++ b/drivers/gpu/drm/i915/display/intel_vdsc_regs.h @@ -51,8 +51,8 @@ #define DSCC_PICTURE_PARAMETER_SET_0 _MMIO(0x6BA00) #define _DSCA_PPS_0 0x6B200 #define _DSCC_PPS_0 0x6BA00 -#define DSCA_PPS(pps) _MMIO(_DSCA_PPS_0 + (pps) * 4) -#define DSCC_PPS(pps) _MMIO(_DSCC_PPS_0 + (pps) * 4) +#define DSCA_PPS(pps) _MMIO(_DSCA_PPS_0 + ((pps) < 12 ? (pps) : (pps) + 12) * 4) +#define DSCC_PPS(pps) _MMIO(_DSCC_PPS_0 + ((pps) < 12 ? (pps) : (pps) + 12) * 4) #define _ICL_DSC0_PICTURE_PARAMETER_SET_0_PB 0x78270 #define _ICL_DSC1_PICTURE_PARAMETER_SET_0_PB 0x78370 #define _ICL_DSC0_PICTURE_PARAMETER_SET_0_PC 0x78470 diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c index c0bc924cd302..c9c55e2ea584 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c @@ -1287,7 +1287,7 @@ static void a6xx_calc_ubwc_config(struct adreno_gpu *gpu) gpu->ubwc_config.highest_bank_bit = 15; if (adreno_is_a610(gpu)) { - gpu->ubwc_config.highest_bank_bit = 14; + gpu->ubwc_config.highest_bank_bit = 13; gpu->ubwc_config.min_acc_len = 1; gpu->ubwc_config.ubwc_mode = 1; } diff --git a/drivers/gpu/drm/msm/msm_gem_prime.c b/drivers/gpu/drm/msm/msm_gem_prime.c index 5f68e31a3e4e..0915f3b68752 100644 --- a/drivers/gpu/drm/msm/msm_gem_prime.c +++ b/drivers/gpu/drm/msm/msm_gem_prime.c @@ -26,7 +26,7 @@ int msm_gem_prime_vmap(struct drm_gem_object *obj, struct iosys_map *map) { void *vaddr; - vaddr = msm_gem_get_vaddr(obj); + vaddr = msm_gem_get_vaddr_locked(obj); if (IS_ERR(vaddr)) return PTR_ERR(vaddr); iosys_map_set_vaddr(map, vaddr); @@ -36,7 +36,7 @@ int msm_gem_prime_vmap(struct drm_gem_object *obj, struct iosys_map *map) void msm_gem_prime_vunmap(struct drm_gem_object *obj, struct iosys_map *map) { - msm_gem_put_vaddr(obj); + msm_gem_put_vaddr_locked(obj); } struct drm_gem_object *msm_gem_prime_import_sg_table(struct drm_device *dev, diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c index 095390774f22..655002b21b0d 100644 --- a/drivers/gpu/drm/msm/msm_gpu.c +++ b/drivers/gpu/drm/msm/msm_gpu.c @@ -751,12 +751,14 @@ void msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit) struct msm_ringbuffer *ring = submit->ring; unsigned long flags; - pm_runtime_get_sync(&gpu->pdev->dev); + WARN_ON(!mutex_is_locked(&gpu->lock)); - mutex_lock(&gpu->lock); + pm_runtime_get_sync(&gpu->pdev->dev); msm_gpu_hw_init(gpu); + submit->seqno = submit->hw_fence->seqno; + update_sw_cntrs(gpu); /* @@ -781,11 +783,8 @@ void msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit) gpu->funcs->submit(gpu, submit); gpu->cur_ctx_seqno = submit->queue->ctx->seqno; - hangcheck_timer_reset(gpu); - - mutex_unlock(&gpu->lock); - pm_runtime_put(&gpu->pdev->dev); + hangcheck_timer_reset(gpu); } /* diff --git a/drivers/gpu/drm/msm/msm_iommu.c b/drivers/gpu/drm/msm/msm_iommu.c index 5cc8d358cc97..d5512037c38b 100644 --- a/drivers/gpu/drm/msm/msm_iommu.c +++ b/drivers/gpu/drm/msm/msm_iommu.c @@ -21,6 +21,8 @@ struct msm_iommu_pagetable { struct msm_mmu base; struct msm_mmu *parent; struct io_pgtable_ops *pgtbl_ops; + const struct iommu_flush_ops *tlb; + struct device *iommu_dev; unsigned long pgsize_bitmap; /* Bitmap of page sizes in use */ phys_addr_t ttbr; u32 asid; @@ -201,11 +203,33 @@ static const struct msm_mmu_funcs pagetable_funcs = { static void msm_iommu_tlb_flush_all(void *cookie) { + struct msm_iommu_pagetable *pagetable = cookie; + struct adreno_smmu_priv *adreno_smmu; + + if (!pm_runtime_get_if_in_use(pagetable->iommu_dev)) + return; + + adreno_smmu = dev_get_drvdata(pagetable->parent->dev); + + pagetable->tlb->tlb_flush_all((void *)adreno_smmu->cookie); + + pm_runtime_put_autosuspend(pagetable->iommu_dev); } static void msm_iommu_tlb_flush_walk(unsigned long iova, size_t size, size_t granule, void *cookie) { + struct msm_iommu_pagetable *pagetable = cookie; + struct adreno_smmu_priv *adreno_smmu; + + if (!pm_runtime_get_if_in_use(pagetable->iommu_dev)) + return; + + adreno_smmu = dev_get_drvdata(pagetable->parent->dev); + + pagetable->tlb->tlb_flush_walk(iova, size, granule, (void *)adreno_smmu->cookie); + + pm_runtime_put_autosuspend(pagetable->iommu_dev); } static void msm_iommu_tlb_add_page(struct iommu_iotlb_gather *gather, @@ -213,7 +237,7 @@ static void msm_iommu_tlb_add_page(struct iommu_iotlb_gather *gather, { } -static const struct iommu_flush_ops null_tlb_ops = { +static const struct iommu_flush_ops tlb_ops = { .tlb_flush_all = msm_iommu_tlb_flush_all, .tlb_flush_walk = msm_iommu_tlb_flush_walk, .tlb_add_page = msm_iommu_tlb_add_page, @@ -254,10 +278,10 @@ struct msm_mmu *msm_iommu_pagetable_create(struct msm_mmu *parent) /* The incoming cfg will have the TTBR1 quirk enabled */ ttbr0_cfg.quirks &= ~IO_PGTABLE_QUIRK_ARM_TTBR1; - ttbr0_cfg.tlb = &null_tlb_ops; + ttbr0_cfg.tlb = &tlb_ops; pagetable->pgtbl_ops = alloc_io_pgtable_ops(ARM_64_LPAE_S1, - &ttbr0_cfg, iommu->domain); + &ttbr0_cfg, pagetable); if (!pagetable->pgtbl_ops) { kfree(pagetable); @@ -279,6 +303,8 @@ struct msm_mmu *msm_iommu_pagetable_create(struct msm_mmu *parent) /* Needed later for TLB flush */ pagetable->parent = parent; + pagetable->tlb = ttbr1_cfg->tlb; + pagetable->iommu_dev = ttbr1_cfg->iommu_dev; pagetable->pgsize_bitmap = ttbr0_cfg.pgsize_bitmap; pagetable->ttbr = ttbr0_cfg.arm_lpae_s1_cfg.ttbr; diff --git a/drivers/gpu/drm/msm/msm_ringbuffer.c b/drivers/gpu/drm/msm/msm_ringbuffer.c index 4bc13f7d005a..9d6655f96f0c 100644 --- a/drivers/gpu/drm/msm/msm_ringbuffer.c +++ b/drivers/gpu/drm/msm/msm_ringbuffer.c @@ -21,8 +21,6 @@ static struct dma_fence *msm_job_run(struct drm_sched_job *job) msm_fence_init(submit->hw_fence, fctx); - submit->seqno = submit->hw_fence->seqno; - mutex_lock(&priv->lru.lock); for (i = 0; i < submit->nr_bos; i++) { @@ -35,8 +33,13 @@ static struct dma_fence *msm_job_run(struct drm_sched_job *job) mutex_unlock(&priv->lru.lock); + /* TODO move submit path over to using a per-ring lock.. */ + mutex_lock(&gpu->lock); + msm_gpu_submit(gpu, submit); + mutex_unlock(&gpu->lock); + return dma_fence_get(submit->hw_fence); } diff --git a/drivers/gpu/drm/nouveau/nouveau_abi16.c b/drivers/gpu/drm/nouveau/nouveau_abi16.c index a04156ca8390..d1bb8151a1df 100644 --- a/drivers/gpu/drm/nouveau/nouveau_abi16.c +++ b/drivers/gpu/drm/nouveau/nouveau_abi16.c @@ -128,12 +128,14 @@ nouveau_abi16_chan_fini(struct nouveau_abi16 *abi16, struct nouveau_abi16_ntfy *ntfy, *temp; /* Cancel all jobs from the entity's queue. */ - drm_sched_entity_fini(&chan->sched.entity); + if (chan->sched) + drm_sched_entity_fini(&chan->sched->entity); if (chan->chan) nouveau_channel_idle(chan->chan); - nouveau_sched_fini(&chan->sched); + if (chan->sched) + nouveau_sched_destroy(&chan->sched); /* cleanup notifier state */ list_for_each_entry_safe(ntfy, temp, &chan->notifiers, head) { @@ -337,10 +339,16 @@ nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS) if (ret) goto done; - ret = nouveau_sched_init(&chan->sched, drm, drm->sched_wq, - chan->chan->dma.ib_max); - if (ret) - goto done; + /* If we're not using the VM_BIND uAPI, we don't need a scheduler. + * + * The client lock is already acquired by nouveau_abi16_get(). + */ + if (nouveau_cli_uvmm(cli)) { + ret = nouveau_sched_create(&chan->sched, drm, drm->sched_wq, + chan->chan->dma.ib_max); + if (ret) + goto done; + } init->channel = chan->chan->chid; diff --git a/drivers/gpu/drm/nouveau/nouveau_abi16.h b/drivers/gpu/drm/nouveau/nouveau_abi16.h index 1f5e243c0c75..11c8c4a80079 100644 --- a/drivers/gpu/drm/nouveau/nouveau_abi16.h +++ b/drivers/gpu/drm/nouveau/nouveau_abi16.h @@ -26,7 +26,7 @@ struct nouveau_abi16_chan { struct nouveau_bo *ntfy; struct nouveau_vma *ntfy_vma; struct nvkm_mm heap; - struct nouveau_sched sched; + struct nouveau_sched *sched; }; struct nouveau_abi16 { diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 6f6c31a9937b..a947e1d5f309 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -201,7 +201,8 @@ nouveau_cli_fini(struct nouveau_cli *cli) WARN_ON(!list_empty(&cli->worker)); usif_client_fini(cli); - nouveau_sched_fini(&cli->sched); + if (cli->sched) + nouveau_sched_destroy(&cli->sched); if (uvmm) nouveau_uvmm_fini(uvmm); nouveau_vmm_fini(&cli->svm); @@ -311,7 +312,7 @@ nouveau_cli_init(struct nouveau_drm *drm, const char *sname, cli->mem = &mems[ret]; /* Don't pass in the (shared) sched_wq in order to let - * nouveau_sched_init() create a dedicated one for VM_BIND jobs. + * nouveau_sched_create() create a dedicated one for VM_BIND jobs. * * This is required to ensure that for VM_BIND jobs free_job() work and * run_job() work can always run concurrently and hence, free_job() work @@ -320,7 +321,7 @@ nouveau_cli_init(struct nouveau_drm *drm, const char *sname, * locks which indirectly or directly are held for allocations * elsewhere. */ - ret = nouveau_sched_init(&cli->sched, drm, NULL, 1); + ret = nouveau_sched_create(&cli->sched, drm, NULL, 1); if (ret) goto done; diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 8a6d94c8b163..e239c6bf4afa 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -98,7 +98,7 @@ struct nouveau_cli { bool disabled; } uvmm; - struct nouveau_sched sched; + struct nouveau_sched *sched; const struct nvif_mclass *mem; diff --git a/drivers/gpu/drm/nouveau/nouveau_exec.c b/drivers/gpu/drm/nouveau/nouveau_exec.c index bc5d71b79ab2..e65c0ef23bc7 100644 --- a/drivers/gpu/drm/nouveau/nouveau_exec.c +++ b/drivers/gpu/drm/nouveau/nouveau_exec.c @@ -389,7 +389,7 @@ nouveau_exec_ioctl_exec(struct drm_device *dev, if (ret) goto out; - args.sched = &chan16->sched; + args.sched = chan16->sched; args.file_priv = file_priv; args.chan = chan; diff --git a/drivers/gpu/drm/nouveau/nouveau_sched.c b/drivers/gpu/drm/nouveau/nouveau_sched.c index dd98f6910f9c..32fa2e273965 100644 --- a/drivers/gpu/drm/nouveau/nouveau_sched.c +++ b/drivers/gpu/drm/nouveau/nouveau_sched.c @@ -398,7 +398,7 @@ static const struct drm_sched_backend_ops nouveau_sched_ops = { .free_job = nouveau_sched_free_job, }; -int +static int nouveau_sched_init(struct nouveau_sched *sched, struct nouveau_drm *drm, struct workqueue_struct *wq, u32 credit_limit) { @@ -453,7 +453,30 @@ fail_wq: return ret; } -void +int +nouveau_sched_create(struct nouveau_sched **psched, struct nouveau_drm *drm, + struct workqueue_struct *wq, u32 credit_limit) +{ + struct nouveau_sched *sched; + int ret; + + sched = kzalloc(sizeof(*sched), GFP_KERNEL); + if (!sched) + return -ENOMEM; + + ret = nouveau_sched_init(sched, drm, wq, credit_limit); + if (ret) { + kfree(sched); + return ret; + } + + *psched = sched; + + return 0; +} + + +static void nouveau_sched_fini(struct nouveau_sched *sched) { struct drm_gpu_scheduler *drm_sched = &sched->base; @@ -471,3 +494,14 @@ nouveau_sched_fini(struct nouveau_sched *sched) if (sched->wq) destroy_workqueue(sched->wq); } + +void +nouveau_sched_destroy(struct nouveau_sched **psched) +{ + struct nouveau_sched *sched = *psched; + + nouveau_sched_fini(sched); + kfree(sched); + + *psched = NULL; +} diff --git a/drivers/gpu/drm/nouveau/nouveau_sched.h b/drivers/gpu/drm/nouveau/nouveau_sched.h index a6528f5981e6..e1f01a23e6f6 100644 --- a/drivers/gpu/drm/nouveau/nouveau_sched.h +++ b/drivers/gpu/drm/nouveau/nouveau_sched.h @@ -111,8 +111,8 @@ struct nouveau_sched { } job; }; -int nouveau_sched_init(struct nouveau_sched *sched, struct nouveau_drm *drm, - struct workqueue_struct *wq, u32 credit_limit); -void nouveau_sched_fini(struct nouveau_sched *sched); +int nouveau_sched_create(struct nouveau_sched **psched, struct nouveau_drm *drm, + struct workqueue_struct *wq, u32 credit_limit); +void nouveau_sched_destroy(struct nouveau_sched **psched); #endif diff --git a/drivers/gpu/drm/nouveau/nouveau_svm.c b/drivers/gpu/drm/nouveau/nouveau_svm.c index cc03e0c22ff3..5e4565c5011a 100644 --- a/drivers/gpu/drm/nouveau/nouveau_svm.c +++ b/drivers/gpu/drm/nouveau/nouveau_svm.c @@ -1011,7 +1011,7 @@ nouveau_svm_fault_buffer_ctor(struct nouveau_svm *svm, s32 oclass, int id) if (ret) return ret; - buffer->fault = kvcalloc(sizeof(*buffer->fault), buffer->entries, GFP_KERNEL); + buffer->fault = kvcalloc(buffer->entries, sizeof(*buffer->fault), GFP_KERNEL); if (!buffer->fault) return -ENOMEM; diff --git a/drivers/gpu/drm/nouveau/nouveau_uvmm.c b/drivers/gpu/drm/nouveau/nouveau_uvmm.c index 4f223c972c6a..0a0a11dc9ec0 100644 --- a/drivers/gpu/drm/nouveau/nouveau_uvmm.c +++ b/drivers/gpu/drm/nouveau/nouveau_uvmm.c @@ -1740,7 +1740,7 @@ nouveau_uvmm_ioctl_vm_bind(struct drm_device *dev, if (ret) return ret; - args.sched = &cli->sched; + args.sched = cli->sched; args.file_priv = file_priv; ret = nouveau_uvmm_vm_bind(&args); diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index 85b3b4871a1d..fdd768bbd487 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -1985,8 +1985,10 @@ static void vop2_crtc_atomic_enable(struct drm_crtc *crtc, clock = vop2_set_intf_mux(vp, rkencoder->crtc_endpoint_id, polflags); } - if (!clock) + if (!clock) { + vop2_unlock(vop2); return; + } if (vcstate->output_mode == ROCKCHIP_OUT_MODE_AAAA && !(vp_data->feature & VOP2_VP_FEATURE_OUTPUT_10BIT)) diff --git a/drivers/gpu/drm/tests/drm_buddy_test.c b/drivers/gpu/drm/tests/drm_buddy_test.c index ea2af6bd9abe..fee6bec757d1 100644 --- a/drivers/gpu/drm/tests/drm_buddy_test.c +++ b/drivers/gpu/drm/tests/drm_buddy_test.c @@ -8,6 +8,7 @@ #include <linux/prime_numbers.h> #include <linux/sched/signal.h> +#include <linux/sizes.h> #include <drm/drm_buddy.h> @@ -18,6 +19,93 @@ static inline u64 get_size(int order, u64 chunk_size) return (1 << order) * chunk_size; } +static void drm_test_buddy_alloc_contiguous(struct kunit *test) +{ + u64 mm_size, ps = SZ_4K, i, n_pages, total; + struct drm_buddy_block *block; + struct drm_buddy mm; + LIST_HEAD(left); + LIST_HEAD(middle); + LIST_HEAD(right); + LIST_HEAD(allocated); + + mm_size = 16 * 3 * SZ_4K; + + KUNIT_EXPECT_FALSE(test, drm_buddy_init(&mm, mm_size, ps)); + + /* + * Idea is to fragment the address space by alternating block + * allocations between three different lists; one for left, middle and + * right. We can then free a list to simulate fragmentation. In + * particular we want to exercise the DRM_BUDDY_CONTIGUOUS_ALLOCATION, + * including the try_harder path. + */ + + i = 0; + n_pages = mm_size / ps; + do { + struct list_head *list; + int slot = i % 3; + + if (slot == 0) + list = &left; + else if (slot == 1) + list = &middle; + else + list = &right; + KUNIT_ASSERT_FALSE_MSG(test, + drm_buddy_alloc_blocks(&mm, 0, mm_size, + ps, ps, list, 0), + "buddy_alloc hit an error size=%d\n", + ps); + } while (++i < n_pages); + + KUNIT_ASSERT_TRUE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size, + 3 * ps, ps, &allocated, + DRM_BUDDY_CONTIGUOUS_ALLOCATION), + "buddy_alloc didn't error size=%d\n", 3 * ps); + + drm_buddy_free_list(&mm, &middle); + KUNIT_ASSERT_TRUE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size, + 3 * ps, ps, &allocated, + DRM_BUDDY_CONTIGUOUS_ALLOCATION), + "buddy_alloc didn't error size=%llu\n", 3 * ps); + KUNIT_ASSERT_TRUE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size, + 2 * ps, ps, &allocated, + DRM_BUDDY_CONTIGUOUS_ALLOCATION), + "buddy_alloc didn't error size=%llu\n", 2 * ps); + + drm_buddy_free_list(&mm, &right); + KUNIT_ASSERT_TRUE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size, + 3 * ps, ps, &allocated, + DRM_BUDDY_CONTIGUOUS_ALLOCATION), + "buddy_alloc didn't error size=%llu\n", 3 * ps); + /* + * At this point we should have enough contiguous space for 2 blocks, + * however they are never buddies (since we freed middle and right) so + * will require the try_harder logic to find them. + */ + KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size, + 2 * ps, ps, &allocated, + DRM_BUDDY_CONTIGUOUS_ALLOCATION), + "buddy_alloc hit an error size=%d\n", 2 * ps); + + drm_buddy_free_list(&mm, &left); + KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size, + 3 * ps, ps, &allocated, + DRM_BUDDY_CONTIGUOUS_ALLOCATION), + "buddy_alloc hit an error size=%d\n", 3 * ps); + + total = 0; + list_for_each_entry(block, &allocated, link) + total += drm_buddy_block_size(&mm, block); + + KUNIT_ASSERT_EQ(test, total, ps * 2 + ps * 3); + + drm_buddy_free_list(&mm, &allocated); + drm_buddy_fini(&mm); +} + static void drm_test_buddy_alloc_pathological(struct kunit *test) { u64 mm_size, size, start = 0; @@ -280,6 +368,7 @@ static struct kunit_case drm_buddy_tests[] = { KUNIT_CASE(drm_test_buddy_alloc_optimistic), KUNIT_CASE(drm_test_buddy_alloc_pessimistic), KUNIT_CASE(drm_test_buddy_alloc_pathological), + KUNIT_CASE(drm_test_buddy_alloc_contiguous), {} }; diff --git a/drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_object.h b/drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_object.h index 68d9f6116bdf..777c20ceabab 100644 --- a/drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_object.h +++ b/drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_object.h @@ -10,7 +10,7 @@ #include "xe_bo.h" -#define i915_gem_object_is_shmem(obj) ((obj)->flags & XE_BO_CREATE_SYSTEM_BIT) +#define i915_gem_object_is_shmem(obj) (0) /* We don't use shmem */ static inline dma_addr_t i915_gem_object_get_dma_address(const struct xe_bo *bo, pgoff_t n) { diff --git a/drivers/gpu/drm/xe/xe_pt.c b/drivers/gpu/drm/xe/xe_pt.c index e45b37c3f0c2..ac19bfa3f798 100644 --- a/drivers/gpu/drm/xe/xe_pt.c +++ b/drivers/gpu/drm/xe/xe_pt.c @@ -20,8 +20,8 @@ struct xe_pt_dir { struct xe_pt pt; - /** @dir: Directory structure for the xe_pt_walk functionality */ - struct xe_ptw_dir dir; + /** @children: Array of page-table child nodes */ + struct xe_ptw *children[XE_PDES]; }; #if IS_ENABLED(CONFIG_DRM_XE_DEBUG_VM) @@ -44,7 +44,7 @@ static struct xe_pt_dir *as_xe_pt_dir(struct xe_pt *pt) static struct xe_pt *xe_pt_entry(struct xe_pt_dir *pt_dir, unsigned int index) { - return container_of(pt_dir->dir.entries[index], struct xe_pt, base); + return container_of(pt_dir->children[index], struct xe_pt, base); } static u64 __xe_pt_empty_pte(struct xe_tile *tile, struct xe_vm *vm, @@ -65,6 +65,14 @@ static u64 __xe_pt_empty_pte(struct xe_tile *tile, struct xe_vm *vm, XE_PTE_NULL; } +static void xe_pt_free(struct xe_pt *pt) +{ + if (pt->level) + kfree(as_xe_pt_dir(pt)); + else + kfree(pt); +} + /** * xe_pt_create() - Create a page-table. * @vm: The vm to create for. @@ -85,15 +93,19 @@ struct xe_pt *xe_pt_create(struct xe_vm *vm, struct xe_tile *tile, { struct xe_pt *pt; struct xe_bo *bo; - size_t size; int err; - size = !level ? sizeof(struct xe_pt) : sizeof(struct xe_pt_dir) + - XE_PDES * sizeof(struct xe_ptw *); - pt = kzalloc(size, GFP_KERNEL); + if (level) { + struct xe_pt_dir *dir = kzalloc(sizeof(*dir), GFP_KERNEL); + + pt = (dir) ? &dir->pt : NULL; + } else { + pt = kzalloc(sizeof(*pt), GFP_KERNEL); + } if (!pt) return ERR_PTR(-ENOMEM); + pt->level = level; bo = xe_bo_create_pin_map(vm->xe, tile, vm, SZ_4K, ttm_bo_type_kernel, XE_BO_CREATE_VRAM_IF_DGFX(tile) | @@ -106,8 +118,7 @@ struct xe_pt *xe_pt_create(struct xe_vm *vm, struct xe_tile *tile, goto err_kfree; } pt->bo = bo; - pt->level = level; - pt->base.dir = level ? &as_xe_pt_dir(pt)->dir : NULL; + pt->base.children = level ? as_xe_pt_dir(pt)->children : NULL; if (vm->xef) xe_drm_client_add_bo(vm->xef->client, pt->bo); @@ -116,7 +127,7 @@ struct xe_pt *xe_pt_create(struct xe_vm *vm, struct xe_tile *tile, return pt; err_kfree: - kfree(pt); + xe_pt_free(pt); return ERR_PTR(err); } @@ -193,7 +204,7 @@ void xe_pt_destroy(struct xe_pt *pt, u32 flags, struct llist_head *deferred) deferred); } } - kfree(pt); + xe_pt_free(pt); } /** @@ -358,7 +369,7 @@ xe_pt_insert_entry(struct xe_pt_stage_bind_walk *xe_walk, struct xe_pt *parent, struct iosys_map *map = &parent->bo->vmap; if (unlikely(xe_child)) - parent->base.dir->entries[offset] = &xe_child->base; + parent->base.children[offset] = &xe_child->base; xe_pt_write(xe_walk->vm->xe, map, offset, pte); parent->num_live++; @@ -853,7 +864,7 @@ static void xe_pt_commit_bind(struct xe_vma *vma, xe_pt_destroy(xe_pt_entry(pt_dir, j_), xe_vma_vm(vma)->flags, deferred); - pt_dir->dir.entries[j_] = &newpte->base; + pt_dir->children[j_] = &newpte->base; } kfree(entries[i].pt_entries); } @@ -1507,7 +1518,7 @@ xe_pt_commit_unbind(struct xe_vma *vma, xe_pt_destroy(xe_pt_entry(pt_dir, i), xe_vma_vm(vma)->flags, deferred); - pt_dir->dir.entries[i] = NULL; + pt_dir->children[i] = NULL; } } } diff --git a/drivers/gpu/drm/xe/xe_pt_walk.c b/drivers/gpu/drm/xe/xe_pt_walk.c index 8f6c8d063f39..b8b3d2aea492 100644 --- a/drivers/gpu/drm/xe/xe_pt_walk.c +++ b/drivers/gpu/drm/xe/xe_pt_walk.c @@ -74,7 +74,7 @@ int xe_pt_walk_range(struct xe_ptw *parent, unsigned int level, u64 addr, u64 end, struct xe_pt_walk *walk) { pgoff_t offset = xe_pt_offset(addr, level, walk); - struct xe_ptw **entries = parent->dir ? parent->dir->entries : NULL; + struct xe_ptw **entries = parent->children ? parent->children : NULL; const struct xe_pt_walk_ops *ops = walk->ops; enum page_walk_action action; struct xe_ptw *child; diff --git a/drivers/gpu/drm/xe/xe_pt_walk.h b/drivers/gpu/drm/xe/xe_pt_walk.h index ec3d1e9efa6d..5ecc4d2f0f65 100644 --- a/drivers/gpu/drm/xe/xe_pt_walk.h +++ b/drivers/gpu/drm/xe/xe_pt_walk.h @@ -8,28 +8,15 @@ #include <linux/pagewalk.h> #include <linux/types.h> -struct xe_ptw_dir; - /** * struct xe_ptw - base class for driver pagetable subclassing. - * @dir: Pointer to an array of children if any. + * @children: Pointer to an array of children if any. * * Drivers could subclass this, and if it's a page-directory, typically - * embed the xe_ptw_dir::entries array in the same allocation. + * embed an array of xe_ptw pointers. */ struct xe_ptw { - struct xe_ptw_dir *dir; -}; - -/** - * struct xe_ptw_dir - page directory structure - * @entries: Array holding page directory children. - * - * It is the responsibility of the user to ensure @entries is - * correctly sized. - */ -struct xe_ptw_dir { - struct xe_ptw *entries[0]; + struct xe_ptw **children; }; /** diff --git a/drivers/gpu/drm/xe/xe_range_fence.c b/drivers/gpu/drm/xe/xe_range_fence.c index d35d9ec58e86..372378e89e98 100644 --- a/drivers/gpu/drm/xe/xe_range_fence.c +++ b/drivers/gpu/drm/xe/xe_range_fence.c @@ -151,6 +151,11 @@ xe_range_fence_tree_next(struct xe_range_fence *rfence, u64 start, u64 last) return xe_range_fence_tree_iter_next(rfence, start, last); } +static void xe_range_fence_free(struct xe_range_fence *rfence) +{ + kfree(rfence); +} + const struct xe_range_fence_ops xe_range_fence_kfree_ops = { - .free = (void (*)(struct xe_range_fence *rfence)) kfree, + .free = xe_range_fence_free, }; diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c index 865e10d0a06a..7b00faa67287 100644 --- a/drivers/gpu/drm/xe/xe_vm.c +++ b/drivers/gpu/drm/xe/xe_vm.c @@ -995,9 +995,16 @@ int xe_vm_prepare_vma(struct drm_exec *exec, struct xe_vma *vma, int err; XE_WARN_ON(!vm); - err = drm_exec_prepare_obj(exec, xe_vm_obj(vm), num_shared); - if (!err && bo && !bo->vm) - err = drm_exec_prepare_obj(exec, &bo->ttm.base, num_shared); + if (num_shared) + err = drm_exec_prepare_obj(exec, xe_vm_obj(vm), num_shared); + else + err = drm_exec_lock_obj(exec, xe_vm_obj(vm)); + if (!err && bo && !bo->vm) { + if (num_shared) + err = drm_exec_prepare_obj(exec, &bo->ttm.base, num_shared); + else + err = drm_exec_lock_obj(exec, &bo->ttm.base); + } return err; } diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c index 6ef0c88e3e60..d2f3f234f29d 100644 --- a/drivers/hid/hid-logitech-hidpp.c +++ b/drivers/hid/hid-logitech-hidpp.c @@ -203,6 +203,8 @@ struct hidpp_device { struct hidpp_scroll_counter vertical_wheel_counter; u8 wireless_feature_index; + + bool connected_once; }; /* HID++ 1.0 error codes */ @@ -988,8 +990,13 @@ static int hidpp_root_get_protocol_version(struct hidpp_device *hidpp) hidpp->protocol_minor = response.rap.params[1]; print_version: - hid_info(hidpp->hid_dev, "HID++ %u.%u device connected.\n", - hidpp->protocol_major, hidpp->protocol_minor); + if (!hidpp->connected_once) { + hid_info(hidpp->hid_dev, "HID++ %u.%u device connected.\n", + hidpp->protocol_major, hidpp->protocol_minor); + hidpp->connected_once = true; + } else + hid_dbg(hidpp->hid_dev, "HID++ %u.%u device connected.\n", + hidpp->protocol_major, hidpp->protocol_minor); return 0; } @@ -4184,7 +4191,7 @@ static void hidpp_connect_event(struct work_struct *work) /* Get device version to check if it is connected */ ret = hidpp_root_get_protocol_version(hidpp); if (ret) { - hid_info(hidpp->hid_dev, "Disconnected\n"); + hid_dbg(hidpp->hid_dev, "Disconnected\n"); if (hidpp->battery.ps) { hidpp->battery.online = false; hidpp->battery.status = POWER_SUPPLY_STATUS_UNKNOWN; diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index fd5b0637dad6..3e91e4d6ba6f 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -2153,6 +2153,10 @@ static const struct hid_device_id mt_devices[] = { { .driver_data = MT_CLS_WIN_8_FORCE_MULTI_INPUT, HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8, + USB_VENDOR_ID_SYNAPTICS, 0xcddc) }, + + { .driver_data = MT_CLS_WIN_8_FORCE_MULTI_INPUT, + HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8, USB_VENDOR_ID_SYNAPTICS, 0xce08) }, { .driver_data = MT_CLS_WIN_8_FORCE_MULTI_INPUT, diff --git a/drivers/hid/intel-ish-hid/ishtp/bus.c b/drivers/hid/intel-ish-hid/ishtp/bus.c index aa6cb033bb06..03d5601ce807 100644 --- a/drivers/hid/intel-ish-hid/ishtp/bus.c +++ b/drivers/hid/intel-ish-hid/ishtp/bus.c @@ -722,6 +722,8 @@ void ishtp_bus_remove_all_clients(struct ishtp_device *ishtp_dev, spin_lock_irqsave(&ishtp_dev->cl_list_lock, flags); list_for_each_entry(cl, &ishtp_dev->cl_list, link) { cl->state = ISHTP_CL_DISCONNECTED; + if (warm_reset && cl->device->reference_count) + continue; /* * Wake any pending process. The waiter would check dev->state diff --git a/drivers/hid/intel-ish-hid/ishtp/client.c b/drivers/hid/intel-ish-hid/ishtp/client.c index 82c907f01bd3..8a7f2f6a4f86 100644 --- a/drivers/hid/intel-ish-hid/ishtp/client.c +++ b/drivers/hid/intel-ish-hid/ishtp/client.c @@ -49,7 +49,9 @@ static void ishtp_read_list_flush(struct ishtp_cl *cl) list_for_each_entry_safe(rb, next, &cl->dev->read_list.list, list) if (rb->cl && ishtp_cl_cmp_id(cl, rb->cl)) { list_del(&rb->list); - ishtp_io_rb_free(rb); + spin_lock(&cl->free_list_spinlock); + list_add_tail(&rb->list, &cl->free_rb_list.list); + spin_unlock(&cl->free_list_spinlock); } spin_unlock_irqrestore(&cl->dev->read_list_spinlock, flags); } diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c index b613f11ed949..2bc45b24075c 100644 --- a/drivers/hid/wacom_sys.c +++ b/drivers/hid/wacom_sys.c @@ -2087,7 +2087,7 @@ static int wacom_allocate_inputs(struct wacom *wacom) return 0; } -static int wacom_register_inputs(struct wacom *wacom) +static int wacom_setup_inputs(struct wacom *wacom) { struct input_dev *pen_input_dev, *touch_input_dev, *pad_input_dev; struct wacom_wac *wacom_wac = &(wacom->wacom_wac); @@ -2106,10 +2106,6 @@ static int wacom_register_inputs(struct wacom *wacom) input_free_device(pen_input_dev); wacom_wac->pen_input = NULL; pen_input_dev = NULL; - } else { - error = input_register_device(pen_input_dev); - if (error) - goto fail; } error = wacom_setup_touch_input_capabilities(touch_input_dev, wacom_wac); @@ -2118,10 +2114,6 @@ static int wacom_register_inputs(struct wacom *wacom) input_free_device(touch_input_dev); wacom_wac->touch_input = NULL; touch_input_dev = NULL; - } else { - error = input_register_device(touch_input_dev); - if (error) - goto fail; } error = wacom_setup_pad_input_capabilities(pad_input_dev, wacom_wac); @@ -2130,7 +2122,34 @@ static int wacom_register_inputs(struct wacom *wacom) input_free_device(pad_input_dev); wacom_wac->pad_input = NULL; pad_input_dev = NULL; - } else { + } + + return 0; +} + +static int wacom_register_inputs(struct wacom *wacom) +{ + struct input_dev *pen_input_dev, *touch_input_dev, *pad_input_dev; + struct wacom_wac *wacom_wac = &(wacom->wacom_wac); + int error = 0; + + pen_input_dev = wacom_wac->pen_input; + touch_input_dev = wacom_wac->touch_input; + pad_input_dev = wacom_wac->pad_input; + + if (pen_input_dev) { + error = input_register_device(pen_input_dev); + if (error) + goto fail; + } + + if (touch_input_dev) { + error = input_register_device(touch_input_dev); + if (error) + goto fail; + } + + if (pad_input_dev) { error = input_register_device(pad_input_dev); if (error) goto fail; @@ -2383,6 +2402,20 @@ static int wacom_parse_and_register(struct wacom *wacom, bool wireless) if (error) goto fail; + error = wacom_setup_inputs(wacom); + if (error) + goto fail; + + if (features->type == HID_GENERIC) + connect_mask |= HID_CONNECT_DRIVER; + + /* Regular HID work starts now */ + error = hid_hw_start(hdev, connect_mask); + if (error) { + hid_err(hdev, "hw start failed\n"); + goto fail; + } + error = wacom_register_inputs(wacom); if (error) goto fail; @@ -2397,16 +2430,6 @@ static int wacom_parse_and_register(struct wacom *wacom, bool wireless) goto fail; } - if (features->type == HID_GENERIC) - connect_mask |= HID_CONNECT_DRIVER; - - /* Regular HID work starts now */ - error = hid_hw_start(hdev, connect_mask); - if (error) { - hid_err(hdev, "hw start failed\n"); - goto fail; - } - if (!wireless) { /* Note that if query fails it is not a hard failure */ wacom_query_tablet_data(wacom); diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index da8a01fedd39..fbe10fbc5769 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -2575,7 +2575,14 @@ static void wacom_wac_pen_report(struct hid_device *hdev, wacom_wac->hid_data.tipswitch); input_report_key(input, wacom_wac->tool[0], sense); if (wacom_wac->serial[0]) { - input_event(input, EV_MSC, MSC_SERIAL, wacom_wac->serial[0]); + /* + * xf86-input-wacom does not accept a serial number + * of '0'. Report the low 32 bits if possible, but + * if they are zero, report the upper ones instead. + */ + __u32 serial_lo = wacom_wac->serial[0] & 0xFFFFFFFFu; + __u32 serial_hi = wacom_wac->serial[0] >> 32; + input_event(input, EV_MSC, MSC_SERIAL, (int)(serial_lo ? serial_lo : serial_hi)); input_report_abs(input, ABS_MISC, sense ? id : 0); } diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 3757b9391e60..aa0ee8ecd6f2 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -90,10 +90,8 @@ obj-$(CONFIG_I2C_NPCM) += i2c-npcm7xx.o obj-$(CONFIG_I2C_OCORES) += i2c-ocores.o obj-$(CONFIG_I2C_OMAP) += i2c-omap.o obj-$(CONFIG_I2C_OWL) += i2c-owl.o -i2c-pasemi-objs := i2c-pasemi-core.o i2c-pasemi-pci.o -obj-$(CONFIG_I2C_PASEMI) += i2c-pasemi.o -i2c-apple-objs := i2c-pasemi-core.o i2c-pasemi-platform.o -obj-$(CONFIG_I2C_APPLE) += i2c-apple.o +obj-$(CONFIG_I2C_PASEMI) += i2c-pasemi-core.o i2c-pasemi-pci.o +obj-$(CONFIG_I2C_APPLE) += i2c-pasemi-core.o i2c-pasemi-platform.o obj-$(CONFIG_I2C_PCA_PLATFORM) += i2c-pca-platform.o obj-$(CONFIG_I2C_PNX) += i2c-pnx.o obj-$(CONFIG_I2C_PXA) += i2c-pxa.o diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 3932e8d96a17..2c36b36d7d51 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -498,11 +498,10 @@ static int i801_block_transaction_by_block(struct i801_priv *priv, /* Set block buffer mode */ outb_p(inb_p(SMBAUXCTL(priv)) | SMBAUXCTL_E32B, SMBAUXCTL(priv)); - inb_p(SMBHSTCNT(priv)); /* reset the data buffer index */ - if (read_write == I2C_SMBUS_WRITE) { len = data->block[0]; outb_p(len, SMBHSTDAT0(priv)); + inb_p(SMBHSTCNT(priv)); /* reset the data buffer index */ for (i = 0; i < len; i++) outb_p(data->block[i+1], SMBBLKDAT(priv)); } @@ -520,6 +519,7 @@ static int i801_block_transaction_by_block(struct i801_priv *priv, } data->block[0] = len; + inb_p(SMBHSTCNT(priv)); /* reset the data buffer index */ for (i = 0; i < len; i++) data->block[i + 1] = inb_p(SMBBLKDAT(priv)); } diff --git a/drivers/i2c/busses/i2c-pasemi-core.c b/drivers/i2c/busses/i2c-pasemi-core.c index 7d54a9f34c74..bd8becbdeeb2 100644 --- a/drivers/i2c/busses/i2c-pasemi-core.c +++ b/drivers/i2c/busses/i2c-pasemi-core.c @@ -369,6 +369,7 @@ int pasemi_i2c_common_probe(struct pasemi_smbus *smbus) return 0; } +EXPORT_SYMBOL_GPL(pasemi_i2c_common_probe); irqreturn_t pasemi_irq_handler(int irq, void *dev_id) { @@ -378,3 +379,8 @@ irqreturn_t pasemi_irq_handler(int irq, void *dev_id) complete(&smbus->irq_completion); return IRQ_HANDLED; } +EXPORT_SYMBOL_GPL(pasemi_irq_handler); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Olof Johansson <olof@lixom.net>"); +MODULE_DESCRIPTION("PA Semi PWRficient SMBus driver"); diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c index 0d2e7171e3a6..da94df466e83 100644 --- a/drivers/i2c/busses/i2c-qcom-geni.c +++ b/drivers/i2c/busses/i2c-qcom-geni.c @@ -613,20 +613,20 @@ static int geni_i2c_gpi_xfer(struct geni_i2c_dev *gi2c, struct i2c_msg msgs[], i peripheral.addr = msgs[i].addr; + ret = geni_i2c_gpi(gi2c, &msgs[i], &config, + &tx_addr, &tx_buf, I2C_WRITE, gi2c->tx_c); + if (ret) + goto err; + if (msgs[i].flags & I2C_M_RD) { ret = geni_i2c_gpi(gi2c, &msgs[i], &config, &rx_addr, &rx_buf, I2C_READ, gi2c->rx_c); if (ret) goto err; - } - - ret = geni_i2c_gpi(gi2c, &msgs[i], &config, - &tx_addr, &tx_buf, I2C_WRITE, gi2c->tx_c); - if (ret) - goto err; - if (msgs[i].flags & I2C_M_RD) dma_async_issue_pending(gi2c->rx_c); + } + dma_async_issue_pending(gi2c->tx_c); timeout = wait_for_completion_timeout(&gi2c->done, XFER_TIMEOUT); diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig index 52eb46ef84c1..9c351ffc7bed 100644 --- a/drivers/iio/Kconfig +++ b/drivers/iio/Kconfig @@ -71,6 +71,15 @@ config IIO_TRIGGERED_EVENT help Provides helper functions for setting up triggered events. +config IIO_BACKEND + tristate + help + Framework to handle complex IIO aggregate devices. The typical + architecture that can make use of this framework is to have one + device as the frontend device which can be "linked" against one or + multiple backend devices. The framework then makes it easy to get + and control such backend devices. + source "drivers/iio/accel/Kconfig" source "drivers/iio/adc/Kconfig" source "drivers/iio/addac/Kconfig" diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile index 9622347a1c1b..0ba0e1521ba4 100644 --- a/drivers/iio/Makefile +++ b/drivers/iio/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_IIO_GTS_HELPER) += industrialio-gts-helper.o obj-$(CONFIG_IIO_SW_DEVICE) += industrialio-sw-device.o obj-$(CONFIG_IIO_SW_TRIGGER) += industrialio-sw-trigger.o obj-$(CONFIG_IIO_TRIGGERED_EVENT) += industrialio-triggered-event.o +obj-$(CONFIG_IIO_BACKEND) += industrialio-backend.o obj-y += accel/ obj-y += adc/ diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig index 91adcac875a4..c2da5066e9a7 100644 --- a/drivers/iio/accel/Kconfig +++ b/drivers/iio/accel/Kconfig @@ -219,10 +219,12 @@ config BMA400 config BMA400_I2C tristate + select REGMAP_I2C depends on BMA400 config BMA400_SPI tristate + select REGMAP_SPI depends on BMA400 config BMC150_ACCEL @@ -254,11 +256,11 @@ config BMC150_ACCEL_SPI config BMI088_ACCEL tristate "Bosch BMI088 Accelerometer Driver" - depends on SPI select IIO_BUFFER select IIO_TRIGGERED_BUFFER select REGMAP - select BMI088_ACCEL_SPI + select BMI088_ACCEL_SPI if SPI + select BMI088_ACCEL_I2C if I2C help Say yes here to build support for the following Bosch accelerometers: BMI088, BMI085, BMI090L. Note that all of these are combo module that @@ -267,6 +269,10 @@ config BMI088_ACCEL This driver only implements the accelerometer part, which has its own address and register map. BMG160 provides the gyroscope driver. +config BMI088_ACCEL_I2C + tristate + select REGMAP_I2C + config BMI088_ACCEL_SPI tristate select REGMAP_SPI diff --git a/drivers/iio/accel/Makefile b/drivers/iio/accel/Makefile index 311ead9c3ef1..db90532ba24a 100644 --- a/drivers/iio/accel/Makefile +++ b/drivers/iio/accel/Makefile @@ -30,6 +30,7 @@ obj-$(CONFIG_BMC150_ACCEL) += bmc150-accel-core.o obj-$(CONFIG_BMC150_ACCEL_I2C) += bmc150-accel-i2c.o obj-$(CONFIG_BMC150_ACCEL_SPI) += bmc150-accel-spi.o obj-$(CONFIG_BMI088_ACCEL) += bmi088-accel-core.o +obj-$(CONFIG_BMI088_ACCEL_I2C) += bmi088-accel-i2c.o obj-$(CONFIG_BMI088_ACCEL_SPI) += bmi088-accel-spi.o obj-$(CONFIG_DA280) += da280.o obj-$(CONFIG_DA311) += da311.o diff --git a/drivers/iio/accel/adxl367.c b/drivers/iio/accel/adxl367.c index 90b7ae6d42b7..834ee6d63947 100644 --- a/drivers/iio/accel/adxl367.c +++ b/drivers/iio/accel/adxl367.c @@ -339,22 +339,17 @@ static int adxl367_set_act_threshold(struct adxl367_state *st, { int ret; - mutex_lock(&st->lock); + guard(mutex)(&st->lock); ret = adxl367_set_measure_en(st, false); if (ret) - goto out; + return ret; ret = _adxl367_set_act_threshold(st, act, threshold); if (ret) - goto out; - - ret = adxl367_set_measure_en(st, true); - -out: - mutex_unlock(&st->lock); + return ret; - return ret; + return adxl367_set_measure_en(st, true); } static int adxl367_set_act_proc_mode(struct adxl367_state *st, @@ -482,51 +477,45 @@ static int adxl367_set_fifo_watermark(struct adxl367_state *st, static int adxl367_set_range(struct iio_dev *indio_dev, enum adxl367_range range) { - struct adxl367_state *st = iio_priv(indio_dev); - int ret; + iio_device_claim_direct_scoped(return -EBUSY, indio_dev) { + struct adxl367_state *st = iio_priv(indio_dev); + int ret; - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; - - mutex_lock(&st->lock); - - ret = adxl367_set_measure_en(st, false); - if (ret) - goto out; + guard(mutex)(&st->lock); - ret = regmap_update_bits(st->regmap, ADXL367_REG_FILTER_CTL, - ADXL367_FILTER_CTL_RANGE_MASK, - FIELD_PREP(ADXL367_FILTER_CTL_RANGE_MASK, - range)); - if (ret) - goto out; + ret = adxl367_set_measure_en(st, false); + if (ret) + return ret; - adxl367_scale_act_thresholds(st, st->range, range); + ret = regmap_update_bits(st->regmap, ADXL367_REG_FILTER_CTL, + ADXL367_FILTER_CTL_RANGE_MASK, + FIELD_PREP(ADXL367_FILTER_CTL_RANGE_MASK, + range)); + if (ret) + return ret; - /* Activity thresholds depend on range */ - ret = _adxl367_set_act_threshold(st, ADXL367_ACTIVITY, - st->act_threshold); - if (ret) - goto out; + adxl367_scale_act_thresholds(st, st->range, range); - ret = _adxl367_set_act_threshold(st, ADXL367_INACTIVITY, - st->inact_threshold); - if (ret) - goto out; - - ret = adxl367_set_measure_en(st, true); - if (ret) - goto out; + /* Activity thresholds depend on range */ + ret = _adxl367_set_act_threshold(st, ADXL367_ACTIVITY, + st->act_threshold); + if (ret) + return ret; - st->range = range; + ret = _adxl367_set_act_threshold(st, ADXL367_INACTIVITY, + st->inact_threshold); + if (ret) + return ret; -out: - mutex_unlock(&st->lock); + ret = adxl367_set_measure_en(st, true); + if (ret) + return ret; - iio_device_release_direct_mode(indio_dev); + st->range = range; - return ret; + return 0; + } + unreachable(); } static int adxl367_time_ms_to_samples(struct adxl367_state *st, unsigned int ms) @@ -587,11 +576,11 @@ static int adxl367_set_act_time_ms(struct adxl367_state *st, { int ret; - mutex_lock(&st->lock); + guard(mutex)(&st->lock); ret = adxl367_set_measure_en(st, false); if (ret) - goto out; + return ret; if (act == ADXL367_ACTIVITY) ret = _adxl367_set_act_time_ms(st, ms); @@ -599,14 +588,9 @@ static int adxl367_set_act_time_ms(struct adxl367_state *st, ret = _adxl367_set_inact_time_ms(st, ms); if (ret) - goto out; - - ret = adxl367_set_measure_en(st, true); - -out: - mutex_unlock(&st->lock); + return ret; - return ret; + return adxl367_set_measure_en(st, true); } static int _adxl367_set_odr(struct adxl367_state *st, enum adxl367_odr odr) @@ -636,31 +620,23 @@ static int _adxl367_set_odr(struct adxl367_state *st, enum adxl367_odr odr) static int adxl367_set_odr(struct iio_dev *indio_dev, enum adxl367_odr odr) { - struct adxl367_state *st = iio_priv(indio_dev); - int ret; + iio_device_claim_direct_scoped(return -EBUSY, indio_dev) { + struct adxl367_state *st = iio_priv(indio_dev);; + int ret; - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; + guard(mutex)(&st->lock); - mutex_lock(&st->lock); - - ret = adxl367_set_measure_en(st, false); - if (ret) - goto out; - - ret = _adxl367_set_odr(st, odr); - if (ret) - goto out; - - ret = adxl367_set_measure_en(st, true); - -out: - mutex_unlock(&st->lock); + ret = adxl367_set_measure_en(st, false); + if (ret) + return ret; - iio_device_release_direct_mode(indio_dev); + ret = _adxl367_set_odr(st, odr); + if (ret) + return ret; - return ret; + return adxl367_set_measure_en(st, true); + } + unreachable(); } static int adxl367_set_temp_adc_en(struct adxl367_state *st, unsigned int reg, @@ -749,36 +725,32 @@ static int adxl367_read_sample(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val) { - struct adxl367_state *st = iio_priv(indio_dev); - u16 sample; - int ret; + iio_device_claim_direct_scoped(return -EBUSY, indio_dev) { + struct adxl367_state *st = iio_priv(indio_dev); + u16 sample; + int ret; - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; + guard(mutex)(&st->lock); - mutex_lock(&st->lock); - - ret = adxl367_set_temp_adc_reg_en(st, chan->address, true); - if (ret) - goto out; - - ret = regmap_bulk_read(st->regmap, chan->address, &st->sample_buf, - sizeof(st->sample_buf)); - if (ret) - goto out; - - sample = FIELD_GET(ADXL367_DATA_MASK, be16_to_cpu(st->sample_buf)); - *val = sign_extend32(sample, chan->scan_type.realbits - 1); + ret = adxl367_set_temp_adc_reg_en(st, chan->address, true); + if (ret) + return ret; - ret = adxl367_set_temp_adc_reg_en(st, chan->address, false); + ret = regmap_bulk_read(st->regmap, chan->address, &st->sample_buf, + sizeof(st->sample_buf)); + if (ret) + return ret; -out: - mutex_unlock(&st->lock); + sample = FIELD_GET(ADXL367_DATA_MASK, be16_to_cpu(st->sample_buf)); + *val = sign_extend32(sample, chan->scan_type.realbits - 1); - iio_device_release_direct_mode(indio_dev); + ret = adxl367_set_temp_adc_reg_en(st, chan->address, false); + if (ret) + return ret; - return ret ?: IIO_VAL_INT; + return IIO_VAL_INT; + } + unreachable(); } static int adxl367_get_status(struct adxl367_state *st, u8 *status, @@ -886,12 +858,12 @@ static int adxl367_read_raw(struct iio_dev *indio_dev, return adxl367_read_sample(indio_dev, chan, val); case IIO_CHAN_INFO_SCALE: switch (chan->type) { - case IIO_ACCEL: - mutex_lock(&st->lock); + case IIO_ACCEL: { + guard(mutex)(&st->lock); *val = adxl367_range_scale_tbl[st->range][0]; *val2 = adxl367_range_scale_tbl[st->range][1]; - mutex_unlock(&st->lock); return IIO_VAL_INT_PLUS_NANO; + } case IIO_TEMP: *val = 1000; *val2 = ADXL367_TEMP_PER_C; @@ -914,12 +886,12 @@ static int adxl367_read_raw(struct iio_dev *indio_dev, default: return -EINVAL; } - case IIO_CHAN_INFO_SAMP_FREQ: - mutex_lock(&st->lock); + case IIO_CHAN_INFO_SAMP_FREQ: { + guard(mutex)(&st->lock); *val = adxl367_samp_freq_tbl[st->odr][0]; *val2 = adxl367_samp_freq_tbl[st->odr][1]; - mutex_unlock(&st->lock); return IIO_VAL_INT_PLUS_MICRO; + } default: return -EINVAL; } @@ -1004,18 +976,15 @@ static int adxl367_read_event_value(struct iio_dev *indio_dev, { struct adxl367_state *st = iio_priv(indio_dev); + guard(mutex)(&st->lock); switch (info) { case IIO_EV_INFO_VALUE: { switch (dir) { case IIO_EV_DIR_RISING: - mutex_lock(&st->lock); *val = st->act_threshold; - mutex_unlock(&st->lock); return IIO_VAL_INT; case IIO_EV_DIR_FALLING: - mutex_lock(&st->lock); *val = st->inact_threshold; - mutex_unlock(&st->lock); return IIO_VAL_INT; default: return -EINVAL; @@ -1024,15 +993,11 @@ static int adxl367_read_event_value(struct iio_dev *indio_dev, case IIO_EV_INFO_PERIOD: switch (dir) { case IIO_EV_DIR_RISING: - mutex_lock(&st->lock); *val = st->act_time_ms; - mutex_unlock(&st->lock); *val2 = 1000; return IIO_VAL_FRACTIONAL; case IIO_EV_DIR_FALLING: - mutex_lock(&st->lock); *val = st->inact_time_ms; - mutex_unlock(&st->lock); *val2 = 1000; return IIO_VAL_FRACTIONAL; default: @@ -1110,9 +1075,7 @@ static int adxl367_write_event_config(struct iio_dev *indio_dev, enum iio_event_direction dir, int state) { - struct adxl367_state *st = iio_priv(indio_dev); enum adxl367_activity_type act; - int ret; switch (dir) { case IIO_EV_DIR_RISING: @@ -1125,33 +1088,28 @@ static int adxl367_write_event_config(struct iio_dev *indio_dev, return -EINVAL; } - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; - - mutex_lock(&st->lock); + iio_device_claim_direct_scoped(return -EBUSY, indio_dev) { + struct adxl367_state *st = iio_priv(indio_dev); + int ret; - ret = adxl367_set_measure_en(st, false); - if (ret) - goto out; + guard(mutex)(&st->lock); - ret = adxl367_set_act_interrupt_en(st, act, state); - if (ret) - goto out; - - ret = adxl367_set_act_en(st, act, state ? ADCL367_ACT_REF_ENABLED - : ADXL367_ACT_DISABLED); - if (ret) - goto out; - - ret = adxl367_set_measure_en(st, true); + ret = adxl367_set_measure_en(st, false); + if (ret) + return ret; -out: - mutex_unlock(&st->lock); + ret = adxl367_set_act_interrupt_en(st, act, state); + if (ret) + return ret; - iio_device_release_direct_mode(indio_dev); + ret = adxl367_set_act_en(st, act, state ? ADCL367_ACT_REF_ENABLED + : ADXL367_ACT_DISABLED); + if (ret) + return ret; - return ret; + return adxl367_set_measure_en(st, true); + } + unreachable(); } static ssize_t adxl367_get_fifo_enabled(struct device *dev, @@ -1176,9 +1134,8 @@ static ssize_t adxl367_get_fifo_watermark(struct device *dev, struct adxl367_state *st = iio_priv(dev_to_iio_dev(dev)); unsigned int fifo_watermark; - mutex_lock(&st->lock); + guard(mutex)(&st->lock); fifo_watermark = st->fifo_watermark; - mutex_unlock(&st->lock); return sysfs_emit(buf, "%d\n", fifo_watermark); } @@ -1207,22 +1164,17 @@ static int adxl367_set_watermark(struct iio_dev *indio_dev, unsigned int val) if (val > ADXL367_FIFO_MAX_WATERMARK) return -EINVAL; - mutex_lock(&st->lock); + guard(mutex)(&st->lock); ret = adxl367_set_measure_en(st, false); if (ret) - goto out; + return ret; ret = adxl367_set_fifo_watermark(st, val); if (ret) - goto out; - - ret = adxl367_set_measure_en(st, true); - -out: - mutex_unlock(&st->lock); + return ret; - return ret; + return adxl367_set_measure_en(st, true); } static bool adxl367_find_mask_fifo_format(const unsigned long *scan_mask, @@ -1253,27 +1205,24 @@ static int adxl367_update_scan_mode(struct iio_dev *indio_dev, if (!adxl367_find_mask_fifo_format(active_scan_mask, &fifo_format)) return -EINVAL; - mutex_lock(&st->lock); + guard(mutex)(&st->lock); ret = adxl367_set_measure_en(st, false); if (ret) - goto out; + return ret; ret = adxl367_set_fifo_format(st, fifo_format); if (ret) - goto out; + return ret; ret = adxl367_set_measure_en(st, true); if (ret) - goto out; + return ret; st->fifo_set_size = bitmap_weight(active_scan_mask, indio_dev->masklength); -out: - mutex_unlock(&st->lock); - - return ret; + return 0; } static int adxl367_buffer_postenable(struct iio_dev *indio_dev) @@ -1281,31 +1230,26 @@ static int adxl367_buffer_postenable(struct iio_dev *indio_dev) struct adxl367_state *st = iio_priv(indio_dev); int ret; - mutex_lock(&st->lock); + guard(mutex)(&st->lock); ret = adxl367_set_temp_adc_mask_en(st, indio_dev->active_scan_mask, true); if (ret) - goto out; + return ret; ret = adxl367_set_measure_en(st, false); if (ret) - goto out; + return ret; ret = adxl367_set_fifo_watermark_interrupt_en(st, true); if (ret) - goto out; + return ret; ret = adxl367_set_fifo_mode(st, ADXL367_FIFO_MODE_STREAM); if (ret) - goto out; - - ret = adxl367_set_measure_en(st, true); - -out: - mutex_unlock(&st->lock); + return ret; - return ret; + return adxl367_set_measure_en(st, true); } static int adxl367_buffer_predisable(struct iio_dev *indio_dev) @@ -1313,31 +1257,26 @@ static int adxl367_buffer_predisable(struct iio_dev *indio_dev) struct adxl367_state *st = iio_priv(indio_dev); int ret; - mutex_lock(&st->lock); + guard(mutex)(&st->lock); ret = adxl367_set_measure_en(st, false); if (ret) - goto out; + return ret; ret = adxl367_set_fifo_mode(st, ADXL367_FIFO_MODE_DISABLED); if (ret) - goto out; + return ret; ret = adxl367_set_fifo_watermark_interrupt_en(st, false); if (ret) - goto out; + return ret; ret = adxl367_set_measure_en(st, true); if (ret) - goto out; - - ret = adxl367_set_temp_adc_mask_en(st, indio_dev->active_scan_mask, - false); - -out: - mutex_unlock(&st->lock); + return ret; - return ret; + return adxl367_set_temp_adc_mask_en(st, indio_dev->active_scan_mask, + false); } static const struct iio_buffer_setup_ops adxl367_buffer_ops = { diff --git a/drivers/iio/accel/bmc150-accel-i2c.c b/drivers/iio/accel/bmc150-accel-i2c.c index ee1ba134ad42..1c2e40369839 100644 --- a/drivers/iio/accel/bmc150-accel-i2c.c +++ b/drivers/iio/accel/bmc150-accel-i2c.c @@ -224,6 +224,19 @@ static const struct acpi_device_id bmc150_accel_acpi_match[] = { {"BMA250E"}, {"BMC150A"}, {"BMI055A"}, + /* + * The "BOSC0200" identifier used here is not unique to devices using + * bmc150. The same "BOSC0200" identifier is found in the ACPI tables + * of the ASUS ROG ALLY and Ayaneo AIR Plus which both use a Bosch + * BMI323 chip. This creates a conflict with duplicate ACPI identifiers + * which multiple drivers want to use. Fortunately, when the bmc150 + * driver starts to load on the ASUS ROG ALLY, the chip ID check + * portion fails (correctly) because the chip IDs received (via i2c) + * are unique between bmc150 and bmi323 and a dmesg output similar to + * this: "bmc150_accel_i2c i2c-BOSC0200:00: Invalid chip 0" can be + * seen. This allows the bmi323 driver to take over for ASUS ROG ALLY, + * and other devices using the bmi323 chip. + */ {"BOSC0200"}, {"BSBA0150"}, {"DUAL250E"}, @@ -266,7 +279,7 @@ static struct i2c_driver bmc150_accel_driver = { .driver = { .name = "bmc150_accel_i2c", .of_match_table = bmc150_accel_of_match, - .acpi_match_table = ACPI_PTR(bmc150_accel_acpi_match), + .acpi_match_table = bmc150_accel_acpi_match, .pm = &bmc150_accel_pm_ops, }, .probe = bmc150_accel_probe, diff --git a/drivers/iio/accel/bmc150-accel-spi.c b/drivers/iio/accel/bmc150-accel-spi.c index 921fb46be0b8..a6b9f599eb7b 100644 --- a/drivers/iio/accel/bmc150-accel-spi.c +++ b/drivers/iio/accel/bmc150-accel-spi.c @@ -7,7 +7,6 @@ #include <linux/device.h> #include <linux/mod_devicetable.h> #include <linux/module.h> -#include <linux/acpi.h> #include <linux/regmap.h> #include <linux/spi/spi.h> @@ -70,7 +69,7 @@ MODULE_DEVICE_TABLE(spi, bmc150_accel_id); static struct spi_driver bmc150_accel_driver = { .driver = { .name = "bmc150_accel_spi", - .acpi_match_table = ACPI_PTR(bmc150_accel_acpi_match), + .acpi_match_table = bmc150_accel_acpi_match, .pm = &bmc150_accel_pm_ops, }, .probe = bmc150_accel_probe, diff --git a/drivers/iio/accel/bmi088-accel-i2c.c b/drivers/iio/accel/bmi088-accel-i2c.c new file mode 100644 index 000000000000..17e9156bbe89 --- /dev/null +++ b/drivers/iio/accel/bmi088-accel-i2c.c @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * 3-axis accelerometer driver supporting following Bosch-Sensortec chips: + * - BMI088 + * - BMI085 + * - BMI090L + * + * Copyright 2023 Jun Yan <jerrysteve1101@gmail.com> + */ + +#include <linux/i2c.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/regmap.h> +#include <linux/slab.h> + +#include "bmi088-accel.h" + +static int bmi088_accel_probe(struct i2c_client *i2c) +{ + struct regmap *regmap; + const struct i2c_device_id *id = i2c_client_get_device_id(i2c); + + regmap = devm_regmap_init_i2c(i2c, &bmi088_regmap_conf); + if (IS_ERR(regmap)) { + dev_err(&i2c->dev, "Failed to initialize i2c regmap\n"); + return PTR_ERR(regmap); + } + + return bmi088_accel_core_probe(&i2c->dev, regmap, i2c->irq, + id->driver_data); +} + +static void bmi088_accel_remove(struct i2c_client *i2c) +{ + bmi088_accel_core_remove(&i2c->dev); +} + +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); + +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); + +static struct i2c_driver bmi088_accel_driver = { + .driver = { + .name = "bmi088_accel_i2c", + .pm = pm_ptr(&bmi088_accel_pm_ops), + .of_match_table = bmi088_of_match, + }, + .probe = bmi088_accel_probe, + .remove = bmi088_accel_remove, + .id_table = bmi088_accel_id, +}; +module_i2c_driver(bmi088_accel_driver); + +MODULE_AUTHOR("Jun Yan <jerrysteve1101@gmail.com>"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("BMI088 accelerometer driver (I2C)"); +MODULE_IMPORT_NS(IIO_BMI088); diff --git a/drivers/iio/accel/da280.c b/drivers/iio/accel/da280.c index 572bfe9694b0..992286828844 100644 --- a/drivers/iio/accel/da280.c +++ b/drivers/iio/accel/da280.c @@ -23,8 +23,6 @@ #define DA280_MODE_ENABLE 0x1e #define DA280_MODE_DISABLE 0x9e -enum da280_chipset { da217, da226, da280 }; - /* * a value of + or -4096 corresponds to + or - 1G * scale = 9.81 / 4096 = 0.002395019 @@ -47,6 +45,11 @@ static const struct iio_chan_spec da280_channels[] = { DA280_CHANNEL(DA280_REG_ACC_Z_LSB, Z), }; +struct da280_match_data { + const char *name; + int num_channels; +}; + struct da280_data { struct i2c_client *client; }; @@ -89,17 +92,6 @@ static const struct iio_info da280_info = { .read_raw = da280_read_raw, }; -static enum da280_chipset da280_match_acpi_device(struct device *dev) -{ - const struct acpi_device_id *id; - - id = acpi_match_device(dev->driver->acpi_match_table, dev); - if (!id) - return -EINVAL; - - return (enum da280_chipset) id->driver_data; -} - static void da280_disable(void *client) { da280_enable(client, false); @@ -107,16 +99,21 @@ static void da280_disable(void *client) static int da280_probe(struct i2c_client *client) { - const struct i2c_device_id *id = i2c_client_get_device_id(client); - int ret; + const struct da280_match_data *match_data; struct iio_dev *indio_dev; struct da280_data *data; - enum da280_chipset chip; + int ret; ret = i2c_smbus_read_byte_data(client, DA280_REG_CHIP_ID); if (ret != DA280_CHIP_ID) return (ret < 0) ? ret : -ENODEV; + match_data = i2c_get_match_data(client); + if (!match_data) { + dev_err(&client->dev, "Error match-data not set\n"); + return -EINVAL; + } + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); if (!indio_dev) return -ENOMEM; @@ -127,23 +124,8 @@ static int da280_probe(struct i2c_client *client) indio_dev->info = &da280_info; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->channels = da280_channels; - - if (ACPI_HANDLE(&client->dev)) { - chip = da280_match_acpi_device(&client->dev); - } else { - chip = id->driver_data; - } - - if (chip == da217) { - indio_dev->name = "da217"; - indio_dev->num_channels = 3; - } else if (chip == da226) { - indio_dev->name = "da226"; - indio_dev->num_channels = 2; - } else { - indio_dev->name = "da280"; - indio_dev->num_channels = 3; - } + indio_dev->num_channels = match_data->num_channels; + indio_dev->name = match_data->name; ret = da280_enable(client, true); if (ret < 0) @@ -168,17 +150,21 @@ static int da280_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(da280_pm_ops, da280_suspend, da280_resume); +static const struct da280_match_data da217_match_data = { "da217", 3 }; +static const struct da280_match_data da226_match_data = { "da226", 2 }; +static const struct da280_match_data da280_match_data = { "da280", 3 }; + static const struct acpi_device_id da280_acpi_match[] = { - {"NSA2513", da217}, - {"MIRAACC", da280}, - {}, + { "NSA2513", (kernel_ulong_t)&da217_match_data }, + { "MIRAACC", (kernel_ulong_t)&da280_match_data }, + {} }; MODULE_DEVICE_TABLE(acpi, da280_acpi_match); static const struct i2c_device_id da280_i2c_id[] = { - { "da217", da217 }, - { "da226", da226 }, - { "da280", da280 }, + { "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); @@ -186,7 +172,7 @@ MODULE_DEVICE_TABLE(i2c, da280_i2c_id); static struct i2c_driver da280_driver = { .driver = { .name = "da280", - .acpi_match_table = ACPI_PTR(da280_acpi_match), + .acpi_match_table = da280_acpi_match, .pm = pm_sleep_ptr(&da280_pm_ops), }, .probe = da280_probe, diff --git a/drivers/iio/accel/kxcjk-1013.c b/drivers/iio/accel/kxcjk-1013.c index 894709286b0c..c5f5b1ce7954 100644 --- a/drivers/iio/accel/kxcjk-1013.c +++ b/drivers/iio/accel/kxcjk-1013.c @@ -422,6 +422,23 @@ static int kiox010a_dsm(struct device *dev, int fn_index) ACPI_FREE(obj); return 0; } + +static const struct acpi_device_id kx_acpi_match[] = { + {"KXCJ1013", KXCJK1013}, + {"KXCJ1008", KXCJ91008}, + {"KXCJ9000", KXCJ91008}, + {"KIOX0008", KXCJ91008}, + {"KIOX0009", KXTJ21009}, + {"KIOX000A", KXCJ91008}, + {"KIOX010A", KXCJ91008}, /* KXCJ91008 in the display of a yoga 2-in-1 */ + {"KIOX020A", KXCJ91008}, /* KXCJ91008 in the base of a yoga 2-in-1 */ + {"KXTJ1009", KXTJ21009}, + {"KXJ2109", KXTJ21009}, + {"SMO8500", KXCJ91008}, + { } +}; +MODULE_DEVICE_TABLE(acpi, kx_acpi_match); + #endif static int kxcjk1013_set_mode(struct kxcjk1013_data *data, @@ -1687,22 +1704,6 @@ static const struct dev_pm_ops kxcjk1013_pm_ops = { kxcjk1013_runtime_resume, NULL) }; -static const struct acpi_device_id kx_acpi_match[] = { - {"KXCJ1013", KXCJK1013}, - {"KXCJ1008", KXCJ91008}, - {"KXCJ9000", KXCJ91008}, - {"KIOX0008", KXCJ91008}, - {"KIOX0009", KXTJ21009}, - {"KIOX000A", KXCJ91008}, - {"KIOX010A", KXCJ91008}, /* KXCJ91008 in the display of a yoga 2-in-1 */ - {"KIOX020A", KXCJ91008}, /* KXCJ91008 in the base of a yoga 2-in-1 */ - {"KXTJ1009", KXTJ21009}, - {"KXJ2109", KXTJ21009}, - {"SMO8500", KXCJ91008}, - { }, -}; -MODULE_DEVICE_TABLE(acpi, kx_acpi_match); - static const struct i2c_device_id kxcjk1013_id[] = { {"kxcjk1013", KXCJK1013}, {"kxcj91008", KXCJ91008}, diff --git a/drivers/iio/accel/mma9551.c b/drivers/iio/accel/mma9551.c index d823f2edc6d4..083c08f65baf 100644 --- a/drivers/iio/accel/mma9551.c +++ b/drivers/iio/accel/mma9551.c @@ -604,9 +604,9 @@ MODULE_DEVICE_TABLE(i2c, mma9551_id); static struct i2c_driver mma9551_driver = { .driver = { .name = MMA9551_DRV_NAME, - .acpi_match_table = ACPI_PTR(mma9551_acpi_match), + .acpi_match_table = mma9551_acpi_match, .pm = pm_ptr(&mma9551_pm_ops), - }, + }, .probe = mma9551_probe, .remove = mma9551_remove, .id_table = mma9551_id, diff --git a/drivers/iio/accel/mma9553.c b/drivers/iio/accel/mma9553.c index d01aba4aecba..3cbd0fd4e624 100644 --- a/drivers/iio/accel/mma9553.c +++ b/drivers/iio/accel/mma9553.c @@ -1243,9 +1243,9 @@ MODULE_DEVICE_TABLE(i2c, mma9553_id); static struct i2c_driver mma9553_driver = { .driver = { .name = MMA9553_DRV_NAME, - .acpi_match_table = ACPI_PTR(mma9553_acpi_match), + .acpi_match_table = mma9553_acpi_match, .pm = pm_ptr(&mma9553_pm_ops), - }, + }, .probe = mma9553_probe, .remove = mma9553_remove, .id_table = mma9553_id, diff --git a/drivers/iio/accel/mxc4005.c b/drivers/iio/accel/mxc4005.c index 82e8d0b39049..61839be501c2 100644 --- a/drivers/iio/accel/mxc4005.c +++ b/drivers/iio/accel/mxc4005.c @@ -8,7 +8,7 @@ #include <linux/module.h> #include <linux/i2c.h> #include <linux/iio/iio.h> -#include <linux/acpi.h> +#include <linux/mod_devicetable.h> #include <linux/regmap.h> #include <linux/iio/sysfs.h> #include <linux/iio/trigger.h> @@ -472,6 +472,7 @@ static int mxc4005_probe(struct i2c_client *client) static const struct acpi_device_id mxc4005_acpi_match[] = { {"MXC4005", 0}, {"MXC6655", 0}, + {"MDA6655", 0}, { }, }; MODULE_DEVICE_TABLE(acpi, mxc4005_acpi_match); @@ -493,7 +494,7 @@ MODULE_DEVICE_TABLE(i2c, mxc4005_id); static struct i2c_driver mxc4005_driver = { .driver = { .name = MXC4005_DRV_NAME, - .acpi_match_table = ACPI_PTR(mxc4005_acpi_match), + .acpi_match_table = mxc4005_acpi_match, .of_match_table = mxc4005_of_match, }, .probe = mxc4005_probe, diff --git a/drivers/iio/accel/mxc6255.c b/drivers/iio/accel/mxc6255.c index 33c2253561e6..ac228128c4f9 100644 --- a/drivers/iio/accel/mxc6255.c +++ b/drivers/iio/accel/mxc6255.c @@ -12,7 +12,7 @@ #include <linux/init.h> #include <linux/iio/iio.h> #include <linux/delay.h> -#include <linux/acpi.h> +#include <linux/mod_devicetable.h> #include <linux/regmap.h> #include <linux/iio/sysfs.h> @@ -181,7 +181,7 @@ MODULE_DEVICE_TABLE(i2c, mxc6255_id); static struct i2c_driver mxc6255_driver = { .driver = { .name = MXC6255_DRV_NAME, - .acpi_match_table = ACPI_PTR(mxc6255_acpi_match), + .acpi_match_table = mxc6255_acpi_match, }, .probe = mxc6255_probe, .id_table = mxc6255_id, diff --git a/drivers/iio/accel/st_accel_i2c.c b/drivers/iio/accel/st_accel_i2c.c index 71ee861b2980..fd3749871121 100644 --- a/drivers/iio/accel/st_accel_i2c.c +++ b/drivers/iio/accel/st_accel_i2c.c @@ -10,7 +10,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/mod_devicetable.h> -#include <linux/acpi.h> #include <linux/i2c.h> #include <linux/iio/iio.h> @@ -127,14 +126,12 @@ static const struct of_device_id st_accel_of_match[] = { }; MODULE_DEVICE_TABLE(of, st_accel_of_match); -#ifdef CONFIG_ACPI 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); -#endif static const struct i2c_device_id st_accel_id_table[] = { { LSM303DLH_ACCEL_DEV_NAME }, @@ -204,7 +201,7 @@ static struct i2c_driver st_accel_driver = { .driver = { .name = "st-accel-i2c", .of_match_table = st_accel_of_match, - .acpi_match_table = ACPI_PTR(st_accel_acpi_match), + .acpi_match_table = st_accel_acpi_match, }, .probe = st_accel_i2c_probe, .id_table = st_accel_id_table, diff --git a/drivers/iio/accel/stk8ba50.c b/drivers/iio/accel/stk8ba50.c index 3415ac1b4495..668edc88c89d 100644 --- a/drivers/iio/accel/stk8ba50.c +++ b/drivers/iio/accel/stk8ba50.c @@ -7,11 +7,11 @@ * STK8BA50 7-bit I2C address: 0x18. */ -#include <linux/acpi.h> #include <linux/i2c.h> #include <linux/interrupt.h> #include <linux/kernel.h> #include <linux/module.h> +#include <linux/mod_devicetable.h> #include <linux/iio/buffer.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> @@ -541,7 +541,7 @@ static struct i2c_driver stk8ba50_driver = { .driver = { .name = "stk8ba50", .pm = pm_sleep_ptr(&stk8ba50_pm_ops), - .acpi_match_table = ACPI_PTR(stk8ba50_acpi_id), + .acpi_match_table = stk8ba50_acpi_id, }, .probe = stk8ba50_probe, .remove = stk8ba50_remove, diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 3b73c509bd68..d4462c202784 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -291,7 +291,7 @@ config AD799X config AD9467 tristate "Analog Devices AD9467 High Speed ADC driver" depends on SPI - depends on ADI_AXI_ADC + select IIO_BACKEND help Say yes here to build support for Analog Devices: * AD9467 16-Bit, 200 MSPS/250 MSPS Analog-to-Digital Converter @@ -309,7 +309,7 @@ config ADI_AXI_ADC select IIO_BUFFER_HW_CONSUMER select IIO_BUFFER_DMAENGINE select REGMAP_MMIO - depends on OF + select IIO_BACKEND help Say yes here to build support for Analog Devices Generic AXI ADC IP core. The IP core is used for interfacing with @@ -1312,6 +1312,17 @@ config TI_ADS1100 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 diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index d2fda54a3259..a64326f40fcb 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -116,6 +116,7 @@ obj-$(CONFIG_TI_ADC128S052) += ti-adc128s052.o obj-$(CONFIG_TI_ADC161S626) += ti-adc161s626.o obj-$(CONFIG_TI_ADS1015) += ti-ads1015.o obj-$(CONFIG_TI_ADS1100) += ti-ads1100.o +obj-$(CONFIG_TI_ADS1298) += ti-ads1298.o obj-$(CONFIG_TI_ADS7924) += ti-ads7924.o obj-$(CONFIG_TI_ADS7950) += ti-ads7950.o obj-$(CONFIG_TI_ADS8344) += ti-ads8344.o diff --git a/drivers/iio/adc/ad4130.c b/drivers/iio/adc/ad4130.c index feb86fe6c422..febb64e67955 100644 --- a/drivers/iio/adc/ad4130.c +++ b/drivers/iio/adc/ad4130.c @@ -887,9 +887,9 @@ static int ad4130_set_filter_mode(struct iio_dev *indio_dev, unsigned int old_fs; int ret = 0; - mutex_lock(&st->lock); + guard(mutex)(&st->lock); if (setup_info->filter_mode == val) - goto out; + return 0; old_fs = setup_info->fs; old_filter_mode = setup_info->filter_mode; @@ -911,12 +911,10 @@ static int ad4130_set_filter_mode(struct iio_dev *indio_dev, if (ret) { setup_info->fs = old_fs; setup_info->filter_mode = old_filter_mode; + return ret; } - out: - mutex_unlock(&st->lock); - - return ret; + return 0; } static int ad4130_get_filter_mode(struct iio_dev *indio_dev, @@ -927,9 +925,8 @@ static int ad4130_get_filter_mode(struct iio_dev *indio_dev, struct ad4130_setup_info *setup_info = &st->chans_info[channel].setup; enum ad4130_filter_mode filter_mode; - mutex_lock(&st->lock); + guard(mutex)(&st->lock); filter_mode = setup_info->filter_mode; - mutex_unlock(&st->lock); return filter_mode; } @@ -971,7 +968,7 @@ static int ad4130_set_channel_pga(struct ad4130_state *st, unsigned int channel, struct ad4130_chan_info *chan_info = &st->chans_info[channel]; struct ad4130_setup_info *setup_info = &chan_info->setup; unsigned int pga, old_pga; - int ret = 0; + int ret; for (pga = 0; pga < AD4130_MAX_PGA; pga++) if (val == st->scale_tbls[setup_info->ref_sel][pga][0] && @@ -981,21 +978,20 @@ static int ad4130_set_channel_pga(struct ad4130_state *st, unsigned int channel, if (pga == AD4130_MAX_PGA) return -EINVAL; - mutex_lock(&st->lock); + guard(mutex)(&st->lock); if (pga == setup_info->pga) - goto out; + return 0; old_pga = setup_info->pga; setup_info->pga = pga; ret = ad4130_write_channel_setup(st, channel, false); - if (ret) + if (ret) { setup_info->pga = old_pga; + return ret; + } -out: - mutex_unlock(&st->lock); - - return ret; + return 0; } static int ad4130_set_channel_freq(struct ad4130_state *st, @@ -1004,26 +1000,25 @@ static int ad4130_set_channel_freq(struct ad4130_state *st, struct ad4130_chan_info *chan_info = &st->chans_info[channel]; struct ad4130_setup_info *setup_info = &chan_info->setup; unsigned int fs, old_fs; - int ret = 0; + int ret; - mutex_lock(&st->lock); + guard(mutex)(&st->lock); old_fs = setup_info->fs; ad4130_freq_to_fs(setup_info->filter_mode, val, val2, &fs); if (fs == setup_info->fs) - goto out; + return 0; setup_info->fs = fs; ret = ad4130_write_channel_setup(st, channel, false); - if (ret) + if (ret) { setup_info->fs = old_fs; + return ret; + } -out: - mutex_unlock(&st->lock); - - return ret; + return 0; } static int _ad4130_read_sample(struct iio_dev *indio_dev, unsigned int channel, @@ -1065,20 +1060,13 @@ static int _ad4130_read_sample(struct iio_dev *indio_dev, unsigned int channel, static int ad4130_read_sample(struct iio_dev *indio_dev, unsigned int channel, int *val) { - struct ad4130_state *st = iio_priv(indio_dev); - int ret; - - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; - - mutex_lock(&st->lock); - ret = _ad4130_read_sample(indio_dev, channel, val); - mutex_unlock(&st->lock); + iio_device_claim_direct_scoped(return -EBUSY, indio_dev) { + struct ad4130_state *st = iio_priv(indio_dev); - iio_device_release_direct_mode(indio_dev); - - return ret; + guard(mutex)(&st->lock); + return _ad4130_read_sample(indio_dev, channel, val); + } + unreachable(); } static int ad4130_read_raw(struct iio_dev *indio_dev, @@ -1092,24 +1080,24 @@ static int ad4130_read_raw(struct iio_dev *indio_dev, switch (info) { case IIO_CHAN_INFO_RAW: return ad4130_read_sample(indio_dev, channel, val); - case IIO_CHAN_INFO_SCALE: - mutex_lock(&st->lock); + case IIO_CHAN_INFO_SCALE: { + guard(mutex)(&st->lock); *val = st->scale_tbls[setup_info->ref_sel][setup_info->pga][0]; *val2 = st->scale_tbls[setup_info->ref_sel][setup_info->pga][1]; - mutex_unlock(&st->lock); return IIO_VAL_INT_PLUS_NANO; + } case IIO_CHAN_INFO_OFFSET: *val = st->bipolar ? -BIT(chan->scan_type.realbits - 1) : 0; return IIO_VAL_INT; - case IIO_CHAN_INFO_SAMP_FREQ: - mutex_lock(&st->lock); + case IIO_CHAN_INFO_SAMP_FREQ: { + guard(mutex)(&st->lock); ad4130_fs_to_freq(setup_info->filter_mode, setup_info->fs, val, val2); - mutex_unlock(&st->lock); return IIO_VAL_INT_PLUS_NANO; + } default: return -EINVAL; } @@ -1134,9 +1122,9 @@ static int ad4130_read_avail(struct iio_dev *indio_dev, return IIO_AVAIL_LIST; case IIO_CHAN_INFO_SAMP_FREQ: - mutex_lock(&st->lock); - filter_config = &ad4130_filter_configs[setup_info->filter_mode]; - mutex_unlock(&st->lock); + scoped_guard(mutex, &st->lock) { + filter_config = &ad4130_filter_configs[setup_info->filter_mode]; + } *vals = (int *)filter_config->samp_freq_avail; *length = filter_config->samp_freq_avail_len * 2; @@ -1197,21 +1185,18 @@ static int ad4130_update_scan_mode(struct iio_dev *indio_dev, unsigned int val = 0; int ret; - mutex_lock(&st->lock); + guard(mutex)(&st->lock); for_each_set_bit(channel, scan_mask, indio_dev->num_channels) { ret = ad4130_set_channel_enable(st, channel, true); if (ret) - goto out; + return ret; val++; } st->num_enabled_channels = val; -out: - mutex_unlock(&st->lock); - return 0; } @@ -1232,22 +1217,19 @@ static int ad4130_set_fifo_watermark(struct iio_dev *indio_dev, unsigned int val */ eff = rounddown(AD4130_FIFO_SIZE, st->num_enabled_channels); - mutex_lock(&st->lock); + guard(mutex)(&st->lock); ret = regmap_update_bits(st->regmap, AD4130_FIFO_CONTROL_REG, AD4130_FIFO_CONTROL_WM_MASK, FIELD_PREP(AD4130_FIFO_CONTROL_WM_MASK, ad4130_watermark_reg_val(eff))); if (ret) - goto out; + return ret; st->effective_watermark = eff; st->watermark = val; -out: - mutex_unlock(&st->lock); - - return ret; + return 0; } static const struct iio_info ad4130_info = { @@ -1265,26 +1247,21 @@ static int ad4130_buffer_postenable(struct iio_dev *indio_dev) struct ad4130_state *st = iio_priv(indio_dev); int ret; - mutex_lock(&st->lock); + guard(mutex)(&st->lock); ret = ad4130_set_watermark_interrupt_en(st, true); if (ret) - goto out; + return ret; ret = irq_set_irq_type(st->spi->irq, st->inv_irq_trigger); if (ret) - goto out; + return ret; ret = ad4130_set_fifo_mode(st, AD4130_FIFO_MODE_WM); if (ret) - goto out; - - ret = ad4130_set_mode(st, AD4130_MODE_CONTINUOUS); - -out: - mutex_unlock(&st->lock); + return ret; - return ret; + return ad4130_set_mode(st, AD4130_MODE_CONTINUOUS); } static int ad4130_buffer_predisable(struct iio_dev *indio_dev) @@ -1293,23 +1270,23 @@ static int ad4130_buffer_predisable(struct iio_dev *indio_dev) unsigned int i; int ret; - mutex_lock(&st->lock); + guard(mutex)(&st->lock); ret = ad4130_set_mode(st, AD4130_MODE_IDLE); if (ret) - goto out; + return ret; ret = irq_set_irq_type(st->spi->irq, st->irq_trigger); if (ret) - goto out; + return ret; ret = ad4130_set_fifo_mode(st, AD4130_FIFO_MODE_DISABLED); if (ret) - goto out; + return ret; ret = ad4130_set_watermark_interrupt_en(st, false); if (ret) - goto out; + return ret; /* * update_scan_mode() is not called in the disable path, disable all @@ -1318,13 +1295,10 @@ static int ad4130_buffer_predisable(struct iio_dev *indio_dev) for (i = 0; i < indio_dev->num_channels; i++) { ret = ad4130_set_channel_enable(st, i, false); if (ret) - goto out; + return ret; } -out: - mutex_unlock(&st->lock); - - return ret; + return 0; } static const struct iio_buffer_setup_ops ad4130_buffer_ops = { @@ -1338,9 +1312,8 @@ static ssize_t hwfifo_watermark_show(struct device *dev, struct ad4130_state *st = iio_priv(dev_to_iio_dev(dev)); unsigned int val; - mutex_lock(&st->lock); + guard(mutex)(&st->lock); val = st->watermark; - mutex_unlock(&st->lock); return sysfs_emit(buf, "%d\n", val); } @@ -1821,7 +1794,7 @@ static int ad4130_setup_int_clk(struct ad4130_state *st) { struct device *dev = &st->spi->dev; struct device_node *of_node = dev_of_node(dev); - struct clk_init_data init; + struct clk_init_data init = {}; const char *clk_name; int ret; @@ -1891,10 +1864,14 @@ static int ad4130_setup(struct iio_dev *indio_dev) return ret; /* - * Configure all GPIOs for output. If configured, the interrupt function - * of P2 takes priority over the GPIO out function. + * Configure unused GPIOs for output. If configured, the interrupt + * function of P2 takes priority over the GPIO out function. */ - val = AD4130_IO_CONTROL_GPIO_CTRL_MASK; + val = 0; + for (i = 0; i < AD4130_MAX_GPIOS; i++) + if (st->pins_fn[i + AD4130_AIN2_P1] == AD4130_PIN_FN_NONE) + val |= FIELD_PREP(AD4130_IO_CONTROL_GPIO_CTRL_MASK, BIT(i)); + val |= FIELD_PREP(AD4130_IO_CONTROL_INT_PIN_SEL_MASK, st->int_pin_sel); ret = regmap_write(st->regmap, AD4130_IO_CONTROL_REG, val); diff --git a/drivers/iio/adc/ad7091r-base.c b/drivers/iio/adc/ad7091r-base.c index f4255b91acfc..d6876259ad14 100644 --- a/drivers/iio/adc/ad7091r-base.c +++ b/drivers/iio/adc/ad7091r-base.c @@ -86,28 +86,25 @@ static int ad7091r_read_raw(struct iio_dev *iio_dev, unsigned int read_val; int ret; - mutex_lock(&st->lock); + guard(mutex)(&st->lock); switch (m) { case IIO_CHAN_INFO_RAW: - if (st->mode != AD7091R_MODE_COMMAND) { - ret = -EBUSY; - goto unlock; - } + if (st->mode != AD7091R_MODE_COMMAND) + return -EBUSY; ret = ad7091r_read_one(iio_dev, chan->channel, &read_val); if (ret) - goto unlock; + return ret; *val = read_val; - ret = IIO_VAL_INT; - break; + return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: if (st->vref) { ret = regulator_get_voltage(st->vref); if (ret < 0) - goto unlock; + return ret; *val = ret / 1000; } else { @@ -115,17 +112,11 @@ static int ad7091r_read_raw(struct iio_dev *iio_dev, } *val2 = chan->scan_type.realbits; - ret = IIO_VAL_FRACTIONAL_LOG2; - break; + return IIO_VAL_FRACTIONAL_LOG2; default: - ret = -EINVAL; - break; + return -EINVAL; } - -unlock: - mutex_unlock(&st->lock); - return ret; } static int ad7091r_read_event_config(struct iio_dev *indio_dev, diff --git a/drivers/iio/adc/ad7091r8.c b/drivers/iio/adc/ad7091r8.c index 57700f124803..700564305057 100644 --- a/drivers/iio/adc/ad7091r8.c +++ b/drivers/iio/adc/ad7091r8.c @@ -195,7 +195,7 @@ static int ad7091r8_gpio_setup(struct ad7091r_state *st) st->reset_gpio = devm_gpiod_get_optional(st->dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR(st->reset_gpio)) - return dev_err_probe(st->dev, PTR_ERR(st->convst_gpio), + return dev_err_probe(st->dev, PTR_ERR(st->reset_gpio), "Error on requesting reset GPIO\n"); if (st->reset_gpio) { diff --git a/drivers/iio/adc/ad9467.c b/drivers/iio/adc/ad9467.c index 6581fce4ba95..7475ec2a56c7 100644 --- a/drivers/iio/adc/ad9467.c +++ b/drivers/iio/adc/ad9467.c @@ -17,13 +17,12 @@ #include <linux/of.h> +#include <linux/iio/backend.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> #include <linux/clk.h> -#include <linux/iio/adc/adi-axi-adc.h> - /* * ADI High-Speed ADC common spi interface registers * See Application-Note AN-877: @@ -102,15 +101,20 @@ #define AD9467_REG_VREF_MASK 0x0F struct ad9467_chip_info { - struct adi_axi_adc_chip_info axi_adc_info; - unsigned int default_output_mode; - unsigned int vref_mask; + const char *name; + unsigned int id; + const struct iio_chan_spec *channels; + unsigned int num_channels; + const unsigned int (*scale_table)[2]; + int num_scales; + unsigned long max_rate; + unsigned int default_output_mode; + unsigned int vref_mask; }; -#define to_ad9467_chip_info(_info) \ - container_of(_info, struct ad9467_chip_info, axi_adc_info) - struct ad9467_state { + const struct ad9467_chip_info *info; + struct iio_backend *back; struct spi_device *spi; struct clk *clk; unsigned int output_mode; @@ -151,10 +155,10 @@ static int ad9467_spi_write(struct spi_device *spi, unsigned int reg, return spi_write(spi, buf, ARRAY_SIZE(buf)); } -static int ad9467_reg_access(struct adi_axi_adc_conv *conv, unsigned int reg, +static int ad9467_reg_access(struct iio_dev *indio_dev, unsigned int reg, unsigned int writeval, unsigned int *readval) { - struct ad9467_state *st = adi_axi_adc_conv_priv(conv); + struct ad9467_state *st = iio_priv(indio_dev); struct spi_device *spi = st->spi; int ret; @@ -191,10 +195,10 @@ static const unsigned int ad9467_scale_table[][2] = { {2300, 8}, {2400, 9}, {2500, 10}, }; -static void __ad9467_get_scale(struct adi_axi_adc_conv *conv, int index, +static void __ad9467_get_scale(struct ad9467_state *st, int index, unsigned int *val, unsigned int *val2) { - const struct adi_axi_adc_chip_info *info = conv->chip_info; + const struct ad9467_chip_info *info = st->info; const struct iio_chan_spec *chan = &info->channels[0]; unsigned int tmp; @@ -229,52 +233,44 @@ static const struct iio_chan_spec ad9467_channels[] = { }; static const struct ad9467_chip_info ad9467_chip_tbl = { - .axi_adc_info = { - .name = "ad9467", - .id = CHIPID_AD9467, - .max_rate = 250000000UL, - .scale_table = ad9467_scale_table, - .num_scales = ARRAY_SIZE(ad9467_scale_table), - .channels = ad9467_channels, - .num_channels = ARRAY_SIZE(ad9467_channels), - }, + .name = "ad9467", + .id = CHIPID_AD9467, + .max_rate = 250000000UL, + .scale_table = ad9467_scale_table, + .num_scales = ARRAY_SIZE(ad9467_scale_table), + .channels = ad9467_channels, + .num_channels = ARRAY_SIZE(ad9467_channels), .default_output_mode = AD9467_DEF_OUTPUT_MODE, .vref_mask = AD9467_REG_VREF_MASK, }; static const struct ad9467_chip_info ad9434_chip_tbl = { - .axi_adc_info = { - .name = "ad9434", - .id = CHIPID_AD9434, - .max_rate = 500000000UL, - .scale_table = ad9434_scale_table, - .num_scales = ARRAY_SIZE(ad9434_scale_table), - .channels = ad9434_channels, - .num_channels = ARRAY_SIZE(ad9434_channels), - }, + .name = "ad9434", + .id = CHIPID_AD9434, + .max_rate = 500000000UL, + .scale_table = ad9434_scale_table, + .num_scales = ARRAY_SIZE(ad9434_scale_table), + .channels = ad9434_channels, + .num_channels = ARRAY_SIZE(ad9434_channels), .default_output_mode = AD9434_DEF_OUTPUT_MODE, .vref_mask = AD9434_REG_VREF_MASK, }; static const struct ad9467_chip_info ad9265_chip_tbl = { - .axi_adc_info = { - .name = "ad9265", - .id = CHIPID_AD9265, - .max_rate = 125000000UL, - .scale_table = ad9265_scale_table, - .num_scales = ARRAY_SIZE(ad9265_scale_table), - .channels = ad9467_channels, - .num_channels = ARRAY_SIZE(ad9467_channels), - }, + .name = "ad9265", + .id = CHIPID_AD9265, + .max_rate = 125000000UL, + .scale_table = ad9265_scale_table, + .num_scales = ARRAY_SIZE(ad9265_scale_table), + .channels = ad9467_channels, + .num_channels = ARRAY_SIZE(ad9467_channels), .default_output_mode = AD9265_DEF_OUTPUT_MODE, .vref_mask = AD9265_REG_VREF_MASK, }; -static int ad9467_get_scale(struct adi_axi_adc_conv *conv, int *val, int *val2) +static int ad9467_get_scale(struct ad9467_state *st, int *val, int *val2) { - const struct adi_axi_adc_chip_info *info = conv->chip_info; - const struct ad9467_chip_info *info1 = to_ad9467_chip_info(info); - struct ad9467_state *st = adi_axi_adc_conv_priv(conv); + const struct ad9467_chip_info *info = st->info; unsigned int i, vref_val; int ret; @@ -282,7 +278,7 @@ static int ad9467_get_scale(struct adi_axi_adc_conv *conv, int *val, int *val2) if (ret < 0) return ret; - vref_val = ret & info1->vref_mask; + vref_val = ret & info->vref_mask; for (i = 0; i < info->num_scales; i++) { if (vref_val == info->scale_table[i][1]) @@ -292,15 +288,14 @@ static int ad9467_get_scale(struct adi_axi_adc_conv *conv, int *val, int *val2) if (i == info->num_scales) return -ERANGE; - __ad9467_get_scale(conv, i, val, val2); + __ad9467_get_scale(st, i, val, val2); return IIO_VAL_INT_PLUS_MICRO; } -static int ad9467_set_scale(struct adi_axi_adc_conv *conv, int val, int val2) +static int ad9467_set_scale(struct ad9467_state *st, int val, int val2) { - const struct adi_axi_adc_chip_info *info = conv->chip_info; - struct ad9467_state *st = adi_axi_adc_conv_priv(conv); + const struct ad9467_chip_info *info = st->info; unsigned int scale_val[2]; unsigned int i; int ret; @@ -309,7 +304,7 @@ static int ad9467_set_scale(struct adi_axi_adc_conv *conv, int val, int val2) return -EINVAL; for (i = 0; i < info->num_scales; i++) { - __ad9467_get_scale(conv, i, &scale_val[0], &scale_val[1]); + __ad9467_get_scale(st, i, &scale_val[0], &scale_val[1]); if (scale_val[0] != val || scale_val[1] != val2) continue; @@ -326,15 +321,15 @@ static int ad9467_set_scale(struct adi_axi_adc_conv *conv, int val, int val2) return -EINVAL; } -static int ad9467_read_raw(struct adi_axi_adc_conv *conv, +static int ad9467_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long m) { - struct ad9467_state *st = adi_axi_adc_conv_priv(conv); + struct ad9467_state *st = iio_priv(indio_dev); switch (m) { case IIO_CHAN_INFO_SCALE: - return ad9467_get_scale(conv, val, val2); + return ad9467_get_scale(st, val, val2); case IIO_CHAN_INFO_SAMP_FREQ: *val = clk_get_rate(st->clk); @@ -344,17 +339,17 @@ static int ad9467_read_raw(struct adi_axi_adc_conv *conv, } } -static int ad9467_write_raw(struct adi_axi_adc_conv *conv, +static int ad9467_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, int val2, long mask) { - const struct adi_axi_adc_chip_info *info = conv->chip_info; - struct ad9467_state *st = adi_axi_adc_conv_priv(conv); + struct ad9467_state *st = iio_priv(indio_dev); + const struct ad9467_chip_info *info = st->info; long r_clk; switch (mask) { case IIO_CHAN_INFO_SCALE: - return ad9467_set_scale(conv, val, val2); + return ad9467_set_scale(st, val, val2); case IIO_CHAN_INFO_SAMP_FREQ: r_clk = clk_round_rate(st->clk, val); if (r_clk < 0 || r_clk > info->max_rate) { @@ -369,13 +364,13 @@ static int ad9467_write_raw(struct adi_axi_adc_conv *conv, } } -static int ad9467_read_avail(struct adi_axi_adc_conv *conv, +static int ad9467_read_avail(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, const int **vals, int *type, int *length, long mask) { - const struct adi_axi_adc_chip_info *info = conv->chip_info; - struct ad9467_state *st = adi_axi_adc_conv_priv(conv); + struct ad9467_state *st = iio_priv(indio_dev); + const struct ad9467_chip_info *info = st->info; switch (mask) { case IIO_CHAN_INFO_SCALE: @@ -389,6 +384,33 @@ static int ad9467_read_avail(struct adi_axi_adc_conv *conv, } } +static int ad9467_update_scan_mode(struct iio_dev *indio_dev, + const unsigned long *scan_mask) +{ + struct ad9467_state *st = iio_priv(indio_dev); + unsigned int c; + int ret; + + for (c = 0; c < st->info->num_channels; c++) { + if (test_bit(c, scan_mask)) + ret = iio_backend_chan_enable(st->back, c); + else + ret = iio_backend_chan_disable(st->back, c); + if (ret) + return ret; + } + + return 0; +} + +static const struct iio_info ad9467_info = { + .read_raw = ad9467_read_raw, + .write_raw = ad9467_write_raw, + .update_scan_mode = ad9467_update_scan_mode, + .debugfs_reg_access = ad9467_reg_access, + .read_avail = ad9467_read_avail, +}; + static int ad9467_outputmode_set(struct spi_device *spi, unsigned int mode) { int ret; @@ -401,10 +423,9 @@ static int ad9467_outputmode_set(struct spi_device *spi, unsigned int mode) AN877_ADC_TRANSFER_SYNC); } -static int ad9467_scale_fill(struct adi_axi_adc_conv *conv) +static int ad9467_scale_fill(struct ad9467_state *st) { - const struct adi_axi_adc_chip_info *info = conv->chip_info; - struct ad9467_state *st = adi_axi_adc_conv_priv(conv); + const struct ad9467_chip_info *info = st->info; unsigned int i, val1, val2; st->scales = devm_kmalloc_array(&st->spi->dev, info->num_scales, @@ -413,7 +434,7 @@ static int ad9467_scale_fill(struct adi_axi_adc_conv *conv) return -ENOMEM; for (i = 0; i < info->num_scales; i++) { - __ad9467_get_scale(conv, i, &val1, &val2); + __ad9467_get_scale(st, i, &val1, &val2); st->scales[i][0] = val1; st->scales[i][1] = val2; } @@ -421,11 +442,27 @@ static int ad9467_scale_fill(struct adi_axi_adc_conv *conv) return 0; } -static int ad9467_preenable_setup(struct adi_axi_adc_conv *conv) +static int ad9467_setup(struct ad9467_state *st) { - struct ad9467_state *st = adi_axi_adc_conv_priv(conv); + struct iio_backend_data_fmt data = { + .sign_extend = true, + .enable = true, + }; + unsigned int c, mode; + int ret; + + mode = st->info->default_output_mode | AN877_ADC_OUTPUT_MODE_TWOS_COMPLEMENT; + ret = ad9467_outputmode_set(st->spi, mode); + if (ret) + return ret; - return ad9467_outputmode_set(st->spi, st->output_mode); + for (c = 0; c < st->info->num_channels; c++) { + ret = iio_backend_data_format_set(st->back, c, &data); + if (ret) + return ret; + } + + return 0; } static int ad9467_reset(struct device *dev) @@ -443,25 +480,65 @@ static int ad9467_reset(struct device *dev) return 0; } +static int ad9467_iio_backend_get(struct ad9467_state *st) +{ + struct device *dev = &st->spi->dev; + struct device_node *__back; + + st->back = devm_iio_backend_get(dev, NULL); + if (!IS_ERR(st->back)) + return 0; + /* If not found, don't error out as we might have legacy DT property */ + if (PTR_ERR(st->back) != -ENOENT) + return PTR_ERR(st->back); + + /* + * if we don't get the backend using the normal API's, use the legacy + * 'adi,adc-dev' property. So we get all nodes with that property, and + * look for the one pointing at us. Then we directly lookup that fwnode + * on the backend list of registered devices. This is done so we don't + * make io-backends mandatory which would break DT ABI. + */ + for_each_node_with_property(__back, "adi,adc-dev") { + struct device_node *__me; + + __me = of_parse_phandle(__back, "adi,adc-dev", 0); + if (!__me) + continue; + + if (!device_match_of_node(dev, __me)) { + of_node_put(__me); + continue; + } + + of_node_put(__me); + st->back = __devm_iio_backend_get_from_fwnode_lookup(dev, + of_fwnode_handle(__back)); + of_node_put(__back); + return PTR_ERR_OR_ZERO(st->back); + } + + return -ENODEV; +} + static int ad9467_probe(struct spi_device *spi) { - const struct ad9467_chip_info *info; - struct adi_axi_adc_conv *conv; + struct iio_dev *indio_dev; struct ad9467_state *st; unsigned int id; int ret; - info = spi_get_device_match_data(spi); - if (!info) - return -ENODEV; - - conv = devm_adi_axi_adc_conv_register(&spi->dev, sizeof(*st)); - if (IS_ERR(conv)) - return PTR_ERR(conv); + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; - st = adi_axi_adc_conv_priv(conv); + st = iio_priv(indio_dev); st->spi = spi; + st->info = spi_get_device_match_data(spi); + if (!st->info) + return -ENODEV; + st->clk = devm_clk_get_enabled(&spi->dev, "adc-clk"); if (IS_ERR(st->clk)) return PTR_ERR(st->clk); @@ -475,29 +552,39 @@ static int ad9467_probe(struct spi_device *spi) if (ret) return ret; - conv->chip_info = &info->axi_adc_info; - - ret = ad9467_scale_fill(conv); + ret = ad9467_scale_fill(st); if (ret) return ret; id = ad9467_spi_read(spi, AN877_ADC_REG_CHIP_ID); - if (id != conv->chip_info->id) { + if (id != st->info->id) { dev_err(&spi->dev, "Mismatch CHIP_ID, got 0x%X, expected 0x%X\n", - id, conv->chip_info->id); + id, st->info->id); return -ENODEV; } - conv->reg_access = ad9467_reg_access; - conv->write_raw = ad9467_write_raw; - conv->read_raw = ad9467_read_raw; - conv->read_avail = ad9467_read_avail; - conv->preenable_setup = ad9467_preenable_setup; + indio_dev->name = st->info->name; + indio_dev->channels = st->info->channels; + indio_dev->num_channels = st->info->num_channels; + indio_dev->info = &ad9467_info; - st->output_mode = info->default_output_mode | - AN877_ADC_OUTPUT_MODE_TWOS_COMPLEMENT; + ret = ad9467_iio_backend_get(st); + if (ret) + return ret; - return 0; + ret = devm_iio_backend_request_buffer(&spi->dev, st->back, indio_dev); + if (ret) + return ret; + + ret = devm_iio_backend_enable(&spi->dev, st->back); + if (ret) + return ret; + + ret = ad9467_setup(st); + if (ret) + return ret; + + return devm_iio_device_register(&spi->dev, indio_dev); } static const struct of_device_id ad9467_of_match[] = { @@ -529,4 +616,4 @@ module_spi_driver(ad9467_driver); MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>"); MODULE_DESCRIPTION("Analog Devices AD9467 ADC driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_ADI_AXI); +MODULE_IMPORT_NS(IIO_BACKEND); diff --git a/drivers/iio/adc/ad_sigma_delta.c b/drivers/iio/adc/ad_sigma_delta.c index 7e2192870743..fbba3f4a1189 100644 --- a/drivers/iio/adc/ad_sigma_delta.c +++ b/drivers/iio/adc/ad_sigma_delta.c @@ -568,6 +568,7 @@ EXPORT_SYMBOL_NS_GPL(ad_sd_validate_trigger, IIO_AD_SIGMA_DELTA); static int devm_ad_sd_probe_trigger(struct device *dev, struct iio_dev *indio_dev) { struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev); + unsigned long irq_flags = irq_get_trigger_type(sigma_delta->spi->irq); int ret; if (dev != &sigma_delta->spi->dev) { @@ -588,9 +589,13 @@ static int devm_ad_sd_probe_trigger(struct device *dev, struct iio_dev *indio_de /* the IRQ core clears IRQ_DISABLE_UNLAZY flag when freeing an IRQ */ irq_set_status_flags(sigma_delta->spi->irq, IRQ_DISABLE_UNLAZY); + /* Allow overwriting the flags from firmware */ + if (!irq_flags) + irq_flags = sigma_delta->info->irq_flags; + ret = devm_request_irq(dev, sigma_delta->spi->irq, ad_sd_data_rdy_trig_poll, - sigma_delta->info->irq_flags | IRQF_NO_AUTOEN, + irq_flags | IRQF_NO_AUTOEN, indio_dev->name, sigma_delta); if (ret) diff --git a/drivers/iio/adc/adi-axi-adc.c b/drivers/iio/adc/adi-axi-adc.c index c247ff1541d2..4156639b3c8b 100644 --- a/drivers/iio/adc/adi-axi-adc.c +++ b/drivers/iio/adc/adi-axi-adc.c @@ -8,6 +8,7 @@ #include <linux/bitfield.h> #include <linux/clk.h> +#include <linux/err.h> #include <linux/io.h> #include <linux/delay.h> #include <linux/module.h> @@ -17,13 +18,12 @@ #include <linux/regmap.h> #include <linux/slab.h> -#include <linux/iio/iio.h> -#include <linux/iio/sysfs.h> -#include <linux/iio/buffer.h> -#include <linux/iio/buffer-dmaengine.h> - #include <linux/fpga/adi-axi-common.h> -#include <linux/iio/adc/adi-axi-adc.h> + +#include <linux/iio/backend.h> +#include <linux/iio/buffer-dmaengine.h> +#include <linux/iio/buffer.h> +#include <linux/iio/iio.h> /* * Register definitions: @@ -44,6 +44,7 @@ #define ADI_AXI_REG_CHAN_CTRL_PN_SEL_OWR BIT(10) #define ADI_AXI_REG_CHAN_CTRL_IQCOR_EN BIT(9) #define ADI_AXI_REG_CHAN_CTRL_DCFILT_EN BIT(8) +#define ADI_AXI_REG_CHAN_CTRL_FMT_MASK GENMASK(6, 4) #define ADI_AXI_REG_CHAN_CTRL_FMT_SIGNEXT BIT(6) #define ADI_AXI_REG_CHAN_CTRL_FMT_TYPE BIT(5) #define ADI_AXI_REG_CHAN_CTRL_FMT_EN BIT(4) @@ -55,286 +56,100 @@ ADI_AXI_REG_CHAN_CTRL_FMT_EN | \ ADI_AXI_REG_CHAN_CTRL_ENABLE) -struct adi_axi_adc_core_info { - unsigned int version; -}; - struct adi_axi_adc_state { - struct mutex lock; - - struct adi_axi_adc_client *client; struct regmap *regmap; -}; - -struct adi_axi_adc_client { - struct list_head entry; - struct adi_axi_adc_conv conv; - struct adi_axi_adc_state *state; struct device *dev; - const struct adi_axi_adc_core_info *info; }; -static LIST_HEAD(registered_clients); -static DEFINE_MUTEX(registered_clients_lock); - -static struct adi_axi_adc_client *conv_to_client(struct adi_axi_adc_conv *conv) -{ - return container_of(conv, struct adi_axi_adc_client, conv); -} - -void *adi_axi_adc_conv_priv(struct adi_axi_adc_conv *conv) -{ - struct adi_axi_adc_client *cl = conv_to_client(conv); - - return (char *)cl + ALIGN(sizeof(struct adi_axi_adc_client), - IIO_DMA_MINALIGN); -} -EXPORT_SYMBOL_NS_GPL(adi_axi_adc_conv_priv, IIO_ADI_AXI); - -static int adi_axi_adc_config_dma_buffer(struct device *dev, - struct iio_dev *indio_dev) -{ - const char *dma_name; - - if (!device_property_present(dev, "dmas")) - return 0; - - if (device_property_read_string(dev, "dma-names", &dma_name)) - dma_name = "rx"; - - return devm_iio_dmaengine_buffer_setup(indio_dev->dev.parent, - indio_dev, dma_name); -} - -static int adi_axi_adc_read_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int *val, int *val2, long mask) -{ - struct adi_axi_adc_state *st = iio_priv(indio_dev); - struct adi_axi_adc_conv *conv = &st->client->conv; - - if (!conv->read_raw) - return -EOPNOTSUPP; - - return conv->read_raw(conv, chan, val, val2, mask); -} - -static int adi_axi_adc_write_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int val, int val2, long mask) -{ - struct adi_axi_adc_state *st = iio_priv(indio_dev); - struct adi_axi_adc_conv *conv = &st->client->conv; - - if (!conv->write_raw) - return -EOPNOTSUPP; - - return conv->write_raw(conv, chan, val, val2, mask); -} - -static int adi_axi_adc_read_avail(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - const int **vals, int *type, int *length, - long mask) -{ - struct adi_axi_adc_state *st = iio_priv(indio_dev); - struct adi_axi_adc_conv *conv = &st->client->conv; - - if (!conv->read_avail) - return -EOPNOTSUPP; - - return conv->read_avail(conv, chan, vals, type, length, mask); -} - -static int adi_axi_adc_update_scan_mode(struct iio_dev *indio_dev, - const unsigned long *scan_mask) +static int axi_adc_enable(struct iio_backend *back) { - struct adi_axi_adc_state *st = iio_priv(indio_dev); - struct adi_axi_adc_conv *conv = &st->client->conv; - unsigned int i; + struct adi_axi_adc_state *st = iio_backend_get_priv(back); int ret; - for (i = 0; i < conv->chip_info->num_channels; i++) { - if (test_bit(i, scan_mask)) - ret = regmap_set_bits(st->regmap, - ADI_AXI_REG_CHAN_CTRL(i), - ADI_AXI_REG_CHAN_CTRL_ENABLE); - else - ret = regmap_clear_bits(st->regmap, - ADI_AXI_REG_CHAN_CTRL(i), - ADI_AXI_REG_CHAN_CTRL_ENABLE); - if (ret) - return ret; - } - - return 0; -} - -static struct adi_axi_adc_conv *adi_axi_adc_conv_register(struct device *dev, - size_t sizeof_priv) -{ - struct adi_axi_adc_client *cl; - size_t alloc_size; - - alloc_size = ALIGN(sizeof(struct adi_axi_adc_client), IIO_DMA_MINALIGN); - if (sizeof_priv) - alloc_size += ALIGN(sizeof_priv, IIO_DMA_MINALIGN); - - cl = kzalloc(alloc_size, GFP_KERNEL); - if (!cl) - return ERR_PTR(-ENOMEM); - - mutex_lock(®istered_clients_lock); - - cl->dev = get_device(dev); - - list_add_tail(&cl->entry, ®istered_clients); - - mutex_unlock(®istered_clients_lock); + ret = regmap_set_bits(st->regmap, ADI_AXI_REG_RSTN, + ADI_AXI_REG_RSTN_MMCM_RSTN); + if (ret) + return ret; - return &cl->conv; + fsleep(10000); + return regmap_set_bits(st->regmap, ADI_AXI_REG_RSTN, + ADI_AXI_REG_RSTN_RSTN | ADI_AXI_REG_RSTN_MMCM_RSTN); } -static void adi_axi_adc_conv_unregister(struct adi_axi_adc_conv *conv) +static void axi_adc_disable(struct iio_backend *back) { - struct adi_axi_adc_client *cl = conv_to_client(conv); - - mutex_lock(®istered_clients_lock); - - list_del(&cl->entry); - put_device(cl->dev); + struct adi_axi_adc_state *st = iio_backend_get_priv(back); - mutex_unlock(®istered_clients_lock); - - kfree(cl); + regmap_write(st->regmap, ADI_AXI_REG_RSTN, 0); } -static void devm_adi_axi_adc_conv_release(void *conv) +static int axi_adc_data_format_set(struct iio_backend *back, unsigned int chan, + const struct iio_backend_data_fmt *data) { - adi_axi_adc_conv_unregister(conv); + struct adi_axi_adc_state *st = iio_backend_get_priv(back); + u32 val; + + if (!data->enable) + return regmap_clear_bits(st->regmap, + ADI_AXI_REG_CHAN_CTRL(chan), + ADI_AXI_REG_CHAN_CTRL_FMT_EN); + + val = FIELD_PREP(ADI_AXI_REG_CHAN_CTRL_FMT_EN, true); + if (data->sign_extend) + val |= FIELD_PREP(ADI_AXI_REG_CHAN_CTRL_FMT_SIGNEXT, true); + if (data->type == IIO_BACKEND_OFFSET_BINARY) + val |= FIELD_PREP(ADI_AXI_REG_CHAN_CTRL_FMT_TYPE, true); + + return regmap_update_bits(st->regmap, ADI_AXI_REG_CHAN_CTRL(chan), + ADI_AXI_REG_CHAN_CTRL_FMT_MASK, val); } -struct adi_axi_adc_conv *devm_adi_axi_adc_conv_register(struct device *dev, - size_t sizeof_priv) +static int axi_adc_chan_enable(struct iio_backend *back, unsigned int chan) { - struct adi_axi_adc_conv *conv; - int ret; - - conv = adi_axi_adc_conv_register(dev, sizeof_priv); - if (IS_ERR(conv)) - return conv; + struct adi_axi_adc_state *st = iio_backend_get_priv(back); - ret = devm_add_action_or_reset(dev, devm_adi_axi_adc_conv_release, - conv); - if (ret) - return ERR_PTR(ret); - - return conv; + return regmap_set_bits(st->regmap, ADI_AXI_REG_CHAN_CTRL(chan), + ADI_AXI_REG_CHAN_CTRL_ENABLE); } -EXPORT_SYMBOL_NS_GPL(devm_adi_axi_adc_conv_register, IIO_ADI_AXI); - -static const struct iio_info adi_axi_adc_info = { - .read_raw = &adi_axi_adc_read_raw, - .write_raw = &adi_axi_adc_write_raw, - .update_scan_mode = &adi_axi_adc_update_scan_mode, - .read_avail = &adi_axi_adc_read_avail, -}; - -static const struct adi_axi_adc_core_info adi_axi_adc_10_0_a_info = { - .version = ADI_AXI_PCORE_VER(10, 0, 'a'), -}; -static struct adi_axi_adc_client *adi_axi_adc_attach_client(struct device *dev) +static int axi_adc_chan_disable(struct iio_backend *back, unsigned int chan) { - const struct adi_axi_adc_core_info *info; - struct adi_axi_adc_client *cl; - struct device_node *cln; - - info = of_device_get_match_data(dev); - if (!info) - return ERR_PTR(-ENODEV); - - cln = of_parse_phandle(dev->of_node, "adi,adc-dev", 0); - if (!cln) { - dev_err(dev, "No 'adi,adc-dev' node defined\n"); - return ERR_PTR(-ENODEV); - } - - mutex_lock(®istered_clients_lock); - - list_for_each_entry(cl, ®istered_clients, entry) { - if (!cl->dev) - continue; - - if (cl->dev->of_node != cln) - continue; - - if (!try_module_get(cl->dev->driver->owner)) { - mutex_unlock(®istered_clients_lock); - of_node_put(cln); - return ERR_PTR(-ENODEV); - } - - get_device(cl->dev); - cl->info = info; - mutex_unlock(®istered_clients_lock); - of_node_put(cln); - return cl; - } + struct adi_axi_adc_state *st = iio_backend_get_priv(back); - mutex_unlock(®istered_clients_lock); - of_node_put(cln); - - return ERR_PTR(-EPROBE_DEFER); + return regmap_clear_bits(st->regmap, ADI_AXI_REG_CHAN_CTRL(chan), + ADI_AXI_REG_CHAN_CTRL_ENABLE); } -static int adi_axi_adc_setup_channels(struct device *dev, - struct adi_axi_adc_state *st) +static struct iio_buffer *axi_adc_request_buffer(struct iio_backend *back, + struct iio_dev *indio_dev) { - struct adi_axi_adc_conv *conv = &st->client->conv; - int i, ret; + struct adi_axi_adc_state *st = iio_backend_get_priv(back); + struct iio_buffer *buffer; + const char *dma_name; + int ret; - if (conv->preenable_setup) { - ret = conv->preenable_setup(conv); - if (ret) - return ret; - } + if (device_property_read_string(st->dev, "dma-names", &dma_name)) + dma_name = "rx"; - for (i = 0; i < conv->chip_info->num_channels; i++) { - ret = regmap_write(st->regmap, ADI_AXI_REG_CHAN_CTRL(i), - ADI_AXI_REG_CHAN_CTRL_DEFAULTS); - if (ret) - return ret; + buffer = iio_dmaengine_buffer_alloc(st->dev, dma_name); + if (IS_ERR(buffer)) { + dev_err(st->dev, "Could not get DMA buffer, %ld\n", + PTR_ERR(buffer)); + return ERR_CAST(buffer); } - return 0; -} - -static int axi_adc_reset(struct adi_axi_adc_state *st) -{ - int ret; - - ret = regmap_write(st->regmap, ADI_AXI_REG_RSTN, 0); - if (ret) - return ret; - - mdelay(10); - ret = regmap_write(st->regmap, ADI_AXI_REG_RSTN, - ADI_AXI_REG_RSTN_MMCM_RSTN); + indio_dev->modes |= INDIO_BUFFER_HARDWARE; + ret = iio_device_attach_buffer(indio_dev, buffer); if (ret) - return ret; + return ERR_PTR(ret); - mdelay(10); - return regmap_write(st->regmap, ADI_AXI_REG_RSTN, - ADI_AXI_REG_RSTN_RSTN | ADI_AXI_REG_RSTN_MMCM_RSTN); + return buffer; } -static void adi_axi_adc_cleanup(void *data) +static void axi_adc_free_buffer(struct iio_backend *back, + struct iio_buffer *buffer) { - struct adi_axi_adc_client *cl = data; - - put_device(cl->dev); - module_put(cl->dev->driver->owner); + iio_dmaengine_buffer_free(buffer); } static const struct regmap_config axi_adc_regmap_config = { @@ -344,45 +159,47 @@ static const struct regmap_config axi_adc_regmap_config = { .max_register = 0x0800, }; +static const struct iio_backend_ops adi_axi_adc_generic = { + .enable = axi_adc_enable, + .disable = axi_adc_disable, + .data_format_set = axi_adc_data_format_set, + .chan_enable = axi_adc_chan_enable, + .chan_disable = axi_adc_chan_disable, + .request_buffer = axi_adc_request_buffer, + .free_buffer = axi_adc_free_buffer, +}; + static int adi_axi_adc_probe(struct platform_device *pdev) { - struct adi_axi_adc_conv *conv; - struct iio_dev *indio_dev; - struct adi_axi_adc_client *cl; + const unsigned int *expected_ver; struct adi_axi_adc_state *st; void __iomem *base; unsigned int ver; int ret; - cl = adi_axi_adc_attach_client(&pdev->dev); - if (IS_ERR(cl)) - return PTR_ERR(cl); - - ret = devm_add_action_or_reset(&pdev->dev, adi_axi_adc_cleanup, cl); - if (ret) - return ret; - - indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*st)); - if (indio_dev == NULL) + st = devm_kzalloc(&pdev->dev, sizeof(*st), GFP_KERNEL); + if (!st) return -ENOMEM; - st = iio_priv(indio_dev); - st->client = cl; - cl->state = st; - mutex_init(&st->lock); - base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(base)) return PTR_ERR(base); + st->dev = &pdev->dev; st->regmap = devm_regmap_init_mmio(&pdev->dev, base, &axi_adc_regmap_config); if (IS_ERR(st->regmap)) return PTR_ERR(st->regmap); - conv = &st->client->conv; + expected_ver = device_get_match_data(&pdev->dev); + if (!expected_ver) + return -ENODEV; - ret = axi_adc_reset(st); + /* + * Force disable the core. Up to the frontend to enable us. And we can + * still read/write registers... + */ + ret = regmap_write(st->regmap, ADI_AXI_REG_RSTN, 0); if (ret) return ret; @@ -390,33 +207,19 @@ static int adi_axi_adc_probe(struct platform_device *pdev) if (ret) return ret; - if (cl->info->version > ver) { + if (*expected_ver > ver) { dev_err(&pdev->dev, "IP core version is too old. Expected %d.%.2d.%c, Reported %d.%.2d.%c\n", - ADI_AXI_PCORE_VER_MAJOR(cl->info->version), - ADI_AXI_PCORE_VER_MINOR(cl->info->version), - ADI_AXI_PCORE_VER_PATCH(cl->info->version), + ADI_AXI_PCORE_VER_MAJOR(*expected_ver), + ADI_AXI_PCORE_VER_MINOR(*expected_ver), + ADI_AXI_PCORE_VER_PATCH(*expected_ver), ADI_AXI_PCORE_VER_MAJOR(ver), ADI_AXI_PCORE_VER_MINOR(ver), ADI_AXI_PCORE_VER_PATCH(ver)); return -ENODEV; } - indio_dev->info = &adi_axi_adc_info; - indio_dev->name = "adi-axi-adc"; - indio_dev->modes = INDIO_DIRECT_MODE; - indio_dev->num_channels = conv->chip_info->num_channels; - indio_dev->channels = conv->chip_info->channels; - - ret = adi_axi_adc_config_dma_buffer(&pdev->dev, indio_dev); - if (ret) - return ret; - - ret = adi_axi_adc_setup_channels(&pdev->dev, st); - if (ret) - return ret; - - ret = devm_iio_device_register(&pdev->dev, indio_dev); + ret = devm_iio_backend_register(&pdev->dev, &adi_axi_adc_generic, st); if (ret) return ret; @@ -428,6 +231,8 @@ static int adi_axi_adc_probe(struct platform_device *pdev) return 0; } +static unsigned int adi_axi_adc_10_0_a_info = ADI_AXI_PCORE_VER(10, 0, 'a'); + /* Match table for of_platform binding */ static const struct of_device_id adi_axi_adc_of_match[] = { { .compatible = "adi,axi-adc-10.0.a", .data = &adi_axi_adc_10_0_a_info }, @@ -447,3 +252,5 @@ module_platform_driver(adi_axi_adc_driver); MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>"); MODULE_DESCRIPTION("Analog Devices Generic AXI ADC IP core driver"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(IIO_DMAENGINE_BUFFER); +MODULE_IMPORT_NS(IIO_BACKEND); diff --git a/drivers/iio/adc/max1363.c b/drivers/iio/adc/max1363.c index 7c2a98b8c3a9..8b5bc96cb9fb 100644 --- a/drivers/iio/adc/max1363.c +++ b/drivers/iio/adc/max1363.c @@ -357,62 +357,55 @@ static int max1363_read_single_chan(struct iio_dev *indio_dev, int *val, long m) { - int ret = 0; - s32 data; - u8 rxbuf[2]; - struct max1363_state *st = iio_priv(indio_dev); - struct i2c_client *client = st->client; - - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; - mutex_lock(&st->lock); - - /* - * If monitor mode is enabled, the method for reading a single - * channel will have to be rather different and has not yet - * been implemented. - * - * Also, cannot read directly if buffered capture enabled. - */ - if (st->monitor_on) { - ret = -EBUSY; - goto error_ret; - } - - /* Check to see if current scan mode is correct */ - if (st->current_mode != &max1363_mode_table[chan->address]) { - /* Update scan mode if needed */ - st->current_mode = &max1363_mode_table[chan->address]; - ret = max1363_set_scan_mode(st); - if (ret < 0) - goto error_ret; - } - if (st->chip_info->bits != 8) { - /* Get reading */ - data = st->recv(client, rxbuf, 2); - if (data < 0) { - ret = data; - goto error_ret; + iio_device_claim_direct_scoped(return -EBUSY, indio_dev) { + s32 data; + u8 rxbuf[2]; + struct max1363_state *st = iio_priv(indio_dev); + struct i2c_client *client = st->client; + + guard(mutex)(&st->lock); + + /* + * If monitor mode is enabled, the method for reading a single + * channel will have to be rather different and has not yet + * been implemented. + * + * Also, cannot read directly if buffered capture enabled. + */ + if (st->monitor_on) + return -EBUSY; + + /* Check to see if current scan mode is correct */ + if (st->current_mode != &max1363_mode_table[chan->address]) { + int ret; + + /* Update scan mode if needed */ + st->current_mode = &max1363_mode_table[chan->address]; + ret = max1363_set_scan_mode(st); + if (ret < 0) + return ret; } - data = (rxbuf[1] | rxbuf[0] << 8) & - ((1 << st->chip_info->bits) - 1); - } else { - /* Get reading */ - data = st->recv(client, rxbuf, 1); - if (data < 0) { - ret = data; - goto error_ret; + if (st->chip_info->bits != 8) { + /* Get reading */ + data = st->recv(client, rxbuf, 2); + if (data < 0) + return data; + + data = (rxbuf[1] | rxbuf[0] << 8) & + ((1 << st->chip_info->bits) - 1); + } else { + /* Get reading */ + data = st->recv(client, rxbuf, 1); + if (data < 0) + return data; + + data = rxbuf[0]; } - data = rxbuf[0]; - } - *val = data; - -error_ret: - mutex_unlock(&st->lock); - iio_device_release_direct_mode(indio_dev); - return ret; + *val = data; + return 0; + } + unreachable(); } static int max1363_read_raw(struct iio_dev *indio_dev, @@ -710,9 +703,8 @@ static ssize_t max1363_monitor_store_freq(struct device *dev, if (!found) return -EINVAL; - mutex_lock(&st->lock); - st->monitor_speed = i; - mutex_unlock(&st->lock); + scoped_guard(mutex, &st->lock) + st->monitor_speed = i; return 0; } @@ -815,12 +807,11 @@ static int max1363_read_event_config(struct iio_dev *indio_dev, int val; int number = chan->channel; - mutex_lock(&st->lock); + guard(mutex)(&st->lock); if (dir == IIO_EV_DIR_FALLING) val = (1 << number) & st->mask_low; else val = (1 << number) & st->mask_high; - mutex_unlock(&st->lock); return val; } @@ -962,46 +953,42 @@ static int max1363_write_event_config(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, enum iio_event_type type, enum iio_event_direction dir, int state) { - int ret = 0; struct max1363_state *st = iio_priv(indio_dev); - u16 unifiedmask; - int number = chan->channel; - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; - mutex_lock(&st->lock); - - unifiedmask = st->mask_low | st->mask_high; - if (dir == IIO_EV_DIR_FALLING) { - - if (state == 0) - st->mask_low &= ~(1 << number); - else { - ret = __max1363_check_event_mask((1 << number), - unifiedmask); - if (ret) - goto error_ret; - st->mask_low |= (1 << number); - } - } else { - if (state == 0) - st->mask_high &= ~(1 << number); - else { - ret = __max1363_check_event_mask((1 << number), - unifiedmask); - if (ret) - goto error_ret; - st->mask_high |= (1 << number); + iio_device_claim_direct_scoped(return -EBUSY, indio_dev) { + int number = chan->channel; + u16 unifiedmask; + int ret; + + guard(mutex)(&st->lock); + + unifiedmask = st->mask_low | st->mask_high; + if (dir == IIO_EV_DIR_FALLING) { + + if (state == 0) + st->mask_low &= ~(1 << number); + else { + ret = __max1363_check_event_mask((1 << number), + unifiedmask); + if (ret) + return ret; + st->mask_low |= (1 << number); + } + } else { + if (state == 0) + st->mask_high &= ~(1 << number); + else { + ret = __max1363_check_event_mask((1 << number), + unifiedmask); + if (ret) + return ret; + st->mask_high |= (1 << number); + } } } - max1363_monitor_mode_update(st, !!(st->mask_high | st->mask_low)); -error_ret: - mutex_unlock(&st->lock); - iio_device_release_direct_mode(indio_dev); - return ret; + return 0; } /* diff --git a/drivers/iio/adc/rtq6056.c b/drivers/iio/adc/rtq6056.c index ad4cea6839b2..a5464737e527 100644 --- a/drivers/iio/adc/rtq6056.c +++ b/drivers/iio/adc/rtq6056.c @@ -39,6 +39,10 @@ #define RTQ6056_DEFAULT_CONFIG 0x4127 #define RTQ6056_CONT_ALLON 7 +#define RTQ6059_DEFAULT_CONFIG 0x3C47 +#define RTQ6059_VBUS_LSB_OFFSET 3 +#define RTQ6059_AVG_BASE 8 + enum { RTQ6056_CH_VSHUNT = 0, RTQ6056_CH_VBUS, @@ -47,19 +51,46 @@ enum { RTQ6056_MAX_CHANNEL }; +/* + * The enum is to present the 0x00 CONFIG RG bitfield for the 16bit RG value + * field value order from LSB to MSB + * RTQ6053/6 is OPMODE->VSHUNTCT->VBUSCT->AVG->RESET + * RTQ6059 is OPMODE->SADC->BADC->PGA->RESET + */ enum { F_OPMODE = 0, F_VSHUNTCT, + F_RTQ6059_SADC = F_VSHUNTCT, F_VBUSCT, + F_RTQ6059_BADC = F_VBUSCT, F_AVG, + F_RTQ6059_PGA = F_AVG, F_RESET, F_MAX_FIELDS }; +struct rtq6056_priv; + +struct richtek_dev_data { + bool fixed_samp_freq; + u8 vbus_offset; + int default_conv_time_us; + unsigned int default_config; + unsigned int calib_coefficient; + const int *avg_sample_list; + int avg_sample_list_length; + const struct reg_field *reg_fields; + const struct iio_chan_spec *channels; + int num_channels; + int (*read_scale)(struct iio_chan_spec const *ch, int *val, int *val2); + int (*set_average)(struct rtq6056_priv *priv, int val); +}; + struct rtq6056_priv { struct device *dev; struct regmap *regmap; struct regmap_field *rm_fields[F_MAX_FIELDS]; + const struct richtek_dev_data *devdata; u32 shunt_resistor_uohm; int vshuntct_us; int vbusct_us; @@ -74,6 +105,14 @@ static const struct reg_field rtq6056_reg_fields[F_MAX_FIELDS] = { [F_RESET] = REG_FIELD(RTQ6056_REG_CONFIG, 15, 15), }; +static const struct reg_field rtq6059_reg_fields[F_MAX_FIELDS] = { + [F_OPMODE] = REG_FIELD(RTQ6056_REG_CONFIG, 0, 2), + [F_RTQ6059_SADC] = REG_FIELD(RTQ6056_REG_CONFIG, 3, 6), + [F_RTQ6059_BADC] = REG_FIELD(RTQ6056_REG_CONFIG, 7, 10), + [F_RTQ6059_PGA] = REG_FIELD(RTQ6056_REG_CONFIG, 11, 12), + [F_RESET] = REG_FIELD(RTQ6056_REG_CONFIG, 15, 15), +}; + static const struct iio_chan_spec rtq6056_channels[RTQ6056_MAX_CHANNEL + 1] = { { .type = IIO_VOLTAGE, @@ -151,10 +190,93 @@ static const struct iio_chan_spec rtq6056_channels[RTQ6056_MAX_CHANNEL + 1] = { IIO_CHAN_SOFT_TIMESTAMP(RTQ6056_MAX_CHANNEL), }; +/* + * Difference between RTQ6056 and RTQ6059 + * - Fixed sampling conversion time + * - Average sample numbers + * - Channel scale + * - calibration coefficient + */ +static const struct iio_chan_spec rtq6059_channels[RTQ6056_MAX_CHANNEL + 1] = { + { + .type = IIO_VOLTAGE, + .indexed = 1, + .channel = 0, + .address = RTQ6056_REG_SHUNTVOLT, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_SAMP_FREQ), + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), + .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), + .scan_index = 0, + .scan_type = { + .sign = 's', + .realbits = 16, + .storagebits = 16, + .endianness = IIO_CPU, + }, + }, + { + .type = IIO_VOLTAGE, + .indexed = 1, + .channel = 1, + .address = RTQ6056_REG_BUSVOLT, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_SAMP_FREQ), + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), + .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), + .scan_index = 1, + .scan_type = { + .sign = 'u', + .realbits = 16, + .storagebits = 16, + .endianness = IIO_CPU, + }, + }, + { + .type = IIO_POWER, + .indexed = 1, + .channel = 2, + .address = RTQ6056_REG_POWER, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_SAMP_FREQ), + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), + .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), + .scan_index = 2, + .scan_type = { + .sign = 'u', + .realbits = 16, + .storagebits = 16, + .endianness = IIO_CPU, + }, + }, + { + .type = IIO_CURRENT, + .indexed = 1, + .channel = 3, + .address = RTQ6056_REG_CURRENT, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SAMP_FREQ), + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), + .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), + .scan_index = 3, + .scan_type = { + .sign = 's', + .realbits = 16, + .storagebits = 16, + .endianness = IIO_CPU, + }, + }, + IIO_CHAN_SOFT_TIMESTAMP(RTQ6056_MAX_CHANNEL), +}; + static int rtq6056_adc_read_channel(struct rtq6056_priv *priv, struct iio_chan_spec const *ch, int *val) { + const struct richtek_dev_data *devdata = priv->devdata; struct device *dev = priv->dev; unsigned int addr = ch->address; unsigned int regval; @@ -168,12 +290,21 @@ static int rtq6056_adc_read_channel(struct rtq6056_priv *priv, return ret; /* Power and VBUS is unsigned 16-bit, others are signed 16-bit */ - if (addr == RTQ6056_REG_BUSVOLT || addr == RTQ6056_REG_POWER) + switch (addr) { + case RTQ6056_REG_BUSVOLT: + regval >>= devdata->vbus_offset; *val = regval; - else + return IIO_VAL_INT; + case RTQ6056_REG_POWER: + *val = regval; + return IIO_VAL_INT; + case RTQ6056_REG_SHUNTVOLT: + case RTQ6056_REG_CURRENT: *val = sign_extend32(regval, 16); - - return IIO_VAL_INT; + return IIO_VAL_INT; + default: + return -EINVAL; + } } static int rtq6056_adc_read_scale(struct iio_chan_spec const *ch, int *val, @@ -199,6 +330,28 @@ static int rtq6056_adc_read_scale(struct iio_chan_spec const *ch, int *val, } } +static int rtq6059_adc_read_scale(struct iio_chan_spec const *ch, int *val, + int *val2) +{ + switch (ch->address) { + case RTQ6056_REG_SHUNTVOLT: + /* VSHUNT lsb 10uV */ + *val = 10000; + *val2 = 1000000; + return IIO_VAL_FRACTIONAL; + case RTQ6056_REG_BUSVOLT: + /* VBUS lsb 4mV */ + *val = 4; + return IIO_VAL_INT; + case RTQ6056_REG_POWER: + /* Power lsb 20mW */ + *val = 20; + return IIO_VAL_INT; + default: + return -EINVAL; + } +} + /* * Sample frequency for channel VSHUNT and VBUS. The indices correspond * with the bit value expected by the chip. And it can be found at @@ -248,6 +401,10 @@ static const int rtq6056_avg_sample_list[] = { 1, 4, 16, 64, 128, 256, 512, 1024, }; +static const int rtq6059_avg_sample_list[] = { + 1, 2, 4, 8, 16, 32, 64, 128, +}; + static int rtq6056_adc_set_average(struct rtq6056_priv *priv, int val) { unsigned int selector; @@ -268,6 +425,30 @@ static int rtq6056_adc_set_average(struct rtq6056_priv *priv, int val) return 0; } +static int rtq6059_adc_set_average(struct rtq6056_priv *priv, int val) +{ + unsigned int selector; + int ret; + + if (val > 128 || val < 1) + return -EINVAL; + + /* The supported average sample is 2^x (x from 0 to 7) */ + selector = fls(val) - 1; + + ret = regmap_field_write(priv->rm_fields[F_RTQ6059_BADC], + RTQ6059_AVG_BASE + selector); + if (ret) + return ret; + + ret = regmap_field_write(priv->rm_fields[F_RTQ6059_SADC], + RTQ6059_AVG_BASE + selector); + + priv->avg_sample = BIT(selector); + + return 0; +} + static int rtq6056_adc_get_sample_freq(struct rtq6056_priv *priv, struct iio_chan_spec const *ch, int *val) { @@ -292,12 +473,13 @@ static int rtq6056_adc_read_raw(struct iio_dev *indio_dev, int *val2, long mask) { struct rtq6056_priv *priv = iio_priv(indio_dev); + const struct richtek_dev_data *devdata = priv->devdata; switch (mask) { case IIO_CHAN_INFO_RAW: return rtq6056_adc_read_channel(priv, chan, val); case IIO_CHAN_INFO_SCALE: - return rtq6056_adc_read_scale(chan, val, val2); + return devdata->read_scale(chan, val, val2); case IIO_CHAN_INFO_OVERSAMPLING_RATIO: *val = priv->avg_sample; return IIO_VAL_INT; @@ -313,6 +495,9 @@ static int rtq6056_adc_read_avail(struct iio_dev *indio_dev, const int **vals, int *type, int *length, long mask) { + struct rtq6056_priv *priv = iio_priv(indio_dev); + const struct richtek_dev_data *devdata = priv->devdata; + switch (mask) { case IIO_CHAN_INFO_SAMP_FREQ: *vals = rtq6056_samp_freq_list; @@ -320,9 +505,9 @@ static int rtq6056_adc_read_avail(struct iio_dev *indio_dev, *length = ARRAY_SIZE(rtq6056_samp_freq_list); return IIO_AVAIL_LIST; case IIO_CHAN_INFO_OVERSAMPLING_RATIO: - *vals = rtq6056_avg_sample_list; + *vals = devdata->avg_sample_list; + *length = devdata->avg_sample_list_length; *type = IIO_VAL_INT; - *length = ARRAY_SIZE(rtq6056_avg_sample_list); return IIO_AVAIL_LIST; default: return -EINVAL; @@ -334,6 +519,7 @@ static int rtq6056_adc_write_raw(struct iio_dev *indio_dev, int val2, long mask) { struct rtq6056_priv *priv = iio_priv(indio_dev); + const struct richtek_dev_data *devdata = priv->devdata; int ret; ret = iio_device_claim_direct_mode(indio_dev); @@ -342,10 +528,15 @@ static int rtq6056_adc_write_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_SAMP_FREQ: + if (devdata->fixed_samp_freq) { + ret = -EINVAL; + break; + } + ret = rtq6056_adc_set_samp_freq(priv, chan, val); break; case IIO_CHAN_INFO_OVERSAMPLING_RATIO: - ret = rtq6056_adc_set_average(priv, val); + ret = devdata->set_average(priv, val); break; default: ret = -EINVAL; @@ -374,6 +565,7 @@ static int rtq6056_adc_read_label(struct iio_dev *indio_dev, static int rtq6056_set_shunt_resistor(struct rtq6056_priv *priv, int resistor_uohm) { + const struct richtek_dev_data *devdata = priv->devdata; unsigned int calib_val; int ret; @@ -382,8 +574,8 @@ static int rtq6056_set_shunt_resistor(struct rtq6056_priv *priv, return -EINVAL; } - /* calibration = 5120000 / (Rshunt (uOhm) * current lsb (1mA)) */ - calib_val = 5120000 / resistor_uohm; + /* calibration = coefficient / (Rshunt (uOhm) * current lsb (1mA)) */ + calib_val = devdata->calib_coefficient / resistor_uohm; ret = regmap_write(priv->regmap, RTQ6056_REG_CALIBRATION, calib_val); if (ret) return ret; @@ -450,6 +642,7 @@ static irqreturn_t rtq6056_buffer_trigger_handler(int irq, void *p) struct iio_poll_func *pf = p; struct iio_dev *indio_dev = pf->indio_dev; struct rtq6056_priv *priv = iio_priv(indio_dev); + const struct richtek_dev_data *devdata = priv->devdata; struct device *dev = priv->dev; struct { u16 vals[RTQ6056_MAX_CHANNEL]; @@ -469,6 +662,9 @@ static irqreturn_t rtq6056_buffer_trigger_handler(int irq, void *p) if (ret) goto out; + if (addr == RTQ6056_REG_BUSVOLT) + raw >>= devdata->vbus_offset; + data.vals[i++] = raw; } @@ -528,20 +724,26 @@ static int rtq6056_probe(struct i2c_client *i2c) struct rtq6056_priv *priv; struct device *dev = &i2c->dev; struct regmap *regmap; + const struct richtek_dev_data *devdata; unsigned int vendor_id, shunt_resistor_uohm; int ret; if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_WORD_DATA)) return -EOPNOTSUPP; + devdata = device_get_match_data(dev); + if (!devdata) + return dev_err_probe(dev, -EINVAL, "Invalid dev data\n"); + indio_dev = devm_iio_device_alloc(dev, sizeof(*priv)); if (!indio_dev) return -ENOMEM; priv = iio_priv(indio_dev); priv->dev = dev; - priv->vshuntct_us = priv->vbusct_us = 1037; + priv->vshuntct_us = priv->vbusct_us = devdata->default_conv_time_us; priv->avg_sample = 1; + priv->devdata = devdata; i2c_set_clientdata(i2c, priv); regmap = devm_regmap_init_i2c(i2c, &rtq6056_regmap_config); @@ -561,15 +763,11 @@ static int rtq6056_probe(struct i2c_client *i2c) "Invalid vendor id 0x%04x\n", vendor_id); ret = devm_regmap_field_bulk_alloc(dev, regmap, priv->rm_fields, - rtq6056_reg_fields, F_MAX_FIELDS); + devdata->reg_fields, F_MAX_FIELDS); if (ret) return dev_err_probe(dev, ret, "Failed to init regmap field\n"); - /* - * By default, configure average sample as 1, bus and shunt conversion - * time as 1037 microsecond, and operating mode to all on. - */ - ret = regmap_write(regmap, RTQ6056_REG_CONFIG, RTQ6056_DEFAULT_CONFIG); + ret = regmap_write(regmap, RTQ6056_REG_CONFIG, devdata->default_config); if (ret) return dev_err_probe(dev, ret, "Failed to enable continuous sensing\n"); @@ -598,8 +796,8 @@ static int rtq6056_probe(struct i2c_client *i2c) indio_dev->name = "rtq6056"; indio_dev->modes = INDIO_DIRECT_MODE; - indio_dev->channels = rtq6056_channels; - indio_dev->num_channels = ARRAY_SIZE(rtq6056_channels); + indio_dev->channels = devdata->channels; + indio_dev->num_channels = devdata->num_channels; indio_dev->info = &rtq6056_info; ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL, @@ -640,8 +838,45 @@ static int rtq6056_runtime_resume(struct device *dev) static DEFINE_RUNTIME_DEV_PM_OPS(rtq6056_pm_ops, rtq6056_runtime_suspend, rtq6056_runtime_resume, NULL); +static const struct richtek_dev_data rtq6056_devdata = { + .default_conv_time_us = 1037, + .calib_coefficient = 5120000, + /* + * By default, configure average sample as 1, bus and shunt conversion + * time as 1037 microsecond, and operating mode to all on. + */ + .default_config = RTQ6056_DEFAULT_CONFIG, + .avg_sample_list = rtq6056_avg_sample_list, + .avg_sample_list_length = ARRAY_SIZE(rtq6056_avg_sample_list), + .reg_fields = rtq6056_reg_fields, + .channels = rtq6056_channels, + .num_channels = ARRAY_SIZE(rtq6056_channels), + .read_scale = rtq6056_adc_read_scale, + .set_average = rtq6056_adc_set_average, +}; + +static const struct richtek_dev_data rtq6059_devdata = { + .fixed_samp_freq = true, + .vbus_offset = RTQ6059_VBUS_LSB_OFFSET, + .default_conv_time_us = 532, + .calib_coefficient = 40960000, + /* + * By default, configure average sample as 1, bus and shunt conversion + * time as 532 microsecond, and operating mode to all on. + */ + .default_config = RTQ6059_DEFAULT_CONFIG, + .avg_sample_list = rtq6059_avg_sample_list, + .avg_sample_list_length = ARRAY_SIZE(rtq6059_avg_sample_list), + .reg_fields = rtq6059_reg_fields, + .channels = rtq6059_channels, + .num_channels = ARRAY_SIZE(rtq6059_channels), + .read_scale = rtq6059_adc_read_scale, + .set_average = rtq6059_adc_set_average, +}; + static const struct of_device_id rtq6056_device_match[] = { - { .compatible = "richtek,rtq6056" }, + { .compatible = "richtek,rtq6056", .data = &rtq6056_devdata }, + { .compatible = "richtek,rtq6059", .data = &rtq6059_devdata }, {} }; MODULE_DEVICE_TABLE(of, rtq6056_device_match); diff --git a/drivers/iio/adc/ti-adc108s102.c b/drivers/iio/adc/ti-adc108s102.c index c82a161630e1..69fcbbc7e418 100644 --- a/drivers/iio/adc/ti-adc108s102.c +++ b/drivers/iio/adc/ti-adc108s102.c @@ -293,13 +293,11 @@ static const struct of_device_id adc108s102_of_match[] = { }; MODULE_DEVICE_TABLE(of, adc108s102_of_match); -#ifdef CONFIG_ACPI static const struct acpi_device_id adc108s102_acpi_ids[] = { { "INT3495", 0 }, { } }; MODULE_DEVICE_TABLE(acpi, adc108s102_acpi_ids); -#endif static const struct spi_device_id adc108s102_id[] = { { "adc108s102", 0 }, @@ -311,7 +309,7 @@ static struct spi_driver adc108s102_driver = { .driver = { .name = "adc108s102", .of_match_table = adc108s102_of_match, - .acpi_match_table = ACPI_PTR(adc108s102_acpi_ids), + .acpi_match_table = adc108s102_acpi_ids, }, .probe = adc108s102_probe, .id_table = adc108s102_id, diff --git a/drivers/iio/adc/ti-ads1015.c b/drivers/iio/adc/ti-ads1015.c index 6799ea49dbc7..6ae967e4d8fa 100644 --- a/drivers/iio/adc/ti-ads1015.c +++ b/drivers/iio/adc/ti-ads1015.c @@ -925,7 +925,7 @@ static int ads1015_client_get_channels_config(struct i2c_client *client) if (!fwnode_property_read_u32(node, "ti,gain", &pval)) { pga = pval; - if (pga > 6) { + if (pga > 5) { dev_err(dev, "invalid gain on %pfw\n", node); fwnode_handle_put(node); return -EINVAL; diff --git a/drivers/iio/adc/ti-ads1298.c b/drivers/iio/adc/ti-ads1298.c new file mode 100644 index 000000000000..ed895a30beed --- /dev/null +++ b/drivers/iio/adc/ti-ads1298.c @@ -0,0 +1,769 @@ +// SPDX-License-Identifier: GPL-2.0 +/* TI ADS1298 chip family driver + * Copyright (C) 2023 - 2024 Topic Embedded Products + */ + +#include <linux/bitfield.h> +#include <linux/cleanup.h> +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/gpio/consumer.h> +#include <linux/log2.h> +#include <linux/math.h> +#include <linux/module.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> +#include <linux/slab.h> +#include <linux/spi/spi.h> +#include <linux/units.h> + +#include <linux/iio/iio.h> +#include <linux/iio/buffer.h> +#include <linux/iio/kfifo_buf.h> + +#include <asm/unaligned.h> + +/* Commands */ +#define ADS1298_CMD_WAKEUP 0x02 +#define ADS1298_CMD_STANDBY 0x04 +#define ADS1298_CMD_RESET 0x06 +#define ADS1298_CMD_START 0x08 +#define ADS1298_CMD_STOP 0x0a +#define ADS1298_CMD_RDATAC 0x10 +#define ADS1298_CMD_SDATAC 0x11 +#define ADS1298_CMD_RDATA 0x12 +#define ADS1298_CMD_RREG 0x20 +#define ADS1298_CMD_WREG 0x40 + +/* Registers */ +#define ADS1298_REG_ID 0x00 +#define ADS1298_MASK_ID_FAMILY GENMASK(7, 3) +#define ADS1298_MASK_ID_CHANNELS GENMASK(2, 0) +#define ADS1298_ID_FAMILY_ADS129X 0x90 +#define ADS1298_ID_FAMILY_ADS129XR 0xd0 + +#define ADS1298_REG_CONFIG1 0x01 +#define ADS1298_MASK_CONFIG1_HR BIT(7) +#define ADS1298_MASK_CONFIG1_DR GENMASK(2, 0) +#define ADS1298_SHIFT_DR_HR 6 +#define ADS1298_SHIFT_DR_LP 7 +#define ADS1298_LOWEST_DR 0x06 + +#define ADS1298_REG_CONFIG2 0x02 +#define ADS1298_MASK_CONFIG2_RESERVED BIT(6) +#define ADS1298_MASK_CONFIG2_WCT_CHOP BIT(5) +#define ADS1298_MASK_CONFIG2_INT_TEST BIT(4) +#define ADS1298_MASK_CONFIG2_TEST_AMP BIT(2) +#define ADS1298_MASK_CONFIG2_TEST_FREQ_DC GENMASK(1, 0) +#define ADS1298_MASK_CONFIG2_TEST_FREQ_SLOW 0 +#define ADS1298_MASK_CONFIG2_TEST_FREQ_FAST BIT(0) + +#define ADS1298_REG_CONFIG3 0x03 +#define ADS1298_MASK_CONFIG3_PWR_REFBUF BIT(7) +#define ADS1298_MASK_CONFIG3_RESERVED BIT(6) +#define ADS1298_MASK_CONFIG3_VREF_4V BIT(5) + +#define ADS1298_REG_LOFF 0x04 +#define ADS1298_REG_CHnSET(n) (0x05 + n) +#define ADS1298_MASK_CH_PD BIT(7) +#define ADS1298_MASK_CH_PGA GENMASK(6, 4) +#define ADS1298_MASK_CH_MUX GENMASK(2, 0) + +#define ADS1298_REG_LOFF_STATP 0x12 +#define ADS1298_REG_LOFF_STATN 0x13 +#define ADS1298_REG_CONFIG4 0x17 +#define ADS1298_MASK_CONFIG4_SINGLE_SHOT BIT(3) + +#define ADS1298_REG_WCT1 0x18 +#define ADS1298_REG_WCT2 0x19 + +#define ADS1298_MAX_CHANNELS 8 +#define ADS1298_BITS_PER_SAMPLE 24 +#define ADS1298_CLK_RATE_HZ 2048000 +#define ADS1298_CLOCKS_TO_USECS(x) \ + (DIV_ROUND_UP((x) * MICROHZ_PER_HZ, ADS1298_CLK_RATE_HZ)) +/* + * Read/write register commands require 4 clocks to decode, for speeds above + * 2x the clock rate, this would require extra time between the command byte and + * the data. Much simpler is to just limit the SPI transfer speed while doing + * register access. + */ +#define ADS1298_SPI_BUS_SPEED_SLOW ADS1298_CLK_RATE_HZ +/* For reading and writing registers, we need a 3-byte buffer */ +#define ADS1298_SPI_CMD_BUFFER_SIZE 3 +/* Outputs status word and 'n' 24-bit samples, plus the command byte */ +#define ADS1298_SPI_RDATA_BUFFER_SIZE(n) (((n) + 1) * 3 + 1) +#define ADS1298_SPI_RDATA_BUFFER_SIZE_MAX \ + ADS1298_SPI_RDATA_BUFFER_SIZE(ADS1298_MAX_CHANNELS) + +struct ads1298_private { + const struct ads1298_chip_info *chip_info; + struct spi_device *spi; + struct regulator *reg_avdd; + struct regulator *reg_vref; + struct clk *clk; + struct regmap *regmap; + struct completion completion; + struct iio_trigger *trig; + struct spi_transfer rdata_xfer; + struct spi_message rdata_msg; + spinlock_t irq_busy_lock; /* Handshake between SPI and DRDY irqs */ + /* + * rdata_xfer_busy increments when a DRDY occurs and decrements when SPI + * completion is reported. Hence its meaning is: + * 0 = Waiting for DRDY interrupt + * 1 = SPI transfer in progress + * 2 = DRDY during SPI transfer, start another transfer on completion + * >2 = Multiple DRDY during transfer, lost rdata_xfer_busy - 2 samples + */ + unsigned int rdata_xfer_busy; + + /* Temporary storage for demuxing data after SPI transfer */ + u32 bounce_buffer[ADS1298_MAX_CHANNELS]; + + /* For synchronous SPI exchanges (read/write registers) */ + u8 cmd_buffer[ADS1298_SPI_CMD_BUFFER_SIZE] __aligned(IIO_DMA_MINALIGN); + + /* Buffer used for incoming SPI data */ + u8 rx_buffer[ADS1298_SPI_RDATA_BUFFER_SIZE_MAX]; + /* Contains the RDATA command and zeroes to clock out */ + u8 tx_buffer[ADS1298_SPI_RDATA_BUFFER_SIZE_MAX]; +}; + +/* Three bytes per sample in RX buffer, starting at offset 4 */ +#define ADS1298_OFFSET_IN_RX_BUFFER(index) (3 * (index) + 4) + +#define ADS1298_CHAN(index) \ +{ \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .channel = index, \ + .address = ADS1298_OFFSET_IN_RX_BUFFER(index), \ + .info_mask_separate = \ + BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SCALE), \ + .info_mask_shared_by_all = \ + BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ + .scan_index = index, \ + .scan_type = { \ + .sign = 's', \ + .realbits = ADS1298_BITS_PER_SAMPLE, \ + .storagebits = 32, \ + .endianness = IIO_CPU, \ + }, \ +} + +static const struct iio_chan_spec ads1298_channels[] = { + ADS1298_CHAN(0), + ADS1298_CHAN(1), + ADS1298_CHAN(2), + ADS1298_CHAN(3), + ADS1298_CHAN(4), + ADS1298_CHAN(5), + ADS1298_CHAN(6), + ADS1298_CHAN(7), +}; + +static int ads1298_write_cmd(struct ads1298_private *priv, u8 command) +{ + struct spi_transfer xfer = { + .tx_buf = priv->cmd_buffer, + .rx_buf = priv->cmd_buffer, + .len = 1, + .speed_hz = ADS1298_SPI_BUS_SPEED_SLOW, + .delay = { + .value = 2, + .unit = SPI_DELAY_UNIT_USECS, + }, + }; + + priv->cmd_buffer[0] = command; + + return spi_sync_transfer(priv->spi, &xfer, 1); +} + +static int ads1298_read_one(struct ads1298_private *priv, int chan_index) +{ + int ret; + + /* Enable the channel */ + ret = regmap_update_bits(priv->regmap, ADS1298_REG_CHnSET(chan_index), + ADS1298_MASK_CH_PD, 0); + if (ret) + return ret; + + /* Enable single-shot mode, so we don't need to send a STOP */ + ret = regmap_update_bits(priv->regmap, ADS1298_REG_CONFIG4, + ADS1298_MASK_CONFIG4_SINGLE_SHOT, + ADS1298_MASK_CONFIG4_SINGLE_SHOT); + if (ret) + return ret; + + reinit_completion(&priv->completion); + + ret = ads1298_write_cmd(priv, ADS1298_CMD_START); + if (ret < 0) { + dev_err(&priv->spi->dev, "CMD_START error: %d\n", ret); + return ret; + } + + /* Cannot take longer than 40ms (250Hz) */ + ret = wait_for_completion_timeout(&priv->completion, msecs_to_jiffies(50)); + if (!ret) + return -ETIMEDOUT; + + return 0; +} + +static int ads1298_get_samp_freq(struct ads1298_private *priv, int *val) +{ + unsigned long rate; + unsigned int cfg; + int ret; + + ret = regmap_read(priv->regmap, ADS1298_REG_CONFIG1, &cfg); + if (ret) + return ret; + + if (priv->clk) + rate = clk_get_rate(priv->clk); + else + rate = ADS1298_CLK_RATE_HZ; + if (!rate) + return -EINVAL; + + /* Data rate shift depends on HR/LP mode */ + if (cfg & ADS1298_MASK_CONFIG1_HR) + rate >>= ADS1298_SHIFT_DR_HR; + else + rate >>= ADS1298_SHIFT_DR_LP; + + *val = rate >> (cfg & ADS1298_MASK_CONFIG1_DR); + + return IIO_VAL_INT; +} + +static int ads1298_set_samp_freq(struct ads1298_private *priv, int val) +{ + unsigned long rate; + unsigned int factor; + unsigned int cfg; + + if (priv->clk) + rate = clk_get_rate(priv->clk); + else + rate = ADS1298_CLK_RATE_HZ; + if (!rate) + return -EINVAL; + + factor = (rate >> ADS1298_SHIFT_DR_HR) / val; + if (factor >= BIT(ADS1298_SHIFT_DR_LP)) + cfg = ADS1298_LOWEST_DR; + else if (factor) + cfg = ADS1298_MASK_CONFIG1_HR | ilog2(factor); /* Use HR mode */ + else + cfg = ADS1298_MASK_CONFIG1_HR; /* Fastest possible */ + + return regmap_update_bits(priv->regmap, ADS1298_REG_CONFIG1, + ADS1298_MASK_CONFIG1_HR | ADS1298_MASK_CONFIG1_DR, + cfg); +} + +static const u8 ads1298_pga_settings[] = { 6, 1, 2, 3, 4, 8, 12 }; + +static int ads1298_get_scale(struct ads1298_private *priv, + int channel, int *val, int *val2) +{ + int ret; + unsigned int regval; + u8 gain; + + if (priv->reg_vref) { + ret = regulator_get_voltage(priv->reg_vref); + if (ret < 0) + return ret; + + *val = ret / MILLI; /* Convert to millivolts */ + } else { + ret = regmap_read(priv->regmap, ADS1298_REG_CONFIG3, ®val); + if (ret) + return ret; + + /* Refererence in millivolts */ + *val = regval & ADS1298_MASK_CONFIG3_VREF_4V ? 4000 : 2400; + } + + ret = regmap_read(priv->regmap, ADS1298_REG_CHnSET(channel), ®val); + if (ret) + return ret; + + gain = ads1298_pga_settings[FIELD_GET(ADS1298_MASK_CH_PGA, regval)]; + *val /= gain; /* Full scale is VREF / gain */ + + *val2 = ADS1298_BITS_PER_SAMPLE - 1; /* Signed, hence the -1 */ + + return IIO_VAL_FRACTIONAL_LOG2; +} + +static int ads1298_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct ads1298_private *priv = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) + return ret; + + ret = ads1298_read_one(priv, chan->scan_index); + + iio_device_release_direct_mode(indio_dev); + + if (ret) + return ret; + + *val = sign_extend32(get_unaligned_be24(priv->rx_buffer + chan->address), + ADS1298_BITS_PER_SAMPLE - 1); + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + return ads1298_get_scale(priv, chan->channel, val, val2); + case IIO_CHAN_INFO_SAMP_FREQ: + return ads1298_get_samp_freq(priv, val); + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + ret = regmap_read(priv->regmap, ADS1298_REG_CONFIG1, val); + if (ret) + return ret; + + *val = 16 << (*val & ADS1298_MASK_CONFIG1_DR); + return IIO_VAL_INT; + default: + return -EINVAL; + } +} + +static int ads1298_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int val, + int val2, long mask) +{ + struct ads1298_private *priv = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + return ads1298_set_samp_freq(priv, val); + default: + return -EINVAL; + } +} + +static int ads1298_reg_write(void *context, unsigned int reg, unsigned int val) +{ + struct ads1298_private *priv = context; + struct spi_transfer reg_write_xfer = { + .tx_buf = priv->cmd_buffer, + .rx_buf = priv->cmd_buffer, + .len = 3, + .speed_hz = ADS1298_SPI_BUS_SPEED_SLOW, + .delay = { + .value = 2, + .unit = SPI_DELAY_UNIT_USECS, + }, + }; + + priv->cmd_buffer[0] = ADS1298_CMD_WREG | reg; + priv->cmd_buffer[1] = 0; /* Number of registers to be written - 1 */ + priv->cmd_buffer[2] = val; + + return spi_sync_transfer(priv->spi, ®_write_xfer, 1); +} + +static int ads1298_reg_read(void *context, unsigned int reg, unsigned int *val) +{ + struct ads1298_private *priv = context; + struct spi_transfer reg_read_xfer = { + .tx_buf = priv->cmd_buffer, + .rx_buf = priv->cmd_buffer, + .len = 3, + .speed_hz = ADS1298_SPI_BUS_SPEED_SLOW, + .delay = { + .value = 2, + .unit = SPI_DELAY_UNIT_USECS, + }, + }; + int ret; + + priv->cmd_buffer[0] = ADS1298_CMD_RREG | reg; + priv->cmd_buffer[1] = 0; /* Number of registers to be read - 1 */ + priv->cmd_buffer[2] = 0; + + ret = spi_sync_transfer(priv->spi, ®_read_xfer, 1); + if (ret) + return ret; + + *val = priv->cmd_buffer[2]; + + return 0; +} + +static int ads1298_reg_access(struct iio_dev *indio_dev, unsigned int reg, + unsigned int writeval, unsigned int *readval) +{ + struct ads1298_private *priv = iio_priv(indio_dev); + + if (readval) + return regmap_read(priv->regmap, reg, readval); + + return regmap_write(priv->regmap, reg, writeval); +} + +static void ads1298_rdata_unmark_busy(struct ads1298_private *priv) +{ + /* Notify we're no longer waiting for the SPI transfer to complete */ + guard(spinlock_irqsave)(&priv->irq_busy_lock); + priv->rdata_xfer_busy = 0; +} + +static int ads1298_update_scan_mode(struct iio_dev *indio_dev, + const unsigned long *scan_mask) +{ + struct ads1298_private *priv = iio_priv(indio_dev); + unsigned int val; + int ret; + int i; + + /* Make the interrupt routines start with a clean slate */ + ads1298_rdata_unmark_busy(priv); + + /* Configure power-down bits to match scan mask */ + for (i = 0; i < indio_dev->num_channels; i++) { + val = test_bit(i, scan_mask) ? 0 : ADS1298_MASK_CH_PD; + ret = regmap_update_bits(priv->regmap, ADS1298_REG_CHnSET(i), + ADS1298_MASK_CH_PD, val); + if (ret) + return ret; + } + + return 0; +} + +static const struct iio_info ads1298_info = { + .read_raw = &ads1298_read_raw, + .write_raw = &ads1298_write_raw, + .update_scan_mode = &ads1298_update_scan_mode, + .debugfs_reg_access = &ads1298_reg_access, +}; + +static void ads1298_rdata_release_busy_or_restart(struct ads1298_private *priv) +{ + guard(spinlock_irqsave)(&priv->irq_busy_lock); + + if (priv->rdata_xfer_busy > 1) { + /* + * DRDY interrupt occurred before SPI completion. Start a new + * SPI transaction now to retrieve the data that wasn't latched + * into the ADS1298 chip's transfer buffer yet. + */ + spi_async(priv->spi, &priv->rdata_msg); + /* + * If more than one DRDY took place, there was an overrun. Since + * the sample is already lost, reset the counter to 1 so that + * we will wait for a DRDY interrupt after this SPI transaction. + */ + priv->rdata_xfer_busy = 1; + } else { + /* No pending data, wait for DRDY */ + priv->rdata_xfer_busy = 0; + } +} + +/* Called from SPI completion interrupt handler */ +static void ads1298_rdata_complete(void *context) +{ + struct iio_dev *indio_dev = context; + struct ads1298_private *priv = iio_priv(indio_dev); + int scan_index; + u32 *bounce = priv->bounce_buffer; + + if (!iio_buffer_enabled(indio_dev)) { + /* + * for a single transfer mode we're kept in direct_mode until + * completion, avoiding a race with buffered IO. + */ + ads1298_rdata_unmark_busy(priv); + complete(&priv->completion); + return; + } + + /* Demux the channel data into our bounce buffer */ + for_each_set_bit(scan_index, indio_dev->active_scan_mask, + indio_dev->masklength) { + const struct iio_chan_spec *scan_chan = + &indio_dev->channels[scan_index]; + const u8 *data = priv->rx_buffer + scan_chan->address; + + *bounce++ = get_unaligned_be24(data); + } + + /* rx_buffer can be overwritten from this point on */ + ads1298_rdata_release_busy_or_restart(priv); + + iio_push_to_buffers(indio_dev, priv->bounce_buffer); +} + +static irqreturn_t ads1298_interrupt(int irq, void *dev_id) +{ + struct iio_dev *indio_dev = dev_id; + struct ads1298_private *priv = iio_priv(indio_dev); + unsigned int wasbusy; + + guard(spinlock_irqsave)(&priv->irq_busy_lock); + + wasbusy = priv->rdata_xfer_busy++; + /* When no SPI transfer in transit, start one now */ + if (!wasbusy) + spi_async(priv->spi, &priv->rdata_msg); + + return IRQ_HANDLED; +}; + +static int ads1298_buffer_postenable(struct iio_dev *indio_dev) +{ + struct ads1298_private *priv = iio_priv(indio_dev); + int ret; + + /* Disable single-shot mode */ + ret = regmap_update_bits(priv->regmap, ADS1298_REG_CONFIG4, + ADS1298_MASK_CONFIG4_SINGLE_SHOT, 0); + if (ret) + return ret; + + return ads1298_write_cmd(priv, ADS1298_CMD_START); +} + +static int ads1298_buffer_predisable(struct iio_dev *indio_dev) +{ + struct ads1298_private *priv = iio_priv(indio_dev); + + return ads1298_write_cmd(priv, ADS1298_CMD_STOP); +} + +static const struct iio_buffer_setup_ops ads1298_setup_ops = { + .postenable = &ads1298_buffer_postenable, + .predisable = &ads1298_buffer_predisable, +}; + +static void ads1298_reg_disable(void *reg) +{ + regulator_disable(reg); +} + +static const struct regmap_range ads1298_regmap_volatile_range[] = { + regmap_reg_range(ADS1298_REG_LOFF_STATP, ADS1298_REG_LOFF_STATN), +}; + +static const struct regmap_access_table ads1298_regmap_volatile = { + .yes_ranges = ads1298_regmap_volatile_range, + .n_yes_ranges = ARRAY_SIZE(ads1298_regmap_volatile_range), +}; + +static const struct regmap_config ads1298_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .reg_read = ads1298_reg_read, + .reg_write = ads1298_reg_write, + .max_register = ADS1298_REG_WCT2, + .volatile_table = &ads1298_regmap_volatile, + .cache_type = REGCACHE_MAPLE, +}; + +static int ads1298_init(struct iio_dev *indio_dev) +{ + struct ads1298_private *priv = iio_priv(indio_dev); + struct device *dev = &priv->spi->dev; + const char *suffix; + unsigned int val; + int ret; + + /* Device initializes into RDATAC mode, which we don't want */ + ret = ads1298_write_cmd(priv, ADS1298_CMD_SDATAC); + if (ret) + return ret; + + ret = regmap_read(priv->regmap, ADS1298_REG_ID, &val); + if (ret) + return ret; + + /* Fill in name and channel count based on what the chip told us */ + indio_dev->num_channels = 4 + 2 * (val & ADS1298_MASK_ID_CHANNELS); + switch (val & ADS1298_MASK_ID_FAMILY) { + case ADS1298_ID_FAMILY_ADS129X: + suffix = ""; + break; + case ADS1298_ID_FAMILY_ADS129XR: + suffix = "r"; + break; + default: + return dev_err_probe(dev, -ENODEV, "Unknown ID: 0x%x\n", val); + } + indio_dev->name = devm_kasprintf(dev, GFP_KERNEL, "ads129%u%s", + indio_dev->num_channels, suffix); + + /* Enable internal test signal, double amplitude, double frequency */ + ret = regmap_write(priv->regmap, ADS1298_REG_CONFIG2, + ADS1298_MASK_CONFIG2_RESERVED | + ADS1298_MASK_CONFIG2_INT_TEST | + ADS1298_MASK_CONFIG2_TEST_AMP | + ADS1298_MASK_CONFIG2_TEST_FREQ_FAST); + if (ret) + return ret; + + val = ADS1298_MASK_CONFIG3_RESERVED; /* Must write 1 always */ + if (!priv->reg_vref) { + /* Enable internal reference */ + val |= ADS1298_MASK_CONFIG3_PWR_REFBUF; + /* Use 4V VREF when power supply is at least 4.4V */ + if (regulator_get_voltage(priv->reg_avdd) >= 4400000) + val |= ADS1298_MASK_CONFIG3_VREF_4V; + } + return regmap_write(priv->regmap, ADS1298_REG_CONFIG3, val); +} + +static int ads1298_probe(struct spi_device *spi) +{ + struct ads1298_private *priv; + struct iio_dev *indio_dev; + struct device *dev = &spi->dev; + struct gpio_desc *reset_gpio; + int ret; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*priv)); + if (!indio_dev) + return -ENOMEM; + + priv = iio_priv(indio_dev); + + /* Reset to be asserted before enabling clock and power */ + 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), + "Cannot get reset GPIO\n"); + + /* VREF can be supplied externally, otherwise use internal reference */ + priv->reg_vref = devm_regulator_get_optional(dev, "vref"); + if (IS_ERR(priv->reg_vref)) { + if (PTR_ERR(priv->reg_vref) != -ENODEV) + return dev_err_probe(dev, PTR_ERR(priv->reg_avdd), + "Failed to get vref regulator\n"); + + priv->reg_vref = NULL; + } else { + ret = regulator_enable(priv->reg_vref); + if (ret) + return ret; + + ret = devm_add_action_or_reset(dev, ads1298_reg_disable, priv->reg_vref); + if (ret) + return ret; + } + + priv->clk = devm_clk_get_optional_enabled(dev, "clk"); + if (IS_ERR(priv->clk)) + return dev_err_probe(dev, PTR_ERR(priv->clk), "Failed to get clk\n"); + + priv->reg_avdd = devm_regulator_get(dev, "avdd"); + if (IS_ERR(priv->reg_avdd)) + return dev_err_probe(dev, PTR_ERR(priv->reg_avdd), + "Failed to get avdd regulator\n"); + + ret = regulator_enable(priv->reg_avdd); + if (ret) + return dev_err_probe(dev, ret, "Failed to enable avdd regulator\n"); + + ret = devm_add_action_or_reset(dev, ads1298_reg_disable, priv->reg_avdd); + if (ret) + return ret; + + priv->spi = spi; + init_completion(&priv->completion); + spin_lock_init(&priv->irq_busy_lock); + priv->regmap = devm_regmap_init(dev, NULL, priv, &ads1298_regmap_config); + if (IS_ERR(priv->regmap)) + return PTR_ERR(priv->regmap); + + indio_dev->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE; + indio_dev->channels = ads1298_channels; + indio_dev->info = &ads1298_info; + + if (reset_gpio) { + /* + * Deassert reset now that clock and power are active. + * Minimum reset pulsewidth is 2 clock cycles. + */ + fsleep(ADS1298_CLOCKS_TO_USECS(2)); + gpiod_set_value_cansleep(reset_gpio, 0); + } else { + ret = ads1298_write_cmd(priv, ADS1298_CMD_RESET); + if (ret) + return dev_err_probe(dev, ret, "RESET failed\n"); + } + /* Wait 18 clock cycles for reset command to complete */ + fsleep(ADS1298_CLOCKS_TO_USECS(18)); + + ret = ads1298_init(indio_dev); + if (ret) + return dev_err_probe(dev, ret, "Init failed\n"); + + priv->tx_buffer[0] = ADS1298_CMD_RDATA; + priv->rdata_xfer.tx_buf = priv->tx_buffer; + priv->rdata_xfer.rx_buf = priv->rx_buffer; + priv->rdata_xfer.len = ADS1298_SPI_RDATA_BUFFER_SIZE(indio_dev->num_channels); + /* Must keep CS low for 4 clocks */ + priv->rdata_xfer.delay.value = 2; + priv->rdata_xfer.delay.unit = SPI_DELAY_UNIT_USECS; + spi_message_init_with_transfers(&priv->rdata_msg, &priv->rdata_xfer, 1); + priv->rdata_msg.complete = &ads1298_rdata_complete; + priv->rdata_msg.context = indio_dev; + + ret = devm_request_irq(dev, spi->irq, &ads1298_interrupt, + IRQF_TRIGGER_FALLING, indio_dev->name, + indio_dev); + if (ret) + return ret; + + ret = devm_iio_kfifo_buffer_setup(dev, indio_dev, &ads1298_setup_ops); + if (ret) + return ret; + + return devm_iio_device_register(dev, indio_dev); +} + +static const struct spi_device_id ads1298_id[] = { + { "ads1298" }, + { } +}; +MODULE_DEVICE_TABLE(spi, ads1298_id); + +static const struct of_device_id ads1298_of_table[] = { + { .compatible = "ti,ads1298" }, + { } +}; +MODULE_DEVICE_TABLE(of, ads1298_of_table); + +static struct spi_driver ads1298_driver = { + .driver = { + .name = "ads1298", + .of_match_table = ads1298_of_table, + }, + .probe = ads1298_probe, + .id_table = ads1298_id, +}; +module_spi_driver(ads1298_driver); + +MODULE_AUTHOR("Mike Looijmans <mike.looijmans@topic.nl>"); +MODULE_DESCRIPTION("TI ADS1298 ADC"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/buffer/industrialio-buffer-dmaengine.c b/drivers/iio/buffer/industrialio-buffer-dmaengine.c index 5f85ba38e6f6..a18c1da292af 100644 --- a/drivers/iio/buffer/industrialio-buffer-dmaengine.c +++ b/drivers/iio/buffer/industrialio-buffer-dmaengine.c @@ -159,7 +159,7 @@ static const struct iio_dev_attr *iio_dmaengine_buffer_attrs[] = { * Once done using the buffer iio_dmaengine_buffer_free() should be used to * release it. */ -static struct iio_buffer *iio_dmaengine_buffer_alloc(struct device *dev, +struct iio_buffer *iio_dmaengine_buffer_alloc(struct device *dev, const char *channel) { struct dmaengine_buffer *dmaengine_buffer; @@ -210,6 +210,7 @@ err_free: kfree(dmaengine_buffer); return ERR_PTR(ret); } +EXPORT_SYMBOL_NS_GPL(iio_dmaengine_buffer_alloc, IIO_DMAENGINE_BUFFER); /** * iio_dmaengine_buffer_free() - Free dmaengine buffer @@ -217,7 +218,7 @@ err_free: * * Frees a buffer previously allocated with iio_dmaengine_buffer_alloc(). */ -static void iio_dmaengine_buffer_free(struct iio_buffer *buffer) +void iio_dmaengine_buffer_free(struct iio_buffer *buffer) { struct dmaengine_buffer *dmaengine_buffer = iio_buffer_to_dmaengine_buffer(buffer); @@ -227,6 +228,7 @@ static void iio_dmaengine_buffer_free(struct iio_buffer *buffer) iio_buffer_put(buffer); } +EXPORT_SYMBOL_NS_GPL(iio_dmaengine_buffer_free, IIO_DMAENGINE_BUFFER); static void __devm_iio_dmaengine_buffer_free(void *buffer) { @@ -279,8 +281,7 @@ int devm_iio_dmaengine_buffer_setup(struct device *dev, { struct iio_buffer *buffer; - buffer = devm_iio_dmaengine_buffer_alloc(indio_dev->dev.parent, - channel); + buffer = devm_iio_dmaengine_buffer_alloc(dev, channel); if (IS_ERR(buffer)) return PTR_ERR(buffer); @@ -288,7 +289,7 @@ int devm_iio_dmaengine_buffer_setup(struct device *dev, return iio_device_attach_buffer(indio_dev, buffer); } -EXPORT_SYMBOL_GPL(devm_iio_dmaengine_buffer_setup); +EXPORT_SYMBOL_NS_GPL(devm_iio_dmaengine_buffer_setup, IIO_DMAENGINE_BUFFER); MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); MODULE_DESCRIPTION("DMA buffer for the IIO framework"); diff --git a/drivers/iio/common/inv_sensors/inv_sensors_timestamp.c b/drivers/iio/common/inv_sensors/inv_sensors_timestamp.c index 03823ee57f59..3b0f9598a7c7 100644 --- a/drivers/iio/common/inv_sensors/inv_sensors_timestamp.c +++ b/drivers/iio/common/inv_sensors/inv_sensors_timestamp.c @@ -126,7 +126,7 @@ void inv_sensors_timestamp_interrupt(struct inv_sensors_timestamp *ts, struct inv_sensors_timestamp_interval *it; int64_t delta, interval; const uint32_t fifo_mult = fifo_period / ts->chip.clock_period; - uint32_t period = ts->period; + uint32_t period; bool valid = false; if (fifo_nb == 0) diff --git a/drivers/iio/dummy/iio_dummy_evgen.c b/drivers/iio/dummy/iio_dummy_evgen.c index 5a0072727ba4..16d3f144dda0 100644 --- a/drivers/iio/dummy/iio_dummy_evgen.c +++ b/drivers/iio/dummy/iio_dummy_evgen.c @@ -31,8 +31,6 @@ * @regs: irq regs we are faking * @lock: protect the evgen state * @inuse: mask of which irqs are connected - * @irq_sim: interrupt simulator - * @base: base of irq range * @irq_sim_domain: irq simulator domain */ struct iio_dummy_eventgen { diff --git a/drivers/iio/dummy/iio_simple_dummy.c b/drivers/iio/dummy/iio_simple_dummy.c index c24f609c2ade..09efacaf8f78 100644 --- a/drivers/iio/dummy/iio_simple_dummy.c +++ b/drivers/iio/dummy/iio_simple_dummy.c @@ -283,65 +283,63 @@ static int iio_dummy_read_raw(struct iio_dev *indio_dev, long mask) { struct iio_dummy_state *st = iio_priv(indio_dev); - int ret = -EINVAL; - mutex_lock(&st->lock); switch (mask) { case IIO_CHAN_INFO_RAW: /* magic value - channel value read */ - switch (chan->type) { - case IIO_VOLTAGE: - if (chan->output) { - /* Set integer part to cached value */ - *val = st->dac_val; - ret = IIO_VAL_INT; - } else if (chan->differential) { - if (chan->channel == 1) - *val = st->differential_adc_val[0]; - else - *val = st->differential_adc_val[1]; - ret = IIO_VAL_INT; - } else { - *val = st->single_ended_adc_val; - ret = IIO_VAL_INT; + iio_device_claim_direct_scoped(return -EBUSY, indio_dev) { + guard(mutex)(&st->lock); + switch (chan->type) { + case IIO_VOLTAGE: + if (chan->output) { + /* Set integer part to cached value */ + *val = st->dac_val; + return IIO_VAL_INT; + } else if (chan->differential) { + if (chan->channel == 1) + *val = st->differential_adc_val[0]; + else + *val = st->differential_adc_val[1]; + return IIO_VAL_INT; + } else { + *val = st->single_ended_adc_val; + return IIO_VAL_INT; + } + + case IIO_ACCEL: + *val = st->accel_val; + return IIO_VAL_INT; + default: + return -EINVAL; } - break; - case IIO_ACCEL: - *val = st->accel_val; - ret = IIO_VAL_INT; - break; - default: - break; } - break; + unreachable(); case IIO_CHAN_INFO_PROCESSED: - switch (chan->type) { - case IIO_STEPS: - *val = st->steps; - ret = IIO_VAL_INT; - break; - case IIO_ACTIVITY: - switch (chan->channel2) { - case IIO_MOD_RUNNING: - *val = st->activity_running; - ret = IIO_VAL_INT; - break; - case IIO_MOD_WALKING: - *val = st->activity_walking; - ret = IIO_VAL_INT; - break; + iio_device_claim_direct_scoped(return -EBUSY, indio_dev) { + guard(mutex)(&st->lock); + switch (chan->type) { + case IIO_STEPS: + *val = st->steps; + return IIO_VAL_INT; + case IIO_ACTIVITY: + switch (chan->channel2) { + case IIO_MOD_RUNNING: + *val = st->activity_running; + return IIO_VAL_INT; + case IIO_MOD_WALKING: + *val = st->activity_walking; + return IIO_VAL_INT; + default: + return -EINVAL; + } default: - break; + return -EINVAL; } - break; - default: - break; } - break; + unreachable(); case IIO_CHAN_INFO_OFFSET: /* only single ended adc -> 7 */ *val = 7; - ret = IIO_VAL_INT; - break; + return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: switch (chan->type) { case IIO_VOLTAGE: @@ -350,60 +348,57 @@ static int iio_dummy_read_raw(struct iio_dev *indio_dev, /* only single ended adc -> 0.001333 */ *val = 0; *val2 = 1333; - ret = IIO_VAL_INT_PLUS_MICRO; - break; + return IIO_VAL_INT_PLUS_MICRO; case 1: /* all differential adc -> 0.000001344 */ *val = 0; *val2 = 1344; - ret = IIO_VAL_INT_PLUS_NANO; + return IIO_VAL_INT_PLUS_NANO; + default: + return -EINVAL; } - break; default: - break; + return -EINVAL; } - break; - case IIO_CHAN_INFO_CALIBBIAS: + case IIO_CHAN_INFO_CALIBBIAS: { + guard(mutex)(&st->lock); /* only the acceleration axis - read from cache */ *val = st->accel_calibbias; - ret = IIO_VAL_INT; - break; - case IIO_CHAN_INFO_CALIBSCALE: + return IIO_VAL_INT; + } + case IIO_CHAN_INFO_CALIBSCALE: { + guard(mutex)(&st->lock); *val = st->accel_calibscale->val; *val2 = st->accel_calibscale->val2; - ret = IIO_VAL_INT_PLUS_MICRO; - break; + return IIO_VAL_INT_PLUS_MICRO; + } case IIO_CHAN_INFO_SAMP_FREQ: *val = 3; *val2 = 33; - ret = IIO_VAL_INT_PLUS_NANO; - break; - case IIO_CHAN_INFO_ENABLE: + return IIO_VAL_INT_PLUS_NANO; + case IIO_CHAN_INFO_ENABLE: { + guard(mutex)(&st->lock); switch (chan->type) { case IIO_STEPS: *val = st->steps_enabled; - ret = IIO_VAL_INT; - break; + return IIO_VAL_INT; default: - break; + return -EINVAL; } - break; - case IIO_CHAN_INFO_CALIBHEIGHT: + } + case IIO_CHAN_INFO_CALIBHEIGHT: { + guard(mutex)(&st->lock); switch (chan->type) { case IIO_STEPS: *val = st->height; - ret = IIO_VAL_INT; - break; + return IIO_VAL_INT; default: - break; + return -EINVAL; } - break; - + } default: - break; + return -EINVAL; } - mutex_unlock(&st->lock); - return ret; } /** @@ -426,7 +421,6 @@ static int iio_dummy_write_raw(struct iio_dev *indio_dev, long mask) { int i; - int ret = 0; struct iio_dummy_state *st = iio_priv(indio_dev); switch (mask) { @@ -436,10 +430,10 @@ static int iio_dummy_write_raw(struct iio_dev *indio_dev, if (chan->output == 0) return -EINVAL; - /* Locking not required as writing single value */ - mutex_lock(&st->lock); - st->dac_val = val; - mutex_unlock(&st->lock); + scoped_guard(mutex, &st->lock) { + /* Locking not required as writing single value */ + st->dac_val = val; + } return 0; default: return -EINVAL; @@ -447,9 +441,9 @@ static int iio_dummy_write_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_PROCESSED: switch (chan->type) { case IIO_STEPS: - mutex_lock(&st->lock); - st->steps = val; - mutex_unlock(&st->lock); + scoped_guard(mutex, &st->lock) { + st->steps = val; + } return 0; case IIO_ACTIVITY: if (val < 0) @@ -470,30 +464,29 @@ static int iio_dummy_write_raw(struct iio_dev *indio_dev, default: return -EINVAL; } - case IIO_CHAN_INFO_CALIBSCALE: - mutex_lock(&st->lock); + case IIO_CHAN_INFO_CALIBSCALE: { + guard(mutex)(&st->lock); /* Compare against table - hard matching here */ for (i = 0; i < ARRAY_SIZE(dummy_scales); i++) if (val == dummy_scales[i].val && val2 == dummy_scales[i].val2) break; if (i == ARRAY_SIZE(dummy_scales)) - ret = -EINVAL; - else - st->accel_calibscale = &dummy_scales[i]; - mutex_unlock(&st->lock); - return ret; + return -EINVAL; + st->accel_calibscale = &dummy_scales[i]; + return 0; + } case IIO_CHAN_INFO_CALIBBIAS: - mutex_lock(&st->lock); - st->accel_calibbias = val; - mutex_unlock(&st->lock); + scoped_guard(mutex, &st->lock) { + st->accel_calibbias = val; + } return 0; case IIO_CHAN_INFO_ENABLE: switch (chan->type) { case IIO_STEPS: - mutex_lock(&st->lock); - st->steps_enabled = val; - mutex_unlock(&st->lock); + scoped_guard(mutex, &st->lock) { + st->steps_enabled = val; + } return 0; default: return -EINVAL; diff --git a/drivers/iio/frequency/Kconfig b/drivers/iio/frequency/Kconfig index 9e85dfa58508..c455be7d4a1c 100644 --- a/drivers/iio/frequency/Kconfig +++ b/drivers/iio/frequency/Kconfig @@ -60,6 +60,16 @@ config ADF4377 To compile this driver as a module, choose M here: the module will be called adf4377. +config ADMFM2000 + tristate "Analog Devices ADMFM2000 Dual Microwave Down Converter" + depends on GPIOLIB + help + Say yes here to build support for Analog Devices ADMFM2000 Dual + Microwave Down Converter. + + To compile this driver as a module, choose M here: the + module will be called admfm2000. + config ADMV1013 tristate "Analog Devices ADMV1013 Microwave Upconverter" depends on SPI && COMMON_CLK diff --git a/drivers/iio/frequency/Makefile b/drivers/iio/frequency/Makefile index b616c29b4a08..70d0e0b70e80 100644 --- a/drivers/iio/frequency/Makefile +++ b/drivers/iio/frequency/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_AD9523) += ad9523.o obj-$(CONFIG_ADF4350) += adf4350.o obj-$(CONFIG_ADF4371) += adf4371.o obj-$(CONFIG_ADF4377) += adf4377.o +obj-$(CONFIG_ADMFM2000) += admfm2000.o obj-$(CONFIG_ADMV1013) += admv1013.o obj-$(CONFIG_ADMV1014) += admv1014.o obj-$(CONFIG_ADMV4420) += admv4420.o diff --git a/drivers/iio/frequency/admfm2000.c b/drivers/iio/frequency/admfm2000.c new file mode 100644 index 000000000000..c34d79e55a7c --- /dev/null +++ b/drivers/iio/frequency/admfm2000.c @@ -0,0 +1,282 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * ADMFM2000 Dual Microwave Down Converter + * + * Copyright 2024 Analog Devices Inc. + */ + +#include <linux/device.h> +#include <linux/err.h> +#include <linux/gpio/consumer.h> +#include <linux/iio/iio.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/mod_devicetable.h> +#include <linux/platform_device.h> +#include <linux/property.h> + +#define ADMFM2000_MIXER_MODE 0 +#define ADMFM2000_DIRECT_IF_MODE 1 +#define ADMFM2000_DSA_GPIOS 5 +#define ADMFM2000_MODE_GPIOS 2 +#define ADMFM2000_MAX_GAIN 0 +#define ADMFM2000_MIN_GAIN -31000 +#define ADMFM2000_DEFAULT_GAIN -0x20 + +struct admfm2000_state { + struct mutex lock; /* protect sensor state */ + struct gpio_desc *sw1_ch[2]; + struct gpio_desc *sw2_ch[2]; + struct gpio_desc *dsa1_gpios[5]; + struct gpio_desc *dsa2_gpios[5]; + u32 gain[2]; +}; + +static int admfm2000_mode(struct iio_dev *indio_dev, u32 chan, u32 mode) +{ + struct admfm2000_state *st = iio_priv(indio_dev); + int i; + + switch (mode) { + case ADMFM2000_MIXER_MODE: + for (i = 0; i < ADMFM2000_MODE_GPIOS; i++) { + gpiod_set_value_cansleep(st->sw1_ch[i], (chan == 0) ? 1 : 0); + gpiod_set_value_cansleep(st->sw2_ch[i], (chan == 0) ? 0 : 1); + } + return 0; + case ADMFM2000_DIRECT_IF_MODE: + for (i = 0; i < ADMFM2000_MODE_GPIOS; i++) { + gpiod_set_value_cansleep(st->sw1_ch[i], (chan == 0) ? 0 : 1); + gpiod_set_value_cansleep(st->sw2_ch[i], (chan == 0) ? 1 : 0); + } + return 0; + default: + return -EINVAL; + } +} + +static int admfm2000_attenuation(struct iio_dev *indio_dev, u32 chan, u32 value) +{ + struct admfm2000_state *st = iio_priv(indio_dev); + int i; + + switch (chan) { + case 0: + for (i = 0; i < ADMFM2000_DSA_GPIOS; i++) + gpiod_set_value_cansleep(st->dsa1_gpios[i], value & (1 << i)); + return 0; + case 1: + for (i = 0; i < ADMFM2000_DSA_GPIOS; i++) + gpiod_set_value_cansleep(st->dsa2_gpios[i], value & (1 << i)); + return 0; + default: + return -EINVAL; + } +} + +static int admfm2000_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val, + int *val2, long mask) +{ + struct admfm2000_state *st = iio_priv(indio_dev); + int gain; + + switch (mask) { + case IIO_CHAN_INFO_HARDWAREGAIN: + mutex_lock(&st->lock); + gain = ~(st->gain[chan->channel]) * -1000; + *val = gain / 1000; + *val2 = (gain % 1000) * 1000; + mutex_unlock(&st->lock); + + return IIO_VAL_INT_PLUS_MICRO_DB; + default: + return -EINVAL; + } +} + +static int admfm2000_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int val, + int val2, long mask) +{ + struct admfm2000_state *st = iio_priv(indio_dev); + int gain, ret; + + if (val < 0) + gain = (val * 1000) - (val2 / 1000); + else + gain = (val * 1000) + (val2 / 1000); + + if (gain > ADMFM2000_MAX_GAIN || gain < ADMFM2000_MIN_GAIN) + return -EINVAL; + + switch (mask) { + case IIO_CHAN_INFO_HARDWAREGAIN: + mutex_lock(&st->lock); + st->gain[chan->channel] = ~((abs(gain) / 1000) & 0x1F); + + ret = admfm2000_attenuation(indio_dev, chan->channel, + st->gain[chan->channel]); + mutex_unlock(&st->lock); + return ret; + default: + return -EINVAL; + } +} + +static int admfm2000_write_raw_get_fmt(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + long mask) +{ + switch (mask) { + case IIO_CHAN_INFO_HARDWAREGAIN: + return IIO_VAL_INT_PLUS_MICRO_DB; + default: + return -EINVAL; + } +} + +static const struct iio_info admfm2000_info = { + .read_raw = &admfm2000_read_raw, + .write_raw = &admfm2000_write_raw, + .write_raw_get_fmt = &admfm2000_write_raw_get_fmt, +}; + +#define ADMFM2000_CHAN(_channel) { \ + .type = IIO_VOLTAGE, \ + .output = 1, \ + .indexed = 1, \ + .channel = _channel, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_HARDWAREGAIN), \ +} + +static const struct iio_chan_spec admfm2000_channels[] = { + ADMFM2000_CHAN(0), + ADMFM2000_CHAN(1), +}; + +static int admfm2000_channel_config(struct admfm2000_state *st, + struct iio_dev *indio_dev) +{ + struct platform_device *pdev = to_platform_device(indio_dev->dev.parent); + struct device *dev = &pdev->dev; + struct fwnode_handle *child; + struct gpio_desc **dsa; + struct gpio_desc **sw; + int ret, i; + bool mode; + u32 reg; + + device_for_each_child_node(dev, child) { + ret = fwnode_property_read_u32(child, "reg", ®); + if (ret) { + fwnode_handle_put(child); + return dev_err_probe(dev, ret, + "Failed to get reg property\n"); + } + + if (reg >= indio_dev->num_channels) { + fwnode_handle_put(child); + return dev_err_probe(dev, -EINVAL, "reg bigger than: %d\n", + indio_dev->num_channels); + } + + if (fwnode_property_present(child, "adi,mixer-mode")) + mode = ADMFM2000_MIXER_MODE; + else + mode = ADMFM2000_DIRECT_IF_MODE; + + switch (reg) { + case 0: + sw = st->sw1_ch; + dsa = st->dsa1_gpios; + break; + case 1: + sw = st->sw2_ch; + dsa = st->dsa2_gpios; + break; + default: + fwnode_handle_put(child); + return -EINVAL; + } + + for (i = 0; i < ADMFM2000_MODE_GPIOS; i++) { + sw[i] = devm_fwnode_gpiod_get_index(dev, child, "switch", + i, GPIOD_OUT_LOW, NULL); + if (IS_ERR(sw[i])) { + fwnode_handle_put(child); + return dev_err_probe(dev, PTR_ERR(sw[i]), + "Failed to get gpios\n"); + } + } + + for (i = 0; i < ADMFM2000_DSA_GPIOS; i++) { + dsa[i] = devm_fwnode_gpiod_get_index(dev, child, + "attenuation", i, + GPIOD_OUT_LOW, NULL); + if (IS_ERR(dsa[i])) { + fwnode_handle_put(child); + return dev_err_probe(dev, PTR_ERR(dsa[i]), + "Failed to get gpios\n"); + } + } + + ret = admfm2000_mode(indio_dev, reg, mode); + if (ret) { + fwnode_handle_put(child); + return ret; + } + } + + return 0; +} + +static int admfm2000_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct admfm2000_state *st; + struct iio_dev *indio_dev; + int ret; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; + + st = iio_priv(indio_dev); + + indio_dev->name = "admfm2000"; + indio_dev->num_channels = ARRAY_SIZE(admfm2000_channels); + indio_dev->channels = admfm2000_channels; + indio_dev->info = &admfm2000_info; + indio_dev->modes = INDIO_DIRECT_MODE; + + st->gain[0] = ADMFM2000_DEFAULT_GAIN; + st->gain[1] = ADMFM2000_DEFAULT_GAIN; + + mutex_init(&st->lock); + + ret = admfm2000_channel_config(st, indio_dev); + if (ret) + return ret; + + return devm_iio_device_register(dev, indio_dev); +} + +static const struct of_device_id admfm2000_of_match[] = { + { .compatible = "adi,admfm2000" }, + { } +}; +MODULE_DEVICE_TABLE(of, admfm2000_of_match); + +static struct platform_driver admfm2000_driver = { + .driver = { + .name = "admfm2000", + .of_match_table = admfm2000_of_match, + }, + .probe = admfm2000_probe, +}; +module_platform_driver(admfm2000_driver); + +MODULE_AUTHOR("Kim Seer Paller <kimseer.paller@analog.com>"); +MODULE_DESCRIPTION("ADMFM2000 Dual Microwave Down Converter"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/gyro/bmg160_i2c.c b/drivers/iio/gyro/bmg160_i2c.c index 2f9675596138..9c8e20c25e96 100644 --- a/drivers/iio/gyro/bmg160_i2c.c +++ b/drivers/iio/gyro/bmg160_i2c.c @@ -3,7 +3,7 @@ #include <linux/regmap.h> #include <linux/iio/iio.h> #include <linux/module.h> -#include <linux/acpi.h> +#include <linux/mod_devicetable.h> #include "bmg160.h" @@ -66,7 +66,7 @@ MODULE_DEVICE_TABLE(of, bmg160_of_match); static struct i2c_driver bmg160_i2c_driver = { .driver = { .name = "bmg160_i2c", - .acpi_match_table = ACPI_PTR(bmg160_acpi_match), + .acpi_match_table = bmg160_acpi_match, .of_match_table = bmg160_of_match, .pm = &bmg160_pm_ops, }, diff --git a/drivers/iio/health/afe4403.c b/drivers/iio/health/afe4403.c index df3bc5c3d378..1dbe48dae74e 100644 --- a/drivers/iio/health/afe4403.c +++ b/drivers/iio/health/afe4403.c @@ -346,6 +346,13 @@ err: return IRQ_HANDLED; } +static void afe4403_regulator_disable(void *data) +{ + struct regulator *regulator = data; + + regulator_disable(regulator); +} + #define AFE4403_TIMING_PAIRS \ { AFE440X_LED2STC, 0x000050 }, \ { AFE440X_LED2ENDC, 0x0003e7 }, \ @@ -495,19 +502,24 @@ static int afe4403_probe(struct spi_device *spi) dev_err(afe->dev, "Unable to enable regulator\n"); return ret; } + ret = devm_add_action_or_reset(afe->dev, afe4403_regulator_disable, afe->regulator); + if (ret) { + dev_err(afe->dev, "Unable to add regulator disable action\n"); + return ret; + } ret = regmap_write(afe->regmap, AFE440X_CONTROL0, AFE440X_CONTROL0_SW_RESET); if (ret) { dev_err(afe->dev, "Unable to reset device\n"); - goto err_disable_reg; + return ret; } ret = regmap_multi_reg_write(afe->regmap, afe4403_reg_sequences, ARRAY_SIZE(afe4403_reg_sequences)); if (ret) { dev_err(afe->dev, "Unable to set register defaults\n"); - goto err_disable_reg; + return ret; } indio_dev->modes = INDIO_DIRECT_MODE; @@ -523,16 +535,15 @@ static int afe4403_probe(struct spi_device *spi) iio_device_id(indio_dev)); if (!afe->trig) { dev_err(afe->dev, "Unable to allocate IIO trigger\n"); - ret = -ENOMEM; - goto err_disable_reg; + return -ENOMEM; } iio_trigger_set_drvdata(afe->trig, indio_dev); - ret = iio_trigger_register(afe->trig); + ret = devm_iio_trigger_register(afe->dev, afe->trig); if (ret) { dev_err(afe->dev, "Unable to register IIO trigger\n"); - goto err_disable_reg; + return ret; } ret = devm_request_threaded_irq(afe->dev, afe->irq, @@ -542,52 +553,25 @@ static int afe4403_probe(struct spi_device *spi) afe->trig); if (ret) { dev_err(afe->dev, "Unable to request IRQ\n"); - goto err_trig; + return ret; } } - ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time, - afe4403_trigger_handler, NULL); + ret = devm_iio_triggered_buffer_setup(afe->dev, indio_dev, + &iio_pollfunc_store_time, + afe4403_trigger_handler, NULL); if (ret) { dev_err(afe->dev, "Unable to setup buffer\n"); - goto err_trig; + return ret; } - ret = iio_device_register(indio_dev); + ret = devm_iio_device_register(afe->dev, indio_dev); if (ret) { dev_err(afe->dev, "Unable to register IIO device\n"); - goto err_buff; + return ret; } return 0; - -err_buff: - iio_triggered_buffer_cleanup(indio_dev); -err_trig: - if (afe->irq > 0) - iio_trigger_unregister(afe->trig); -err_disable_reg: - regulator_disable(afe->regulator); - - return ret; -} - -static void afe4403_remove(struct spi_device *spi) -{ - struct iio_dev *indio_dev = spi_get_drvdata(spi); - struct afe4403_data *afe = iio_priv(indio_dev); - int ret; - - iio_device_unregister(indio_dev); - - iio_triggered_buffer_cleanup(indio_dev); - - if (afe->irq > 0) - iio_trigger_unregister(afe->trig); - - ret = regulator_disable(afe->regulator); - if (ret) - dev_warn(afe->dev, "Unable to disable regulator\n"); } static const struct spi_device_id afe4403_ids[] = { @@ -603,7 +587,6 @@ static struct spi_driver afe4403_spi_driver = { .pm = pm_sleep_ptr(&afe4403_pm_ops), }, .probe = afe4403_probe, - .remove = afe4403_remove, .id_table = afe4403_ids, }; module_spi_driver(afe4403_spi_driver); diff --git a/drivers/iio/health/afe4404.c b/drivers/iio/health/afe4404.c index ede1e8201311..7768b07ef7a6 100644 --- a/drivers/iio/health/afe4404.c +++ b/drivers/iio/health/afe4404.c @@ -349,6 +349,13 @@ err: return IRQ_HANDLED; } +static void afe4404_regulator_disable(void *data) +{ + struct regulator *regulator = data; + + regulator_disable(regulator); +} + /* Default timings from data-sheet */ #define AFE4404_TIMING_PAIRS \ { AFE440X_PRPCOUNT, 39999 }, \ @@ -502,19 +509,24 @@ static int afe4404_probe(struct i2c_client *client) dev_err(afe->dev, "Unable to enable regulator\n"); return ret; } + ret = devm_add_action_or_reset(afe->dev, afe4404_regulator_disable, afe->regulator); + if (ret) { + dev_err(afe->dev, "Unable to enable regulator\n"); + return ret; + } ret = regmap_write(afe->regmap, AFE440X_CONTROL0, AFE440X_CONTROL0_SW_RESET); if (ret) { dev_err(afe->dev, "Unable to reset device\n"); - goto disable_reg; + return ret; } ret = regmap_multi_reg_write(afe->regmap, afe4404_reg_sequences, ARRAY_SIZE(afe4404_reg_sequences)); if (ret) { dev_err(afe->dev, "Unable to set register defaults\n"); - goto disable_reg; + return ret; } indio_dev->modes = INDIO_DIRECT_MODE; @@ -530,16 +542,15 @@ static int afe4404_probe(struct i2c_client *client) iio_device_id(indio_dev)); if (!afe->trig) { dev_err(afe->dev, "Unable to allocate IIO trigger\n"); - ret = -ENOMEM; - goto disable_reg; + return -ENOMEM; } iio_trigger_set_drvdata(afe->trig, indio_dev); - ret = iio_trigger_register(afe->trig); + ret = devm_iio_trigger_register(afe->dev, afe->trig); if (ret) { dev_err(afe->dev, "Unable to register IIO trigger\n"); - goto disable_reg; + return ret; } ret = devm_request_threaded_irq(afe->dev, afe->irq, @@ -549,52 +560,25 @@ static int afe4404_probe(struct i2c_client *client) afe->trig); if (ret) { dev_err(afe->dev, "Unable to request IRQ\n"); - goto disable_reg; + return ret; } } - ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time, - afe4404_trigger_handler, NULL); + ret = devm_iio_triggered_buffer_setup(afe->dev, indio_dev, + &iio_pollfunc_store_time, + afe4404_trigger_handler, NULL); if (ret) { dev_err(afe->dev, "Unable to setup buffer\n"); - goto unregister_trigger; + return ret; } - ret = iio_device_register(indio_dev); + ret = devm_iio_device_register(afe->dev, indio_dev); if (ret) { dev_err(afe->dev, "Unable to register IIO device\n"); - goto unregister_triggered_buffer; + return ret; } return 0; - -unregister_triggered_buffer: - iio_triggered_buffer_cleanup(indio_dev); -unregister_trigger: - if (afe->irq > 0) - iio_trigger_unregister(afe->trig); -disable_reg: - regulator_disable(afe->regulator); - - return ret; -} - -static void afe4404_remove(struct i2c_client *client) -{ - struct iio_dev *indio_dev = i2c_get_clientdata(client); - struct afe4404_data *afe = iio_priv(indio_dev); - int ret; - - iio_device_unregister(indio_dev); - - iio_triggered_buffer_cleanup(indio_dev); - - if (afe->irq > 0) - iio_trigger_unregister(afe->trig); - - ret = regulator_disable(afe->regulator); - if (ret) - dev_err(afe->dev, "Unable to disable regulator\n"); } static const struct i2c_device_id afe4404_ids[] = { @@ -610,7 +594,6 @@ static struct i2c_driver afe4404_i2c_driver = { .pm = pm_sleep_ptr(&afe4404_pm_ops), }, .probe = afe4404_probe, - .remove = afe4404_remove, .id_table = afe4404_ids, }; module_i2c_driver(afe4404_i2c_driver); diff --git a/drivers/iio/humidity/Kconfig b/drivers/iio/humidity/Kconfig index 2de5494e7c22..b15b7a3b66d5 100644 --- a/drivers/iio/humidity/Kconfig +++ b/drivers/iio/humidity/Kconfig @@ -48,6 +48,18 @@ config HDC2010 To compile this driver as a module, choose M here: the module will be called hdc2010. +config HDC3020 + tristate "TI HDC3020 relative humidity and temperature sensor" + depends on I2C + select CRC8 + help + Say yes here to build support for the Texas Instruments + HDC3020, HDC3021 and HDC3022 relative humidity and temperature + sensors. + + To compile this driver as a module, choose M here: the module + will be called hdc3020. + config HID_SENSOR_HUMIDITY tristate "HID Environmental humidity sensor" depends on HID_SENSOR_HUB diff --git a/drivers/iio/humidity/Makefile b/drivers/iio/humidity/Makefile index f19ff3de97c5..5fbeef299f61 100644 --- a/drivers/iio/humidity/Makefile +++ b/drivers/iio/humidity/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_AM2315) += am2315.o obj-$(CONFIG_DHT11) += dht11.o obj-$(CONFIG_HDC100X) += hdc100x.o obj-$(CONFIG_HDC2010) += hdc2010.o +obj-$(CONFIG_HDC3020) += hdc3020.o obj-$(CONFIG_HID_SENSOR_HUMIDITY) += hid-sensor-humidity.o hts221-y := hts221_core.o \ diff --git a/drivers/iio/humidity/hdc3020.c b/drivers/iio/humidity/hdc3020.c index 4e3311170725..1e5d0d4797b1 100644 --- a/drivers/iio/humidity/hdc3020.c +++ b/drivers/iio/humidity/hdc3020.c @@ -5,41 +5,66 @@ * * Copyright (C) 2023 * + * Copyright (C) 2024 Liebherr-Electronics and Drives GmbH + * * Datasheet: https://www.ti.com/lit/ds/symlink/hdc3020.pdf */ +#include <linux/bitfield.h> #include <linux/bitops.h> #include <linux/cleanup.h> #include <linux/crc8.h> #include <linux/delay.h> #include <linux/i2c.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/module.h> #include <linux/mutex.h> +#include <linux/units.h> #include <asm/unaligned.h> +#include <linux/iio/events.h> #include <linux/iio/iio.h> -#define HDC3020_HEATER_CMD_MSB 0x30 /* shared by all heater commands */ -#define HDC3020_HEATER_ENABLE 0x6D -#define HDC3020_HEATER_DISABLE 0x66 -#define HDC3020_HEATER_CONFIG 0x6E +#define HDC3020_S_AUTO_10HZ_MOD0 0x2737 +#define HDC3020_S_STATUS 0x3041 +#define HDC3020_HEATER_DISABLE 0x3066 +#define HDC3020_HEATER_ENABLE 0x306D +#define HDC3020_HEATER_CONFIG 0x306E +#define HDC3020_EXIT_AUTO 0x3093 +#define HDC3020_S_T_RH_THRESH_LOW 0x6100 +#define HDC3020_S_T_RH_THRESH_LOW_CLR 0x610B +#define HDC3020_S_T_RH_THRESH_HIGH_CLR 0x6116 +#define HDC3020_S_T_RH_THRESH_HIGH 0x611D +#define HDC3020_R_T_RH_AUTO 0xE000 +#define HDC3020_R_T_LOW_AUTO 0xE002 +#define HDC3020_R_T_HIGH_AUTO 0xE003 +#define HDC3020_R_RH_LOW_AUTO 0xE004 +#define HDC3020_R_RH_HIGH_AUTO 0xE005 +#define HDC3020_R_T_RH_THRESH_LOW 0xE102 +#define HDC3020_R_T_RH_THRESH_LOW_CLR 0xE109 +#define HDC3020_R_T_RH_THRESH_HIGH_CLR 0xE114 +#define HDC3020_R_T_RH_THRESH_HIGH 0xE11F +#define HDC3020_R_STATUS 0xF32D + +#define HDC3020_THRESH_TEMP_MASK GENMASK(8, 0) +#define HDC3020_THRESH_TEMP_TRUNC_SHIFT 7 +#define HDC3020_THRESH_HUM_MASK GENMASK(15, 9) +#define HDC3020_THRESH_HUM_TRUNC_SHIFT 9 + +#define HDC3020_STATUS_T_LOW_ALERT BIT(6) +#define HDC3020_STATUS_T_HIGH_ALERT BIT(7) +#define HDC3020_STATUS_RH_LOW_ALERT BIT(8) +#define HDC3020_STATUS_RH_HIGH_ALERT BIT(9) #define HDC3020_READ_RETRY_TIMES 10 #define HDC3020_BUSY_DELAY_MS 10 #define HDC3020_CRC8_POLYNOMIAL 0x31 -static const u8 HDC3020_S_AUTO_10HZ_MOD0[2] = { 0x27, 0x37 }; - -static const u8 HDC3020_EXIT_AUTO[2] = { 0x30, 0x93 }; - -static const u8 HDC3020_R_T_RH_AUTO[2] = { 0xE0, 0x00 }; -static const u8 HDC3020_R_T_LOW_AUTO[2] = { 0xE0, 0x02 }; -static const u8 HDC3020_R_T_HIGH_AUTO[2] = { 0xE0, 0x03 }; -static const u8 HDC3020_R_RH_LOW_AUTO[2] = { 0xE0, 0x04 }; -static const u8 HDC3020_R_RH_HIGH_AUTO[2] = { 0xE0, 0x05 }; +#define HDC3020_MIN_TEMP -40 +#define HDC3020_MAX_TEMP 125 struct hdc3020_data { struct i2c_client *client; @@ -54,18 +79,37 @@ struct hdc3020_data { static const int hdc3020_heater_vals[] = {0, 1, 0x3FFF}; +static const struct iio_event_spec hdc3020_t_rh_event[] = { + { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_RISING, + .mask_separate = BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_HYSTERESIS), + }, + { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_FALLING, + .mask_separate = BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_HYSTERESIS), + }, +}; + static const struct iio_chan_spec hdc3020_channels[] = { { .type = IIO_TEMP, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_PEAK) | BIT(IIO_CHAN_INFO_TROUGH) | BIT(IIO_CHAN_INFO_OFFSET), + .event_spec = hdc3020_t_rh_event, + .num_event_specs = ARRAY_SIZE(hdc3020_t_rh_event), }, { .type = IIO_HUMIDITYRELATIVE, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_PEAK) | BIT(IIO_CHAN_INFO_TROUGH), + .event_spec = hdc3020_t_rh_event, + .num_event_specs = ARRAY_SIZE(hdc3020_t_rh_event), }, { /* @@ -82,7 +126,7 @@ static const struct iio_chan_spec hdc3020_channels[] = { DECLARE_CRC8_TABLE(hdc3020_crc8_table); -static int hdc3020_write_bytes(struct hdc3020_data *data, const u8 *buf, u8 len) +static int hdc3020_write_bytes(struct hdc3020_data *data, u8 *buf, u8 len) { struct i2c_client *client = data->client; struct i2c_msg msg; @@ -90,7 +134,7 @@ static int hdc3020_write_bytes(struct hdc3020_data *data, const u8 *buf, u8 len) msg.addr = client->addr; msg.flags = 0; - msg.buf = (char *)buf; + msg.buf = buf; msg.len = len; /* @@ -109,26 +153,28 @@ static int hdc3020_write_bytes(struct hdc3020_data *data, const u8 *buf, u8 len) return -ETIMEDOUT; } -static int hdc3020_read_bytes(struct hdc3020_data *data, const u8 *buf, - void *val, int len) +static +int hdc3020_read_bytes(struct hdc3020_data *data, u16 reg, u8 *buf, int len) { + u8 reg_buf[2]; int ret, cnt; struct i2c_client *client = data->client; struct i2c_msg msg[2] = { [0] = { .addr = client->addr, .flags = 0, - .buf = (char *)buf, + .buf = reg_buf, .len = 2, }, [1] = { .addr = client->addr, .flags = I2C_M_RD, - .buf = val, + .buf = buf, .len = len, }, }; + put_unaligned_be16(reg, reg_buf); /* * During the measurement process, HDC3020 will not return data. * So wait for a while and try again @@ -145,48 +191,12 @@ static int hdc3020_read_bytes(struct hdc3020_data *data, const u8 *buf, return -ETIMEDOUT; } -static int hdc3020_read_measurement(struct hdc3020_data *data, - enum iio_chan_type type, int *val) -{ - u8 crc, buf[6]; - int ret; - - ret = hdc3020_read_bytes(data, HDC3020_R_T_RH_AUTO, buf, 6); - if (ret < 0) - return ret; - - /* CRC check of the temperature measurement */ - crc = crc8(hdc3020_crc8_table, buf, 2, CRC8_INIT_VALUE); - if (crc != buf[2]) - return -EINVAL; - - /* CRC check of the relative humidity measurement */ - crc = crc8(hdc3020_crc8_table, buf + 3, 2, CRC8_INIT_VALUE); - if (crc != buf[5]) - return -EINVAL; - - if (type == IIO_TEMP) - *val = get_unaligned_be16(buf); - else if (type == IIO_HUMIDITYRELATIVE) - *val = get_unaligned_be16(&buf[3]); - else - return -EINVAL; - - return 0; -} - -/* - * After exiting the automatic measurement mode or resetting, the peak - * value will be reset to the default value - * This method is used to get the highest temp measured during automatic - * measurement - */ -static int hdc3020_read_high_peak_t(struct hdc3020_data *data, int *val) +static int hdc3020_read_be16(struct hdc3020_data *data, u16 reg) { u8 crc, buf[3]; int ret; - ret = hdc3020_read_bytes(data, HDC3020_R_T_HIGH_AUTO, buf, 3); + ret = hdc3020_read_bytes(data, reg, buf, 3); if (ret < 0) return ret; @@ -194,73 +204,43 @@ static int hdc3020_read_high_peak_t(struct hdc3020_data *data, int *val) if (crc != buf[2]) return -EINVAL; - *val = get_unaligned_be16(buf); - - return 0; + return get_unaligned_be16(buf); } -/* - * This method is used to get the lowest temp measured during automatic - * measurement - */ -static int hdc3020_read_low_peak_t(struct hdc3020_data *data, int *val) +static int hdc3020_exec_cmd(struct hdc3020_data *data, u16 reg) { - u8 crc, buf[3]; - int ret; + u8 reg_buf[2]; - ret = hdc3020_read_bytes(data, HDC3020_R_T_LOW_AUTO, buf, 3); - if (ret < 0) - return ret; - - crc = crc8(hdc3020_crc8_table, buf, 2, CRC8_INIT_VALUE); - if (crc != buf[2]) - return -EINVAL; - - *val = get_unaligned_be16(buf); - - return 0; + put_unaligned_be16(reg, reg_buf); + return hdc3020_write_bytes(data, reg_buf, 2); } -/* - * This method is used to get the highest humidity measured during automatic - * measurement - */ -static int hdc3020_read_high_peak_rh(struct hdc3020_data *data, int *val) +static int hdc3020_read_measurement(struct hdc3020_data *data, + enum iio_chan_type type, int *val) { - u8 crc, buf[3]; + u8 crc, buf[6]; int ret; - ret = hdc3020_read_bytes(data, HDC3020_R_RH_HIGH_AUTO, buf, 3); + ret = hdc3020_read_bytes(data, HDC3020_R_T_RH_AUTO, buf, 6); if (ret < 0) return ret; + /* CRC check of the temperature measurement */ crc = crc8(hdc3020_crc8_table, buf, 2, CRC8_INIT_VALUE); if (crc != buf[2]) return -EINVAL; - *val = get_unaligned_be16(buf); - - return 0; -} - -/* - * This method is used to get the lowest humidity measured during automatic - * measurement - */ -static int hdc3020_read_low_peak_rh(struct hdc3020_data *data, int *val) -{ - u8 crc, buf[3]; - int ret; - - ret = hdc3020_read_bytes(data, HDC3020_R_RH_LOW_AUTO, buf, 3); - if (ret < 0) - return ret; - - crc = crc8(hdc3020_crc8_table, buf, 2, CRC8_INIT_VALUE); - if (crc != buf[2]) + /* CRC check of the relative humidity measurement */ + crc = crc8(hdc3020_crc8_table, buf + 3, 2, CRC8_INIT_VALUE); + if (crc != buf[5]) return -EINVAL; - *val = get_unaligned_be16(buf); + if (type == IIO_TEMP) + *val = get_unaligned_be16(buf); + else if (type == IIO_HUMIDITYRELATIVE) + *val = get_unaligned_be16(&buf[3]); + else + return -EINVAL; return 0; } @@ -286,28 +266,28 @@ static int hdc3020_read_raw(struct iio_dev *indio_dev, } case IIO_CHAN_INFO_PEAK: { guard(mutex)(&data->lock); - if (chan->type == IIO_TEMP) { - ret = hdc3020_read_high_peak_t(data, val); - if (ret < 0) - return ret; - } else { - ret = hdc3020_read_high_peak_rh(data, val); - if (ret < 0) - return ret; - } + if (chan->type == IIO_TEMP) + ret = hdc3020_read_be16(data, HDC3020_R_T_HIGH_AUTO); + else + ret = hdc3020_read_be16(data, HDC3020_R_RH_HIGH_AUTO); + + if (ret < 0) + return ret; + + *val = ret; return IIO_VAL_INT; } case IIO_CHAN_INFO_TROUGH: { guard(mutex)(&data->lock); - if (chan->type == IIO_TEMP) { - ret = hdc3020_read_low_peak_t(data, val); - if (ret < 0) - return ret; - } else { - ret = hdc3020_read_low_peak_rh(data, val); - if (ret < 0) - return ret; - } + if (chan->type == IIO_TEMP) + ret = hdc3020_read_be16(data, HDC3020_R_T_LOW_AUTO); + else + ret = hdc3020_read_be16(data, HDC3020_R_RH_LOW_AUTO); + + if (ret < 0) + return ret; + + *val = ret; return IIO_VAL_INT; } case IIO_CHAN_INFO_SCALE: @@ -322,7 +302,7 @@ static int hdc3020_read_raw(struct iio_dev *indio_dev, if (chan->type != IIO_TEMP) return -EINVAL; - *val = 16852; + *val = -16852; return IIO_VAL_INT; default: @@ -352,23 +332,17 @@ static int hdc3020_update_heater(struct hdc3020_data *data, int val) if (val < hdc3020_heater_vals[0] || val > hdc3020_heater_vals[2]) return -EINVAL; - buf[0] = HDC3020_HEATER_CMD_MSB; + if (!val) + hdc3020_exec_cmd(data, HDC3020_HEATER_DISABLE); - if (!val) { - buf[1] = HDC3020_HEATER_DISABLE; - return hdc3020_write_bytes(data, buf, 2); - } - - buf[1] = HDC3020_HEATER_CONFIG; + put_unaligned_be16(HDC3020_HEATER_CONFIG, buf); put_unaligned_be16(val & GENMASK(13, 0), &buf[2]); buf[4] = crc8(hdc3020_crc8_table, buf + 2, 2, CRC8_INIT_VALUE); ret = hdc3020_write_bytes(data, buf, 5); if (ret < 0) return ret; - buf[1] = HDC3020_HEATER_ENABLE; - - return hdc3020_write_bytes(data, buf, 2); + return hdc3020_exec_cmd(data, HDC3020_HEATER_ENABLE); } static int hdc3020_write_raw(struct iio_dev *indio_dev, @@ -389,15 +363,197 @@ static int hdc3020_write_raw(struct iio_dev *indio_dev, return -EINVAL; } +static int hdc3020_write_thresh(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 hdc3020_data *data = iio_priv(indio_dev); + u8 buf[5]; + u64 tmp; + u16 reg; + int ret; + + /* Supported temperature range is from –40 to 125 degree celsius */ + if (val < HDC3020_MIN_TEMP || val > HDC3020_MAX_TEMP) + return -EINVAL; + + /* Select threshold register */ + if (info == IIO_EV_INFO_VALUE) { + if (dir == IIO_EV_DIR_RISING) + reg = HDC3020_S_T_RH_THRESH_HIGH; + else + reg = HDC3020_S_T_RH_THRESH_LOW; + } else { + if (dir == IIO_EV_DIR_RISING) + reg = HDC3020_S_T_RH_THRESH_HIGH_CLR; + else + reg = HDC3020_S_T_RH_THRESH_LOW_CLR; + } + + guard(mutex)(&data->lock); + ret = hdc3020_read_be16(data, reg); + if (ret < 0) + return ret; + + switch (chan->type) { + case IIO_TEMP: + /* + * Calculate temperature threshold, shift it down to get the + * truncated threshold representation in the 9LSBs while keeping + * the current humidity threshold in the 7 MSBs. + */ + tmp = ((u64)(((val + 45) * MICRO) + val2)) * 65535ULL; + tmp = div_u64(tmp, MICRO * 175); + val = tmp >> HDC3020_THRESH_TEMP_TRUNC_SHIFT; + val = FIELD_PREP(HDC3020_THRESH_TEMP_MASK, val); + val |= (FIELD_GET(HDC3020_THRESH_HUM_MASK, ret) << + HDC3020_THRESH_HUM_TRUNC_SHIFT); + break; + case IIO_HUMIDITYRELATIVE: + /* + * Calculate humidity threshold, shift it down and up to get the + * truncated threshold representation in the 7MSBs while keeping + * the current temperature threshold in the 9 LSBs. + */ + tmp = ((u64)((val * MICRO) + val2)) * 65535ULL; + tmp = div_u64(tmp, MICRO * 100); + val = tmp >> HDC3020_THRESH_HUM_TRUNC_SHIFT; + val = FIELD_PREP(HDC3020_THRESH_HUM_MASK, val); + val |= FIELD_GET(HDC3020_THRESH_TEMP_MASK, ret); + break; + default: + return -EOPNOTSUPP; + } + + put_unaligned_be16(reg, buf); + put_unaligned_be16(val, buf + 2); + buf[4] = crc8(hdc3020_crc8_table, buf + 2, 2, CRC8_INIT_VALUE); + return hdc3020_write_bytes(data, buf, 5); +} + +static int hdc3020_read_thresh(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 hdc3020_data *data = iio_priv(indio_dev); + u16 reg; + int ret; + + /* Select threshold register */ + if (info == IIO_EV_INFO_VALUE) { + if (dir == IIO_EV_DIR_RISING) + reg = HDC3020_R_T_RH_THRESH_HIGH; + else + reg = HDC3020_R_T_RH_THRESH_LOW; + } else { + if (dir == IIO_EV_DIR_RISING) + reg = HDC3020_R_T_RH_THRESH_HIGH_CLR; + else + reg = HDC3020_R_T_RH_THRESH_LOW_CLR; + } + + guard(mutex)(&data->lock); + ret = hdc3020_read_be16(data, reg); + if (ret < 0) + return ret; + + switch (chan->type) { + case IIO_TEMP: + /* + * Get the temperature threshold from 9 LSBs, shift them to get + * the truncated temperature threshold representation and + * calculate the threshold according to the formula in the + * datasheet. + */ + *val = FIELD_GET(HDC3020_THRESH_TEMP_MASK, ret); + *val = *val << HDC3020_THRESH_TEMP_TRUNC_SHIFT; + *val = -2949075 + (175 * (*val)); + *val2 = 65535; + return IIO_VAL_FRACTIONAL; + case IIO_HUMIDITYRELATIVE: + /* + * Get the humidity threshold from 7 MSBs, shift them to get the + * truncated humidity threshold representation and calculate the + * threshold according to the formula in the datasheet. + */ + *val = FIELD_GET(HDC3020_THRESH_HUM_MASK, ret); + *val = (*val << HDC3020_THRESH_HUM_TRUNC_SHIFT) * 100; + *val2 = 65535; + return IIO_VAL_FRACTIONAL; + default: + return -EOPNOTSUPP; + } +} + +static irqreturn_t hdc3020_interrupt_handler(int irq, void *private) +{ + struct iio_dev *indio_dev = private; + struct hdc3020_data *data; + s64 time; + int ret; + + data = iio_priv(indio_dev); + ret = hdc3020_read_be16(data, HDC3020_R_STATUS); + if (ret < 0) + return IRQ_HANDLED; + + if (!(ret & (HDC3020_STATUS_T_HIGH_ALERT | HDC3020_STATUS_T_LOW_ALERT | + HDC3020_STATUS_RH_HIGH_ALERT | HDC3020_STATUS_RH_LOW_ALERT))) + return IRQ_NONE; + + time = iio_get_time_ns(indio_dev); + if (ret & HDC3020_STATUS_T_HIGH_ALERT) + iio_push_event(indio_dev, + IIO_MOD_EVENT_CODE(IIO_TEMP, 0, + IIO_NO_MOD, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_RISING), + time); + + if (ret & HDC3020_STATUS_T_LOW_ALERT) + iio_push_event(indio_dev, + IIO_MOD_EVENT_CODE(IIO_TEMP, 0, + IIO_NO_MOD, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_FALLING), + time); + + if (ret & HDC3020_STATUS_RH_HIGH_ALERT) + iio_push_event(indio_dev, + IIO_MOD_EVENT_CODE(IIO_HUMIDITYRELATIVE, 0, + IIO_NO_MOD, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_RISING), + time); + + if (ret & HDC3020_STATUS_RH_LOW_ALERT) + iio_push_event(indio_dev, + IIO_MOD_EVENT_CODE(IIO_HUMIDITYRELATIVE, 0, + IIO_NO_MOD, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_FALLING), + time); + + return IRQ_HANDLED; +} + static const struct iio_info hdc3020_info = { .read_raw = hdc3020_read_raw, .write_raw = hdc3020_write_raw, .read_avail = hdc3020_read_available, + .read_event_value = hdc3020_read_thresh, + .write_event_value = hdc3020_write_thresh, }; static void hdc3020_stop(void *data) { - hdc3020_write_bytes((struct hdc3020_data *)data, HDC3020_EXIT_AUTO, 2); + hdc3020_exec_cmd((struct hdc3020_data *)data, HDC3020_EXIT_AUTO); } static int hdc3020_probe(struct i2c_client *client) @@ -424,8 +580,25 @@ static int hdc3020_probe(struct i2c_client *client) indio_dev->info = &hdc3020_info; indio_dev->channels = hdc3020_channels; indio_dev->num_channels = ARRAY_SIZE(hdc3020_channels); + if (client->irq) { + ret = devm_request_threaded_irq(&client->dev, client->irq, + NULL, hdc3020_interrupt_handler, + IRQF_ONESHOT, "hdc3020", + indio_dev); + if (ret) + return dev_err_probe(&client->dev, ret, + "Failed to request IRQ\n"); + + /* + * The alert output is activated by default upon power up, + * hardware reset, and soft reset. Clear the status register. + */ + ret = hdc3020_exec_cmd(data, HDC3020_S_STATUS); + if (ret) + return ret; + } - ret = hdc3020_write_bytes(data, HDC3020_S_AUTO_10HZ_MOD0, 2); + ret = hdc3020_exec_cmd(data, HDC3020_S_AUTO_10HZ_MOD0); if (ret) return dev_err_probe(&client->dev, ret, "Unable to set up measurement\n"); diff --git a/drivers/iio/humidity/hts221_i2c.c b/drivers/iio/humidity/hts221_i2c.c index 30f2068ea156..5cb263e0ef5a 100644 --- a/drivers/iio/humidity/hts221_i2c.c +++ b/drivers/iio/humidity/hts221_i2c.c @@ -9,7 +9,7 @@ #include <linux/kernel.h> #include <linux/module.h> -#include <linux/acpi.h> +#include <linux/mod_devicetable.h> #include <linux/i2c.h> #include <linux/slab.h> #include <linux/regmap.h> @@ -63,7 +63,7 @@ static struct i2c_driver hts221_driver = { .name = "hts221_i2c", .pm = pm_sleep_ptr(&hts221_pm_ops), .of_match_table = hts221_i2c_of_match, - .acpi_match_table = ACPI_PTR(hts221_acpi_match), + .acpi_match_table = hts221_acpi_match, }, .probe = hts221_i2c_probe, .id_table = hts221_i2c_id_table, diff --git a/drivers/iio/imu/adis16475.c b/drivers/iio/imu/adis16475.c index 64be656f0b80..01f55cc902fa 100644 --- a/drivers/iio/imu/adis16475.c +++ b/drivers/iio/imu/adis16475.c @@ -1363,22 +1363,16 @@ static int adis16475_config_sync_mode(struct adis16475 *st) static int adis16475_config_irq_pin(struct adis16475 *st) { int ret; - struct irq_data *desc; u32 irq_type; u16 val = 0; u8 polarity; struct spi_device *spi = st->adis.spi; - desc = irq_get_irq_data(spi->irq); - if (!desc) { - dev_err(&spi->dev, "Could not find IRQ %d\n", spi->irq); - return -EINVAL; - } /* * It is possible to configure the data ready polarity. Furthermore, we * need to update the adis struct if we want data ready as active low. */ - irq_type = irqd_get_trigger_type(desc); + irq_type = irq_get_trigger_type(spi->irq); if (irq_type == IRQ_TYPE_EDGE_RISING) { polarity = 1; st->adis.irq_flag = IRQF_TRIGGER_RISING; diff --git a/drivers/iio/imu/adis16480.c b/drivers/iio/imu/adis16480.c index fe520194a837..b40a55bba30c 100644 --- a/drivers/iio/imu/adis16480.c +++ b/drivers/iio/imu/adis16480.c @@ -1246,18 +1246,11 @@ static int adis16480_config_irq_pin(struct adis16480 *st) { struct device *dev = &st->adis.spi->dev; struct fwnode_handle *fwnode = dev_fwnode(dev); - struct irq_data *desc; enum adis16480_int_pin pin; unsigned int irq_type; uint16_t val; int i, irq = 0; - desc = irq_get_irq_data(st->adis.spi->irq); - if (!desc) { - dev_err(dev, "Could not find IRQ %d\n", irq); - return -EINVAL; - } - /* Disable data ready since the default after reset is on */ val = ADIS16480_DRDY_EN(0); @@ -1285,7 +1278,7 @@ static int adis16480_config_irq_pin(struct adis16480 *st) * configured as positive or negative, corresponding to * IRQ_TYPE_EDGE_RISING or IRQ_TYPE_EDGE_FALLING respectively. */ - irq_type = irqd_get_trigger_type(desc); + irq_type = irq_get_trigger_type(st->adis.spi->irq); if (irq_type == IRQ_TYPE_EDGE_RISING) { /* Default */ val |= ADIS16480_DRDY_POL(1); } else if (irq_type == IRQ_TYPE_EDGE_FALLING) { diff --git a/drivers/iio/imu/bmi160/bmi160_i2c.c b/drivers/iio/imu/bmi160/bmi160_i2c.c index 81652c08e644..a081305254db 100644 --- a/drivers/iio/imu/bmi160/bmi160_i2c.c +++ b/drivers/iio/imu/bmi160/bmi160_i2c.c @@ -43,6 +43,15 @@ static const struct i2c_device_id bmi160_i2c_id[] = { MODULE_DEVICE_TABLE(i2c, bmi160_i2c_id); static const struct acpi_device_id bmi160_acpi_match[] = { + /* + * FIRMWARE BUG WORKAROUND + * Some manufacturers like GPD, Lenovo or Aya used the incorrect + * ID "10EC5280" for bmi160 in their DSDT. A fixed firmware is not + * available as of Feb 2024 after trying to work with OEMs, and + * this is not expected to change anymore since at least some of + * the affected devices are from 2021/2022. + */ + {"10EC5280", 0}, {"BMI0160", 0}, { }, }; diff --git a/drivers/iio/imu/bmi323/bmi323_core.c b/drivers/iio/imu/bmi323/bmi323_core.c index 183af482828f..5d42ab9b176a 100644 --- a/drivers/iio/imu/bmi323/bmi323_core.c +++ b/drivers/iio/imu/bmi323/bmi323_core.c @@ -1668,52 +1668,41 @@ static int bmi323_write_raw(struct iio_dev *indio_dev, int val2, long mask) { struct bmi323_data *data = iio_priv(indio_dev); - int ret; switch (mask) { case IIO_CHAN_INFO_SAMP_FREQ: - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; - - ret = bmi323_set_odr(data, bmi323_iio_to_sensor(chan->type), - val, val2); - iio_device_release_direct_mode(indio_dev); - return ret; + iio_device_claim_direct_scoped(return -EBUSY, indio_dev) + return bmi323_set_odr(data, + bmi323_iio_to_sensor(chan->type), + val, val2); + unreachable(); case IIO_CHAN_INFO_SCALE: - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; - - ret = bmi323_set_scale(data, bmi323_iio_to_sensor(chan->type), - val, val2); - iio_device_release_direct_mode(indio_dev); - return ret; + iio_device_claim_direct_scoped(return -EBUSY, indio_dev) + return bmi323_set_scale(data, + bmi323_iio_to_sensor(chan->type), + val, val2); + unreachable(); case IIO_CHAN_INFO_OVERSAMPLING_RATIO: - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; - - ret = bmi323_set_average(data, bmi323_iio_to_sensor(chan->type), - val); - - iio_device_release_direct_mode(indio_dev); - return ret; + iio_device_claim_direct_scoped(return -EBUSY, indio_dev) + return bmi323_set_average(data, + bmi323_iio_to_sensor(chan->type), + val); + unreachable(); case IIO_CHAN_INFO_ENABLE: return bmi323_enable_steps(data, val); - case IIO_CHAN_INFO_PROCESSED: - scoped_guard(mutex, &data->mutex) { - if (val || !FIELD_GET(BMI323_FEAT_IO0_STP_CNT_MSK, - data->feature_events)) - return -EINVAL; + case IIO_CHAN_INFO_PROCESSED: { + guard(mutex)(&data->mutex); - /* Clear step counter value */ - ret = bmi323_update_ext_reg(data, BMI323_STEP_SC1_REG, - BMI323_STEP_SC1_RST_CNT_MSK, - FIELD_PREP(BMI323_STEP_SC1_RST_CNT_MSK, - 1)); - } - return ret; + if (val || !FIELD_GET(BMI323_FEAT_IO0_STP_CNT_MSK, + data->feature_events)) + return -EINVAL; + + /* Clear step counter value */ + return bmi323_update_ext_reg(data, BMI323_STEP_SC1_REG, + BMI323_STEP_SC1_RST_CNT_MSK, + FIELD_PREP(BMI323_STEP_SC1_RST_CNT_MSK, + 1)); + } default: return -EINVAL; } @@ -1724,7 +1713,6 @@ static int bmi323_read_raw(struct iio_dev *indio_dev, int *val2, long mask) { struct bmi323_data *data = iio_priv(indio_dev); - int ret; switch (mask) { case IIO_CHAN_INFO_PROCESSED: @@ -1733,14 +1721,10 @@ static int bmi323_read_raw(struct iio_dev *indio_dev, switch (chan->type) { case IIO_ACCEL: case IIO_ANGL_VEL: - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; - - ret = bmi323_read_axis(data, chan, val); - - iio_device_release_direct_mode(indio_dev); - return ret; + iio_device_claim_direct_scoped(return -EBUSY, + indio_dev) + return bmi323_read_axis(data, chan, val); + unreachable(); case IIO_TEMP: return bmi323_get_temp_data(data, val); default: diff --git a/drivers/iio/imu/bmi323/bmi323_i2c.c b/drivers/iio/imu/bmi323/bmi323_i2c.c index 20a8001b9956..52140bf05765 100644 --- a/drivers/iio/imu/bmi323/bmi323_i2c.c +++ b/drivers/iio/imu/bmi323/bmi323_i2c.c @@ -93,6 +93,26 @@ static int bmi323_i2c_probe(struct i2c_client *i2c) return bmi323_core_probe(dev); } +static const struct acpi_device_id bmi323_acpi_match[] = { + /* + * The "BOSC0200" identifier used here is not unique to bmi323 devices. + * The same "BOSC0200" identifier is found in the ACPI tables of devices + * using the bmc150 chip. This creates a conflict with duplicate ACPI + * identifiers which multiple drivers want to use. If a non-bmi323 + * device starts to load with this "BOSC0200" ACPI match here, then the + * chip ID check portion should fail because the chip IDs received (via + * i2c) are unique between bmc150 and bmi323 and the driver should + * relinquish the device. If and when a different driver (such as + * bmc150) starts to load with the "BOSC0200" ACPI match, a short reset + * should ensure that the device is not in a bad state during that + * driver initialization. This device reset does occur in both the + * bmi323 and bmc150 init sequences. + */ + { "BOSC0200" }, + { } +}; +MODULE_DEVICE_TABLE(acpi, bmi323_acpi_match); + static const struct i2c_device_id bmi323_i2c_ids[] = { { "bmi323" }, { } @@ -109,6 +129,7 @@ static struct i2c_driver bmi323_i2c_driver = { .driver = { .name = "bmi323", .of_match_table = bmi323_of_i2c_match, + .acpi_match_table = bmi323_acpi_match, }, .probe = bmi323_i2c_probe, .id_table = bmi323_i2c_ids, diff --git a/drivers/iio/imu/bno055/Kconfig b/drivers/iio/imu/bno055/Kconfig index 83e53acfbe88..c7f5866a177d 100644 --- a/drivers/iio/imu/bno055/Kconfig +++ b/drivers/iio/imu/bno055/Kconfig @@ -8,6 +8,7 @@ config BOSCH_BNO055 config BOSCH_BNO055_SERIAL tristate "Bosch BNO055 attached via UART" depends on SERIAL_DEV_BUS + select REGMAP select BOSCH_BNO055 help Enable this to support Bosch BNO055 IMUs attached via UART. diff --git a/drivers/iio/imu/fxos8700_i2c.c b/drivers/iio/imu/fxos8700_i2c.c index 2ace306d0f9a..e99677ad96a2 100644 --- a/drivers/iio/imu/fxos8700_i2c.c +++ b/drivers/iio/imu/fxos8700_i2c.c @@ -10,7 +10,6 @@ * 1 | 0 | 0x1C * 1 | 1 | 0x1F */ -#include <linux/acpi.h> #include <linux/i2c.h> #include <linux/module.h> #include <linux/mod_devicetable.h> @@ -57,7 +56,7 @@ MODULE_DEVICE_TABLE(of, fxos8700_of_match); static struct i2c_driver fxos8700_i2c_driver = { .driver = { .name = "fxos8700_i2c", - .acpi_match_table = ACPI_PTR(fxos8700_acpi_match), + .acpi_match_table = fxos8700_acpi_match, .of_match_table = fxos8700_of_match, }, .probe = fxos8700_i2c_probe, diff --git a/drivers/iio/imu/fxos8700_spi.c b/drivers/iio/imu/fxos8700_spi.c index 27e694cce173..6b0dc7a776b9 100644 --- a/drivers/iio/imu/fxos8700_spi.c +++ b/drivers/iio/imu/fxos8700_spi.c @@ -2,7 +2,6 @@ /* * FXOS8700 - NXP IMU, SPI bits */ -#include <linux/acpi.h> #include <linux/module.h> #include <linux/mod_devicetable.h> #include <linux/regmap.h> @@ -46,7 +45,7 @@ static struct spi_driver fxos8700_spi_driver = { .probe = fxos8700_spi_probe, .id_table = fxos8700_spi_id, .driver = { - .acpi_match_table = ACPI_PTR(fxos8700_acpi_match), + .acpi_match_table = fxos8700_acpi_match, .of_match_table = fxos8700_of_match, .name = "fxos8700_spi", }, diff --git a/drivers/iio/imu/kmx61.c b/drivers/iio/imu/kmx61.c index 958167b31241..7d3e061f3046 100644 --- a/drivers/iio/imu/kmx61.c +++ b/drivers/iio/imu/kmx61.c @@ -1514,7 +1514,7 @@ MODULE_DEVICE_TABLE(i2c, kmx61_id); static struct i2c_driver kmx61_driver = { .driver = { .name = KMX61_DRV_NAME, - .acpi_match_table = ACPI_PTR(kmx61_acpi_match), + .acpi_match_table = kmx61_acpi_match, .pm = pm_ptr(&kmx61_pm_ops), }, .probe = kmx61_probe, diff --git a/drivers/iio/imu/st_lsm6dsx/Kconfig b/drivers/iio/imu/st_lsm6dsx/Kconfig index 5865a295a4df..89d687ec3099 100644 --- a/drivers/iio/imu/st_lsm6dsx/Kconfig +++ b/drivers/iio/imu/st_lsm6dsx/Kconfig @@ -11,11 +11,32 @@ config IIO_ST_LSM6DSX select IIO_ST_LSM6DSX_I3C if (I3C) help Say yes here to build support for STMicroelectronics LSM6DSx imu - sensor. Supported devices: lsm6ds3, lsm6ds3h, lsm6dsl, lsm6dsm, - ism330dlc, lsm6dso, lsm6dsox, asm330lhh, asm330lhhx, lsm6dsr, - lsm6ds3tr-c, ism330dhcx, lsm6dsrx, lsm6ds0, lsm6dsop, lsm6dstx, - lsm6dsv, lsm6dsv16x, lsm6dso16is, ism330is, asm330lhb, lsm6dst - and the accelerometer/gyroscope of lsm9ds1. + sensor. + Supported devices: + - asm330lhb + - asm330lhh + - asm330lhhx + - asm330lhhxg1 + - ism330dhcx + - ism330dlc + - ism330is + - lsm6ds0 + - lsm6ds3 + - lsm6ds3h + - lsm6ds3tr-c + - lsm6dsl + - lsm6dsm + - lsm6dso + - lsm6dso16is + - lsm6dsop + - lsm6dsox + - lsm6dsr + - lsm6dsrx + - lsm6dst + - lsm6dstx + - lsm6dsv + - lsm6dsv16x + - lsm9ds1 To compile this driver as a module, choose M here: the module will be called st_lsm6dsx. diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h index c19237717e81..a3b93566533b 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h @@ -38,6 +38,7 @@ #define ST_LSM6DSO16IS_DEV_NAME "lsm6dso16is" #define ST_ISM330IS_DEV_NAME "ism330is" #define ST_ASM330LHB_DEV_NAME "asm330lhb" +#define ST_ASM330LHHXG1_DEV_NAME "asm330lhhxg1" enum st_lsm6dsx_hw_id { ST_LSM6DS3_ID = 1, @@ -63,6 +64,7 @@ enum st_lsm6dsx_hw_id { ST_LSM6DSO16IS_ID, ST_ISM330IS_ID, ST_ASM330LHB_ID, + ST_ASM330LHHXG1_ID, ST_LSM6DSX_MAX_ID, }; diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c index 066fe561c5e8..0a7cd8c1aa33 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c @@ -2,7 +2,7 @@ /* * STMicroelectronics st_lsm6dsx FIFO buffer library driver * - * LSM6DS3/LSM6DS3H/LSM6DSL/LSM6DSM/ISM330DLC/LSM6DS3TR-C: + * Pattern FIFO: * The FIFO buffer can be configured to store data from gyroscope and * accelerometer. Samples are queued without any tag according to a * specific pattern based on 'FIFO data sets' (6 bytes each): @@ -14,12 +14,34 @@ * (e.g. Gx, Gy, Gz, Ax, Ay, Az), then data are repeated depending on the * value of the decimation factor and ODR set for each FIFO data set. * - * LSM6DSO/LSM6DSOX/ASM330LHH/ASM330LHHX/LSM6DSR/LSM6DSRX/ISM330DHCX/ - * LSM6DST/LSM6DSOP/LSM6DSTX/LSM6DSV/ASM330LHB: + * Supported devices: + * - ISM330DLC + * - LSM6DS3 + * - LSM6DS3H + * - LSM6DS3TR-C + * - LSM6DSL + * - LSM6DSM + * + * Tagged FIFO: * The FIFO buffer can be configured to store data from gyroscope and * accelerometer. Each sample is queued with a tag (1B) indicating data * source (gyroscope, accelerometer, hw timer). * + * Supported devices: + * - ASM330LHB + * - ASM330LHH + * - ASM330LHHX + * - ASM330LHHXG1 + * - ISM330DHCX + * - LSM6DSO + * - LSM6DSOP + * - LSM6DSOX + * - LSM6DSR + * - LSM6DSRX + * - LSM6DST + * - LSM6DSTX + * - LSM6DSV + * * FIFO supported modes: * - BYPASS: FIFO disabled * - CONTINUOUS: FIFO enabled. When the buffer is full, the FIFO index diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c index b6e6b1df8a61..0716986f9812 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c @@ -14,34 +14,51 @@ * by a different driver. * * Supported sensors: - * - LSM6DS3: + * + * - LSM6DS3 * - Accelerometer/Gyroscope supported ODR [Hz]: 12.5, 26, 52, 104, 208, 416 * - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16 * - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000 * - FIFO size: 8KB * - * - LSM6DS3H/LSM6DSL/LSM6DSM/ISM330DLC/LSM6DS3TR-C: + * - ISM330DLC + * - LSM6DS3H + * - LSM6DS3TR-C + * - LSM6DSL + * - LSM6DSM * - Accelerometer/Gyroscope supported ODR [Hz]: 12.5, 26, 52, 104, 208, 416 * - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16 * - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000 * - FIFO size: 4KB * - * - LSM6DSO/LSM6DSOX/ASM330LHH/ASM330LHHX/LSM6DSR/ISM330DHCX/LSM6DST/LSM6DSOP/ - * LSM6DSTX/LSM6DSO16IS/ISM330IS: + * - ASM330LHH + * - ASM330LHHX + * - ASM330LHHXG1 + * - ISM330DHCX + * - ISM330IS + * - LSM6DSO + * - LSM6DSO16IS + * - LSM6DSOP + * - LSM6DSOX + * - LSM6DSR + * - LSM6DST + * - LSM6DSTX * - Accelerometer/Gyroscope supported ODR [Hz]: 12.5, 26, 52, 104, 208, 416, * 833 * - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16 * - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000 * - FIFO size: 3KB * - * - LSM6DSV/LSM6DSV16X: + * - LSM6DSV + * - LSM6DSV16X * - Accelerometer/Gyroscope supported ODR [Hz]: 7.5, 15, 30, 60, 120, 240, * 480, 960 * - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16 * - Gyroscope supported full-scale [dps]: +-125/+-250/+-500/+-1000/+-2000 * - FIFO size: 3KB * - * - LSM9DS1/LSM6DS0: + * - LSM6DS0 + * - LSM9DS1 * - Accelerometer supported ODR [Hz]: 10, 50, 119, 238, 476, 952 * - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16 * - Gyroscope supported ODR [Hz]: 15, 60, 119, 238, 476, 952 @@ -821,6 +838,10 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .name = ST_ASM330LHHX_DEV_NAME, .wai = 0x6b, }, { + .hw_id = ST_ASM330LHHXG1_ID, + .name = ST_ASM330LHHXG1_DEV_NAME, + .wai = 0x6b, + }, { .hw_id = ST_LSM6DSTX_ID, .name = ST_LSM6DSTX_DEV_NAME, .wai = 0x6d, diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c index 911444ec57c0..cddf41cc0ca9 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c @@ -134,6 +134,10 @@ static const struct of_device_id st_lsm6dsx_i2c_of_match[] = { .compatible = "st,asm330lhb", .data = (void *)ST_ASM330LHB_ID, }, + { + .compatible = "st,asm330lhhxg1", + .data = (void *)ST_ASM330LHHXG1_ID, + }, {}, }; MODULE_DEVICE_TABLE(of, st_lsm6dsx_i2c_of_match); @@ -168,6 +172,7 @@ static const struct i2c_device_id st_lsm6dsx_i2c_id_table[] = { { ST_LSM6DSO16IS_DEV_NAME, ST_LSM6DSO16IS_ID }, { 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_spi.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c index f56c170c41a9..c122c8831365 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c @@ -129,6 +129,10 @@ static const struct of_device_id st_lsm6dsx_spi_of_match[] = { .compatible = "st,asm330lhb", .data = (void *)ST_ASM330LHB_ID, }, + { + .compatible = "st,asm330lhhxg1", + .data = (void *)ST_ASM330LHHXG1_ID, + }, {}, }; MODULE_DEVICE_TABLE(of, st_lsm6dsx_spi_of_match); @@ -157,6 +161,7 @@ static const struct spi_device_id st_lsm6dsx_spi_id_table[] = { { ST_LSM6DSO16IS_DEV_NAME, ST_LSM6DSO16IS_ID }, { 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.h b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0.h index 76678cdefb07..e67d31b48441 100644 --- a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0.h +++ b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0.h @@ -4,9 +4,12 @@ #ifndef ST_LSM9DS0_H #define ST_LSM9DS0_H -struct iio_dev; +struct device; +struct regmap; struct regulator; +struct iio_dev; + struct st_lsm9ds0 { struct device *dev; const char *name; diff --git a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_core.c b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_core.c index e887b45cdbcd..10c1b2ba7a3d 100644 --- a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_core.c +++ b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_core.c @@ -7,10 +7,10 @@ * Author: Andy Shevchenko <andriy.shevchenko@linux.intel.com> */ -#include <linux/device.h> +#include <linux/array_size.h> +#include <linux/dev_printk.h> #include <linux/err.h> #include <linux/module.h> -#include <linux/regmap.h> #include <linux/regulator/consumer.h> #include <linux/iio/common/st_sensors.h> @@ -25,10 +25,9 @@ static int st_lsm9ds0_probe_accel(struct st_lsm9ds0 *lsm9ds0, struct regmap *reg struct st_sensor_data *data; settings = st_accel_get_settings(lsm9ds0->name); - if (!settings) { - dev_err(dev, "device name %s not recognized.\n", lsm9ds0->name); - return -ENODEV; - } + if (!settings) + return dev_err_probe(dev, -ENODEV, "device name %s not recognized.\n", + lsm9ds0->name); lsm9ds0->accel = devm_iio_device_alloc(dev, sizeof(*data)); if (!lsm9ds0->accel) @@ -51,10 +50,9 @@ static int st_lsm9ds0_probe_magn(struct st_lsm9ds0 *lsm9ds0, struct regmap *regm struct st_sensor_data *data; settings = st_magn_get_settings(lsm9ds0->name); - if (!settings) { - dev_err(dev, "device name %s not recognized.\n", lsm9ds0->name); - return -ENODEV; - } + if (!settings) + return dev_err_probe(dev, -ENODEV, "device name %s not recognized.\n", + lsm9ds0->name); lsm9ds0->magn = devm_iio_device_alloc(dev, sizeof(*data)); if (!lsm9ds0->magn) @@ -80,8 +78,7 @@ int st_lsm9ds0_probe(struct st_lsm9ds0 *lsm9ds0, struct regmap *regmap) ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(regulator_names), regulator_names); if (ret) - return dev_err_probe(dev, ret, - "unable to enable Vdd supply\n"); + return dev_err_probe(dev, ret, "unable to enable Vdd supply\n"); /* Setup accelerometer device */ ret = st_lsm9ds0_probe_accel(lsm9ds0, regmap); diff --git a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c index 61d855083aa0..d03cec3b24fe 100644 --- a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c +++ b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c @@ -7,8 +7,10 @@ * Author: Andy Shevchenko <andriy.shevchenko@linux.intel.com> */ +#include <linux/device.h> +#include <linux/err.h> +#include <linux/gfp_types.h> #include <linux/i2c.h> -#include <linux/kernel.h> #include <linux/module.h> #include <linux/mod_devicetable.h> #include <linux/regmap.h> @@ -39,7 +41,7 @@ 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 8cc041d56cf7..69e9135795a3 100644 --- a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c +++ b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c @@ -7,7 +7,9 @@ * Author: Andy Shevchenko <andriy.shevchenko@linux.intel.com> */ -#include <linux/kernel.h> +#include <linux/device.h> +#include <linux/err.h> +#include <linux/gfp_types.h> #include <linux/module.h> #include <linux/mod_devicetable.h> #include <linux/regmap.h> diff --git a/drivers/iio/industrialio-backend.c b/drivers/iio/industrialio-backend.c new file mode 100644 index 000000000000..2fea2bbbe47f --- /dev/null +++ b/drivers/iio/industrialio-backend.c @@ -0,0 +1,418 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Framework to handle complex IIO aggregate devices. + * + * The typical architecture is to have one device as the frontend device which + * can be "linked" against one or multiple backend devices. All the IIO and + * userspace interface is expected to be registers/managed by the frontend + * device which will callback into the backends when needed (to get/set some + * configuration that it does not directly control). + * + * ------------------------------------------------------- + * ------------------ | ------------ ------------ ------- FPGA| + * | ADC |------------------------| | ADC CORE |---------| DMA CORE |------| RAM | | + * | (Frontend/IIO) | Serial Data (eg: LVDS) | |(backend) |---------| |------| | | + * | |------------------------| ------------ ------------ ------- | + * ------------------ ------------------------------------------------------- + * + * The framework interface is pretty simple: + * - Backends should register themselves with devm_iio_backend_register() + * - Frontend devices should get backends with devm_iio_backend_get() + * + * Also to note that the primary target for this framework are converters like + * ADC/DACs so iio_backend_ops will have some operations typical of converter + * devices. On top of that, this is "generic" for all IIO which means any kind + * of device can make use of the framework. That said, If the iio_backend_ops + * struct begins to grow out of control, we can always refactor things so that + * the industrialio-backend.c is only left with the really generic stuff. Then, + * we can build on top of it depending on the needs. + * + * Copyright (C) 2023-2024 Analog Devices Inc. + */ +#define dev_fmt(fmt) "iio-backend: " fmt + +#include <linux/cleanup.h> +#include <linux/device.h> +#include <linux/err.h> +#include <linux/errno.h> +#include <linux/list.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/property.h> +#include <linux/slab.h> +#include <linux/types.h> + +#include <linux/iio/backend.h> + +struct iio_backend { + struct list_head entry; + const struct iio_backend_ops *ops; + struct device *dev; + struct module *owner; + void *priv; +}; + +/* + * Helper struct for requesting buffers. This ensures that we have all data + * that we need to free the buffer in a device managed action. + */ +struct iio_backend_buffer_pair { + struct iio_backend *back; + struct iio_buffer *buffer; +}; + +static LIST_HEAD(iio_back_list); +static DEFINE_MUTEX(iio_back_lock); + +/* + * Helper macros to call backend ops. Makes sure the option is supported. + */ +#define iio_backend_check_op(back, op) ({ \ + struct iio_backend *____back = back; \ + int ____ret = 0; \ + \ + if (!____back->ops->op) \ + ____ret = -EOPNOTSUPP; \ + \ + ____ret; \ +}) + +#define iio_backend_op_call(back, op, args...) ({ \ + struct iio_backend *__back = back; \ + int __ret; \ + \ + __ret = iio_backend_check_op(__back, op); \ + if (!__ret) \ + __ret = __back->ops->op(__back, ##args); \ + \ + __ret; \ +}) + +#define iio_backend_ptr_op_call(back, op, args...) ({ \ + struct iio_backend *__back = back; \ + void *ptr_err; \ + int __ret; \ + \ + __ret = iio_backend_check_op(__back, op); \ + if (__ret) \ + ptr_err = ERR_PTR(__ret); \ + else \ + ptr_err = __back->ops->op(__back, ##args); \ + \ + ptr_err; \ +}) + +#define iio_backend_void_op_call(back, op, args...) { \ + struct iio_backend *__back = back; \ + int __ret; \ + \ + __ret = iio_backend_check_op(__back, op); \ + if (!__ret) \ + __back->ops->op(__back, ##args); \ +} + +/** + * iio_backend_chan_enable - Enable a backend channel + * @back: Backend device + * @chan: Channel number + * + * RETURNS: + * 0 on success, negative error number on failure. + */ +int iio_backend_chan_enable(struct iio_backend *back, unsigned int chan) +{ + return iio_backend_op_call(back, chan_enable, chan); +} +EXPORT_SYMBOL_NS_GPL(iio_backend_chan_enable, IIO_BACKEND); + +/** + * iio_backend_chan_disable - Disable a backend channel + * @back: Backend device + * @chan: Channel number + * + * RETURNS: + * 0 on success, negative error number on failure. + */ +int iio_backend_chan_disable(struct iio_backend *back, unsigned int chan) +{ + return iio_backend_op_call(back, chan_disable, chan); +} +EXPORT_SYMBOL_NS_GPL(iio_backend_chan_disable, IIO_BACKEND); + +static void __iio_backend_disable(void *back) +{ + iio_backend_void_op_call(back, disable); +} + +/** + * devm_iio_backend_enable - Device managed backend enable + * @dev: Consumer device for the backend + * @back: Backend device + * + * RETURNS: + * 0 on success, negative error number on failure. + */ +int devm_iio_backend_enable(struct device *dev, struct iio_backend *back) +{ + int ret; + + ret = iio_backend_op_call(back, enable); + if (ret) + return ret; + + return devm_add_action_or_reset(dev, __iio_backend_disable, back); +} +EXPORT_SYMBOL_NS_GPL(devm_iio_backend_enable, IIO_BACKEND); + +/** + * iio_backend_data_format_set - Configure the channel data format + * @back: Backend device + * @chan: Channel number + * @data: Data format + * + * Properly configure a channel with respect to the expected data format. A + * @struct iio_backend_data_fmt must be passed with the settings. + * + * RETURNS: + * 0 on success, negative error number on failure. + */ +int iio_backend_data_format_set(struct iio_backend *back, unsigned int chan, + const struct iio_backend_data_fmt *data) +{ + if (!data || data->type >= IIO_BACKEND_DATA_TYPE_MAX) + return -EINVAL; + + return iio_backend_op_call(back, data_format_set, chan, data); +} +EXPORT_SYMBOL_NS_GPL(iio_backend_data_format_set, IIO_BACKEND); + +static void iio_backend_free_buffer(void *arg) +{ + struct iio_backend_buffer_pair *pair = arg; + + iio_backend_void_op_call(pair->back, free_buffer, pair->buffer); +} + +/** + * devm_iio_backend_request_buffer - Device managed buffer request + * @dev: Consumer device for the backend + * @back: Backend device + * @indio_dev: IIO device + * + * Request an IIO buffer from the backend. The type of the buffer (typically + * INDIO_BUFFER_HARDWARE) is up to the backend to decide. This is because, + * normally, the backend dictates what kind of buffering we can get. + * + * The backend .free_buffer() hooks is automatically called on @dev detach. + * + * RETURNS: + * 0 on success, negative error number on failure. + */ +int devm_iio_backend_request_buffer(struct device *dev, + struct iio_backend *back, + struct iio_dev *indio_dev) +{ + struct iio_backend_buffer_pair *pair; + struct iio_buffer *buffer; + + pair = devm_kzalloc(dev, sizeof(*pair), GFP_KERNEL); + if (!pair) + return -ENOMEM; + + buffer = iio_backend_ptr_op_call(back, request_buffer, indio_dev); + if (IS_ERR(buffer)) + return PTR_ERR(buffer); + + /* weak reference should be all what we need */ + pair->back = back; + pair->buffer = buffer; + + return devm_add_action_or_reset(dev, iio_backend_free_buffer, pair); +} +EXPORT_SYMBOL_NS_GPL(devm_iio_backend_request_buffer, IIO_BACKEND); + +static void iio_backend_release(void *arg) +{ + struct iio_backend *back = arg; + + module_put(back->owner); +} + +static int __devm_iio_backend_get(struct device *dev, struct iio_backend *back) +{ + struct device_link *link; + int ret; + + /* + * Make sure the provider cannot be unloaded before the consumer module. + * Note that device_links would still guarantee that nothing is + * accessible (and breaks) but this makes it explicit that the consumer + * module must be also unloaded. + */ + if (!try_module_get(back->owner)) + return dev_err_probe(dev, -ENODEV, + "Cannot get module reference\n"); + + ret = devm_add_action_or_reset(dev, iio_backend_release, back); + if (ret) + return ret; + + link = device_link_add(dev, back->dev, DL_FLAG_AUTOREMOVE_CONSUMER); + if (!link) + return dev_err_probe(dev, -EINVAL, + "Could not link to supplier(%s)\n", + dev_name(back->dev)); + + dev_dbg(dev, "Found backend(%s) device\n", dev_name(back->dev)); + + return 0; +} + +/** + * devm_iio_backend_get - Device managed backend device get + * @dev: Consumer device for the backend + * @name: Backend name + * + * Get's the backend associated with @dev. + * + * RETURNS: + * A backend pointer, negative error pointer otherwise. + */ +struct iio_backend *devm_iio_backend_get(struct device *dev, const char *name) +{ + struct fwnode_handle *fwnode; + struct iio_backend *back; + unsigned int index; + int ret; + + if (name) { + ret = device_property_match_string(dev, "io-backend-names", + name); + if (ret < 0) + return ERR_PTR(ret); + index = ret; + } else { + index = 0; + } + + fwnode = fwnode_find_reference(dev_fwnode(dev), "io-backends", index); + if (IS_ERR(fwnode)) { + dev_err_probe(dev, PTR_ERR(fwnode), + "Cannot get Firmware reference\n"); + return ERR_CAST(fwnode); + } + + guard(mutex)(&iio_back_lock); + list_for_each_entry(back, &iio_back_list, entry) { + if (!device_match_fwnode(back->dev, fwnode)) + continue; + + fwnode_handle_put(fwnode); + ret = __devm_iio_backend_get(dev, back); + if (ret) + return ERR_PTR(ret); + + return back; + } + + fwnode_handle_put(fwnode); + return ERR_PTR(-EPROBE_DEFER); +} +EXPORT_SYMBOL_NS_GPL(devm_iio_backend_get, IIO_BACKEND); + +/** + * __devm_iio_backend_get_from_fwnode_lookup - Device managed fwnode backend device get + * @dev: Consumer device for the backend + * @fwnode: Firmware node of the backend device + * + * Search the backend list for a device matching @fwnode. + * This API should not be used and it's only present for preventing the first + * user of this framework to break it's DT ABI. + * + * RETURNS: + * A backend pointer, negative error pointer otherwise. + */ +struct iio_backend * +__devm_iio_backend_get_from_fwnode_lookup(struct device *dev, + struct fwnode_handle *fwnode) +{ + struct iio_backend *back; + int ret; + + guard(mutex)(&iio_back_lock); + list_for_each_entry(back, &iio_back_list, entry) { + if (!device_match_fwnode(back->dev, fwnode)) + continue; + + ret = __devm_iio_backend_get(dev, back); + if (ret) + return ERR_PTR(ret); + + return back; + } + + return ERR_PTR(-EPROBE_DEFER); +} +EXPORT_SYMBOL_NS_GPL(__devm_iio_backend_get_from_fwnode_lookup, IIO_BACKEND); + +/** + * iio_backend_get_priv - Get driver private data + * @back: Backend device + */ +void *iio_backend_get_priv(const struct iio_backend *back) +{ + return back->priv; +} +EXPORT_SYMBOL_NS_GPL(iio_backend_get_priv, IIO_BACKEND); + +static void iio_backend_unregister(void *arg) +{ + struct iio_backend *back = arg; + + guard(mutex)(&iio_back_lock); + list_del(&back->entry); +} + +/** + * devm_iio_backend_register - Device managed backend device register + * @dev: Backend device being registered + * @ops: Backend ops + * @priv: Device private data + * + * @ops is mandatory. Not providing it results in -EINVAL. + * + * RETURNS: + * 0 on success, negative error number on failure. + */ +int devm_iio_backend_register(struct device *dev, + const struct iio_backend_ops *ops, void *priv) +{ + struct iio_backend *back; + + if (!ops) + return dev_err_probe(dev, -EINVAL, "No backend ops given\n"); + + /* + * Through device_links, we guarantee that a frontend device cannot be + * bound/exist if the backend driver is not around. Hence, we can bind + * the backend object lifetime with the device being passed since + * removing it will tear the frontend/consumer down. + */ + back = devm_kzalloc(dev, sizeof(*back), GFP_KERNEL); + if (!back) + return -ENOMEM; + + back->ops = ops; + back->owner = dev->driver->owner; + back->dev = dev; + back->priv = priv; + scoped_guard(mutex, &iio_back_lock) + list_add(&back->entry, &iio_back_list); + + return devm_add_action_or_reset(dev, iio_backend_unregister, back); +} +EXPORT_SYMBOL_NS_GPL(devm_iio_backend_register, IIO_BACKEND); + +MODULE_AUTHOR("Nuno Sa <nuno.sa@analog.com>"); +MODULE_DESCRIPTION("Framework to handle complex IIO aggregate devices"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index 9a85752124dd..4302093b92c7 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -42,7 +42,7 @@ static DEFINE_IDA(iio_ida); static dev_t iio_devt; #define IIO_DEV_MAX 256 -struct bus_type iio_bus_type = { +const struct bus_type iio_bus_type = { .name = "iio", }; EXPORT_SYMBOL(iio_bus_type); @@ -213,9 +213,7 @@ bool iio_buffer_enabled(struct iio_dev *indio_dev) { struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); - return iio_dev_opaque->currentmode & - (INDIO_BUFFER_HARDWARE | INDIO_BUFFER_SOFTWARE | - INDIO_BUFFER_TRIGGERED); + return iio_dev_opaque->currentmode & INDIO_ALL_BUFFER_MODES; } EXPORT_SYMBOL_GPL(iio_buffer_enabled); @@ -1584,10 +1582,13 @@ static int iio_device_register_sysfs(struct iio_dev *indio_dev) ret = iio_device_register_sysfs_group(indio_dev, &iio_dev_opaque->chan_attr_group); if (ret) - goto error_clear_attrs; + goto error_free_chan_attrs; return 0; +error_free_chan_attrs: + kfree(iio_dev_opaque->chan_attr_group.attrs); + iio_dev_opaque->chan_attr_group.attrs = NULL; error_clear_attrs: iio_free_chan_devattr_list(&iio_dev_opaque->channel_attr_list); diff --git a/drivers/iio/industrialio-gts-helper.c b/drivers/iio/industrialio-gts-helper.c index 7653261d2dc2..b51eb6cb766f 100644 --- a/drivers/iio/industrialio-gts-helper.c +++ b/drivers/iio/industrialio-gts-helper.c @@ -34,24 +34,11 @@ static int iio_gts_get_gain(const u64 max, const u64 scale) { u64 full = max; - int tmp = 1; if (scale > full || !scale) return -EINVAL; - if (U64_MAX - full < scale) { - /* Risk of overflow */ - if (full - scale < scale) - return 1; - - full -= scale; - tmp++; - } - - while (full > scale * (u64)tmp) - tmp++; - - return tmp; + return div64_u64(full, scale); } /** diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig index 143003232d1c..fd5a9879a582 100644 --- a/drivers/iio/light/Kconfig +++ b/drivers/iio/light/Kconfig @@ -87,13 +87,14 @@ config APDS9960 module will be called apds9960 config AS73211 - tristate "AMS AS73211 XYZ color sensor" + tristate "AMS AS73211 XYZ color sensor and AMS AS7331 UV sensor" depends on I2C select IIO_BUFFER select IIO_TRIGGERED_BUFFER help If you say yes here you get support for the AMS AS73211 - JENCOLOR(R) Digital XYZ Sensor. + JENCOLOR(R) Digital XYZ and the AMS AS7331 UVA, UVB and UVC + ultraviolet sensors. For triggered measurements, you will need an additional trigger driver like IIO_HRTIMER_TRIGGER or IIO_SYSFS_TRIGGER. diff --git a/drivers/iio/light/as73211.c b/drivers/iio/light/as73211.c index ec97a3a46839..be0068081ebb 100644 --- a/drivers/iio/light/as73211.c +++ b/drivers/iio/light/as73211.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Support for AMS AS73211 JENCOLOR(R) Digital XYZ Sensor + * Support for AMS AS73211 JENCOLOR(R) Digital XYZ Sensor and AMS AS7331 + * UVA, UVB and UVC (DUV) Ultraviolet Sensor * * Author: Christian Eggers <ceggers@arri.de> * @@ -9,7 +10,9 @@ * Color light sensor with 16-bit channels for x, y, z and temperature); * 7-bit I2C slave address 0x74 .. 0x77. * - * Datasheet: https://ams.com/documents/20143/36005/AS73211_DS000556_3-01.pdf + * Datasheets: + * AS73211: https://ams.com/documents/20143/36005/AS73211_DS000556_3-01.pdf + * AS7331: https://ams.com/documents/20143/9106314/AS7331_DS001047_4-00.pdf */ #include <linux/bitfield.h> @@ -84,6 +87,20 @@ static const int as73211_hardwaregain_avail[] = { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, }; +struct as73211_data; + +/** + * struct as73211_spec_dev_data - device-specific data + * @intensity_scale: Function to retrieve intensity scale values. + * @channels: Device channels. + * @num_channels: Number of channels of the device. + */ +struct as73211_spec_dev_data { + int (*intensity_scale)(struct as73211_data *data, int chan, int *val, int *val2); + struct iio_chan_spec const *channels; + int num_channels; +}; + /** * struct as73211_data - Instance data for one AS73211 * @client: I2C client. @@ -94,6 +111,7 @@ static const int as73211_hardwaregain_avail[] = { * @mutex: Keeps cached registers in sync with the device. * @completion: Completion to wait for interrupt. * @int_time_avail: Available integration times (depend on sampling frequency). + * @spec_dev: device-specific configuration. */ struct as73211_data { struct i2c_client *client; @@ -104,6 +122,7 @@ struct as73211_data { struct mutex mutex; struct completion completion; int int_time_avail[AS73211_SAMPLE_TIME_NUM * 2]; + const struct as73211_spec_dev_data *spec_dev; }; #define AS73211_COLOR_CHANNEL(_color, _si, _addr) { \ @@ -138,6 +157,10 @@ struct as73211_data { #define AS73211_SCALE_Y 298384270 /* nW/m^2 */ #define AS73211_SCALE_Z 160241927 /* nW/m^2 */ +#define AS7331_SCALE_UVA 340000 /* nW/cm^2 */ +#define AS7331_SCALE_UVB 378000 /* nW/cm^2 */ +#define AS7331_SCALE_UVC 166000 /* nW/cm^2 */ + /* Channel order MUST match devices result register order */ #define AS73211_SCAN_INDEX_TEMP 0 #define AS73211_SCAN_INDEX_X 1 @@ -176,6 +199,28 @@ static const struct iio_chan_spec as73211_channels[] = { IIO_CHAN_SOFT_TIMESTAMP(AS73211_SCAN_INDEX_TS), }; +static const struct iio_chan_spec as7331_channels[] = { + { + .type = IIO_TEMP, + .info_mask_separate = + BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_OFFSET) | + BIT(IIO_CHAN_INFO_SCALE), + .address = AS73211_OUT_TEMP, + .scan_index = AS73211_SCAN_INDEX_TEMP, + .scan_type = { + .sign = 'u', + .realbits = 16, + .storagebits = 16, + .endianness = IIO_LE, + } + }, + AS73211_COLOR_CHANNEL(LIGHT_UVA, AS73211_SCAN_INDEX_X, AS73211_OUT_MRES1), + AS73211_COLOR_CHANNEL(LIGHT_UVB, AS73211_SCAN_INDEX_Y, AS73211_OUT_MRES2), + AS73211_COLOR_CHANNEL(LIGHT_DUV, AS73211_SCAN_INDEX_Z, AS73211_OUT_MRES3), + IIO_CHAN_SOFT_TIMESTAMP(AS73211_SCAN_INDEX_TS), +}; + static unsigned int as73211_integration_time_1024cyc(struct as73211_data *data) { /* @@ -316,6 +361,48 @@ static int as73211_req_data(struct as73211_data *data) return 0; } +static int as73211_intensity_scale(struct as73211_data *data, int chan, + int *val, int *val2) +{ + switch (chan) { + case IIO_MOD_X: + *val = AS73211_SCALE_X; + break; + case IIO_MOD_Y: + *val = AS73211_SCALE_Y; + break; + case IIO_MOD_Z: + *val = AS73211_SCALE_Z; + break; + default: + return -EINVAL; + } + *val2 = as73211_integration_time_1024cyc(data) * as73211_gain(data); + + return IIO_VAL_FRACTIONAL; +} + +static int as7331_intensity_scale(struct as73211_data *data, int chan, + int *val, int *val2) +{ + switch (chan) { + case IIO_MOD_LIGHT_UVA: + *val = AS7331_SCALE_UVA; + break; + case IIO_MOD_LIGHT_UVB: + *val = AS7331_SCALE_UVB; + break; + case IIO_MOD_LIGHT_DUV: + *val = AS7331_SCALE_UVC; + break; + default: + return -EINVAL; + } + *val2 = as73211_integration_time_1024cyc(data) * as73211_gain(data); + + return IIO_VAL_FRACTIONAL; +} + static int as73211_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long mask) { @@ -355,30 +442,13 @@ static int as73211_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec cons *val2 = AS73211_SCALE_TEMP_MICRO; return IIO_VAL_INT_PLUS_MICRO; - case IIO_INTENSITY: { - unsigned int scale; - - switch (chan->channel2) { - case IIO_MOD_X: - scale = AS73211_SCALE_X; - break; - case IIO_MOD_Y: - scale = AS73211_SCALE_Y; - break; - case IIO_MOD_Z: - scale = AS73211_SCALE_Z; - break; - default: - return -EINVAL; - } - scale /= as73211_gain(data); - scale /= as73211_integration_time_1024cyc(data); - *val = scale; - return IIO_VAL_INT; + case IIO_INTENSITY: + return data->spec_dev->intensity_scale(data, chan->channel2, + val, val2); default: return -EINVAL; - }} + } case IIO_CHAN_INFO_SAMP_FREQ: /* f_samp is configured in CREG3 in powers of 2 (x 1.024 MHz) */ @@ -676,13 +746,17 @@ static int as73211_probe(struct i2c_client *client) i2c_set_clientdata(client, indio_dev); data->client = client; + data->spec_dev = i2c_get_match_data(client); + if (!data->spec_dev) + return -EINVAL; + mutex_init(&data->mutex); init_completion(&data->completion); indio_dev->info = &as73211_info; indio_dev->name = AS73211_DRV_NAME; - indio_dev->channels = as73211_channels; - indio_dev->num_channels = ARRAY_SIZE(as73211_channels); + indio_dev->channels = data->spec_dev->channels; + indio_dev->num_channels = data->spec_dev->num_channels; indio_dev->modes = INDIO_DIRECT_MODE; ret = i2c_smbus_read_byte_data(data->client, AS73211_REG_OSR); @@ -772,14 +846,28 @@ static int as73211_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(as73211_pm_ops, as73211_suspend, as73211_resume); +static const struct as73211_spec_dev_data as73211_spec = { + .intensity_scale = as73211_intensity_scale, + .channels = as73211_channels, + .num_channels = ARRAY_SIZE(as73211_channels), +}; + +static const struct as73211_spec_dev_data as7331_spec = { + .intensity_scale = as7331_intensity_scale, + .channels = as7331_channels, + .num_channels = ARRAY_SIZE(as7331_channels), +}; + static const struct of_device_id as73211_of_match[] = { - { .compatible = "ams,as73211" }, + { .compatible = "ams,as73211", &as73211_spec }, + { .compatible = "ams,as7331", &as7331_spec }, { } }; MODULE_DEVICE_TABLE(of, as73211_of_match); static const struct i2c_device_id as73211_id[] = { - { "as73211", 0 }, + { "as73211", (kernel_ulong_t)&as73211_spec }, + { "as7331", (kernel_ulong_t)&as7331_spec }, { } }; MODULE_DEVICE_TABLE(i2c, as73211_id); diff --git a/drivers/iio/light/hid-sensor-als.c b/drivers/iio/light/hid-sensor-als.c index 5cd27f04b45e..260281194f61 100644 --- a/drivers/iio/light/hid-sensor-als.c +++ b/drivers/iio/light/hid-sensor-als.c @@ -14,8 +14,11 @@ #include "../common/hid-sensors/hid-sensor-trigger.h" enum { - CHANNEL_SCAN_INDEX_INTENSITY = 0, - CHANNEL_SCAN_INDEX_ILLUM = 1, + CHANNEL_SCAN_INDEX_INTENSITY, + CHANNEL_SCAN_INDEX_ILLUM, + CHANNEL_SCAN_INDEX_COLOR_TEMP, + CHANNEL_SCAN_INDEX_CHROMATICITY_X, + CHANNEL_SCAN_INDEX_CHROMATICITY_Y, CHANNEL_SCAN_INDEX_MAX }; @@ -25,6 +28,7 @@ struct als_state { struct hid_sensor_hub_callbacks callbacks; struct hid_sensor_common common_attributes; struct hid_sensor_hub_attribute_info als[CHANNEL_SCAN_INDEX_MAX]; + struct iio_chan_spec channels[CHANNEL_SCAN_INDEX_MAX + 1]; struct { u32 illum[CHANNEL_SCAN_INDEX_MAX]; u64 timestamp __aligned(8); @@ -33,7 +37,18 @@ struct als_state { int scale_post_decml; int scale_precision; int value_offset; + int num_channels; s64 timestamp; + unsigned long als_scan_mask[2]; +}; + +/* The order of usage ids must match scan index starting from CHANNEL_SCAN_INDEX_INTENSITY */ +static const u32 als_usage_ids[] = { + HID_USAGE_SENSOR_LIGHT_ILLUM, + HID_USAGE_SENSOR_LIGHT_ILLUM, + HID_USAGE_SENSOR_LIGHT_COLOR_TEMPERATURE, + HID_USAGE_SENSOR_LIGHT_CHROMATICITY_X, + HID_USAGE_SENSOR_LIGHT_CHROMATICITY_Y, }; static const u32 als_sensitivity_addresses[] = { @@ -65,6 +80,40 @@ static const struct iio_chan_spec als_channels[] = { BIT(IIO_CHAN_INFO_HYSTERESIS_RELATIVE), .scan_index = CHANNEL_SCAN_INDEX_ILLUM, }, + { + .type = IIO_COLORTEMP, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) | + BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_SAMP_FREQ) | + BIT(IIO_CHAN_INFO_HYSTERESIS) | + BIT(IIO_CHAN_INFO_HYSTERESIS_RELATIVE), + .scan_index = CHANNEL_SCAN_INDEX_COLOR_TEMP, + }, + { + .type = IIO_CHROMATICITY, + .modified = 1, + .channel2 = IIO_MOD_X, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) | + BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_SAMP_FREQ) | + BIT(IIO_CHAN_INFO_HYSTERESIS) | + BIT(IIO_CHAN_INFO_HYSTERESIS_RELATIVE), + .scan_index = CHANNEL_SCAN_INDEX_CHROMATICITY_X, + }, + { + .type = IIO_CHROMATICITY, + .modified = 1, + .channel2 = IIO_MOD_Y, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) | + BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_SAMP_FREQ) | + BIT(IIO_CHAN_INFO_HYSTERESIS) | + BIT(IIO_CHAN_INFO_HYSTERESIS_RELATIVE), + .scan_index = CHANNEL_SCAN_INDEX_CHROMATICITY_Y, + }, IIO_CHAN_SOFT_TIMESTAMP(CHANNEL_SCAN_INDEX_TIMESTAMP) }; @@ -103,6 +152,21 @@ static int als_read_raw(struct iio_dev *indio_dev, min = als_state->als[chan->scan_index].logical_minimum; address = HID_USAGE_SENSOR_LIGHT_ILLUM; break; + case CHANNEL_SCAN_INDEX_COLOR_TEMP: + report_id = als_state->als[chan->scan_index].report_id; + min = als_state->als[chan->scan_index].logical_minimum; + address = HID_USAGE_SENSOR_LIGHT_COLOR_TEMPERATURE; + break; + case CHANNEL_SCAN_INDEX_CHROMATICITY_X: + report_id = als_state->als[chan->scan_index].report_id; + min = als_state->als[chan->scan_index].logical_minimum; + address = HID_USAGE_SENSOR_LIGHT_CHROMATICITY_X; + break; + case CHANNEL_SCAN_INDEX_CHROMATICITY_Y: + report_id = als_state->als[chan->scan_index].report_id; + min = als_state->als[chan->scan_index].logical_minimum; + address = HID_USAGE_SENSOR_LIGHT_CHROMATICITY_Y; + break; default: report_id = -1; break; @@ -223,9 +287,22 @@ static int als_capture_sample(struct hid_sensor_hub_device *hsdev, als_state->scan.illum[CHANNEL_SCAN_INDEX_ILLUM] = sample_data; ret = 0; break; + case HID_USAGE_SENSOR_LIGHT_COLOR_TEMPERATURE: + als_state->scan.illum[CHANNEL_SCAN_INDEX_COLOR_TEMP] = sample_data; + ret = 0; + break; + case HID_USAGE_SENSOR_LIGHT_CHROMATICITY_X: + als_state->scan.illum[CHANNEL_SCAN_INDEX_CHROMATICITY_X] = sample_data; + ret = 0; + break; + case HID_USAGE_SENSOR_LIGHT_CHROMATICITY_Y: + als_state->scan.illum[CHANNEL_SCAN_INDEX_CHROMATICITY_Y] = sample_data; + ret = 0; + break; case HID_USAGE_SENSOR_TIME_TIMESTAMP: als_state->timestamp = hid_sensor_convert_timestamp(&als_state->common_attributes, *(s64 *)raw_data); + ret = 0; break; default: break; @@ -237,27 +314,38 @@ static int als_capture_sample(struct hid_sensor_hub_device *hsdev, /* Parse report which is specific to an usage id*/ static int als_parse_report(struct platform_device *pdev, struct hid_sensor_hub_device *hsdev, - struct iio_chan_spec *channels, unsigned usage_id, struct als_state *st) { - int ret; + struct iio_chan_spec *channels; + int ret, index = 0; int i; - for (i = 0; i <= CHANNEL_SCAN_INDEX_ILLUM; ++i) { + channels = st->channels; + + for (i = 0; i < CHANNEL_SCAN_INDEX_MAX; ++i) { ret = sensor_hub_input_get_attribute_info(hsdev, HID_INPUT_REPORT, usage_id, - HID_USAGE_SENSOR_LIGHT_ILLUM, + als_usage_ids[i], &st->als[i]); if (ret < 0) - return ret; - als_adjust_channel_bit_mask(channels, i, st->als[i].size); + continue; + + channels[index] = als_channels[i]; + st->als_scan_mask[0] |= BIT(i); + als_adjust_channel_bit_mask(channels, index, st->als[i].size); + ++index; dev_dbg(&pdev->dev, "als %x:%x\n", st->als[i].index, st->als[i].report_id); } + st->num_channels = index; + /* Return success even if one usage id is present */ + if (index) + ret = 0; + st->scale_precision = hid_sensor_format_scale(usage_id, &st->als[CHANNEL_SCAN_INDEX_INTENSITY], &st->scale_pre_decml, &st->scale_post_decml); @@ -293,15 +381,7 @@ static int hid_als_probe(struct platform_device *pdev) return ret; } - indio_dev->channels = devm_kmemdup(&pdev->dev, als_channels, - sizeof(als_channels), GFP_KERNEL); - if (!indio_dev->channels) { - dev_err(&pdev->dev, "failed to duplicate channels\n"); - return -ENOMEM; - } - ret = als_parse_report(pdev, hsdev, - (struct iio_chan_spec *)indio_dev->channels, hsdev->usage, als_state); if (ret) { @@ -309,8 +389,15 @@ static int hid_als_probe(struct platform_device *pdev) return ret; } - indio_dev->num_channels = - ARRAY_SIZE(als_channels); + /* Add timestamp channel */ + als_state->channels[als_state->num_channels] = als_channels[CHANNEL_SCAN_INDEX_TIMESTAMP]; + + /* +1 for adding timestamp channel */ + indio_dev->num_channels = als_state->num_channels + 1; + + indio_dev->channels = als_state->channels; + indio_dev->available_scan_masks = als_state->als_scan_mask; + indio_dev->info = &als_info; indio_dev->name = name; indio_dev->modes = INDIO_DIRECT_MODE; diff --git a/drivers/iio/light/jsa1212.c b/drivers/iio/light/jsa1212.c index 37e2807041a1..869196746045 100644 --- a/drivers/iio/light/jsa1212.c +++ b/drivers/iio/light/jsa1212.c @@ -12,10 +12,10 @@ #include <linux/kernel.h> #include <linux/slab.h> #include <linux/module.h> +#include <linux/mod_devicetable.h> #include <linux/delay.h> #include <linux/i2c.h> #include <linux/mutex.h> -#include <linux/acpi.h> #include <linux/regmap.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> @@ -438,7 +438,7 @@ static struct i2c_driver jsa1212_driver = { .driver = { .name = JSA1212_DRIVER_NAME, .pm = pm_sleep_ptr(&jsa1212_pm_ops), - .acpi_match_table = ACPI_PTR(jsa1212_acpi_match), + .acpi_match_table = jsa1212_acpi_match, }, .probe = jsa1212_probe, .remove = jsa1212_remove, diff --git a/drivers/iio/light/ltr501.c b/drivers/iio/light/ltr501.c index 061c122fdc5e..8c516ede9116 100644 --- a/drivers/iio/light/ltr501.c +++ b/drivers/iio/light/ltr501.c @@ -10,6 +10,7 @@ */ #include <linux/module.h> +#include <linux/mod_devicetable.h> #include <linux/i2c.h> #include <linux/err.h> #include <linux/delay.h> @@ -1639,7 +1640,7 @@ static struct i2c_driver ltr501_driver = { .name = LTR501_DRV_NAME, .of_match_table = ltr501_of_match, .pm = pm_sleep_ptr(<r501_pm_ops), - .acpi_match_table = ACPI_PTR(ltr_acpi_match), + .acpi_match_table = ltr_acpi_match, }, .probe = ltr501_probe, .remove = ltr501_remove, diff --git a/drivers/iio/light/max44000.c b/drivers/iio/light/max44000.c index db96c5b73100..26b464b1b650 100644 --- a/drivers/iio/light/max44000.c +++ b/drivers/iio/light/max44000.c @@ -10,6 +10,7 @@ */ #include <linux/module.h> +#include <linux/mod_devicetable.h> #include <linux/init.h> #include <linux/i2c.h> #include <linux/regmap.h> @@ -19,7 +20,6 @@ #include <linux/iio/buffer.h> #include <linux/iio/trigger_consumer.h> #include <linux/iio/triggered_buffer.h> -#include <linux/acpi.h> #define MAX44000_DRV_NAME "max44000" @@ -603,18 +603,16 @@ static const struct i2c_device_id max44000_id[] = { }; MODULE_DEVICE_TABLE(i2c, max44000_id); -#ifdef CONFIG_ACPI static const struct acpi_device_id max44000_acpi_match[] = { {"MAX44000", 0}, { } }; MODULE_DEVICE_TABLE(acpi, max44000_acpi_match); -#endif static struct i2c_driver max44000_driver = { .driver = { .name = MAX44000_DRV_NAME, - .acpi_match_table = ACPI_PTR(max44000_acpi_match), + .acpi_match_table = max44000_acpi_match, }, .probe = max44000_probe, .id_table = max44000_id, diff --git a/drivers/iio/light/rpr0521.c b/drivers/iio/light/rpr0521.c index bbb8581622f2..40d5732b5e32 100644 --- a/drivers/iio/light/rpr0521.c +++ b/drivers/iio/light/rpr0521.c @@ -10,11 +10,11 @@ */ #include <linux/module.h> +#include <linux/mod_devicetable.h> #include <linux/init.h> #include <linux/i2c.h> #include <linux/regmap.h> #include <linux/delay.h> -#include <linux/acpi.h> #include <linux/iio/iio.h> #include <linux/iio/buffer.h> @@ -1119,7 +1119,7 @@ static struct i2c_driver rpr0521_driver = { .driver = { .name = RPR0521_DRV_NAME, .pm = pm_ptr(&rpr0521_pm_ops), - .acpi_match_table = ACPI_PTR(rpr0521_acpi_match), + .acpi_match_table = rpr0521_acpi_match, }, .probe = rpr0521_probe, .remove = rpr0521_remove, diff --git a/drivers/iio/light/stk3310.c b/drivers/iio/light/stk3310.c index 72b08d870d33..7b71ad71d78d 100644 --- a/drivers/iio/light/stk3310.c +++ b/drivers/iio/light/stk3310.c @@ -7,11 +7,11 @@ * IIO driver for STK3310/STK3311. 7-bit I2C address: 0x48. */ -#include <linux/acpi.h> #include <linux/i2c.h> #include <linux/interrupt.h> #include <linux/kernel.h> #include <linux/module.h> +#include <linux/mod_devicetable.h> #include <linux/regmap.h> #include <linux/iio/events.h> #include <linux/iio/iio.h> @@ -712,7 +712,7 @@ static struct i2c_driver stk3310_driver = { .name = "stk3310", .of_match_table = stk3310_of_match, .pm = pm_sleep_ptr(&stk3310_pm_ops), - .acpi_match_table = ACPI_PTR(stk3310_acpi_id), + .acpi_match_table = stk3310_acpi_id, }, .probe = stk3310_probe, .remove = stk3310_remove, diff --git a/drivers/iio/light/us5182d.c b/drivers/iio/light/us5182d.c index 61b3b2aea626..9189a1d4d7e1 100644 --- a/drivers/iio/light/us5182d.c +++ b/drivers/iio/light/us5182d.c @@ -9,7 +9,7 @@ #include <linux/kernel.h> #include <linux/module.h> -#include <linux/acpi.h> +#include <linux/mod_devicetable.h> #include <linux/delay.h> #include <linux/i2c.h> #include <linux/iio/events.h> @@ -972,7 +972,7 @@ static struct i2c_driver us5182d_driver = { .name = US5182D_DRV_NAME, .pm = pm_ptr(&us5182d_pm_ops), .of_match_table = us5182d_of_match, - .acpi_match_table = ACPI_PTR(us5182d_acpi_match), + .acpi_match_table = us5182d_acpi_match, }, .probe = us5182d_probe, .remove = us5182d_remove, diff --git a/drivers/iio/light/vcnl4000.c b/drivers/iio/light/vcnl4000.c index fdf763a04b0b..4e3641ff2ed4 100644 --- a/drivers/iio/light/vcnl4000.c +++ b/drivers/iio/light/vcnl4000.c @@ -90,6 +90,7 @@ #define VCNL4040_PS_CONF1_PS_SHUTDOWN BIT(0) #define VCNL4040_PS_CONF2_PS_IT GENMASK(3, 1) /* Proximity integration time */ #define VCNL4040_CONF1_PS_PERS GENMASK(5, 4) /* Proximity interrupt persistence setting */ +#define VCNL4040_PS_CONF2_PS_HD BIT(11) /* Proximity high definition */ #define VCNL4040_PS_CONF2_PS_INT GENMASK(9, 8) /* Proximity interrupt mode */ #define VCNL4040_PS_CONF3_MPS GENMASK(6, 5) /* Proximity multi pulse number */ #define VCNL4040_PS_MS_LED_I GENMASK(10, 8) /* Proximity current */ @@ -114,6 +115,13 @@ #define VCNL4010_INT_DRDY \ (BIT(VCNL4010_INT_PROXIMITY) | BIT(VCNL4010_INT_ALS)) +#define VCNL4040_CONF3_PS_MPS_16BITS 3 /* 8 multi pulses */ +#define VCNL4040_CONF3_PS_LED_I_16BITS 3 /* 120 mA */ + +#define VCNL4040_CONF3_PS_SAMPLE_16BITS \ + (FIELD_PREP(VCNL4040_PS_CONF3_MPS, VCNL4040_CONF3_PS_MPS_16BITS) | \ + FIELD_PREP(VCNL4040_PS_MS_LED_I, VCNL4040_CONF3_PS_LED_I_16BITS)) + static const int vcnl4010_prox_sampling_frequency[][2] = { {1, 950000}, {3, 906250}, @@ -195,6 +203,7 @@ struct vcnl4000_data { enum vcnl4000_device_ids id; int rev; int al_scale; + int ps_scale; u8 ps_int; /* proximity interrupt mode */ u8 als_int; /* ambient light interrupt mode*/ const struct vcnl4000_chip_spec *chip_spec; @@ -345,6 +354,7 @@ static int vcnl4200_set_power_state(struct vcnl4000_data *data, bool on) static int vcnl4200_init(struct vcnl4000_data *data) { int ret, id; + u16 regval; ret = i2c_smbus_read_word_data(data->client, VCNL4200_DEV_ID); if (ret < 0) @@ -386,9 +396,32 @@ static int vcnl4200_init(struct vcnl4000_data *data) break; } data->al_scale = data->chip_spec->ulux_step; + data->ps_scale = 16; mutex_init(&data->vcnl4200_al.lock); mutex_init(&data->vcnl4200_ps.lock); + /* Use 16 bits proximity sensor readings */ + ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF1); + if (ret < 0) + return ret; + + regval = ret | VCNL4040_PS_CONF2_PS_HD; + ret = i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF1, + regval); + if (ret < 0) + return ret; + + /* Align proximity sensor sample rate to 16 bits data width */ + ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF3); + if (ret < 0) + return ret; + + regval = ret | VCNL4040_CONF3_PS_SAMPLE_16BITS; + ret = i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF3, + regval); + if (ret < 0) + return ret; + ret = data->chip_spec->set_power_state(data, true); if (ret < 0) return ret; @@ -901,8 +934,9 @@ static int vcnl4000_read_raw(struct iio_dev *indio_dev, break; case IIO_PROXIMITY: ret = data->chip_spec->measure_proximity(data, val); + *val2 = data->ps_scale; if (!ret) - ret = IIO_VAL_INT; + ret = IIO_VAL_FRACTIONAL; break; default: ret = -EINVAL; diff --git a/drivers/iio/magnetometer/bmc150_magn_i2c.c b/drivers/iio/magnetometer/bmc150_magn_i2c.c index 281d1fa31c8e..48d9c698f520 100644 --- a/drivers/iio/magnetometer/bmc150_magn_i2c.c +++ b/drivers/iio/magnetometer/bmc150_magn_i2c.c @@ -11,7 +11,6 @@ #include <linux/mod_devicetable.h> #include <linux/i2c.h> #include <linux/module.h> -#include <linux/acpi.h> #include <linux/regmap.h> #include "bmc150_magn.h" @@ -68,7 +67,7 @@ static struct i2c_driver bmc150_magn_driver = { .driver = { .name = "bmc150_magn_i2c", .of_match_table = bmc150_magn_of_match, - .acpi_match_table = ACPI_PTR(bmc150_magn_acpi_match), + .acpi_match_table = bmc150_magn_acpi_match, .pm = &bmc150_magn_pm_ops, }, .probe = bmc150_magn_i2c_probe, diff --git a/drivers/iio/magnetometer/bmc150_magn_spi.c b/drivers/iio/magnetometer/bmc150_magn_spi.c index 882987721071..abc75a05c46a 100644 --- a/drivers/iio/magnetometer/bmc150_magn_spi.c +++ b/drivers/iio/magnetometer/bmc150_magn_spi.c @@ -10,7 +10,6 @@ #include <linux/module.h> #include <linux/mod_devicetable.h> #include <linux/spi/spi.h> -#include <linux/acpi.h> #include <linux/regmap.h> #include "bmc150_magn.h" @@ -55,7 +54,7 @@ static struct spi_driver bmc150_magn_spi_driver = { .remove = bmc150_magn_spi_remove, .id_table = bmc150_magn_spi_id, .driver = { - .acpi_match_table = ACPI_PTR(bmc150_magn_acpi_match), + .acpi_match_table = bmc150_magn_acpi_match, .name = "bmc150_magn_spi", }, }; diff --git a/drivers/iio/magnetometer/mmc35240.c b/drivers/iio/magnetometer/mmc35240.c index b495b8a63928..6b9f4b056191 100644 --- a/drivers/iio/magnetometer/mmc35240.c +++ b/drivers/iio/magnetometer/mmc35240.c @@ -10,11 +10,11 @@ */ #include <linux/module.h> +#include <linux/mod_devicetable.h> #include <linux/init.h> #include <linux/i2c.h> #include <linux/delay.h> #include <linux/regmap.h> -#include <linux/acpi.h> #include <linux/pm.h> #include <linux/iio/iio.h> @@ -573,7 +573,7 @@ static struct i2c_driver mmc35240_driver = { .name = MMC35240_DRV_NAME, .of_match_table = mmc35240_of_match, .pm = pm_sleep_ptr(&mmc35240_pm_ops), - .acpi_match_table = ACPI_PTR(mmc35240_acpi_match), + .acpi_match_table = mmc35240_acpi_match, }, .probe = mmc35240_probe, .id_table = mmc35240_id, diff --git a/drivers/iio/magnetometer/rm3100-core.c b/drivers/iio/magnetometer/rm3100-core.c index 69938204456f..42b70cd42b39 100644 --- a/drivers/iio/magnetometer/rm3100-core.c +++ b/drivers/iio/magnetometer/rm3100-core.c @@ -530,6 +530,7 @@ int rm3100_common_probe(struct device *dev, struct regmap *regmap, int irq) struct rm3100_data *data; unsigned int tmp; int ret; + int samp_rate_index; indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); if (!indio_dev) @@ -586,9 +587,14 @@ int rm3100_common_probe(struct device *dev, struct regmap *regmap, int irq) ret = regmap_read(regmap, RM3100_REG_TMRC, &tmp); if (ret < 0) return ret; + + samp_rate_index = tmp - RM3100_TMRC_OFFSET; + if (samp_rate_index < 0 || samp_rate_index >= RM3100_SAMP_NUM) { + dev_err(dev, "The value read from RM3100_REG_TMRC is invalid!\n"); + return -EINVAL; + } /* Initializing max wait time, which is double conversion time. */ - data->conversion_time = rm3100_samp_rates[tmp - RM3100_TMRC_OFFSET][2] - * 2; + data->conversion_time = rm3100_samp_rates[samp_rate_index][2] * 2; /* Cycle count values may not be what we want. */ if ((tmp - RM3100_TMRC_OFFSET) == 0) diff --git a/drivers/iio/potentiometer/max5487.c b/drivers/iio/potentiometer/max5487.c index 42723c996c9f..4838d2e72f53 100644 --- a/drivers/iio/potentiometer/max5487.c +++ b/drivers/iio/potentiometer/max5487.c @@ -5,8 +5,8 @@ * Copyright (C) 2016 Cristina-Gabriela Moraru <cristina.moraru09@gmail.com> */ #include <linux/module.h> +#include <linux/mod_devicetable.h> #include <linux/spi/spi.h> -#include <linux/acpi.h> #include <linux/iio/sysfs.h> #include <linux/iio/iio.h> @@ -144,7 +144,7 @@ MODULE_DEVICE_TABLE(acpi, max5487_acpi_match); static struct spi_driver max5487_driver = { .driver = { .name = "max5487", - .acpi_match_table = ACPI_PTR(max5487_acpi_match), + .acpi_match_table = max5487_acpi_match, }, .id_table = max5487_id, .probe = max5487_spi_probe, diff --git a/drivers/iio/pressure/Kconfig b/drivers/iio/pressure/Kconfig index 79adfd059c3a..3ad38506028e 100644 --- a/drivers/iio/pressure/Kconfig +++ b/drivers/iio/pressure/Kconfig @@ -114,6 +114,8 @@ config HSC030PA depends on (I2C || SPI_MASTER) select HSC030PA_I2C if I2C select HSC030PA_SPI if SPI_MASTER + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER help Say Y here to build support for the Honeywell TruStability HSC and SSC pressure and temperature sensor series. @@ -181,7 +183,9 @@ config MPL3115 config MPRLS0025PA tristate "Honeywell MPRLS0025PA (MicroPressure sensors series)" - depends on I2C + depends on (I2C || SPI_MASTER) + select MPRLS0025PA_I2C if I2C + select MPRLS0025PA_SPI if SPI_MASTER select IIO_BUFFER select IIO_TRIGGERED_BUFFER help @@ -192,6 +196,16 @@ config MPRLS0025PA To compile this driver as a module, choose M here: the module will be called mprls0025pa. +config MPRLS0025PA_I2C + tristate + depends on MPRLS0025PA + depends on I2C + +config MPRLS0025PA_SPI + tristate + depends on MPRLS0025PA + depends on SPI_MASTER + config MS5611 tristate "Measurement Specialties MS5611 pressure sensor driver" select IIO_BUFFER diff --git a/drivers/iio/pressure/Makefile b/drivers/iio/pressure/Makefile index b0f8b94662f2..a93709e35760 100644 --- a/drivers/iio/pressure/Makefile +++ b/drivers/iio/pressure/Makefile @@ -24,6 +24,8 @@ obj-$(CONFIG_MPL115_I2C) += mpl115_i2c.o obj-$(CONFIG_MPL115_SPI) += mpl115_spi.o obj-$(CONFIG_MPL3115) += mpl3115.o obj-$(CONFIG_MPRLS0025PA) += mprls0025pa.o +obj-$(CONFIG_MPRLS0025PA_I2C) += mprls0025pa_i2c.o +obj-$(CONFIG_MPRLS0025PA_SPI) += mprls0025pa_spi.o obj-$(CONFIG_MS5611) += ms5611_core.o obj-$(CONFIG_MS5611_I2C) += ms5611_i2c.o obj-$(CONFIG_MS5611_SPI) += ms5611_spi.o diff --git a/drivers/iio/pressure/bmp280-spi.c b/drivers/iio/pressure/bmp280-spi.c index 433d6fac83c4..e8a5fed07e88 100644 --- a/drivers/iio/pressure/bmp280-spi.c +++ b/drivers/iio/pressure/bmp280-spi.c @@ -87,6 +87,7 @@ static const struct of_device_id bmp280_of_spi_match[] = { MODULE_DEVICE_TABLE(of, bmp280_of_spi_match); static const struct spi_device_id bmp280_spi_id[] = { + { "bmp085", (kernel_ulong_t)&bmp180_chip_info }, { "bmp180", (kernel_ulong_t)&bmp180_chip_info }, { "bmp181", (kernel_ulong_t)&bmp180_chip_info }, { "bmp280", (kernel_ulong_t)&bmp280_chip_info }, diff --git a/drivers/iio/pressure/hp206c.c b/drivers/iio/pressure/hp206c.c index a072de6cb59c..261af1562827 100644 --- a/drivers/iio/pressure/hp206c.c +++ b/drivers/iio/pressure/hp206c.c @@ -11,12 +11,12 @@ */ #include <linux/module.h> +#include <linux/mod_devicetable.h> #include <linux/i2c.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> #include <linux/delay.h> #include <linux/util_macros.h> -#include <linux/acpi.h> #include <asm/unaligned.h> @@ -400,20 +400,18 @@ static const struct i2c_device_id hp206c_id[] = { }; MODULE_DEVICE_TABLE(i2c, hp206c_id); -#ifdef CONFIG_ACPI static const struct acpi_device_id hp206c_acpi_match[] = { {"HOP206C", 0}, { }, }; MODULE_DEVICE_TABLE(acpi, hp206c_acpi_match); -#endif static struct i2c_driver hp206c_driver = { .probe = hp206c_probe, .id_table = hp206c_id, .driver = { .name = "hp206c", - .acpi_match_table = ACPI_PTR(hp206c_acpi_match), + .acpi_match_table = hp206c_acpi_match, }, }; diff --git a/drivers/iio/pressure/hsc030pa.c b/drivers/iio/pressure/hsc030pa.c index d6a51f0c335f..1682b90d4557 100644 --- a/drivers/iio/pressure/hsc030pa.c +++ b/drivers/iio/pressure/hsc030pa.c @@ -22,8 +22,11 @@ #include <linux/types.h> #include <linux/units.h> +#include <linux/iio/buffer.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> +#include <linux/iio/trigger_consumer.h> +#include <linux/iio/triggered_buffer.h> #include <asm/unaligned.h> @@ -297,6 +300,29 @@ static int hsc_get_measurement(struct hsc_data *data) return 0; } +static irqreturn_t hsc_trigger_handler(int irq, void *private) +{ + struct iio_poll_func *pf = private; + struct iio_dev *indio_dev = pf->indio_dev; + struct hsc_data *data = iio_priv(indio_dev); + int ret; + + ret = hsc_get_measurement(data); + if (ret) + goto error; + + 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)); + +error: + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} + /* * IIO ABI expects * value = (conv + offset) * scale @@ -382,13 +408,29 @@ static const struct iio_chan_spec hsc_channels[] = { .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_OFFSET), + .scan_index = 0, + .scan_type = { + .sign = 'u', + .realbits = 14, + .storagebits = 16, + .endianness = IIO_BE, + }, }, { .type = IIO_TEMP, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_OFFSET), + .scan_index = 1, + .scan_type = { + .sign = 'u', + .realbits = 11, + .storagebits = 16, + .shift = 5, + .endianness = IIO_BE, + }, }, + IIO_CHAN_SOFT_TIMESTAMP(2), }; static const struct iio_info hsc_info = { @@ -406,7 +448,7 @@ int hsc_common_probe(struct device *dev, hsc_recv_fn recv) struct hsc_data *hsc; struct iio_dev *indio_dev; const char *triplet; - u64 tmp; + s64 tmp; int ret; indio_dev = devm_iio_device_alloc(dev, sizeof(*hsc)); @@ -485,6 +527,11 @@ int hsc_common_probe(struct device *dev, hsc_recv_fn recv) indio_dev->channels = hsc->chip->channels; indio_dev->num_channels = hsc->chip->num_channels; + ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL, + hsc_trigger_handler, NULL); + if (ret) + return ret; + return devm_iio_device_register(dev, indio_dev); } EXPORT_SYMBOL_NS(hsc_common_probe, IIO_HONEYWELL_HSC030PA); diff --git a/drivers/iio/pressure/hsc030pa.h b/drivers/iio/pressure/hsc030pa.h index d20420dba4f6..9b40f46f575f 100644 --- a/drivers/iio/pressure/hsc030pa.h +++ b/drivers/iio/pressure/hsc030pa.h @@ -10,7 +10,10 @@ #include <linux/types.h> +#include <linux/iio/iio.h> + #define HSC_REG_MEASUREMENT_RD_SIZE 4 +#define HSC_RESP_TIME_MS 2 struct device; @@ -53,6 +56,10 @@ struct hsc_data { s32 p_scale_dec; s64 p_offset; s32 p_offset_dec; + struct { + __be16 chan[2]; + s64 timestamp __aligned(8); + } scan; u8 buffer[HSC_REG_MEASUREMENT_RD_SIZE] __aligned(IIO_DMA_MINALIGN); }; diff --git a/drivers/iio/pressure/hsc030pa_i2c.c b/drivers/iio/pressure/hsc030pa_i2c.c index e2b524b36417..b3fd230e71da 100644 --- a/drivers/iio/pressure/hsc030pa_i2c.c +++ b/drivers/iio/pressure/hsc030pa_i2c.c @@ -4,14 +4,17 @@ * * Copyright (c) 2023 Petre Rodan <petre.rodan@subdimension.ro> * - * Datasheet: https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/products/sensors/pressure-sensors/board-mount-pressure-sensors/trustability-hsc-series/documents/sps-siot-trustability-hsc-series-high-accuracy-board-mount-pressure-sensors-50099148-a-en-ciid-151133.pdf [hsc] - * Datasheet: https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/products/sensors/pressure-sensors/board-mount-pressure-sensors/common/documents/sps-siot-i2c-comms-digital-output-pressure-sensors-tn-008201-3-en-ciid-45841.pdf [i2c related] + * Datasheet: https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/products/sensors/pressure-sensors/board-mount-pressure-sensors/common/documents/sps-siot-i2c-comms-digital-output-pressure-sensors-tn-008201-3-en-ciid-45841.pdf + * Datasheet: https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/products/sensors/pressure-sensors/common/documents/sps-siot-sleep-mode-technical-note-008286-1-en-ciid-155793.pdf */ +#include <linux/delay.h> +#include <linux/device.h> #include <linux/errno.h> #include <linux/i2c.h> #include <linux/mod_devicetable.h> #include <linux/module.h> +#include <linux/types.h> #include <linux/iio/iio.h> @@ -23,6 +26,8 @@ static int hsc_i2c_recv(struct hsc_data *data) struct i2c_msg msg; int ret; + msleep_interruptible(HSC_RESP_TIME_MS); + msg.addr = client->addr; msg.flags = client->flags | I2C_M_RD; msg.len = HSC_REG_MEASUREMENT_RD_SIZE; diff --git a/drivers/iio/pressure/hsc030pa_spi.c b/drivers/iio/pressure/hsc030pa_spi.c index a719bade8326..818fa6303454 100644 --- a/drivers/iio/pressure/hsc030pa_spi.c +++ b/drivers/iio/pressure/hsc030pa_spi.c @@ -4,13 +4,17 @@ * * Copyright (c) 2023 Petre Rodan <petre.rodan@subdimension.ro> * - * Datasheet: https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/products/sensors/pressure-sensors/board-mount-pressure-sensors/trustability-hsc-series/documents/sps-siot-trustability-hsc-series-high-accuracy-board-mount-pressure-sensors-50099148-a-en-ciid-151133.pdf + * Datasheet: https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/products/sensors/pressure-sensors/common/documents/sps-siot-spi-comms-digital-ouptu-pressure-sensors-tn-008202-3-en-ciid-45843.pdf + * Datasheet: https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/products/sensors/pressure-sensors/common/documents/sps-siot-sleep-mode-technical-note-008286-1-en-ciid-155793.pdf */ +#include <linux/delay.h> +#include <linux/device.h> #include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/spi/spi.h> #include <linux/stddef.h> +#include <linux/types.h> #include <linux/iio/iio.h> @@ -25,6 +29,7 @@ static int hsc_spi_recv(struct hsc_data *data) .len = HSC_REG_MEASUREMENT_RD_SIZE, }; + msleep_interruptible(HSC_RESP_TIME_MS); return spi_sync_transfer(spi, &xfer, 1); } diff --git a/drivers/iio/pressure/mprls0025pa.c b/drivers/iio/pressure/mprls0025pa.c index 30fb2de36821..33a15d4c642c 100644 --- a/drivers/iio/pressure/mprls0025pa.c +++ b/drivers/iio/pressure/mprls0025pa.c @@ -5,17 +5,13 @@ * Copyright (c) Andreas Klinger <ak@it-klinger.de> * * Data sheet: - * https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/ - * products/sensors/pressure-sensors/board-mount-pressure-sensors/ - * micropressure-mpr-series/documents/ - * sps-siot-mpr-series-datasheet-32332628-ciid-172626.pdf + * https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/products/sensors/pressure-sensors/board-mount-pressure-sensors/micropressure-mpr-series/documents/sps-siot-mpr-series-datasheet-32332628-ciid-172626.pdf * - * 7-bit I2C default slave address: 0x18 */ -#include <linux/delay.h> -#include <linux/device.h> -#include <linux/i2c.h> +#include <linux/array_size.h> +#include <linux/bitfield.h> +#include <linux/bits.h> #include <linux/math64.h> #include <linux/mod_devicetable.h> #include <linux/module.h> @@ -25,7 +21,6 @@ #include <linux/gpio/consumer.h> #include <linux/iio/buffer.h> -#include <linux/iio/iio.h> #include <linux/iio/trigger_consumer.h> #include <linux/iio/triggered_buffer.h> @@ -33,11 +28,15 @@ #include <asm/unaligned.h> -/* bits in i2c status byte */ -#define MPR_I2C_POWER BIT(6) /* device is powered */ -#define MPR_I2C_BUSY BIT(5) /* device is busy */ -#define MPR_I2C_MEMORY BIT(2) /* integrity test passed */ -#define MPR_I2C_MATH BIT(0) /* internal math saturation */ +#include "mprls0025pa.h" + +/* bits in status byte */ +#define MPR_ST_POWER BIT(6) /* device is powered */ +#define MPR_ST_BUSY BIT(5) /* device is busy */ +#define MPR_ST_MEMORY BIT(2) /* integrity test passed */ +#define MPR_ST_MATH BIT(0) /* internal math saturation */ + +#define MPR_ST_ERR_FLAG (MPR_ST_BUSY | MPR_ST_MEMORY | MPR_ST_MATH) /* * support _RAW sysfs interface: @@ -70,60 +69,87 @@ * transfer function B: 2.5% to 22.5% of 2^24 * transfer function C: 20% to 80% of 2^24 */ -enum mpr_func_id { - MPR_FUNCTION_A, - MPR_FUNCTION_B, - MPR_FUNCTION_C, -}; - struct mpr_func_spec { u32 output_min; u32 output_max; }; static const struct mpr_func_spec mpr_func_spec[] = { - [MPR_FUNCTION_A] = {.output_min = 1677722, .output_max = 15099494}, - [MPR_FUNCTION_B] = {.output_min = 419430, .output_max = 3774874}, - [MPR_FUNCTION_C] = {.output_min = 3355443, .output_max = 13421773}, + [MPR_FUNCTION_A] = { .output_min = 1677722, .output_max = 15099494 }, + [MPR_FUNCTION_B] = { .output_min = 419430, .output_max = 3774874 }, + [MPR_FUNCTION_C] = { .output_min = 3355443, .output_max = 13421773 }, }; -struct mpr_chan { - s32 pres; /* pressure value */ - s64 ts; /* timestamp */ +enum mpr_variants { + MPR0001BA = 0x00, MPR01_6BA = 0x01, MPR02_5BA = 0x02, MPR0060MG = 0x03, + MPR0100MG = 0x04, MPR0160MG = 0x05, MPR0250MG = 0x06, MPR0400MG = 0x07, + MPR0600MG = 0x08, MPR0001BG = 0x09, MPR01_6BG = 0x0a, MPR02_5BG = 0x0b, + MPR0100KA = 0x0c, MPR0160KA = 0x0d, MPR0250KA = 0x0e, MPR0006KG = 0x0f, + MPR0010KG = 0x10, MPR0016KG = 0x11, MPR0025KG = 0x12, MPR0040KG = 0x13, + MPR0060KG = 0x14, MPR0100KG = 0x15, MPR0160KG = 0x16, MPR0250KG = 0x17, + MPR0015PA = 0x18, MPR0025PA = 0x19, MPR0030PA = 0x1a, MPR0001PG = 0x1b, + MPR0005PG = 0x1c, MPR0015PG = 0x1d, MPR0030PG = 0x1e, MPR0300YG = 0x1f, + MPR_VARIANTS_MAX +}; + +static const char * const mpr_triplet_variants[MPR_VARIANTS_MAX] = { + [MPR0001BA] = "0001BA", [MPR01_6BA] = "01.6BA", [MPR02_5BA] = "02.5BA", + [MPR0060MG] = "0060MG", [MPR0100MG] = "0100MG", [MPR0160MG] = "0160MG", + [MPR0250MG] = "0250MG", [MPR0400MG] = "0400MG", [MPR0600MG] = "0600MG", + [MPR0001BG] = "0001BG", [MPR01_6BG] = "01.6BG", [MPR02_5BG] = "02.5BG", + [MPR0100KA] = "0100KA", [MPR0160KA] = "0160KA", [MPR0250KA] = "0250KA", + [MPR0006KG] = "0006KG", [MPR0010KG] = "0010KG", [MPR0016KG] = "0016KG", + [MPR0025KG] = "0025KG", [MPR0040KG] = "0040KG", [MPR0060KG] = "0060KG", + [MPR0100KG] = "0100KG", [MPR0160KG] = "0160KG", [MPR0250KG] = "0250KG", + [MPR0015PA] = "0015PA", [MPR0025PA] = "0025PA", [MPR0030PA] = "0030PA", + [MPR0001PG] = "0001PG", [MPR0005PG] = "0005PG", [MPR0015PG] = "0015PG", + [MPR0030PG] = "0030PG", [MPR0300YG] = "0300YG" +}; + +/** + * struct mpr_range_config - list of pressure ranges based on nomenclature + * @pmin: lowest pressure that can be measured + * @pmax: highest pressure that can be measured + */ +struct mpr_range_config { + const s32 pmin; + const s32 pmax; }; -struct mpr_data { - struct i2c_client *client; - struct mutex lock; /* - * access to device during read - */ - u32 pmin; /* minimal pressure in pascal */ - u32 pmax; /* maximal pressure in pascal */ - enum mpr_func_id function; /* transfer function */ - u32 outmin; /* - * minimal numerical range raw - * value from sensor - */ - u32 outmax; /* - * maximal numerical range raw - * value from sensor - */ - int scale; /* int part of scale */ - int scale2; /* nano part of scale */ - int offset; /* int part of offset */ - int offset2; /* nano part of offset */ - struct gpio_desc *gpiod_reset; /* reset */ - int irq; /* - * end of conversion irq; - * used to distinguish between - * irq mode and reading in a - * loop until data is ready - */ - struct completion completion; /* handshake from irq to read */ - struct mpr_chan chan; /* - * channel values for buffered - * mode - */ +/* All min max limits have been converted to pascals */ +static const struct mpr_range_config mpr_range_config[MPR_VARIANTS_MAX] = { + [MPR0001BA] = { .pmin = 0, .pmax = 100000 }, + [MPR01_6BA] = { .pmin = 0, .pmax = 160000 }, + [MPR02_5BA] = { .pmin = 0, .pmax = 250000 }, + [MPR0060MG] = { .pmin = 0, .pmax = 6000 }, + [MPR0100MG] = { .pmin = 0, .pmax = 10000 }, + [MPR0160MG] = { .pmin = 0, .pmax = 16000 }, + [MPR0250MG] = { .pmin = 0, .pmax = 25000 }, + [MPR0400MG] = { .pmin = 0, .pmax = 40000 }, + [MPR0600MG] = { .pmin = 0, .pmax = 60000 }, + [MPR0001BG] = { .pmin = 0, .pmax = 100000 }, + [MPR01_6BG] = { .pmin = 0, .pmax = 160000 }, + [MPR02_5BG] = { .pmin = 0, .pmax = 250000 }, + [MPR0100KA] = { .pmin = 0, .pmax = 100000 }, + [MPR0160KA] = { .pmin = 0, .pmax = 160000 }, + [MPR0250KA] = { .pmin = 0, .pmax = 250000 }, + [MPR0006KG] = { .pmin = 0, .pmax = 6000 }, + [MPR0010KG] = { .pmin = 0, .pmax = 10000 }, + [MPR0016KG] = { .pmin = 0, .pmax = 16000 }, + [MPR0025KG] = { .pmin = 0, .pmax = 25000 }, + [MPR0040KG] = { .pmin = 0, .pmax = 40000 }, + [MPR0060KG] = { .pmin = 0, .pmax = 60000 }, + [MPR0100KG] = { .pmin = 0, .pmax = 100000 }, + [MPR0160KG] = { .pmin = 0, .pmax = 160000 }, + [MPR0250KG] = { .pmin = 0, .pmax = 250000 }, + [MPR0015PA] = { .pmin = 0, .pmax = 103421 }, + [MPR0025PA] = { .pmin = 0, .pmax = 172369 }, + [MPR0030PA] = { .pmin = 0, .pmax = 206843 }, + [MPR0001PG] = { .pmin = 0, .pmax = 6895 }, + [MPR0005PG] = { .pmin = 0, .pmax = 34474 }, + [MPR0015PG] = { .pmin = 0, .pmax = 103421 }, + [MPR0030PG] = { .pmin = 0, .pmax = 206843 }, + [MPR0300YG] = { .pmin = 0, .pmax = 39997 } }; static const struct iio_chan_spec mpr_channels[] = { @@ -153,11 +179,11 @@ static void mpr_reset(struct mpr_data *data) } /** - * mpr_read_pressure() - Read pressure value from sensor via I2C + * mpr_read_pressure() - Read pressure value from sensor * @data: Pointer to private data struct. * @press: Output value read from sensor. * - * Reading from the sensor by sending and receiving I2C telegrams. + * Reading from the sensor by sending and receiving telegrams. * * If there is an end of conversion (EOC) interrupt registered the function * waits for a maximum of one second for the interrupt. @@ -170,25 +196,17 @@ static void mpr_reset(struct mpr_data *data) */ static int mpr_read_pressure(struct mpr_data *data, s32 *press) { - struct device *dev = &data->client->dev; + struct device *dev = data->dev; int ret, i; - u8 wdata[] = {0xAA, 0x00, 0x00}; - s32 status; int nloops = 10; - u8 buf[4]; reinit_completion(&data->completion); - ret = i2c_master_send(data->client, wdata, sizeof(wdata)); + ret = data->ops->write(data, MPR_CMD_SYNC, MPR_PKT_SYNC_LEN); if (ret < 0) { dev_err(dev, "error while writing ret: %d\n", ret); return ret; } - if (ret != sizeof(wdata)) { - dev_err(dev, "received size doesn't fit - ret: %d / %u\n", ret, - (u32)sizeof(wdata)); - return -EIO; - } if (data->irq > 0) { ret = wait_for_completion_timeout(&data->completion, HZ); @@ -206,14 +224,14 @@ static int mpr_read_pressure(struct mpr_data *data, s32 *press) * quite long */ usleep_range(5000, 10000); - status = i2c_smbus_read_byte(data->client); - if (status < 0) { + ret = data->ops->read(data, MPR_CMD_NOP, 1); + if (ret < 0) { dev_err(dev, "error while reading, status: %d\n", - status); - return status; + ret); + return ret; } - if (!(status & MPR_I2C_BUSY)) + if (!(data->buffer[0] & MPR_ST_ERR_FLAG)) break; } if (i == nloops) { @@ -222,29 +240,19 @@ static int mpr_read_pressure(struct mpr_data *data, s32 *press) } } - ret = i2c_master_recv(data->client, buf, sizeof(buf)); - if (ret < 0) { - dev_err(dev, "error in i2c_master_recv ret: %d\n", ret); + ret = data->ops->read(data, MPR_CMD_NOP, MPR_PKT_NOP_LEN); + if (ret < 0) return ret; - } - if (ret != sizeof(buf)) { - dev_err(dev, "received size doesn't fit - ret: %d / %u\n", ret, - (u32)sizeof(buf)); - return -EIO; - } - if (buf[0] & MPR_I2C_BUSY) { - /* - * it should never be the case that status still indicates - * business - */ - dev_err(dev, "data still not ready: %08x\n", buf[0]); + if (data->buffer[0] & MPR_ST_ERR_FLAG) { + dev_err(data->dev, + "unexpected status byte %02x\n", data->buffer[0]); return -ETIMEDOUT; } - *press = get_unaligned_be24(&buf[1]); + *press = get_unaligned_be24(&data->buffer[1]); - dev_dbg(dev, "received: %*ph cnt: %d\n", ret, buf, *press); + dev_dbg(dev, "received: %*ph cnt: %d\n", ret, data->buffer, *press); return 0; } @@ -271,7 +279,7 @@ static irqreturn_t mpr_trigger_handler(int irq, void *p) goto err; iio_push_to_buffers_with_timestamp(indio_dev, &data->chan, - iio_get_time_ns(indio_dev)); + iio_get_time_ns(indio_dev)); err: mutex_unlock(&data->lock); @@ -316,25 +324,23 @@ static const struct iio_info mpr_info = { .read_raw = &mpr_read_raw, }; -static int mpr_probe(struct i2c_client *client) +int mpr_common_probe(struct device *dev, const struct mpr_ops *ops, int irq) { int ret; struct mpr_data *data; struct iio_dev *indio_dev; - struct device *dev = &client->dev; + const char *triplet; s64 scale, offset; - - if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_BYTE)) - return dev_err_probe(dev, -EOPNOTSUPP, - "I2C functionality not supported\n"); + u32 func; indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); if (!indio_dev) - return dev_err_probe(dev, -ENOMEM, "couldn't get iio_dev\n"); + return -ENOMEM; data = iio_priv(indio_dev); - data->client = client; - data->irq = client->irq; + data->dev = dev; + data->ops = ops; + data->irq = irq; mutex_init(&data->lock); init_completion(&data->completion); @@ -348,103 +354,102 @@ static int mpr_probe(struct i2c_client *client) ret = devm_regulator_get_enable(dev, "vdd"); if (ret) return dev_err_probe(dev, ret, - "can't get and enable vdd supply\n"); + "can't get and enable vdd supply\n"); - if (dev_fwnode(dev)) { + ret = data->ops->init(data->dev); + if (ret) + return ret; + + ret = device_property_read_u32(dev, + "honeywell,transfer-function", &func); + if (ret) + return dev_err_probe(dev, ret, + "honeywell,transfer-function could not be read\n"); + data->function = func - 1; + if (data->function > MPR_FUNCTION_C) + return dev_err_probe(dev, -EINVAL, + "honeywell,transfer-function %d invalid\n", + data->function); + + ret = device_property_read_string(dev, "honeywell,pressure-triplet", + &triplet); + if (ret) { ret = device_property_read_u32(dev, "honeywell,pmin-pascal", - &data->pmin); + &data->pmin); if (ret) return dev_err_probe(dev, ret, - "honeywell,pmin-pascal could not be read\n"); + "honeywell,pmin-pascal could not be read\n"); + ret = device_property_read_u32(dev, "honeywell,pmax-pascal", - &data->pmax); + &data->pmax); if (ret) return dev_err_probe(dev, ret, - "honeywell,pmax-pascal could not be read\n"); - ret = device_property_read_u32(dev, - "honeywell,transfer-function", &data->function); - if (ret) - return dev_err_probe(dev, ret, - "honeywell,transfer-function could not be read\n"); - if (data->function > MPR_FUNCTION_C) - return dev_err_probe(dev, -EINVAL, - "honeywell,transfer-function %d invalid\n", - data->function); + "honeywell,pmax-pascal could not be read\n"); } else { - /* when loaded as i2c device we need to use default values */ - dev_notice(dev, "firmware node not found; using defaults\n"); - data->pmin = 0; - data->pmax = 172369; /* 25 psi */ - data->function = MPR_FUNCTION_A; + ret = device_property_match_property_string(dev, + "honeywell,pressure-triplet", + mpr_triplet_variants, + MPR_VARIANTS_MAX); + if (ret < 0) + return dev_err_probe(dev, -EINVAL, + "honeywell,pressure-triplet is invalid\n"); + + data->pmin = mpr_range_config[ret].pmin; + data->pmax = mpr_range_config[ret].pmax; } + if (data->pmin >= data->pmax) + return dev_err_probe(dev, -EINVAL, + "pressure limits are invalid\n"); + data->outmin = mpr_func_spec[data->function].output_min; data->outmax = mpr_func_spec[data->function].output_max; /* use 64 bit calculation for preserving a reasonable precision */ scale = div_s64(((s64)(data->pmax - data->pmin)) * NANO, - data->outmax - data->outmin); + data->outmax - data->outmin); data->scale = div_s64_rem(scale, NANO, &data->scale2); /* * multiply with NANO before dividing by scale and later divide by NANO * again. */ offset = ((-1LL) * (s64)data->outmin) * NANO - - div_s64(div_s64((s64)data->pmin * NANO, scale), NANO); + div_s64(div_s64((s64)data->pmin * NANO, scale), NANO); data->offset = div_s64_rem(offset, NANO, &data->offset2); if (data->irq > 0) { ret = devm_request_irq(dev, data->irq, mpr_eoc_handler, - IRQF_TRIGGER_RISING, client->name, data); + IRQF_TRIGGER_RISING, + dev_name(dev), + data); if (ret) return dev_err_probe(dev, ret, - "request irq %d failed\n", data->irq); + "request irq %d failed\n", data->irq); } data->gpiod_reset = devm_gpiod_get_optional(dev, "reset", - GPIOD_OUT_HIGH); + GPIOD_OUT_HIGH); if (IS_ERR(data->gpiod_reset)) return dev_err_probe(dev, PTR_ERR(data->gpiod_reset), - "request reset-gpio failed\n"); + "request reset-gpio failed\n"); mpr_reset(data); ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL, - mpr_trigger_handler, NULL); + mpr_trigger_handler, NULL); if (ret) return dev_err_probe(dev, ret, - "iio triggered buffer setup failed\n"); + "iio triggered buffer setup failed\n"); ret = devm_iio_device_register(dev, indio_dev); if (ret) return dev_err_probe(dev, ret, - "unable to register iio device\n"); + "unable to register iio device\n"); return 0; } - -static const struct of_device_id mpr_matches[] = { - { .compatible = "honeywell,mprls0025pa" }, - { } -}; -MODULE_DEVICE_TABLE(of, mpr_matches); - -static const struct i2c_device_id mpr_id[] = { - { "mprls0025pa" }, - { } -}; -MODULE_DEVICE_TABLE(i2c, mpr_id); - -static struct i2c_driver mpr_driver = { - .probe = mpr_probe, - .id_table = mpr_id, - .driver = { - .name = "mprls0025pa", - .of_match_table = mpr_matches, - }, -}; -module_i2c_driver(mpr_driver); +EXPORT_SYMBOL_NS(mpr_common_probe, IIO_HONEYWELL_MPRLS0025PA); MODULE_AUTHOR("Andreas Klinger <ak@it-klinger.de>"); -MODULE_DESCRIPTION("Honeywell MPRLS0025PA I2C driver"); +MODULE_DESCRIPTION("Honeywell MPR pressure sensor core driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/iio/pressure/mprls0025pa.h b/drivers/iio/pressure/mprls0025pa.h new file mode 100644 index 000000000000..9d5c30afa9d6 --- /dev/null +++ b/drivers/iio/pressure/mprls0025pa.h @@ -0,0 +1,102 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * MPRLS0025PA - Honeywell MicroPressure pressure sensor series driver + * + * Copyright (c) Andreas Klinger <ak@it-klinger.de> + * + * Data sheet: + * https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/products/sensors/pressure-sensors/board-mount-pressure-sensors/micropressure-mpr-series/documents/sps-siot-mpr-series-datasheet-32332628-ciid-172626.pdf + */ + +#ifndef _MPRLS0025PA_H +#define _MPRLS0025PA_H + +#include <linux/completion.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/mutex.h> +#include <linux/stddef.h> +#include <linux/types.h> + +#include <linux/iio/iio.h> + +#define MPR_MEASUREMENT_RD_SIZE 4 +#define MPR_CMD_NOP 0xf0 +#define MPR_CMD_SYNC 0xaa +#define MPR_PKT_NOP_LEN MPR_MEASUREMENT_RD_SIZE +#define MPR_PKT_SYNC_LEN 3 + +struct device; + +struct iio_chan_spec; +struct iio_dev; + +struct mpr_data; +struct mpr_ops; + +/** + * struct mpr_chan + * @pres: pressure value + * @ts: timestamp + */ +struct mpr_chan { + s32 pres; + s64 ts; +}; + +enum mpr_func_id { + MPR_FUNCTION_A, + MPR_FUNCTION_B, + MPR_FUNCTION_C, +}; + +/** + * struct mpr_data + * @dev: current device structure + * @ops: functions that implement the sensor reads/writes, bus init + * @lock: access to device during read + * @pmin: minimal pressure in pascal + * @pmax: maximal pressure in pascal + * @function: transfer function + * @outmin: minimum raw pressure in counts (based on transfer function) + * @outmax: maximum raw pressure in counts (based on transfer function) + * @scale: pressure scale + * @scale2: pressure scale, decimal number + * @offset: pressure offset + * @offset2: pressure offset, decimal number + * @gpiod_reset: reset + * @irq: end of conversion irq. used to distinguish between irq mode and + * reading in a loop until data is ready + * @completion: handshake from irq to read + * @chan: channel values for buffered mode + * @buffer: raw conversion data + */ +struct mpr_data { + struct device *dev; + const struct mpr_ops *ops; + struct mutex lock; + u32 pmin; + u32 pmax; + enum mpr_func_id function; + u32 outmin; + u32 outmax; + int scale; + int scale2; + int offset; + int offset2; + struct gpio_desc *gpiod_reset; + int irq; + struct completion completion; + struct mpr_chan chan; + u8 buffer[MPR_MEASUREMENT_RD_SIZE] __aligned(IIO_DMA_MINALIGN); +}; + +struct mpr_ops { + int (*init)(struct device *dev); + int (*read)(struct mpr_data *data, const u8 cmd, const u8 cnt); + int (*write)(struct mpr_data *data, const u8 cmd, const u8 cnt); +}; + +int mpr_common_probe(struct device *dev, const struct mpr_ops *ops, int irq); + +#endif diff --git a/drivers/iio/pressure/mprls0025pa_i2c.c b/drivers/iio/pressure/mprls0025pa_i2c.c new file mode 100644 index 000000000000..7a5c5aa2b456 --- /dev/null +++ b/drivers/iio/pressure/mprls0025pa_i2c.c @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * MPRLS0025PA - Honeywell MicroPressure pressure sensor series driver + * + * Copyright (c) Andreas Klinger <ak@it-klinger.de> + * + * Data sheet: + * https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/products/sensors/pressure-sensors/board-mount-pressure-sensors/micropressure-mpr-series/documents/sps-siot-mpr-series-datasheet-32332628-ciid-172626.pdf + */ + +#include <linux/device.h> +#include <linux/errno.h> +#include <linux/i2c.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/types.h> + +#include "mprls0025pa.h" + +static int mpr_i2c_init(struct device *unused) +{ + return 0; +} + +static int mpr_i2c_read(struct mpr_data *data, const u8 unused, const u8 cnt) +{ + int ret; + struct i2c_client *client = to_i2c_client(data->dev); + + if (cnt > MPR_MEASUREMENT_RD_SIZE) + return -EOVERFLOW; + + memset(data->buffer, 0, MPR_MEASUREMENT_RD_SIZE); + ret = i2c_master_recv(client, data->buffer, cnt); + if (ret < 0) + return ret; + else if (ret != cnt) + return -EIO; + + return 0; +} + +static int mpr_i2c_write(struct mpr_data *data, const u8 cmd, const u8 unused) +{ + int ret; + struct i2c_client *client = to_i2c_client(data->dev); + u8 wdata[MPR_PKT_SYNC_LEN]; + + memset(wdata, 0, sizeof(wdata)); + wdata[0] = cmd; + + ret = i2c_master_send(client, wdata, MPR_PKT_SYNC_LEN); + if (ret < 0) + return ret; + else if (ret != MPR_PKT_SYNC_LEN) + return -EIO; + + return 0; +} + +static const struct mpr_ops mpr_i2c_ops = { + .init = mpr_i2c_init, + .read = mpr_i2c_read, + .write = mpr_i2c_write, +}; + +static int mpr_i2c_probe(struct i2c_client *client) +{ + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_BYTE)) + return -EOPNOTSUPP; + + return mpr_common_probe(&client->dev, &mpr_i2c_ops, client->irq); +} + +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); + +static struct i2c_driver mpr_i2c_driver = { + .probe = mpr_i2c_probe, + .id_table = mpr_i2c_id, + .driver = { + .name = "mprls0025pa", + .of_match_table = mpr_i2c_match, + }, +}; +module_i2c_driver(mpr_i2c_driver); + +MODULE_AUTHOR("Andreas Klinger <ak@it-klinger.de>"); +MODULE_DESCRIPTION("Honeywell MPR pressure sensor i2c driver"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(IIO_HONEYWELL_MPRLS0025PA); diff --git a/drivers/iio/pressure/mprls0025pa_spi.c b/drivers/iio/pressure/mprls0025pa_spi.c new file mode 100644 index 000000000000..3aed14cd95c5 --- /dev/null +++ b/drivers/iio/pressure/mprls0025pa_spi.c @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * MPRLS0025PA - Honeywell MicroPressure MPR series SPI sensor driver + * + * Copyright (c) 2024 Petre Rodan <petre.rodan@subdimension.ro> + * + * Data sheet: + * https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/products/sensors/pressure-sensors/board-mount-pressure-sensors/micropressure-mpr-series/documents/sps-siot-mpr-series-datasheet-32332628-ciid-172626.pdf + */ + +#include <linux/device.h> +#include <linux/errno.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/spi/spi.h> +#include <linux/stddef.h> +#include <linux/types.h> + +#include "mprls0025pa.h" + +struct mpr_spi_buf { + u8 tx[MPR_MEASUREMENT_RD_SIZE] __aligned(IIO_DMA_MINALIGN); +}; + +static int mpr_spi_init(struct device *dev) +{ + struct spi_device *spi = to_spi_device(dev); + struct mpr_spi_buf *buf; + + buf = devm_kzalloc(dev, sizeof(*buf), GFP_KERNEL); + if (!buf) + return -ENOMEM; + + spi_set_drvdata(spi, buf); + + return 0; +} + +static int mpr_spi_xfer(struct mpr_data *data, const u8 cmd, const u8 pkt_len) +{ + struct spi_device *spi = to_spi_device(data->dev); + struct mpr_spi_buf *buf = spi_get_drvdata(spi); + struct spi_transfer xfer; + + if (pkt_len > MPR_MEASUREMENT_RD_SIZE) + return -EOVERFLOW; + + buf->tx[0] = cmd; + xfer.tx_buf = buf->tx; + xfer.rx_buf = data->buffer; + xfer.len = pkt_len; + + return spi_sync_transfer(spi, &xfer, 1); +} + +static const struct mpr_ops mpr_spi_ops = { + .init = mpr_spi_init, + .read = mpr_spi_xfer, + .write = mpr_spi_xfer, +}; + +static int mpr_spi_probe(struct spi_device *spi) +{ + return mpr_common_probe(&spi->dev, &mpr_spi_ops, spi->irq); +} + +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); + +static struct spi_driver mpr_spi_driver = { + .driver = { + .name = "mprls0025pa", + .of_match_table = mpr_spi_match, + }, + .probe = mpr_spi_probe, + .id_table = mpr_spi_id, +}; +module_spi_driver(mpr_spi_driver); + +MODULE_AUTHOR("Petre Rodan <petre.rodan@subdimension.ro>"); +MODULE_DESCRIPTION("Honeywell MPR pressure sensor spi driver"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(IIO_HONEYWELL_MPRLS0025PA); diff --git a/drivers/iio/pressure/st_pressure_i2c.c b/drivers/iio/pressure/st_pressure_i2c.c index 5101552e3f38..389523d6ae32 100644 --- a/drivers/iio/pressure/st_pressure_i2c.c +++ b/drivers/iio/pressure/st_pressure_i2c.c @@ -7,7 +7,6 @@ * Denis Ciocca <denis.ciocca@st.com> */ -#include <linux/acpi.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/mod_devicetable.h> @@ -55,13 +54,11 @@ static const struct of_device_id st_press_of_match[] = { }; MODULE_DEVICE_TABLE(of, st_press_of_match); -#ifdef CONFIG_ACPI static const struct acpi_device_id st_press_acpi_match[] = { {"SNO9210", LPS22HB}, { }, }; MODULE_DEVICE_TABLE(acpi, st_press_acpi_match); -#endif static const struct i2c_device_id st_press_id_table[] = { { LPS001WP_PRESS_DEV_NAME, LPS001WP }, @@ -114,7 +111,7 @@ static struct i2c_driver st_press_driver = { .driver = { .name = "st-press-i2c", .of_match_table = st_press_of_match, - .acpi_match_table = ACPI_PTR(st_press_acpi_match), + .acpi_match_table = st_press_acpi_match, }, .probe = st_press_i2c_probe, .id_table = st_press_id_table, diff --git a/drivers/iio/proximity/sx9310.c b/drivers/iio/proximity/sx9310.c index 0d230a0dff56..427c9343d6d1 100644 --- a/drivers/iio/proximity/sx9310.c +++ b/drivers/iio/proximity/sx9310.c @@ -337,28 +337,19 @@ static int sx9310_read_raw(struct iio_dev *indio_dev, int *val2, long mask) { struct sx_common_data *data = iio_priv(indio_dev); - int ret; if (chan->type != IIO_PROXIMITY) return -EINVAL; switch (mask) { case IIO_CHAN_INFO_RAW: - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; - - ret = sx_common_read_proximity(data, chan, val); - iio_device_release_direct_mode(indio_dev); - return ret; + iio_device_claim_direct_scoped(return -EBUSY, indio_dev) + return sx_common_read_proximity(data, chan, val); + unreachable(); case IIO_CHAN_INFO_HARDWAREGAIN: - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; - - ret = sx9310_read_gain(data, chan, val); - iio_device_release_direct_mode(indio_dev); - return ret; + iio_device_claim_direct_scoped(return -EBUSY, indio_dev) + return sx9310_read_gain(data, chan, val); + unreachable(); case IIO_CHAN_INFO_SAMP_FREQ: return sx9310_read_samp_freq(data, val, val2); default: @@ -546,12 +537,10 @@ static int sx9310_write_thresh(struct sx_common_data *data, return -EINVAL; regval = FIELD_PREP(SX9310_REG_PROX_CTRL8_9_PTHRESH_MASK, regval); - mutex_lock(&data->mutex); - ret = regmap_update_bits(data->regmap, reg, - SX9310_REG_PROX_CTRL8_9_PTHRESH_MASK, regval); - mutex_unlock(&data->mutex); - return ret; + guard(mutex)(&data->mutex); + return regmap_update_bits(data->regmap, reg, + SX9310_REG_PROX_CTRL8_9_PTHRESH_MASK, regval); } static int sx9310_write_hysteresis(struct sx_common_data *data, @@ -576,17 +565,14 @@ static int sx9310_write_hysteresis(struct sx_common_data *data, return -EINVAL; hyst = FIELD_PREP(SX9310_REG_PROX_CTRL10_HYST_MASK, hyst); - mutex_lock(&data->mutex); - ret = regmap_update_bits(data->regmap, SX9310_REG_PROX_CTRL10, - SX9310_REG_PROX_CTRL10_HYST_MASK, hyst); - mutex_unlock(&data->mutex); - return ret; + guard(mutex)(&data->mutex); + return regmap_update_bits(data->regmap, SX9310_REG_PROX_CTRL10, + SX9310_REG_PROX_CTRL10_HYST_MASK, hyst); } static int sx9310_write_far_debounce(struct sx_common_data *data, int val) { - int ret; unsigned int regval; if (val > 0) @@ -596,18 +582,14 @@ static int sx9310_write_far_debounce(struct sx_common_data *data, int val) regval = FIELD_PREP(SX9310_REG_PROX_CTRL10_FAR_DEBOUNCE_MASK, val); - mutex_lock(&data->mutex); - ret = regmap_update_bits(data->regmap, SX9310_REG_PROX_CTRL10, - SX9310_REG_PROX_CTRL10_FAR_DEBOUNCE_MASK, - regval); - mutex_unlock(&data->mutex); - - return ret; + guard(mutex)(&data->mutex); + return regmap_update_bits(data->regmap, SX9310_REG_PROX_CTRL10, + SX9310_REG_PROX_CTRL10_FAR_DEBOUNCE_MASK, + regval); } static int sx9310_write_close_debounce(struct sx_common_data *data, int val) { - int ret; unsigned int regval; if (val > 0) @@ -617,13 +599,10 @@ static int sx9310_write_close_debounce(struct sx_common_data *data, int val) regval = FIELD_PREP(SX9310_REG_PROX_CTRL10_CLOSE_DEBOUNCE_MASK, val); - mutex_lock(&data->mutex); - ret = regmap_update_bits(data->regmap, SX9310_REG_PROX_CTRL10, - SX9310_REG_PROX_CTRL10_CLOSE_DEBOUNCE_MASK, - regval); - mutex_unlock(&data->mutex); - - return ret; + guard(mutex)(&data->mutex); + return regmap_update_bits(data->regmap, SX9310_REG_PROX_CTRL10, + SX9310_REG_PROX_CTRL10_CLOSE_DEBOUNCE_MASK, + regval); } static int sx9310_write_event_val(struct iio_dev *indio_dev, @@ -658,7 +637,7 @@ static int sx9310_write_event_val(struct iio_dev *indio_dev, static int sx9310_set_samp_freq(struct sx_common_data *data, int val, int val2) { - int i, ret; + int i; for (i = 0; i < ARRAY_SIZE(sx9310_samp_freq_table); i++) if (val == sx9310_samp_freq_table[i].val && @@ -668,23 +647,17 @@ static int sx9310_set_samp_freq(struct sx_common_data *data, int val, int val2) if (i == ARRAY_SIZE(sx9310_samp_freq_table)) return -EINVAL; - mutex_lock(&data->mutex); - - ret = regmap_update_bits( + guard(mutex)(&data->mutex); + return regmap_update_bits( data->regmap, SX9310_REG_PROX_CTRL0, SX9310_REG_PROX_CTRL0_SCANPERIOD_MASK, FIELD_PREP(SX9310_REG_PROX_CTRL0_SCANPERIOD_MASK, i)); - - mutex_unlock(&data->mutex); - - return ret; } static int sx9310_write_gain(struct sx_common_data *data, const struct iio_chan_spec *chan, int val) { unsigned int gain, mask; - int ret; gain = ilog2(val); @@ -703,12 +676,9 @@ static int sx9310_write_gain(struct sx_common_data *data, return -EINVAL; } - mutex_lock(&data->mutex); - ret = regmap_update_bits(data->regmap, SX9310_REG_PROX_CTRL3, mask, - gain); - mutex_unlock(&data->mutex); - - return ret; + guard(mutex)(&data->mutex); + return regmap_update_bits(data->regmap, SX9310_REG_PROX_CTRL3, mask, + gain); } static int sx9310_write_raw(struct iio_dev *indio_dev, @@ -969,22 +939,18 @@ static int sx9310_suspend(struct device *dev) disable_irq_nosync(data->client->irq); - mutex_lock(&data->mutex); + guard(mutex)(&data->mutex); ret = regmap_read(data->regmap, SX9310_REG_PROX_CTRL0, &data->suspend_ctrl); if (ret) - goto out; + return ret; ctrl0 = data->suspend_ctrl & ~SX9310_REG_PROX_CTRL0_SENSOREN_MASK; ret = regmap_write(data->regmap, SX9310_REG_PROX_CTRL0, ctrl0); if (ret) - goto out; - - ret = regmap_write(data->regmap, SX9310_REG_PAUSE, 0); + return ret; -out: - mutex_unlock(&data->mutex); - return ret; + return regmap_write(data->regmap, SX9310_REG_PAUSE, 0); } static int sx9310_resume(struct device *dev) @@ -992,18 +958,16 @@ static int sx9310_resume(struct device *dev) struct sx_common_data *data = iio_priv(dev_get_drvdata(dev)); int ret; - mutex_lock(&data->mutex); - ret = regmap_write(data->regmap, SX9310_REG_PAUSE, 1); - if (ret) - goto out; - - ret = regmap_write(data->regmap, SX9310_REG_PROX_CTRL0, - data->suspend_ctrl); + scoped_guard(mutex, &data->mutex) { + ret = regmap_write(data->regmap, SX9310_REG_PAUSE, 1); + if (ret) + return ret; -out: - mutex_unlock(&data->mutex); - if (ret) - return ret; + ret = regmap_write(data->regmap, SX9310_REG_PROX_CTRL0, + data->suspend_ctrl); + if (ret) + return ret; + } enable_irq(data->client->irq); return 0; diff --git a/drivers/iio/proximity/sx9324.c b/drivers/iio/proximity/sx9324.c index ac2ed2da21cc..aa0d14a49d5e 100644 --- a/drivers/iio/proximity/sx9324.c +++ b/drivers/iio/proximity/sx9324.c @@ -429,25 +429,16 @@ static int sx9324_read_raw(struct iio_dev *indio_dev, int *val, int *val2, long mask) { struct sx_common_data *data = iio_priv(indio_dev); - int ret; switch (mask) { case IIO_CHAN_INFO_RAW: - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; - - ret = sx_common_read_proximity(data, chan, val); - iio_device_release_direct_mode(indio_dev); - return ret; + iio_device_claim_direct_scoped(return -EBUSY, indio_dev) + return sx_common_read_proximity(data, chan, val); + unreachable(); case IIO_CHAN_INFO_HARDWAREGAIN: - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; - - ret = sx9324_read_gain(data, chan, val); - iio_device_release_direct_mode(indio_dev); - return ret; + iio_device_claim_direct_scoped(return -EBUSY, indio_dev) + return sx9324_read_gain(data, chan, val); + unreachable(); case IIO_CHAN_INFO_SAMP_FREQ: return sx9324_read_samp_freq(data, val, val2); default: @@ -484,7 +475,7 @@ static int sx9324_read_avail(struct iio_dev *indio_dev, static int sx9324_set_samp_freq(struct sx_common_data *data, int val, int val2) { - int i, ret; + int i; for (i = 0; i < ARRAY_SIZE(sx9324_samp_freq_table); i++) if (val == sx9324_samp_freq_table[i].val && @@ -494,15 +485,11 @@ static int sx9324_set_samp_freq(struct sx_common_data *data, if (i == ARRAY_SIZE(sx9324_samp_freq_table)) return -EINVAL; - mutex_lock(&data->mutex); - - ret = regmap_update_bits(data->regmap, - SX9324_REG_GNRL_CTRL0, - SX9324_REG_GNRL_CTRL0_SCANPERIOD_MASK, i); - - mutex_unlock(&data->mutex); + guard(mutex)(&data->mutex); - return ret; + return regmap_update_bits(data->regmap, + SX9324_REG_GNRL_CTRL0, + SX9324_REG_GNRL_CTRL0_SCANPERIOD_MASK, i); } static int sx9324_read_thresh(struct sx_common_data *data, @@ -623,7 +610,6 @@ static int sx9324_write_thresh(struct sx_common_data *data, const struct iio_chan_spec *chan, int _val) { unsigned int reg, val = _val; - int ret; reg = SX9324_REG_PROX_CTRL6 + chan->channel / 2; @@ -633,11 +619,9 @@ static int sx9324_write_thresh(struct sx_common_data *data, if (val > 0xff) return -EINVAL; - mutex_lock(&data->mutex); - ret = regmap_write(data->regmap, reg, val); - mutex_unlock(&data->mutex); + guard(mutex)(&data->mutex); - return ret; + return regmap_write(data->regmap, reg, val); } static int sx9324_write_hysteresis(struct sx_common_data *data, @@ -662,18 +646,15 @@ static int sx9324_write_hysteresis(struct sx_common_data *data, return -EINVAL; hyst = FIELD_PREP(SX9324_REG_PROX_CTRL5_HYST_MASK, hyst); - mutex_lock(&data->mutex); - ret = regmap_update_bits(data->regmap, SX9324_REG_PROX_CTRL5, - SX9324_REG_PROX_CTRL5_HYST_MASK, hyst); - mutex_unlock(&data->mutex); + guard(mutex)(&data->mutex); - return ret; + return regmap_update_bits(data->regmap, SX9324_REG_PROX_CTRL5, + SX9324_REG_PROX_CTRL5_HYST_MASK, hyst); } static int sx9324_write_far_debounce(struct sx_common_data *data, int _val) { unsigned int regval, val = _val; - int ret; if (val > 0) val = ilog2(val); @@ -682,19 +663,16 @@ static int sx9324_write_far_debounce(struct sx_common_data *data, int _val) regval = FIELD_PREP(SX9324_REG_PROX_CTRL5_FAR_DEBOUNCE_MASK, val); - mutex_lock(&data->mutex); - ret = regmap_update_bits(data->regmap, SX9324_REG_PROX_CTRL5, - SX9324_REG_PROX_CTRL5_FAR_DEBOUNCE_MASK, - regval); - mutex_unlock(&data->mutex); + guard(mutex)(&data->mutex); - return ret; + return regmap_update_bits(data->regmap, SX9324_REG_PROX_CTRL5, + SX9324_REG_PROX_CTRL5_FAR_DEBOUNCE_MASK, + regval); } static int sx9324_write_close_debounce(struct sx_common_data *data, int _val) { unsigned int regval, val = _val; - int ret; if (val > 0) val = ilog2(val); @@ -703,13 +681,11 @@ static int sx9324_write_close_debounce(struct sx_common_data *data, int _val) regval = FIELD_PREP(SX9324_REG_PROX_CTRL5_CLOSE_DEBOUNCE_MASK, val); - mutex_lock(&data->mutex); - ret = regmap_update_bits(data->regmap, SX9324_REG_PROX_CTRL5, - SX9324_REG_PROX_CTRL5_CLOSE_DEBOUNCE_MASK, - regval); - mutex_unlock(&data->mutex); + guard(mutex)(&data->mutex); - return ret; + return regmap_update_bits(data->regmap, SX9324_REG_PROX_CTRL5, + SX9324_REG_PROX_CTRL5_CLOSE_DEBOUNCE_MASK, + regval); } static int sx9324_write_event_val(struct iio_dev *indio_dev, @@ -746,7 +722,6 @@ static int sx9324_write_gain(struct sx_common_data *data, const struct iio_chan_spec *chan, int val) { unsigned int gain, reg; - int ret; reg = SX9324_REG_PROX_CTRL0 + chan->channel / 2; @@ -756,13 +731,11 @@ static int sx9324_write_gain(struct sx_common_data *data, gain = FIELD_PREP(SX9324_REG_PROX_CTRL0_GAIN_MASK, gain); - mutex_lock(&data->mutex); - ret = regmap_update_bits(data->regmap, reg, - SX9324_REG_PROX_CTRL0_GAIN_MASK, - gain); - mutex_unlock(&data->mutex); + guard(mutex)(&data->mutex); - return ret; + return regmap_update_bits(data->regmap, reg, + SX9324_REG_PROX_CTRL0_GAIN_MASK, + gain); } static int sx9324_write_raw(struct iio_dev *indio_dev, @@ -873,6 +846,29 @@ static int sx9324_init_compensation(struct iio_dev *indio_dev) 20000, 2000000); } +static u8 sx9324_parse_phase_prop(struct device *dev, + struct sx_common_reg_default *reg_def, + const char *prop) +{ + unsigned int pin_defs[SX9324_NUM_PINS]; + int count, ret, pin; + u32 raw = 0; + + count = device_property_count_u32(dev, prop); + if (count != ARRAY_SIZE(pin_defs)) + return reg_def->def; + ret = device_property_read_u32_array(dev, prop, pin_defs, + ARRAY_SIZE(pin_defs)); + if (ret) + return reg_def->def; + + for (pin = 0; pin < SX9324_NUM_PINS; pin++) + raw |= (pin_defs[pin] << (2 * pin)) & + SX9324_REG_AFE_PH0_PIN_MASK(pin); + + return raw; +} + static const struct sx_common_reg_default * sx9324_get_default_reg(struct device *dev, int idx, struct sx_common_reg_default *reg_def) @@ -881,37 +877,29 @@ sx9324_get_default_reg(struct device *dev, int idx, "highest" }; static const char * const sx9324_csidle[] = { "hi-z", "hi-z", "gnd", "vdd" }; -#define SX9324_PIN_DEF "semtech,ph0-pin" -#define SX9324_RESOLUTION_DEF "semtech,ph01-resolution" -#define SX9324_PROXRAW_DEF "semtech,ph01-proxraw-strength" - unsigned int pin_defs[SX9324_NUM_PINS]; - char prop[] = SX9324_PROXRAW_DEF; u32 start = 0, raw = 0, pos = 0; - int ret, count, ph, pin; + const char *prop; + int ret; memcpy(reg_def, &sx9324_default_regs[idx], sizeof(*reg_def)); sx_common_get_raw_register_config(dev, reg_def); switch (reg_def->reg) { case SX9324_REG_AFE_PH0: + reg_def->def = sx9324_parse_phase_prop(dev, reg_def, + "semtech,ph0-pin"); + break; case SX9324_REG_AFE_PH1: + reg_def->def = sx9324_parse_phase_prop(dev, reg_def, + "semtech,ph1-pin"); + break; case SX9324_REG_AFE_PH2: + reg_def->def = sx9324_parse_phase_prop(dev, reg_def, + "semtech,ph2-pin"); + break; case SX9324_REG_AFE_PH3: - ph = reg_def->reg - SX9324_REG_AFE_PH0; - snprintf(prop, ARRAY_SIZE(prop), "semtech,ph%d-pin", ph); - - count = device_property_count_u32(dev, prop); - if (count != ARRAY_SIZE(pin_defs)) - break; - ret = device_property_read_u32_array(dev, prop, pin_defs, - ARRAY_SIZE(pin_defs)); - if (ret) - break; - - for (pin = 0; pin < SX9324_NUM_PINS; pin++) - raw |= (pin_defs[pin] << (2 * pin)) & - SX9324_REG_AFE_PH0_PIN_MASK(pin); - reg_def->def = raw; + reg_def->def = sx9324_parse_phase_prop(dev, reg_def, + "semtech,ph3-pin"); break; case SX9324_REG_AFE_CTRL0: ret = device_property_match_property_string(dev, "semtech,cs-idle-sleep", @@ -933,11 +921,9 @@ sx9324_get_default_reg(struct device *dev, int idx, case SX9324_REG_AFE_CTRL4: case SX9324_REG_AFE_CTRL7: if (reg_def->reg == SX9324_REG_AFE_CTRL4) - strncpy(prop, "semtech,ph01-resolution", - ARRAY_SIZE(prop)); + prop = "semtech,ph01-resolution"; else - strncpy(prop, "semtech,ph23-resolution", - ARRAY_SIZE(prop)); + prop = "semtech,ph23-resolution"; ret = device_property_read_u32(dev, prop, &raw); if (ret) @@ -1008,11 +994,9 @@ sx9324_get_default_reg(struct device *dev, int idx, case SX9324_REG_PROX_CTRL0: case SX9324_REG_PROX_CTRL1: if (reg_def->reg == SX9324_REG_PROX_CTRL0) - strncpy(prop, "semtech,ph01-proxraw-strength", - ARRAY_SIZE(prop)); + prop = "semtech,ph01-proxraw-strength"; else - strncpy(prop, "semtech,ph23-proxraw-strength", - ARRAY_SIZE(prop)); + prop = "semtech,ph23-proxraw-strength"; ret = device_property_read_u32(dev, prop, &raw); if (ret) break; @@ -1081,34 +1065,30 @@ static int sx9324_suspend(struct device *dev) disable_irq_nosync(data->client->irq); - mutex_lock(&data->mutex); + guard(mutex)(&data->mutex); ret = regmap_read(data->regmap, SX9324_REG_GNRL_CTRL1, ®val); + if (ret < 0) + return ret; data->suspend_ctrl = FIELD_GET(SX9324_REG_GNRL_CTRL1_PHEN_MASK, regval); - if (ret < 0) - goto out; /* Disable all phases, send the device to sleep. */ - ret = regmap_write(data->regmap, SX9324_REG_GNRL_CTRL1, 0); - -out: - mutex_unlock(&data->mutex); - return ret; + return regmap_write(data->regmap, SX9324_REG_GNRL_CTRL1, 0); } static int sx9324_resume(struct device *dev) { struct sx_common_data *data = iio_priv(dev_get_drvdata(dev)); - int ret; - mutex_lock(&data->mutex); - ret = regmap_write(data->regmap, SX9324_REG_GNRL_CTRL1, - data->suspend_ctrl | SX9324_REG_GNRL_CTRL1_PAUSECTRL); - mutex_unlock(&data->mutex); - if (ret) - return ret; + scoped_guard(mutex, &data->mutex) { + int ret = regmap_write(data->regmap, SX9324_REG_GNRL_CTRL1, + data->suspend_ctrl | + SX9324_REG_GNRL_CTRL1_PAUSECTRL); + if (ret) + return ret; + } enable_irq(data->client->irq); return 0; diff --git a/drivers/iio/proximity/sx9360.c b/drivers/iio/proximity/sx9360.c index 2c4e14a4fe9f..75a1c29f14eb 100644 --- a/drivers/iio/proximity/sx9360.c +++ b/drivers/iio/proximity/sx9360.c @@ -322,25 +322,16 @@ static int sx9360_read_raw(struct iio_dev *indio_dev, int *val, int *val2, long mask) { struct sx_common_data *data = iio_priv(indio_dev); - int ret; switch (mask) { case IIO_CHAN_INFO_RAW: - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; - - ret = sx_common_read_proximity(data, chan, val); - iio_device_release_direct_mode(indio_dev); - return ret; + iio_device_claim_direct_scoped(return -EBUSY, indio_dev) + return sx_common_read_proximity(data, chan, val); + unreachable(); case IIO_CHAN_INFO_HARDWAREGAIN: - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; - - ret = sx9360_read_gain(data, chan, val); - iio_device_release_direct_mode(indio_dev); - return ret; + iio_device_claim_direct_scoped(return -EBUSY, indio_dev) + return sx9360_read_gain(data, chan, val); + unreachable(); case IIO_CHAN_INFO_SAMP_FREQ: return sx9360_read_samp_freq(data, val, val2); default: @@ -387,19 +378,15 @@ static int sx9360_read_avail(struct iio_dev *indio_dev, static int sx9360_set_samp_freq(struct sx_common_data *data, int val, int val2) { - int ret, reg; + int reg; __be16 buf; reg = val * 8192 / SX9360_FOSC_HZ + val2 * 8192 / (SX9360_FOSC_MHZ); buf = cpu_to_be16(reg); - mutex_lock(&data->mutex); - - ret = regmap_bulk_write(data->regmap, SX9360_REG_GNRL_CTRL1, &buf, - sizeof(buf)); + guard(mutex)(&data->mutex); - mutex_unlock(&data->mutex); - - return ret; + return regmap_bulk_write(data->regmap, SX9360_REG_GNRL_CTRL1, &buf, + sizeof(buf)); } static int sx9360_read_thresh(struct sx_common_data *data, int *val) @@ -510,7 +497,6 @@ static int sx9360_read_event_val(struct iio_dev *indio_dev, static int sx9360_write_thresh(struct sx_common_data *data, int _val) { unsigned int val = _val; - int ret; if (val >= 1) val = int_sqrt(2 * val); @@ -518,11 +504,8 @@ static int sx9360_write_thresh(struct sx_common_data *data, int _val) if (val > 0xff) return -EINVAL; - mutex_lock(&data->mutex); - ret = regmap_write(data->regmap, SX9360_REG_PROX_CTRL5, val); - mutex_unlock(&data->mutex); - - return ret; + guard(mutex)(&data->mutex); + return regmap_write(data->regmap, SX9360_REG_PROX_CTRL5, val); } static int sx9360_write_hysteresis(struct sx_common_data *data, int _val) @@ -546,18 +529,14 @@ static int sx9360_write_hysteresis(struct sx_common_data *data, int _val) return -EINVAL; hyst = FIELD_PREP(SX9360_REG_PROX_CTRL4_HYST_MASK, hyst); - mutex_lock(&data->mutex); - ret = regmap_update_bits(data->regmap, SX9360_REG_PROX_CTRL4, - SX9360_REG_PROX_CTRL4_HYST_MASK, hyst); - mutex_unlock(&data->mutex); - - return ret; + guard(mutex)(&data->mutex); + return regmap_update_bits(data->regmap, SX9360_REG_PROX_CTRL4, + SX9360_REG_PROX_CTRL4_HYST_MASK, hyst); } static int sx9360_write_far_debounce(struct sx_common_data *data, int _val) { unsigned int regval, val = _val; - int ret; if (val > 0) val = ilog2(val); @@ -566,19 +545,15 @@ static int sx9360_write_far_debounce(struct sx_common_data *data, int _val) regval = FIELD_PREP(SX9360_REG_PROX_CTRL4_FAR_DEBOUNCE_MASK, val); - mutex_lock(&data->mutex); - ret = regmap_update_bits(data->regmap, SX9360_REG_PROX_CTRL4, - SX9360_REG_PROX_CTRL4_FAR_DEBOUNCE_MASK, - regval); - mutex_unlock(&data->mutex); - - return ret; + guard(mutex)(&data->mutex); + return regmap_update_bits(data->regmap, SX9360_REG_PROX_CTRL4, + SX9360_REG_PROX_CTRL4_FAR_DEBOUNCE_MASK, + regval); } static int sx9360_write_close_debounce(struct sx_common_data *data, int _val) { unsigned int regval, val = _val; - int ret; if (val > 0) val = ilog2(val); @@ -587,13 +562,10 @@ static int sx9360_write_close_debounce(struct sx_common_data *data, int _val) regval = FIELD_PREP(SX9360_REG_PROX_CTRL4_CLOSE_DEBOUNCE_MASK, val); - mutex_lock(&data->mutex); - ret = regmap_update_bits(data->regmap, SX9360_REG_PROX_CTRL4, - SX9360_REG_PROX_CTRL4_CLOSE_DEBOUNCE_MASK, - regval); - mutex_unlock(&data->mutex); - - return ret; + guard(mutex)(&data->mutex); + return regmap_update_bits(data->regmap, SX9360_REG_PROX_CTRL4, + SX9360_REG_PROX_CTRL4_CLOSE_DEBOUNCE_MASK, + regval); } static int sx9360_write_event_val(struct iio_dev *indio_dev, @@ -630,19 +602,15 @@ static int sx9360_write_gain(struct sx_common_data *data, const struct iio_chan_spec *chan, int val) { unsigned int gain, reg; - int ret; gain = ilog2(val); reg = SX9360_REG_PROX_CTRL0_PHR + chan->channel; gain = FIELD_PREP(SX9360_REG_PROX_CTRL0_GAIN_MASK, gain); - mutex_lock(&data->mutex); - ret = regmap_update_bits(data->regmap, reg, - SX9360_REG_PROX_CTRL0_GAIN_MASK, - gain); - mutex_unlock(&data->mutex); - - return ret; + guard(mutex)(&data->mutex); + return regmap_update_bits(data->regmap, reg, + SX9360_REG_PROX_CTRL0_GAIN_MASK, + gain); } static int sx9360_write_raw(struct iio_dev *indio_dev, @@ -827,36 +795,31 @@ static int sx9360_suspend(struct device *dev) disable_irq_nosync(data->client->irq); - mutex_lock(&data->mutex); + guard(mutex)(&data->mutex); ret = regmap_read(data->regmap, SX9360_REG_GNRL_CTRL0, ®val); + if (ret < 0) + return ret; data->suspend_ctrl = FIELD_GET(SX9360_REG_GNRL_CTRL0_PHEN_MASK, regval); - if (ret < 0) - goto out; /* Disable all phases, send the device to sleep. */ - ret = regmap_write(data->regmap, SX9360_REG_GNRL_CTRL0, 0); - -out: - mutex_unlock(&data->mutex); - return ret; + return regmap_write(data->regmap, SX9360_REG_GNRL_CTRL0, 0); } static int sx9360_resume(struct device *dev) { struct sx_common_data *data = iio_priv(dev_get_drvdata(dev)); - int ret; - - mutex_lock(&data->mutex); - ret = regmap_update_bits(data->regmap, SX9360_REG_GNRL_CTRL0, - SX9360_REG_GNRL_CTRL0_PHEN_MASK, - data->suspend_ctrl); - mutex_unlock(&data->mutex); - if (ret) - return ret; + scoped_guard(mutex, &data->mutex) { + int ret = regmap_update_bits(data->regmap, + SX9360_REG_GNRL_CTRL0, + SX9360_REG_GNRL_CTRL0_PHEN_MASK, + data->suspend_ctrl); + if (ret) + return ret; + } enable_irq(data->client->irq); return 0; } diff --git a/drivers/iio/test/Kconfig b/drivers/iio/test/Kconfig index 0b6e4e278a2f..33cca49c8058 100644 --- a/drivers/iio/test/Kconfig +++ b/drivers/iio/test/Kconfig @@ -4,6 +4,20 @@ # # Keep in alphabetical order +config IIO_GTS_KUNIT_TEST + tristate "Test IIO formatting functions" if !KUNIT_ALL_TESTS + depends on KUNIT + select IIO_GTS_HELPER + select TEST_KUNIT_DEVICE_HELPERS + default KUNIT_ALL_TESTS + help + build unit tests for the IIO light sensor gain-time-scale helpers. + + For more information on KUnit and unit tests in general, please refer + to the KUnit documentation in Documentation/dev-tools/kunit/. + + If unsure, say N. Keep in alphabetical order + config IIO_RESCALE_KUNIT_TEST tristate "Test IIO rescale conversion functions" if !KUNIT_ALL_TESTS depends on KUNIT && IIO_RESCALE diff --git a/drivers/iio/test/Makefile b/drivers/iio/test/Makefile index d76eaf36da82..e9a4cf1ff57f 100644 --- a/drivers/iio/test/Makefile +++ b/drivers/iio/test/Makefile @@ -6,4 +6,5 @@ # Keep in alphabetical order obj-$(CONFIG_IIO_RESCALE_KUNIT_TEST) += iio-test-rescale.o obj-$(CONFIG_IIO_FORMAT_KUNIT_TEST) += iio-test-format.o +obj-$(CONFIG_IIO_GTS_KUNIT_TEST) += iio-test-gts.o CFLAGS_iio-test-format.o += $(DISABLE_STRUCTLEAK_PLUGIN) diff --git a/drivers/iio/test/iio-test-gts.c b/drivers/iio/test/iio-test-gts.c new file mode 100644 index 000000000000..cf7ab773ea0b --- /dev/null +++ b/drivers/iio/test/iio-test-gts.c @@ -0,0 +1,513 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Unit tests for IIO light sensor gain-time-scale helpers + * + * Copyright (c) 2023 Matti Vaittinen <mazziesaccount@gmail.com> + */ + +#include <kunit/device.h> +#include <kunit/test.h> +#include <linux/device.h> +#include <linux/iio/iio-gts-helper.h> +#include <linux/iio/types.h> + +/* + * Please, read the "rant" from the top of the lib/test_linear_ranges.c if + * you see a line of helper code which is not being tested. + * + * Then, please look at the line which is not being tested. Is this line + * somehow unusually complex? If answer is "no", then chances are that the + * "development inertia" caused by adding a test exceeds the benefits. + * + * If yes, then adding a test is probably a good idea but please stop for a + * moment and consider the effort of changing all the tests when code gets + * refactored. Eventually it neeeds to be. + */ + +#define TEST_TSEL_50 1 +#define TEST_TSEL_X_MIN TEST_TSEL_50 +#define TEST_TSEL_100 0 +#define TEST_TSEL_200 2 +#define TEST_TSEL_400 4 +#define TEST_TSEL_X_MAX TEST_TSEL_400 + +#define TEST_GSEL_1 0x00 +#define TEST_GSEL_X_MIN TEST_GSEL_1 +#define TEST_GSEL_4 0x08 +#define TEST_GSEL_16 0x0a +#define TEST_GSEL_32 0x0b +#define TEST_GSEL_64 0x0c +#define TEST_GSEL_256 0x18 +#define TEST_GSEL_512 0x19 +#define TEST_GSEL_1024 0x1a +#define TEST_GSEL_2048 0x1b +#define TEST_GSEL_4096 0x1c +#define TEST_GSEL_X_MAX TEST_GSEL_4096 + +#define TEST_SCALE_1X 64 +#define TEST_SCALE_MIN_X TEST_SCALE_1X +#define TEST_SCALE_2X 32 +#define TEST_SCALE_4X 16 +#define TEST_SCALE_8X 8 +#define TEST_SCALE_16X 4 +#define TEST_SCALE_32X 2 +#define TEST_SCALE_64X 1 + +#define TEST_SCALE_NANO_128X 500000000 +#define TEST_SCALE_NANO_256X 250000000 +#define TEST_SCALE_NANO_512X 125000000 +#define TEST_SCALE_NANO_1024X 62500000 +#define TEST_SCALE_NANO_2048X 31250000 +#define TEST_SCALE_NANO_4096X 15625000 +#define TEST_SCALE_NANO_4096X2 7812500 +#define TEST_SCALE_NANO_4096X4 3906250 +#define TEST_SCALE_NANO_4096X8 1953125 + +#define TEST_SCALE_NANO_MAX_X TEST_SCALE_NANO_4096X8 + +/* + * Can't have this allocated from stack because the kunit clean-up will + * happen only after the test function has already gone + */ +static struct iio_gts gts; + +static const struct iio_gain_sel_pair gts_test_gains[] = { + GAIN_SCALE_GAIN(1, TEST_GSEL_1), + GAIN_SCALE_GAIN(4, TEST_GSEL_4), + GAIN_SCALE_GAIN(16, TEST_GSEL_16), + GAIN_SCALE_GAIN(32, TEST_GSEL_32), + GAIN_SCALE_GAIN(64, TEST_GSEL_64), + GAIN_SCALE_GAIN(256, TEST_GSEL_256), + GAIN_SCALE_GAIN(512, TEST_GSEL_512), + GAIN_SCALE_GAIN(1024, TEST_GSEL_1024), + GAIN_SCALE_GAIN(2048, TEST_GSEL_2048), + GAIN_SCALE_GAIN(4096, TEST_GSEL_4096), +#define HWGAIN_MAX 4096 +}; + +static const struct iio_itime_sel_mul gts_test_itimes[] = { + GAIN_SCALE_ITIME_US(400 * 1000, TEST_TSEL_400, 8), + GAIN_SCALE_ITIME_US(200 * 1000, TEST_TSEL_200, 4), + GAIN_SCALE_ITIME_US(100 * 1000, TEST_TSEL_100, 2), + GAIN_SCALE_ITIME_US(50 * 1000, TEST_TSEL_50, 1), +#define TIMEGAIN_MAX 8 +}; +#define TOTAL_GAIN_MAX (HWGAIN_MAX * TIMEGAIN_MAX) +#define IIO_GTS_TEST_DEV "iio-gts-test-dev" + +static struct device *__test_init_iio_gain_scale(struct kunit *test, + struct iio_gts *gts, const struct iio_gain_sel_pair *g_table, + int num_g, const struct iio_itime_sel_mul *i_table, int num_i) +{ + struct device *dev; + int ret; + + dev = kunit_device_register(test, IIO_GTS_TEST_DEV); + + KUNIT_EXPECT_NOT_ERR_OR_NULL(test, dev); + if (IS_ERR_OR_NULL(dev)) + return NULL; + + ret = devm_iio_init_iio_gts(dev, TEST_SCALE_1X, 0, g_table, num_g, + i_table, num_i, gts); + KUNIT_EXPECT_EQ(test, 0, ret); + if (ret) + return NULL; + + return dev; +} + +#define test_init_iio_gain_scale(test, gts) \ + __test_init_iio_gain_scale(test, gts, gts_test_gains, \ + ARRAY_SIZE(gts_test_gains), gts_test_itimes, \ + ARRAY_SIZE(gts_test_itimes)) + +static void test_init_iio_gts_invalid(struct kunit *test) +{ + struct device *dev; + int ret; + const struct iio_itime_sel_mul itimes_neg[] = { + GAIN_SCALE_ITIME_US(-10, TEST_TSEL_400, 8), + GAIN_SCALE_ITIME_US(200 * 1000, TEST_TSEL_200, 4), + }; + const struct iio_gain_sel_pair gains_neg[] = { + GAIN_SCALE_GAIN(1, TEST_GSEL_1), + GAIN_SCALE_GAIN(2, TEST_GSEL_4), + GAIN_SCALE_GAIN(-2, TEST_GSEL_16), + }; + /* 55555 * 38656 = 2147534080 => overflows 32bit int */ + const struct iio_itime_sel_mul itimes_overflow[] = { + GAIN_SCALE_ITIME_US(400 * 1000, TEST_TSEL_400, 55555), + GAIN_SCALE_ITIME_US(200 * 1000, TEST_TSEL_200, 4), + }; + const struct iio_gain_sel_pair gains_overflow[] = { + GAIN_SCALE_GAIN(1, TEST_GSEL_1), + GAIN_SCALE_GAIN(2, TEST_GSEL_4), + GAIN_SCALE_GAIN(38656, TEST_GSEL_16), + }; + + dev = kunit_device_register(test, IIO_GTS_TEST_DEV); + KUNIT_EXPECT_NOT_ERR_OR_NULL(test, dev); + if (!dev) + return; + + /* Ok gains, negative time */ + ret = devm_iio_init_iio_gts(dev, TEST_SCALE_1X, 0, gts_test_gains, + ARRAY_SIZE(gts_test_gains), itimes_neg, + ARRAY_SIZE(itimes_neg), >s); + KUNIT_EXPECT_EQ(test, -EINVAL, ret); + + /* Ok times, negative gain */ + ret = devm_iio_init_iio_gts(dev, TEST_SCALE_1X, 0, gains_neg, + ARRAY_SIZE(gains_neg), gts_test_itimes, + ARRAY_SIZE(gts_test_itimes), >s); + KUNIT_EXPECT_EQ(test, -EINVAL, ret); + + /* gain * time overflow int */ + ret = devm_iio_init_iio_gts(dev, TEST_SCALE_1X, 0, gains_overflow, + ARRAY_SIZE(gains_overflow), itimes_overflow, + ARRAY_SIZE(itimes_overflow), >s); + KUNIT_EXPECT_EQ(test, -EOVERFLOW, ret); +} + +static void test_iio_gts_find_gain_for_scale_using_time(struct kunit *test) +{ + struct device *dev; + int ret, gain_sel; + + dev = test_init_iio_gain_scale(test, >s); + if (!dev) + return; + + ret = iio_gts_find_gain_sel_for_scale_using_time(>s, TEST_TSEL_100, + TEST_SCALE_8X, 0, &gain_sel); + /* + * Meas time 100 => gain by time 2x + * TEST_SCALE_8X matches total gain 8x + * => required HWGAIN 4x + */ + KUNIT_EXPECT_EQ(test, 0, ret); + KUNIT_EXPECT_EQ(test, TEST_GSEL_4, gain_sel); + + ret = iio_gts_find_gain_sel_for_scale_using_time(>s, TEST_TSEL_200, 0, + TEST_SCALE_NANO_256X, &gain_sel); + /* + * Meas time 200 => gain by time 4x + * TEST_SCALE_256X matches total gain 256x + * => required HWGAIN 256/4 => 64x + */ + KUNIT_EXPECT_EQ(test, 0, ret); + KUNIT_EXPECT_EQ(test, TEST_GSEL_64, gain_sel); + + /* Min time, Min gain */ + ret = iio_gts_find_gain_sel_for_scale_using_time(>s, TEST_TSEL_X_MIN, + TEST_SCALE_MIN_X, 0, &gain_sel); + KUNIT_EXPECT_EQ(test, 0, ret); + KUNIT_EXPECT_EQ(test, TEST_GSEL_1, gain_sel); + + /* Max time, Max gain */ + ret = iio_gts_find_gain_sel_for_scale_using_time(>s, TEST_TSEL_X_MAX, + 0, TEST_SCALE_NANO_MAX_X, &gain_sel); + KUNIT_EXPECT_EQ(test, 0, ret); + KUNIT_EXPECT_EQ(test, TEST_GSEL_4096, gain_sel); + + ret = iio_gts_find_gain_sel_for_scale_using_time(>s, TEST_TSEL_100, 0, + TEST_SCALE_NANO_256X, &gain_sel); + /* + * Meas time 100 => gain by time 2x + * TEST_SCALE_256X matches total gain 256x + * => required HWGAIN 256/2 => 128x (not in gain-table - unsupported) + */ + KUNIT_EXPECT_NE(test, 0, ret); + + ret = iio_gts_find_gain_sel_for_scale_using_time(>s, TEST_TSEL_200, 0, + TEST_SCALE_NANO_MAX_X, &gain_sel); + /* We can't reach the max gain with integration time smaller than MAX */ + KUNIT_EXPECT_NE(test, 0, ret); + + ret = iio_gts_find_gain_sel_for_scale_using_time(>s, TEST_TSEL_50, 0, + TEST_SCALE_NANO_MAX_X, &gain_sel); + /* We can't reach the max gain with integration time smaller than MAX */ + KUNIT_EXPECT_NE(test, 0, ret); +} + +static void test_iio_gts_find_new_gain_sel_by_old_gain_time(struct kunit *test) +{ + struct device *dev; + int ret, old_gain, new_gain, old_time_sel, new_time_sel; + + dev = test_init_iio_gain_scale(test, >s); + if (!dev) + return; + + old_gain = 32; + old_time_sel = TEST_TSEL_200; + new_time_sel = TEST_TSEL_400; + + ret = iio_gts_find_new_gain_sel_by_old_gain_time(>s, old_gain, + old_time_sel, new_time_sel, &new_gain); + KUNIT_EXPECT_EQ(test, 0, ret); + /* + * Doubling the integration time doubles the total gain - so old + * (hw)gain must be divided by two to compensate. => 32 / 2 => 16 + */ + KUNIT_EXPECT_EQ(test, 16, new_gain); + + old_gain = 4; + old_time_sel = TEST_TSEL_50; + new_time_sel = TEST_TSEL_200; + ret = iio_gts_find_new_gain_sel_by_old_gain_time(>s, old_gain, + old_time_sel, new_time_sel, &new_gain); + KUNIT_EXPECT_EQ(test, 0, ret); + /* + * gain by time 1x => 4x - (hw)gain 4x => 1x + */ + KUNIT_EXPECT_EQ(test, 1, new_gain); + + old_gain = 512; + old_time_sel = TEST_TSEL_400; + new_time_sel = TEST_TSEL_50; + ret = iio_gts_find_new_gain_sel_by_old_gain_time(>s, old_gain, + old_time_sel, new_time_sel, &new_gain); + KUNIT_EXPECT_EQ(test, 0, ret); + /* + * gain by time 8x => 1x - (hw)gain 512x => 4096x) + */ + KUNIT_EXPECT_EQ(test, 4096, new_gain); + + /* Unsupported gain 2x */ + old_gain = 4; + old_time_sel = TEST_TSEL_200; + new_time_sel = TEST_TSEL_400; + ret = iio_gts_find_new_gain_sel_by_old_gain_time(>s, old_gain, + old_time_sel, new_time_sel, &new_gain); + KUNIT_EXPECT_NE(test, 0, ret); + + /* Too small gain */ + old_gain = 4; + old_time_sel = TEST_TSEL_50; + new_time_sel = TEST_TSEL_400; + ret = iio_gts_find_new_gain_sel_by_old_gain_time(>s, old_gain, + old_time_sel, new_time_sel, &new_gain); + KUNIT_EXPECT_NE(test, 0, ret); + + /* Too big gain */ + old_gain = 1024; + old_time_sel = TEST_TSEL_400; + new_time_sel = TEST_TSEL_50; + ret = iio_gts_find_new_gain_sel_by_old_gain_time(>s, old_gain, + old_time_sel, new_time_sel, &new_gain); + KUNIT_EXPECT_NE(test, 0, ret); + +} + +static void test_iio_find_closest_gain_low(struct kunit *test) +{ + struct device *dev; + bool in_range; + int ret; + + const struct iio_gain_sel_pair gts_test_gains_gain_low[] = { + GAIN_SCALE_GAIN(4, TEST_GSEL_4), + GAIN_SCALE_GAIN(16, TEST_GSEL_16), + GAIN_SCALE_GAIN(32, TEST_GSEL_32), + }; + + dev = test_init_iio_gain_scale(test, >s); + if (!dev) + return; + + ret = iio_find_closest_gain_low(>s, 2, &in_range); + KUNIT_EXPECT_EQ(test, 1, ret); + KUNIT_EXPECT_EQ(test, true, in_range); + + ret = iio_find_closest_gain_low(>s, 1, &in_range); + KUNIT_EXPECT_EQ(test, 1, ret); + KUNIT_EXPECT_EQ(test, true, in_range); + + ret = iio_find_closest_gain_low(>s, 4095, &in_range); + KUNIT_EXPECT_EQ(test, 2048, ret); + KUNIT_EXPECT_EQ(test, true, in_range); + + ret = iio_find_closest_gain_low(>s, 4097, &in_range); + KUNIT_EXPECT_EQ(test, 4096, ret); + KUNIT_EXPECT_EQ(test, false, in_range); + + kunit_device_unregister(test, dev); + + dev = __test_init_iio_gain_scale(test, >s, gts_test_gains_gain_low, + ARRAY_SIZE(gts_test_gains_gain_low), + gts_test_itimes, ARRAY_SIZE(gts_test_itimes)); + if (!dev) + return; + + ret = iio_find_closest_gain_low(>s, 3, &in_range); + KUNIT_EXPECT_EQ(test, -EINVAL, ret); + KUNIT_EXPECT_EQ(test, false, in_range); +} + +static void test_iio_gts_total_gain_to_scale(struct kunit *test) +{ + struct device *dev; + int ret, scale_int, scale_nano; + + dev = test_init_iio_gain_scale(test, >s); + if (!dev) + return; + + ret = iio_gts_total_gain_to_scale(>s, 1, &scale_int, &scale_nano); + KUNIT_EXPECT_EQ(test, 0, ret); + KUNIT_EXPECT_EQ(test, TEST_SCALE_1X, scale_int); + KUNIT_EXPECT_EQ(test, 0, scale_nano); + + ret = iio_gts_total_gain_to_scale(>s, 1, &scale_int, &scale_nano); + KUNIT_EXPECT_EQ(test, 0, ret); + KUNIT_EXPECT_EQ(test, TEST_SCALE_1X, scale_int); + KUNIT_EXPECT_EQ(test, 0, scale_nano); + + ret = iio_gts_total_gain_to_scale(>s, 4096 * 8, &scale_int, + &scale_nano); + KUNIT_EXPECT_EQ(test, 0, ret); + KUNIT_EXPECT_EQ(test, 0, scale_int); + KUNIT_EXPECT_EQ(test, TEST_SCALE_NANO_4096X8, scale_nano); +} + +static void test_iio_gts_chk_times(struct kunit *test, const int *vals) +{ + static const int expected[] = {0, 50000, 0, 100000, 0, 200000, 0, 400000}; + int i; + + for (i = 0; i < ARRAY_SIZE(expected); i++) + KUNIT_EXPECT_EQ(test, expected[i], vals[i]); +} + +static void test_iio_gts_chk_scales_all(struct kunit *test, struct iio_gts *gts, + const int *vals, int len) +{ + static const int gains[] = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, + 1024, 2048, 4096, 4096 * 2, 4096 * 4, + 4096 * 8}; + int expected[ARRAY_SIZE(gains) * 2]; + int i, ret; + int exp_len = ARRAY_SIZE(gains) * 2; + + KUNIT_EXPECT_EQ(test, exp_len, len); + if (len != exp_len) + return; + + for (i = 0; i < ARRAY_SIZE(gains); i++) { + ret = iio_gts_total_gain_to_scale(gts, gains[i], + &expected[2 * i], + &expected[2 * i + 1]); + KUNIT_EXPECT_EQ(test, 0, ret); + if (ret) + return; + } + + for (i = 0; i < ARRAY_SIZE(expected); i++) + KUNIT_EXPECT_EQ(test, expected[i], vals[i]); +} + +static void test_iio_gts_chk_scales_t200(struct kunit *test, struct iio_gts *gts, + const int *vals, int len) +{ + /* The gain caused by time 200 is 4x */ + static const int gains[] = { + 1 * 4, + 4 * 4, + 16 * 4, + 32 * 4, + 64 * 4, + 256 * 4, + 512 * 4, + 1024 * 4, + 2048 * 4, + 4096 * 4 + }; + int expected[ARRAY_SIZE(gains) * 2]; + int i, ret; + + KUNIT_EXPECT_EQ(test, 2 * ARRAY_SIZE(gains), len); + if (len < 2 * ARRAY_SIZE(gains)) + return; + + for (i = 0; i < ARRAY_SIZE(gains); i++) { + ret = iio_gts_total_gain_to_scale(gts, gains[i], + &expected[2 * i], + &expected[2 * i + 1]); + KUNIT_EXPECT_EQ(test, 0, ret); + if (ret) + return; + } + + for (i = 0; i < ARRAY_SIZE(expected); i++) + KUNIT_EXPECT_EQ(test, expected[i], vals[i]); +} + +static void test_iio_gts_avail_test(struct kunit *test) +{ + struct device *dev; + int ret; + int type, len; + const int *vals; + + dev = test_init_iio_gain_scale(test, >s); + if (!dev) + return; + + /* test table building for times and iio_gts_avail_times() */ + ret = iio_gts_avail_times(>s, &vals, &type, &len); + KUNIT_EXPECT_EQ(test, IIO_AVAIL_LIST, ret); + if (ret) + return; + + KUNIT_EXPECT_EQ(test, IIO_VAL_INT_PLUS_MICRO, type); + KUNIT_EXPECT_EQ(test, 8, len); + if (len < 8) + return; + + test_iio_gts_chk_times(test, vals); + + /* Test table building for all scales and iio_gts_all_avail_scales() */ + ret = iio_gts_all_avail_scales(>s, &vals, &type, &len); + KUNIT_EXPECT_EQ(test, IIO_AVAIL_LIST, ret); + if (ret) + return; + + KUNIT_EXPECT_EQ(test, IIO_VAL_INT_PLUS_NANO, type); + + test_iio_gts_chk_scales_all(test, >s, vals, len); + + /* + * Test table building for scales/time and + * iio_gts_avail_scales_for_time() + */ + ret = iio_gts_avail_scales_for_time(>s, 200000, &vals, &type, &len); + KUNIT_EXPECT_EQ(test, IIO_AVAIL_LIST, ret); + if (ret) + return; + + KUNIT_EXPECT_EQ(test, IIO_VAL_INT_PLUS_NANO, type); + test_iio_gts_chk_scales_t200(test, >s, vals, len); +} + +static struct kunit_case iio_gts_test_cases[] = { + KUNIT_CASE(test_init_iio_gts_invalid), + KUNIT_CASE(test_iio_gts_find_gain_for_scale_using_time), + KUNIT_CASE(test_iio_gts_find_new_gain_sel_by_old_gain_time), + 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 = { + .name = "iio-gain-time-scale", + .test_cases = iio_gts_test_cases, +}; + +kunit_test_suite(iio_gts_test_suite); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Matti Vaittinen <mazziesaccount@gmail.com>"); +MODULE_DESCRIPTION("Test IIO light sensor gain-time-scale helpers"); +MODULE_IMPORT_NS(IIO_GTS_HELPER); diff --git a/drivers/interconnect/qcom/sc8180x.c b/drivers/interconnect/qcom/sc8180x.c index 20331e119beb..03d626776ba1 100644 --- a/drivers/interconnect/qcom/sc8180x.c +++ b/drivers/interconnect/qcom/sc8180x.c @@ -1372,6 +1372,7 @@ static struct qcom_icc_bcm bcm_mm0 = { static struct qcom_icc_bcm bcm_co0 = { .name = "CO0", + .keepalive = true, .num_nodes = 1, .nodes = { &slv_qns_cdsp_mem_noc } }; diff --git a/drivers/interconnect/qcom/sm8550.c b/drivers/interconnect/qcom/sm8550.c index 629faa4c9aae..fc22cecf650f 100644 --- a/drivers/interconnect/qcom/sm8550.c +++ b/drivers/interconnect/qcom/sm8550.c @@ -2223,6 +2223,7 @@ static struct platform_driver qnoc_driver = { .driver = { .name = "qnoc-sm8550", .of_match_table = qnoc_of_match, + .sync_state = icc_sync_state, }, }; diff --git a/drivers/interconnect/qcom/sm8650.c b/drivers/interconnect/qcom/sm8650.c index b83de54577b6..b962e6c233ef 100644 --- a/drivers/interconnect/qcom/sm8650.c +++ b/drivers/interconnect/qcom/sm8650.c @@ -1160,7 +1160,7 @@ static struct qcom_icc_node qns_gemnoc_sf = { static struct qcom_icc_bcm bcm_acv = { .name = "ACV", - .enable_mask = BIT(3), + .enable_mask = BIT(0), .num_nodes = 1, .nodes = { &ebi }, }; diff --git a/drivers/interconnect/qcom/x1e80100.c b/drivers/interconnect/qcom/x1e80100.c index d19501d913b3..cbaf4f9c41be 100644 --- a/drivers/interconnect/qcom/x1e80100.c +++ b/drivers/interconnect/qcom/x1e80100.c @@ -1586,6 +1586,7 @@ static struct qcom_icc_node qns_pcie_south_gem_noc_pcie = { static struct qcom_icc_bcm bcm_acv = { .name = "ACV", + .enable_mask = BIT(3), .num_nodes = 1, .nodes = { &ebi }, }; diff --git a/drivers/irqchip/irq-brcmstb-l2.c b/drivers/irqchip/irq-brcmstb-l2.c index 5559c943f03f..2b0b3175cea0 100644 --- a/drivers/irqchip/irq-brcmstb-l2.c +++ b/drivers/irqchip/irq-brcmstb-l2.c @@ -2,7 +2,7 @@ /* * Generic Broadcom Set Top Box Level 2 Interrupt controller driver * - * Copyright (C) 2014-2017 Broadcom + * Copyright (C) 2014-2024 Broadcom */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -112,6 +112,9 @@ static void brcmstb_l2_intc_irq_handle(struct irq_desc *desc) generic_handle_domain_irq(b->domain, irq); } while (status); out: + /* Don't ack parent before all device writes are done */ + wmb(); + chained_irq_exit(chip, desc); } diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index d097001c1e3e..53abd4779914 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -207,6 +207,11 @@ static bool require_its_list_vmovp(struct its_vm *vm, struct its_node *its) return (gic_rdists->has_rvpeid || vm->vlpi_count[its->list_nr]); } +static bool rdists_support_shareable(void) +{ + return !(gic_rdists->flags & RDIST_FLAGS_FORCE_NON_SHAREABLE); +} + static u16 get_its_list(struct its_vm *vm) { struct its_node *its; @@ -2710,10 +2715,12 @@ static u64 inherit_vpe_l1_table_from_its(void) break; } val |= FIELD_PREP(GICR_VPROPBASER_4_1_ADDR, addr >> 12); - val |= FIELD_PREP(GICR_VPROPBASER_SHAREABILITY_MASK, - FIELD_GET(GITS_BASER_SHAREABILITY_MASK, baser)); - val |= FIELD_PREP(GICR_VPROPBASER_INNER_CACHEABILITY_MASK, - FIELD_GET(GITS_BASER_INNER_CACHEABILITY_MASK, baser)); + if (rdists_support_shareable()) { + val |= FIELD_PREP(GICR_VPROPBASER_SHAREABILITY_MASK, + FIELD_GET(GITS_BASER_SHAREABILITY_MASK, baser)); + val |= FIELD_PREP(GICR_VPROPBASER_INNER_CACHEABILITY_MASK, + FIELD_GET(GITS_BASER_INNER_CACHEABILITY_MASK, baser)); + } val |= FIELD_PREP(GICR_VPROPBASER_4_1_SIZE, GITS_BASER_NR_PAGES(baser) - 1); return val; @@ -2936,8 +2943,10 @@ static int allocate_vpe_l1_table(void) WARN_ON(!IS_ALIGNED(pa, psz)); val |= FIELD_PREP(GICR_VPROPBASER_4_1_ADDR, pa >> 12); - val |= GICR_VPROPBASER_RaWb; - val |= GICR_VPROPBASER_InnerShareable; + if (rdists_support_shareable()) { + val |= GICR_VPROPBASER_RaWb; + val |= GICR_VPROPBASER_InnerShareable; + } val |= GICR_VPROPBASER_4_1_Z; val |= GICR_VPROPBASER_4_1_VALID; @@ -3126,7 +3135,7 @@ static void its_cpu_init_lpis(void) gicr_write_propbaser(val, rbase + GICR_PROPBASER); tmp = gicr_read_propbaser(rbase + GICR_PROPBASER); - if (gic_rdists->flags & RDIST_FLAGS_FORCE_NON_SHAREABLE) + if (!rdists_support_shareable()) tmp &= ~GICR_PROPBASER_SHAREABILITY_MASK; if ((tmp ^ val) & GICR_PROPBASER_SHAREABILITY_MASK) { @@ -3153,7 +3162,7 @@ static void its_cpu_init_lpis(void) gicr_write_pendbaser(val, rbase + GICR_PENDBASER); tmp = gicr_read_pendbaser(rbase + GICR_PENDBASER); - if (gic_rdists->flags & RDIST_FLAGS_FORCE_NON_SHAREABLE) + if (!rdists_support_shareable()) tmp &= ~GICR_PENDBASER_SHAREABILITY_MASK; if (!(tmp & GICR_PENDBASER_SHAREABILITY_MASK)) { @@ -3817,8 +3826,9 @@ static int its_vpe_set_affinity(struct irq_data *d, bool force) { struct its_vpe *vpe = irq_data_get_irq_chip_data(d); - int from, cpu = cpumask_first(mask_val); + struct cpumask common, *table_mask; unsigned long flags; + int from, cpu; /* * Changing affinity is mega expensive, so let's be as lazy as @@ -3834,19 +3844,22 @@ static int its_vpe_set_affinity(struct irq_data *d, * taken on any vLPI handling path that evaluates vpe->col_idx. */ from = vpe_to_cpuid_lock(vpe, &flags); - if (from == cpu) - goto out; - - vpe->col_idx = cpu; + table_mask = gic_data_rdist_cpu(from)->vpe_table_mask; /* - * GICv4.1 allows us to skip VMOVP if moving to a cpu whose RD - * is sharing its VPE table with the current one. + * If we are offered another CPU in the same GICv4.1 ITS + * affinity, pick this one. Otherwise, any CPU will do. */ - if (gic_data_rdist_cpu(cpu)->vpe_table_mask && - cpumask_test_cpu(from, gic_data_rdist_cpu(cpu)->vpe_table_mask)) + if (table_mask && cpumask_and(&common, mask_val, table_mask)) + cpu = cpumask_test_cpu(from, &common) ? from : cpumask_first(&common); + else + cpu = cpumask_first(mask_val); + + if (from == cpu) goto out; + vpe->col_idx = cpu; + its_send_vmovp(vpe); its_vpe_db_proxy_move(vpe, from, cpu); @@ -3880,14 +3893,18 @@ static void its_vpe_schedule(struct its_vpe *vpe) val = virt_to_phys(page_address(vpe->its_vm->vprop_page)) & GENMASK_ULL(51, 12); val |= (LPI_NRBITS - 1) & GICR_VPROPBASER_IDBITS_MASK; - val |= GICR_VPROPBASER_RaWb; - val |= GICR_VPROPBASER_InnerShareable; + if (rdists_support_shareable()) { + val |= GICR_VPROPBASER_RaWb; + val |= GICR_VPROPBASER_InnerShareable; + } gicr_write_vpropbaser(val, vlpi_base + GICR_VPROPBASER); val = virt_to_phys(page_address(vpe->vpt_page)) & GENMASK_ULL(51, 16); - val |= GICR_VPENDBASER_RaWaWb; - val |= GICR_VPENDBASER_InnerShareable; + if (rdists_support_shareable()) { + val |= GICR_VPENDBASER_RaWaWb; + val |= GICR_VPENDBASER_InnerShareable; + } /* * There is no good way of finding out if the pending table is * empty as we can race against the doorbell interrupt very @@ -5078,6 +5095,8 @@ static int __init its_probe_one(struct its_node *its) u32 ctlr; int err; + its_enable_quirks(its); + if (is_v4(its)) { if (!(its->typer & GITS_TYPER_VMOVP)) { err = its_compute_its_list_map(its); @@ -5429,7 +5448,6 @@ static int __init its_of_probe(struct device_node *node) if (!its) return -ENOMEM; - its_enable_quirks(its); err = its_probe_one(its); if (err) { its_node_destroy(its); diff --git a/drivers/irqchip/irq-loongson-eiointc.c b/drivers/irqchip/irq-loongson-eiointc.c index 1623cd779175..b3736bdd4b9f 100644 --- a/drivers/irqchip/irq-loongson-eiointc.c +++ b/drivers/irqchip/irq-loongson-eiointc.c @@ -241,7 +241,7 @@ static int eiointc_domain_alloc(struct irq_domain *domain, unsigned int virq, int ret; unsigned int i, type; unsigned long hwirq = 0; - struct eiointc *priv = domain->host_data; + struct eiointc_priv *priv = domain->host_data; ret = irq_domain_translate_onecell(domain, arg, &hwirq, &type); if (ret) diff --git a/drivers/irqchip/irq-qcom-mpm.c b/drivers/irqchip/irq-qcom-mpm.c index cda5838d2232..7942d8eb3d00 100644 --- a/drivers/irqchip/irq-qcom-mpm.c +++ b/drivers/irqchip/irq-qcom-mpm.c @@ -389,8 +389,8 @@ static int qcom_mpm_init(struct device_node *np, struct device_node *parent) /* Don't use devm_ioremap_resource, as we're accessing a shared region. */ priv->base = devm_ioremap(dev, res.start, resource_size(&res)); of_node_put(msgram_np); - if (IS_ERR(priv->base)) - return PTR_ERR(priv->base); + if (!priv->base) + return -ENOMEM; } else { /* Otherwise, fall back to simple MMIO. */ priv->base = devm_platform_ioremap_resource(pdev, 0); diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c index aebd3c12020b..c381c22135a2 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c @@ -725,6 +725,9 @@ irqreturn_t rkisp1_capture_isr(int irq, void *ctx) unsigned int i; u32 status; + if (!rkisp1->irqs_enabled) + return IRQ_NONE; + status = rkisp1_read(rkisp1, RKISP1_CIF_MI_MIS); if (!status) return IRQ_NONE; diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h index 4b6b28c05b89..b757f75edecf 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h @@ -450,6 +450,7 @@ struct rkisp1_debug { * @debug: debug params to be exposed on debugfs * @info: version-specific ISP information * @irqs: IRQ line numbers + * @irqs_enabled: the hardware is enabled and can cause interrupts */ struct rkisp1_device { void __iomem *base_addr; @@ -471,6 +472,7 @@ struct rkisp1_device { struct rkisp1_debug debug; const struct rkisp1_info *info; int irqs[RKISP1_NUM_IRQS]; + bool irqs_enabled; }; /* diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-csi.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-csi.c index b6e47e2f1b94..4202642e0523 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-csi.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-csi.c @@ -196,6 +196,9 @@ irqreturn_t rkisp1_csi_isr(int irq, void *ctx) struct rkisp1_device *rkisp1 = dev_get_drvdata(dev); u32 val, status; + if (!rkisp1->irqs_enabled) + return IRQ_NONE; + status = rkisp1_read(rkisp1, RKISP1_CIF_MIPI_MIS); if (!status) return IRQ_NONE; diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c index f96f821a7b50..73cf08a74011 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c @@ -305,6 +305,24 @@ static int __maybe_unused rkisp1_runtime_suspend(struct device *dev) { struct rkisp1_device *rkisp1 = dev_get_drvdata(dev); + rkisp1->irqs_enabled = false; + /* Make sure the IRQ handler will see the above */ + mb(); + + /* + * Wait until any running IRQ handler has returned. The IRQ handler + * may get called even after this (as it's a shared interrupt line) + * but the 'irqs_enabled' flag will make the handler return immediately. + */ + for (unsigned int il = 0; il < ARRAY_SIZE(rkisp1->irqs); ++il) { + if (rkisp1->irqs[il] == -1) + continue; + + /* Skip if the irq line is the same as previous */ + if (il == 0 || rkisp1->irqs[il - 1] != rkisp1->irqs[il]) + synchronize_irq(rkisp1->irqs[il]); + } + clk_bulk_disable_unprepare(rkisp1->clk_size, rkisp1->clks); return pinctrl_pm_select_sleep_state(dev); } @@ -321,6 +339,10 @@ static int __maybe_unused rkisp1_runtime_resume(struct device *dev) if (ret) return ret; + rkisp1->irqs_enabled = true; + /* Make sure the IRQ handler will see the above */ + mb(); + return 0; } @@ -559,7 +581,7 @@ static int rkisp1_probe(struct platform_device *pdev) rkisp1->irqs[il] = irq; } - ret = devm_request_irq(dev, irq, info->isrs[i].isr, 0, + ret = devm_request_irq(dev, irq, info->isrs[i].isr, IRQF_SHARED, dev_driver_string(dev), dev); if (ret) { dev_err(dev, "request irq failed: %d\n", ret); diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c index f00873d31c42..78a1f7a1499b 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c @@ -976,6 +976,9 @@ irqreturn_t rkisp1_isp_isr(int irq, void *ctx) struct rkisp1_device *rkisp1 = dev_get_drvdata(dev); u32 status, isp_err; + if (!rkisp1->irqs_enabled) + return IRQ_NONE; + status = rkisp1_read(rkisp1, RKISP1_CIF_ISP_MIS); if (!status) return IRQ_NONE; diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig index 2afe67ffa285..74d69ce22a33 100644 --- a/drivers/media/rc/Kconfig +++ b/drivers/media/rc/Kconfig @@ -319,6 +319,7 @@ config IR_PWM_TX tristate "PWM IR transmitter" depends on LIRC depends on PWM + depends on HIGH_RES_TIMERS depends on OF help Say Y if you want to use a PWM based IR transmitter. This is diff --git a/drivers/media/rc/bpf-lirc.c b/drivers/media/rc/bpf-lirc.c index fe17c7f98e81..52d82cbe7685 100644 --- a/drivers/media/rc/bpf-lirc.c +++ b/drivers/media/rc/bpf-lirc.c @@ -253,7 +253,7 @@ int lirc_prog_attach(const union bpf_attr *attr, struct bpf_prog *prog) if (attr->attach_flags) return -EINVAL; - rcdev = rc_dev_get_from_fd(attr->target_fd); + rcdev = rc_dev_get_from_fd(attr->target_fd, true); if (IS_ERR(rcdev)) return PTR_ERR(rcdev); @@ -278,7 +278,7 @@ int lirc_prog_detach(const union bpf_attr *attr) if (IS_ERR(prog)) return PTR_ERR(prog); - rcdev = rc_dev_get_from_fd(attr->target_fd); + rcdev = rc_dev_get_from_fd(attr->target_fd, true); if (IS_ERR(rcdev)) { bpf_prog_put(prog); return PTR_ERR(rcdev); @@ -303,7 +303,7 @@ int lirc_prog_query(const union bpf_attr *attr, union bpf_attr __user *uattr) if (attr->query.query_flags) return -EINVAL; - rcdev = rc_dev_get_from_fd(attr->query.target_fd); + rcdev = rc_dev_get_from_fd(attr->query.target_fd, false); if (IS_ERR(rcdev)) return PTR_ERR(rcdev); diff --git a/drivers/media/rc/ir_toy.c b/drivers/media/rc/ir_toy.c index 196806709259..69e630d85262 100644 --- a/drivers/media/rc/ir_toy.c +++ b/drivers/media/rc/ir_toy.c @@ -332,6 +332,7 @@ static int irtoy_tx(struct rc_dev *rc, uint *txbuf, uint count) sizeof(COMMAND_SMODE_EXIT), STATE_COMMAND_NO_RESP); if (err) { dev_err(irtoy->dev, "exit sample mode: %d\n", err); + kfree(buf); return err; } @@ -339,6 +340,7 @@ static int irtoy_tx(struct rc_dev *rc, uint *txbuf, uint count) sizeof(COMMAND_SMODE_ENTER), STATE_COMMAND); if (err) { dev_err(irtoy->dev, "enter sample mode: %d\n", err); + kfree(buf); return err; } diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c index a537734832c5..caad59f76793 100644 --- a/drivers/media/rc/lirc_dev.c +++ b/drivers/media/rc/lirc_dev.c @@ -814,7 +814,7 @@ void __exit lirc_dev_exit(void) unregister_chrdev_region(lirc_base_dev, RC_DEV_MAX); } -struct rc_dev *rc_dev_get_from_fd(int fd) +struct rc_dev *rc_dev_get_from_fd(int fd, bool write) { struct fd f = fdget(fd); struct lirc_fh *fh; @@ -828,6 +828,9 @@ struct rc_dev *rc_dev_get_from_fd(int fd) return ERR_PTR(-EINVAL); } + if (write && !(f.file->f_mode & FMODE_WRITE)) + return ERR_PTR(-EPERM); + fh = f.file->private_data; dev = fh->rc; diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h index ef1e95e1af7f..7df949fc65e2 100644 --- a/drivers/media/rc/rc-core-priv.h +++ b/drivers/media/rc/rc-core-priv.h @@ -325,7 +325,7 @@ void lirc_raw_event(struct rc_dev *dev, struct ir_raw_event ev); void lirc_scancode_event(struct rc_dev *dev, struct lirc_scancode *lsc); int lirc_register(struct rc_dev *dev); void lirc_unregister(struct rc_dev *dev); -struct rc_dev *rc_dev_get_from_fd(int fd); +struct rc_dev *rc_dev_get_from_fd(int fd, bool write); #else static inline int lirc_dev_init(void) { return 0; } static inline void lirc_dev_exit(void) {} diff --git a/drivers/misc/eeprom/idt_89hpesx.c b/drivers/misc/eeprom/idt_89hpesx.c index d807d08e2614..327afb866b21 100644 --- a/drivers/misc/eeprom/idt_89hpesx.c +++ b/drivers/misc/eeprom/idt_89hpesx.c @@ -129,7 +129,7 @@ struct idt_smb_seq { struct idt_eeprom_seq { u8 cmd; u8 eeaddr; - u16 memaddr; + __le16 memaddr; u8 data; } __packed; @@ -141,8 +141,8 @@ struct idt_eeprom_seq { */ struct idt_csr_seq { u8 cmd; - u16 csraddr; - u32 data; + __le16 csraddr; + __le32 data; } __packed; /* diff --git a/drivers/misc/hpilo.c b/drivers/misc/hpilo.c index f1b74d3f8958..04bd34c8c506 100644 --- a/drivers/misc/hpilo.c +++ b/drivers/misc/hpilo.c @@ -770,7 +770,7 @@ static void ilo_remove(struct pci_dev *pdev) static int ilo_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { - int devnum, minor, start, error = 0; + int devnum, slot, start, error = 0; struct ilo_hwinfo *ilo_hw; if (pci_match_id(ilo_blacklist, pdev)) { @@ -839,11 +839,11 @@ static int ilo_probe(struct pci_dev *pdev, goto remove_isr; } - for (minor = 0 ; minor < max_ccb; minor++) { + for (slot = 0; slot < max_ccb; slot++) { struct device *dev; dev = device_create(&ilo_class, &pdev->dev, - MKDEV(ilo_major, minor), NULL, - "hpilo!d%dccb%d", devnum, minor); + MKDEV(ilo_major, start + slot), NULL, + "hpilo!d%dccb%d", devnum, slot); if (IS_ERR(dev)) dev_err(&pdev->dev, "Could not create files\n"); } diff --git a/drivers/misc/mei/gsc-me.c b/drivers/misc/mei/gsc-me.c index 6be8f1cc052c..9e558ec2ea1d 100644 --- a/drivers/misc/mei/gsc-me.c +++ b/drivers/misc/mei/gsc-me.c @@ -293,6 +293,10 @@ static const struct auxiliary_device_id mei_gsc_id_table[] = { .driver_data = MEI_ME_GSCFI_CFG, }, { + .name = "xe.mei-gscfi", + .driver_data = MEI_ME_GSCFI_CFG, + }, + { /* sentinel */ } }; @@ -312,5 +316,6 @@ module_auxiliary_driver(mei_gsc_driver); MODULE_AUTHOR("Intel Corporation"); MODULE_ALIAS("auxiliary:i915.mei-gsc"); MODULE_ALIAS("auxiliary:i915.mei-gscfi"); +MODULE_ALIAS("auxiliary:xe.mei-gscfi"); MODULE_DESCRIPTION("Intel(R) Graphics System Controller"); MODULE_LICENSE("GPL"); diff --git a/drivers/misc/mei/hdcp/Kconfig b/drivers/misc/mei/hdcp/Kconfig index 9be312ec798d..631dd9651d7c 100644 --- a/drivers/misc/mei/hdcp/Kconfig +++ b/drivers/misc/mei/hdcp/Kconfig @@ -4,7 +4,7 @@ config INTEL_MEI_HDCP tristate "Intel HDCP2.2 services of ME Interface" depends on INTEL_MEI_ME - depends on DRM_I915 + depends on DRM_I915 || DRM_XE help MEI Support for HDCP2.2 Services on Intel platforms. diff --git a/drivers/misc/mei/hdcp/mei_hdcp.c b/drivers/misc/mei/hdcp/mei_hdcp.c index 51359cc5ece9..f8759a6c9ed3 100644 --- a/drivers/misc/mei/hdcp/mei_hdcp.c +++ b/drivers/misc/mei/hdcp/mei_hdcp.c @@ -17,6 +17,7 @@ */ #include <linux/module.h> +#include <linux/pci.h> #include <linux/slab.h> #include <linux/mei.h> #include <linux/mei_cl_bus.h> @@ -781,9 +782,18 @@ static int mei_hdcp_component_match(struct device *dev, int subcomponent, void *data) { struct device *base = data; + struct pci_dev *pdev; - if (!dev->driver || strcmp(dev->driver->name, "i915") || - subcomponent != I915_COMPONENT_HDCP) + if (!dev_is_pci(dev)) + return 0; + + pdev = to_pci_dev(dev); + + if (pdev->class != (PCI_CLASS_DISPLAY_VGA << 8) || + pdev->vendor != PCI_VENDOR_ID_INTEL) + return 0; + + if (subcomponent != I915_COMPONENT_HDCP) return 0; base = base->parent; diff --git a/drivers/misc/mei/pxp/Kconfig b/drivers/misc/mei/pxp/Kconfig index e9219b61cd92..aa2dece4a927 100644 --- a/drivers/misc/mei/pxp/Kconfig +++ b/drivers/misc/mei/pxp/Kconfig @@ -4,7 +4,7 @@ config INTEL_MEI_PXP tristate "Intel PXP services of ME Interface" depends on INTEL_MEI_ME - depends on DRM_I915 + depends on DRM_I915 || DRM_XE help MEI Support for PXP Services on Intel platforms. diff --git a/drivers/misc/mei/pxp/mei_pxp.c b/drivers/misc/mei/pxp/mei_pxp.c index 787c6a27a4be..b1e4c23b31a3 100644 --- a/drivers/misc/mei/pxp/mei_pxp.c +++ b/drivers/misc/mei/pxp/mei_pxp.c @@ -13,6 +13,7 @@ #include <linux/delay.h> #include <linux/module.h> +#include <linux/pci.h> #include <linux/slab.h> #include <linux/mei.h> #include <linux/mei_cl_bus.h> @@ -225,12 +226,21 @@ static int mei_pxp_component_match(struct device *dev, int subcomponent, void *data) { struct device *base = data; + struct pci_dev *pdev; if (!dev) return 0; - if (!dev->driver || strcmp(dev->driver->name, "i915") || - subcomponent != I915_COMPONENT_PXP) + if (!dev_is_pci(dev)) + return 0; + + pdev = to_pci_dev(dev); + + if (pdev->class != (PCI_CLASS_DISPLAY_VGA << 8) || + pdev->vendor != PCI_VENDOR_ID_INTEL) + return 0; + + if (subcomponent != I915_COMPONENT_PXP) return 0; base = base->parent; diff --git a/drivers/net/arcnet/arc-rawmode.c b/drivers/net/arcnet/arc-rawmode.c index 8c651fdee039..57f1729066f2 100644 --- a/drivers/net/arcnet/arc-rawmode.c +++ b/drivers/net/arcnet/arc-rawmode.c @@ -186,4 +186,5 @@ static void __exit arcnet_raw_exit(void) module_init(arcnet_raw_init); module_exit(arcnet_raw_exit); +MODULE_DESCRIPTION("ARCnet raw mode packet interface module"); MODULE_LICENSE("GPL"); diff --git a/drivers/net/arcnet/arc-rimi.c b/drivers/net/arcnet/arc-rimi.c index 8c3ccc7c83cd..53d10a04d1bd 100644 --- a/drivers/net/arcnet/arc-rimi.c +++ b/drivers/net/arcnet/arc-rimi.c @@ -312,6 +312,7 @@ module_param(node, int, 0); module_param(io, int, 0); module_param(irq, int, 0); module_param_string(device, device, sizeof(device), 0); +MODULE_DESCRIPTION("ARCnet COM90xx RIM I chipset driver"); MODULE_LICENSE("GPL"); static struct net_device *my_dev; diff --git a/drivers/net/arcnet/capmode.c b/drivers/net/arcnet/capmode.c index c09b567845e1..7a0a79973769 100644 --- a/drivers/net/arcnet/capmode.c +++ b/drivers/net/arcnet/capmode.c @@ -265,4 +265,5 @@ static void __exit capmode_module_exit(void) module_init(capmode_module_init); module_exit(capmode_module_exit); +MODULE_DESCRIPTION("ARCnet CAP mode packet interface module"); MODULE_LICENSE("GPL"); diff --git a/drivers/net/arcnet/com20020-pci.c b/drivers/net/arcnet/com20020-pci.c index 7b5c8bb02f11..c5e571ec94c9 100644 --- a/drivers/net/arcnet/com20020-pci.c +++ b/drivers/net/arcnet/com20020-pci.c @@ -61,6 +61,7 @@ module_param(timeout, int, 0); module_param(backplane, int, 0); module_param(clockp, int, 0); module_param(clockm, int, 0); +MODULE_DESCRIPTION("ARCnet COM20020 chipset PCI driver"); MODULE_LICENSE("GPL"); static void led_tx_set(struct led_classdev *led_cdev, diff --git a/drivers/net/arcnet/com20020.c b/drivers/net/arcnet/com20020.c index 06e1651b594b..a0053e3992a3 100644 --- a/drivers/net/arcnet/com20020.c +++ b/drivers/net/arcnet/com20020.c @@ -399,6 +399,7 @@ EXPORT_SYMBOL(com20020_found); EXPORT_SYMBOL(com20020_netdev_ops); #endif +MODULE_DESCRIPTION("ARCnet COM20020 chipset core driver"); MODULE_LICENSE("GPL"); #ifdef MODULE diff --git a/drivers/net/arcnet/com20020_cs.c b/drivers/net/arcnet/com20020_cs.c index dc3253b318da..75f08aa7528b 100644 --- a/drivers/net/arcnet/com20020_cs.c +++ b/drivers/net/arcnet/com20020_cs.c @@ -97,6 +97,7 @@ module_param(backplane, int, 0); module_param(clockp, int, 0); module_param(clockm, int, 0); +MODULE_DESCRIPTION("ARCnet COM20020 chipset PCMCIA driver"); MODULE_LICENSE("GPL"); /*====================================================================*/ diff --git a/drivers/net/arcnet/com90io.c b/drivers/net/arcnet/com90io.c index 37b47749fc8b..3b463fbc6402 100644 --- a/drivers/net/arcnet/com90io.c +++ b/drivers/net/arcnet/com90io.c @@ -350,6 +350,7 @@ static char device[9]; /* use eg. device=arc1 to change name */ module_param_hw(io, int, ioport, 0); module_param_hw(irq, int, irq, 0); module_param_string(device, device, sizeof(device), 0); +MODULE_DESCRIPTION("ARCnet COM90xx IO mapped chipset driver"); MODULE_LICENSE("GPL"); #ifndef MODULE diff --git a/drivers/net/arcnet/com90xx.c b/drivers/net/arcnet/com90xx.c index f49dae194284..b3b287c16561 100644 --- a/drivers/net/arcnet/com90xx.c +++ b/drivers/net/arcnet/com90xx.c @@ -645,6 +645,7 @@ static void com90xx_copy_from_card(struct net_device *dev, int bufnum, TIME(dev, "memcpy_fromio", count, memcpy_fromio(buf, memaddr, count)); } +MODULE_DESCRIPTION("ARCnet COM90xx normal chipset driver"); MODULE_LICENSE("GPL"); static int __init com90xx_init(void) diff --git a/drivers/net/arcnet/rfc1051.c b/drivers/net/arcnet/rfc1051.c index a7752a5b647f..46519ca63a0a 100644 --- a/drivers/net/arcnet/rfc1051.c +++ b/drivers/net/arcnet/rfc1051.c @@ -78,6 +78,7 @@ static void __exit arcnet_rfc1051_exit(void) module_init(arcnet_rfc1051_init); module_exit(arcnet_rfc1051_exit); +MODULE_DESCRIPTION("ARCNet packet format (RFC 1051) module"); MODULE_LICENSE("GPL"); /* Determine a packet's protocol ID. diff --git a/drivers/net/arcnet/rfc1201.c b/drivers/net/arcnet/rfc1201.c index a4c856282674..0edf35d971c5 100644 --- a/drivers/net/arcnet/rfc1201.c +++ b/drivers/net/arcnet/rfc1201.c @@ -35,6 +35,7 @@ #include "arcdevice.h" +MODULE_DESCRIPTION("ARCNet packet format (RFC 1201) module"); MODULE_LICENSE("GPL"); static __be16 type_trans(struct sk_buff *skb, struct net_device *dev); diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 4e0600c7b050..a11748b8d69b 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1819,6 +1819,8 @@ void bond_xdp_set_features(struct net_device *bond_dev) bond_for_each_slave(bond, slave, iter) val &= slave->dev->xdp_features; + val &= ~NETDEV_XDP_ACT_XSK_ZEROCOPY; + xdp_set_features_flag(bond_dev, val); } @@ -5909,9 +5911,6 @@ void bond_setup(struct net_device *bond_dev) if (BOND_MODE(bond) == BOND_MODE_ACTIVEBACKUP) bond_dev->features |= BOND_XFRM_FEATURES; #endif /* CONFIG_XFRM_OFFLOAD */ - - if (bond_xdp_check(bond)) - bond_dev->xdp_features = NETDEV_XDP_ACT_MASK; } /* Destroy a bonding device. diff --git a/drivers/net/can/dev/netlink.c b/drivers/net/can/dev/netlink.c index 036d85ef07f5..dfdc039d92a6 100644 --- a/drivers/net/can/dev/netlink.c +++ b/drivers/net/can/dev/netlink.c @@ -346,7 +346,7 @@ static int can_changelink(struct net_device *dev, struct nlattr *tb[], /* Neither of TDC parameters nor TDC flags are * provided: do calculation */ - can_calc_tdco(&priv->tdc, priv->tdc_const, &priv->data_bittiming, + can_calc_tdco(&priv->tdc, priv->tdc_const, &dbt, &priv->ctrlmode, priv->ctrlmode_supported); } /* else: both CAN_CTRLMODE_TDC_{AUTO,MANUAL} are explicitly * turned off. TDC is disabled: do nothing diff --git a/drivers/net/dsa/dsa_loop_bdinfo.c b/drivers/net/dsa/dsa_loop_bdinfo.c index 237066d30704..14ca42491512 100644 --- a/drivers/net/dsa/dsa_loop_bdinfo.c +++ b/drivers/net/dsa/dsa_loop_bdinfo.c @@ -32,4 +32,5 @@ static int __init dsa_loop_bdinfo_init(void) } arch_initcall(dsa_loop_bdinfo_init) +MODULE_DESCRIPTION("DSA mock-up switch driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/net/ethernet/amd/pds_core/main.c b/drivers/net/ethernet/amd/pds_core/main.c index cdbf053b5376..0050c5894563 100644 --- a/drivers/net/ethernet/amd/pds_core/main.c +++ b/drivers/net/ethernet/amd/pds_core/main.c @@ -451,6 +451,9 @@ static void pdsc_remove(struct pci_dev *pdev) static void pdsc_stop_health_thread(struct pdsc *pdsc) { + if (pdsc->pdev->is_virtfn) + return; + timer_shutdown_sync(&pdsc->wdtimer); if (pdsc->health_work.func) cancel_work_sync(&pdsc->health_work); @@ -458,6 +461,9 @@ static void pdsc_stop_health_thread(struct pdsc *pdsc) static void pdsc_restart_health_thread(struct pdsc *pdsc) { + if (pdsc->pdev->is_virtfn) + return; + timer_setup(&pdsc->wdtimer, pdsc_wdtimer_cb, 0); mod_timer(&pdsc->wdtimer, jiffies + 1); } diff --git a/drivers/net/ethernet/broadcom/asp2/bcmasp_intf.c b/drivers/net/ethernet/broadcom/asp2/bcmasp_intf.c index 53e542881255..f59557b0cd51 100644 --- a/drivers/net/ethernet/broadcom/asp2/bcmasp_intf.c +++ b/drivers/net/ethernet/broadcom/asp2/bcmasp_intf.c @@ -684,6 +684,8 @@ static int bcmasp_init_rx(struct bcmasp_intf *intf) intf->rx_buf_order = get_order(RING_BUFFER_SIZE); buffer_pg = alloc_pages(GFP_KERNEL, intf->rx_buf_order); + if (!buffer_pg) + return -ENOMEM; dma = dma_map_page(kdev, buffer_pg, 0, RING_BUFFER_SIZE, DMA_FROM_DEVICE); @@ -1092,6 +1094,7 @@ static int bcmasp_netif_init(struct net_device *dev, bool phy_connect) return 0; err_reclaim_tx: + netif_napi_del(&intf->tx_napi); bcmasp_reclaim_free_all_tx(intf); err_phy_disconnect: if (phydev) diff --git a/drivers/net/ethernet/brocade/bna/bnad.c b/drivers/net/ethernet/brocade/bna/bnad.c index 31191b520b58..c32174484a96 100644 --- a/drivers/net/ethernet/brocade/bna/bnad.c +++ b/drivers/net/ethernet/brocade/bna/bnad.c @@ -1091,10 +1091,10 @@ bnad_cb_tx_resume(struct bnad *bnad, struct bna_tx *tx) * Free all TxQs buffers and then notify TX_E_CLEANUP_DONE to Tx fsm. */ static void -bnad_tx_cleanup(struct delayed_work *work) +bnad_tx_cleanup(struct work_struct *work) { struct bnad_tx_info *tx_info = - container_of(work, struct bnad_tx_info, tx_cleanup_work); + container_of(work, struct bnad_tx_info, tx_cleanup_work.work); struct bnad *bnad = NULL; struct bna_tcb *tcb; unsigned long flags; @@ -1170,7 +1170,7 @@ bnad_cb_rx_stall(struct bnad *bnad, struct bna_rx *rx) * Free all RxQs buffers and then notify RX_E_CLEANUP_DONE to Rx fsm. */ static void -bnad_rx_cleanup(void *work) +bnad_rx_cleanup(struct work_struct *work) { struct bnad_rx_info *rx_info = container_of(work, struct bnad_rx_info, rx_cleanup_work); @@ -1991,8 +1991,7 @@ bnad_setup_tx(struct bnad *bnad, u32 tx_id) } tx_info->tx = tx; - INIT_DELAYED_WORK(&tx_info->tx_cleanup_work, - (work_func_t)bnad_tx_cleanup); + INIT_DELAYED_WORK(&tx_info->tx_cleanup_work, bnad_tx_cleanup); /* Register ISR for the Tx object */ if (intr_info->intr_type == BNA_INTR_T_MSIX) { @@ -2248,8 +2247,7 @@ bnad_setup_rx(struct bnad *bnad, u32 rx_id) rx_info->rx = rx; spin_unlock_irqrestore(&bnad->bna_lock, flags); - INIT_WORK(&rx_info->rx_cleanup_work, - (work_func_t)(bnad_rx_cleanup)); + INIT_WORK(&rx_info->rx_cleanup_work, bnad_rx_cleanup); /* * Init NAPI, so that state is set to NAPI_STATE_SCHED, diff --git a/drivers/net/ethernet/intel/i40e/i40e_dcb.c b/drivers/net/ethernet/intel/i40e/i40e_dcb.c index 9d88ed6105fd..8db1eb0c1768 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_dcb.c +++ b/drivers/net/ethernet/intel/i40e/i40e_dcb.c @@ -1523,7 +1523,7 @@ void i40e_dcb_hw_rx_ets_bw_config(struct i40e_hw *hw, u8 *bw_share, reg = rd32(hw, I40E_PRTDCB_RETSTCC(i)); reg &= ~(I40E_PRTDCB_RETSTCC_BWSHARE_MASK | I40E_PRTDCB_RETSTCC_UPINTC_MODE_MASK | - I40E_PRTDCB_RETSTCC_ETSTC_SHIFT); + I40E_PRTDCB_RETSTCC_ETSTC_MASK); reg |= FIELD_PREP(I40E_PRTDCB_RETSTCC_BWSHARE_MASK, bw_share[i]); reg |= FIELD_PREP(I40E_PRTDCB_RETSTCC_UPINTC_MODE_MASK, diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 6e7fd473abfd..54eb55464e31 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -4926,27 +4926,23 @@ int i40e_vsi_start_rings(struct i40e_vsi *vsi) void i40e_vsi_stop_rings(struct i40e_vsi *vsi) { struct i40e_pf *pf = vsi->back; - int pf_q, err, q_end; + u32 pf_q, tx_q_end, rx_q_end; /* When port TX is suspended, don't wait */ if (test_bit(__I40E_PORT_SUSPENDED, vsi->back->state)) return i40e_vsi_stop_rings_no_wait(vsi); - q_end = vsi->base_queue + vsi->num_queue_pairs; - for (pf_q = vsi->base_queue; pf_q < q_end; pf_q++) - i40e_pre_tx_queue_cfg(&pf->hw, (u32)pf_q, false); + tx_q_end = vsi->base_queue + + vsi->alloc_queue_pairs * (i40e_enabled_xdp_vsi(vsi) ? 2 : 1); + for (pf_q = vsi->base_queue; pf_q < tx_q_end; pf_q++) + i40e_pre_tx_queue_cfg(&pf->hw, pf_q, false); - for (pf_q = vsi->base_queue; pf_q < q_end; pf_q++) { - err = i40e_control_wait_rx_q(pf, pf_q, false); - if (err) - dev_info(&pf->pdev->dev, - "VSI seid %d Rx ring %d disable timeout\n", - vsi->seid, pf_q); - } + rx_q_end = vsi->base_queue + vsi->num_queue_pairs; + for (pf_q = vsi->base_queue; pf_q < rx_q_end; pf_q++) + i40e_control_rx_q(pf, pf_q, false); msleep(I40E_DISABLE_TX_GAP_MSEC); - pf_q = vsi->base_queue; - for (pf_q = vsi->base_queue; pf_q < q_end; pf_q++) + for (pf_q = vsi->base_queue; pf_q < tx_q_end; pf_q++) wr32(&pf->hw, I40E_QTX_ENA(pf_q), 0); i40e_vsi_wait_queues_disabled(vsi); @@ -5360,7 +5356,7 @@ static int i40e_pf_wait_queues_disabled(struct i40e_pf *pf) { int v, ret = 0; - for (v = 0; v < pf->hw.func_caps.num_vsis; v++) { + for (v = 0; v < pf->num_alloc_vsi; v++) { if (pf->vsi[v]) { ret = i40e_vsi_wait_queues_disabled(pf->vsi[v]); if (ret) diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index 908cdbd3ec5d..b34c71770887 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -2848,6 +2848,24 @@ error_param: (u8 *)&stats, sizeof(stats)); } +/** + * i40e_can_vf_change_mac + * @vf: pointer to the VF info + * + * Return true if the VF is allowed to change its MAC filters, false otherwise + */ +static bool i40e_can_vf_change_mac(struct i40e_vf *vf) +{ + /* If the VF MAC address has been set administratively (via the + * ndo_set_vf_mac command), then deny permission to the VF to + * add/delete unicast MAC addresses, unless the VF is trusted + */ + if (vf->pf_set_mac && !vf->trusted) + return false; + + return true; +} + #define I40E_MAX_MACVLAN_PER_HW 3072 #define I40E_MAX_MACVLAN_PER_PF(num_ports) (I40E_MAX_MACVLAN_PER_HW / \ (num_ports)) @@ -2907,8 +2925,8 @@ static inline int i40e_check_vf_permission(struct i40e_vf *vf, * The VF may request to set the MAC address filter already * assigned to it so do not return an error in that case. */ - if (!test_bit(I40E_VIRTCHNL_VF_CAP_PRIVILEGE, &vf->vf_caps) && - !is_multicast_ether_addr(addr) && vf->pf_set_mac && + if (!i40e_can_vf_change_mac(vf) && + !is_multicast_ether_addr(addr) && !ether_addr_equal(addr, vf->default_lan_addr.addr)) { dev_err(&pf->pdev->dev, "VF attempting to override administratively set MAC address, bring down and up the VF interface to resume normal operation\n"); @@ -3114,19 +3132,29 @@ static int i40e_vc_del_mac_addr_msg(struct i40e_vf *vf, u8 *msg) ret = -EINVAL; goto error_param; } - if (ether_addr_equal(al->list[i].addr, vf->default_lan_addr.addr)) - was_unimac_deleted = true; } vsi = pf->vsi[vf->lan_vsi_idx]; spin_lock_bh(&vsi->mac_filter_hash_lock); /* delete addresses from the list */ - for (i = 0; i < al->num_elements; i++) + for (i = 0; i < al->num_elements; i++) { + const u8 *addr = al->list[i].addr; + + /* Allow to delete VF primary MAC only if it was not set + * administratively by PF or if VF is trusted. + */ + if (ether_addr_equal(addr, vf->default_lan_addr.addr) && + i40e_can_vf_change_mac(vf)) + was_unimac_deleted = true; + else + continue; + if (i40e_del_mac_filter(vsi, al->list[i].addr)) { ret = -EINVAL; spin_unlock_bh(&vsi->mac_filter_hash_lock); goto error_param; } + } spin_unlock_bh(&vsi->mac_filter_hash_lock); diff --git a/drivers/net/ethernet/intel/ice/ice_lag.c b/drivers/net/ethernet/intel/ice/ice_lag.c index 2a25323105e5..467372d541d2 100644 --- a/drivers/net/ethernet/intel/ice/ice_lag.c +++ b/drivers/net/ethernet/intel/ice/ice_lag.c @@ -152,6 +152,27 @@ ice_lag_find_hw_by_lport(struct ice_lag *lag, u8 lport) } /** + * ice_pkg_has_lport_extract - check if lport extraction supported + * @hw: HW struct + */ +static bool ice_pkg_has_lport_extract(struct ice_hw *hw) +{ + int i; + + for (i = 0; i < hw->blk[ICE_BLK_SW].es.count; i++) { + u16 offset; + u8 fv_prot; + + ice_find_prot_off(hw, ICE_BLK_SW, ICE_SW_DEFAULT_PROFILE, i, + &fv_prot, &offset); + if (fv_prot == ICE_FV_PROT_MDID && + offset == ICE_LP_EXT_BUF_OFFSET) + return true; + } + return false; +} + +/** * ice_lag_find_primary - returns pointer to primary interfaces lag struct * @lag: local interfaces lag struct */ @@ -1206,7 +1227,7 @@ static void ice_lag_del_prune_list(struct ice_lag *lag, struct ice_pf *event_pf) } /** - * ice_lag_init_feature_support_flag - Check for NVM support for LAG + * ice_lag_init_feature_support_flag - Check for package and NVM support for LAG * @pf: PF struct */ static void ice_lag_init_feature_support_flag(struct ice_pf *pf) @@ -1219,7 +1240,7 @@ static void ice_lag_init_feature_support_flag(struct ice_pf *pf) else ice_clear_feature_support(pf, ICE_F_ROCE_LAG); - if (caps->sriov_lag) + if (caps->sriov_lag && ice_pkg_has_lport_extract(&pf->hw)) ice_set_feature_support(pf, ICE_F_SRIOV_LAG); else ice_clear_feature_support(pf, ICE_F_SRIOV_LAG); diff --git a/drivers/net/ethernet/intel/ice/ice_lag.h b/drivers/net/ethernet/intel/ice/ice_lag.h index ede833dfa658..183b38792ef2 100644 --- a/drivers/net/ethernet/intel/ice/ice_lag.h +++ b/drivers/net/ethernet/intel/ice/ice_lag.h @@ -17,6 +17,9 @@ enum ice_lag_role { #define ICE_LAG_INVALID_PORT 0xFF #define ICE_LAG_RESET_RETRIES 5 +#define ICE_SW_DEFAULT_PROFILE 0 +#define ICE_FV_PROT_MDID 255 +#define ICE_LP_EXT_BUF_OFFSET 32 struct ice_pf; struct ice_vf; diff --git a/drivers/net/ethernet/intel/igb/igb.h b/drivers/net/ethernet/intel/igb/igb.h index a2b759531cb7..3c2dc7bdebb5 100644 --- a/drivers/net/ethernet/intel/igb/igb.h +++ b/drivers/net/ethernet/intel/igb/igb.h @@ -637,7 +637,7 @@ struct igb_adapter { struct timespec64 period; } perout[IGB_N_PEROUT]; - char fw_version[32]; + char fw_version[48]; #ifdef CONFIG_IGB_HWMON struct hwmon_buff *igb_hwmon_buff; bool ets; diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index 4df8d4153aa5..cebb44f51d5f 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -3069,7 +3069,6 @@ void igb_set_fw_version(struct igb_adapter *adapter) { struct e1000_hw *hw = &adapter->hw; struct e1000_fw_version fw; - char *lbuf; igb_get_fw_version(hw, &fw); @@ -3077,34 +3076,36 @@ void igb_set_fw_version(struct igb_adapter *adapter) case e1000_i210: case e1000_i211: if (!(igb_get_flash_presence_i210(hw))) { - lbuf = kasprintf(GFP_KERNEL, "%2d.%2d-%d", - fw.invm_major, fw.invm_minor, - fw.invm_img_type); + snprintf(adapter->fw_version, + sizeof(adapter->fw_version), + "%2d.%2d-%d", + fw.invm_major, fw.invm_minor, + fw.invm_img_type); break; } fallthrough; default: /* if option rom is valid, display its version too */ if (fw.or_valid) { - lbuf = kasprintf(GFP_KERNEL, "%d.%d, 0x%08x, %d.%d.%d", - fw.eep_major, fw.eep_minor, - fw.etrack_id, fw.or_major, fw.or_build, - fw.or_patch); + snprintf(adapter->fw_version, + sizeof(adapter->fw_version), + "%d.%d, 0x%08x, %d.%d.%d", + fw.eep_major, fw.eep_minor, fw.etrack_id, + fw.or_major, fw.or_build, fw.or_patch); /* no option rom */ } else if (fw.etrack_id != 0X0000) { - lbuf = kasprintf(GFP_KERNEL, "%d.%d, 0x%08x", - fw.eep_major, fw.eep_minor, - fw.etrack_id); + snprintf(adapter->fw_version, + sizeof(adapter->fw_version), + "%d.%d, 0x%08x", + fw.eep_major, fw.eep_minor, fw.etrack_id); } else { - lbuf = kasprintf(GFP_KERNEL, "%d.%d.%d", fw.eep_major, - fw.eep_minor, fw.eep_build); + snprintf(adapter->fw_version, + sizeof(adapter->fw_version), + "%d.%d.%d", + fw.eep_major, fw.eep_minor, fw.eep_build); } break; } - - /* the truncate happens here if it doesn't fit */ - strscpy(adapter->fw_version, lbuf, sizeof(adapter->fw_version)); - kfree(lbuf); } /** diff --git a/drivers/net/ethernet/intel/igc/igc_phy.c b/drivers/net/ethernet/intel/igc/igc_phy.c index 7cd8716d2ffa..861f37076861 100644 --- a/drivers/net/ethernet/intel/igc/igc_phy.c +++ b/drivers/net/ethernet/intel/igc/igc_phy.c @@ -130,11 +130,7 @@ void igc_power_down_phy_copper(struct igc_hw *hw) /* The PHY will retain its settings across a power down/up cycle */ hw->phy.ops.read_reg(hw, PHY_CONTROL, &mii_reg); mii_reg |= MII_CR_POWER_DOWN; - - /* Temporary workaround - should be removed when PHY will implement - * IEEE registers as properly - */ - /* hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg);*/ + hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg); usleep_range(1000, 2000); } diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c index 8cfd74ad991c..e5d6156655ba 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c @@ -61,28 +61,6 @@ int rvu_npc_get_tx_nibble_cfg(struct rvu *rvu, u64 nibble_ena) return 0; } -static int npc_mcam_verify_pf_func(struct rvu *rvu, - struct mcam_entry *entry_data, u8 intf, - u16 pcifunc) -{ - u16 pf_func, pf_func_mask; - - if (is_npc_intf_rx(intf)) - return 0; - - pf_func_mask = (entry_data->kw_mask[0] >> 32) & - NPC_KEX_PF_FUNC_MASK; - pf_func = (entry_data->kw[0] >> 32) & NPC_KEX_PF_FUNC_MASK; - - pf_func = be16_to_cpu((__force __be16)pf_func); - if (pf_func_mask != NPC_KEX_PF_FUNC_MASK || - ((pf_func & ~RVU_PFVF_FUNC_MASK) != - (pcifunc & ~RVU_PFVF_FUNC_MASK))) - return -EINVAL; - - return 0; -} - void rvu_npc_set_pkind(struct rvu *rvu, int pkind, struct rvu_pfvf *pfvf) { int blkaddr; @@ -2851,12 +2829,6 @@ int rvu_mbox_handler_npc_mcam_write_entry(struct rvu *rvu, else nix_intf = pfvf->nix_rx_intf; - if (!is_pffunc_af(pcifunc) && - npc_mcam_verify_pf_func(rvu, &req->entry_data, req->intf, pcifunc)) { - rc = NPC_MCAM_INVALID_REQ; - goto exit; - } - /* For AF installed rules, the nix_intf should be set to target NIX */ if (is_pffunc_af(req->hdr.pcifunc)) nix_intf = req->intf; @@ -3208,10 +3180,6 @@ int rvu_mbox_handler_npc_mcam_alloc_and_write_entry(struct rvu *rvu, if (!is_npc_interface_valid(rvu, req->intf)) return NPC_MCAM_INVALID_REQ; - if (npc_mcam_verify_pf_func(rvu, &req->entry_data, req->intf, - req->hdr.pcifunc)) - return NPC_MCAM_INVALID_REQ; - /* Try to allocate a MCAM entry */ entry_req.hdr.pcifunc = req->hdr.pcifunc; entry_req.contig = true; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/dpll.c b/drivers/net/ethernet/mellanox/mlx5/core/dpll.c index 18fed2b34fb1..928bf24d4b12 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/dpll.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/dpll.c @@ -389,7 +389,7 @@ static void mlx5_dpll_remove(struct auxiliary_device *adev) struct mlx5_dpll *mdpll = auxiliary_get_drvdata(adev); struct mlx5_core_dev *mdev = mdpll->mdev; - cancel_delayed_work(&mdpll->work); + cancel_delayed_work_sync(&mdpll->work); mlx5_dpll_mdev_netdev_untrack(mdpll, mdev); destroy_workqueue(mdpll->wq); dpll_pin_unregister(mdpll->dpll, mdpll->dpll_pin, diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_lag.c b/drivers/net/ethernet/microchip/lan966x/lan966x_lag.c index 41fa2523d91d..5f2cd9a8cf8f 100644 --- a/drivers/net/ethernet/microchip/lan966x/lan966x_lag.c +++ b/drivers/net/ethernet/microchip/lan966x/lan966x_lag.c @@ -37,19 +37,24 @@ static void lan966x_lag_set_aggr_pgids(struct lan966x *lan966x) /* Now, set PGIDs for each active LAG */ for (lag = 0; lag < lan966x->num_phys_ports; ++lag) { - struct net_device *bond = lan966x->ports[lag]->bond; + struct lan966x_port *port = lan966x->ports[lag]; int num_active_ports = 0; + struct net_device *bond; unsigned long bond_mask; u8 aggr_idx[16]; - if (!bond || (visited & BIT(lag))) + if (!port || !port->bond || (visited & BIT(lag))) continue; + bond = port->bond; bond_mask = lan966x_lag_get_mask(lan966x, bond); for_each_set_bit(p, &bond_mask, lan966x->num_phys_ports) { struct lan966x_port *port = lan966x->ports[p]; + if (!port) + continue; + lan_wr(ANA_PGID_PGID_SET(bond_mask), lan966x, ANA_PGID(p)); if (port->lag_tx_active) diff --git a/drivers/net/ethernet/pensando/ionic/ionic_txrx.c b/drivers/net/ethernet/pensando/ionic/ionic_txrx.c index 54cd96b035d6..6f4776759863 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_txrx.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_txrx.c @@ -579,6 +579,9 @@ int ionic_tx_napi(struct napi_struct *napi, int budget) work_done = ionic_cq_service(cq, budget, ionic_tx_service, NULL, NULL); + if (unlikely(!budget)) + return budget; + if (work_done < budget && napi_complete_done(napi, work_done)) { ionic_dim_update(qcq, IONIC_LIF_F_TX_DIM_INTR); flags |= IONIC_INTR_CRED_UNMASK; @@ -607,6 +610,9 @@ int ionic_rx_napi(struct napi_struct *napi, int budget) u32 work_done = 0; u32 flags = 0; + if (unlikely(!budget)) + return budget; + lif = cq->bound_q->lif; idev = &lif->ionic->idev; @@ -656,6 +662,9 @@ int ionic_txrx_napi(struct napi_struct *napi, int budget) tx_work_done = ionic_cq_service(txcq, IONIC_TX_BUDGET_DEFAULT, ionic_tx_service, NULL, NULL); + if (unlikely(!budget)) + return budget; + rx_work_done = ionic_cq_service(rxcq, budget, ionic_rx_service, NULL, NULL); diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c index 0e3731f50fc2..f7566cfa45ca 100644 --- a/drivers/net/ethernet/renesas/ravb_main.c +++ b/drivers/net/ethernet/renesas/ravb_main.c @@ -772,29 +772,25 @@ static bool ravb_rx_gbeth(struct net_device *ndev, int *quota, int q) struct ravb_rx_desc *desc; struct sk_buff *skb; dma_addr_t dma_addr; + int rx_packets = 0; u8 desc_status; - int boguscnt; u16 pkt_len; u8 die_dt; int entry; int limit; + int i; entry = priv->cur_rx[q] % priv->num_rx_ring[q]; - boguscnt = priv->dirty_rx[q] + priv->num_rx_ring[q] - priv->cur_rx[q]; + limit = priv->dirty_rx[q] + priv->num_rx_ring[q] - priv->cur_rx[q]; stats = &priv->stats[q]; - boguscnt = min(boguscnt, *quota); - limit = boguscnt; desc = &priv->gbeth_rx_ring[entry]; - while (desc->die_dt != DT_FEMPTY) { + for (i = 0; i < limit && rx_packets < *quota && desc->die_dt != DT_FEMPTY; i++) { /* Descriptor type must be checked before all other reads */ dma_rmb(); desc_status = desc->msc; pkt_len = le16_to_cpu(desc->ds_cc) & RX_DS; - if (--boguscnt < 0) - break; - /* We use 0-byte descriptors to mark the DMA mapping errors */ if (!pkt_len) continue; @@ -820,7 +816,7 @@ static bool ravb_rx_gbeth(struct net_device *ndev, int *quota, int q) skb_put(skb, pkt_len); skb->protocol = eth_type_trans(skb, ndev); napi_gro_receive(&priv->napi[q], skb); - stats->rx_packets++; + rx_packets++; stats->rx_bytes += pkt_len; break; case DT_FSTART: @@ -848,7 +844,7 @@ static bool ravb_rx_gbeth(struct net_device *ndev, int *quota, int q) eth_type_trans(priv->rx_1st_skb, ndev); napi_gro_receive(&priv->napi[q], priv->rx_1st_skb); - stats->rx_packets++; + rx_packets++; stats->rx_bytes += pkt_len; break; } @@ -887,9 +883,9 @@ static bool ravb_rx_gbeth(struct net_device *ndev, int *quota, int q) desc->die_dt = DT_FEMPTY; } - *quota -= limit - (++boguscnt); - - return boguscnt <= 0; + stats->rx_packets += rx_packets; + *quota -= rx_packets; + return *quota == 0; } /* Packet receive function for Ethernet AVB */ diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c index 323c57f03c93..1af2f89a0504 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c @@ -830,41 +830,42 @@ static const struct dwxgmac3_error_desc dwxgmac3_dma_errors[32]= { { false, "UNKNOWN", "Unknown Error" }, /* 31 */ }; -static const char * const dpp_rx_err = "Read Rx Descriptor Parity checker Error"; -static const char * const dpp_tx_err = "Read Tx Descriptor Parity checker Error"; +#define DPP_RX_ERR "Read Rx Descriptor Parity checker Error" +#define DPP_TX_ERR "Read Tx Descriptor Parity checker Error" + static const struct dwxgmac3_error_desc dwxgmac3_dma_dpp_errors[32] = { - { true, "TDPES0", dpp_tx_err }, - { true, "TDPES1", dpp_tx_err }, - { true, "TDPES2", dpp_tx_err }, - { true, "TDPES3", dpp_tx_err }, - { true, "TDPES4", dpp_tx_err }, - { true, "TDPES5", dpp_tx_err }, - { true, "TDPES6", dpp_tx_err }, - { true, "TDPES7", dpp_tx_err }, - { true, "TDPES8", dpp_tx_err }, - { true, "TDPES9", dpp_tx_err }, - { true, "TDPES10", dpp_tx_err }, - { true, "TDPES11", dpp_tx_err }, - { true, "TDPES12", dpp_tx_err }, - { true, "TDPES13", dpp_tx_err }, - { true, "TDPES14", dpp_tx_err }, - { true, "TDPES15", dpp_tx_err }, - { true, "RDPES0", dpp_rx_err }, - { true, "RDPES1", dpp_rx_err }, - { true, "RDPES2", dpp_rx_err }, - { true, "RDPES3", dpp_rx_err }, - { true, "RDPES4", dpp_rx_err }, - { true, "RDPES5", dpp_rx_err }, - { true, "RDPES6", dpp_rx_err }, - { true, "RDPES7", dpp_rx_err }, - { true, "RDPES8", dpp_rx_err }, - { true, "RDPES9", dpp_rx_err }, - { true, "RDPES10", dpp_rx_err }, - { true, "RDPES11", dpp_rx_err }, - { true, "RDPES12", dpp_rx_err }, - { true, "RDPES13", dpp_rx_err }, - { true, "RDPES14", dpp_rx_err }, - { true, "RDPES15", dpp_rx_err }, + { true, "TDPES0", DPP_TX_ERR }, + { true, "TDPES1", DPP_TX_ERR }, + { true, "TDPES2", DPP_TX_ERR }, + { true, "TDPES3", DPP_TX_ERR }, + { true, "TDPES4", DPP_TX_ERR }, + { true, "TDPES5", DPP_TX_ERR }, + { true, "TDPES6", DPP_TX_ERR }, + { true, "TDPES7", DPP_TX_ERR }, + { true, "TDPES8", DPP_TX_ERR }, + { true, "TDPES9", DPP_TX_ERR }, + { true, "TDPES10", DPP_TX_ERR }, + { true, "TDPES11", DPP_TX_ERR }, + { true, "TDPES12", DPP_TX_ERR }, + { true, "TDPES13", DPP_TX_ERR }, + { true, "TDPES14", DPP_TX_ERR }, + { true, "TDPES15", DPP_TX_ERR }, + { true, "RDPES0", DPP_RX_ERR }, + { true, "RDPES1", DPP_RX_ERR }, + { true, "RDPES2", DPP_RX_ERR }, + { true, "RDPES3", DPP_RX_ERR }, + { true, "RDPES4", DPP_RX_ERR }, + { true, "RDPES5", DPP_RX_ERR }, + { true, "RDPES6", DPP_RX_ERR }, + { true, "RDPES7", DPP_RX_ERR }, + { true, "RDPES8", DPP_RX_ERR }, + { true, "RDPES9", DPP_RX_ERR }, + { true, "RDPES10", DPP_RX_ERR }, + { true, "RDPES11", DPP_RX_ERR }, + { true, "RDPES12", DPP_RX_ERR }, + { true, "RDPES13", DPP_RX_ERR }, + { true, "RDPES14", DPP_RX_ERR }, + { true, "RDPES15", DPP_RX_ERR }, }; static void dwxgmac3_handle_dma_err(struct net_device *ndev, diff --git a/drivers/net/ethernet/ti/Kconfig b/drivers/net/ethernet/ti/Kconfig index be01450c20dc..1530d13984d4 100644 --- a/drivers/net/ethernet/ti/Kconfig +++ b/drivers/net/ethernet/ti/Kconfig @@ -189,6 +189,7 @@ config TI_ICSSG_PRUETH select TI_K3_CPPI_DESC_POOL depends on PRU_REMOTEPROC depends on ARCH_K3 && OF && TI_K3_UDMA_GLUE_LAYER + depends on PTP_1588_CLOCK_OPTIONAL help Support dual Gigabit Ethernet ports over the ICSSG PRU Subsystem. This subsystem is available starting with the AM65 platform. diff --git a/drivers/net/ethernet/ti/cpts.c b/drivers/net/ethernet/ti/cpts.c index bcccf43d368b..dbbea9146040 100644 --- a/drivers/net/ethernet/ti/cpts.c +++ b/drivers/net/ethernet/ti/cpts.c @@ -638,6 +638,16 @@ static void cpts_calc_mult_shift(struct cpts *cpts) freq, cpts->cc.mult, cpts->cc.shift, (ns - NSEC_PER_SEC)); } +static void cpts_clk_unregister(void *clk) +{ + clk_hw_unregister_mux(clk); +} + +static void cpts_clk_del_provider(void *np) +{ + of_clk_del_provider(np); +} + static int cpts_of_mux_clk_setup(struct cpts *cpts, struct device_node *node) { struct device_node *refclk_np; @@ -687,9 +697,7 @@ static int cpts_of_mux_clk_setup(struct cpts *cpts, struct device_node *node) goto mux_fail; } - ret = devm_add_action_or_reset(cpts->dev, - (void(*)(void *))clk_hw_unregister_mux, - clk_hw); + ret = devm_add_action_or_reset(cpts->dev, cpts_clk_unregister, clk_hw); if (ret) { dev_err(cpts->dev, "add clkmux unreg action %d", ret); goto mux_fail; @@ -699,8 +707,7 @@ static int cpts_of_mux_clk_setup(struct cpts *cpts, struct device_node *node) if (ret) goto mux_fail; - ret = devm_add_action_or_reset(cpts->dev, - (void(*)(void *))of_clk_del_provider, + ret = devm_add_action_or_reset(cpts->dev, cpts_clk_del_provider, refclk_np); if (ret) { dev_err(cpts->dev, "add clkmux provider unreg action %d", ret); diff --git a/drivers/net/fddi/skfp/skfddi.c b/drivers/net/fddi/skfp/skfddi.c index 2b6a607ac0b7..a273362c9e70 100644 --- a/drivers/net/fddi/skfp/skfddi.c +++ b/drivers/net/fddi/skfp/skfddi.c @@ -153,6 +153,7 @@ static const struct pci_device_id skfddi_pci_tbl[] = { { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(pci, skfddi_pci_tbl); +MODULE_DESCRIPTION("SysKonnect FDDI PCI driver"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mirko Lindner <mlindner@syskonnect.de>"); diff --git a/drivers/net/ieee802154/fakelb.c b/drivers/net/ieee802154/fakelb.c index 35e55f198e05..2930141d7dd2 100644 --- a/drivers/net/ieee802154/fakelb.c +++ b/drivers/net/ieee802154/fakelb.c @@ -259,4 +259,5 @@ static __exit void fake_remove_module(void) module_init(fakelb_init_module); module_exit(fake_remove_module); +MODULE_DESCRIPTION("IEEE 802.15.4 loopback driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/net/ipvlan/ipvtap.c b/drivers/net/ipvlan/ipvtap.c index 60944a4beada..1afc4c47be73 100644 --- a/drivers/net/ipvlan/ipvtap.c +++ b/drivers/net/ipvlan/ipvtap.c @@ -237,4 +237,5 @@ static void __exit ipvtap_exit(void) module_exit(ipvtap_exit); MODULE_ALIAS_RTNL_LINK("ipvtap"); MODULE_AUTHOR("Sainath Grandhi <sainath.grandhi@intel.com>"); +MODULE_DESCRIPTION("IP-VLAN based tap driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/net/phy/mdio_devres.c b/drivers/net/phy/mdio_devres.c index 69b829e6ab35..7fd3377dbd79 100644 --- a/drivers/net/phy/mdio_devres.c +++ b/drivers/net/phy/mdio_devres.c @@ -131,4 +131,5 @@ int __devm_of_mdiobus_register(struct device *dev, struct mii_bus *mdio, EXPORT_SYMBOL(__devm_of_mdiobus_register); #endif /* CONFIG_OF_MDIO */ +MODULE_DESCRIPTION("Network MDIO bus devres helpers"); MODULE_LICENSE("GPL"); diff --git a/drivers/net/plip/plip.c b/drivers/net/plip/plip.c index 40ce8abe6999..cc7d1113ece0 100644 --- a/drivers/net/plip/plip.c +++ b/drivers/net/plip/plip.c @@ -1437,4 +1437,5 @@ static int __init plip_init (void) module_init(plip_init); module_exit(plip_cleanup_module); +MODULE_DESCRIPTION("PLIP (parallel port) network module"); MODULE_LICENSE("GPL"); diff --git a/drivers/net/ppp/bsd_comp.c b/drivers/net/ppp/bsd_comp.c index db0dc36d12e3..55954594e157 100644 --- a/drivers/net/ppp/bsd_comp.c +++ b/drivers/net/ppp/bsd_comp.c @@ -1166,5 +1166,6 @@ static void __exit bsdcomp_cleanup(void) module_init(bsdcomp_init); module_exit(bsdcomp_cleanup); +MODULE_DESCRIPTION("PPP BSD-Compress compression module"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_ALIAS("ppp-compress-" __stringify(CI_BSD_COMPRESS)); diff --git a/drivers/net/ppp/ppp_async.c b/drivers/net/ppp/ppp_async.c index 125793d8aefa..c33c3db3cc08 100644 --- a/drivers/net/ppp/ppp_async.c +++ b/drivers/net/ppp/ppp_async.c @@ -87,6 +87,7 @@ struct asyncppp { static int flag_time = HZ; module_param(flag_time, int, 0); MODULE_PARM_DESC(flag_time, "ppp_async: interval between flagged packets (in clock ticks)"); +MODULE_DESCRIPTION("PPP async serial channel module"); MODULE_LICENSE("GPL"); MODULE_ALIAS_LDISC(N_PPP); diff --git a/drivers/net/ppp/ppp_deflate.c b/drivers/net/ppp/ppp_deflate.c index e6d48e5c65a3..4d2ff63f2ee2 100644 --- a/drivers/net/ppp/ppp_deflate.c +++ b/drivers/net/ppp/ppp_deflate.c @@ -630,6 +630,7 @@ static void __exit deflate_cleanup(void) module_init(deflate_init); module_exit(deflate_cleanup); +MODULE_DESCRIPTION("PPP Deflate compression module"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_ALIAS("ppp-compress-" __stringify(CI_DEFLATE)); MODULE_ALIAS("ppp-compress-" __stringify(CI_DEFLATE_DRAFT)); diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c index 0193af2d31c9..3dd52bf28f15 100644 --- a/drivers/net/ppp/ppp_generic.c +++ b/drivers/net/ppp/ppp_generic.c @@ -3604,6 +3604,7 @@ EXPORT_SYMBOL(ppp_input_error); EXPORT_SYMBOL(ppp_output_wakeup); EXPORT_SYMBOL(ppp_register_compressor); EXPORT_SYMBOL(ppp_unregister_compressor); +MODULE_DESCRIPTION("Generic PPP layer driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS_CHARDEV(PPP_MAJOR, 0); MODULE_ALIAS_RTNL_LINK("ppp"); diff --git a/drivers/net/ppp/ppp_synctty.c b/drivers/net/ppp/ppp_synctty.c index 52d05ce4a281..45bf59ac8f57 100644 --- a/drivers/net/ppp/ppp_synctty.c +++ b/drivers/net/ppp/ppp_synctty.c @@ -724,5 +724,6 @@ ppp_sync_cleanup(void) module_init(ppp_sync_init); module_exit(ppp_sync_cleanup); +MODULE_DESCRIPTION("PPP synchronous TTY channel module"); MODULE_LICENSE("GPL"); MODULE_ALIAS_LDISC(N_SYNC_PPP); diff --git a/drivers/net/ppp/pppoe.c b/drivers/net/ppp/pppoe.c index 8e7238e97d0a..2ea4f4890d23 100644 --- a/drivers/net/ppp/pppoe.c +++ b/drivers/net/ppp/pppoe.c @@ -1007,26 +1007,21 @@ static int pppoe_recvmsg(struct socket *sock, struct msghdr *m, struct sk_buff *skb; int error = 0; - if (sk->sk_state & PPPOX_BOUND) { - error = -EIO; - goto end; - } + if (sk->sk_state & PPPOX_BOUND) + return -EIO; skb = skb_recv_datagram(sk, flags, &error); - if (error < 0) - goto end; + if (!skb) + return error; - if (skb) { - total_len = min_t(size_t, total_len, skb->len); - error = skb_copy_datagram_msg(skb, 0, m, total_len); - if (error == 0) { - consume_skb(skb); - return total_len; - } + total_len = min_t(size_t, total_len, skb->len); + error = skb_copy_datagram_msg(skb, 0, m, total_len); + if (error == 0) { + consume_skb(skb); + return total_len; } kfree_skb(skb); -end: return error; } diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c index b96f30d11644..dcc4810cb324 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c @@ -618,7 +618,7 @@ int iwl_sar_get_wrds_table(struct iwl_fw_runtime *fwrt) &tbl_rev); if (!IS_ERR(wifi_pkg)) { if (tbl_rev != 2) { - ret = PTR_ERR(wifi_pkg); + ret = -EINVAL; goto out_free; } @@ -634,7 +634,7 @@ int iwl_sar_get_wrds_table(struct iwl_fw_runtime *fwrt) &tbl_rev); if (!IS_ERR(wifi_pkg)) { if (tbl_rev != 1) { - ret = PTR_ERR(wifi_pkg); + ret = -EINVAL; goto out_free; } @@ -650,7 +650,7 @@ int iwl_sar_get_wrds_table(struct iwl_fw_runtime *fwrt) &tbl_rev); if (!IS_ERR(wifi_pkg)) { if (tbl_rev != 0) { - ret = PTR_ERR(wifi_pkg); + ret = -EINVAL; goto out_free; } @@ -707,7 +707,7 @@ int iwl_sar_get_ewrd_table(struct iwl_fw_runtime *fwrt) &tbl_rev); if (!IS_ERR(wifi_pkg)) { if (tbl_rev != 2) { - ret = PTR_ERR(wifi_pkg); + ret = -EINVAL; goto out_free; } @@ -723,7 +723,7 @@ int iwl_sar_get_ewrd_table(struct iwl_fw_runtime *fwrt) &tbl_rev); if (!IS_ERR(wifi_pkg)) { if (tbl_rev != 1) { - ret = PTR_ERR(wifi_pkg); + ret = -EINVAL; goto out_free; } @@ -739,7 +739,7 @@ int iwl_sar_get_ewrd_table(struct iwl_fw_runtime *fwrt) &tbl_rev); if (!IS_ERR(wifi_pkg)) { if (tbl_rev != 0) { - ret = PTR_ERR(wifi_pkg); + ret = -EINVAL; goto out_free; } @@ -1116,6 +1116,9 @@ int iwl_acpi_get_ppag_table(struct iwl_fw_runtime *fwrt) goto read_table; } + ret = PTR_ERR(wifi_pkg); + goto out_free; + read_table: fwrt->ppag_ver = tbl_rev; flags = &wifi_pkg->package.elements[1]; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 3447d67a8b31..53e26c3c3a9a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -3687,6 +3687,9 @@ iwl_mvm_sta_state_notexist_to_none(struct iwl_mvm *mvm, NL80211_TDLS_SETUP); } + if (ret) + return ret; + for_each_sta_active_link(vif, sta, link_sta, i) link_sta->agg.max_rc_amsdu_len = 1; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 886d00098528..af15d470c69b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -505,6 +505,10 @@ static bool iwl_mvm_is_dup(struct ieee80211_sta *sta, int queue, return false; mvm_sta = iwl_mvm_sta_from_mac80211(sta); + + if (WARN_ON_ONCE(!mvm_sta->dup_data)) + return false; + dup_data = &mvm_sta->dup_data[queue]; /* diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c index 218fdf1ed530..2e653a417d62 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2018-2023 Intel Corporation + * Copyright (C) 2012-2014, 2018-2024 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2017 Intel Deutschland GmbH */ @@ -972,6 +972,7 @@ void iwl_mvm_rx_session_protect_notif(struct iwl_mvm *mvm, if (!le32_to_cpu(notif->status) || !le32_to_cpu(notif->start)) { /* End TE, notify mac80211 */ mvmvif->time_event_data.id = SESSION_PROTECT_CONF_MAX_ID; + mvmvif->time_event_data.link_id = -1; iwl_mvm_p2p_roc_finished(mvm); ieee80211_remain_on_channel_expired(mvm->hw); } else if (le32_to_cpu(notif->start)) { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index db986bfc4dc3..461f26d9214e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -520,13 +520,24 @@ static void iwl_mvm_set_tx_cmd_crypto(struct iwl_mvm *mvm, } } +static void iwl_mvm_copy_hdr(void *cmd, const void *hdr, int hdrlen, + const u8 *addr3_override) +{ + struct ieee80211_hdr *out_hdr = cmd; + + memcpy(cmd, hdr, hdrlen); + if (addr3_override) + memcpy(out_hdr->addr3, addr3_override, ETH_ALEN); +} + /* * Allocates and sets the Tx cmd the driver data pointers in the skb */ static struct iwl_device_tx_cmd * iwl_mvm_set_tx_params(struct iwl_mvm *mvm, struct sk_buff *skb, struct ieee80211_tx_info *info, int hdrlen, - struct ieee80211_sta *sta, u8 sta_id) + struct ieee80211_sta *sta, u8 sta_id, + const u8 *addr3_override) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct iwl_device_tx_cmd *dev_cmd; @@ -584,7 +595,7 @@ iwl_mvm_set_tx_params(struct iwl_mvm *mvm, struct sk_buff *skb, cmd->len = cpu_to_le16((u16)skb->len); /* Copy MAC header from skb into command buffer */ - memcpy(cmd->hdr, hdr, hdrlen); + iwl_mvm_copy_hdr(cmd->hdr, hdr, hdrlen, addr3_override); cmd->flags = cpu_to_le16(flags); cmd->rate_n_flags = cpu_to_le32(rate_n_flags); @@ -599,7 +610,7 @@ iwl_mvm_set_tx_params(struct iwl_mvm *mvm, struct sk_buff *skb, cmd->len = cpu_to_le16((u16)skb->len); /* Copy MAC header from skb into command buffer */ - memcpy(cmd->hdr, hdr, hdrlen); + iwl_mvm_copy_hdr(cmd->hdr, hdr, hdrlen, addr3_override); cmd->flags = cpu_to_le32(flags); cmd->rate_n_flags = cpu_to_le32(rate_n_flags); @@ -617,7 +628,7 @@ iwl_mvm_set_tx_params(struct iwl_mvm *mvm, struct sk_buff *skb, iwl_mvm_set_tx_cmd_rate(mvm, tx_cmd, info, sta, hdr->frame_control); /* Copy MAC header from skb into command buffer */ - memcpy(tx_cmd->hdr, hdr, hdrlen); + iwl_mvm_copy_hdr(tx_cmd->hdr, hdr, hdrlen, addr3_override); out: return dev_cmd; @@ -820,7 +831,8 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb) IWL_DEBUG_TX(mvm, "station Id %d, queue=%d\n", sta_id, queue); - dev_cmd = iwl_mvm_set_tx_params(mvm, skb, &info, hdrlen, NULL, sta_id); + dev_cmd = iwl_mvm_set_tx_params(mvm, skb, &info, hdrlen, NULL, sta_id, + NULL); if (!dev_cmd) return -1; @@ -1140,7 +1152,8 @@ static int iwl_mvm_tx_pkt_queued(struct iwl_mvm *mvm, */ static int iwl_mvm_tx_mpdu(struct iwl_mvm *mvm, struct sk_buff *skb, struct ieee80211_tx_info *info, - struct ieee80211_sta *sta) + struct ieee80211_sta *sta, + const u8 *addr3_override) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct iwl_mvm_sta *mvmsta; @@ -1172,7 +1185,8 @@ static int iwl_mvm_tx_mpdu(struct iwl_mvm *mvm, struct sk_buff *skb, iwl_mvm_probe_resp_set_noa(mvm, skb); dev_cmd = iwl_mvm_set_tx_params(mvm, skb, info, hdrlen, - sta, mvmsta->deflink.sta_id); + sta, mvmsta->deflink.sta_id, + addr3_override); if (!dev_cmd) goto drop; @@ -1294,9 +1308,11 @@ int iwl_mvm_tx_skb_sta(struct iwl_mvm *mvm, struct sk_buff *skb, struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); struct ieee80211_tx_info info; struct sk_buff_head mpdus_skbs; + struct ieee80211_vif *vif; unsigned int payload_len; int ret; struct sk_buff *orig_skb = skb; + const u8 *addr3; if (WARN_ON_ONCE(!mvmsta)) return -1; @@ -1307,26 +1323,59 @@ int iwl_mvm_tx_skb_sta(struct iwl_mvm *mvm, struct sk_buff *skb, memcpy(&info, skb->cb, sizeof(info)); if (!skb_is_gso(skb)) - return iwl_mvm_tx_mpdu(mvm, skb, &info, sta); + return iwl_mvm_tx_mpdu(mvm, skb, &info, sta, NULL); payload_len = skb_tail_pointer(skb) - skb_transport_header(skb) - tcp_hdrlen(skb) + skb->data_len; if (payload_len <= skb_shinfo(skb)->gso_size) - return iwl_mvm_tx_mpdu(mvm, skb, &info, sta); + return iwl_mvm_tx_mpdu(mvm, skb, &info, sta, NULL); __skb_queue_head_init(&mpdus_skbs); + vif = info.control.vif; + if (!vif) + return -1; + ret = iwl_mvm_tx_tso(mvm, skb, &info, sta, &mpdus_skbs); if (ret) return ret; WARN_ON(skb_queue_empty(&mpdus_skbs)); + /* + * As described in IEEE sta 802.11-2020, table 9-30 (Address + * field contents), A-MSDU address 3 should contain the BSSID + * address. + * Pass address 3 down to iwl_mvm_tx_mpdu() and further to set it + * in the command header. We need to preserve the original + * address 3 in the skb header to correctly create all the + * A-MSDU subframe headers from it. + */ + switch (vif->type) { + case NL80211_IFTYPE_STATION: + addr3 = vif->cfg.ap_addr; + break; + case NL80211_IFTYPE_AP: + addr3 = vif->addr; + break; + default: + addr3 = NULL; + break; + } + while (!skb_queue_empty(&mpdus_skbs)) { + struct ieee80211_hdr *hdr; + bool amsdu; + skb = __skb_dequeue(&mpdus_skbs); + hdr = (void *)skb->data; + amsdu = ieee80211_is_data_qos(hdr->frame_control) && + (*ieee80211_get_qos_ctl(hdr) & + IEEE80211_QOS_CTL_A_MSDU_PRESENT); - ret = iwl_mvm_tx_mpdu(mvm, skb, &info, sta); + ret = iwl_mvm_tx_mpdu(mvm, skb, &info, sta, + amsdu ? addr3 : NULL); if (ret) { /* Free skbs created as part of TSO logic that have not yet been dequeued */ __skb_queue_purge(&mpdus_skbs); diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index fab361a250d6..ef76850d9bcd 100644 --- a/drivers/net/xen-netback/netback.c +++ b/drivers/net/xen-netback/netback.c @@ -1778,5 +1778,6 @@ static void __exit netback_fini(void) } module_exit(netback_fini); +MODULE_DESCRIPTION("Xen backend network device module"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_ALIAS("xen-backend:vif"); diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index 60537c9224bf..0a96362912ce 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -1153,6 +1153,10 @@ u32 nvme_command_effects(struct nvme_ctrl *ctrl, struct nvme_ns *ns, u8 opcode) effects &= ~NVME_CMD_EFFECTS_CSE_MASK; } else { effects = le32_to_cpu(ctrl->effects->acs[opcode]); + + /* Ignore execution restrictions if any relaxation bits are set */ + if (effects & NVME_CMD_EFFECTS_CSER_MASK) + effects &= ~NVME_CMD_EFFECTS_CSE_MASK; } return effects; diff --git a/drivers/nvme/host/fabrics.c b/drivers/nvme/host/fabrics.c index 3499acbf6a82..495c171daead 100644 --- a/drivers/nvme/host/fabrics.c +++ b/drivers/nvme/host/fabrics.c @@ -534,6 +534,7 @@ int nvmf_connect_io_queue(struct nvme_ctrl *ctrl, u16 qid) if (ret) { nvmf_log_connect_error(ctrl, ret, le32_to_cpu(res.u32), &cmd, data); + goto out_free_data; } result = le32_to_cpu(res.u32); if (result & (NVME_CONNECT_AUTHREQ_ATR | NVME_CONNECT_AUTHREQ_ASCR)) { diff --git a/drivers/nvme/target/fabrics-cmd.c b/drivers/nvme/target/fabrics-cmd.c index d8da840a1c0e..9964ffe347d2 100644 --- a/drivers/nvme/target/fabrics-cmd.c +++ b/drivers/nvme/target/fabrics-cmd.c @@ -209,7 +209,7 @@ static void nvmet_execute_admin_connect(struct nvmet_req *req) struct nvmf_connect_command *c = &req->cmd->connect; struct nvmf_connect_data *d; struct nvmet_ctrl *ctrl = NULL; - u16 status = 0; + u16 status; int ret; if (!nvmet_check_transfer_len(req, sizeof(struct nvmf_connect_data))) @@ -290,7 +290,7 @@ static void nvmet_execute_io_connect(struct nvmet_req *req) struct nvmf_connect_data *d; struct nvmet_ctrl *ctrl; u16 qid = le16_to_cpu(c->qid); - u16 status = 0; + u16 status; if (!nvmet_check_transfer_len(req, sizeof(struct nvmf_connect_data))) return; diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index 980123fb4dde..eb357ac2e54a 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -460,8 +460,9 @@ static int nvmem_populate_sysfs_cells(struct nvmem_device *nvmem) list_for_each_entry(entry, &nvmem->cells, node) { sysfs_bin_attr_init(&attrs[i]); attrs[i].attr.name = devm_kasprintf(&nvmem->dev, GFP_KERNEL, - "%s@%x", entry->name, - entry->offset); + "%s@%x,%x", entry->name, + entry->offset, + entry->bit_offset); attrs[i].attr.mode = 0444; attrs[i].size = entry->bytes; attrs[i].read = &nvmem_cell_attr_read; diff --git a/drivers/of/property.c b/drivers/of/property.c index 641a40cf5cf3..606656fb3def 100644 --- a/drivers/of/property.c +++ b/drivers/of/property.c @@ -763,7 +763,9 @@ struct device_node *of_graph_get_port_parent(struct device_node *node) /* Walk 3 levels up only if there is 'ports' node. */ for (depth = 3; depth && node; depth--) { node = of_get_next_parent(node); - if (depth == 2 && !of_node_name_eq(node, "ports")) + if (depth == 2 && !of_node_name_eq(node, "ports") && + !of_node_name_eq(node, "in-ports") && + !of_node_name_eq(node, "out-ports")) break; } return node; @@ -1063,36 +1065,6 @@ of_fwnode_device_get_match_data(const struct fwnode_handle *fwnode, return of_device_get_match_data(dev); } -static struct device_node *of_get_compat_node(struct device_node *np) -{ - of_node_get(np); - - while (np) { - if (!of_device_is_available(np)) { - of_node_put(np); - np = NULL; - } - - if (of_property_present(np, "compatible")) - break; - - np = of_get_next_parent(np); - } - - return np; -} - -static struct device_node *of_get_compat_node_parent(struct device_node *np) -{ - struct device_node *parent, *node; - - parent = of_get_parent(np); - node = of_get_compat_node(parent); - of_node_put(parent); - - return node; -} - static void of_link_to_phandle(struct device_node *con_np, struct device_node *sup_np) { @@ -1222,10 +1194,10 @@ static struct device_node *parse_##fname(struct device_node *np, \ * parse_prop.prop_name: Name of property holding a phandle value * parse_prop.index: For properties holding a list of phandles, this is the * index into the list + * @get_con_dev: If the consumer node containing the property is never converted + * to a struct device, implement this ops so fw_devlink can use it + * to find the true consumer. * @optional: Describes whether a supplier is mandatory or not - * @node_not_dev: The consumer node containing the property is never converted - * to a struct device. Instead, parse ancestor nodes for the - * compatible property to find a node corresponding to a device. * * Returns: * parse_prop() return values are @@ -1236,15 +1208,16 @@ static struct device_node *parse_##fname(struct device_node *np, \ struct supplier_bindings { struct device_node *(*parse_prop)(struct device_node *np, const char *prop_name, int index); + struct device_node *(*get_con_dev)(struct device_node *np); bool optional; - bool node_not_dev; }; DEFINE_SIMPLE_PROP(clocks, "clocks", "#clock-cells") DEFINE_SIMPLE_PROP(interconnects, "interconnects", "#interconnect-cells") DEFINE_SIMPLE_PROP(iommus, "iommus", "#iommu-cells") DEFINE_SIMPLE_PROP(mboxes, "mboxes", "#mbox-cells") -DEFINE_SIMPLE_PROP(io_channels, "io-channel", "#io-channel-cells") +DEFINE_SIMPLE_PROP(io_channels, "io-channels", "#io-channel-cells") +DEFINE_SIMPLE_PROP(io_backends, "io-backends", "#io-backend-cells") DEFINE_SIMPLE_PROP(interrupt_parent, "interrupt-parent", NULL) DEFINE_SIMPLE_PROP(dmas, "dmas", "#dma-cells") DEFINE_SIMPLE_PROP(power_domains, "power-domains", "#power-domain-cells") @@ -1262,7 +1235,6 @@ DEFINE_SIMPLE_PROP(pinctrl5, "pinctrl-5", NULL) DEFINE_SIMPLE_PROP(pinctrl6, "pinctrl-6", NULL) DEFINE_SIMPLE_PROP(pinctrl7, "pinctrl-7", NULL) DEFINE_SIMPLE_PROP(pinctrl8, "pinctrl-8", NULL) -DEFINE_SIMPLE_PROP(remote_endpoint, "remote-endpoint", NULL) DEFINE_SIMPLE_PROP(pwms, "pwms", "#pwm-cells") DEFINE_SIMPLE_PROP(resets, "resets", "#reset-cells") DEFINE_SIMPLE_PROP(leds, "leds", NULL) @@ -1328,6 +1300,17 @@ static struct device_node *parse_interrupts(struct device_node *np, return of_irq_parse_one(np, index, &sup_args) ? NULL : sup_args.np; } +static struct device_node *parse_remote_endpoint(struct device_node *np, + const char *prop_name, + int index) +{ + /* Return NULL for index > 0 to signify end of remote-endpoints. */ + if (!index || strcmp(prop_name, "remote-endpoint")) + return NULL; + + return of_graph_get_remote_port_parent(np); +} + static const struct supplier_bindings of_supplier_bindings[] = { { .parse_prop = parse_clocks, }, { .parse_prop = parse_interconnects, }, @@ -1335,6 +1318,7 @@ static const struct supplier_bindings of_supplier_bindings[] = { { .parse_prop = parse_iommu_maps, .optional = true, }, { .parse_prop = parse_mboxes, }, { .parse_prop = parse_io_channels, }, + { .parse_prop = parse_io_backends, }, { .parse_prop = parse_interrupt_parent, }, { .parse_prop = parse_dmas, .optional = true, }, { .parse_prop = parse_power_domains, }, @@ -1352,7 +1336,10 @@ static const struct supplier_bindings of_supplier_bindings[] = { { .parse_prop = parse_pinctrl6, }, { .parse_prop = parse_pinctrl7, }, { .parse_prop = parse_pinctrl8, }, - { .parse_prop = parse_remote_endpoint, .node_not_dev = true, }, + { + .parse_prop = parse_remote_endpoint, + .get_con_dev = of_graph_get_port_parent, + }, { .parse_prop = parse_pwms, }, { .parse_prop = parse_resets, }, { .parse_prop = parse_leds, }, @@ -1403,8 +1390,8 @@ static int of_link_property(struct device_node *con_np, const char *prop_name) while ((phandle = s->parse_prop(con_np, prop_name, i))) { struct device_node *con_dev_np; - con_dev_np = s->node_not_dev - ? of_get_compat_node_parent(con_np) + con_dev_np = s->get_con_dev + ? s->get_con_dev(con_np) : of_node_get(con_np); matched = true; i++; diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c index cfd60e35a899..d7593bde2d02 100644 --- a/drivers/of/unittest.c +++ b/drivers/of/unittest.c @@ -50,6 +50,12 @@ static struct unittest_results { failed; \ }) +#ifdef CONFIG_OF_KOBJ +#define OF_KREF_READ(NODE) kref_read(&(NODE)->kobj.kref) +#else +#define OF_KREF_READ(NODE) 1 +#endif + /* * Expected message may have a message level other than KERN_INFO. * Print the expected message only if the current loglevel will allow @@ -570,7 +576,7 @@ static void __init of_unittest_parse_phandle_with_args_map(void) pr_err("missing testcase data\n"); return; } - prefs[i] = kref_read(&p[i]->kobj.kref); + prefs[i] = OF_KREF_READ(p[i]); } rc = of_count_phandle_with_args(np, "phandle-list", "#phandle-cells"); @@ -693,9 +699,9 @@ static void __init of_unittest_parse_phandle_with_args_map(void) unittest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc); for (i = 0; i < ARRAY_SIZE(p); ++i) { - unittest(prefs[i] == kref_read(&p[i]->kobj.kref), + unittest(prefs[i] == OF_KREF_READ(p[i]), "provider%d: expected:%d got:%d\n", - i, prefs[i], kref_read(&p[i]->kobj.kref)); + i, prefs[i], OF_KREF_READ(p[i])); of_node_put(p[i]); } } diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 9ab9b1008d8b..c3585229c12a 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -2522,29 +2522,36 @@ static void pci_pme_list_scan(struct work_struct *work) if (pdev->pme_poll) { struct pci_dev *bridge = pdev->bus->self; struct device *dev = &pdev->dev; - int pm_status; + struct device *bdev = bridge ? &bridge->dev : NULL; + int bref = 0; /* - * If bridge is in low power state, the - * configuration space of subordinate devices - * may be not accessible + * If we have a bridge, it should be in an active/D0 + * state or the configuration space of subordinate + * devices may not be accessible or stable over the + * course of the call. */ - if (bridge && bridge->current_state != PCI_D0) - continue; + if (bdev) { + bref = pm_runtime_get_if_active(bdev, true); + if (!bref) + continue; + + if (bridge->current_state != PCI_D0) + goto put_bridge; + } /* - * If the device is in a low power state it - * should not be polled either. + * The device itself should be suspended but config + * space must be accessible, therefore it cannot be in + * D3cold. */ - pm_status = pm_runtime_get_if_active(dev, true); - if (!pm_status) - continue; - - if (pdev->current_state != PCI_D3cold) + if (pm_runtime_suspended(dev) && + pdev->current_state != PCI_D3cold) pci_pme_wakeup(pdev, NULL); - if (pm_status > 0) - pm_runtime_put(dev); +put_bridge: + if (bref > 0) + pm_runtime_put(bdev); } else { list_del(&pme_dev->list); kfree(pme_dev); diff --git a/drivers/perf/arm-cmn.c b/drivers/perf/arm-cmn.c index c584165b13ba..7e3aa7e2345f 100644 --- a/drivers/perf/arm-cmn.c +++ b/drivers/perf/arm-cmn.c @@ -2305,6 +2305,17 @@ static int arm_cmn_discover(struct arm_cmn *cmn, unsigned int rgn_offset) dev_dbg(cmn->dev, "ignoring external node %llx\n", reg); continue; } + /* + * AmpereOneX erratum AC04_MESH_1 makes some XPs report a bogus + * child count larger than the number of valid child pointers. + * A child offset of 0 can only occur on CMN-600; otherwise it + * would imply the root node being its own grandchild, which + * we can safely dismiss in general. + */ + if (reg == 0 && cmn->part != PART_CMN600) { + dev_dbg(cmn->dev, "bogus child pointer?\n"); + continue; + } arm_cmn_init_node_info(cmn, reg & CMN_CHILD_NODE_ADDR, dn); diff --git a/drivers/perf/cxl_pmu.c b/drivers/perf/cxl_pmu.c index 365d964b0f6a..bc0d414a6aff 100644 --- a/drivers/perf/cxl_pmu.c +++ b/drivers/perf/cxl_pmu.c @@ -419,7 +419,7 @@ static struct attribute *cxl_pmu_event_attrs[] = { CXL_PMU_EVENT_CXL_ATTR(s2m_ndr_cmp, CXL_PMU_GID_S2M_NDR, BIT(0)), CXL_PMU_EVENT_CXL_ATTR(s2m_ndr_cmps, CXL_PMU_GID_S2M_NDR, BIT(1)), CXL_PMU_EVENT_CXL_ATTR(s2m_ndr_cmpe, CXL_PMU_GID_S2M_NDR, BIT(2)), - CXL_PMU_EVENT_CXL_ATTR(s2m_ndr_biconflictack, CXL_PMU_GID_S2M_NDR, BIT(3)), + CXL_PMU_EVENT_CXL_ATTR(s2m_ndr_biconflictack, CXL_PMU_GID_S2M_NDR, BIT(4)), /* CXL rev 3.0 Table 3-46 S2M DRS opcodes */ CXL_PMU_EVENT_CXL_ATTR(s2m_drs_memdata, CXL_PMU_GID_S2M_DRS, BIT(0)), CXL_PMU_EVENT_CXL_ATTR(s2m_drs_memdatanxm, CXL_PMU_GID_S2M_DRS, BIT(1)), diff --git a/drivers/scsi/fcoe/fcoe_ctlr.c b/drivers/scsi/fcoe/fcoe_ctlr.c index 19eee108db02..5c8d1ba3f8f3 100644 --- a/drivers/scsi/fcoe/fcoe_ctlr.c +++ b/drivers/scsi/fcoe/fcoe_ctlr.c @@ -319,17 +319,16 @@ static void fcoe_ctlr_announce(struct fcoe_ctlr *fip) { struct fcoe_fcf *sel; struct fcoe_fcf *fcf; - unsigned long flags; mutex_lock(&fip->ctlr_mutex); - spin_lock_irqsave(&fip->ctlr_lock, flags); + spin_lock_bh(&fip->ctlr_lock); kfree_skb(fip->flogi_req); fip->flogi_req = NULL; list_for_each_entry(fcf, &fip->fcfs, list) fcf->flogi_sent = 0; - spin_unlock_irqrestore(&fip->ctlr_lock, flags); + spin_unlock_bh(&fip->ctlr_lock); sel = fip->sel_fcf; if (sel && ether_addr_equal(sel->fcf_mac, fip->dest_addr)) @@ -700,7 +699,6 @@ int fcoe_ctlr_els_send(struct fcoe_ctlr *fip, struct fc_lport *lport, { struct fc_frame *fp; struct fc_frame_header *fh; - unsigned long flags; u16 old_xid; u8 op; u8 mac[ETH_ALEN]; @@ -734,11 +732,11 @@ int fcoe_ctlr_els_send(struct fcoe_ctlr *fip, struct fc_lport *lport, op = FIP_DT_FLOGI; if (fip->mode == FIP_MODE_VN2VN) break; - spin_lock_irqsave(&fip->ctlr_lock, flags); + spin_lock_bh(&fip->ctlr_lock); kfree_skb(fip->flogi_req); fip->flogi_req = skb; fip->flogi_req_send = 1; - spin_unlock_irqrestore(&fip->ctlr_lock, flags); + spin_unlock_bh(&fip->ctlr_lock); schedule_work(&fip->timer_work); return -EINPROGRESS; case ELS_FDISC: @@ -1707,11 +1705,10 @@ static int fcoe_ctlr_flogi_send_locked(struct fcoe_ctlr *fip) static int fcoe_ctlr_flogi_retry(struct fcoe_ctlr *fip) { struct fcoe_fcf *fcf; - unsigned long flags; int error; mutex_lock(&fip->ctlr_mutex); - spin_lock_irqsave(&fip->ctlr_lock, flags); + spin_lock_bh(&fip->ctlr_lock); LIBFCOE_FIP_DBG(fip, "re-sending FLOGI - reselect\n"); fcf = fcoe_ctlr_select(fip); if (!fcf || fcf->flogi_sent) { @@ -1722,7 +1719,7 @@ static int fcoe_ctlr_flogi_retry(struct fcoe_ctlr *fip) fcoe_ctlr_solicit(fip, NULL); error = fcoe_ctlr_flogi_send_locked(fip); } - spin_unlock_irqrestore(&fip->ctlr_lock, flags); + spin_unlock_bh(&fip->ctlr_lock); mutex_unlock(&fip->ctlr_mutex); return error; } @@ -1739,9 +1736,8 @@ static int fcoe_ctlr_flogi_retry(struct fcoe_ctlr *fip) static void fcoe_ctlr_flogi_send(struct fcoe_ctlr *fip) { struct fcoe_fcf *fcf; - unsigned long flags; - spin_lock_irqsave(&fip->ctlr_lock, flags); + spin_lock_bh(&fip->ctlr_lock); fcf = fip->sel_fcf; if (!fcf || !fip->flogi_req_send) goto unlock; @@ -1768,7 +1764,7 @@ static void fcoe_ctlr_flogi_send(struct fcoe_ctlr *fip) } else /* XXX */ LIBFCOE_FIP_DBG(fip, "No FCF selected - defer send\n"); unlock: - spin_unlock_irqrestore(&fip->ctlr_lock, flags); + spin_unlock_bh(&fip->ctlr_lock); } /** diff --git a/drivers/scsi/fnic/fnic.h b/drivers/scsi/fnic/fnic.h index 2074937c05bc..ce73f08ee889 100644 --- a/drivers/scsi/fnic/fnic.h +++ b/drivers/scsi/fnic/fnic.h @@ -305,6 +305,7 @@ struct fnic { unsigned int copy_wq_base; struct work_struct link_work; struct work_struct frame_work; + struct work_struct flush_work; struct sk_buff_head frame_queue; struct sk_buff_head tx_queue; @@ -363,7 +364,7 @@ void fnic_handle_event(struct work_struct *work); int fnic_rq_cmpl_handler(struct fnic *fnic, int); int fnic_alloc_rq_frame(struct vnic_rq *rq); void fnic_free_rq_buf(struct vnic_rq *rq, struct vnic_rq_buf *buf); -void fnic_flush_tx(struct fnic *); +void fnic_flush_tx(struct work_struct *work); void fnic_eth_send(struct fcoe_ctlr *, struct sk_buff *skb); void fnic_set_port_id(struct fc_lport *, u32, struct fc_frame *); void fnic_update_mac(struct fc_lport *, u8 *new); diff --git a/drivers/scsi/fnic/fnic_fcs.c b/drivers/scsi/fnic/fnic_fcs.c index 5e312a55cc7d..a08293b2ad9f 100644 --- a/drivers/scsi/fnic/fnic_fcs.c +++ b/drivers/scsi/fnic/fnic_fcs.c @@ -1182,7 +1182,7 @@ int fnic_send(struct fc_lport *lp, struct fc_frame *fp) /** * fnic_flush_tx() - send queued frames. - * @fnic: fnic device + * @work: pointer to work element * * Send frames that were waiting to go out in FC or Ethernet mode. * Whenever changing modes we purge queued frames, so these frames should @@ -1190,8 +1190,9 @@ int fnic_send(struct fc_lport *lp, struct fc_frame *fp) * * Called without fnic_lock held. */ -void fnic_flush_tx(struct fnic *fnic) +void fnic_flush_tx(struct work_struct *work) { + struct fnic *fnic = container_of(work, struct fnic, flush_work); struct sk_buff *skb; struct fc_frame *fp; diff --git a/drivers/scsi/fnic/fnic_main.c b/drivers/scsi/fnic/fnic_main.c index 5ed1d897311a..29eead383eb9 100644 --- a/drivers/scsi/fnic/fnic_main.c +++ b/drivers/scsi/fnic/fnic_main.c @@ -830,6 +830,7 @@ static int fnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) spin_lock_init(&fnic->vlans_lock); INIT_WORK(&fnic->fip_frame_work, fnic_handle_fip_frame); INIT_WORK(&fnic->event_work, fnic_handle_event); + INIT_WORK(&fnic->flush_work, fnic_flush_tx); skb_queue_head_init(&fnic->fip_frame_queue); INIT_LIST_HEAD(&fnic->evlist); INIT_LIST_HEAD(&fnic->vlans); diff --git a/drivers/scsi/fnic/fnic_scsi.c b/drivers/scsi/fnic/fnic_scsi.c index 8d7fc5284293..fc4cee91b175 100644 --- a/drivers/scsi/fnic/fnic_scsi.c +++ b/drivers/scsi/fnic/fnic_scsi.c @@ -680,7 +680,7 @@ static int fnic_fcpio_fw_reset_cmpl_handler(struct fnic *fnic, spin_unlock_irqrestore(&fnic->fnic_lock, flags); - fnic_flush_tx(fnic); + queue_work(fnic_event_queue, &fnic->flush_work); reset_cmpl_handler_end: fnic_clear_state_flags(fnic, FNIC_FLAGS_FWRESET); @@ -736,7 +736,7 @@ static int fnic_fcpio_flogi_reg_cmpl_handler(struct fnic *fnic, } spin_unlock_irqrestore(&fnic->fnic_lock, flags); - fnic_flush_tx(fnic); + queue_work(fnic_event_queue, &fnic->flush_work); queue_work(fnic_event_queue, &fnic->frame_work); } else { spin_unlock_irqrestore(&fnic->fnic_lock, flags); diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c index 546cdce525fc..833a1bb7a914 100644 --- a/drivers/spi/spi-imx.c +++ b/drivers/spi/spi-imx.c @@ -2,6 +2,7 @@ // Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved. // Copyright (C) 2008 Juergen Beisert +#include <linux/bits.h> #include <linux/clk.h> #include <linux/completion.h> #include <linux/delay.h> @@ -660,15 +661,15 @@ static int mx51_ecspi_prepare_transfer(struct spi_imx_data *spi_imx, << MX51_ECSPI_CTRL_BL_OFFSET; else { if (spi_imx->usedma) { - ctrl |= (spi_imx->bits_per_word * - spi_imx_bytes_per_word(spi_imx->bits_per_word) - 1) + ctrl |= (spi_imx->bits_per_word - 1) << MX51_ECSPI_CTRL_BL_OFFSET; } else { if (spi_imx->count >= MX51_ECSPI_CTRL_MAX_BURST) - ctrl |= (MX51_ECSPI_CTRL_MAX_BURST - 1) + ctrl |= (MX51_ECSPI_CTRL_MAX_BURST * BITS_PER_BYTE - 1) << MX51_ECSPI_CTRL_BL_OFFSET; else - ctrl |= (spi_imx->count * spi_imx->bits_per_word - 1) + ctrl |= spi_imx->count / DIV_ROUND_UP(spi_imx->bits_per_word, + BITS_PER_BYTE) * spi_imx->bits_per_word << MX51_ECSPI_CTRL_BL_OFFSET; } } diff --git a/drivers/spi/spi-intel-pci.c b/drivers/spi/spi-intel-pci.c index 07d20ca1164c..4337ca51d7aa 100644 --- a/drivers/spi/spi-intel-pci.c +++ b/drivers/spi/spi-intel-pci.c @@ -85,6 +85,7 @@ static const struct pci_device_id intel_spi_pci_ids[] = { { PCI_VDEVICE(INTEL, 0xa2a4), (unsigned long)&cnl_info }, { PCI_VDEVICE(INTEL, 0xa324), (unsigned long)&cnl_info }, { PCI_VDEVICE(INTEL, 0xa3a4), (unsigned long)&cnl_info }, + { PCI_VDEVICE(INTEL, 0xa823), (unsigned long)&cnl_info }, { }, }; MODULE_DEVICE_TABLE(pci, intel_spi_pci_ids); diff --git a/drivers/spi/spi-mxs.c b/drivers/spi/spi-mxs.c index 1bf080339b5a..88cbe4f00cc3 100644 --- a/drivers/spi/spi-mxs.c +++ b/drivers/spi/spi-mxs.c @@ -39,6 +39,7 @@ #include <linux/spi/spi.h> #include <linux/spi/mxs-spi.h> #include <trace/events/spi.h> +#include <linux/dma/mxs-dma.h> #define DRIVER_NAME "mxs-spi" @@ -252,7 +253,7 @@ static int mxs_spi_txrx_dma(struct mxs_spi *spi, desc = dmaengine_prep_slave_sg(ssp->dmach, &dma_xfer[sg_count].sg, 1, (flags & TXRX_WRITE) ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM, - DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + DMA_PREP_INTERRUPT | MXS_DMA_CTRL_WAIT4END); if (!desc) { dev_err(ssp->dev, diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c index a0c9fea908f5..ddf1c684bcc7 100644 --- a/drivers/spi/spi-omap2-mcspi.c +++ b/drivers/spi/spi-omap2-mcspi.c @@ -53,8 +53,6 @@ /* per-register bitmasks: */ #define OMAP2_MCSPI_IRQSTATUS_EOW BIT(17) -#define OMAP2_MCSPI_IRQSTATUS_TX0_EMPTY BIT(0) -#define OMAP2_MCSPI_IRQSTATUS_RX0_FULL BIT(2) #define OMAP2_MCSPI_MODULCTRL_SINGLE BIT(0) #define OMAP2_MCSPI_MODULCTRL_MS BIT(2) @@ -293,7 +291,7 @@ static void omap2_mcspi_set_mode(struct spi_controller *ctlr) } static void omap2_mcspi_set_fifo(const struct spi_device *spi, - struct spi_transfer *t, int enable, int dma_enabled) + struct spi_transfer *t, int enable) { struct spi_controller *ctlr = spi->controller; struct omap2_mcspi_cs *cs = spi->controller_state; @@ -314,28 +312,20 @@ static void omap2_mcspi_set_fifo(const struct spi_device *spi, max_fifo_depth = OMAP2_MCSPI_MAX_FIFODEPTH / 2; else max_fifo_depth = OMAP2_MCSPI_MAX_FIFODEPTH; - if (dma_enabled) - wcnt = t->len / bytes_per_word; - else - wcnt = 0; + + wcnt = t->len / bytes_per_word; if (wcnt > OMAP2_MCSPI_MAX_FIFOWCNT) goto disable_fifo; xferlevel = wcnt << 16; if (t->rx_buf != NULL) { chconf |= OMAP2_MCSPI_CHCONF_FFER; - if (dma_enabled) - xferlevel |= (bytes_per_word - 1) << 8; - else - xferlevel |= (max_fifo_depth - 1) << 8; + xferlevel |= (bytes_per_word - 1) << 8; } if (t->tx_buf != NULL) { chconf |= OMAP2_MCSPI_CHCONF_FFET; - if (dma_enabled) - xferlevel |= bytes_per_word - 1; - else - xferlevel |= (max_fifo_depth - 1); + xferlevel |= bytes_per_word - 1; } mcspi_write_reg(ctlr, OMAP2_MCSPI_XFERLEVEL, xferlevel); @@ -892,113 +882,6 @@ out: return count - c; } -static unsigned -omap2_mcspi_txrx_piofifo(struct spi_device *spi, struct spi_transfer *xfer) -{ - struct omap2_mcspi_cs *cs = spi->controller_state; - struct omap2_mcspi *mcspi; - unsigned int count, c; - unsigned int iter, cwc; - int last_request; - void __iomem *base = cs->base; - void __iomem *tx_reg; - void __iomem *rx_reg; - void __iomem *chstat_reg; - void __iomem *irqstat_reg; - int word_len, bytes_per_word; - u8 *rx; - const u8 *tx; - - mcspi = spi_controller_get_devdata(spi->controller); - count = xfer->len; - c = count; - word_len = cs->word_len; - bytes_per_word = mcspi_bytes_per_word(word_len); - - /* - * We store the pre-calculated register addresses on stack to speed - * up the transfer loop. - */ - tx_reg = base + OMAP2_MCSPI_TX0; - rx_reg = base + OMAP2_MCSPI_RX0; - chstat_reg = base + OMAP2_MCSPI_CHSTAT0; - irqstat_reg = base + OMAP2_MCSPI_IRQSTATUS; - - if (c < (word_len >> 3)) - return 0; - - rx = xfer->rx_buf; - tx = xfer->tx_buf; - - do { - /* calculate number of words in current iteration */ - cwc = min((unsigned int)mcspi->fifo_depth / bytes_per_word, - c / bytes_per_word); - last_request = cwc != (mcspi->fifo_depth / bytes_per_word); - if (tx) { - if (mcspi_wait_for_reg_bit(irqstat_reg, - OMAP2_MCSPI_IRQSTATUS_TX0_EMPTY) < 0) { - dev_err(&spi->dev, "TX Empty timed out\n"); - goto out; - } - writel_relaxed(OMAP2_MCSPI_IRQSTATUS_TX0_EMPTY, irqstat_reg); - - for (iter = 0; iter < cwc; iter++, tx += bytes_per_word) { - if (bytes_per_word == 1) - writel_relaxed(*tx, tx_reg); - else if (bytes_per_word == 2) - writel_relaxed(*((u16 *)tx), tx_reg); - else if (bytes_per_word == 4) - writel_relaxed(*((u32 *)tx), tx_reg); - } - } - - if (rx) { - if (!last_request && - mcspi_wait_for_reg_bit(irqstat_reg, - OMAP2_MCSPI_IRQSTATUS_RX0_FULL) < 0) { - dev_err(&spi->dev, "RX_FULL timed out\n"); - goto out; - } - writel_relaxed(OMAP2_MCSPI_IRQSTATUS_RX0_FULL, irqstat_reg); - - for (iter = 0; iter < cwc; iter++, rx += bytes_per_word) { - if (last_request && - mcspi_wait_for_reg_bit(chstat_reg, - OMAP2_MCSPI_CHSTAT_RXS) < 0) { - dev_err(&spi->dev, "RXS timed out\n"); - goto out; - } - if (bytes_per_word == 1) - *rx = readl_relaxed(rx_reg); - else if (bytes_per_word == 2) - *((u16 *)rx) = readl_relaxed(rx_reg); - else if (bytes_per_word == 4) - *((u32 *)rx) = readl_relaxed(rx_reg); - } - } - - if (last_request) { - if (mcspi_wait_for_reg_bit(chstat_reg, - OMAP2_MCSPI_CHSTAT_EOT) < 0) { - dev_err(&spi->dev, "EOT timed out\n"); - goto out; - } - if (mcspi_wait_for_reg_bit(chstat_reg, - OMAP2_MCSPI_CHSTAT_TXFFE) < 0) { - dev_err(&spi->dev, "TXFFE timed out\n"); - goto out; - } - omap2_mcspi_set_enable(spi, 0); - } - c -= cwc * bytes_per_word; - } while (c >= bytes_per_word); - -out: - omap2_mcspi_set_enable(spi, 1); - return count - c; -} - static u32 omap2_mcspi_calc_divisor(u32 speed_hz, u32 ref_clk_hz) { u32 div; @@ -1323,9 +1206,7 @@ static int omap2_mcspi_transfer_one(struct spi_controller *ctlr, if ((mcspi_dma->dma_rx && mcspi_dma->dma_tx) && ctlr->cur_msg_mapped && ctlr->can_dma(ctlr, spi, t)) - omap2_mcspi_set_fifo(spi, t, 1, 1); - else if (t->len > OMAP2_MCSPI_MAX_FIFODEPTH) - omap2_mcspi_set_fifo(spi, t, 1, 0); + omap2_mcspi_set_fifo(spi, t, 1); omap2_mcspi_set_enable(spi, 1); @@ -1338,8 +1219,6 @@ static int omap2_mcspi_transfer_one(struct spi_controller *ctlr, ctlr->cur_msg_mapped && ctlr->can_dma(ctlr, spi, t)) count = omap2_mcspi_txrx_dma(spi, t); - else if (mcspi->fifo_depth > 0) - count = omap2_mcspi_txrx_piofifo(spi, t); else count = omap2_mcspi_txrx_pio(spi, t); @@ -1352,7 +1231,7 @@ static int omap2_mcspi_transfer_one(struct spi_controller *ctlr, omap2_mcspi_set_enable(spi, 0); if (mcspi->fifo_depth > 0) - omap2_mcspi_set_fifo(spi, t, 0, 0); + omap2_mcspi_set_fifo(spi, t, 0); out: /* Restore defaults if they were overriden */ @@ -1375,7 +1254,7 @@ out: omap2_mcspi_set_cs(spi, !(spi->mode & SPI_CS_HIGH)); if (mcspi->fifo_depth > 0 && t) - omap2_mcspi_set_fifo(spi, t, 0, 0); + omap2_mcspi_set_fifo(spi, t, 0); return status; } diff --git a/drivers/spi/spi-ppc4xx.c b/drivers/spi/spi-ppc4xx.c index 03aab661be9d..942c3117ab3a 100644 --- a/drivers/spi/spi-ppc4xx.c +++ b/drivers/spi/spi-ppc4xx.c @@ -25,11 +25,13 @@ #include <linux/slab.h> #include <linux/errno.h> #include <linux/wait.h> +#include <linux/platform_device.h> #include <linux/of_address.h> #include <linux/of_irq.h> #include <linux/of_platform.h> #include <linux/interrupt.h> #include <linux/delay.h> +#include <linux/platform_device.h> #include <linux/spi/spi.h> #include <linux/spi/spi_bitbang.h> @@ -166,10 +168,8 @@ static int spi_ppc4xx_setupxfer(struct spi_device *spi, struct spi_transfer *t) int scr; u8 cdm = 0; u32 speed; - u8 bits_per_word; /* Start with the generic configuration for this device. */ - bits_per_word = spi->bits_per_word; speed = spi->max_speed_hz; /* @@ -177,9 +177,6 @@ static int spi_ppc4xx_setupxfer(struct spi_device *spi, struct spi_transfer *t) * the transfer to overwrite the generic configuration with zeros. */ if (t) { - if (t->bits_per_word) - bits_per_word = t->bits_per_word; - if (t->speed_hz) speed = min(t->speed_hz, spi->max_speed_hz); } @@ -362,22 +359,22 @@ static int spi_ppc4xx_of_probe(struct platform_device *op) /* Setup the state for the bitbang driver */ bbp = &hw->bitbang; - bbp->master = hw->host; + bbp->ctlr = hw->host; bbp->setup_transfer = spi_ppc4xx_setupxfer; bbp->txrx_bufs = spi_ppc4xx_txrx; bbp->use_dma = 0; - bbp->master->setup = spi_ppc4xx_setup; - bbp->master->cleanup = spi_ppc4xx_cleanup; - bbp->master->bits_per_word_mask = SPI_BPW_MASK(8); - bbp->master->use_gpio_descriptors = true; + bbp->ctlr->setup = spi_ppc4xx_setup; + bbp->ctlr->cleanup = spi_ppc4xx_cleanup; + bbp->ctlr->bits_per_word_mask = SPI_BPW_MASK(8); + bbp->ctlr->use_gpio_descriptors = true; /* * The SPI core will count the number of GPIO descriptors to figure * out the number of chip selects available on the platform. */ - bbp->master->num_chipselect = 0; + bbp->ctlr->num_chipselect = 0; /* the spi->mode bits understood by this driver: */ - bbp->master->mode_bits = + bbp->ctlr->mode_bits = SPI_CPHA | SPI_CPOL | SPI_CS_HIGH | SPI_LSB_FIRST; /* Get the clock for the OPB */ diff --git a/drivers/staging/iio/impedance-analyzer/ad5933.c b/drivers/staging/iio/impedance-analyzer/ad5933.c index e748a5d04e97..9149d41fe65b 100644 --- a/drivers/staging/iio/impedance-analyzer/ad5933.c +++ b/drivers/staging/iio/impedance-analyzer/ad5933.c @@ -608,7 +608,7 @@ static void ad5933_work(struct work_struct *work) struct ad5933_state, work.work); struct iio_dev *indio_dev = i2c_get_clientdata(st->client); __be16 buf[2]; - int val[2]; + u16 val[2]; unsigned char status; int ret; diff --git a/drivers/staging/media/atomisp/pci/atomisp_cmd.c b/drivers/staging/media/atomisp/pci/atomisp_cmd.c index f44e6412f4e3..d0db2efe0045 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_cmd.c +++ b/drivers/staging/media/atomisp/pci/atomisp_cmd.c @@ -3723,12 +3723,10 @@ apply_min_padding: static int atomisp_set_crop(struct atomisp_device *isp, const struct v4l2_mbus_framefmt *format, + struct v4l2_subdev_state *sd_state, int which) { struct atomisp_input_subdev *input = &isp->inputs[isp->asd.input_curr]; - struct v4l2_subdev_state pad_state = { - .pads = &input->pad_cfg, - }; struct v4l2_subdev_selection sel = { .which = which, .target = V4L2_SEL_TGT_CROP, @@ -3754,7 +3752,7 @@ static int atomisp_set_crop(struct atomisp_device *isp, sel.r.left = ((input->native_rect.width - sel.r.width) / 2) & ~1; sel.r.top = ((input->native_rect.height - sel.r.height) / 2) & ~1; - ret = v4l2_subdev_call(input->camera, pad, set_selection, &pad_state, &sel); + ret = v4l2_subdev_call(input->camera, pad, set_selection, sd_state, &sel); if (ret) dev_err(isp->dev, "Error setting crop to %ux%u @%ux%u: %d\n", sel.r.width, sel.r.height, sel.r.left, sel.r.top, ret); @@ -3770,9 +3768,6 @@ int atomisp_try_fmt(struct atomisp_device *isp, struct v4l2_pix_format *f, const struct atomisp_format_bridge *fmt, *snr_fmt; struct atomisp_sub_device *asd = &isp->asd; struct atomisp_input_subdev *input = &isp->inputs[asd->input_curr]; - struct v4l2_subdev_state pad_state = { - .pads = &input->pad_cfg, - }; struct v4l2_subdev_format format = { .which = V4L2_SUBDEV_FORMAT_TRY, }; @@ -3809,11 +3804,16 @@ int atomisp_try_fmt(struct atomisp_device *isp, struct v4l2_pix_format *f, dev_dbg(isp->dev, "try_mbus_fmt: asking for %ux%u\n", format.format.width, format.format.height); - ret = atomisp_set_crop(isp, &format.format, V4L2_SUBDEV_FORMAT_TRY); - if (ret) - return ret; + v4l2_subdev_lock_state(input->try_sd_state); + + ret = atomisp_set_crop(isp, &format.format, input->try_sd_state, + V4L2_SUBDEV_FORMAT_TRY); + if (ret == 0) + ret = v4l2_subdev_call(input->camera, pad, set_fmt, + input->try_sd_state, &format); + + v4l2_subdev_unlock_state(input->try_sd_state); - ret = v4l2_subdev_call(input->camera, pad, set_fmt, &pad_state, &format); if (ret) return ret; @@ -4238,9 +4238,7 @@ static int atomisp_set_fmt_to_snr(struct video_device *vdev, const struct v4l2_p struct atomisp_device *isp = asd->isp; struct atomisp_input_subdev *input = &isp->inputs[asd->input_curr]; const struct atomisp_format_bridge *format; - struct v4l2_subdev_state pad_state = { - .pads = &input->pad_cfg, - }; + struct v4l2_subdev_state *act_sd_state; struct v4l2_subdev_format vformat = { .which = V4L2_SUBDEV_FORMAT_TRY, }; @@ -4268,12 +4266,18 @@ static int atomisp_set_fmt_to_snr(struct video_device *vdev, const struct v4l2_p /* Disable dvs if resolution can't be supported by sensor */ if (asd->params.video_dis_en && asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO) { - ret = atomisp_set_crop(isp, &vformat.format, V4L2_SUBDEV_FORMAT_TRY); - if (ret) - return ret; + v4l2_subdev_lock_state(input->try_sd_state); + + ret = atomisp_set_crop(isp, &vformat.format, input->try_sd_state, + V4L2_SUBDEV_FORMAT_TRY); + if (ret == 0) { + vformat.which = V4L2_SUBDEV_FORMAT_TRY; + ret = v4l2_subdev_call(input->camera, pad, set_fmt, + input->try_sd_state, &vformat); + } + + v4l2_subdev_unlock_state(input->try_sd_state); - vformat.which = V4L2_SUBDEV_FORMAT_TRY; - ret = v4l2_subdev_call(input->camera, pad, set_fmt, &pad_state, &vformat); if (ret) return ret; @@ -4291,12 +4295,18 @@ static int atomisp_set_fmt_to_snr(struct video_device *vdev, const struct v4l2_p } } - ret = atomisp_set_crop(isp, &vformat.format, V4L2_SUBDEV_FORMAT_ACTIVE); - if (ret) - return ret; + act_sd_state = v4l2_subdev_lock_and_get_active_state(input->camera); + + ret = atomisp_set_crop(isp, &vformat.format, act_sd_state, + V4L2_SUBDEV_FORMAT_ACTIVE); + if (ret == 0) { + vformat.which = V4L2_SUBDEV_FORMAT_ACTIVE; + ret = v4l2_subdev_call(input->camera, pad, set_fmt, act_sd_state, &vformat); + } + + if (act_sd_state) + v4l2_subdev_unlock_state(act_sd_state); - vformat.which = V4L2_SUBDEV_FORMAT_ACTIVE; - ret = v4l2_subdev_call(input->camera, pad, set_fmt, NULL, &vformat); if (ret) return ret; diff --git a/drivers/staging/media/atomisp/pci/atomisp_internal.h b/drivers/staging/media/atomisp/pci/atomisp_internal.h index f7b4bee9574b..d5b077e602ca 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_internal.h +++ b/drivers/staging/media/atomisp/pci/atomisp_internal.h @@ -132,8 +132,8 @@ struct atomisp_input_subdev { /* Sensor rects for sensors which support crop */ struct v4l2_rect native_rect; struct v4l2_rect active_rect; - /* Sensor pad_cfg for which == V4L2_SUBDEV_FORMAT_TRY calls */ - struct v4l2_subdev_pad_config pad_cfg; + /* Sensor state for which == V4L2_SUBDEV_FORMAT_TRY calls */ + struct v4l2_subdev_state *try_sd_state; struct v4l2_subdev *motor; diff --git a/drivers/staging/media/atomisp/pci/atomisp_ioctl.c b/drivers/staging/media/atomisp/pci/atomisp_ioctl.c index 01b7fa9b56a2..5b2d88c02d36 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_ioctl.c +++ b/drivers/staging/media/atomisp/pci/atomisp_ioctl.c @@ -781,12 +781,20 @@ static int atomisp_enum_framesizes(struct file *file, void *priv, .which = V4L2_SUBDEV_FORMAT_ACTIVE, .code = input->code, }; + struct v4l2_subdev_state *act_sd_state; int ret; + if (!input->camera) + return -EINVAL; + if (input->crop_support) return atomisp_enum_framesizes_crop(isp, fsize); - ret = v4l2_subdev_call(input->camera, pad, enum_frame_size, NULL, &fse); + act_sd_state = v4l2_subdev_lock_and_get_active_state(input->camera); + ret = v4l2_subdev_call(input->camera, pad, enum_frame_size, + act_sd_state, &fse); + if (act_sd_state) + v4l2_subdev_unlock_state(act_sd_state); if (ret) return ret; @@ -803,18 +811,25 @@ static int atomisp_enum_frameintervals(struct file *file, void *priv, struct video_device *vdev = video_devdata(file); struct atomisp_device *isp = video_get_drvdata(vdev); struct atomisp_sub_device *asd = atomisp_to_video_pipe(vdev)->asd; + struct atomisp_input_subdev *input = &isp->inputs[asd->input_curr]; struct v4l2_subdev_frame_interval_enum fie = { - .code = atomisp_in_fmt_conv[0].code, + .code = atomisp_in_fmt_conv[0].code, .index = fival->index, .width = fival->width, .height = fival->height, .which = V4L2_SUBDEV_FORMAT_ACTIVE, }; + struct v4l2_subdev_state *act_sd_state; int ret; - ret = v4l2_subdev_call(isp->inputs[asd->input_curr].camera, - pad, enum_frame_interval, NULL, - &fie); + if (!input->camera) + return -EINVAL; + + act_sd_state = v4l2_subdev_lock_and_get_active_state(input->camera); + ret = v4l2_subdev_call(input->camera, pad, enum_frame_interval, + act_sd_state, &fie); + if (act_sd_state) + v4l2_subdev_unlock_state(act_sd_state); if (ret) return ret; @@ -830,30 +845,25 @@ static int atomisp_enum_fmt_cap(struct file *file, void *fh, struct video_device *vdev = video_devdata(file); struct atomisp_device *isp = video_get_drvdata(vdev); struct atomisp_sub_device *asd = atomisp_to_video_pipe(vdev)->asd; + struct atomisp_input_subdev *input = &isp->inputs[asd->input_curr]; struct v4l2_subdev_mbus_code_enum code = { .which = V4L2_SUBDEV_FORMAT_ACTIVE, }; const struct atomisp_format_bridge *format; - struct v4l2_subdev *camera; + struct v4l2_subdev_state *act_sd_state; unsigned int i, fi = 0; - int rval; + int ret; - camera = isp->inputs[asd->input_curr].camera; - if(!camera) { - dev_err(isp->dev, "%s(): camera is NULL, device is %s\n", - __func__, vdev->name); + if (!input->camera) return -EINVAL; - } - rval = v4l2_subdev_call(camera, pad, enum_mbus_code, NULL, &code); - if (rval == -ENOIOCTLCMD) { - dev_warn(isp->dev, - "enum_mbus_code pad op not supported by %s. Please fix your sensor driver!\n", - camera->name); - } - - if (rval) - return rval; + act_sd_state = v4l2_subdev_lock_and_get_active_state(input->camera); + ret = v4l2_subdev_call(input->camera, pad, enum_mbus_code, + act_sd_state, &code); + if (act_sd_state) + v4l2_subdev_unlock_state(act_sd_state); + if (ret) + return ret; for (i = 0; i < ARRAY_SIZE(atomisp_output_fmts); i++) { format = &atomisp_output_fmts[i]; diff --git a/drivers/staging/media/atomisp/pci/atomisp_v4l2.c b/drivers/staging/media/atomisp/pci/atomisp_v4l2.c index c1c8501ec61f..547e1444ad97 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_v4l2.c +++ b/drivers/staging/media/atomisp/pci/atomisp_v4l2.c @@ -862,6 +862,9 @@ static void atomisp_unregister_entities(struct atomisp_device *isp) v4l2_device_unregister(&isp->v4l2_dev); media_device_unregister(&isp->media_dev); media_device_cleanup(&isp->media_dev); + + for (i = 0; i < isp->input_cnt; i++) + __v4l2_subdev_state_free(isp->inputs[i].try_sd_state); } static int atomisp_register_entities(struct atomisp_device *isp) @@ -933,32 +936,49 @@ v4l2_device_failed: static void atomisp_init_sensor(struct atomisp_input_subdev *input) { + static struct lock_class_key try_sd_state_key; struct v4l2_subdev_mbus_code_enum mbus_code_enum = { }; struct v4l2_subdev_frame_size_enum fse = { }; - struct v4l2_subdev_state sd_state = { - .pads = &input->pad_cfg, - }; struct v4l2_subdev_selection sel = { }; + struct v4l2_subdev_state *try_sd_state, *act_sd_state; int i, err; + /* + * FIXME: Drivers are not supposed to use __v4l2_subdev_state_alloc() + * but atomisp needs this for try_fmt on its /dev/video# node since + * it emulates a normal v4l2 device there, passing through try_fmt / + * set_fmt to the sensor. + */ + try_sd_state = __v4l2_subdev_state_alloc(input->camera, + "atomisp:try_sd_state->lock", &try_sd_state_key); + if (IS_ERR(try_sd_state)) + return; + + input->try_sd_state = try_sd_state; + + act_sd_state = v4l2_subdev_lock_and_get_active_state(input->camera); + mbus_code_enum.which = V4L2_SUBDEV_FORMAT_ACTIVE; - err = v4l2_subdev_call(input->camera, pad, enum_mbus_code, NULL, &mbus_code_enum); + err = v4l2_subdev_call(input->camera, pad, enum_mbus_code, + act_sd_state, &mbus_code_enum); if (!err) input->code = mbus_code_enum.code; sel.which = V4L2_SUBDEV_FORMAT_ACTIVE; sel.target = V4L2_SEL_TGT_NATIVE_SIZE; - err = v4l2_subdev_call(input->camera, pad, get_selection, NULL, &sel); + err = v4l2_subdev_call(input->camera, pad, get_selection, + act_sd_state, &sel); if (err) - return; + goto unlock_act_sd_state; input->native_rect = sel.r; sel.which = V4L2_SUBDEV_FORMAT_ACTIVE; sel.target = V4L2_SEL_TGT_CROP_DEFAULT; - err = v4l2_subdev_call(input->camera, pad, get_selection, NULL, &sel); + err = v4l2_subdev_call(input->camera, pad, get_selection, + act_sd_state, &sel); if (err) - return; + goto unlock_act_sd_state; input->active_rect = sel.r; @@ -973,7 +993,8 @@ static void atomisp_init_sensor(struct atomisp_input_subdev *input) fse.code = input->code; fse.which = V4L2_SUBDEV_FORMAT_ACTIVE; - err = v4l2_subdev_call(input->camera, pad, enum_frame_size, NULL, &fse); + err = v4l2_subdev_call(input->camera, pad, enum_frame_size, + act_sd_state, &fse); if (err) break; @@ -989,22 +1010,26 @@ static void atomisp_init_sensor(struct atomisp_input_subdev *input) * for padding, set the crop rect to cover the entire sensor instead * of only the default active area. * - * Do this for both try and active formats since the try_crop rect in - * pad_cfg may influence (clamp) future try_fmt calls with which == try. + * Do this for both try and active formats since the crop rect in + * try_sd_state may influence (clamp size) in calls with which == try. */ sel.which = V4L2_SUBDEV_FORMAT_TRY; sel.target = V4L2_SEL_TGT_CROP; sel.r = input->native_rect; - err = v4l2_subdev_call(input->camera, pad, set_selection, &sd_state, &sel); + v4l2_subdev_lock_state(input->try_sd_state); + err = v4l2_subdev_call(input->camera, pad, set_selection, + input->try_sd_state, &sel); + v4l2_subdev_unlock_state(input->try_sd_state); if (err) - return; + goto unlock_act_sd_state; sel.which = V4L2_SUBDEV_FORMAT_ACTIVE; sel.target = V4L2_SEL_TGT_CROP; sel.r = input->native_rect; - err = v4l2_subdev_call(input->camera, pad, set_selection, NULL, &sel); + err = v4l2_subdev_call(input->camera, pad, set_selection, + act_sd_state, &sel); if (err) - return; + goto unlock_act_sd_state; dev_info(input->camera->dev, "Supports crop native %dx%d active %dx%d binning %d\n", input->native_rect.width, input->native_rect.height, @@ -1012,6 +1037,10 @@ static void atomisp_init_sensor(struct atomisp_input_subdev *input) input->binning_support); input->crop_support = true; + +unlock_act_sd_state: + if (act_sd_state) + v4l2_subdev_unlock_state(act_sd_state); } int atomisp_register_device_nodes(struct atomisp_device *isp) diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index a5f58988130a..c1fbcdd16182 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -759,6 +759,29 @@ static ssize_t emulate_tas_store(struct config_item *item, return count; } +static int target_try_configure_unmap(struct se_device *dev, + const char *config_opt) +{ + if (!dev->transport->configure_unmap) { + pr_err("Generic Block Discard not supported\n"); + return -ENOSYS; + } + + if (!target_dev_configured(dev)) { + pr_err("Generic Block Discard setup for %s requires device to be configured\n", + config_opt); + return -ENODEV; + } + + if (!dev->transport->configure_unmap(dev)) { + pr_err("Generic Block Discard setup for %s failed\n", + config_opt); + return -ENOSYS; + } + + return 0; +} + static ssize_t emulate_tpu_store(struct config_item *item, const char *page, size_t count) { @@ -776,11 +799,9 @@ static ssize_t emulate_tpu_store(struct config_item *item, * Discard supported is detected iblock_create_virtdevice(). */ if (flag && !da->max_unmap_block_desc_count) { - if (!dev->transport->configure_unmap || - !dev->transport->configure_unmap(dev)) { - pr_err("Generic Block Discard not supported\n"); - return -ENOSYS; - } + ret = target_try_configure_unmap(dev, "emulate_tpu"); + if (ret) + return ret; } da->emulate_tpu = flag; @@ -806,11 +827,9 @@ static ssize_t emulate_tpws_store(struct config_item *item, * Discard supported is detected iblock_create_virtdevice(). */ if (flag && !da->max_unmap_block_desc_count) { - if (!dev->transport->configure_unmap || - !dev->transport->configure_unmap(dev)) { - pr_err("Generic Block Discard not supported\n"); - return -ENOSYS; - } + ret = target_try_configure_unmap(dev, "emulate_tpws"); + if (ret) + return ret; } da->emulate_tpws = flag; @@ -1022,12 +1041,9 @@ static ssize_t unmap_zeroes_data_store(struct config_item *item, * Discard supported is detected iblock_configure_device(). */ if (flag && !da->max_unmap_block_desc_count) { - if (!dev->transport->configure_unmap || - !dev->transport->configure_unmap(dev)) { - pr_err("dev[%p]: Thin Provisioning LBPRZ will not be set because max_unmap_block_desc_count is zero\n", - da->da_dev); - return -ENOSYS; - } + ret = target_try_configure_unmap(dev, "unmap_zeroes_data"); + if (ret) + return ret; } da->unmap_zeroes_data = flag; pr_debug("dev[%p]: SE Device Thin Provisioning LBPRZ bit: %d\n", diff --git a/drivers/thunderbolt/tb_regs.h b/drivers/thunderbolt/tb_regs.h index 87e4795275fe..6f798f6a2b84 100644 --- a/drivers/thunderbolt/tb_regs.h +++ b/drivers/thunderbolt/tb_regs.h @@ -203,7 +203,7 @@ struct tb_regs_switch_header { #define ROUTER_CS_5_WOP BIT(1) #define ROUTER_CS_5_WOU BIT(2) #define ROUTER_CS_5_WOD BIT(3) -#define ROUTER_CS_5_C3S BIT(23) +#define ROUTER_CS_5_CNS BIT(23) #define ROUTER_CS_5_PTO BIT(24) #define ROUTER_CS_5_UTO BIT(25) #define ROUTER_CS_5_HCO BIT(26) diff --git a/drivers/thunderbolt/usb4.c b/drivers/thunderbolt/usb4.c index f8f0d24ff6e4..1515eff8cc3e 100644 --- a/drivers/thunderbolt/usb4.c +++ b/drivers/thunderbolt/usb4.c @@ -290,7 +290,7 @@ int usb4_switch_setup(struct tb_switch *sw) } /* TBT3 supported by the CM */ - val |= ROUTER_CS_5_C3S; + val &= ~ROUTER_CS_5_CNS; return tb_sw_write(sw, &val, TB_CFG_SWITCH, ROUTER_CS_5, 1); } diff --git a/drivers/tty/serial/8250/8250_pci1xxxx.c b/drivers/tty/serial/8250/8250_pci1xxxx.c index cd258922bd78..2dda737b1660 100644 --- a/drivers/tty/serial/8250/8250_pci1xxxx.c +++ b/drivers/tty/serial/8250/8250_pci1xxxx.c @@ -302,7 +302,7 @@ static void pci1xxxx_process_read_data(struct uart_port *port, * to read, the data is received one byte at a time. */ while (valid_burst_count--) { - if (*buff_index >= (RX_BUF_SIZE - UART_BURST_SIZE)) + if (*buff_index > (RX_BUF_SIZE - UART_BURST_SIZE)) break; burst_buf = (u32 *)&rx_buff[*buff_index]; *burst_buf = readl(port->membase + UART_RX_BURST_FIFO); diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c index 3ec725555bcc..4749331fe618 100644 --- a/drivers/tty/serial/mxs-auart.c +++ b/drivers/tty/serial/mxs-auart.c @@ -605,13 +605,16 @@ static void mxs_auart_tx_chars(struct mxs_auart_port *s) return; } - pending = uart_port_tx(&s->port, ch, + pending = uart_port_tx_flags(&s->port, ch, UART_TX_NOSTOP, !(mxs_read(s, REG_STAT) & AUART_STAT_TXFF), mxs_write(ch, s, REG_DATA)); if (pending) mxs_set(AUART_INTR_TXIEN, s, REG_INTR); else mxs_clr(AUART_INTR_TXIEN, s, REG_INTR); + + if (uart_tx_stopped(&s->port)) + mxs_auart_stop_tx(&s->port); } static void mxs_auart_rx_char(struct mxs_auart_port *s) diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index e3eea965e57b..e120611a5174 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -376,7 +376,6 @@ /* Global HWPARAMS4 Register */ #define DWC3_GHWPARAMS4_HIBER_SCRATCHBUFS(n) (((n) & (0x0f << 13)) >> 13) #define DWC3_MAX_HIBER_SCRATCHBUFS 15 -#define DWC3_EXT_BUFF_CONTROL BIT(21) /* Global HWPARAMS6 Register */ #define DWC3_GHWPARAMS6_BCSUPPORT BIT(14) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 564976b3e2b9..4c8dd6724678 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -673,12 +673,6 @@ static int dwc3_gadget_set_ep_config(struct dwc3_ep *dep, unsigned int action) params.param1 |= DWC3_DEPCFG_BINTERVAL_M1(bInterval_m1); } - if (dep->endpoint.fifo_mode) { - if (!(dwc->hwparams.hwparams4 & DWC3_EXT_BUFF_CONTROL)) - return -EINVAL; - params.param1 |= DWC3_DEPCFG_EBC_HWO_NOWB | DWC3_DEPCFG_USE_EBC; - } - return dwc3_send_gadget_ep_cmd(dep, DWC3_DEPCMD_SETEPCONFIG, ¶ms); } diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h index fd7a4e94397e..55a56cf67d73 100644 --- a/drivers/usb/dwc3/gadget.h +++ b/drivers/usb/dwc3/gadget.h @@ -26,8 +26,6 @@ struct dwc3; #define DWC3_DEPCFG_XFER_NOT_READY_EN BIT(10) #define DWC3_DEPCFG_FIFO_ERROR_EN BIT(11) #define DWC3_DEPCFG_STREAM_EVENT_EN BIT(13) -#define DWC3_DEPCFG_EBC_HWO_NOWB BIT(14) -#define DWC3_DEPCFG_USE_EBC BIT(15) #define DWC3_DEPCFG_BINTERVAL_M1(n) (((n) & 0xff) << 16) #define DWC3_DEPCFG_STREAM_CAPABLE BIT(24) #define DWC3_DEPCFG_EP_NUMBER(n) (((n) & 0x1f) << 25) diff --git a/drivers/xen/events/events_base.c b/drivers/xen/events/events_base.c index b8cfea7812d6..3b9f080109d7 100644 --- a/drivers/xen/events/events_base.c +++ b/drivers/xen/events/events_base.c @@ -923,8 +923,8 @@ static void shutdown_pirq(struct irq_data *data) return; do_mask(info, EVT_MASK_REASON_EXPLICIT); - xen_evtchn_close(evtchn); xen_irq_info_cleanup(info); + xen_evtchn_close(evtchn); } static void enable_pirq(struct irq_data *data) @@ -956,6 +956,7 @@ EXPORT_SYMBOL_GPL(xen_irq_from_gsi); static void __unbind_from_irq(struct irq_info *info, unsigned int irq) { evtchn_port_t evtchn; + bool close_evtchn = false; if (!info) { xen_irq_free_desc(irq); @@ -975,7 +976,7 @@ static void __unbind_from_irq(struct irq_info *info, unsigned int irq) struct xenbus_device *dev; if (!info->is_static) - xen_evtchn_close(evtchn); + close_evtchn = true; switch (info->type) { case IRQT_VIRQ: @@ -995,6 +996,9 @@ static void __unbind_from_irq(struct irq_info *info, unsigned int irq) } xen_irq_info_cleanup(info); + + if (close_evtchn) + xen_evtchn_close(evtchn); } xen_free_irq(info); diff --git a/drivers/xen/gntalloc.c b/drivers/xen/gntalloc.c index 26ffb8755ffb..f93f73ecefee 100644 --- a/drivers/xen/gntalloc.c +++ b/drivers/xen/gntalloc.c @@ -317,7 +317,7 @@ static long gntalloc_ioctl_alloc(struct gntalloc_file_private_data *priv, rc = -EFAULT; goto out_free; } - if (copy_to_user(arg->gref_ids, gref_ids, + if (copy_to_user(arg->gref_ids_flex, gref_ids, sizeof(gref_ids[0]) * op.count)) { rc = -EFAULT; goto out_free; diff --git a/drivers/xen/pcpu.c b/drivers/xen/pcpu.c index 508655273145..c63f317e3df3 100644 --- a/drivers/xen/pcpu.c +++ b/drivers/xen/pcpu.c @@ -65,7 +65,7 @@ struct pcpu { uint32_t flags; }; -static struct bus_type xen_pcpu_subsys = { +static const struct bus_type xen_pcpu_subsys = { .name = "xen_cpu", .dev_name = "xen_cpu", }; diff --git a/drivers/xen/privcmd.c b/drivers/xen/privcmd.c index 35b6e306026a..67dfa4778864 100644 --- a/drivers/xen/privcmd.c +++ b/drivers/xen/privcmd.c @@ -1223,18 +1223,13 @@ struct privcmd_kernel_ioreq *alloc_ioreq(struct privcmd_ioeventfd *ioeventfd) kioreq->ioreq = (struct ioreq *)(page_to_virt(pages[0])); mmap_write_unlock(mm); - size = sizeof(*ports) * kioreq->vcpus; - ports = kzalloc(size, GFP_KERNEL); - if (!ports) { - ret = -ENOMEM; + ports = memdup_array_user(u64_to_user_ptr(ioeventfd->ports), + kioreq->vcpus, sizeof(*ports)); + if (IS_ERR(ports)) { + ret = PTR_ERR(ports); goto error_kfree; } - if (copy_from_user(ports, u64_to_user_ptr(ioeventfd->ports), size)) { - ret = -EFAULT; - goto error_kfree_ports; - } - for (i = 0; i < kioreq->vcpus; i++) { kioreq->ports[i].vcpu = i; kioreq->ports[i].port = ports[i]; @@ -1256,7 +1251,7 @@ struct privcmd_kernel_ioreq *alloc_ioreq(struct privcmd_ioeventfd *ioeventfd) error_unbind: while (--i >= 0) unbind_from_irqhandler(irq_from_evtchn(ports[i]), &kioreq->ports[i]); -error_kfree_ports: + kfree(ports); error_kfree: kfree(kioreq); diff --git a/drivers/xen/xen-balloon.c b/drivers/xen/xen-balloon.c index 8cd583db20b1..b293d7652f15 100644 --- a/drivers/xen/xen-balloon.c +++ b/drivers/xen/xen-balloon.c @@ -237,7 +237,7 @@ static const struct attribute_group *balloon_groups[] = { NULL }; -static struct bus_type balloon_subsys = { +static const struct bus_type balloon_subsys = { .name = BALLOON_CLASS_NAME, .dev_name = BALLOON_CLASS_NAME, }; diff --git a/drivers/xen/xenbus/xenbus_client.c b/drivers/xen/xenbus/xenbus_client.c index 32835b4b9bc5..51b3124b0d56 100644 --- a/drivers/xen/xenbus/xenbus_client.c +++ b/drivers/xen/xenbus/xenbus_client.c @@ -116,14 +116,15 @@ EXPORT_SYMBOL_GPL(xenbus_strstate); * @dev: xenbus device * @path: path to watch * @watch: watch to register + * @will_handle: events queuing determine callback * @callback: callback to register * * Register a @watch on the given path, using the given xenbus_watch structure - * for storage, and the given @callback function as the callback. On success, - * the given @path will be saved as @watch->node, and remains the - * caller's to free. On error, @watch->node will - * be NULL, the device will switch to %XenbusStateClosing, and the error will - * be saved in the store. + * for storage, @will_handle function as the callback to determine if each + * event need to be queued, and the given @callback function as the callback. + * On success, the given @path will be saved as @watch->node, and remains the + * caller's to free. On error, @watch->node will be NULL, the device will + * switch to %XenbusStateClosing, and the error will be saved in the store. * * Returns: %0 on success or -errno on error */ @@ -158,11 +159,13 @@ EXPORT_SYMBOL_GPL(xenbus_watch_path); * xenbus_watch_pathfmt - register a watch on a sprintf-formatted path * @dev: xenbus device * @watch: watch to register + * @will_handle: events queuing determine callback * @callback: callback to register * @pathfmt: format of path to watch * * Register a watch on the given @path, using the given xenbus_watch - * structure for storage, and the given @callback function as the + * structure for storage, @will_handle function as the callback to determine if + * each event need to be queued, and the given @callback function as the * callback. On success, the watched path (@path/@path2) will be saved * as @watch->node, and becomes the caller's to kfree(). * On error, watch->node will be NULL, so the caller has nothing to diff --git a/fs/bcachefs/bcachefs.h b/fs/bcachefs/bcachefs.h index b80c6c9efd8c..69d0d60d50e3 100644 --- a/fs/bcachefs/bcachefs.h +++ b/fs/bcachefs/bcachefs.h @@ -1249,6 +1249,18 @@ static inline struct stdio_redirect *bch2_fs_stdio_redirect(struct bch_fs *c) return stdio; } +static inline unsigned metadata_replicas_required(struct bch_fs *c) +{ + return min(c->opts.metadata_replicas, + c->opts.metadata_replicas_required); +} + +static inline unsigned data_replicas_required(struct bch_fs *c) +{ + return min(c->opts.data_replicas, + c->opts.data_replicas_required); +} + #define BKEY_PADDED_ONSTACK(key, pad) \ struct { struct bkey_i key; __u64 key ## _pad[pad]; } diff --git a/fs/bcachefs/btree_update_interior.c b/fs/bcachefs/btree_update_interior.c index 17a5938aa71a..4530b14ff2c3 100644 --- a/fs/bcachefs/btree_update_interior.c +++ b/fs/bcachefs/btree_update_interior.c @@ -280,7 +280,8 @@ retry: writepoint_ptr(&c->btree_write_point), &devs_have, res->nr_replicas, - c->opts.metadata_replicas_required, + min(res->nr_replicas, + c->opts.metadata_replicas_required), watermark, 0, cl, &wp); if (unlikely(ret)) return ERR_PTR(ret); diff --git a/fs/bcachefs/fs.c b/fs/bcachefs/fs.c index ec419b8e2c43..77ae65542db9 100644 --- a/fs/bcachefs/fs.c +++ b/fs/bcachefs/fs.c @@ -435,7 +435,7 @@ static int bch2_link(struct dentry *old_dentry, struct inode *vdir, bch2_subvol_is_ro(c, inode->ei_subvol) ?: __bch2_link(c, inode, dir, dentry); if (unlikely(ret)) - return ret; + return bch2_err_class(ret); ihold(&inode->v); d_instantiate(dentry, &inode->v); @@ -487,8 +487,9 @@ static int bch2_unlink(struct inode *vdir, struct dentry *dentry) struct bch_inode_info *dir= to_bch_ei(vdir); struct bch_fs *c = dir->v.i_sb->s_fs_info; - return bch2_subvol_is_ro(c, dir->ei_subvol) ?: + int ret = bch2_subvol_is_ro(c, dir->ei_subvol) ?: __bch2_unlink(vdir, dentry, false); + return bch2_err_class(ret); } static int bch2_symlink(struct mnt_idmap *idmap, @@ -523,7 +524,7 @@ static int bch2_symlink(struct mnt_idmap *idmap, return 0; err: iput(&inode->v); - return ret; + return bch2_err_class(ret); } static int bch2_mkdir(struct mnt_idmap *idmap, @@ -641,7 +642,7 @@ err: src_inode, dst_inode); - return ret; + return bch2_err_class(ret); } static void bch2_setattr_copy(struct mnt_idmap *idmap, diff --git a/fs/bcachefs/io_write.c b/fs/bcachefs/io_write.c index ef3a53f9045a..2c098ac017b3 100644 --- a/fs/bcachefs/io_write.c +++ b/fs/bcachefs/io_write.c @@ -1564,6 +1564,7 @@ CLOSURE_CALLBACK(bch2_write) BUG_ON(!op->write_point.v); BUG_ON(bkey_eq(op->pos, POS_MAX)); + op->nr_replicas_required = min_t(unsigned, op->nr_replicas_required, op->nr_replicas); op->start_time = local_clock(); bch2_keylist_init(&op->insert_keys, op->inline_keys); wbio_init(bio)->put_bio = false; diff --git a/fs/bcachefs/journal_io.c b/fs/bcachefs/journal_io.c index bfd6585e746d..47805193f18c 100644 --- a/fs/bcachefs/journal_io.c +++ b/fs/bcachefs/journal_io.c @@ -1478,6 +1478,8 @@ static int journal_write_alloc(struct journal *j, struct journal_buf *w) c->opts.foreground_target; unsigned i, replicas = 0, replicas_want = READ_ONCE(c->opts.metadata_replicas); + unsigned replicas_need = min_t(unsigned, replicas_want, + READ_ONCE(c->opts.metadata_replicas_required)); rcu_read_lock(); retry: @@ -1526,7 +1528,7 @@ done: BUG_ON(bkey_val_u64s(&w->key.k) > BCH_REPLICAS_MAX); - return replicas >= c->opts.metadata_replicas_required ? 0 : -EROFS; + return replicas >= replicas_need ? 0 : -EROFS; } static void journal_buf_realloc(struct journal *j, struct journal_buf *buf) diff --git a/fs/bcachefs/journal_reclaim.c b/fs/bcachefs/journal_reclaim.c index 820d25e19e5f..2cf626315652 100644 --- a/fs/bcachefs/journal_reclaim.c +++ b/fs/bcachefs/journal_reclaim.c @@ -205,7 +205,7 @@ void bch2_journal_space_available(struct journal *j) j->can_discard = can_discard; - if (nr_online < c->opts.metadata_replicas_required) { + if (nr_online < metadata_replicas_required(c)) { ret = JOURNAL_ERR_insufficient_devices; goto out; } diff --git a/fs/bcachefs/printbuf.c b/fs/bcachefs/printbuf.c index accf246c3233..b27d22925929 100644 --- a/fs/bcachefs/printbuf.c +++ b/fs/bcachefs/printbuf.c @@ -56,6 +56,7 @@ void bch2_prt_vprintf(struct printbuf *out, const char *fmt, va_list args) va_copy(args2, args); len = vsnprintf(out->buf + out->pos, printbuf_remaining(out), fmt, args2); + va_end(args2); } while (len + 1 >= printbuf_remaining(out) && !bch2_printbuf_make_room(out, len + 1)); diff --git a/fs/bcachefs/recovery.c b/fs/bcachefs/recovery.c index 9127d0e3ca2f..21e13bb4335b 100644 --- a/fs/bcachefs/recovery.c +++ b/fs/bcachefs/recovery.c @@ -577,8 +577,9 @@ u64 bch2_recovery_passes_from_stable(u64 v) static bool check_version_upgrade(struct bch_fs *c) { - unsigned latest_compatible = bch2_latest_compatible_version(c->sb.version); unsigned latest_version = bcachefs_metadata_version_current; + unsigned latest_compatible = min(latest_version, + bch2_latest_compatible_version(c->sb.version)); unsigned old_version = c->sb.version_upgrade_complete ?: c->sb.version; unsigned new_version = 0; @@ -597,7 +598,7 @@ static bool check_version_upgrade(struct bch_fs *c) new_version = latest_version; break; case BCH_VERSION_UPGRADE_none: - new_version = old_version; + new_version = min(old_version, latest_version); break; } } @@ -774,7 +775,7 @@ int bch2_fs_recovery(struct bch_fs *c) goto err; } - if (!(c->opts.nochanges && c->opts.norecovery)) { + if (!c->opts.nochanges) { mutex_lock(&c->sb_lock); bool write_sb = false; @@ -804,7 +805,7 @@ int bch2_fs_recovery(struct bch_fs *c) if (bch2_check_version_downgrade(c)) { struct printbuf buf = PRINTBUF; - prt_str(&buf, "Version downgrade required:\n"); + prt_str(&buf, "Version downgrade required:"); __le64 passes = ext->recovery_passes_required[0]; bch2_sb_set_downgrade(c, @@ -812,7 +813,7 @@ int bch2_fs_recovery(struct bch_fs *c) BCH_VERSION_MINOR(c->sb.version)); passes = ext->recovery_passes_required[0] & ~passes; if (passes) { - prt_str(&buf, " running recovery passes: "); + prt_str(&buf, "\n running recovery passes: "); prt_bitflags(&buf, bch2_recovery_passes, bch2_recovery_passes_from_stable(le64_to_cpu(passes))); } diff --git a/fs/bcachefs/sb-members.c b/fs/bcachefs/sb-members.c index a45354d2acde..eff5ce18c69c 100644 --- a/fs/bcachefs/sb-members.c +++ b/fs/bcachefs/sb-members.c @@ -421,7 +421,7 @@ void bch2_dev_errors_reset(struct bch_dev *ca) m = bch2_members_v2_get_mut(c->disk_sb.sb, ca->dev_idx); for (unsigned i = 0; i < ARRAY_SIZE(m->errors_at_reset); i++) m->errors_at_reset[i] = cpu_to_le64(atomic64_read(&ca->errors[i])); - m->errors_reset_time = ktime_get_real_seconds(); + m->errors_reset_time = cpu_to_le64(ktime_get_real_seconds()); bch2_write_super(c); mutex_unlock(&c->sb_lock); diff --git a/fs/bcachefs/super-io.c b/fs/bcachefs/super-io.c index d60c7d27a047..36988add581f 100644 --- a/fs/bcachefs/super-io.c +++ b/fs/bcachefs/super-io.c @@ -717,7 +717,7 @@ retry: if (IS_ERR(sb->bdev_handle)) { ret = PTR_ERR(sb->bdev_handle); - goto out; + goto err; } sb->bdev = sb->bdev_handle->bdev; diff --git a/fs/bcachefs/super.c b/fs/bcachefs/super.c index b9911402b175..6b23e11825e6 100644 --- a/fs/bcachefs/super.c +++ b/fs/bcachefs/super.c @@ -1428,10 +1428,10 @@ bool bch2_dev_state_allowed(struct bch_fs *c, struct bch_dev *ca, required = max(!(flags & BCH_FORCE_IF_METADATA_DEGRADED) ? c->opts.metadata_replicas - : c->opts.metadata_replicas_required, + : metadata_replicas_required(c), !(flags & BCH_FORCE_IF_DATA_DEGRADED) ? c->opts.data_replicas - : c->opts.data_replicas_required); + : data_replicas_required(c)); return nr_rw >= required; case BCH_MEMBER_STATE_failed: diff --git a/fs/btrfs/block-group.c b/fs/btrfs/block-group.c index a9be9ac99222..378d9103a207 100644 --- a/fs/btrfs/block-group.c +++ b/fs/btrfs/block-group.c @@ -1455,6 +1455,7 @@ out: */ void btrfs_delete_unused_bgs(struct btrfs_fs_info *fs_info) { + LIST_HEAD(retry_list); struct btrfs_block_group *block_group; struct btrfs_space_info *space_info; struct btrfs_trans_handle *trans; @@ -1476,6 +1477,7 @@ void btrfs_delete_unused_bgs(struct btrfs_fs_info *fs_info) spin_lock(&fs_info->unused_bgs_lock); while (!list_empty(&fs_info->unused_bgs)) { + u64 used; int trimming; block_group = list_first_entry(&fs_info->unused_bgs, @@ -1511,9 +1513,9 @@ void btrfs_delete_unused_bgs(struct btrfs_fs_info *fs_info) goto next; } + spin_lock(&space_info->lock); spin_lock(&block_group->lock); - if (block_group->reserved || block_group->pinned || - block_group->used || block_group->ro || + if (btrfs_is_block_group_used(block_group) || block_group->ro || list_is_singular(&block_group->list)) { /* * We want to bail if we made new allocations or have @@ -1523,10 +1525,49 @@ void btrfs_delete_unused_bgs(struct btrfs_fs_info *fs_info) */ trace_btrfs_skip_unused_block_group(block_group); spin_unlock(&block_group->lock); + spin_unlock(&space_info->lock); up_write(&space_info->groups_sem); goto next; } + + /* + * The block group may be unused but there may be space reserved + * accounting with the existence of that block group, that is, + * space_info->bytes_may_use was incremented by a task but no + * space was yet allocated from the block group by the task. + * That space may or may not be allocated, as we are generally + * pessimistic about space reservation for metadata as well as + * for data when using compression (as we reserve space based on + * the worst case, when data can't be compressed, and before + * actually attempting compression, before starting writeback). + * + * So check if the total space of the space_info minus the size + * of this block group is less than the used space of the + * space_info - if that's the case, then it means we have tasks + * that might be relying on the block group in order to allocate + * extents, and add back the block group to the unused list when + * we finish, so that we retry later in case no tasks ended up + * needing to allocate extents from the block group. + */ + used = btrfs_space_info_used(space_info, true); + if (space_info->total_bytes - block_group->length < used) { + /* + * Add a reference for the list, compensate for the ref + * drop under the "next" label for the + * fs_info->unused_bgs list. + */ + btrfs_get_block_group(block_group); + list_add_tail(&block_group->bg_list, &retry_list); + + trace_btrfs_skip_unused_block_group(block_group); + spin_unlock(&block_group->lock); + spin_unlock(&space_info->lock); + up_write(&space_info->groups_sem); + goto next; + } + spin_unlock(&block_group->lock); + spin_unlock(&space_info->lock); /* We don't want to force the issue, only flip if it's ok. */ ret = inc_block_group_ro(block_group, 0); @@ -1650,12 +1691,16 @@ next: btrfs_put_block_group(block_group); spin_lock(&fs_info->unused_bgs_lock); } + list_splice_tail(&retry_list, &fs_info->unused_bgs); spin_unlock(&fs_info->unused_bgs_lock); mutex_unlock(&fs_info->reclaim_bgs_lock); return; flip_async: btrfs_end_transaction(trans); + spin_lock(&fs_info->unused_bgs_lock); + list_splice_tail(&retry_list, &fs_info->unused_bgs); + spin_unlock(&fs_info->unused_bgs_lock); mutex_unlock(&fs_info->reclaim_bgs_lock); btrfs_put_block_group(block_group); btrfs_discard_punt_unused_bgs_list(fs_info); @@ -2684,6 +2729,37 @@ next: btrfs_dec_delayed_refs_rsv_bg_inserts(fs_info); list_del_init(&block_group->bg_list); clear_bit(BLOCK_GROUP_FLAG_NEW, &block_group->runtime_flags); + + /* + * If the block group is still unused, add it to the list of + * unused block groups. The block group may have been created in + * order to satisfy a space reservation, in which case the + * extent allocation only happens later. But often we don't + * actually need to allocate space that we previously reserved, + * so the block group may become unused for a long time. For + * example for metadata we generally reserve space for a worst + * possible scenario, but then don't end up allocating all that + * space or none at all (due to no need to COW, extent buffers + * were already COWed in the current transaction and still + * unwritten, tree heights lower than the maximum possible + * height, etc). For data we generally reserve the axact amount + * of space we are going to allocate later, the exception is + * when using compression, as we must reserve space based on the + * uncompressed data size, because the compression is only done + * when writeback triggered and we don't know how much space we + * are actually going to need, so we reserve the uncompressed + * size because the data may be uncompressible in the worst case. + */ + if (ret == 0) { + bool used; + + spin_lock(&block_group->lock); + used = btrfs_is_block_group_used(block_group); + spin_unlock(&block_group->lock); + + if (!used) + btrfs_mark_bg_unused(block_group); + } } btrfs_trans_release_chunk_metadata(trans); } diff --git a/fs/btrfs/block-group.h b/fs/btrfs/block-group.h index c4a1f01cc1c2..962b11983901 100644 --- a/fs/btrfs/block-group.h +++ b/fs/btrfs/block-group.h @@ -257,6 +257,13 @@ static inline u64 btrfs_block_group_end(struct btrfs_block_group *block_group) return (block_group->start + block_group->length); } +static inline bool btrfs_is_block_group_used(const struct btrfs_block_group *bg) +{ + lockdep_assert_held(&bg->lock); + + return (bg->used > 0 || bg->reserved > 0 || bg->pinned > 0); +} + static inline bool btrfs_is_block_group_data_only( struct btrfs_block_group *block_group) { diff --git a/fs/btrfs/delalloc-space.c b/fs/btrfs/delalloc-space.c index 2833e8ef4c09..acf9f4b6c044 100644 --- a/fs/btrfs/delalloc-space.c +++ b/fs/btrfs/delalloc-space.c @@ -245,7 +245,6 @@ static void btrfs_calculate_inode_block_rsv_size(struct btrfs_fs_info *fs_info, struct btrfs_block_rsv *block_rsv = &inode->block_rsv; u64 reserve_size = 0; u64 qgroup_rsv_size = 0; - u64 csum_leaves; unsigned outstanding_extents; lockdep_assert_held(&inode->lock); @@ -260,10 +259,12 @@ static void btrfs_calculate_inode_block_rsv_size(struct btrfs_fs_info *fs_info, outstanding_extents); reserve_size += btrfs_calc_metadata_size(fs_info, 1); } - csum_leaves = btrfs_csum_bytes_to_leaves(fs_info, - inode->csum_bytes); - reserve_size += btrfs_calc_insert_metadata_size(fs_info, - csum_leaves); + if (!(inode->flags & BTRFS_INODE_NODATASUM)) { + u64 csum_leaves; + + csum_leaves = btrfs_csum_bytes_to_leaves(fs_info, inode->csum_bytes); + reserve_size += btrfs_calc_insert_metadata_size(fs_info, csum_leaves); + } /* * For qgroup rsv, the calculation is very simple: * account one nodesize for each outstanding extent @@ -278,14 +279,20 @@ static void btrfs_calculate_inode_block_rsv_size(struct btrfs_fs_info *fs_info, spin_unlock(&block_rsv->lock); } -static void calc_inode_reservations(struct btrfs_fs_info *fs_info, +static void calc_inode_reservations(struct btrfs_inode *inode, u64 num_bytes, u64 disk_num_bytes, u64 *meta_reserve, u64 *qgroup_reserve) { + struct btrfs_fs_info *fs_info = inode->root->fs_info; u64 nr_extents = count_max_extents(fs_info, num_bytes); - u64 csum_leaves = btrfs_csum_bytes_to_leaves(fs_info, disk_num_bytes); + u64 csum_leaves; u64 inode_update = btrfs_calc_metadata_size(fs_info, 1); + if (inode->flags & BTRFS_INODE_NODATASUM) + csum_leaves = 0; + else + csum_leaves = btrfs_csum_bytes_to_leaves(fs_info, disk_num_bytes); + *meta_reserve = btrfs_calc_insert_metadata_size(fs_info, nr_extents + csum_leaves); @@ -337,7 +344,7 @@ int btrfs_delalloc_reserve_metadata(struct btrfs_inode *inode, u64 num_bytes, * everything out and try again, which is bad. This way we just * over-reserve slightly, and clean up the mess when we are done. */ - calc_inode_reservations(fs_info, num_bytes, disk_num_bytes, + calc_inode_reservations(inode, num_bytes, disk_num_bytes, &meta_reserve, &qgroup_reserve); ret = btrfs_qgroup_reserve_meta_prealloc(root, qgroup_reserve, true, noflush); @@ -359,7 +366,8 @@ int btrfs_delalloc_reserve_metadata(struct btrfs_inode *inode, u64 num_bytes, nr_extents = count_max_extents(fs_info, num_bytes); spin_lock(&inode->lock); btrfs_mod_outstanding_extents(inode, nr_extents); - inode->csum_bytes += disk_num_bytes; + if (!(inode->flags & BTRFS_INODE_NODATASUM)) + inode->csum_bytes += disk_num_bytes; btrfs_calculate_inode_block_rsv_size(fs_info, inode); spin_unlock(&inode->lock); @@ -393,7 +401,8 @@ void btrfs_delalloc_release_metadata(struct btrfs_inode *inode, u64 num_bytes, num_bytes = ALIGN(num_bytes, fs_info->sectorsize); spin_lock(&inode->lock); - inode->csum_bytes -= num_bytes; + if (!(inode->flags & BTRFS_INODE_NODATASUM)) + inode->csum_bytes -= num_bytes; btrfs_calculate_inode_block_rsv_size(fs_info, inode); spin_unlock(&inode->lock); diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 1eb93d3962aa..f88e0ca8331d 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -3184,8 +3184,23 @@ out: unwritten_start += logical_len; clear_extent_uptodate(io_tree, unwritten_start, end, NULL); - /* Drop extent maps for the part of the extent we didn't write. */ - btrfs_drop_extent_map_range(inode, unwritten_start, end, false); + /* + * Drop extent maps for the part of the extent we didn't write. + * + * We have an exception here for the free_space_inode, this is + * because when we do btrfs_get_extent() on the free space inode + * we will search the commit root. If this is a new block group + * we won't find anything, and we will trip over the assert in + * writepage where we do ASSERT(em->block_start != + * EXTENT_MAP_HOLE). + * + * Theoretically we could also skip this for any NOCOW extent as + * we don't mess with the extent map tree in the NOCOW case, but + * for now simply skip this if we are the free space inode. + */ + if (!btrfs_is_free_space_inode(inode)) + btrfs_drop_extent_map_range(inode, unwritten_start, + end, false); /* * If the ordered extent had an IOERR or something else went @@ -10273,6 +10288,13 @@ ssize_t btrfs_do_encoded_write(struct kiocb *iocb, struct iov_iter *from, if (encoded->encryption != BTRFS_ENCODED_IO_ENCRYPTION_NONE) return -EINVAL; + /* + * Compressed extents should always have checksums, so error out if we + * have a NOCOW file or inode was created while mounted with NODATASUM. + */ + if (inode->flags & BTRFS_INODE_NODATASUM) + return -EINVAL; + orig_count = iov_iter_count(from); /* The extent size must be sane. */ diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 5b3333ceef04..c52807d97efa 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c @@ -564,56 +564,22 @@ static int btrfs_reserve_trans_metadata(struct btrfs_fs_info *fs_info, u64 num_bytes, u64 *delayed_refs_bytes) { - struct btrfs_block_rsv *delayed_refs_rsv = &fs_info->delayed_refs_rsv; struct btrfs_space_info *si = fs_info->trans_block_rsv.space_info; - u64 extra_delayed_refs_bytes = 0; - u64 bytes; + u64 bytes = num_bytes + *delayed_refs_bytes; int ret; /* - * If there's a gap between the size of the delayed refs reserve and - * its reserved space, than some tasks have added delayed refs or bumped - * its size otherwise (due to block group creation or removal, or block - * group item update). Also try to allocate that gap in order to prevent - * using (and possibly abusing) the global reserve when committing the - * transaction. - */ - if (flush == BTRFS_RESERVE_FLUSH_ALL && - !btrfs_block_rsv_full(delayed_refs_rsv)) { - spin_lock(&delayed_refs_rsv->lock); - if (delayed_refs_rsv->size > delayed_refs_rsv->reserved) - extra_delayed_refs_bytes = delayed_refs_rsv->size - - delayed_refs_rsv->reserved; - spin_unlock(&delayed_refs_rsv->lock); - } - - bytes = num_bytes + *delayed_refs_bytes + extra_delayed_refs_bytes; - - /* * We want to reserve all the bytes we may need all at once, so we only * do 1 enospc flushing cycle per transaction start. */ ret = btrfs_reserve_metadata_bytes(fs_info, si, bytes, flush); - if (ret == 0) { - if (extra_delayed_refs_bytes > 0) - btrfs_migrate_to_delayed_refs_rsv(fs_info, - extra_delayed_refs_bytes); - return 0; - } - - if (extra_delayed_refs_bytes > 0) { - bytes -= extra_delayed_refs_bytes; - ret = btrfs_reserve_metadata_bytes(fs_info, si, bytes, flush); - if (ret == 0) - return 0; - } /* * If we are an emergency flush, which can steal from the global block * reserve, then attempt to not reserve space for the delayed refs, as * we will consume space for them from the global block reserve. */ - if (flush == BTRFS_RESERVE_FLUSH_ALL_STEAL) { + if (ret && flush == BTRFS_RESERVE_FLUSH_ALL_STEAL) { bytes -= *delayed_refs_bytes; *delayed_refs_bytes = 0; ret = btrfs_reserve_metadata_bytes(fs_info, si, bytes, flush); diff --git a/fs/btrfs/zoned.c b/fs/btrfs/zoned.c index 168af9d000d1..3a5d69ff25fc 100644 --- a/fs/btrfs/zoned.c +++ b/fs/btrfs/zoned.c @@ -1670,6 +1670,7 @@ out: } bitmap_free(active); kfree(zone_info); + btrfs_free_chunk_map(map); return ret; } diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index ad1f46c66fbf..7fb4aae97412 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c @@ -2156,6 +2156,30 @@ retry: ceph_cap_string(cap->implemented), ceph_cap_string(revoking)); + /* completed revocation? going down and there are no caps? */ + if (revoking) { + if ((revoking & cap_used) == 0) { + doutc(cl, "completed revocation of %s\n", + ceph_cap_string(cap->implemented & ~cap->issued)); + goto ack; + } + + /* + * If the "i_wrbuffer_ref" was increased by mmap or generic + * cache write just before the ceph_check_caps() is called, + * the Fb capability revoking will fail this time. Then we + * must wait for the BDI's delayed work to flush the dirty + * pages and to release the "i_wrbuffer_ref", which will cost + * at most 5 seconds. That means the MDS needs to wait at + * most 5 seconds to finished the Fb capability's revocation. + * + * Let's queue a writeback for it. + */ + if (S_ISREG(inode->i_mode) && ci->i_wrbuffer_ref && + (revoking & CEPH_CAP_FILE_BUFFER)) + queue_writeback = true; + } + if (cap == ci->i_auth_cap && (cap->issued & CEPH_CAP_FILE_WR)) { /* request larger max_size from MDS? */ @@ -2183,30 +2207,6 @@ retry: } } - /* completed revocation? going down and there are no caps? */ - if (revoking) { - if ((revoking & cap_used) == 0) { - doutc(cl, "completed revocation of %s\n", - ceph_cap_string(cap->implemented & ~cap->issued)); - goto ack; - } - - /* - * If the "i_wrbuffer_ref" was increased by mmap or generic - * cache write just before the ceph_check_caps() is called, - * the Fb capability revoking will fail this time. Then we - * must wait for the BDI's delayed work to flush the dirty - * pages and to release the "i_wrbuffer_ref", which will cost - * at most 5 seconds. That means the MDS needs to wait at - * most 5 seconds to finished the Fb capability's revocation. - * - * Let's queue a writeback for it. - */ - if (S_ISREG(inode->i_mode) && ci->i_wrbuffer_ref && - (revoking & CEPH_CAP_FILE_BUFFER)) - queue_writeback = true; - } - /* want more caps from mds? */ if (want & ~cap->mds_wanted) { if (want & ~(cap->mds_wanted | cap->issued)) @@ -4772,7 +4772,22 @@ int ceph_drop_caps_for_unlink(struct inode *inode) if (__ceph_caps_dirty(ci)) { struct ceph_mds_client *mdsc = ceph_inode_to_fs_client(inode)->mdsc; - __cap_delay_requeue_front(mdsc, ci); + + doutc(mdsc->fsc->client, "%p %llx.%llx\n", inode, + ceph_vinop(inode)); + spin_lock(&mdsc->cap_unlink_delay_lock); + ci->i_ceph_flags |= CEPH_I_FLUSH; + if (!list_empty(&ci->i_cap_delay_list)) + list_del_init(&ci->i_cap_delay_list); + list_add_tail(&ci->i_cap_delay_list, + &mdsc->cap_unlink_delay_list); + spin_unlock(&mdsc->cap_unlink_delay_lock); + + /* + * Fire the work immediately, because the MDS maybe + * waiting for caps release. + */ + ceph_queue_cap_unlink_work(mdsc); } } spin_unlock(&ci->i_ceph_lock); diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index f71bb9c9569f..3ab9c268a8bb 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -2484,6 +2484,50 @@ void ceph_reclaim_caps_nr(struct ceph_mds_client *mdsc, int nr) } } +void ceph_queue_cap_unlink_work(struct ceph_mds_client *mdsc) +{ + struct ceph_client *cl = mdsc->fsc->client; + if (mdsc->stopping) + return; + + if (queue_work(mdsc->fsc->cap_wq, &mdsc->cap_unlink_work)) { + doutc(cl, "caps unlink work queued\n"); + } else { + doutc(cl, "failed to queue caps unlink work\n"); + } +} + +static void ceph_cap_unlink_work(struct work_struct *work) +{ + struct ceph_mds_client *mdsc = + container_of(work, struct ceph_mds_client, cap_unlink_work); + struct ceph_client *cl = mdsc->fsc->client; + + doutc(cl, "begin\n"); + spin_lock(&mdsc->cap_unlink_delay_lock); + while (!list_empty(&mdsc->cap_unlink_delay_list)) { + struct ceph_inode_info *ci; + struct inode *inode; + + ci = list_first_entry(&mdsc->cap_unlink_delay_list, + struct ceph_inode_info, + i_cap_delay_list); + list_del_init(&ci->i_cap_delay_list); + + inode = igrab(&ci->netfs.inode); + if (inode) { + spin_unlock(&mdsc->cap_unlink_delay_lock); + doutc(cl, "on %p %llx.%llx\n", inode, + ceph_vinop(inode)); + ceph_check_caps(ci, CHECK_CAPS_FLUSH); + iput(inode); + spin_lock(&mdsc->cap_unlink_delay_lock); + } + } + spin_unlock(&mdsc->cap_unlink_delay_lock); + doutc(cl, "done\n"); +} + /* * requests */ @@ -5359,6 +5403,8 @@ int ceph_mdsc_init(struct ceph_fs_client *fsc) INIT_LIST_HEAD(&mdsc->cap_delay_list); INIT_LIST_HEAD(&mdsc->cap_wait_list); spin_lock_init(&mdsc->cap_delay_lock); + INIT_LIST_HEAD(&mdsc->cap_unlink_delay_list); + spin_lock_init(&mdsc->cap_unlink_delay_lock); INIT_LIST_HEAD(&mdsc->snap_flush_list); spin_lock_init(&mdsc->snap_flush_lock); mdsc->last_cap_flush_tid = 1; @@ -5367,6 +5413,7 @@ int ceph_mdsc_init(struct ceph_fs_client *fsc) spin_lock_init(&mdsc->cap_dirty_lock); init_waitqueue_head(&mdsc->cap_flushing_wq); INIT_WORK(&mdsc->cap_reclaim_work, ceph_cap_reclaim_work); + INIT_WORK(&mdsc->cap_unlink_work, ceph_cap_unlink_work); err = ceph_metric_init(&mdsc->metric); if (err) goto err_mdsmap; @@ -5640,6 +5687,7 @@ void ceph_mdsc_close_sessions(struct ceph_mds_client *mdsc) ceph_cleanup_global_and_empty_realms(mdsc); cancel_work_sync(&mdsc->cap_reclaim_work); + cancel_work_sync(&mdsc->cap_unlink_work); cancel_delayed_work_sync(&mdsc->delayed_work); /* cancel timer */ doutc(cl, "done\n"); diff --git a/fs/ceph/mds_client.h b/fs/ceph/mds_client.h index 40560af38827..03f8ff00874f 100644 --- a/fs/ceph/mds_client.h +++ b/fs/ceph/mds_client.h @@ -462,6 +462,8 @@ struct ceph_mds_client { unsigned long last_renew_caps; /* last time we renewed our caps */ struct list_head cap_delay_list; /* caps with delayed release */ spinlock_t cap_delay_lock; /* protects cap_delay_list */ + struct list_head cap_unlink_delay_list; /* caps with delayed release for unlink */ + spinlock_t cap_unlink_delay_lock; /* protects cap_unlink_delay_list */ struct list_head snap_flush_list; /* cap_snaps ready to flush */ spinlock_t snap_flush_lock; @@ -475,6 +477,8 @@ struct ceph_mds_client { struct work_struct cap_reclaim_work; atomic_t cap_reclaim_pending; + struct work_struct cap_unlink_work; + /* * Cap reservations * @@ -574,6 +578,7 @@ extern void ceph_flush_cap_releases(struct ceph_mds_client *mdsc, struct ceph_mds_session *session); extern void ceph_queue_cap_reclaim_work(struct ceph_mds_client *mdsc); extern void ceph_reclaim_caps_nr(struct ceph_mds_client *mdsc, int nr); +extern void ceph_queue_cap_unlink_work(struct ceph_mds_client *mdsc); extern int ceph_iterate_session_caps(struct ceph_mds_session *session, int (*cb)(struct inode *, int mds, void *), void *arg); diff --git a/fs/namespace.c b/fs/namespace.c index 437f60e96d40..5a51315c6678 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -4472,10 +4472,15 @@ static int do_mount_setattr(struct path *path, struct mount_kattr *kattr) /* * If this is an attached mount make sure it's located in the callers * mount namespace. If it's not don't let the caller interact with it. - * If this is a detached mount make sure it has an anonymous mount - * namespace attached to it, i.e. we've created it via OPEN_TREE_CLONE. + * + * If this mount doesn't have a parent it's most often simply a + * detached mount with an anonymous mount namespace. IOW, something + * that's simply not attached yet. But there are apparently also users + * that do change mount properties on the rootfs itself. That obviously + * neither has a parent nor is it a detached mount so we cannot + * unconditionally check for detached mounts. */ - if (!(mnt_has_parent(mnt) ? check_mnt(mnt) : is_anon_ns(mnt->mnt_ns))) + if ((mnt_has_parent(mnt) || !is_anon_ns(mnt->mnt_ns)) && !check_mnt(mnt)) goto out; /* diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c index b8e25ca51016..8586e2f5d243 100644 --- a/fs/overlayfs/copy_up.c +++ b/fs/overlayfs/copy_up.c @@ -265,20 +265,18 @@ static int ovl_copy_up_file(struct ovl_fs *ofs, struct dentry *dentry, if (IS_ERR(old_file)) return PTR_ERR(old_file); + /* Try to use clone_file_range to clone up within the same fs */ + cloned = vfs_clone_file_range(old_file, 0, new_file, 0, len, 0); + if (cloned == len) + goto out_fput; + + /* Couldn't clone, so now we try to copy the data */ error = rw_verify_area(READ, old_file, &old_pos, len); if (!error) error = rw_verify_area(WRITE, new_file, &new_pos, len); if (error) goto out_fput; - /* Try to use clone_file_range to clone up within the same fs */ - ovl_start_write(dentry); - cloned = do_clone_file_range(old_file, 0, new_file, 0, len, 0); - ovl_end_write(dentry); - if (cloned == len) - goto out_fput; - /* Couldn't clone, so now we try to copy the data */ - /* Check if lower fs supports seek operation */ if (old_file->f_mode & FMODE_LSEEK) skip_hole = true; diff --git a/fs/remap_range.c b/fs/remap_range.c index f8c1120b8311..de07f978ce3e 100644 --- a/fs/remap_range.c +++ b/fs/remap_range.c @@ -373,9 +373,9 @@ int generic_remap_file_range_prep(struct file *file_in, loff_t pos_in, } EXPORT_SYMBOL(generic_remap_file_range_prep); -loff_t do_clone_file_range(struct file *file_in, loff_t pos_in, - struct file *file_out, loff_t pos_out, - loff_t len, unsigned int remap_flags) +loff_t vfs_clone_file_range(struct file *file_in, loff_t pos_in, + struct file *file_out, loff_t pos_out, + loff_t len, unsigned int remap_flags) { loff_t ret; @@ -391,23 +391,6 @@ loff_t do_clone_file_range(struct file *file_in, loff_t pos_in, if (!file_in->f_op->remap_file_range) return -EOPNOTSUPP; - ret = file_in->f_op->remap_file_range(file_in, pos_in, - file_out, pos_out, len, remap_flags); - if (ret < 0) - return ret; - - fsnotify_access(file_in); - fsnotify_modify(file_out); - return ret; -} -EXPORT_SYMBOL(do_clone_file_range); - -loff_t vfs_clone_file_range(struct file *file_in, loff_t pos_in, - struct file *file_out, loff_t pos_out, - loff_t len, unsigned int remap_flags) -{ - loff_t ret; - ret = remap_verify_area(file_in, pos_in, len, false); if (ret) return ret; @@ -417,10 +400,14 @@ loff_t vfs_clone_file_range(struct file *file_in, loff_t pos_in, return ret; file_start_write(file_out); - ret = do_clone_file_range(file_in, pos_in, file_out, pos_out, len, - remap_flags); + ret = file_in->f_op->remap_file_range(file_in, pos_in, + file_out, pos_out, len, remap_flags); file_end_write(file_out); + if (ret < 0) + return ret; + fsnotify_access(file_in); + fsnotify_modify(file_out); return ret; } EXPORT_SYMBOL(vfs_clone_file_range); diff --git a/fs/smb/client/cached_dir.c b/fs/smb/client/cached_dir.c index 1daeb5714faa..3de5047a7ff9 100644 --- a/fs/smb/client/cached_dir.c +++ b/fs/smb/client/cached_dir.c @@ -242,6 +242,7 @@ replay_again: .desired_access = FILE_READ_DATA | FILE_READ_ATTRIBUTES, .disposition = FILE_OPEN, .fid = pfid, + .replay = !!(retries), }; rc = SMB2_open_init(tcon, server, diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h index c86a72c9d9ec..53c75cfb33ab 100644 --- a/fs/smb/client/cifsglob.h +++ b/fs/smb/client/cifsglob.h @@ -1378,6 +1378,7 @@ struct cifs_open_parms { struct cifs_fid *fid; umode_t mode; bool reconnect:1; + bool replay:1; /* indicates that this open is for a replay */ }; struct cifs_fid { diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c index d03253f8f145..ac9595504f4b 100644 --- a/fs/smb/client/connect.c +++ b/fs/smb/client/connect.c @@ -3444,8 +3444,18 @@ int cifs_mount_get_tcon(struct cifs_mount_ctx *mnt_ctx) * the user on mount */ if ((cifs_sb->ctx->wsize == 0) || - (cifs_sb->ctx->wsize > server->ops->negotiate_wsize(tcon, ctx))) - cifs_sb->ctx->wsize = server->ops->negotiate_wsize(tcon, ctx); + (cifs_sb->ctx->wsize > server->ops->negotiate_wsize(tcon, ctx))) { + cifs_sb->ctx->wsize = + round_down(server->ops->negotiate_wsize(tcon, ctx), PAGE_SIZE); + /* + * in the very unlikely event that the server sent a max write size under PAGE_SIZE, + * (which would get rounded down to 0) then reset wsize to absolute minimum eg 4096 + */ + if (cifs_sb->ctx->wsize == 0) { + cifs_sb->ctx->wsize = PAGE_SIZE; + cifs_dbg(VFS, "wsize too small, reset to minimum ie PAGE_SIZE, usually 4096\n"); + } + } if ((cifs_sb->ctx->rsize == 0) || (cifs_sb->ctx->rsize > server->ops->negotiate_rsize(tcon, ctx))) cifs_sb->ctx->rsize = server->ops->negotiate_rsize(tcon, ctx); diff --git a/fs/smb/client/fs_context.c b/fs/smb/client/fs_context.c index aec8dbd1f9db..4b2f5aa2ea0e 100644 --- a/fs/smb/client/fs_context.c +++ b/fs/smb/client/fs_context.c @@ -1111,6 +1111,17 @@ static int smb3_fs_context_parse_param(struct fs_context *fc, case Opt_wsize: ctx->wsize = result.uint_32; ctx->got_wsize = true; + if (ctx->wsize % PAGE_SIZE != 0) { + ctx->wsize = round_down(ctx->wsize, PAGE_SIZE); + if (ctx->wsize == 0) { + ctx->wsize = PAGE_SIZE; + cifs_dbg(VFS, "wsize too small, reset to minimum %ld\n", PAGE_SIZE); + } else { + cifs_dbg(VFS, + "wsize rounded down to %d to multiple of PAGE_SIZE %ld\n", + ctx->wsize, PAGE_SIZE); + } + } break; case Opt_acregmax: ctx->acregmax = HZ * result.uint_32; diff --git a/fs/smb/client/namespace.c b/fs/smb/client/namespace.c index a6968573b775..4a517b280f2b 100644 --- a/fs/smb/client/namespace.c +++ b/fs/smb/client/namespace.c @@ -168,6 +168,21 @@ static char *automount_fullpath(struct dentry *dentry, void *page) return s; } +static void fs_context_set_ids(struct smb3_fs_context *ctx) +{ + kuid_t uid = current_fsuid(); + kgid_t gid = current_fsgid(); + + if (ctx->multiuser) { + if (!ctx->uid_specified) + ctx->linux_uid = uid; + if (!ctx->gid_specified) + ctx->linux_gid = gid; + } + if (!ctx->cruid_specified) + ctx->cred_uid = uid; +} + /* * Create a vfsmount that we can automount */ @@ -205,6 +220,7 @@ static struct vfsmount *cifs_do_automount(struct path *path) tmp.leaf_fullpath = NULL; tmp.UNC = tmp.prepath = NULL; tmp.dfs_root_ses = NULL; + fs_context_set_ids(&tmp); rc = smb3_fs_context_dup(ctx, &tmp); if (rc) { diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c index 83c898afc835..4695433fcf39 100644 --- a/fs/smb/client/smb2ops.c +++ b/fs/smb/client/smb2ops.c @@ -619,7 +619,7 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf, goto out; } - while (bytes_left >= sizeof(*p)) { + while (bytes_left >= (ssize_t)sizeof(*p)) { memset(&tmp_iface, 0, sizeof(tmp_iface)); tmp_iface.speed = le64_to_cpu(p->LinkSpeed); tmp_iface.rdma_capable = le32_to_cpu(p->Capability & RDMA_CAPABLE) ? 1 : 0; @@ -1204,6 +1204,7 @@ replay_again: .disposition = FILE_OPEN, .create_options = cifs_create_options(cifs_sb, 0), .fid = &fid, + .replay = !!(retries), }; rc = SMB2_open_init(tcon, server, @@ -1569,6 +1570,7 @@ replay_again: .disposition = FILE_OPEN, .create_options = cifs_create_options(cifs_sb, create_options), .fid = &fid, + .replay = !!(retries), }; if (qi.flags & PASSTHRU_FSCTL) { @@ -2295,6 +2297,7 @@ replay_again: .disposition = FILE_OPEN, .create_options = cifs_create_options(cifs_sb, 0), .fid = fid, + .replay = !!(retries), }; rc = SMB2_open_init(tcon, server, @@ -2681,6 +2684,7 @@ replay_again: .disposition = FILE_OPEN, .create_options = cifs_create_options(cifs_sb, 0), .fid = &fid, + .replay = !!(retries), }; rc = SMB2_open_init(tcon, server, @@ -5213,7 +5217,7 @@ static int smb2_create_reparse_symlink(const unsigned int xid, struct inode *new; struct kvec iov; __le16 *path; - char *sym; + char *sym, sep = CIFS_DIR_SEP(cifs_sb); u16 len, plen; int rc = 0; @@ -5227,7 +5231,8 @@ static int smb2_create_reparse_symlink(const unsigned int xid, .symlink_target = sym, }; - path = cifs_convert_path_to_utf16(symname, cifs_sb); + convert_delimiter(sym, sep); + path = cifs_convert_path_to_utf16(sym, cifs_sb); if (!path) { rc = -ENOMEM; goto out; @@ -5250,7 +5255,10 @@ static int smb2_create_reparse_symlink(const unsigned int xid, buf->PrintNameLength = cpu_to_le16(plen); memcpy(buf->PathBuffer, path, plen); buf->Flags = cpu_to_le32(*symname != '/' ? SYMLINK_FLAG_RELATIVE : 0); + if (*sym != sep) + buf->Flags = cpu_to_le32(SYMLINK_FLAG_RELATIVE); + convert_delimiter(sym, '/'); iov.iov_base = buf; iov.iov_len = len; new = smb2_get_reparse_inode(&data, inode->i_sb, xid, diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c index 4085ce27fd38..608ee05491e2 100644 --- a/fs/smb/client/smb2pdu.c +++ b/fs/smb/client/smb2pdu.c @@ -2404,8 +2404,13 @@ create_durable_v2_buf(struct cifs_open_parms *oparms) */ buf->dcontext.Timeout = cpu_to_le32(oparms->tcon->handle_timeout); buf->dcontext.Flags = cpu_to_le32(SMB2_DHANDLE_FLAG_PERSISTENT); - generate_random_uuid(buf->dcontext.CreateGuid); - memcpy(pfid->create_guid, buf->dcontext.CreateGuid, 16); + + /* for replay, we should not overwrite the existing create guid */ + if (!oparms->replay) { + generate_random_uuid(buf->dcontext.CreateGuid); + memcpy(pfid->create_guid, buf->dcontext.CreateGuid, 16); + } else + memcpy(buf->dcontext.CreateGuid, pfid->create_guid, 16); /* SMB2_CREATE_DURABLE_HANDLE_REQUEST is "DH2Q" */ buf->Name[0] = 'D'; @@ -3142,6 +3147,7 @@ replay_again: /* reinitialize for possible replay */ flags = 0; server = cifs_pick_channel(ses); + oparms->replay = !!(retries); cifs_dbg(FYI, "create/open\n"); if (!ses || !server) diff --git a/fs/zonefs/file.c b/fs/zonefs/file.c index 6ab2318a9c8e..dba5dcb62bef 100644 --- a/fs/zonefs/file.c +++ b/fs/zonefs/file.c @@ -348,7 +348,12 @@ static int zonefs_file_write_dio_end_io(struct kiocb *iocb, ssize_t size, struct zonefs_inode_info *zi = ZONEFS_I(inode); if (error) { - zonefs_io_error(inode, true); + /* + * For Sync IOs, error recovery is called from + * zonefs_file_dio_write(). + */ + if (!is_sync_kiocb(iocb)) + zonefs_io_error(inode, true); return error; } @@ -491,6 +496,14 @@ static ssize_t zonefs_file_dio_write(struct kiocb *iocb, struct iov_iter *from) ret = -EINVAL; goto inode_unlock; } + /* + * Advance the zone write pointer offset. This assumes that the + * IO will succeed, which is OK to do because we do not allow + * partial writes (IOMAP_DIO_PARTIAL is not set) and if the IO + * fails, the error path will correct the write pointer offset. + */ + z->z_wpoffset += count; + zonefs_inode_account_active(inode); mutex_unlock(&zi->i_truncate_mutex); } @@ -504,20 +517,19 @@ static ssize_t zonefs_file_dio_write(struct kiocb *iocb, struct iov_iter *from) if (ret == -ENOTBLK) ret = -EBUSY; - if (zonefs_zone_is_seq(z) && - (ret > 0 || ret == -EIOCBQUEUED)) { - if (ret > 0) - count = ret; - - /* - * Update the zone write pointer offset assuming the write - * operation succeeded. If it did not, the error recovery path - * will correct it. Also do active seq file accounting. - */ - mutex_lock(&zi->i_truncate_mutex); - z->z_wpoffset += count; - zonefs_inode_account_active(inode); - mutex_unlock(&zi->i_truncate_mutex); + /* + * For a failed IO or partial completion, trigger error recovery + * to update the zone write pointer offset to a correct value. + * For asynchronous IOs, zonefs_file_write_dio_end_io() may already + * have executed error recovery if the IO already completed when we + * reach here. However, we cannot know that and execute error recovery + * again (that will not change anything). + */ + if (zonefs_zone_is_seq(z)) { + if (ret > 0 && ret != count) + ret = -EIO; + if (ret < 0 && ret != -EIOCBQUEUED) + zonefs_io_error(inode, true); } inode_unlock: diff --git a/fs/zonefs/super.c b/fs/zonefs/super.c index 93971742613a..b6e8e7c96251 100644 --- a/fs/zonefs/super.c +++ b/fs/zonefs/super.c @@ -246,16 +246,18 @@ static void zonefs_inode_update_mode(struct inode *inode) z->z_mode = inode->i_mode; } -struct zonefs_ioerr_data { - struct inode *inode; - bool write; -}; - static int zonefs_io_error_cb(struct blk_zone *zone, unsigned int idx, void *data) { - struct zonefs_ioerr_data *err = data; - struct inode *inode = err->inode; + struct blk_zone *z = data; + + *z = *zone; + return 0; +} + +static void zonefs_handle_io_error(struct inode *inode, struct blk_zone *zone, + bool write) +{ struct zonefs_zone *z = zonefs_inode_zone(inode); struct super_block *sb = inode->i_sb; struct zonefs_sb_info *sbi = ZONEFS_SB(sb); @@ -270,8 +272,8 @@ static int zonefs_io_error_cb(struct blk_zone *zone, unsigned int idx, data_size = zonefs_check_zone_condition(sb, z, zone); isize = i_size_read(inode); if (!(z->z_flags & (ZONEFS_ZONE_READONLY | ZONEFS_ZONE_OFFLINE)) && - !err->write && isize == data_size) - return 0; + !write && isize == data_size) + return; /* * At this point, we detected either a bad zone or an inconsistency @@ -292,7 +294,7 @@ static int zonefs_io_error_cb(struct blk_zone *zone, unsigned int idx, * In all cases, warn about inode size inconsistency and handle the * IO error according to the zone condition and to the mount options. */ - if (zonefs_zone_is_seq(z) && isize != data_size) + if (isize != data_size) zonefs_warn(sb, "inode %lu: invalid size %lld (should be %lld)\n", inode->i_ino, isize, data_size); @@ -352,8 +354,6 @@ static int zonefs_io_error_cb(struct blk_zone *zone, unsigned int idx, zonefs_i_size_write(inode, data_size); z->z_wpoffset = data_size; zonefs_inode_account_active(inode); - - return 0; } /* @@ -367,23 +367,25 @@ void __zonefs_io_error(struct inode *inode, bool write) { struct zonefs_zone *z = zonefs_inode_zone(inode); struct super_block *sb = inode->i_sb; - struct zonefs_sb_info *sbi = ZONEFS_SB(sb); unsigned int noio_flag; - unsigned int nr_zones = 1; - struct zonefs_ioerr_data err = { - .inode = inode, - .write = write, - }; + struct blk_zone zone; int ret; /* - * The only files that have more than one zone are conventional zone - * files with aggregated conventional zones, for which the inode zone - * size is always larger than the device zone size. + * Conventional zone have no write pointer and cannot become read-only + * or offline. So simply fake a report for a single or aggregated zone + * and let zonefs_handle_io_error() correct the zone inode information + * according to the mount options. */ - if (z->z_size > bdev_zone_sectors(sb->s_bdev)) - nr_zones = z->z_size >> - (sbi->s_zone_sectors_shift + SECTOR_SHIFT); + if (!zonefs_zone_is_seq(z)) { + zone.start = z->z_sector; + zone.len = z->z_size >> SECTOR_SHIFT; + zone.wp = zone.start + zone.len; + zone.type = BLK_ZONE_TYPE_CONVENTIONAL; + zone.cond = BLK_ZONE_COND_NOT_WP; + zone.capacity = zone.len; + goto handle_io_error; + } /* * Memory allocations in blkdev_report_zones() can trigger a memory @@ -394,12 +396,20 @@ void __zonefs_io_error(struct inode *inode, bool write) * the GFP_NOIO context avoids both problems. */ noio_flag = memalloc_noio_save(); - ret = blkdev_report_zones(sb->s_bdev, z->z_sector, nr_zones, - zonefs_io_error_cb, &err); - if (ret != nr_zones) + ret = blkdev_report_zones(sb->s_bdev, z->z_sector, 1, + zonefs_io_error_cb, &zone); + memalloc_noio_restore(noio_flag); + + if (ret != 1) { zonefs_err(sb, "Get inode %lu zone information failed %d\n", inode->i_ino, ret); - memalloc_noio_restore(noio_flag); + zonefs_warn(sb, "remounting filesystem read-only\n"); + sb->s_flags |= SB_RDONLY; + return; + } + +handle_io_error: + zonefs_handle_io_error(inode, &zone, write); } static struct kmem_cache *zonefs_inode_cachep; diff --git a/include/linux/compiler-gcc.h b/include/linux/compiler-gcc.h index c1a963be7d28..75bd1692d2e3 100644 --- a/include/linux/compiler-gcc.h +++ b/include/linux/compiler-gcc.h @@ -67,10 +67,9 @@ /* * GCC 'asm goto' with outputs miscompiles certain code sequences: * - * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110420 - * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110422 + * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113921 * - * Work it around via the same compiler barrier quirk that we used + * Work around it via the same compiler barrier quirk that we used * to use for the old 'asm goto' workaround. * * Also, always mark such 'asm goto' statements as volatile: all @@ -80,8 +79,10 @@ * * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98619 */ +#ifdef CONFIG_GCC_ASM_GOTO_OUTPUT_WORKAROUND #define asm_goto_output(x...) \ do { asm volatile goto(x); asm (""); } while (0) +#endif #if defined(CONFIG_ARCH_USE_BUILTIN_BSWAP) #define __HAVE_BUILTIN_BSWAP32__ diff --git a/include/linux/compiler_types.h b/include/linux/compiler_types.h index 663d8791c871..0caf354cb94b 100644 --- a/include/linux/compiler_types.h +++ b/include/linux/compiler_types.h @@ -362,8 +362,15 @@ struct ftrace_likely_data { #define __member_size(p) __builtin_object_size(p, 1) #endif +/* + * Some versions of gcc do not mark 'asm goto' volatile: + * + * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=103979 + * + * We do it here by hand, because it doesn't hurt. + */ #ifndef asm_goto_output -#define asm_goto_output(x...) asm goto(x) +#define asm_goto_output(x...) asm volatile goto(x) #endif #ifdef CONFIG_CC_HAS_ASM_INLINE diff --git a/include/linux/fs.h b/include/linux/fs.h index ed5966a70495..023f37c60709 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2101,9 +2101,6 @@ int __generic_remap_file_range_prep(struct file *file_in, loff_t pos_in, int generic_remap_file_range_prep(struct file *file_in, loff_t pos_in, struct file *file_out, loff_t pos_out, loff_t *count, unsigned int remap_flags); -extern loff_t do_clone_file_range(struct file *file_in, loff_t pos_in, - struct file *file_out, loff_t pos_out, - loff_t len, unsigned int remap_flags); extern loff_t vfs_clone_file_range(struct file *file_in, loff_t pos_in, struct file *file_out, loff_t pos_out, loff_t len, unsigned int remap_flags); diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h index 9a5c6c76e653..7f75c9a51874 100644 --- a/include/linux/gpio/driver.h +++ b/include/linux/gpio/driver.h @@ -819,6 +819,24 @@ static inline struct gpio_chip *gpiod_to_chip(const struct gpio_desc *desc) return ERR_PTR(-ENODEV); } +static inline struct gpio_device *gpiod_to_gpio_device(struct gpio_desc *desc) +{ + WARN_ON(1); + return ERR_PTR(-ENODEV); +} + +static inline int gpio_device_get_base(struct gpio_device *gdev) +{ + WARN_ON(1); + return -ENODEV; +} + +static inline const char *gpio_device_get_label(struct gpio_device *gdev) +{ + WARN_ON(1); + return NULL; +} + static inline int gpiochip_lock_as_irq(struct gpio_chip *gc, unsigned int offset) { diff --git a/include/linux/hid-sensor-ids.h b/include/linux/hid-sensor-ids.h index 13b1e65fbdcc..6730ee900ee1 100644 --- a/include/linux/hid-sensor-ids.h +++ b/include/linux/hid-sensor-ids.h @@ -21,6 +21,10 @@ #define HID_USAGE_SENSOR_ALS 0x200041 #define HID_USAGE_SENSOR_DATA_LIGHT 0x2004d0 #define HID_USAGE_SENSOR_LIGHT_ILLUM 0x2004d1 +#define HID_USAGE_SENSOR_LIGHT_COLOR_TEMPERATURE 0x2004d2 +#define HID_USAGE_SENSOR_LIGHT_CHROMATICITY 0x2004d3 +#define HID_USAGE_SENSOR_LIGHT_CHROMATICITY_X 0x2004d4 +#define HID_USAGE_SENSOR_LIGHT_CHROMATICITY_Y 0x2004d5 /* PROX (200011) */ #define HID_USAGE_SENSOR_PROX 0x200011 diff --git a/include/linux/iio/adc/ad_sigma_delta.h b/include/linux/iio/adc/ad_sigma_delta.h index 7852f6c9a714..719cf9cc6e1a 100644 --- a/include/linux/iio/adc/ad_sigma_delta.h +++ b/include/linux/iio/adc/ad_sigma_delta.h @@ -8,6 +8,8 @@ #ifndef __AD_SIGMA_DELTA_H__ #define __AD_SIGMA_DELTA_H__ +#include <linux/iio/iio.h> + enum ad_sigma_delta_mode { AD_SD_MODE_CONTINUOUS = 0, AD_SD_MODE_SINGLE = 1, @@ -99,7 +101,7 @@ struct ad_sigma_delta { * 'rx_buf' is up to 32 bits per sample + 64 bit timestamp, * rounded to 16 bytes to take into account padding. */ - uint8_t tx_buf[4] ____cacheline_aligned; + uint8_t tx_buf[4] __aligned(IIO_DMA_MINALIGN); uint8_t rx_buf[16] __aligned(8); }; diff --git a/include/linux/iio/adc/adi-axi-adc.h b/include/linux/iio/adc/adi-axi-adc.h deleted file mode 100644 index b7904992d561..000000000000 --- a/include/linux/iio/adc/adi-axi-adc.h +++ /dev/null @@ -1,68 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Analog Devices Generic AXI ADC IP core driver/library - * Link: https://wiki.analog.com/resources/fpga/docs/axi_adc_ip - * - * Copyright 2012-2020 Analog Devices Inc. - */ -#ifndef __ADI_AXI_ADC_H__ -#define __ADI_AXI_ADC_H__ - -struct device; -struct iio_chan_spec; - -/** - * struct adi_axi_adc_chip_info - Chip specific information - * @name Chip name - * @id Chip ID (usually product ID) - * @channels Channel specifications of type @struct iio_chan_spec - * @num_channels Number of @channels - * @scale_table Supported scales by the chip; tuples of 2 ints - * @num_scales Number of scales in the table - * @max_rate Maximum sampling rate supported by the device - */ -struct adi_axi_adc_chip_info { - const char *name; - unsigned int id; - - const struct iio_chan_spec *channels; - unsigned int num_channels; - - const unsigned int (*scale_table)[2]; - int num_scales; - - unsigned long max_rate; -}; - -/** - * struct adi_axi_adc_conv - data of the ADC attached to the AXI ADC - * @chip_info chip info details for the client ADC - * @preenable_setup op to run in the client before enabling the AXI ADC - * @reg_access IIO debugfs_reg_access hook for the client ADC - * @read_raw IIO read_raw hook for the client ADC - * @write_raw IIO write_raw hook for the client ADC - * @read_avail IIO read_avail hook for the client ADC - */ -struct adi_axi_adc_conv { - const struct adi_axi_adc_chip_info *chip_info; - - int (*preenable_setup)(struct adi_axi_adc_conv *conv); - int (*reg_access)(struct adi_axi_adc_conv *conv, unsigned int reg, - unsigned int writeval, unsigned int *readval); - int (*read_raw)(struct adi_axi_adc_conv *conv, - struct iio_chan_spec const *chan, - int *val, int *val2, long mask); - int (*write_raw)(struct adi_axi_adc_conv *conv, - struct iio_chan_spec const *chan, - int val, int val2, long mask); - int (*read_avail)(struct adi_axi_adc_conv *conv, - struct iio_chan_spec const *chan, - const int **val, int *type, int *length, long mask); -}; - -struct adi_axi_adc_conv *devm_adi_axi_adc_conv_register(struct device *dev, - size_t sizeof_priv); - -void *adi_axi_adc_conv_priv(struct adi_axi_adc_conv *conv); - -#endif diff --git a/include/linux/iio/backend.h b/include/linux/iio/backend.h new file mode 100644 index 000000000000..a6d79381866e --- /dev/null +++ b/include/linux/iio/backend.h @@ -0,0 +1,72 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +#ifndef _IIO_BACKEND_H_ +#define _IIO_BACKEND_H_ + +#include <linux/types.h> + +struct fwnode_handle; +struct iio_backend; +struct device; +struct iio_dev; + +enum iio_backend_data_type { + IIO_BACKEND_TWOS_COMPLEMENT, + IIO_BACKEND_OFFSET_BINARY, + IIO_BACKEND_DATA_TYPE_MAX +}; + +/** + * struct iio_backend_data_fmt - Backend data format + * @type: Data type. + * @sign_extend: Bool to tell if the data is sign extended. + * @enable: Enable/Disable the data format module. If disabled, + * not formatting will happen. + */ +struct iio_backend_data_fmt { + enum iio_backend_data_type type; + bool sign_extend; + bool enable; +}; + +/** + * struct iio_backend_ops - operations structure for an iio_backend + * @enable: Enable backend. + * @disable: Disable backend. + * @chan_enable: Enable one channel. + * @chan_disable: Disable one channel. + * @data_format_set: Configure the data format for a specific channel. + * @request_buffer: Request an IIO buffer. + * @free_buffer: Free an IIO buffer. + **/ +struct iio_backend_ops { + int (*enable)(struct iio_backend *back); + void (*disable)(struct iio_backend *back); + int (*chan_enable)(struct iio_backend *back, unsigned int chan); + int (*chan_disable)(struct iio_backend *back, unsigned int chan); + int (*data_format_set)(struct iio_backend *back, unsigned int chan, + const struct iio_backend_data_fmt *data); + struct iio_buffer *(*request_buffer)(struct iio_backend *back, + struct iio_dev *indio_dev); + void (*free_buffer)(struct iio_backend *back, + struct iio_buffer *buffer); +}; + +int iio_backend_chan_enable(struct iio_backend *back, unsigned int chan); +int iio_backend_chan_disable(struct iio_backend *back, unsigned int chan); +int devm_iio_backend_enable(struct device *dev, struct iio_backend *back); +int iio_backend_data_format_set(struct iio_backend *back, unsigned int chan, + const struct iio_backend_data_fmt *data); +int devm_iio_backend_request_buffer(struct device *dev, + struct iio_backend *back, + struct iio_dev *indio_dev); + +void *iio_backend_get_priv(const struct iio_backend *conv); +struct iio_backend *devm_iio_backend_get(struct device *dev, const char *name); +struct iio_backend * +__devm_iio_backend_get_from_fwnode_lookup(struct device *dev, + struct fwnode_handle *fwnode); + +int devm_iio_backend_register(struct device *dev, + const struct iio_backend_ops *ops, void *priv); + +#endif diff --git a/include/linux/iio/buffer-dmaengine.h b/include/linux/iio/buffer-dmaengine.h index 5c355be89814..cbb8ba957fad 100644 --- a/include/linux/iio/buffer-dmaengine.h +++ b/include/linux/iio/buffer-dmaengine.h @@ -10,6 +10,9 @@ struct iio_dev; struct device; +struct iio_buffer *iio_dmaengine_buffer_alloc(struct device *dev, + const char *channel); +void iio_dmaengine_buffer_free(struct iio_buffer *buffer); int devm_iio_dmaengine_buffer_setup(struct device *dev, struct iio_dev *indio_dev, const char *channel); diff --git a/include/linux/iio/common/st_sensors.h b/include/linux/iio/common/st_sensors.h index 607c3a89a647..f9ae5cdd884f 100644 --- a/include/linux/iio/common/st_sensors.h +++ b/include/linux/iio/common/st_sensors.h @@ -258,9 +258,9 @@ struct st_sensor_data { bool hw_irq_trigger; s64 hw_timestamp; - char buffer_data[ST_SENSORS_MAX_BUFFER_SIZE] ____cacheline_aligned; - struct mutex odr_lock; + + char buffer_data[ST_SENSORS_MAX_BUFFER_SIZE] __aligned(IIO_DMA_MINALIGN); }; #ifdef CONFIG_IIO_BUFFER diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h index c5b36d2c1e73..e370a7bb3300 100644 --- a/include/linux/iio/iio.h +++ b/include/linux/iio/iio.h @@ -9,6 +9,7 @@ #include <linux/device.h> #include <linux/cdev.h> +#include <linux/cleanup.h> #include <linux/slab.h> #include <linux/iio/types.h> /* IIO TODO LIST */ @@ -638,10 +639,37 @@ int __devm_iio_device_register(struct device *dev, struct iio_dev *indio_dev, 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); + +/* + * This autocleanup logic is normally used via + * iio_device_claim_direct_scoped(). + */ +DEFINE_GUARD(iio_claim_direct, struct iio_dev *, iio_device_claim_direct_mode(_T), + iio_device_release_direct_mode(_T)) + +DEFINE_GUARD_COND(iio_claim_direct, _try, ({ + struct iio_dev *dev; + int d = iio_device_claim_direct_mode(_T); + + if (d < 0) + dev = NULL; + else + dev = _T; + dev; + })) + +/** + * iio_device_claim_direct_scoped() - Scoped call to iio_device_claim_direct. + * @fail: What to do on failure to claim device. + * @iio_dev: Pointer to the IIO devices structure + */ +#define iio_device_claim_direct_scoped(fail, iio_dev) \ + scoped_cond_guard(iio_claim_direct_try, fail, iio_dev) + int iio_device_claim_buffer_mode(struct iio_dev *indio_dev); void iio_device_release_buffer_mode(struct iio_dev *indio_dev); -extern struct bus_type iio_bus_type; +extern const struct bus_type iio_bus_type; /** * iio_device_put() - reference counted deallocation of struct device diff --git a/include/linux/iio/imu/adis.h b/include/linux/iio/imu/adis.h index dc9ea299e088..8898966bc0f0 100644 --- a/include/linux/iio/imu/adis.h +++ b/include/linux/iio/imu/adis.h @@ -11,6 +11,7 @@ #include <linux/spi/spi.h> #include <linux/interrupt.h> +#include <linux/iio/iio.h> #include <linux/iio/types.h> #define ADIS_WRITE_REG(reg) ((0x80 | (reg))) @@ -131,7 +132,7 @@ struct adis { unsigned long irq_flag; void *buffer; - u8 tx[10] ____cacheline_aligned; + u8 tx[10] __aligned(IIO_DMA_MINALIGN); u8 rx[4]; }; diff --git a/include/linux/mhi.h b/include/linux/mhi.h index d0f9b522f328..77b8c0a26674 100644 --- a/include/linux/mhi.h +++ b/include/linux/mhi.h @@ -320,12 +320,7 @@ struct mhi_controller_config { * @hw_ev_rings: Number of hardware event rings * @sw_ev_rings: Number of software event rings * @nr_irqs: Number of IRQ allocated by bus master (required) - * @family_number: MHI controller family number - * @device_number: MHI controller device number - * @major_version: MHI controller major revision number - * @minor_version: MHI controller minor revision number * @serial_number: MHI controller serial number obtained from BHI - * @oem_pk_hash: MHI controller OEM PK Hash obtained from BHI * @mhi_event: MHI event ring configurations table * @mhi_cmd: MHI command ring configurations table * @mhi_ctxt: MHI device context, shared memory between host and device @@ -369,15 +364,6 @@ struct mhi_controller_config { * Fields marked as (required) need to be populated by the controller driver * before calling mhi_register_controller(). For the fields marked as (optional) * they can be populated depending on the usecase. - * - * The following fields are present for the purpose of implementing any device - * specific quirks or customizations for specific MHI revisions used in device - * by the controller drivers. The MHI stack will just populate these fields - * during mhi_register_controller(): - * family_number - * device_number - * major_version - * minor_version */ struct mhi_controller { struct device *cntrl_dev; @@ -408,12 +394,7 @@ struct mhi_controller { u32 hw_ev_rings; u32 sw_ev_rings; u32 nr_irqs; - u32 family_number; - u32 device_number; - u32 major_version; - u32 minor_version; u32 serial_number; - u32 oem_pk_hash[MHI_MAX_OEM_PK_HASH_SEGMENTS]; struct mhi_event *mhi_event; struct mhi_cmd *mhi_cmd; diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 118c40258d07..ef7bfbb98497 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -2141,6 +2141,11 @@ struct net_device { /* TXRX read-mostly hotpath */ __cacheline_group_begin(net_device_read_txrx); + union { + struct pcpu_lstats __percpu *lstats; + struct pcpu_sw_netstats __percpu *tstats; + struct pcpu_dstats __percpu *dstats; + }; unsigned int flags; unsigned short hard_header_len; netdev_features_t features; @@ -2395,11 +2400,6 @@ struct net_device { enum netdev_ml_priv_type ml_priv_type; enum netdev_stat_type pcpu_stat_type:8; - union { - struct pcpu_lstats __percpu *lstats; - struct pcpu_sw_netstats __percpu *tstats; - struct pcpu_dstats __percpu *dstats; - }; #if IS_ENABLED(CONFIG_GARP) struct garp_port __rcu *garp_port; diff --git a/include/linux/nvme.h b/include/linux/nvme.h index bc605ec4a3fd..3ef4053ea950 100644 --- a/include/linux/nvme.h +++ b/include/linux/nvme.h @@ -646,6 +646,7 @@ enum { NVME_CMD_EFFECTS_NCC = 1 << 2, NVME_CMD_EFFECTS_NIC = 1 << 3, NVME_CMD_EFFECTS_CCC = 1 << 4, + NVME_CMD_EFFECTS_CSER_MASK = GENMASK(15, 14), NVME_CMD_EFFECTS_CSE_MASK = GENMASK(18, 16), NVME_CMD_EFFECTS_UUID_SEL = 1 << 19, NVME_CMD_EFFECTS_SCOPE_MASK = GENMASK(31, 20), diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h index eaaef3ffec22..90507d4afcd6 100644 --- a/include/linux/ptrace.h +++ b/include/linux/ptrace.h @@ -393,6 +393,10 @@ static inline void user_single_step_report(struct pt_regs *regs) #define current_user_stack_pointer() user_stack_pointer(current_pt_regs()) #endif +#ifndef exception_ip +#define exception_ip(x) instruction_pointer(x) +#endif + extern int task_current_syscall(struct task_struct *target, struct syscall_info *info); extern void sigaction_compat_abi(struct k_sigaction *act, struct k_sigaction *oact); diff --git a/include/linux/seq_buf.h b/include/linux/seq_buf.h index c44f4b47b945..fe41da005970 100644 --- a/include/linux/seq_buf.h +++ b/include/linux/seq_buf.h @@ -2,7 +2,10 @@ #ifndef _LINUX_SEQ_BUF_H #define _LINUX_SEQ_BUF_H -#include <linux/fs.h> +#include <linux/bug.h> +#include <linux/minmax.h> +#include <linux/seq_file.h> +#include <linux/types.h> /* * Trace sequences are used to allow a function to call several other functions @@ -10,7 +13,7 @@ */ /** - * seq_buf - seq buffer structure + * struct seq_buf - seq buffer structure * @buffer: pointer to the buffer * @size: size of the buffer * @len: the amount of data inside the buffer @@ -77,10 +80,10 @@ static inline unsigned int seq_buf_used(struct seq_buf *s) } /** - * seq_buf_str - get %NUL-terminated C string from seq_buf + * seq_buf_str - get NUL-terminated C string from seq_buf * @s: the seq_buf handle * - * This makes sure that the buffer in @s is nul terminated and + * This makes sure that the buffer in @s is NUL-terminated and * safe to read as a string. * * Note, if this is called when the buffer has overflowed, then @@ -90,7 +93,7 @@ static inline unsigned int seq_buf_used(struct seq_buf *s) * After this function is called, s->buffer is safe to use * in string operations. * - * Returns @s->buf after making sure it is terminated. + * Returns: @s->buf after making sure it is terminated. */ static inline const char *seq_buf_str(struct seq_buf *s) { @@ -110,7 +113,7 @@ static inline const char *seq_buf_str(struct seq_buf *s) * @s: the seq_buf handle * @bufp: the beginning of the buffer is stored here * - * Return the number of bytes available in the buffer, or zero if + * Returns: the number of bytes available in the buffer, or zero if * there's no space. */ static inline size_t seq_buf_get_buf(struct seq_buf *s, char **bufp) @@ -132,7 +135,7 @@ static inline size_t seq_buf_get_buf(struct seq_buf *s, char **bufp) * @num: the number of bytes to commit * * Commit @num bytes of data written to a buffer previously acquired - * by seq_buf_get. To signal an error condition, or that the data + * by seq_buf_get_buf(). To signal an error condition, or that the data * didn't fit in the available space, pass a negative @num value. */ static inline void seq_buf_commit(struct seq_buf *s, int num) diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index 536b2581d3e2..55b1f3ba48ac 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -748,8 +748,17 @@ struct uart_driver { void uart_write_wakeup(struct uart_port *port); -#define __uart_port_tx(uport, ch, tx_ready, put_char, tx_done, for_test, \ - for_post) \ +/** + * enum UART_TX_FLAGS -- flags for uart_port_tx_flags() + * + * @UART_TX_NOSTOP: don't call port->ops->stop_tx() on empty buffer + */ +enum UART_TX_FLAGS { + UART_TX_NOSTOP = BIT(0), +}; + +#define __uart_port_tx(uport, ch, flags, tx_ready, put_char, tx_done, \ + for_test, for_post) \ ({ \ struct uart_port *__port = (uport); \ struct circ_buf *xmit = &__port->state->xmit; \ @@ -777,7 +786,7 @@ void uart_write_wakeup(struct uart_port *port); if (pending < WAKEUP_CHARS) { \ uart_write_wakeup(__port); \ \ - if (pending == 0) \ + if (!((flags) & UART_TX_NOSTOP) && pending == 0) \ __port->ops->stop_tx(__port); \ } \ \ @@ -812,7 +821,7 @@ void uart_write_wakeup(struct uart_port *port); */ #define uart_port_tx_limited(port, ch, count, tx_ready, put_char, tx_done) ({ \ unsigned int __count = (count); \ - __uart_port_tx(port, ch, tx_ready, put_char, tx_done, __count, \ + __uart_port_tx(port, ch, 0, tx_ready, put_char, tx_done, __count, \ __count--); \ }) @@ -826,8 +835,21 @@ void uart_write_wakeup(struct uart_port *port); * See uart_port_tx_limited() for more details. */ #define uart_port_tx(port, ch, tx_ready, put_char) \ - __uart_port_tx(port, ch, tx_ready, put_char, ({}), true, ({})) + __uart_port_tx(port, ch, 0, tx_ready, put_char, ({}), true, ({})) + +/** + * uart_port_tx_flags -- transmit helper for uart_port with flags + * @port: uart port + * @ch: variable to store a character to be written to the HW + * @flags: %UART_TX_NOSTOP or similar + * @tx_ready: can HW accept more data function + * @put_char: function to write a character + * + * See uart_port_tx_limited() for more details. + */ +#define uart_port_tx_flags(port, ch, flags, tx_ready, put_char) \ + __uart_port_tx(port, ch, flags, tx_ready, put_char, ({}), true, ({})) /* * Baud rate helpers. */ diff --git a/include/linux/tcp.h b/include/linux/tcp.h index 89b290d8c8dc..a1c47a6d69b0 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h @@ -221,8 +221,10 @@ struct tcp_sock { u32 lost_out; /* Lost packets */ u32 sacked_out; /* SACK'd packets */ u16 tcp_header_len; /* Bytes of tcp header to send */ + u8 scaling_ratio; /* see tcp_win_from_space() */ u8 chrono_type : 2, /* current chronograph type */ repair : 1, + tcp_usec_ts : 1, /* TSval values in usec */ is_sack_reneg:1, /* in recovery from loss with SACK reneg? */ is_cwnd_limited:1;/* forward progress limited by snd_cwnd? */ __cacheline_group_end(tcp_sock_read_txrx); @@ -352,7 +354,6 @@ struct tcp_sock { u32 compressed_ack_rcv_nxt; struct list_head tsq_node; /* anchor in tsq_tasklet.head list */ - u8 scaling_ratio; /* see tcp_win_from_space() */ /* Information of the most recently (s)acked skb */ struct tcp_rack { u64 mstamp; /* (Re)sent time of the skb */ @@ -368,8 +369,7 @@ struct tcp_sock { u8 compressed_ack; u8 dup_ack_counter:2, tlp_retrans:1, /* TLP is a retransmission */ - tcp_usec_ts:1, /* TSval values in usec */ - unused:4; + unused:5; u8 thin_lto : 1,/* Use linear timeouts for thin streams */ recvmsg_inq : 1,/* Indicate # of bytes in queue upon recvmsg */ fastopen_connect:1, /* FASTOPEN_CONNECT sockopt */ diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index a771ccc038ac..6532beb587b1 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -236,7 +236,6 @@ struct usb_ep { unsigned max_streams:16; unsigned mult:2; unsigned maxburst:5; - unsigned fifo_mode:1; u8 address; const struct usb_endpoint_descriptor *desc; const struct usb_ss_ep_comp_descriptor *comp_desc; diff --git a/include/net/tls.h b/include/net/tls.h index 962f0c501111..340ad43971e4 100644 --- a/include/net/tls.h +++ b/include/net/tls.h @@ -97,9 +97,6 @@ struct tls_sw_context_tx { struct tls_rec *open_rec; struct list_head tx_list; atomic_t encrypt_pending; - /* protect crypto_wait with encrypt_pending */ - spinlock_t encrypt_compl_lock; - int async_notify; u8 async_capable:1; #define BIT_TX_SCHEDULED 0 @@ -136,8 +133,6 @@ struct tls_sw_context_rx { struct tls_strparser strp; atomic_t decrypt_pending; - /* protect crypto_wait with decrypt_pending*/ - spinlock_t decrypt_compl_lock; struct sk_buff_head async_hold; struct wait_queue_head wq; }; diff --git a/include/sound/tas2781.h b/include/sound/tas2781.h index b00d65417c31..9aff384941de 100644 --- a/include/sound/tas2781.h +++ b/include/sound/tas2781.h @@ -142,6 +142,7 @@ struct tasdevice_priv { void tas2781_reset(struct tasdevice_priv *tas_dev); int tascodec_init(struct tasdevice_priv *tas_priv, void *codec, + struct module *module, void (*cont)(const struct firmware *fw, void *context)); struct tasdevice_priv *tasdevice_kzalloc(struct i2c_client *i2c); int tasdevice_init(struct tasdevice_priv *tas_priv); diff --git a/include/uapi/linux/iio/types.h b/include/uapi/linux/iio/types.h index 5060963707b1..f2e0b2d50e6b 100644 --- a/include/uapi/linux/iio/types.h +++ b/include/uapi/linux/iio/types.h @@ -91,8 +91,6 @@ enum iio_modifier { IIO_MOD_CO2, IIO_MOD_VOC, IIO_MOD_LIGHT_UV, - IIO_MOD_LIGHT_UVA, - IIO_MOD_LIGHT_UVB, IIO_MOD_LIGHT_DUV, IIO_MOD_PM1, IIO_MOD_PM2P5, @@ -107,6 +105,8 @@ enum iio_modifier { IIO_MOD_PITCH, IIO_MOD_YAW, IIO_MOD_ROLL, + IIO_MOD_LIGHT_UVA, + IIO_MOD_LIGHT_UVB, }; enum iio_event_type { diff --git a/include/uapi/xen/gntalloc.h b/include/uapi/xen/gntalloc.h index 48d2790ef928..3109282672f3 100644 --- a/include/uapi/xen/gntalloc.h +++ b/include/uapi/xen/gntalloc.h @@ -31,7 +31,10 @@ struct ioctl_gntalloc_alloc_gref { __u64 index; /* The grant references of the newly created grant, one per page */ /* Variable size, depending on count */ - __u32 gref_ids[1]; + union { + __u32 gref_ids[1]; + __DECLARE_FLEX_ARRAY(__u32, gref_ids_flex); + }; }; #define GNTALLOC_FLAG_WRITABLE 1 diff --git a/init/Kconfig b/init/Kconfig index deda3d14135b..8426d59cc634 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -89,6 +89,15 @@ config CC_HAS_ASM_GOTO_TIED_OUTPUT # Detect buggy gcc and clang, fixed in gcc-11 clang-14. def_bool $(success,echo 'int foo(int *x) { asm goto (".long (%l[bar]) - .": "+m"(*x) ::: bar); return *x; bar: return 0; }' | $CC -x c - -c -o /dev/null) +config GCC_ASM_GOTO_OUTPUT_WORKAROUND + bool + depends on CC_IS_GCC && CC_HAS_ASM_GOTO_OUTPUT + # Fixed in GCC 14, 13.3, 12.4 and 11.5 + # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113921 + default y if GCC_VERSION < 110500 + default y if GCC_VERSION >= 120000 && GCC_VERSION < 120400 + default y if GCC_VERSION >= 130000 && GCC_VERSION < 130300 + config TOOLS_SUPPORT_RELR def_bool $(success,env "CC=$(CC)" "LD=$(LD)" "NM=$(NM)" "OBJCOPY=$(OBJCOPY)" $(srctree)/scripts/tools-support-relr.sh) diff --git a/io_uring/net.c b/io_uring/net.c index 43bc9a5f96f9..161622029147 100644 --- a/io_uring/net.c +++ b/io_uring/net.c @@ -1372,7 +1372,7 @@ retry: * has already been done */ if (issue_flags & IO_URING_F_MULTISHOT) - ret = IOU_ISSUE_SKIP_COMPLETE; + return IOU_ISSUE_SKIP_COMPLETE; return ret; } if (ret == -ERESTARTSYS) @@ -1397,7 +1397,8 @@ retry: ret, IORING_CQE_F_MORE)) goto retry; - return -ECANCELED; + io_req_set_res(req, ret, 0); + return IOU_STOP_MULTISHOT; } int io_socket_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe) diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index c060d5b47910..83ba342aef31 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -5331,7 +5331,7 @@ static int register_ftrace_function_nolock(struct ftrace_ops *ops); * not support ftrace_regs_caller but direct_call, use SAVE_ARGS so that it * jumps from ftrace_caller for multiple ftrace_ops. */ -#ifndef HAVE_DYNAMIC_FTRACE_WITH_REGS +#ifndef CONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS #define MULTI_FLAGS (FTRACE_OPS_FL_DIRECT | FTRACE_OPS_FL_SAVE_ARGS) #else #define MULTI_FLAGS (FTRACE_OPS_FL_DIRECT | FTRACE_OPS_FL_SAVE_REGS) diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 9ff8a439d674..8198bfc54b58 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -39,6 +39,7 @@ #include <linux/ctype.h> #include <linux/init.h> #include <linux/panic_notifier.h> +#include <linux/kmemleak.h> #include <linux/poll.h> #include <linux/nmi.h> #include <linux/fs.h> @@ -1532,7 +1533,7 @@ void disable_trace_on_warning(void) bool tracer_tracing_is_on(struct trace_array *tr) { if (tr->array_buffer.buffer) - return ring_buffer_record_is_on(tr->array_buffer.buffer); + return ring_buffer_record_is_set_on(tr->array_buffer.buffer); return !tr->buffer_disabled; } @@ -2339,6 +2340,7 @@ static void free_saved_cmdlines_buffer(struct saved_cmdlines_buffer *s) int order = get_order(sizeof(*s) + s->cmdline_num * TASK_COMM_LEN); kfree(s->map_cmdline_to_pid); + kmemleak_free(s); free_pages((unsigned long)s, order); } @@ -2358,6 +2360,7 @@ static struct saved_cmdlines_buffer *allocate_cmdlines_buffer(unsigned int val) return NULL; s = page_address(page); + kmemleak_alloc(s, size, 1, GFP_KERNEL); memset(s, 0, sizeof(*s)); /* Round up to actual allocation */ diff --git a/kernel/trace/trace_btf.c b/kernel/trace/trace_btf.c index ca224d53bfdc..5bbdbcbbde3c 100644 --- a/kernel/trace/trace_btf.c +++ b/kernel/trace/trace_btf.c @@ -91,8 +91,8 @@ retry: for_each_member(i, type, member) { if (!member->name_off) { /* Anonymous union/struct: push it for later use */ - type = btf_type_skip_modifiers(btf, member->type, &tid); - if (type && top < BTF_ANON_STACK_MAX) { + if (btf_type_skip_modifiers(btf, member->type, &tid) && + top < BTF_ANON_STACK_MAX) { anon_stack[top].tid = tid; anon_stack[top++].offset = cur_offset + member->offset; diff --git a/kernel/trace/trace_events_synth.c b/kernel/trace/trace_events_synth.c index e7af286af4f1..c82b401a294d 100644 --- a/kernel/trace/trace_events_synth.c +++ b/kernel/trace/trace_events_synth.c @@ -441,8 +441,9 @@ static unsigned int trace_string(struct synth_trace_event *entry, if (is_dynamic) { union trace_synth_field *data = &entry->fields[*n_u64]; + len = fetch_store_strlen((unsigned long)str_val); data->as_dynamic.offset = struct_size(entry, fields, event->n_u64) + data_size; - data->as_dynamic.len = fetch_store_strlen((unsigned long)str_val); + data->as_dynamic.len = len; ret = fetch_store_string((unsigned long)str_val, &entry->fields[*n_u64], entry); diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 76e60faed892..7b482a26d741 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -5786,13 +5786,9 @@ static int workqueue_apply_unbound_cpumask(const cpumask_var_t unbound_cpumask) list_for_each_entry(wq, &workqueues, list) { if (!(wq->flags & WQ_UNBOUND)) continue; - /* creating multiple pwqs breaks ordering guarantee */ - if (!list_empty(&wq->pwqs)) { - if (wq->flags & __WQ_ORDERED_EXPLICIT) - continue; - wq->flags &= ~__WQ_ORDERED; - } + if (wq->flags & __WQ_ORDERED) + continue; ctx = apply_wqattrs_prepare(wq, wq->unbound_attrs, unbound_cpumask); if (IS_ERR(ctx)) { diff --git a/lib/kobject.c b/lib/kobject.c index 59dbcbdb1c91..72fa20f405f1 100644 --- a/lib/kobject.c +++ b/lib/kobject.c @@ -74,10 +74,12 @@ static int create_dir(struct kobject *kobj) if (error) return error; - error = sysfs_create_groups(kobj, ktype->default_groups); - if (error) { - sysfs_remove_dir(kobj); - return error; + if (ktype) { + error = sysfs_create_groups(kobj, ktype->default_groups); + if (error) { + sysfs_remove_dir(kobj); + return error; + } } /* @@ -589,7 +591,8 @@ static void __kobject_del(struct kobject *kobj) sd = kobj->sd; ktype = get_ktype(kobj); - sysfs_remove_groups(kobj, ktype->default_groups); + if (ktype) + sysfs_remove_groups(kobj, ktype->default_groups); /* send "remove" if the caller did not do it but sent "add" */ if (kobj->state_add_uevent_sent && !kobj->state_remove_uevent_sent) { @@ -666,6 +669,10 @@ static void kobject_cleanup(struct kobject *kobj) pr_debug("'%s' (%p): %s, parent %p\n", kobject_name(kobj), kobj, __func__, kobj->parent); + if (t && !t->release) + pr_debug("'%s' (%p): does not have a release() function, it is broken and must be fixed. See Documentation/core-api/kobject.rst.\n", + kobject_name(kobj), kobj); + /* remove from sysfs if the caller did not do it */ if (kobj->state_in_sysfs) { pr_debug("'%s' (%p): auto cleanup kobject_del\n", @@ -676,13 +683,10 @@ static void kobject_cleanup(struct kobject *kobj) parent = NULL; } - if (t->release) { + if (t && t->release) { pr_debug("'%s' (%p): calling ktype release\n", kobject_name(kobj), kobj); t->release(kobj); - } else { - pr_debug("'%s' (%p): does not have a release() function, it is broken and must be fixed. See Documentation/core-api/kobject.rst.\n", - kobject_name(kobj), kobj); } /* free name if we allocated it */ @@ -1056,7 +1060,7 @@ const struct kobj_ns_type_operations *kobj_child_ns_ops(const struct kobject *pa { const struct kobj_ns_type_operations *ops = NULL; - if (parent && parent->ktype->child_ns_type) + if (parent && parent->ktype && parent->ktype->child_ns_type) ops = parent->ktype->child_ns_type(parent); return ops; diff --git a/lib/kunit/device-impl.h b/lib/kunit/device-impl.h index 54bd55836405..5fcd48ff0f36 100644 --- a/lib/kunit/device-impl.h +++ b/lib/kunit/device-impl.h @@ -13,5 +13,7 @@ // For internal use only -- registers the kunit_bus. int kunit_bus_init(void); +// For internal use only -- unregisters the kunit_bus. +void kunit_bus_shutdown(void); #endif //_KUNIT_DEVICE_IMPL_H diff --git a/lib/kunit/device.c b/lib/kunit/device.c index 074c6dd2e36a..644a38a1f5b1 100644 --- a/lib/kunit/device.c +++ b/lib/kunit/device.c @@ -54,6 +54,20 @@ int kunit_bus_init(void) return error; } +/* Unregister the 'kunit_bus' in case the KUnit module is unloaded. */ +void kunit_bus_shutdown(void) +{ + /* Make sure the bus exists before we unregister it. */ + if (IS_ERR_OR_NULL(kunit_bus_device)) + return; + + bus_unregister(&kunit_bus_type); + + root_device_unregister(kunit_bus_device); + + kunit_bus_device = NULL; +} + /* Release a 'fake' KUnit device. */ static void kunit_device_release(struct device *d) { diff --git a/lib/kunit/test.c b/lib/kunit/test.c index 31a5a992e646..1d1475578515 100644 --- a/lib/kunit/test.c +++ b/lib/kunit/test.c @@ -928,6 +928,9 @@ static void __exit kunit_exit(void) #ifdef CONFIG_MODULES unregister_module_notifier(&kunit_mod_nb); #endif + + kunit_bus_shutdown(); + kunit_debugfs_cleanup(); } module_exit(kunit_exit); diff --git a/lib/seq_buf.c b/lib/seq_buf.c index 010c730ca7fc..f3f3436d60a9 100644 --- a/lib/seq_buf.c +++ b/lib/seq_buf.c @@ -13,16 +13,26 @@ * seq_buf_init() more than once to reset the seq_buf to start * from scratch. */ -#include <linux/uaccess.h> -#include <linux/seq_file.h> + +#include <linux/bug.h> +#include <linux/err.h> +#include <linux/export.h> +#include <linux/hex.h> +#include <linux/minmax.h> +#include <linux/printk.h> #include <linux/seq_buf.h> +#include <linux/seq_file.h> +#include <linux/sprintf.h> +#include <linux/string.h> +#include <linux/types.h> +#include <linux/uaccess.h> /** * seq_buf_can_fit - can the new data fit in the current buffer? * @s: the seq_buf descriptor * @len: The length to see if it can fit in the current buffer * - * Returns true if there's enough unused space in the seq_buf buffer + * Returns: true if there's enough unused space in the seq_buf buffer * to fit the amount of new data according to @len. */ static bool seq_buf_can_fit(struct seq_buf *s, size_t len) @@ -35,7 +45,7 @@ static bool seq_buf_can_fit(struct seq_buf *s, size_t len) * @m: the seq_file descriptor that is the destination * @s: the seq_buf descriptor that is the source. * - * Returns zero on success, non zero otherwise + * Returns: zero on success, non-zero otherwise. */ int seq_buf_print_seq(struct seq_file *m, struct seq_buf *s) { @@ -50,9 +60,9 @@ int seq_buf_print_seq(struct seq_file *m, struct seq_buf *s) * @fmt: printf format string * @args: va_list of arguments from a printf() type function * - * Writes a vnprintf() format into the sequencce buffer. + * Writes a vnprintf() format into the sequence buffer. * - * Returns zero on success, -1 on overflow. + * Returns: zero on success, -1 on overflow. */ int seq_buf_vprintf(struct seq_buf *s, const char *fmt, va_list args) { @@ -78,7 +88,7 @@ int seq_buf_vprintf(struct seq_buf *s, const char *fmt, va_list args) * * Writes a printf() format into the sequence buffer. * - * Returns zero on success, -1 on overflow. + * Returns: zero on success, -1 on overflow. */ int seq_buf_printf(struct seq_buf *s, const char *fmt, ...) { @@ -94,12 +104,12 @@ int seq_buf_printf(struct seq_buf *s, const char *fmt, ...) EXPORT_SYMBOL_GPL(seq_buf_printf); /** - * seq_buf_do_printk - printk seq_buf line by line + * seq_buf_do_printk - printk() seq_buf line by line * @s: seq_buf descriptor * @lvl: printk level * * printk()-s a multi-line sequential buffer line by line. The function - * makes sure that the buffer in @s is nul terminated and safe to read + * makes sure that the buffer in @s is NUL-terminated and safe to read * as a string. */ void seq_buf_do_printk(struct seq_buf *s, const char *lvl) @@ -139,7 +149,7 @@ EXPORT_SYMBOL_GPL(seq_buf_do_printk); * This function will take the format and the binary array and finish * the conversion into the ASCII string within the buffer. * - * Returns zero on success, -1 on overflow. + * Returns: zero on success, -1 on overflow. */ int seq_buf_bprintf(struct seq_buf *s, const char *fmt, const u32 *binary) { @@ -167,7 +177,7 @@ int seq_buf_bprintf(struct seq_buf *s, const char *fmt, const u32 *binary) * * Copy a simple string into the sequence buffer. * - * Returns zero on success, -1 on overflow + * Returns: zero on success, -1 on overflow. */ int seq_buf_puts(struct seq_buf *s, const char *str) { @@ -196,7 +206,7 @@ EXPORT_SYMBOL_GPL(seq_buf_puts); * * Copy a single character into the sequence buffer. * - * Returns zero on success, -1 on overflow + * Returns: zero on success, -1 on overflow. */ int seq_buf_putc(struct seq_buf *s, unsigned char c) { @@ -212,7 +222,7 @@ int seq_buf_putc(struct seq_buf *s, unsigned char c) EXPORT_SYMBOL_GPL(seq_buf_putc); /** - * seq_buf_putmem - write raw data into the sequenc buffer + * seq_buf_putmem - write raw data into the sequence buffer * @s: seq_buf descriptor * @mem: The raw memory to copy into the buffer * @len: The length of the raw memory to copy (in bytes) @@ -221,7 +231,7 @@ EXPORT_SYMBOL_GPL(seq_buf_putc); * buffer and a strcpy() would not work. Using this function allows * for such cases. * - * Returns zero on success, -1 on overflow + * Returns: zero on success, -1 on overflow. */ int seq_buf_putmem(struct seq_buf *s, const void *mem, unsigned int len) { @@ -249,7 +259,7 @@ int seq_buf_putmem(struct seq_buf *s, const void *mem, unsigned int len) * raw memory into the buffer it writes its ASCII representation of it * in hex characters. * - * Returns zero on success, -1 on overflow + * Returns: zero on success, -1 on overflow. */ int seq_buf_putmem_hex(struct seq_buf *s, const void *mem, unsigned int len) @@ -297,7 +307,7 @@ int seq_buf_putmem_hex(struct seq_buf *s, const void *mem, * * Write a path name into the sequence buffer. * - * Returns the number of written bytes on success, -1 on overflow + * Returns: the number of written bytes on success, -1 on overflow. */ int seq_buf_path(struct seq_buf *s, const struct path *path, const char *esc) { @@ -332,6 +342,7 @@ int seq_buf_path(struct seq_buf *s, const struct path *path, const char *esc) * or until it reaches the end of the content in the buffer (@s->len), * whichever comes first. * + * Returns: * On success, it returns a positive number of the number of bytes * it copied. * @@ -382,11 +393,11 @@ int seq_buf_to_user(struct seq_buf *s, char __user *ubuf, size_t start, int cnt) * linebuf size is maximal length for one line. * 32 * 3 - maximum bytes per line, each printed into 2 chars + 1 for * separating space - * 2 - spaces separating hex dump and ascii representation - * 32 - ascii representation + * 2 - spaces separating hex dump and ASCII representation + * 32 - ASCII representation * 1 - terminating '\0' * - * Returns zero on success, -1 on overflow + * Returns: zero on success, -1 on overflow. */ int seq_buf_hex_dump(struct seq_buf *s, const char *prefix_str, int prefix_type, int rowsize, int groupsize, diff --git a/mm/memory.c b/mm/memory.c index 89bcae0b224d..15f8b10ea17c 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -5478,7 +5478,7 @@ static inline bool get_mmap_lock_carefully(struct mm_struct *mm, struct pt_regs return true; if (regs && !user_mode(regs)) { - unsigned long ip = instruction_pointer(regs); + unsigned long ip = exception_ip(regs); if (!search_exception_tables(ip)) return false; } @@ -5503,7 +5503,7 @@ static inline bool upgrade_mmap_lock_carefully(struct mm_struct *mm, struct pt_r { mmap_read_unlock(mm); if (regs && !user_mode(regs)) { - unsigned long ip = instruction_pointer(regs); + unsigned long ip = exception_ip(regs); if (!search_exception_tables(ip)) return false; } diff --git a/net/6lowpan/core.c b/net/6lowpan/core.c index 7b3341cef926..850d4a185f55 100644 --- a/net/6lowpan/core.c +++ b/net/6lowpan/core.c @@ -179,4 +179,5 @@ static void __exit lowpan_module_exit(void) module_init(lowpan_module_init); module_exit(lowpan_module_exit); +MODULE_DESCRIPTION("IPv6 over Low-Power Wireless Personal Area Network core module"); MODULE_LICENSE("GPL"); diff --git a/net/atm/mpc.c b/net/atm/mpc.c index 033871e718a3..324e3ab96bb3 100644 --- a/net/atm/mpc.c +++ b/net/atm/mpc.c @@ -1532,4 +1532,5 @@ static void __exit atm_mpoa_cleanup(void) module_init(atm_mpoa_init); module_exit(atm_mpoa_cleanup); +MODULE_DESCRIPTION("Multi-Protocol Over ATM (MPOA) driver"); MODULE_LICENSE("GPL"); diff --git a/net/can/j1939/j1939-priv.h b/net/can/j1939/j1939-priv.h index 16af1a7f80f6..31a93cae5111 100644 --- a/net/can/j1939/j1939-priv.h +++ b/net/can/j1939/j1939-priv.h @@ -86,7 +86,7 @@ struct j1939_priv { unsigned int tp_max_packet_size; /* lock for j1939_socks list */ - spinlock_t j1939_socks_lock; + rwlock_t j1939_socks_lock; struct list_head j1939_socks; struct kref rx_kref; @@ -301,6 +301,7 @@ struct j1939_sock { int ifindex; struct j1939_addr addr; + spinlock_t filters_lock; struct j1939_filter *filters; int nfilters; pgn_t pgn_rx_filter; diff --git a/net/can/j1939/main.c b/net/can/j1939/main.c index ecff1c947d68..a6fb89fa6278 100644 --- a/net/can/j1939/main.c +++ b/net/can/j1939/main.c @@ -274,7 +274,7 @@ struct j1939_priv *j1939_netdev_start(struct net_device *ndev) return ERR_PTR(-ENOMEM); j1939_tp_init(priv); - spin_lock_init(&priv->j1939_socks_lock); + rwlock_init(&priv->j1939_socks_lock); INIT_LIST_HEAD(&priv->j1939_socks); mutex_lock(&j1939_netdev_lock); diff --git a/net/can/j1939/socket.c b/net/can/j1939/socket.c index 14c431663233..305dd72c844c 100644 --- a/net/can/j1939/socket.c +++ b/net/can/j1939/socket.c @@ -80,16 +80,16 @@ static void j1939_jsk_add(struct j1939_priv *priv, struct j1939_sock *jsk) jsk->state |= J1939_SOCK_BOUND; j1939_priv_get(priv); - spin_lock_bh(&priv->j1939_socks_lock); + write_lock_bh(&priv->j1939_socks_lock); list_add_tail(&jsk->list, &priv->j1939_socks); - spin_unlock_bh(&priv->j1939_socks_lock); + write_unlock_bh(&priv->j1939_socks_lock); } static void j1939_jsk_del(struct j1939_priv *priv, struct j1939_sock *jsk) { - spin_lock_bh(&priv->j1939_socks_lock); + write_lock_bh(&priv->j1939_socks_lock); list_del_init(&jsk->list); - spin_unlock_bh(&priv->j1939_socks_lock); + write_unlock_bh(&priv->j1939_socks_lock); j1939_priv_put(priv); jsk->state &= ~J1939_SOCK_BOUND; @@ -262,12 +262,17 @@ static bool j1939_sk_match_dst(struct j1939_sock *jsk, static bool j1939_sk_match_filter(struct j1939_sock *jsk, const struct j1939_sk_buff_cb *skcb) { - const struct j1939_filter *f = jsk->filters; - int nfilter = jsk->nfilters; + const struct j1939_filter *f; + int nfilter; + + spin_lock_bh(&jsk->filters_lock); + + f = jsk->filters; + nfilter = jsk->nfilters; if (!nfilter) /* receive all when no filters are assigned */ - return true; + goto filter_match_found; for (; nfilter; ++f, --nfilter) { if ((skcb->addr.pgn & f->pgn_mask) != f->pgn) @@ -276,9 +281,15 @@ static bool j1939_sk_match_filter(struct j1939_sock *jsk, continue; if ((skcb->addr.src_name & f->name_mask) != f->name) continue; - return true; + goto filter_match_found; } + + spin_unlock_bh(&jsk->filters_lock); return false; + +filter_match_found: + spin_unlock_bh(&jsk->filters_lock); + return true; } static bool j1939_sk_recv_match_one(struct j1939_sock *jsk, @@ -329,13 +340,13 @@ bool j1939_sk_recv_match(struct j1939_priv *priv, struct j1939_sk_buff_cb *skcb) struct j1939_sock *jsk; bool match = false; - spin_lock_bh(&priv->j1939_socks_lock); + read_lock_bh(&priv->j1939_socks_lock); list_for_each_entry(jsk, &priv->j1939_socks, list) { match = j1939_sk_recv_match_one(jsk, skcb); if (match) break; } - spin_unlock_bh(&priv->j1939_socks_lock); + read_unlock_bh(&priv->j1939_socks_lock); return match; } @@ -344,11 +355,11 @@ void j1939_sk_recv(struct j1939_priv *priv, struct sk_buff *skb) { struct j1939_sock *jsk; - spin_lock_bh(&priv->j1939_socks_lock); + read_lock_bh(&priv->j1939_socks_lock); list_for_each_entry(jsk, &priv->j1939_socks, list) { j1939_sk_recv_one(jsk, skb); } - spin_unlock_bh(&priv->j1939_socks_lock); + read_unlock_bh(&priv->j1939_socks_lock); } static void j1939_sk_sock_destruct(struct sock *sk) @@ -401,6 +412,7 @@ static int j1939_sk_init(struct sock *sk) atomic_set(&jsk->skb_pending, 0); spin_lock_init(&jsk->sk_session_queue_lock); INIT_LIST_HEAD(&jsk->sk_session_queue); + spin_lock_init(&jsk->filters_lock); /* j1939_sk_sock_destruct() depends on SOCK_RCU_FREE flag */ sock_set_flag(sk, SOCK_RCU_FREE); @@ -703,9 +715,11 @@ static int j1939_sk_setsockopt(struct socket *sock, int level, int optname, } lock_sock(&jsk->sk); + spin_lock_bh(&jsk->filters_lock); ofilters = jsk->filters; jsk->filters = filters; jsk->nfilters = count; + spin_unlock_bh(&jsk->filters_lock); release_sock(&jsk->sk); kfree(ofilters); return 0; @@ -1080,12 +1094,12 @@ void j1939_sk_errqueue(struct j1939_session *session, } /* spread RX notifications to all sockets subscribed to this session */ - spin_lock_bh(&priv->j1939_socks_lock); + read_lock_bh(&priv->j1939_socks_lock); list_for_each_entry(jsk, &priv->j1939_socks, list) { if (j1939_sk_recv_match_one(jsk, &session->skcb)) __j1939_sk_errqueue(session, &jsk->sk, type); } - spin_unlock_bh(&priv->j1939_socks_lock); + read_unlock_bh(&priv->j1939_socks_lock); }; void j1939_sk_send_loop_abort(struct sock *sk, int err) @@ -1273,7 +1287,7 @@ void j1939_sk_netdev_event_netdown(struct j1939_priv *priv) struct j1939_sock *jsk; int error_code = ENETDOWN; - spin_lock_bh(&priv->j1939_socks_lock); + read_lock_bh(&priv->j1939_socks_lock); list_for_each_entry(jsk, &priv->j1939_socks, list) { jsk->sk.sk_err = error_code; if (!sock_flag(&jsk->sk, SOCK_DEAD)) @@ -1281,7 +1295,7 @@ void j1939_sk_netdev_event_netdown(struct j1939_priv *priv) j1939_sk_queue_drop_all(priv, jsk, error_code); } - spin_unlock_bh(&priv->j1939_socks_lock); + read_unlock_bh(&priv->j1939_socks_lock); } static int j1939_sk_no_ioctlcmd(struct socket *sock, unsigned int cmd, diff --git a/net/core/dev.c b/net/core/dev.c index cb2dab0feee0..73a021973007 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -336,7 +336,7 @@ int netdev_name_node_alt_create(struct net_device *dev, const char *name) return -ENOMEM; netdev_name_node_add(net, name_node); /* The node that holds dev->name acts as a head of per-device list. */ - list_add_tail(&name_node->list, &dev->name_node->list); + list_add_tail_rcu(&name_node->list, &dev->name_node->list); return 0; } @@ -11652,11 +11652,12 @@ static void __init net_dev_struct_check(void) CACHELINE_ASSERT_GROUP_SIZE(struct net_device, net_device_read_tx, 160); /* TXRX read-mostly hotpath */ + CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_txrx, lstats); CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_txrx, flags); CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_txrx, hard_header_len); CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_txrx, features); CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_txrx, ip6_ptr); - CACHELINE_ASSERT_GROUP_SIZE(struct net_device, net_device_read_txrx, 30); + CACHELINE_ASSERT_GROUP_SIZE(struct net_device, net_device_read_txrx, 38); /* RX read-mostly hotpath */ CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_rx, ptype_specific); diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index f6f29eb03ec2..9c4f427f3a50 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -1020,14 +1020,17 @@ static size_t rtnl_xdp_size(void) static size_t rtnl_prop_list_size(const struct net_device *dev) { struct netdev_name_node *name_node; - size_t size; + unsigned int cnt = 0; + + rcu_read_lock(); + list_for_each_entry_rcu(name_node, &dev->name_node->list, list) + cnt++; + rcu_read_unlock(); - if (list_empty(&dev->name_node->list)) + if (!cnt) return 0; - size = nla_total_size(0); - list_for_each_entry(name_node, &dev->name_node->list, list) - size += nla_total_size(ALTIFNAMSIZ); - return size; + + return nla_total_size(0) + cnt * nla_total_size(ALTIFNAMSIZ); } static size_t rtnl_proto_down_size(const struct net_device *dev) diff --git a/net/handshake/handshake-test.c b/net/handshake/handshake-test.c index 16ed7bfd29e4..34fd1d9b2db8 100644 --- a/net/handshake/handshake-test.c +++ b/net/handshake/handshake-test.c @@ -471,7 +471,10 @@ static void handshake_req_destroy_test1(struct kunit *test) handshake_req_cancel(sock->sk); /* Act */ - fput(filp); + /* Ensure the close/release/put process has run to + * completion before checking the result. + */ + __fput_sync(filp); /* Assert */ KUNIT_EXPECT_PTR_EQ(test, handshake_req_destroy_test, req); diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c index a2e6e1fdf82b..64aec3dff8ec 100644 --- a/net/ipv4/ah4.c +++ b/net/ipv4/ah4.c @@ -597,5 +597,6 @@ static void __exit ah4_fini(void) module_init(ah4_init); module_exit(ah4_fini); +MODULE_DESCRIPTION("IPv4 AH transformation library"); MODULE_LICENSE("GPL"); MODULE_ALIAS_XFRM_TYPE(AF_INET, XFRM_PROTO_AH); diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c index 4ccfc104f13a..4dd9e5040672 100644 --- a/net/ipv4/esp4.c +++ b/net/ipv4/esp4.c @@ -1247,5 +1247,6 @@ static void __exit esp4_fini(void) module_init(esp4_init); module_exit(esp4_fini); +MODULE_DESCRIPTION("IPv4 ESP transformation library"); MODULE_LICENSE("GPL"); MODULE_ALIAS_XFRM_TYPE(AF_INET, XFRM_PROTO_ESP); diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 5169c3c72cff..6b9cf5a24c19 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -1793,6 +1793,7 @@ static void __exit ipgre_fini(void) module_init(ipgre_init); module_exit(ipgre_fini); +MODULE_DESCRIPTION("IPv4 GRE tunnels over IP library"); MODULE_LICENSE("GPL"); MODULE_ALIAS_RTNL_LINK("gre"); MODULE_ALIAS_RTNL_LINK("gretap"); diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 41537d18eecf..67d846622365 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -972,8 +972,8 @@ static int __ip_append_data(struct sock *sk, unsigned int maxfraglen, fragheaderlen, maxnonfragsize; int csummode = CHECKSUM_NONE; struct rtable *rt = (struct rtable *)cork->dst; + bool paged, hold_tskey, extra_uref = false; unsigned int wmem_alloc_delta = 0; - bool paged, extra_uref = false; u32 tskey = 0; skb = skb_peek_tail(queue); @@ -982,10 +982,6 @@ static int __ip_append_data(struct sock *sk, mtu = cork->gso_size ? IP_MAX_MTU : cork->fragsize; paged = !!cork->gso_size; - if (cork->tx_flags & SKBTX_ANY_TSTAMP && - READ_ONCE(sk->sk_tsflags) & SOF_TIMESTAMPING_OPT_ID) - tskey = atomic_inc_return(&sk->sk_tskey) - 1; - hh_len = LL_RESERVED_SPACE(rt->dst.dev); fragheaderlen = sizeof(struct iphdr) + (opt ? opt->optlen : 0); @@ -1052,6 +1048,11 @@ static int __ip_append_data(struct sock *sk, cork->length += length; + hold_tskey = cork->tx_flags & SKBTX_ANY_TSTAMP && + READ_ONCE(sk->sk_tsflags) & SOF_TIMESTAMPING_OPT_ID; + if (hold_tskey) + tskey = atomic_inc_return(&sk->sk_tskey) - 1; + /* So, what's going on in the loop below? * * We use calculated fragment length to generate chained skb, @@ -1274,6 +1275,8 @@ error: cork->length -= length; IP_INC_STATS(sock_net(sk), IPSTATS_MIB_OUTDISCARDS); refcount_add(wmem_alloc_delta, &sk->sk_wmem_alloc); + if (hold_tskey) + atomic_dec(&sk->sk_tskey); return err; } diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c index beeae624c412..a4513ffb66cb 100644 --- a/net/ipv4/ip_tunnel.c +++ b/net/ipv4/ip_tunnel.c @@ -1298,4 +1298,5 @@ void ip_tunnel_setup(struct net_device *dev, unsigned int net_id) } EXPORT_SYMBOL_GPL(ip_tunnel_setup); +MODULE_DESCRIPTION("IPv4 tunnel implementation library"); MODULE_LICENSE("GPL"); diff --git a/net/ipv4/ip_vti.c b/net/ipv4/ip_vti.c index 9ab9b3ebe0cd..d1d6bb28ed6e 100644 --- a/net/ipv4/ip_vti.c +++ b/net/ipv4/ip_vti.c @@ -721,6 +721,7 @@ static void __exit vti_fini(void) module_init(vti_init); module_exit(vti_fini); +MODULE_DESCRIPTION("Virtual (secure) IP tunneling library"); MODULE_LICENSE("GPL"); MODULE_ALIAS_RTNL_LINK("vti"); MODULE_ALIAS_NETDEV("ip_vti0"); diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index 27b8f83c6ea2..03afa3871efc 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c @@ -658,6 +658,7 @@ static void __exit ipip_fini(void) module_init(ipip_init); module_exit(ipip_fini); +MODULE_DESCRIPTION("IP/IP protocol decoder library"); MODULE_LICENSE("GPL"); MODULE_ALIAS_RTNL_LINK("ipip"); MODULE_ALIAS_NETDEV("tunl0"); diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 7e2481b9eae1..c82dc42f57c6 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -4615,7 +4615,8 @@ static void __init tcp_struct_check(void) CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_read_txrx, prr_out); CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_read_txrx, lost_out); CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_read_txrx, sacked_out); - CACHELINE_ASSERT_GROUP_SIZE(struct tcp_sock, tcp_sock_read_txrx, 31); + CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_read_txrx, scaling_ratio); + CACHELINE_ASSERT_GROUP_SIZE(struct tcp_sock, tcp_sock_read_txrx, 32); /* RX read-mostly hotpath cache lines */ CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_read_rx, copied_seq); diff --git a/net/ipv4/tunnel4.c b/net/ipv4/tunnel4.c index 5048c47c79b2..4c1f836aae38 100644 --- a/net/ipv4/tunnel4.c +++ b/net/ipv4/tunnel4.c @@ -294,4 +294,5 @@ static void __exit tunnel4_fini(void) module_init(tunnel4_init); module_exit(tunnel4_fini); +MODULE_DESCRIPTION("IPv4 XFRM tunnel library"); MODULE_LICENSE("GPL"); diff --git a/net/ipv4/udp_tunnel_core.c b/net/ipv4/udp_tunnel_core.c index a87defb2b167..860aff5f8599 100644 --- a/net/ipv4/udp_tunnel_core.c +++ b/net/ipv4/udp_tunnel_core.c @@ -253,4 +253,5 @@ struct rtable *udp_tunnel_dst_lookup(struct sk_buff *skb, } EXPORT_SYMBOL_GPL(udp_tunnel_dst_lookup); +MODULE_DESCRIPTION("IPv4 Foo over UDP tunnel driver"); MODULE_LICENSE("GPL"); diff --git a/net/ipv4/xfrm4_tunnel.c b/net/ipv4/xfrm4_tunnel.c index 8489fa106583..8cb266af1393 100644 --- a/net/ipv4/xfrm4_tunnel.c +++ b/net/ipv4/xfrm4_tunnel.c @@ -114,5 +114,6 @@ static void __exit ipip_fini(void) module_init(ipip_init); module_exit(ipip_fini); +MODULE_DESCRIPTION("IPv4 XFRM tunnel driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS_XFRM_TYPE(AF_INET, XFRM_PROTO_IPIP); diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c index 2016e90e6e1d..eb474f0987ae 100644 --- a/net/ipv6/ah6.c +++ b/net/ipv6/ah6.c @@ -800,5 +800,6 @@ static void __exit ah6_fini(void) module_init(ah6_init); module_exit(ah6_fini); +MODULE_DESCRIPTION("IPv6 AH transformation helpers"); MODULE_LICENSE("GPL"); MODULE_ALIAS_XFRM_TYPE(AF_INET6, XFRM_PROTO_AH); diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c index 2cc1a45742d8..6e6efe026cdc 100644 --- a/net/ipv6/esp6.c +++ b/net/ipv6/esp6.c @@ -1301,5 +1301,6 @@ static void __exit esp6_fini(void) module_init(esp6_init); module_exit(esp6_fini); +MODULE_DESCRIPTION("IPv6 ESP transformation helpers"); MODULE_LICENSE("GPL"); MODULE_ALIAS_XFRM_TYPE(AF_INET6, XFRM_PROTO_ESP); diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index a722a43dd668..31b86fe661aa 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -1424,11 +1424,11 @@ static int __ip6_append_data(struct sock *sk, bool zc = false; u32 tskey = 0; struct rt6_info *rt = (struct rt6_info *)cork->dst; + bool paged, hold_tskey, extra_uref = false; struct ipv6_txoptions *opt = v6_cork->opt; int csummode = CHECKSUM_NONE; unsigned int maxnonfragsize, headersize; unsigned int wmem_alloc_delta = 0; - bool paged, extra_uref = false; skb = skb_peek_tail(queue); if (!skb) { @@ -1440,10 +1440,6 @@ static int __ip6_append_data(struct sock *sk, mtu = cork->gso_size ? IP6_MAX_MTU : cork->fragsize; orig_mtu = mtu; - if (cork->tx_flags & SKBTX_ANY_TSTAMP && - READ_ONCE(sk->sk_tsflags) & SOF_TIMESTAMPING_OPT_ID) - tskey = atomic_inc_return(&sk->sk_tskey) - 1; - hh_len = LL_RESERVED_SPACE(rt->dst.dev); fragheaderlen = sizeof(struct ipv6hdr) + rt->rt6i_nfheader_len + @@ -1538,6 +1534,11 @@ emsgsize: flags &= ~MSG_SPLICE_PAGES; } + hold_tskey = cork->tx_flags & SKBTX_ANY_TSTAMP && + READ_ONCE(sk->sk_tsflags) & SOF_TIMESTAMPING_OPT_ID; + if (hold_tskey) + tskey = atomic_inc_return(&sk->sk_tskey) - 1; + /* * Let's try using as much space as possible. * Use MTU if total length of the message fits into the MTU. @@ -1794,6 +1795,8 @@ error: cork->length -= length; IP6_INC_STATS(sock_net(sk), rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS); refcount_add(wmem_alloc_delta, &sk->sk_wmem_alloc); + if (hold_tskey) + atomic_dec(&sk->sk_tskey); return err; } diff --git a/net/ipv6/ip6_udp_tunnel.c b/net/ipv6/ip6_udp_tunnel.c index a7bf0327b380..c99053189ea8 100644 --- a/net/ipv6/ip6_udp_tunnel.c +++ b/net/ipv6/ip6_udp_tunnel.c @@ -182,4 +182,5 @@ struct dst_entry *udp_tunnel6_dst_lookup(struct sk_buff *skb, } EXPORT_SYMBOL_GPL(udp_tunnel6_dst_lookup); +MODULE_DESCRIPTION("IPv6 Foo over UDP tunnel driver"); MODULE_LICENSE("GPL"); diff --git a/net/ipv6/mip6.c b/net/ipv6/mip6.c index 83d2a8be263f..6a16a5bd0d91 100644 --- a/net/ipv6/mip6.c +++ b/net/ipv6/mip6.c @@ -405,6 +405,7 @@ static void __exit mip6_fini(void) module_init(mip6_init); module_exit(mip6_fini); +MODULE_DESCRIPTION("IPv6 Mobility driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS_XFRM_TYPE(AF_INET6, XFRM_PROTO_DSTOPTS); MODULE_ALIAS_XFRM_TYPE(AF_INET6, XFRM_PROTO_ROUTING); diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index cc24cefdb85c..5e9f625b76e3 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -1956,6 +1956,7 @@ xfrm_tunnel_failed: module_init(sit_init); module_exit(sit_cleanup); +MODULE_DESCRIPTION("IPv6-in-IPv4 tunnel SIT driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS_RTNL_LINK("sit"); MODULE_ALIAS_NETDEV("sit0"); diff --git a/net/ipv6/tunnel6.c b/net/ipv6/tunnel6.c index 00e8d8b1c9a7..dc4ea9b11794 100644 --- a/net/ipv6/tunnel6.c +++ b/net/ipv6/tunnel6.c @@ -302,4 +302,5 @@ static void __exit tunnel6_fini(void) module_init(tunnel6_init); module_exit(tunnel6_fini); +MODULE_DESCRIPTION("IP-in-IPv6 tunnel driver"); MODULE_LICENSE("GPL"); diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c index 1323f2f6928e..f6cb94f82cc3 100644 --- a/net/ipv6/xfrm6_tunnel.c +++ b/net/ipv6/xfrm6_tunnel.c @@ -401,5 +401,6 @@ static void __exit xfrm6_tunnel_fini(void) module_init(xfrm6_tunnel_init); module_exit(xfrm6_tunnel_fini); +MODULE_DESCRIPTION("IPv6 XFRM tunnel driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS_XFRM_TYPE(AF_INET6, XFRM_PROTO_IPV6); diff --git a/net/key/af_key.c b/net/key/af_key.c index d68d01804dc7..f79fb99271ed 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -3924,5 +3924,6 @@ out_unregister_key_proto: module_init(ipsec_pfkey_init); module_exit(ipsec_pfkey_exit); +MODULE_DESCRIPTION("PF_KEY socket helpers"); MODULE_LICENSE("GPL"); MODULE_ALIAS_NETPROTO(PF_KEY); diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index e448ab338448..6fbb15b65902 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -5,7 +5,7 @@ * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> * Copyright 2007 Johannes Berg <johannes@sipsolutions.net> * Copyright 2013-2014 Intel Mobile Communications GmbH - * Copyright (C) 2018-2022 Intel Corporation + * Copyright (C) 2018-2024 Intel Corporation * * Transmit and frame generation functions. */ @@ -3927,6 +3927,7 @@ begin: goto begin; skb = __skb_dequeue(&tx.skbs); + info = IEEE80211_SKB_CB(skb); if (!skb_queue_empty(&tx.skbs)) { spin_lock_bh(&fq->lock); @@ -3971,7 +3972,7 @@ begin: } encap_out: - IEEE80211_SKB_CB(skb)->control.vif = vif; + info->control.vif = vif; if (tx.sta && wiphy_ext_feature_isset(local->hw.wiphy, NL80211_EXT_FEATURE_AQL)) { diff --git a/net/mptcp/fastopen.c b/net/mptcp/fastopen.c index 74698582a285..ad28da655f8b 100644 --- a/net/mptcp/fastopen.c +++ b/net/mptcp/fastopen.c @@ -59,13 +59,12 @@ void mptcp_fastopen_subflow_synack_set_params(struct mptcp_subflow_context *subf mptcp_data_unlock(sk); } -void mptcp_fastopen_gen_msk_ackseq(struct mptcp_sock *msk, struct mptcp_subflow_context *subflow, - const struct mptcp_options_received *mp_opt) +void __mptcp_fastopen_gen_msk_ackseq(struct mptcp_sock *msk, struct mptcp_subflow_context *subflow, + const struct mptcp_options_received *mp_opt) { struct sock *sk = (struct sock *)msk; struct sk_buff *skb; - mptcp_data_lock(sk); skb = skb_peek_tail(&sk->sk_receive_queue); if (skb) { WARN_ON_ONCE(MPTCP_SKB_CB(skb)->end_seq); @@ -77,5 +76,4 @@ void mptcp_fastopen_gen_msk_ackseq(struct mptcp_sock *msk, struct mptcp_subflow_ } pr_debug("msk=%p ack_seq=%llx", msk, msk->ack_seq); - mptcp_data_unlock(sk); } diff --git a/net/mptcp/options.c b/net/mptcp/options.c index d2527d189a79..e3e96a49f922 100644 --- a/net/mptcp/options.c +++ b/net/mptcp/options.c @@ -962,9 +962,7 @@ static bool check_fully_established(struct mptcp_sock *msk, struct sock *ssk, /* subflows are fully established as soon as we get any * additional ack, including ADD_ADDR. */ - subflow->fully_established = 1; - WRITE_ONCE(msk->fully_established, true); - goto check_notify; + goto set_fully_established; } /* If the first established packet does not contain MP_CAPABLE + data @@ -986,7 +984,10 @@ static bool check_fully_established(struct mptcp_sock *msk, struct sock *ssk, set_fully_established: if (unlikely(!READ_ONCE(msk->pm.server_side))) pr_warn_once("bogus mpc option on established client sk"); - mptcp_subflow_fully_established(subflow, mp_opt); + + mptcp_data_lock((struct sock *)msk); + __mptcp_subflow_fully_established(msk, subflow, mp_opt); + mptcp_data_unlock((struct sock *)msk); check_notify: /* if the subflow is not already linked into the conn_list, we can't diff --git a/net/mptcp/pm_userspace.c b/net/mptcp/pm_userspace.c index efecbe3cf415..4f3901d5b8ef 100644 --- a/net/mptcp/pm_userspace.c +++ b/net/mptcp/pm_userspace.c @@ -130,10 +130,21 @@ int mptcp_userspace_pm_get_flags_and_ifindex_by_id(struct mptcp_sock *msk, int mptcp_userspace_pm_get_local_id(struct mptcp_sock *msk, struct mptcp_addr_info *skc) { - struct mptcp_pm_addr_entry new_entry; + struct mptcp_pm_addr_entry *entry = NULL, *e, new_entry; __be16 msk_sport = ((struct inet_sock *) inet_sk((struct sock *)msk))->inet_sport; + spin_lock_bh(&msk->pm.lock); + list_for_each_entry(e, &msk->pm.userspace_pm_local_addr_list, list) { + if (mptcp_addresses_equal(&e->addr, skc, false)) { + entry = e; + break; + } + } + spin_unlock_bh(&msk->pm.lock); + if (entry) + return entry->addr.id; + memset(&new_entry, 0, sizeof(struct mptcp_pm_addr_entry)); new_entry.addr = *skc; new_entry.addr.id = 0; diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index 028e8b473626..8ef2927ebca2 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -1505,8 +1505,11 @@ static void mptcp_update_post_push(struct mptcp_sock *msk, void mptcp_check_and_set_pending(struct sock *sk) { - if (mptcp_send_head(sk)) - mptcp_sk(sk)->push_pending |= BIT(MPTCP_PUSH_PENDING); + if (mptcp_send_head(sk)) { + mptcp_data_lock(sk); + mptcp_sk(sk)->cb_flags |= BIT(MPTCP_PUSH_PENDING); + mptcp_data_unlock(sk); + } } static int __subflow_push_pending(struct sock *sk, struct sock *ssk, @@ -1960,6 +1963,9 @@ static void mptcp_rcv_space_adjust(struct mptcp_sock *msk, int copied) if (copied <= 0) return; + if (!msk->rcvspace_init) + mptcp_rcv_space_init(msk, msk->first); + msk->rcvq_space.copied += copied; mstamp = div_u64(tcp_clock_ns(), NSEC_PER_USEC); @@ -3142,7 +3148,6 @@ static int mptcp_disconnect(struct sock *sk, int flags) mptcp_destroy_common(msk, MPTCP_CF_FASTCLOSE); WRITE_ONCE(msk->flags, 0); msk->cb_flags = 0; - msk->push_pending = 0; msk->recovery = false; msk->can_ack = false; msk->fully_established = false; @@ -3158,6 +3163,7 @@ static int mptcp_disconnect(struct sock *sk, int flags) msk->bytes_received = 0; msk->bytes_sent = 0; msk->bytes_retrans = 0; + msk->rcvspace_init = 0; WRITE_ONCE(sk->sk_shutdown, 0); sk_error_report(sk); @@ -3180,6 +3186,7 @@ struct sock *mptcp_sk_clone_init(const struct sock *sk, { struct mptcp_subflow_request_sock *subflow_req = mptcp_subflow_rsk(req); struct sock *nsk = sk_clone_lock(sk, GFP_ATOMIC); + struct mptcp_subflow_context *subflow; struct mptcp_sock *msk; if (!nsk) @@ -3220,7 +3227,8 @@ struct sock *mptcp_sk_clone_init(const struct sock *sk, /* The msk maintain a ref to each subflow in the connections list */ WRITE_ONCE(msk->first, ssk); - list_add(&mptcp_subflow_ctx(ssk)->node, &msk->conn_list); + subflow = mptcp_subflow_ctx(ssk); + list_add(&subflow->node, &msk->conn_list); sock_hold(ssk); /* new mpc subflow takes ownership of the newly @@ -3235,6 +3243,9 @@ struct sock *mptcp_sk_clone_init(const struct sock *sk, __mptcp_propagate_sndbuf(nsk, ssk); mptcp_rcv_space_init(msk, ssk); + + if (mp_opt->suboptions & OPTION_MPTCP_MPC_ACK) + __mptcp_subflow_fully_established(msk, subflow, mp_opt); bh_unlock_sock(nsk); /* note: the newly allocated socket refcount is 2 now */ @@ -3245,6 +3256,7 @@ void mptcp_rcv_space_init(struct mptcp_sock *msk, const struct sock *ssk) { const struct tcp_sock *tp = tcp_sk(ssk); + msk->rcvspace_init = 1; msk->rcvq_space.copied = 0; msk->rcvq_space.rtt_us = 0; @@ -3255,8 +3267,6 @@ void mptcp_rcv_space_init(struct mptcp_sock *msk, const struct sock *ssk) TCP_INIT_CWND * tp->advmss); if (msk->rcvq_space.space == 0) msk->rcvq_space.space = TCP_INIT_CWND * TCP_MSS_DEFAULT; - - WRITE_ONCE(msk->wnd_end, msk->snd_nxt + tcp_sk(ssk)->snd_wnd); } void mptcp_destroy_common(struct mptcp_sock *msk, unsigned int flags) @@ -3330,8 +3340,7 @@ static void mptcp_release_cb(struct sock *sk) struct mptcp_sock *msk = mptcp_sk(sk); for (;;) { - unsigned long flags = (msk->cb_flags & MPTCP_FLAGS_PROCESS_CTX_NEED) | - msk->push_pending; + unsigned long flags = (msk->cb_flags & MPTCP_FLAGS_PROCESS_CTX_NEED); struct list_head join_list; if (!flags) @@ -3347,7 +3356,6 @@ static void mptcp_release_cb(struct sock *sk) * datapath acquires the msk socket spinlock while helding * the subflow socket lock */ - msk->push_pending = 0; msk->cb_flags &= ~flags; spin_unlock_bh(&sk->sk_lock.slock); @@ -3475,13 +3483,8 @@ void mptcp_finish_connect(struct sock *ssk) * accessing the field below */ WRITE_ONCE(msk->local_key, subflow->local_key); - WRITE_ONCE(msk->write_seq, subflow->idsn + 1); - WRITE_ONCE(msk->snd_nxt, msk->write_seq); - WRITE_ONCE(msk->snd_una, msk->write_seq); mptcp_pm_new_connection(msk, ssk, 0); - - mptcp_rcv_space_init(msk, ssk); } void mptcp_sock_graft(struct sock *sk, struct socket *parent) diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index 3517f2d24a22..ed50f2015dc3 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -286,7 +286,6 @@ struct mptcp_sock { int rmem_released; unsigned long flags; unsigned long cb_flags; - unsigned long push_pending; bool recovery; /* closing subflow write queue reinjected */ bool can_ack; bool fully_established; @@ -305,7 +304,8 @@ struct mptcp_sock { nodelay:1, fastopening:1, in_accept_queue:1, - free_first:1; + free_first:1, + rcvspace_init:1; struct work_struct work; struct sk_buff *ooo_last_skb; struct rb_root out_of_order_queue; @@ -622,8 +622,9 @@ unsigned int mptcp_stale_loss_cnt(const struct net *net); unsigned int mptcp_close_timeout(const struct sock *sk); int mptcp_get_pm_type(const struct net *net); const char *mptcp_get_scheduler(const struct net *net); -void mptcp_subflow_fully_established(struct mptcp_subflow_context *subflow, - const struct mptcp_options_received *mp_opt); +void __mptcp_subflow_fully_established(struct mptcp_sock *msk, + struct mptcp_subflow_context *subflow, + const struct mptcp_options_received *mp_opt); bool __mptcp_retransmit_pending_data(struct sock *sk); void mptcp_check_and_set_pending(struct sock *sk); void __mptcp_push_pending(struct sock *sk, unsigned int flags); @@ -952,8 +953,8 @@ void mptcp_event_pm_listener(const struct sock *ssk, enum mptcp_event_type event); bool mptcp_userspace_pm_active(const struct mptcp_sock *msk); -void mptcp_fastopen_gen_msk_ackseq(struct mptcp_sock *msk, struct mptcp_subflow_context *subflow, - const struct mptcp_options_received *mp_opt); +void __mptcp_fastopen_gen_msk_ackseq(struct mptcp_sock *msk, struct mptcp_subflow_context *subflow, + const struct mptcp_options_received *mp_opt); void mptcp_fastopen_subflow_synack_set_params(struct mptcp_subflow_context *subflow, struct request_sock *req); @@ -1128,7 +1129,8 @@ static inline bool subflow_simultaneous_connect(struct sock *sk) { struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk); - return (1 << sk->sk_state) & (TCPF_ESTABLISHED | TCPF_FIN_WAIT1) && + return (1 << sk->sk_state) & + (TCPF_ESTABLISHED | TCPF_FIN_WAIT1 | TCPF_FIN_WAIT2 | TCPF_CLOSING) && is_active_ssk(subflow) && !subflow->conn_finished; } diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c index 0dcb721c89d1..c34ecadee120 100644 --- a/net/mptcp/subflow.c +++ b/net/mptcp/subflow.c @@ -421,29 +421,26 @@ static bool subflow_use_different_dport(struct mptcp_sock *msk, const struct soc void __mptcp_sync_state(struct sock *sk, int state) { + struct mptcp_subflow_context *subflow; struct mptcp_sock *msk = mptcp_sk(sk); + struct sock *ssk = msk->first; + + subflow = mptcp_subflow_ctx(ssk); + __mptcp_propagate_sndbuf(sk, ssk); + if (!msk->rcvspace_init) + mptcp_rcv_space_init(msk, ssk); - __mptcp_propagate_sndbuf(sk, msk->first); if (sk->sk_state == TCP_SYN_SENT) { + /* subflow->idsn is always available is TCP_SYN_SENT state, + * even for the FASTOPEN scenarios + */ + WRITE_ONCE(msk->write_seq, subflow->idsn + 1); + WRITE_ONCE(msk->snd_nxt, msk->write_seq); mptcp_set_state(sk, state); sk->sk_state_change(sk); } } -static void mptcp_propagate_state(struct sock *sk, struct sock *ssk) -{ - struct mptcp_sock *msk = mptcp_sk(sk); - - mptcp_data_lock(sk); - if (!sock_owned_by_user(sk)) { - __mptcp_sync_state(sk, ssk->sk_state); - } else { - msk->pending_state = ssk->sk_state; - __set_bit(MPTCP_SYNC_STATE, &msk->cb_flags); - } - mptcp_data_unlock(sk); -} - static void subflow_set_remote_key(struct mptcp_sock *msk, struct mptcp_subflow_context *subflow, const struct mptcp_options_received *mp_opt) @@ -465,6 +462,31 @@ static void subflow_set_remote_key(struct mptcp_sock *msk, atomic64_set(&msk->rcv_wnd_sent, subflow->iasn); } +static void mptcp_propagate_state(struct sock *sk, struct sock *ssk, + struct mptcp_subflow_context *subflow, + const struct mptcp_options_received *mp_opt) +{ + struct mptcp_sock *msk = mptcp_sk(sk); + + mptcp_data_lock(sk); + if (mp_opt) { + /* Options are available only in the non fallback cases + * avoid updating rx path fields otherwise + */ + WRITE_ONCE(msk->snd_una, subflow->idsn + 1); + WRITE_ONCE(msk->wnd_end, subflow->idsn + 1 + tcp_sk(ssk)->snd_wnd); + subflow_set_remote_key(msk, subflow, mp_opt); + } + + if (!sock_owned_by_user(sk)) { + __mptcp_sync_state(sk, ssk->sk_state); + } else { + msk->pending_state = ssk->sk_state; + __set_bit(MPTCP_SYNC_STATE, &msk->cb_flags); + } + mptcp_data_unlock(sk); +} + static void subflow_finish_connect(struct sock *sk, const struct sk_buff *skb) { struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk); @@ -499,10 +521,9 @@ static void subflow_finish_connect(struct sock *sk, const struct sk_buff *skb) if (mp_opt.deny_join_id0) WRITE_ONCE(msk->pm.remote_deny_join_id0, true); subflow->mp_capable = 1; - subflow_set_remote_key(msk, subflow, &mp_opt); MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_MPCAPABLEACTIVEACK); mptcp_finish_connect(sk); - mptcp_propagate_state(parent, sk); + mptcp_propagate_state(parent, sk, subflow, &mp_opt); } else if (subflow->request_join) { u8 hmac[SHA256_DIGEST_SIZE]; @@ -545,8 +566,7 @@ static void subflow_finish_connect(struct sock *sk, const struct sk_buff *skb) } } else if (mptcp_check_fallback(sk)) { fallback: - mptcp_rcv_space_init(msk, sk); - mptcp_propagate_state(parent, sk); + mptcp_propagate_state(parent, sk, subflow, NULL); } return; @@ -731,17 +751,16 @@ void mptcp_subflow_drop_ctx(struct sock *ssk) kfree_rcu(ctx, rcu); } -void mptcp_subflow_fully_established(struct mptcp_subflow_context *subflow, - const struct mptcp_options_received *mp_opt) +void __mptcp_subflow_fully_established(struct mptcp_sock *msk, + struct mptcp_subflow_context *subflow, + const struct mptcp_options_received *mp_opt) { - struct mptcp_sock *msk = mptcp_sk(subflow->conn); - subflow_set_remote_key(msk, subflow, mp_opt); subflow->fully_established = 1; WRITE_ONCE(msk->fully_established, true); if (subflow->is_mptfo) - mptcp_fastopen_gen_msk_ackseq(msk, subflow, mp_opt); + __mptcp_fastopen_gen_msk_ackseq(msk, subflow, mp_opt); } static struct sock *subflow_syn_recv_sock(const struct sock *sk, @@ -834,7 +853,6 @@ create_child: * mpc option */ if (mp_opt.suboptions & OPTION_MPTCP_MPC_ACK) { - mptcp_subflow_fully_established(ctx, &mp_opt); mptcp_pm_fully_established(owner, child); ctx->pm_notified = 1; } @@ -1744,10 +1762,9 @@ static void subflow_state_change(struct sock *sk) msk = mptcp_sk(parent); if (subflow_simultaneous_connect(sk)) { mptcp_do_fallback(sk); - mptcp_rcv_space_init(msk, sk); pr_fallback(msk); subflow->conn_finished = 1; - mptcp_propagate_state(parent, sk); + mptcp_propagate_state(parent, sk, subflow, NULL); } /* as recvmsg() does not acquire the subflow socket for ssk selection diff --git a/net/netfilter/nf_nat_core.c b/net/netfilter/nf_nat_core.c index c3d7ecbc777c..016c816d91cb 100644 --- a/net/netfilter/nf_nat_core.c +++ b/net/netfilter/nf_nat_core.c @@ -551,8 +551,11 @@ static void nf_nat_l4proto_unique_tuple(struct nf_conntrack_tuple *tuple, find_free_id: if (range->flags & NF_NAT_RANGE_PROTO_OFFSET) off = (ntohs(*keyptr) - ntohs(range->base_proto.all)); - else + else if ((range->flags & NF_NAT_RANGE_PROTO_RANDOM_ALL) || + maniptype != NF_NAT_MANIP_DST) off = get_random_u16(); + else + off = 0; attempts = range_size; if (attempts > NF_NAT_MAX_ATTEMPTS) diff --git a/net/netfilter/nft_flow_offload.c b/net/netfilter/nft_flow_offload.c index 397351fa4d5f..ab9576098701 100644 --- a/net/netfilter/nft_flow_offload.c +++ b/net/netfilter/nft_flow_offload.c @@ -361,6 +361,7 @@ static void nft_flow_offload_eval(const struct nft_expr *expr, ct->proto.tcp.seen[1].flags |= IP_CT_TCP_FLAG_BE_LIBERAL; } + __set_bit(NF_FLOW_HW_BIDIRECTIONAL, &flow->flags); ret = flow_offload_add(flowtable, flow); if (ret < 0) goto err_flow_add; diff --git a/net/netfilter/nft_set_pipapo.h b/net/netfilter/nft_set_pipapo.h index f59a0cd81105..3842c7341a9f 100644 --- a/net/netfilter/nft_set_pipapo.h +++ b/net/netfilter/nft_set_pipapo.h @@ -144,10 +144,10 @@ struct nft_pipapo_scratch { /** * struct nft_pipapo_match - Data used for lookup and matching - * @field_count Amount of fields in set + * @field_count: Amount of fields in set * @scratch: Preallocated per-CPU maps for partial matching results * @bsize_max: Maximum lookup table bucket size of all fields, in longs - * @rcu Matching data is swapped on commits + * @rcu: Matching data is swapped on commits * @f: Fields, with lookup and mapping tables */ struct nft_pipapo_match { diff --git a/net/openvswitch/flow_netlink.c b/net/openvswitch/flow_netlink.c index 88965e2068ac..ebc5728aab4e 100644 --- a/net/openvswitch/flow_netlink.c +++ b/net/openvswitch/flow_netlink.c @@ -48,6 +48,7 @@ struct ovs_len_tbl { #define OVS_ATTR_NESTED -1 #define OVS_ATTR_VARIABLE -2 +#define OVS_COPY_ACTIONS_MAX_DEPTH 16 static bool actions_may_change_flow(const struct nlattr *actions) { @@ -2545,13 +2546,15 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr, const struct sw_flow_key *key, struct sw_flow_actions **sfa, __be16 eth_type, __be16 vlan_tci, - u32 mpls_label_count, bool log); + u32 mpls_label_count, bool log, + u32 depth); static int validate_and_copy_sample(struct net *net, const struct nlattr *attr, const struct sw_flow_key *key, struct sw_flow_actions **sfa, __be16 eth_type, __be16 vlan_tci, - u32 mpls_label_count, bool log, bool last) + u32 mpls_label_count, bool log, bool last, + u32 depth) { const struct nlattr *attrs[OVS_SAMPLE_ATTR_MAX + 1]; const struct nlattr *probability, *actions; @@ -2602,7 +2605,8 @@ static int validate_and_copy_sample(struct net *net, const struct nlattr *attr, return err; err = __ovs_nla_copy_actions(net, actions, key, sfa, - eth_type, vlan_tci, mpls_label_count, log); + eth_type, vlan_tci, mpls_label_count, log, + depth + 1); if (err) return err; @@ -2617,7 +2621,8 @@ static int validate_and_copy_dec_ttl(struct net *net, const struct sw_flow_key *key, struct sw_flow_actions **sfa, __be16 eth_type, __be16 vlan_tci, - u32 mpls_label_count, bool log) + u32 mpls_label_count, bool log, + u32 depth) { const struct nlattr *attrs[OVS_DEC_TTL_ATTR_MAX + 1]; int start, action_start, err, rem; @@ -2660,7 +2665,8 @@ static int validate_and_copy_dec_ttl(struct net *net, return action_start; err = __ovs_nla_copy_actions(net, actions, key, sfa, eth_type, - vlan_tci, mpls_label_count, log); + vlan_tci, mpls_label_count, log, + depth + 1); if (err) return err; @@ -2674,7 +2680,8 @@ static int validate_and_copy_clone(struct net *net, const struct sw_flow_key *key, struct sw_flow_actions **sfa, __be16 eth_type, __be16 vlan_tci, - u32 mpls_label_count, bool log, bool last) + u32 mpls_label_count, bool log, bool last, + u32 depth) { int start, err; u32 exec; @@ -2694,7 +2701,8 @@ static int validate_and_copy_clone(struct net *net, return err; err = __ovs_nla_copy_actions(net, attr, key, sfa, - eth_type, vlan_tci, mpls_label_count, log); + eth_type, vlan_tci, mpls_label_count, log, + depth + 1); if (err) return err; @@ -3063,7 +3071,7 @@ static int validate_and_copy_check_pkt_len(struct net *net, struct sw_flow_actions **sfa, __be16 eth_type, __be16 vlan_tci, u32 mpls_label_count, - bool log, bool last) + bool log, bool last, u32 depth) { const struct nlattr *acts_if_greater, *acts_if_lesser_eq; struct nlattr *a[OVS_CHECK_PKT_LEN_ATTR_MAX + 1]; @@ -3111,7 +3119,8 @@ static int validate_and_copy_check_pkt_len(struct net *net, return nested_acts_start; err = __ovs_nla_copy_actions(net, acts_if_lesser_eq, key, sfa, - eth_type, vlan_tci, mpls_label_count, log); + eth_type, vlan_tci, mpls_label_count, log, + depth + 1); if (err) return err; @@ -3124,7 +3133,8 @@ static int validate_and_copy_check_pkt_len(struct net *net, return nested_acts_start; err = __ovs_nla_copy_actions(net, acts_if_greater, key, sfa, - eth_type, vlan_tci, mpls_label_count, log); + eth_type, vlan_tci, mpls_label_count, log, + depth + 1); if (err) return err; @@ -3152,12 +3162,16 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr, const struct sw_flow_key *key, struct sw_flow_actions **sfa, __be16 eth_type, __be16 vlan_tci, - u32 mpls_label_count, bool log) + u32 mpls_label_count, bool log, + u32 depth) { u8 mac_proto = ovs_key_mac_proto(key); const struct nlattr *a; int rem, err; + if (depth > OVS_COPY_ACTIONS_MAX_DEPTH) + return -EOVERFLOW; + nla_for_each_nested(a, attr, rem) { /* Expected argument lengths, (u32)-1 for variable length. */ static const u32 action_lens[OVS_ACTION_ATTR_MAX + 1] = { @@ -3355,7 +3369,7 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr, err = validate_and_copy_sample(net, a, key, sfa, eth_type, vlan_tci, mpls_label_count, - log, last); + log, last, depth); if (err) return err; skip_copy = true; @@ -3426,7 +3440,7 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr, err = validate_and_copy_clone(net, a, key, sfa, eth_type, vlan_tci, mpls_label_count, - log, last); + log, last, depth); if (err) return err; skip_copy = true; @@ -3440,7 +3454,8 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr, eth_type, vlan_tci, mpls_label_count, - log, last); + log, last, + depth); if (err) return err; skip_copy = true; @@ -3450,7 +3465,8 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr, case OVS_ACTION_ATTR_DEC_TTL: err = validate_and_copy_dec_ttl(net, a, key, sfa, eth_type, vlan_tci, - mpls_label_count, log); + mpls_label_count, log, + depth); if (err) return err; skip_copy = true; @@ -3495,7 +3511,8 @@ int ovs_nla_copy_actions(struct net *net, const struct nlattr *attr, (*sfa)->orig_len = nla_len(attr); err = __ovs_nla_copy_actions(net, attr, key, sfa, key->eth.type, - key->eth.vlan.tci, mpls_label_count, log); + key->eth.vlan.tci, mpls_label_count, log, + 0); if (err) ovs_nla_free_flow_actions(*sfa); diff --git a/net/rds/recv.c b/net/rds/recv.c index c71b923764fd..5627f80013f8 100644 --- a/net/rds/recv.c +++ b/net/rds/recv.c @@ -425,6 +425,7 @@ static int rds_still_queued(struct rds_sock *rs, struct rds_incoming *inc, struct sock *sk = rds_rs_to_sk(rs); int ret = 0; unsigned long flags; + struct rds_incoming *to_drop = NULL; write_lock_irqsave(&rs->rs_recv_lock, flags); if (!list_empty(&inc->i_item)) { @@ -435,11 +436,14 @@ static int rds_still_queued(struct rds_sock *rs, struct rds_incoming *inc, -be32_to_cpu(inc->i_hdr.h_len), inc->i_hdr.h_dport); list_del_init(&inc->i_item); - rds_inc_put(inc); + to_drop = inc; } } write_unlock_irqrestore(&rs->rs_recv_lock, flags); + if (to_drop) + rds_inc_put(to_drop); + rdsdebug("inc %p rs %p still %d dropped %d\n", inc, rs, ret, drop); return ret; } @@ -758,16 +762,21 @@ void rds_clear_recv_queue(struct rds_sock *rs) struct sock *sk = rds_rs_to_sk(rs); struct rds_incoming *inc, *tmp; unsigned long flags; + LIST_HEAD(to_drop); write_lock_irqsave(&rs->rs_recv_lock, flags); list_for_each_entry_safe(inc, tmp, &rs->rs_recv_queue, i_item) { rds_recv_rcvbuf_delta(rs, sk, inc->i_conn->c_lcong, -be32_to_cpu(inc->i_hdr.h_len), inc->i_hdr.h_dport); + list_move(&inc->i_item, &to_drop); + } + write_unlock_irqrestore(&rs->rs_recv_lock, flags); + + list_for_each_entry_safe(inc, tmp, &to_drop, i_item) { list_del_init(&inc->i_item); rds_inc_put(inc); } - write_unlock_irqrestore(&rs->rs_recv_lock, flags); } /* diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c index 12386f590b0f..0a1a9e40f237 100644 --- a/net/sched/act_mirred.c +++ b/net/sched/act_mirred.c @@ -533,8 +533,6 @@ static int mirred_device_event(struct notifier_block *unused, * net_device are already rcu protected. */ RCU_INIT_POINTER(m->tcfm_dev, NULL); - } else if (m->tcfm_blockid) { - m->tcfm_blockid = 0; } spin_unlock_bh(&m->tcf_lock); } diff --git a/net/sched/em_canid.c b/net/sched/em_canid.c index 5ea84decec19..5337bc462755 100644 --- a/net/sched/em_canid.c +++ b/net/sched/em_canid.c @@ -222,6 +222,7 @@ static void __exit exit_em_canid(void) tcf_em_unregister(&em_canid_ops); } +MODULE_DESCRIPTION("ematch classifier to match CAN IDs embedded in skb CAN frames"); MODULE_LICENSE("GPL"); module_init(init_em_canid); diff --git a/net/sched/em_cmp.c b/net/sched/em_cmp.c index f17b049ea530..c90ad7ea26b4 100644 --- a/net/sched/em_cmp.c +++ b/net/sched/em_cmp.c @@ -87,6 +87,7 @@ static void __exit exit_em_cmp(void) tcf_em_unregister(&em_cmp_ops); } +MODULE_DESCRIPTION("ematch classifier for basic data types(8/16/32 bit) against skb data"); MODULE_LICENSE("GPL"); module_init(init_em_cmp); diff --git a/net/sched/em_meta.c b/net/sched/em_meta.c index 09d8afd04a2a..8996c73c9779 100644 --- a/net/sched/em_meta.c +++ b/net/sched/em_meta.c @@ -1006,6 +1006,7 @@ static void __exit exit_em_meta(void) tcf_em_unregister(&em_meta_ops); } +MODULE_DESCRIPTION("ematch classifier for various internal kernel metadata, skb metadata and sk metadata"); MODULE_LICENSE("GPL"); module_init(init_em_meta); diff --git a/net/sched/em_nbyte.c b/net/sched/em_nbyte.c index a83b237cbeb0..4f9f21a05d5e 100644 --- a/net/sched/em_nbyte.c +++ b/net/sched/em_nbyte.c @@ -68,6 +68,7 @@ static void __exit exit_em_nbyte(void) tcf_em_unregister(&em_nbyte_ops); } +MODULE_DESCRIPTION("ematch classifier for arbitrary skb multi-bytes"); MODULE_LICENSE("GPL"); module_init(init_em_nbyte); diff --git a/net/sched/em_text.c b/net/sched/em_text.c index f176afb70559..420c66203b17 100644 --- a/net/sched/em_text.c +++ b/net/sched/em_text.c @@ -147,6 +147,7 @@ static void __exit exit_em_text(void) tcf_em_unregister(&em_text_ops); } +MODULE_DESCRIPTION("ematch classifier for embedded text in skbs"); MODULE_LICENSE("GPL"); module_init(init_em_text); diff --git a/net/sched/em_u32.c b/net/sched/em_u32.c index 71b070da0437..fdec4db5ec89 100644 --- a/net/sched/em_u32.c +++ b/net/sched/em_u32.c @@ -52,6 +52,7 @@ static void __exit exit_em_u32(void) tcf_em_unregister(&em_u32_ops); } +MODULE_DESCRIPTION("ematch skb classifier using 32 bit chunks of data"); MODULE_LICENSE("GPL"); module_init(init_em_u32); diff --git a/net/sctp/inqueue.c b/net/sctp/inqueue.c index 7182c5a450fb..5c1652181805 100644 --- a/net/sctp/inqueue.c +++ b/net/sctp/inqueue.c @@ -38,6 +38,14 @@ void sctp_inq_init(struct sctp_inq *queue) INIT_WORK(&queue->immediate, NULL); } +/* Properly release the chunk which is being worked on. */ +static inline void sctp_inq_chunk_free(struct sctp_chunk *chunk) +{ + if (chunk->head_skb) + chunk->skb = chunk->head_skb; + sctp_chunk_free(chunk); +} + /* Release the memory associated with an SCTP inqueue. */ void sctp_inq_free(struct sctp_inq *queue) { @@ -53,7 +61,7 @@ void sctp_inq_free(struct sctp_inq *queue) * free it as well. */ if (queue->in_progress) { - sctp_chunk_free(queue->in_progress); + sctp_inq_chunk_free(queue->in_progress); queue->in_progress = NULL; } } @@ -130,9 +138,7 @@ struct sctp_chunk *sctp_inq_pop(struct sctp_inq *queue) goto new_skb; } - if (chunk->head_skb) - chunk->skb = chunk->head_skb; - sctp_chunk_free(chunk); + sctp_inq_chunk_free(chunk); chunk = queue->in_progress = NULL; } else { /* Nothing to do. Next chunk in the packet, please. */ diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c index a2cb30af46cb..0f53a5c6fd9d 100644 --- a/net/smc/af_smc.c +++ b/net/smc/af_smc.c @@ -924,6 +924,7 @@ static int smc_switch_to_fallback(struct smc_sock *smc, int reason_code) smc->clcsock->file->private_data = smc->clcsock; smc->clcsock->wq.fasync_list = smc->sk.sk_socket->wq.fasync_list; + smc->sk.sk_socket->wq.fasync_list = NULL; /* There might be some wait entries remaining * in smc sk->sk_wq and they should be woken up diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c index 31e8a94dfc11..9fbc70200cd0 100644 --- a/net/tls/tls_sw.c +++ b/net/tls/tls_sw.c @@ -63,6 +63,7 @@ struct tls_decrypt_ctx { u8 iv[TLS_MAX_IV_SIZE]; u8 aad[TLS_MAX_AAD_SIZE]; u8 tail; + bool free_sgout; struct scatterlist sg[]; }; @@ -187,7 +188,6 @@ static void tls_decrypt_done(void *data, int err) struct aead_request *aead_req = data; struct crypto_aead *aead = crypto_aead_reqtfm(aead_req); struct scatterlist *sgout = aead_req->dst; - struct scatterlist *sgin = aead_req->src; struct tls_sw_context_rx *ctx; struct tls_decrypt_ctx *dctx; struct tls_context *tls_ctx; @@ -196,6 +196,17 @@ static void tls_decrypt_done(void *data, int err) struct sock *sk; int aead_size; + /* If requests get too backlogged crypto API returns -EBUSY and calls + * ->complete(-EINPROGRESS) immediately followed by ->complete(0) + * to make waiting for backlog to flush with crypto_wait_req() easier. + * First wait converts -EBUSY -> -EINPROGRESS, and the second one + * -EINPROGRESS -> 0. + * We have a single struct crypto_async_request per direction, this + * scheme doesn't help us, so just ignore the first ->complete(). + */ + if (err == -EINPROGRESS) + return; + aead_size = sizeof(*aead_req) + crypto_aead_reqsize(aead); aead_size = ALIGN(aead_size, __alignof__(*dctx)); dctx = (void *)((u8 *)aead_req + aead_size); @@ -213,7 +224,7 @@ static void tls_decrypt_done(void *data, int err) } /* Free the destination pages if skb was not decrypted inplace */ - if (sgout != sgin) { + if (dctx->free_sgout) { /* Skip the first S/G entry as it points to AAD */ for_each_sg(sg_next(sgout), sg, UINT_MAX, pages) { if (!sg) @@ -224,10 +235,17 @@ static void tls_decrypt_done(void *data, int err) kfree(aead_req); - spin_lock_bh(&ctx->decrypt_compl_lock); - if (!atomic_dec_return(&ctx->decrypt_pending)) + if (atomic_dec_and_test(&ctx->decrypt_pending)) complete(&ctx->async_wait.completion); - spin_unlock_bh(&ctx->decrypt_compl_lock); +} + +static int tls_decrypt_async_wait(struct tls_sw_context_rx *ctx) +{ + if (!atomic_dec_and_test(&ctx->decrypt_pending)) + crypto_wait_req(-EINPROGRESS, &ctx->async_wait); + atomic_inc(&ctx->decrypt_pending); + + return ctx->async_wait.err; } static int tls_do_decryption(struct sock *sk, @@ -253,6 +271,7 @@ static int tls_do_decryption(struct sock *sk, aead_request_set_callback(aead_req, CRYPTO_TFM_REQ_MAY_BACKLOG, tls_decrypt_done, aead_req); + DEBUG_NET_WARN_ON_ONCE(atomic_read(&ctx->decrypt_pending) < 1); atomic_inc(&ctx->decrypt_pending); } else { aead_request_set_callback(aead_req, @@ -261,6 +280,10 @@ static int tls_do_decryption(struct sock *sk, } ret = crypto_aead_decrypt(aead_req); + if (ret == -EBUSY) { + ret = tls_decrypt_async_wait(ctx); + ret = ret ?: -EINPROGRESS; + } if (ret == -EINPROGRESS) { if (darg->async) return 0; @@ -439,9 +462,10 @@ static void tls_encrypt_done(void *data, int err) struct tls_rec *rec = data; struct scatterlist *sge; struct sk_msg *msg_en; - bool ready = false; struct sock *sk; - int pending; + + if (err == -EINPROGRESS) /* see the comment in tls_decrypt_done() */ + return; msg_en = &rec->msg_encrypted; @@ -476,23 +500,25 @@ static void tls_encrypt_done(void *data, int err) /* If received record is at head of tx_list, schedule tx */ first_rec = list_first_entry(&ctx->tx_list, struct tls_rec, list); - if (rec == first_rec) - ready = true; + if (rec == first_rec) { + /* Schedule the transmission */ + if (!test_and_set_bit(BIT_TX_SCHEDULED, + &ctx->tx_bitmask)) + schedule_delayed_work(&ctx->tx_work.work, 1); + } } - spin_lock_bh(&ctx->encrypt_compl_lock); - pending = atomic_dec_return(&ctx->encrypt_pending); - - if (!pending && ctx->async_notify) + if (atomic_dec_and_test(&ctx->encrypt_pending)) complete(&ctx->async_wait.completion); - spin_unlock_bh(&ctx->encrypt_compl_lock); +} - if (!ready) - return; +static int tls_encrypt_async_wait(struct tls_sw_context_tx *ctx) +{ + if (!atomic_dec_and_test(&ctx->encrypt_pending)) + crypto_wait_req(-EINPROGRESS, &ctx->async_wait); + atomic_inc(&ctx->encrypt_pending); - /* Schedule the transmission */ - if (!test_and_set_bit(BIT_TX_SCHEDULED, &ctx->tx_bitmask)) - schedule_delayed_work(&ctx->tx_work.work, 1); + return ctx->async_wait.err; } static int tls_do_encryption(struct sock *sk, @@ -541,9 +567,14 @@ static int tls_do_encryption(struct sock *sk, /* Add the record in tx_list */ list_add_tail((struct list_head *)&rec->list, &ctx->tx_list); + DEBUG_NET_WARN_ON_ONCE(atomic_read(&ctx->encrypt_pending) < 1); atomic_inc(&ctx->encrypt_pending); rc = crypto_aead_encrypt(aead_req); + if (rc == -EBUSY) { + rc = tls_encrypt_async_wait(ctx); + rc = rc ?: -EINPROGRESS; + } if (!rc || rc != -EINPROGRESS) { atomic_dec(&ctx->encrypt_pending); sge->offset -= prot->prepend_size; @@ -984,7 +1015,6 @@ static int tls_sw_sendmsg_locked(struct sock *sk, struct msghdr *msg, int num_zc = 0; int orig_size; int ret = 0; - int pending; if (!eor && (msg->msg_flags & MSG_EOR)) return -EINVAL; @@ -1163,24 +1193,12 @@ trim_sgl: if (!num_async) { goto send_end; } else if (num_zc) { - /* Wait for pending encryptions to get completed */ - spin_lock_bh(&ctx->encrypt_compl_lock); - ctx->async_notify = true; - - pending = atomic_read(&ctx->encrypt_pending); - spin_unlock_bh(&ctx->encrypt_compl_lock); - if (pending) - crypto_wait_req(-EINPROGRESS, &ctx->async_wait); - else - reinit_completion(&ctx->async_wait.completion); - - /* There can be no concurrent accesses, since we have no - * pending encrypt operations - */ - WRITE_ONCE(ctx->async_notify, false); + int err; - if (ctx->async_wait.err) { - ret = ctx->async_wait.err; + /* Wait for pending encryptions to get completed */ + err = tls_encrypt_async_wait(ctx); + if (err) { + ret = err; copied = 0; } } @@ -1229,7 +1247,6 @@ void tls_sw_splice_eof(struct socket *sock) ssize_t copied = 0; bool retrying = false; int ret = 0; - int pending; if (!ctx->open_rec) return; @@ -1264,22 +1281,7 @@ retry: } /* Wait for pending encryptions to get completed */ - spin_lock_bh(&ctx->encrypt_compl_lock); - ctx->async_notify = true; - - pending = atomic_read(&ctx->encrypt_pending); - spin_unlock_bh(&ctx->encrypt_compl_lock); - if (pending) - crypto_wait_req(-EINPROGRESS, &ctx->async_wait); - else - reinit_completion(&ctx->async_wait.completion); - - /* There can be no concurrent accesses, since we have no pending - * encrypt operations - */ - WRITE_ONCE(ctx->async_notify, false); - - if (ctx->async_wait.err) + if (tls_encrypt_async_wait(ctx)) goto unlock; /* Transmit if any encryptions have completed */ @@ -1581,6 +1583,7 @@ static int tls_decrypt_sg(struct sock *sk, struct iov_iter *out_iov, } else if (out_sg) { memcpy(sgout, out_sg, n_sgout * sizeof(*sgout)); } + dctx->free_sgout = !!pages; /* Prepare and submit AEAD request */ err = tls_do_decryption(sk, sgin, sgout, dctx->iv, @@ -2109,16 +2112,10 @@ put_on_rx_list: recv_end: if (async) { - int ret, pending; + int ret; /* Wait for all previously submitted records to be decrypted */ - spin_lock_bh(&ctx->decrypt_compl_lock); - reinit_completion(&ctx->async_wait.completion); - pending = atomic_read(&ctx->decrypt_pending); - spin_unlock_bh(&ctx->decrypt_compl_lock); - ret = 0; - if (pending) - ret = crypto_wait_req(-EINPROGRESS, &ctx->async_wait); + ret = tls_decrypt_async_wait(ctx); __skb_queue_purge(&ctx->async_hold); if (ret) { @@ -2135,7 +2132,6 @@ recv_end: else err = process_rx_list(ctx, msg, &control, 0, async_copy_bytes, is_peek); - decrypted += max(err, 0); } copied += decrypted; @@ -2435,16 +2431,9 @@ void tls_sw_release_resources_tx(struct sock *sk) struct tls_context *tls_ctx = tls_get_ctx(sk); struct tls_sw_context_tx *ctx = tls_sw_ctx_tx(tls_ctx); struct tls_rec *rec, *tmp; - int pending; /* Wait for any pending async encryptions to complete */ - spin_lock_bh(&ctx->encrypt_compl_lock); - ctx->async_notify = true; - pending = atomic_read(&ctx->encrypt_pending); - spin_unlock_bh(&ctx->encrypt_compl_lock); - - if (pending) - crypto_wait_req(-EINPROGRESS, &ctx->async_wait); + tls_encrypt_async_wait(ctx); tls_tx_records(sk, -1); @@ -2607,7 +2596,7 @@ static struct tls_sw_context_tx *init_ctx_tx(struct tls_context *ctx, struct soc } crypto_init_wait(&sw_ctx_tx->async_wait); - spin_lock_init(&sw_ctx_tx->encrypt_compl_lock); + atomic_set(&sw_ctx_tx->encrypt_pending, 1); INIT_LIST_HEAD(&sw_ctx_tx->tx_list); INIT_DELAYED_WORK(&sw_ctx_tx->tx_work.work, tx_work_handler); sw_ctx_tx->tx_work.sk = sk; @@ -2628,7 +2617,7 @@ static struct tls_sw_context_rx *init_ctx_rx(struct tls_context *ctx) } crypto_init_wait(&sw_ctx_rx->async_wait); - spin_lock_init(&sw_ctx_rx->decrypt_compl_lock); + atomic_set(&sw_ctx_rx->decrypt_pending, 1); init_waitqueue_head(&sw_ctx_rx->wq); skb_queue_head_init(&sw_ctx_rx->rx_list); skb_queue_head_init(&sw_ctx_rx->async_hold); diff --git a/net/unix/garbage.c b/net/unix/garbage.c index 8f63f0b4bf01..2ff7ddbaa782 100644 --- a/net/unix/garbage.c +++ b/net/unix/garbage.c @@ -315,10 +315,11 @@ void unix_gc(void) __skb_queue_purge(&hitlist); #if IS_ENABLED(CONFIG_AF_UNIX_OOB) - list_for_each_entry_safe(u, next, &gc_candidates, link) { - struct sk_buff *skb = u->oob_skb; + while (!list_empty(&gc_candidates)) { + u = list_entry(gc_candidates.next, struct unix_sock, link); + if (u->oob_skb) { + struct sk_buff *skb = u->oob_skb; - if (skb) { u->oob_skb = NULL; kfree_skb(skb); } diff --git a/net/xfrm/xfrm_algo.c b/net/xfrm/xfrm_algo.c index 41533c631431..e6da7e8495c9 100644 --- a/net/xfrm/xfrm_algo.c +++ b/net/xfrm/xfrm_algo.c @@ -858,4 +858,5 @@ int xfrm_count_pfkey_enc_supported(void) } EXPORT_SYMBOL_GPL(xfrm_count_pfkey_enc_supported); +MODULE_DESCRIPTION("XFRM Algorithm interface"); MODULE_LICENSE("GPL"); diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index ad01997c3aa9..f037be190bae 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -3888,5 +3888,6 @@ static void __exit xfrm_user_exit(void) module_init(xfrm_user_init); module_exit(xfrm_user_exit); +MODULE_DESCRIPTION("XFRM User interface"); MODULE_LICENSE("GPL"); MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_XFRM); diff --git a/scripts/clang-tools/gen_compile_commands.py b/scripts/clang-tools/gen_compile_commands.py index 5dea4479240b..e4fb686dfaa9 100755 --- a/scripts/clang-tools/gen_compile_commands.py +++ b/scripts/clang-tools/gen_compile_commands.py @@ -170,7 +170,7 @@ def process_line(root_directory, command_prefix, file_path): # escape the pound sign '#', either as '\#' or '$(pound)' (depending on the # kernel version). The compile_commands.json file is not interepreted # by Make, so this code replaces the escaped version with '#'. - prefix = command_prefix.replace('\#', '#').replace('$(pound)', '#') + prefix = command_prefix.replace(r'\#', '#').replace('$(pound)', '#') # Return the canonical path, eliminating any symbolic links encountered in the path. abs_path = os.path.realpath(os.path.join(root_directory, file_path)) diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh index a432b171be82..7862a8101747 100755 --- a/scripts/link-vmlinux.sh +++ b/scripts/link-vmlinux.sh @@ -135,8 +135,13 @@ gen_btf() ${OBJCOPY} --only-section=.BTF --set-section-flags .BTF=alloc,readonly \ --strip-all ${1} ${2} 2>/dev/null # Change e_type to ET_REL so that it can be used to link final vmlinux. - # Unlike GNU ld, lld does not allow an ET_EXEC input. - printf '\1' | dd of=${2} conv=notrunc bs=1 seek=16 status=none + # GNU ld 2.35+ and lld do not allow an ET_EXEC input. + if is_enabled CONFIG_CPU_BIG_ENDIAN; then + et_rel='\0\1' + else + et_rel='\1\0' + fi + printf "${et_rel}" | dd of=${2} conv=notrunc bs=1 seek=16 status=none } # Create ${2} .S file with all symbols from the ${1} object file diff --git a/scripts/mksysmap b/scripts/mksysmap index 9ba1c9da0a40..57ff5656d566 100755 --- a/scripts/mksysmap +++ b/scripts/mksysmap @@ -48,17 +48,8 @@ ${NM} -n ${1} | sed >${2} -e " / __kvm_nvhe_\\$/d / __kvm_nvhe_\.L/d -# arm64 lld -/ __AArch64ADRPThunk_/d - -# arm lld -/ __ARMV5PILongThunk_/d -/ __ARMV7PILongThunk_/d -/ __ThumbV7PILongThunk_/d - -# mips lld -/ __LA25Thunk_/d -/ __microLA25Thunk_/d +# lld arm/aarch64/mips thunks +/ __[[:alnum:]]*Thunk_/d # CFI type identifiers / __kcfi_typeid_/d diff --git a/scripts/mod/sumversion.c b/scripts/mod/sumversion.c index 31066bfdba04..dc4878502276 100644 --- a/scripts/mod/sumversion.c +++ b/scripts/mod/sumversion.c @@ -326,7 +326,12 @@ static int parse_source_files(const char *objfile, struct md4_ctx *md) /* Sum all files in the same dir or subdirs. */ while ((line = get_line(&pos))) { - char* p = line; + char* p; + + /* trim the leading spaces away */ + while (isspace(*line)) + line++; + p = line; if (strncmp(line, "source_", sizeof("source_")-1) == 0) { p = strrchr(line, ' '); diff --git a/security/security.c b/security/security.c index 3aaad75c9ce8..7035ee35a393 100644 --- a/security/security.c +++ b/security/security.c @@ -29,6 +29,7 @@ #include <linux/backing-dev.h> #include <linux/string.h> #include <linux/msg.h> +#include <linux/overflow.h> #include <net/flow.h> /* How many LSMs were built into the kernel? */ @@ -4015,6 +4016,7 @@ int security_setselfattr(unsigned int attr, struct lsm_ctx __user *uctx, struct security_hook_list *hp; struct lsm_ctx *lctx; int rc = LSM_RET_DEFAULT(setselfattr); + u64 required_len; if (flags) return -EINVAL; @@ -4027,8 +4029,9 @@ int security_setselfattr(unsigned int attr, struct lsm_ctx __user *uctx, if (IS_ERR(lctx)) return PTR_ERR(lctx); - if (size < lctx->len || size < lctx->ctx_len + sizeof(*lctx) || - lctx->len < lctx->ctx_len + sizeof(*lctx)) { + if (size < lctx->len || + check_add_overflow(sizeof(*lctx), lctx->ctx_len, &required_len) || + lctx->len < required_len) { rc = -EINVAL; goto free_out; } diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig index 21a90b3c4cc7..8e0ff70fb610 100644 --- a/sound/pci/hda/Kconfig +++ b/sound/pci/hda/Kconfig @@ -156,7 +156,7 @@ config SND_HDA_SCODEC_CS35L56_I2C depends on I2C depends on ACPI || COMPILE_TEST depends on SND_SOC - select CS_DSP + select FW_CS_DSP select SND_HDA_GENERIC select SND_SOC_CS35L56_SHARED select SND_HDA_SCODEC_CS35L56 @@ -171,7 +171,7 @@ config SND_HDA_SCODEC_CS35L56_SPI depends on SPI_MASTER depends on ACPI || COMPILE_TEST depends on SND_SOC - select CS_DSP + select FW_CS_DSP select SND_HDA_GENERIC select SND_SOC_CS35L56_SHARED select SND_HDA_SCODEC_CS35L56 diff --git a/sound/pci/hda/cs35l41_hda_property.c b/sound/pci/hda/cs35l41_hda_property.c index d74cf11eef1e..87dcb367e239 100644 --- a/sound/pci/hda/cs35l41_hda_property.c +++ b/sound/pci/hda/cs35l41_hda_property.c @@ -91,10 +91,12 @@ static const struct cs35l41_config cs35l41_config_table[] = { { "10431D1F", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4500, 24 }, { "10431DA2", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 0, 0, 0 }, { "10431E02", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 0, 0, 0 }, + { "10431E12", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 0, 0, 0 }, { "10431EE2", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, -1, -1, 0, 0, 0 }, { "10431F12", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4500, 24 }, { "10431F1F", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, -1, 0, 0, 0, 0 }, { "10431F62", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 0, 0, 0 }, + { "17AA386F", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, -1, -1, 0, 0, 0 }, { "17AA38B4", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 0, 0, 0 }, { "17AA38B5", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 0, 0, 0 }, { "17AA38B6", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 0, 0, 0 }, @@ -427,10 +429,12 @@ static const struct cs35l41_prop_model cs35l41_prop_model_table[] = { { "CSC3551", "10431D1F", generic_dsd_config }, { "CSC3551", "10431DA2", generic_dsd_config }, { "CSC3551", "10431E02", generic_dsd_config }, + { "CSC3551", "10431E12", generic_dsd_config }, { "CSC3551", "10431EE2", generic_dsd_config }, { "CSC3551", "10431F12", generic_dsd_config }, { "CSC3551", "10431F1F", generic_dsd_config }, { "CSC3551", "10431F62", generic_dsd_config }, + { "CSC3551", "17AA386F", generic_dsd_config }, { "CSC3551", "17AA38B4", generic_dsd_config }, { "CSC3551", "17AA38B5", generic_dsd_config }, { "CSC3551", "17AA38B6", generic_dsd_config }, diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index e8819e8a9876..e8209178d87b 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -344,6 +344,7 @@ enum { CXT_FIXUP_HP_ZBOOK_MUTE_LED, CXT_FIXUP_HEADSET_MIC, CXT_FIXUP_HP_MIC_NO_PRESENCE, + CXT_PINCFG_SWS_JS201D, }; /* for hda_fixup_thinkpad_acpi() */ @@ -841,6 +842,17 @@ static const struct hda_pintbl cxt_pincfg_lemote[] = { {} }; +/* SuoWoSi/South-holding JS201D with sn6140 */ +static const struct hda_pintbl cxt_pincfg_sws_js201d[] = { + { 0x16, 0x03211040 }, /* hp out */ + { 0x17, 0x91170110 }, /* SPK/Class_D */ + { 0x18, 0x95a70130 }, /* Internal mic */ + { 0x19, 0x03a11020 }, /* Headset Mic */ + { 0x1a, 0x40f001f0 }, /* Not used */ + { 0x21, 0x40f001f0 }, /* Not used */ + {} +}; + static const struct hda_fixup cxt_fixups[] = { [CXT_PINCFG_LENOVO_X200] = { .type = HDA_FIXUP_PINS, @@ -996,6 +1008,10 @@ static const struct hda_fixup cxt_fixups[] = { .chained = true, .chain_id = CXT_FIXUP_HEADSET_MIC, }, + [CXT_PINCFG_SWS_JS201D] = { + .type = HDA_FIXUP_PINS, + .v.pins = cxt_pincfg_sws_js201d, + }, }; static const struct snd_pci_quirk cxt5045_fixups[] = { @@ -1069,6 +1085,7 @@ static const struct snd_pci_quirk cxt5066_fixups[] = { SND_PCI_QUIRK(0x103c, 0x8457, "HP Z2 G4 mini", CXT_FIXUP_HP_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x103c, 0x8458, "HP Z2 G4 mini premium", CXT_FIXUP_HP_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1043, 0x138d, "Asus", CXT_FIXUP_HEADPHONE_MIC_PIN), + SND_PCI_QUIRK(0x14f1, 0x0265, "SWS JS201D", CXT_PINCFG_SWS_JS201D), SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT_FIXUP_OLPC_XO), SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400", CXT_PINCFG_LENOVO_TP410), SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo T410", CXT_PINCFG_LENOVO_TP410), @@ -1109,6 +1126,7 @@ static const struct hda_model_fixup cxt5066_fixup_models[] = { { .id = CXT_FIXUP_HP_ZBOOK_MUTE_LED, .name = "hp-zbook-mute-led" }, { .id = CXT_FIXUP_HP_MIC_NO_PRESENCE, .name = "hp-mic-fix" }, { .id = CXT_PINCFG_LENOVO_NOTEBOOK, .name = "lenovo-20149" }, + { .id = CXT_PINCFG_SWS_JS201D, .name = "sws-js201d" }, {} }; diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 6994c4c5073c..0ec1312bffd5 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -9737,7 +9737,9 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1028, 0x0b71, "Dell Inspiron 16 Plus 7620", ALC295_FIXUP_DELL_INSPIRON_TOP_SPEAKERS), SND_PCI_QUIRK(0x1028, 0x0beb, "Dell XPS 15 9530 (2023)", ALC289_FIXUP_DELL_CS35L41_SPI_2), SND_PCI_QUIRK(0x1028, 0x0c03, "Dell Precision 5340", ALC269_FIXUP_DELL4_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x0c0b, "Dell Oasis 14 RPL-P", ALC289_FIXUP_RTK_AMP_DUAL_SPK), SND_PCI_QUIRK(0x1028, 0x0c0d, "Dell Oasis", ALC289_FIXUP_RTK_AMP_DUAL_SPK), + SND_PCI_QUIRK(0x1028, 0x0c0e, "Dell Oasis 16", ALC289_FIXUP_RTK_AMP_DUAL_SPK), SND_PCI_QUIRK(0x1028, 0x0c19, "Dell Precision 3340", ALC236_FIXUP_DELL_DUAL_CODECS), SND_PCI_QUIRK(0x1028, 0x0c1a, "Dell Precision 3340", ALC236_FIXUP_DELL_DUAL_CODECS), SND_PCI_QUIRK(0x1028, 0x0c1b, "Dell Precision 3440", ALC236_FIXUP_DELL_DUAL_CODECS), @@ -9928,6 +9930,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x8abb, "HP ZBook Firefly 14 G9", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8ad1, "HP EliteBook 840 14 inch G9 Notebook PC", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8ad2, "HP EliteBook 860 16 inch G9 Notebook PC", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8b0f, "HP Elite mt645 G7 Mobile Thin Client U81", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF), SND_PCI_QUIRK(0x103c, 0x8b2f, "HP 255 15.6 inch G10 Notebook PC", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2), SND_PCI_QUIRK(0x103c, 0x8b42, "HP", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8b43, "HP", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED), @@ -9935,6 +9938,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x8b45, "HP", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8b46, "HP", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8b47, "HP", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8b59, "HP Elite mt645 G7 Mobile Thin Client U89", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF), SND_PCI_QUIRK(0x103c, 0x8b5d, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF), SND_PCI_QUIRK(0x103c, 0x8b5e, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF), SND_PCI_QUIRK(0x103c, 0x8b63, "HP Elite Dragonfly 13.5 inch G4", ALC245_FIXUP_CS35L41_SPI_4_HP_GPIO_LED), @@ -10003,6 +10007,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1043, 0x1662, "ASUS GV301QH", ALC294_FIXUP_ASUS_DUAL_SPK), SND_PCI_QUIRK(0x1043, 0x1663, "ASUS GU603ZI/ZJ/ZQ/ZU/ZV", ALC285_FIXUP_ASUS_HEADSET_MIC), SND_PCI_QUIRK(0x1043, 0x1683, "ASUS UM3402YAR", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x1043, 0x16a3, "ASUS UX3402VA", ALC245_FIXUP_CS35L41_SPI_2), SND_PCI_QUIRK(0x1043, 0x16b2, "ASUS GU603", ALC289_FIXUP_ASUS_GA401), SND_PCI_QUIRK(0x1043, 0x16d3, "ASUS UX5304VA", ALC245_FIXUP_CS35L41_SPI_2), SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_FIXUP_STEREO_DMIC), @@ -10046,14 +10051,12 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1043, 0x1d4e, "ASUS TM420", ALC256_FIXUP_ASUS_HPE), SND_PCI_QUIRK(0x1043, 0x1da2, "ASUS UP6502ZA/ZD", ALC245_FIXUP_CS35L41_SPI_2), SND_PCI_QUIRK(0x1043, 0x1e02, "ASUS UX3402ZA", ALC245_FIXUP_CS35L41_SPI_2), - SND_PCI_QUIRK(0x1043, 0x16a3, "ASUS UX3402VA", ALC245_FIXUP_CS35L41_SPI_2), - SND_PCI_QUIRK(0x1043, 0x1f62, "ASUS UX7602ZM", ALC245_FIXUP_CS35L41_SPI_2), SND_PCI_QUIRK(0x1043, 0x1e11, "ASUS Zephyrus G15", ALC289_FIXUP_ASUS_GA502), - SND_PCI_QUIRK(0x1043, 0x1e12, "ASUS UM6702RA/RC", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x1043, 0x1e12, "ASUS UM3402", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x1043, 0x1e51, "ASUS Zephyrus M15", ALC294_FIXUP_ASUS_GU502_PINS), SND_PCI_QUIRK(0x1043, 0x1e5e, "ASUS ROG Strix G513", ALC294_FIXUP_ASUS_G513_PINS), SND_PCI_QUIRK(0x1043, 0x1e8e, "ASUS Zephyrus G15", ALC289_FIXUP_ASUS_GA401), - SND_PCI_QUIRK(0x1043, 0x1ee2, "ASUS UM3402", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x1043, 0x1ee2, "ASUS UM6702RA/RC", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x1043, 0x1c52, "ASUS Zephyrus G15 2022", ALC289_FIXUP_ASUS_GA401), SND_PCI_QUIRK(0x1043, 0x1f11, "ASUS Zephyrus G14", ALC289_FIXUP_ASUS_GA401), SND_PCI_QUIRK(0x1043, 0x1f12, "ASUS UM5302", ALC287_FIXUP_CS35L41_I2C_2), @@ -10260,6 +10263,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x3853, "Lenovo Yoga 7 15ITL5", ALC287_FIXUP_YOGA7_14ITL_SPEAKERS), SND_PCI_QUIRK(0x17aa, 0x3855, "Legion 7 16ITHG6", ALC287_FIXUP_LEGION_16ITHG6), SND_PCI_QUIRK(0x17aa, 0x3869, "Lenovo Yoga7 14IAL7", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN), + SND_PCI_QUIRK(0x17aa, 0x386f, "Legion 7i 16IAX7", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x17aa, 0x3870, "Lenovo Yoga 7 14ARB7", ALC287_FIXUP_YOGA7_14ARB7_I2C), SND_PCI_QUIRK(0x17aa, 0x387d, "Yoga S780-16 pro Quad AAC", ALC287_FIXUP_TAS2781_I2C), SND_PCI_QUIRK(0x17aa, 0x387e, "Yoga S780-16 pro Quad YC", ALC287_FIXUP_TAS2781_I2C), diff --git a/sound/pci/hda/tas2781_hda_i2c.c b/sound/pci/hda/tas2781_hda_i2c.c index 2dd809de62e5..1bfb00102a77 100644 --- a/sound/pci/hda/tas2781_hda_i2c.c +++ b/sound/pci/hda/tas2781_hda_i2c.c @@ -710,7 +710,7 @@ static int tas2781_hda_bind(struct device *dev, struct device *master, strscpy(comps->name, dev_name(dev), sizeof(comps->name)); - ret = tascodec_init(tas_hda->priv, codec, tasdev_fw_ready); + ret = tascodec_init(tas_hda->priv, codec, THIS_MODULE, tasdev_fw_ready); if (!ret) comps->playback_hook = tas2781_hda_playback_hook; diff --git a/sound/soc/amd/yc/acp6x-mach.c b/sound/soc/amd/yc/acp6x-mach.c index 23d44a50d815..cc231185d72c 100644 --- a/sound/soc/amd/yc/acp6x-mach.c +++ b/sound/soc/amd/yc/acp6x-mach.c @@ -238,6 +238,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = { .driver_data = &acp6x_card, .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_NAME, "82UU"), + } + }, + { + .driver_data = &acp6x_card, + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), DMI_MATCH(DMI_PRODUCT_NAME, "82V2"), } }, @@ -251,6 +258,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = { { .driver_data = &acp6x_card, .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_NAME, "83AS"), + } + }, + { + .driver_data = &acp6x_card, + .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK COMPUTER INC."), DMI_MATCH(DMI_PRODUCT_NAME, "UM5302TA"), } diff --git a/sound/soc/codecs/cs35l56-shared.c b/sound/soc/codecs/cs35l56-shared.c index 02fba4bc0a14..995d979b6d87 100644 --- a/sound/soc/codecs/cs35l56-shared.c +++ b/sound/soc/codecs/cs35l56-shared.c @@ -51,7 +51,6 @@ static const struct reg_default cs35l56_reg_defaults[] = { { CS35L56_SWIRE_DP3_CH2_INPUT, 0x00000019 }, { CS35L56_SWIRE_DP3_CH3_INPUT, 0x00000029 }, { CS35L56_SWIRE_DP3_CH4_INPUT, 0x00000028 }, - { CS35L56_IRQ1_CFG, 0x00000000 }, { CS35L56_IRQ1_MASK_1, 0x83ffffff }, { CS35L56_IRQ1_MASK_2, 0xffff7fff }, { CS35L56_IRQ1_MASK_4, 0xe0ffffff }, diff --git a/sound/soc/codecs/cs35l56.c b/sound/soc/codecs/cs35l56.c index c23e29da4cfb..2c1313e34cce 100644 --- a/sound/soc/codecs/cs35l56.c +++ b/sound/soc/codecs/cs35l56.c @@ -5,6 +5,7 @@ // Copyright (C) 2023 Cirrus Logic, Inc. and // Cirrus Logic International Semiconductor Ltd. +#include <linux/acpi.h> #include <linux/completion.h> #include <linux/debugfs.h> #include <linux/delay.h> @@ -15,6 +16,7 @@ #include <linux/module.h> #include <linux/pm.h> #include <linux/pm_runtime.h> +#include <linux/property.h> #include <linux/regmap.h> #include <linux/regulator/consumer.h> #include <linux/slab.h> @@ -68,63 +70,7 @@ static const char * const cs35l56_asp1_mux_control_names[] = { "ASP1 TX1 Source", "ASP1 TX2 Source", "ASP1 TX3 Source", "ASP1 TX4 Source" }; -static int cs35l56_dspwait_asp1tx_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol); - struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(component); - struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; - int index = e->shift_l; - unsigned int addr, val; - int ret; - - /* Wait for mux to be initialized */ - cs35l56_wait_dsp_ready(cs35l56); - flush_work(&cs35l56->mux_init_work); - - addr = cs35l56_asp1_mixer_regs[index]; - ret = regmap_read(cs35l56->base.regmap, addr, &val); - if (ret) - return ret; - - val &= CS35L56_ASP_TXn_SRC_MASK; - ucontrol->value.enumerated.item[0] = snd_soc_enum_val_to_item(e, val); - - return 0; -} - -static int cs35l56_dspwait_asp1tx_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol); - struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol); - struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(component); - struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; - int item = ucontrol->value.enumerated.item[0]; - int index = e->shift_l; - unsigned int addr, val; - bool changed; - int ret; - - /* Wait for mux to be initialized */ - cs35l56_wait_dsp_ready(cs35l56); - flush_work(&cs35l56->mux_init_work); - - addr = cs35l56_asp1_mixer_regs[index]; - val = snd_soc_enum_item_to_val(e, item); - - ret = regmap_update_bits_check(cs35l56->base.regmap, addr, - CS35L56_ASP_TXn_SRC_MASK, val, &changed); - if (!ret) - return ret; - - if (changed) - snd_soc_dapm_mux_update_power(dapm, kcontrol, item, e, NULL); - - return changed; -} - -static void cs35l56_mark_asp1_mixer_widgets_dirty(struct cs35l56_private *cs35l56) +static int cs35l56_sync_asp1_mixer_widgets_with_firmware(struct cs35l56_private *cs35l56) { struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cs35l56->component); const char *prefix = cs35l56->component->name_prefix; @@ -135,13 +81,19 @@ static void cs35l56_mark_asp1_mixer_widgets_dirty(struct cs35l56_private *cs35l5 unsigned int val[4]; int i, item, ret; + if (cs35l56->asp1_mixer_widgets_initialized) + return 0; + /* * Resume so we can read the registers from silicon if the regmap * cache has not yet been populated. */ ret = pm_runtime_resume_and_get(cs35l56->base.dev); if (ret < 0) - return; + return ret; + + /* Wait for firmware download and reboot */ + cs35l56_wait_dsp_ready(cs35l56); ret = regmap_bulk_read(cs35l56->base.regmap, CS35L56_ASP1TX1_INPUT, val, ARRAY_SIZE(val)); @@ -151,12 +103,9 @@ static void cs35l56_mark_asp1_mixer_widgets_dirty(struct cs35l56_private *cs35l5 if (ret) { dev_err(cs35l56->base.dev, "Failed to read ASP1 mixer regs: %d\n", ret); - return; + return ret; } - snd_soc_card_mutex_lock(dapm->card); - WARN_ON(!dapm->card->instantiated); - for (i = 0; i < ARRAY_SIZE(cs35l56_asp1_mux_control_names); ++i) { name = cs35l56_asp1_mux_control_names[i]; @@ -176,16 +125,65 @@ static void cs35l56_mark_asp1_mixer_widgets_dirty(struct cs35l56_private *cs35l5 snd_soc_dapm_mux_update_power(dapm, kcontrol, item, e, NULL); } - snd_soc_card_mutex_unlock(dapm->card); + cs35l56->asp1_mixer_widgets_initialized = true; + + return 0; } -static void cs35l56_mux_init_work(struct work_struct *work) +static int cs35l56_dspwait_asp1tx_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - struct cs35l56_private *cs35l56 = container_of(work, - struct cs35l56_private, - mux_init_work); + struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol); + struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(component); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + int index = e->shift_l; + unsigned int addr, val; + int ret; + + ret = cs35l56_sync_asp1_mixer_widgets_with_firmware(cs35l56); + if (ret) + return ret; + + addr = cs35l56_asp1_mixer_regs[index]; + ret = regmap_read(cs35l56->base.regmap, addr, &val); + if (ret) + return ret; + + val &= CS35L56_ASP_TXn_SRC_MASK; + ucontrol->value.enumerated.item[0] = snd_soc_enum_val_to_item(e, val); + + return 0; +} + +static int cs35l56_dspwait_asp1tx_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol); + struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol); + struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(component); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + int item = ucontrol->value.enumerated.item[0]; + int index = e->shift_l; + unsigned int addr, val; + bool changed; + int ret; - cs35l56_mark_asp1_mixer_widgets_dirty(cs35l56); + ret = cs35l56_sync_asp1_mixer_widgets_with_firmware(cs35l56); + if (ret) + return ret; + + addr = cs35l56_asp1_mixer_regs[index]; + val = snd_soc_enum_item_to_val(e, item); + + ret = regmap_update_bits_check(cs35l56->base.regmap, addr, + CS35L56_ASP_TXn_SRC_MASK, val, &changed); + if (ret) + return ret; + + if (changed) + snd_soc_dapm_mux_update_power(dapm, kcontrol, item, e, NULL); + + return changed; } static DECLARE_TLV_DB_SCALE(vol_tlv, -10000, 25, 0); @@ -936,14 +934,6 @@ static void cs35l56_dsp_work(struct work_struct *work) else cs35l56_patch(cs35l56, firmware_missing); - - /* - * Set starting value of ASP1 mux widgets. Updating a mux takes - * the DAPM mutex. Post this to a separate job so that DAPM - * power-up can wait for dsp_work to complete without deadlocking - * on the DAPM mutex. - */ - queue_work(cs35l56->dsp_wq, &cs35l56->mux_init_work); err: pm_runtime_mark_last_busy(cs35l56->base.dev); pm_runtime_put_autosuspend(cs35l56->base.dev); @@ -989,6 +979,13 @@ static int cs35l56_component_probe(struct snd_soc_component *component) debugfs_create_bool("can_hibernate", 0444, debugfs_root, &cs35l56->base.can_hibernate); debugfs_create_bool("fw_patched", 0444, debugfs_root, &cs35l56->base.fw_patched); + /* + * The widgets for the ASP1TX mixer can't be initialized + * until the firmware has been downloaded and rebooted. + */ + regcache_drop_region(cs35l56->base.regmap, CS35L56_ASP1TX1_INPUT, CS35L56_ASP1TX4_INPUT); + cs35l56->asp1_mixer_widgets_initialized = false; + queue_work(cs35l56->dsp_wq, &cs35l56->dsp_work); return 0; @@ -999,7 +996,6 @@ static void cs35l56_component_remove(struct snd_soc_component *component) struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(component); cancel_work_sync(&cs35l56->dsp_work); - cancel_work_sync(&cs35l56->mux_init_work); if (cs35l56->dsp.cs_dsp.booted) wm_adsp_power_down(&cs35l56->dsp); @@ -1070,10 +1066,8 @@ int cs35l56_system_suspend(struct device *dev) dev_dbg(dev, "system_suspend\n"); - if (cs35l56->component) { + if (cs35l56->component) flush_work(&cs35l56->dsp_work); - cancel_work_sync(&cs35l56->mux_init_work); - } /* * The interrupt line is normally shared, but after we start suspending @@ -1224,7 +1218,6 @@ static int cs35l56_dsp_init(struct cs35l56_private *cs35l56) return -ENOMEM; INIT_WORK(&cs35l56->dsp_work, cs35l56_dsp_work); - INIT_WORK(&cs35l56->mux_init_work, cs35l56_mux_init_work); dsp = &cs35l56->dsp; cs35l56_init_cs_dsp(&cs35l56->base, &dsp->cs_dsp); @@ -1269,6 +1262,94 @@ static int cs35l56_get_firmware_uid(struct cs35l56_private *cs35l56) return 0; } +/* + * Some SoundWire laptops have a spk-id-gpios property but it points to + * the wrong ACPI Device node so can't be used to get the GPIO. Try to + * find the SDCA node containing the GpioIo resource and add a GPIO + * mapping to it. + */ +static const struct acpi_gpio_params cs35l56_af01_first_gpio = { 0, 0, false }; +static const struct acpi_gpio_mapping cs35l56_af01_spkid_gpios_mapping[] = { + { "spk-id-gpios", &cs35l56_af01_first_gpio, 1 }, + { } +}; + +static void cs35l56_acpi_dev_release_driver_gpios(void *adev) +{ + acpi_dev_remove_driver_gpios(adev); +} + +static int cs35l56_try_get_broken_sdca_spkid_gpio(struct cs35l56_private *cs35l56) +{ + struct fwnode_handle *af01_fwnode; + const union acpi_object *obj; + struct gpio_desc *desc; + int ret; + + /* Find the SDCA node containing the GpioIo */ + af01_fwnode = device_get_named_child_node(cs35l56->base.dev, "AF01"); + if (!af01_fwnode) { + dev_dbg(cs35l56->base.dev, "No AF01 node\n"); + return -ENOENT; + } + + ret = acpi_dev_get_property(ACPI_COMPANION(cs35l56->base.dev), + "spk-id-gpios", ACPI_TYPE_PACKAGE, &obj); + if (ret) { + dev_dbg(cs35l56->base.dev, "Could not get spk-id-gpios package: %d\n", ret); + return -ENOENT; + } + + /* The broken properties we can handle are a 4-element package (one GPIO) */ + if (obj->package.count != 4) { + dev_warn(cs35l56->base.dev, "Unexpected spk-id element count %d\n", + obj->package.count); + return -ENOENT; + } + + /* Add a GPIO mapping if it doesn't already have one */ + if (!fwnode_property_present(af01_fwnode, "spk-id-gpios")) { + struct acpi_device *adev = to_acpi_device_node(af01_fwnode); + + /* + * Can't use devm_acpi_dev_add_driver_gpios() because the + * mapping isn't being added to the node pointed to by + * ACPI_COMPANION(). + */ + ret = acpi_dev_add_driver_gpios(adev, cs35l56_af01_spkid_gpios_mapping); + if (ret) { + return dev_err_probe(cs35l56->base.dev, ret, + "Failed to add gpio mapping to AF01\n"); + } + + ret = devm_add_action_or_reset(cs35l56->base.dev, + cs35l56_acpi_dev_release_driver_gpios, + adev); + if (ret) + return ret; + + dev_dbg(cs35l56->base.dev, "Added spk-id-gpios mapping to AF01\n"); + } + + desc = fwnode_gpiod_get_index(af01_fwnode, "spk-id", 0, GPIOD_IN, NULL); + if (IS_ERR(desc)) { + ret = PTR_ERR(desc); + return dev_err_probe(cs35l56->base.dev, ret, "Get GPIO from AF01 failed\n"); + } + + ret = gpiod_get_value_cansleep(desc); + gpiod_put(desc); + + if (ret < 0) { + dev_err_probe(cs35l56->base.dev, ret, "Error reading spk-id GPIO\n"); + return ret; + } + + dev_info(cs35l56->base.dev, "Got spk-id from AF01\n"); + + return ret; +} + int cs35l56_common_probe(struct cs35l56_private *cs35l56) { int ret; @@ -1313,6 +1394,9 @@ int cs35l56_common_probe(struct cs35l56_private *cs35l56) } ret = cs35l56_get_speaker_id(&cs35l56->base); + if (ACPI_COMPANION(cs35l56->base.dev) && cs35l56->sdw_peripheral && (ret == -ENOENT)) + ret = cs35l56_try_get_broken_sdca_spkid_gpio(cs35l56); + if ((ret < 0) && (ret != -ENOENT)) goto err; diff --git a/sound/soc/codecs/cs35l56.h b/sound/soc/codecs/cs35l56.h index 596b141e3f96..b000e7365e40 100644 --- a/sound/soc/codecs/cs35l56.h +++ b/sound/soc/codecs/cs35l56.h @@ -34,7 +34,6 @@ struct cs35l56_private { struct wm_adsp dsp; /* must be first member */ struct cs35l56_base base; struct work_struct dsp_work; - struct work_struct mux_init_work; struct workqueue_struct *dsp_wq; struct snd_soc_component *component; struct regulator_bulk_data supplies[CS35L56_NUM_BULK_SUPPLIES]; @@ -52,6 +51,7 @@ struct cs35l56_private { u8 asp_slot_count; bool tdm_mode; bool sysclk_set; + bool asp1_mixer_widgets_initialized; u8 old_sdw_clock_scale; }; diff --git a/sound/soc/codecs/cs42l43.c b/sound/soc/codecs/cs42l43.c index 6a64681767de..a97ccb512deb 100644 --- a/sound/soc/codecs/cs42l43.c +++ b/sound/soc/codecs/cs42l43.c @@ -2257,7 +2257,10 @@ static int cs42l43_codec_probe(struct platform_device *pdev) pm_runtime_use_autosuspend(priv->dev); pm_runtime_set_active(priv->dev); pm_runtime_get_noresume(priv->dev); - devm_pm_runtime_enable(priv->dev); + + ret = devm_pm_runtime_enable(priv->dev); + if (ret) + goto err_pm; for (i = 0; i < ARRAY_SIZE(cs42l43_irqs); i++) { ret = cs42l43_request_irq(priv, dom, cs42l43_irqs[i].name, @@ -2333,8 +2336,47 @@ static int cs42l43_codec_runtime_resume(struct device *dev) return 0; } -static DEFINE_RUNTIME_DEV_PM_OPS(cs42l43_codec_pm_ops, NULL, - cs42l43_codec_runtime_resume, NULL); +static int cs42l43_codec_suspend(struct device *dev) +{ + struct cs42l43 *cs42l43 = dev_get_drvdata(dev); + + disable_irq(cs42l43->irq); + + return 0; +} + +static int cs42l43_codec_suspend_noirq(struct device *dev) +{ + struct cs42l43 *cs42l43 = dev_get_drvdata(dev); + + enable_irq(cs42l43->irq); + + return 0; +} + +static int cs42l43_codec_resume(struct device *dev) +{ + struct cs42l43 *cs42l43 = dev_get_drvdata(dev); + + enable_irq(cs42l43->irq); + + return 0; +} + +static int cs42l43_codec_resume_noirq(struct device *dev) +{ + struct cs42l43 *cs42l43 = dev_get_drvdata(dev); + + disable_irq(cs42l43->irq); + + return 0; +} + +static const struct dev_pm_ops cs42l43_codec_pm_ops = { + SYSTEM_SLEEP_PM_OPS(cs42l43_codec_suspend, cs42l43_codec_resume) + NOIRQ_SYSTEM_SLEEP_PM_OPS(cs42l43_codec_suspend_noirq, cs42l43_codec_resume_noirq) + RUNTIME_PM_OPS(NULL, cs42l43_codec_runtime_resume, NULL) +}; static const struct platform_device_id cs42l43_codec_id_table[] = { { "cs42l43-codec", }, diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 5150d6ee3748..20191a4473c2 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -3317,6 +3317,7 @@ static void rt5645_jack_detect_work(struct work_struct *work) report, SND_JACK_HEADPHONE); snd_soc_jack_report(rt5645->mic_jack, report, SND_JACK_MICROPHONE); + mutex_unlock(&rt5645->jd_mutex); return; case 4: val = snd_soc_component_read(rt5645->component, RT5645_A_JD_CTRL1) & 0x0020; @@ -3692,6 +3693,11 @@ static const struct rt5645_platform_data jd_mode3_monospk_platform_data = { .mono_speaker = true, }; +static const struct rt5645_platform_data jd_mode3_inv_data = { + .jd_mode = 3, + .inv_jd1_1 = true, +}; + static const struct rt5645_platform_data jd_mode3_platform_data = { .jd_mode = 3, }; @@ -3837,6 +3843,16 @@ static const struct dmi_system_id dmi_platform_data[] = { DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"), DMI_EXACT_MATCH(DMI_BOARD_NAME, "Cherry Trail CR"), DMI_EXACT_MATCH(DMI_BOARD_VERSION, "Default string"), + /* + * Above strings are too generic, LattePanda BIOS versions for + * all 4 hw revisions are: + * DF-BI-7-S70CR100-* + * DF-BI-7-S70CR110-* + * DF-BI-7-S70CR200-* + * LP-BS-7-S70CR700-* + * Do a partial match for S70CR to avoid false positive matches. + */ + DMI_MATCH(DMI_BIOS_VERSION, "S70CR"), }, .driver_data = (void *)&lattepanda_board_platform_data, }, @@ -3871,6 +3887,16 @@ static const struct dmi_system_id dmi_platform_data[] = { }, .driver_data = (void *)&intel_braswell_platform_data, }, + { + .ident = "Meegopad T08", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Default string"), + DMI_MATCH(DMI_PRODUCT_NAME, "Default string"), + DMI_MATCH(DMI_BOARD_NAME, "T3 MRD"), + DMI_MATCH(DMI_BOARD_VERSION, "V1.1"), + }, + .driver_data = (void *)&jd_mode3_inv_data, + }, { } }; diff --git a/sound/soc/codecs/tas2781-comlib.c b/sound/soc/codecs/tas2781-comlib.c index b7e56ceb1acf..5d0e5348b361 100644 --- a/sound/soc/codecs/tas2781-comlib.c +++ b/sound/soc/codecs/tas2781-comlib.c @@ -267,6 +267,7 @@ void tas2781_reset(struct tasdevice_priv *tas_dev) EXPORT_SYMBOL_GPL(tas2781_reset); int tascodec_init(struct tasdevice_priv *tas_priv, void *codec, + struct module *module, void (*cont)(const struct firmware *fw, void *context)) { int ret = 0; @@ -280,7 +281,7 @@ int tascodec_init(struct tasdevice_priv *tas_priv, void *codec, tas_priv->dev_name, tas_priv->ndev); crc8_populate_msb(tas_priv->crc8_lkp_tbl, TASDEVICE_CRC8_POLYNOMIAL); tas_priv->codec = codec; - ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_UEVENT, + ret = request_firmware_nowait(module, FW_ACTION_UEVENT, tas_priv->rca_binaryname, tas_priv->dev, GFP_KERNEL, tas_priv, cont); if (ret) diff --git a/sound/soc/codecs/tas2781-i2c.c b/sound/soc/codecs/tas2781-i2c.c index 32913bd1a623..b5abff230e43 100644 --- a/sound/soc/codecs/tas2781-i2c.c +++ b/sound/soc/codecs/tas2781-i2c.c @@ -566,7 +566,7 @@ static int tasdevice_codec_probe(struct snd_soc_component *codec) { struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec); - return tascodec_init(tas_priv, codec, tasdevice_fw_ready); + return tascodec_init(tas_priv, codec, THIS_MODULE, tasdevice_fw_ready); } static void tasdevice_deinit(void *context) diff --git a/sound/soc/intel/avs/core.c b/sound/soc/intel/avs/core.c index 59c3793f65df..db78eb2f0108 100644 --- a/sound/soc/intel/avs/core.c +++ b/sound/soc/intel/avs/core.c @@ -477,6 +477,9 @@ static int avs_pci_probe(struct pci_dev *pci, const struct pci_device_id *id) return 0; err_i915_init: + pci_free_irq(pci, 0, adev); + pci_free_irq(pci, 0, bus); + pci_free_irq_vectors(pci); pci_clear_master(pci); pci_set_drvdata(pci, NULL); err_acquire_irq: diff --git a/sound/soc/intel/avs/topology.c b/sound/soc/intel/avs/topology.c index 778236d3fd28..48b3c67c9103 100644 --- a/sound/soc/intel/avs/topology.c +++ b/sound/soc/intel/avs/topology.c @@ -857,7 +857,7 @@ assign_copier_gtw_instance(struct snd_soc_component *comp, struct avs_tplg_modcf } /* If topology sets value don't overwrite it */ - if (cfg->copier.vindex.i2s.instance) + if (cfg->copier.vindex.val) return; mach = dev_get_platdata(comp->card->dev); diff --git a/sound/soc/intel/boards/bytcht_cx2072x.c b/sound/soc/intel/boards/bytcht_cx2072x.c index 10a84a2c1036..c014d85a08b2 100644 --- a/sound/soc/intel/boards/bytcht_cx2072x.c +++ b/sound/soc/intel/boards/bytcht_cx2072x.c @@ -241,7 +241,8 @@ static int snd_byt_cht_cx2072x_probe(struct platform_device *pdev) /* fix index of codec dai */ for (i = 0; i < ARRAY_SIZE(byt_cht_cx2072x_dais); i++) { - if (!strcmp(byt_cht_cx2072x_dais[i].codecs->name, + if (byt_cht_cx2072x_dais[i].codecs->name && + !strcmp(byt_cht_cx2072x_dais[i].codecs->name, "i2c-14F10720:00")) { dai_index = i; break; diff --git a/sound/soc/intel/boards/bytcht_da7213.c b/sound/soc/intel/boards/bytcht_da7213.c index 7e5eea690023..f4ac3ddd148b 100644 --- a/sound/soc/intel/boards/bytcht_da7213.c +++ b/sound/soc/intel/boards/bytcht_da7213.c @@ -245,7 +245,8 @@ static int bytcht_da7213_probe(struct platform_device *pdev) /* fix index of codec dai */ for (i = 0; i < ARRAY_SIZE(dailink); i++) { - if (!strcmp(dailink[i].codecs->name, "i2c-DLGS7213:00")) { + if (dailink[i].codecs->name && + !strcmp(dailink[i].codecs->name, "i2c-DLGS7213:00")) { dai_index = i; break; } diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c index 1564a88a885e..2fcec2e02bb5 100644 --- a/sound/soc/intel/boards/bytcht_es8316.c +++ b/sound/soc/intel/boards/bytcht_es8316.c @@ -546,7 +546,8 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) /* fix index of codec dai */ for (i = 0; i < ARRAY_SIZE(byt_cht_es8316_dais); i++) { - if (!strcmp(byt_cht_es8316_dais[i].codecs->name, + if (byt_cht_es8316_dais[i].codecs->name && + !strcmp(byt_cht_es8316_dais[i].codecs->name, "i2c-ESSX8316:00")) { dai_index = i; break; diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index 42466b4b1ca4..03be5e26ec4a 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -1652,7 +1652,8 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) /* fix index of codec dai */ for (i = 0; i < ARRAY_SIZE(byt_rt5640_dais); i++) { - if (!strcmp(byt_rt5640_dais[i].codecs->name, + if (byt_rt5640_dais[i].codecs->name && + !strcmp(byt_rt5640_dais[i].codecs->name, "i2c-10EC5640:00")) { dai_index = i; break; diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c index f9fe8414f454..80c841b000a3 100644 --- a/sound/soc/intel/boards/bytcr_rt5651.c +++ b/sound/soc/intel/boards/bytcr_rt5651.c @@ -910,7 +910,8 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev) /* fix index of codec dai */ for (i = 0; i < ARRAY_SIZE(byt_rt5651_dais); i++) { - if (!strcmp(byt_rt5651_dais[i].codecs->name, + if (byt_rt5651_dais[i].codecs->name && + !strcmp(byt_rt5651_dais[i].codecs->name, "i2c-10EC5651:00")) { dai_index = i; break; diff --git a/sound/soc/intel/boards/bytcr_wm5102.c b/sound/soc/intel/boards/bytcr_wm5102.c index 6978ebde6693..cccb5e90c0fe 100644 --- a/sound/soc/intel/boards/bytcr_wm5102.c +++ b/sound/soc/intel/boards/bytcr_wm5102.c @@ -605,7 +605,8 @@ static int snd_byt_wm5102_mc_probe(struct platform_device *pdev) /* find index of codec dai */ for (i = 0; i < ARRAY_SIZE(byt_wm5102_dais); i++) { - if (!strcmp(byt_wm5102_dais[i].codecs->name, + if (byt_wm5102_dais[i].codecs->name && + !strcmp(byt_wm5102_dais[i].codecs->name, "wm5102-codec")) { dai_index = i; break; diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c index c952a96cde7e..eb41b7115d01 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5645.c +++ b/sound/soc/intel/boards/cht_bsw_rt5645.c @@ -40,7 +40,6 @@ struct cht_acpi_card { struct cht_mc_private { struct snd_soc_jack jack; struct cht_acpi_card *acpi_card; - char codec_name[SND_ACPI_I2C_ID_LEN]; struct clk *mclk; }; @@ -567,14 +566,14 @@ static int snd_cht_mc_probe(struct platform_device *pdev) } card->dev = &pdev->dev; - sprintf(drv->codec_name, "i2c-%s:00", drv->acpi_card->codec_id); /* set correct codec name */ for (i = 0; i < ARRAY_SIZE(cht_dailink); i++) - if (!strcmp(card->dai_link[i].codecs->name, + if (cht_dailink[i].codecs->name && + !strcmp(cht_dailink[i].codecs->name, "i2c-10EC5645:00")) { - card->dai_link[i].codecs->name = drv->codec_name; dai_index = i; + break; } /* fixup codec name based on HID */ diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c index 8cf0b33cc02e..be2d1a8dbca8 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5672.c +++ b/sound/soc/intel/boards/cht_bsw_rt5672.c @@ -466,7 +466,8 @@ static int snd_cht_mc_probe(struct platform_device *pdev) /* find index of codec dai */ for (i = 0; i < ARRAY_SIZE(cht_dailink); i++) { - if (!strcmp(cht_dailink[i].codecs->name, RT5672_I2C_DEFAULT)) { + if (cht_dailink[i].codecs->name && + !strcmp(cht_dailink[i].codecs->name, RT5672_I2C_DEFAULT)) { dai_index = i; break; } diff --git a/sound/soc/qcom/qdsp6/q6apm-dai.c b/sound/soc/qcom/qdsp6/q6apm-dai.c index 052e40cb38fe..00bbd291be5c 100644 --- a/sound/soc/qcom/qdsp6/q6apm-dai.c +++ b/sound/soc/qcom/qdsp6/q6apm-dai.c @@ -123,7 +123,7 @@ static struct snd_pcm_hardware q6apm_dai_hardware_playback = { .fifo_size = 0, }; -static void event_handler(uint32_t opcode, uint32_t token, uint32_t *payload, void *priv) +static void event_handler(uint32_t opcode, uint32_t token, void *payload, void *priv) { struct q6apm_dai_rtd *prtd = priv; struct snd_pcm_substream *substream = prtd->substream; @@ -157,7 +157,7 @@ static void event_handler(uint32_t opcode, uint32_t token, uint32_t *payload, vo } static void event_handler_compr(uint32_t opcode, uint32_t token, - uint32_t *payload, void *priv) + void *payload, void *priv) { struct q6apm_dai_rtd *prtd = priv; struct snd_compr_stream *substream = prtd->cstream; @@ -352,7 +352,7 @@ static int q6apm_dai_open(struct snd_soc_component *component, spin_lock_init(&prtd->lock); prtd->substream = substream; - prtd->graph = q6apm_graph_open(dev, (q6apm_cb)event_handler, prtd, graph_id); + prtd->graph = q6apm_graph_open(dev, event_handler, prtd, graph_id); if (IS_ERR(prtd->graph)) { dev_err(dev, "%s: Could not allocate memory\n", __func__); ret = PTR_ERR(prtd->graph); @@ -496,7 +496,7 @@ static int q6apm_dai_compr_open(struct snd_soc_component *component, return -ENOMEM; prtd->cstream = stream; - prtd->graph = q6apm_graph_open(dev, (q6apm_cb)event_handler_compr, prtd, graph_id); + prtd->graph = q6apm_graph_open(dev, event_handler_compr, prtd, graph_id); if (IS_ERR(prtd->graph)) { ret = PTR_ERR(prtd->graph); kfree(prtd); diff --git a/sound/soc/sof/amd/acp-ipc.c b/sound/soc/sof/amd/acp-ipc.c index 2743f07a5e08..b44b1b1adb6e 100644 --- a/sound/soc/sof/amd/acp-ipc.c +++ b/sound/soc/sof/amd/acp-ipc.c @@ -188,11 +188,13 @@ irqreturn_t acp_sof_ipc_irq_thread(int irq, void *context) dsp_ack = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + dsp_ack_write); if (dsp_ack) { + spin_lock_irq(&sdev->ipc_lock); /* handle immediate reply from DSP core */ acp_dsp_ipc_get_reply(sdev); snd_sof_ipc_reply(sdev, 0); /* set the done bit */ acp_dsp_ipc_dsp_done(sdev); + spin_unlock_irq(&sdev->ipc_lock); ipc_irq = true; } diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c index 32a741fcb84f..07632ae6ccf5 100644 --- a/sound/soc/sof/amd/acp.c +++ b/sound/soc/sof/amd/acp.c @@ -355,21 +355,20 @@ static irqreturn_t acp_irq_thread(int irq, void *context) unsigned int count = ACP_HW_SEM_RETRY_COUNT; spin_lock_irq(&sdev->ipc_lock); - while (snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->hw_semaphore_offset)) { - /* Wait until acquired HW Semaphore lock or timeout */ - count--; - if (!count) { - dev_err(sdev->dev, "%s: Failed to acquire HW lock\n", __func__); - spin_unlock_irq(&sdev->ipc_lock); - return IRQ_NONE; - } + /* Wait until acquired HW Semaphore lock or timeout */ + while (snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->hw_semaphore_offset) && --count) + ; + spin_unlock_irq(&sdev->ipc_lock); + + if (!count) { + dev_err(sdev->dev, "%s: Failed to acquire HW lock\n", __func__); + return IRQ_NONE; } sof_ops(sdev)->irq_thread(irq, sdev); /* Unlock or Release HW Semaphore */ snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->hw_semaphore_offset, 0x0); - spin_unlock_irq(&sdev->ipc_lock); return IRQ_HANDLED; }; diff --git a/sound/soc/sof/intel/pci-lnl.c b/sound/soc/sof/intel/pci-lnl.c index 78a57eb9cbc3..b26ffe767fab 100644 --- a/sound/soc/sof/intel/pci-lnl.c +++ b/sound/soc/sof/intel/pci-lnl.c @@ -36,7 +36,7 @@ static const struct sof_dev_desc lnl_desc = { [SOF_IPC_TYPE_4] = "intel/sof-ipc4/lnl", }, .default_tplg_path = { - [SOF_IPC_TYPE_4] = "intel/sof-ace-tplg", + [SOF_IPC_TYPE_4] = "intel/sof-ipc4-tplg", }, .default_fw_filename = { [SOF_IPC_TYPE_4] = "sof-lnl.ri", diff --git a/sound/soc/sof/intel/pci-tgl.c b/sound/soc/sof/intel/pci-tgl.c index 0660d4b2ac96..a361ee9d1107 100644 --- a/sound/soc/sof/intel/pci-tgl.c +++ b/sound/soc/sof/intel/pci-tgl.c @@ -33,18 +33,18 @@ static const struct sof_dev_desc tgl_desc = { .dspless_mode_supported = true, /* Only supported for HDaudio */ .default_fw_path = { [SOF_IPC_TYPE_3] = "intel/sof", - [SOF_IPC_TYPE_4] = "intel/avs/tgl", + [SOF_IPC_TYPE_4] = "intel/sof-ipc4/tgl", }, .default_lib_path = { - [SOF_IPC_TYPE_4] = "intel/avs-lib/tgl", + [SOF_IPC_TYPE_4] = "intel/sof-ipc4-lib/tgl", }, .default_tplg_path = { [SOF_IPC_TYPE_3] = "intel/sof-tplg", - [SOF_IPC_TYPE_4] = "intel/avs-tplg", + [SOF_IPC_TYPE_4] = "intel/sof-ipc4-tplg", }, .default_fw_filename = { [SOF_IPC_TYPE_3] = "sof-tgl.ri", - [SOF_IPC_TYPE_4] = "dsp_basefw.bin", + [SOF_IPC_TYPE_4] = "sof-tgl.ri", }, .nocodec_tplg_filename = "sof-tgl-nocodec.tplg", .ops = &sof_tgl_ops, @@ -66,18 +66,18 @@ static const struct sof_dev_desc tglh_desc = { .dspless_mode_supported = true, /* Only supported for HDaudio */ .default_fw_path = { [SOF_IPC_TYPE_3] = "intel/sof", - [SOF_IPC_TYPE_4] = "intel/avs/tgl-h", + [SOF_IPC_TYPE_4] = "intel/sof-ipc4/tgl-h", }, .default_lib_path = { - [SOF_IPC_TYPE_4] = "intel/avs-lib/tgl-h", + [SOF_IPC_TYPE_4] = "intel/sof-ipc4-lib/tgl-h", }, .default_tplg_path = { [SOF_IPC_TYPE_3] = "intel/sof-tplg", - [SOF_IPC_TYPE_4] = "intel/avs-tplg", + [SOF_IPC_TYPE_4] = "intel/sof-ipc4-tplg", }, .default_fw_filename = { [SOF_IPC_TYPE_3] = "sof-tgl-h.ri", - [SOF_IPC_TYPE_4] = "dsp_basefw.bin", + [SOF_IPC_TYPE_4] = "sof-tgl-h.ri", }, .nocodec_tplg_filename = "sof-tgl-nocodec.tplg", .ops = &sof_tgl_ops, @@ -98,18 +98,18 @@ static const struct sof_dev_desc ehl_desc = { .dspless_mode_supported = true, /* Only supported for HDaudio */ .default_fw_path = { [SOF_IPC_TYPE_3] = "intel/sof", - [SOF_IPC_TYPE_4] = "intel/avs/ehl", + [SOF_IPC_TYPE_4] = "intel/sof-ipc4/ehl", }, .default_lib_path = { - [SOF_IPC_TYPE_4] = "intel/avs-lib/ehl", + [SOF_IPC_TYPE_4] = "intel/sof-ipc4-lib/ehl", }, .default_tplg_path = { [SOF_IPC_TYPE_3] = "intel/sof-tplg", - [SOF_IPC_TYPE_4] = "intel/avs-tplg", + [SOF_IPC_TYPE_4] = "intel/sof-ipc4-tplg", }, .default_fw_filename = { [SOF_IPC_TYPE_3] = "sof-ehl.ri", - [SOF_IPC_TYPE_4] = "dsp_basefw.bin", + [SOF_IPC_TYPE_4] = "sof-ehl.ri", }, .nocodec_tplg_filename = "sof-ehl-nocodec.tplg", .ops = &sof_tgl_ops, @@ -131,18 +131,18 @@ static const struct sof_dev_desc adls_desc = { .dspless_mode_supported = true, /* Only supported for HDaudio */ .default_fw_path = { [SOF_IPC_TYPE_3] = "intel/sof", - [SOF_IPC_TYPE_4] = "intel/avs/adl-s", + [SOF_IPC_TYPE_4] = "intel/sof-ipc4/adl-s", }, .default_lib_path = { - [SOF_IPC_TYPE_4] = "intel/avs-lib/adl-s", + [SOF_IPC_TYPE_4] = "intel/sof-ipc4-lib/adl-s", }, .default_tplg_path = { [SOF_IPC_TYPE_3] = "intel/sof-tplg", - [SOF_IPC_TYPE_4] = "intel/avs-tplg", + [SOF_IPC_TYPE_4] = "intel/sof-ipc4-tplg", }, .default_fw_filename = { [SOF_IPC_TYPE_3] = "sof-adl-s.ri", - [SOF_IPC_TYPE_4] = "dsp_basefw.bin", + [SOF_IPC_TYPE_4] = "sof-adl-s.ri", }, .nocodec_tplg_filename = "sof-adl-nocodec.tplg", .ops = &sof_tgl_ops, @@ -164,18 +164,18 @@ static const struct sof_dev_desc adl_desc = { .dspless_mode_supported = true, /* Only supported for HDaudio */ .default_fw_path = { [SOF_IPC_TYPE_3] = "intel/sof", - [SOF_IPC_TYPE_4] = "intel/avs/adl", + [SOF_IPC_TYPE_4] = "intel/sof-ipc4/adl", }, .default_lib_path = { - [SOF_IPC_TYPE_4] = "intel/avs-lib/adl", + [SOF_IPC_TYPE_4] = "intel/sof-ipc4-lib/adl", }, .default_tplg_path = { [SOF_IPC_TYPE_3] = "intel/sof-tplg", - [SOF_IPC_TYPE_4] = "intel/avs-tplg", + [SOF_IPC_TYPE_4] = "intel/sof-ipc4-tplg", }, .default_fw_filename = { [SOF_IPC_TYPE_3] = "sof-adl.ri", - [SOF_IPC_TYPE_4] = "dsp_basefw.bin", + [SOF_IPC_TYPE_4] = "sof-adl.ri", }, .nocodec_tplg_filename = "sof-adl-nocodec.tplg", .ops = &sof_tgl_ops, @@ -197,18 +197,18 @@ static const struct sof_dev_desc adl_n_desc = { .dspless_mode_supported = true, /* Only supported for HDaudio */ .default_fw_path = { [SOF_IPC_TYPE_3] = "intel/sof", - [SOF_IPC_TYPE_4] = "intel/avs/adl-n", + [SOF_IPC_TYPE_4] = "intel/sof-ipc4/adl-n", }, .default_lib_path = { - [SOF_IPC_TYPE_4] = "intel/avs-lib/adl-n", + [SOF_IPC_TYPE_4] = "intel/sof-ipc4-lib/adl-n", }, .default_tplg_path = { [SOF_IPC_TYPE_3] = "intel/sof-tplg", - [SOF_IPC_TYPE_4] = "intel/avs-tplg", + [SOF_IPC_TYPE_4] = "intel/sof-ipc4-tplg", }, .default_fw_filename = { [SOF_IPC_TYPE_3] = "sof-adl-n.ri", - [SOF_IPC_TYPE_4] = "dsp_basefw.bin", + [SOF_IPC_TYPE_4] = "sof-adl-n.ri", }, .nocodec_tplg_filename = "sof-adl-nocodec.tplg", .ops = &sof_tgl_ops, @@ -230,18 +230,18 @@ static const struct sof_dev_desc rpls_desc = { .dspless_mode_supported = true, /* Only supported for HDaudio */ .default_fw_path = { [SOF_IPC_TYPE_3] = "intel/sof", - [SOF_IPC_TYPE_4] = "intel/avs/rpl-s", + [SOF_IPC_TYPE_4] = "intel/sof-ipc4/rpl-s", }, .default_lib_path = { - [SOF_IPC_TYPE_4] = "intel/avs-lib/rpl-s", + [SOF_IPC_TYPE_4] = "intel/sof-ipc4-lib/rpl-s", }, .default_tplg_path = { [SOF_IPC_TYPE_3] = "intel/sof-tplg", - [SOF_IPC_TYPE_4] = "intel/avs-tplg", + [SOF_IPC_TYPE_4] = "intel/sof-ipc4-tplg", }, .default_fw_filename = { [SOF_IPC_TYPE_3] = "sof-rpl-s.ri", - [SOF_IPC_TYPE_4] = "dsp_basefw.bin", + [SOF_IPC_TYPE_4] = "sof-rpl-s.ri", }, .nocodec_tplg_filename = "sof-rpl-nocodec.tplg", .ops = &sof_tgl_ops, @@ -263,18 +263,18 @@ static const struct sof_dev_desc rpl_desc = { .dspless_mode_supported = true, /* Only supported for HDaudio */ .default_fw_path = { [SOF_IPC_TYPE_3] = "intel/sof", - [SOF_IPC_TYPE_4] = "intel/avs/rpl", + [SOF_IPC_TYPE_4] = "intel/sof-ipc4/rpl", }, .default_lib_path = { - [SOF_IPC_TYPE_4] = "intel/avs-lib/rpl", + [SOF_IPC_TYPE_4] = "intel/sof-ipc4-lib/rpl", }, .default_tplg_path = { [SOF_IPC_TYPE_3] = "intel/sof-tplg", - [SOF_IPC_TYPE_4] = "intel/avs-tplg", + [SOF_IPC_TYPE_4] = "intel/sof-ipc4-tplg", }, .default_fw_filename = { [SOF_IPC_TYPE_3] = "sof-rpl.ri", - [SOF_IPC_TYPE_4] = "dsp_basefw.bin", + [SOF_IPC_TYPE_4] = "sof-rpl.ri", }, .nocodec_tplg_filename = "sof-rpl-nocodec.tplg", .ops = &sof_tgl_ops, diff --git a/sound/soc/sof/ipc3-topology.c b/sound/soc/sof/ipc3-topology.c index a8832a1c1a24..d47698f4be2d 100644 --- a/sound/soc/sof/ipc3-topology.c +++ b/sound/soc/sof/ipc3-topology.c @@ -2360,27 +2360,16 @@ static int sof_tear_down_left_over_pipelines(struct snd_sof_dev *sdev) return 0; } -/* - * For older firmware, this function doesn't free widgets for static pipelines during suspend. - * It only resets use_count for all widgets. - */ -static int sof_ipc3_tear_down_all_pipelines(struct snd_sof_dev *sdev, bool verify) +static int sof_ipc3_free_widgets_in_list(struct snd_sof_dev *sdev, bool include_scheduler, + bool *dyn_widgets, bool verify) { struct sof_ipc_fw_version *v = &sdev->fw_ready.version; struct snd_sof_widget *swidget; - struct snd_sof_route *sroute; - bool dyn_widgets = false; int ret; - /* - * This function is called during suspend and for one-time topology verification during - * first boot. In both cases, there is no need to protect swidget->use_count and - * sroute->setup because during suspend all running streams are suspended and during - * topology loading the sound card unavailable to open PCMs. - */ list_for_each_entry(swidget, &sdev->widget_list, list) { if (swidget->dynamic_pipeline_widget) { - dyn_widgets = true; + *dyn_widgets = true; continue; } @@ -2395,11 +2384,49 @@ static int sof_ipc3_tear_down_all_pipelines(struct snd_sof_dev *sdev, bool verif continue; } + if (include_scheduler && swidget->id != snd_soc_dapm_scheduler) + continue; + + if (!include_scheduler && swidget->id == snd_soc_dapm_scheduler) + continue; + ret = sof_widget_free(sdev, swidget); if (ret < 0) return ret; } + return 0; +} + +/* + * For older firmware, this function doesn't free widgets for static pipelines during suspend. + * It only resets use_count for all widgets. + */ +static int sof_ipc3_tear_down_all_pipelines(struct snd_sof_dev *sdev, bool verify) +{ + struct sof_ipc_fw_version *v = &sdev->fw_ready.version; + struct snd_sof_widget *swidget; + struct snd_sof_route *sroute; + bool dyn_widgets = false; + int ret; + + /* + * This function is called during suspend and for one-time topology verification during + * first boot. In both cases, there is no need to protect swidget->use_count and + * sroute->setup because during suspend all running streams are suspended and during + * topology loading the sound card unavailable to open PCMs. Do not free the scheduler + * widgets yet so that the secondary cores do not get powered down before all the widgets + * associated with the scheduler are freed. + */ + ret = sof_ipc3_free_widgets_in_list(sdev, false, &dyn_widgets, verify); + if (ret < 0) + return ret; + + /* free all the scheduler widgets now */ + ret = sof_ipc3_free_widgets_in_list(sdev, true, &dyn_widgets, verify); + if (ret < 0) + return ret; + /* * Tear down all pipelines associated with PCMs that did not get suspended * and unset the prepare flag so that they can be set up again during resume. diff --git a/sound/soc/sof/ipc3.c b/sound/soc/sof/ipc3.c index fb40378ad084..c03dd513fbff 100644 --- a/sound/soc/sof/ipc3.c +++ b/sound/soc/sof/ipc3.c @@ -1067,7 +1067,7 @@ static void sof_ipc3_rx_msg(struct snd_sof_dev *sdev) return; } - if (hdr.size < sizeof(hdr)) { + if (hdr.size < sizeof(hdr) || hdr.size > SOF_IPC_MSG_MAX_SIZE) { dev_err(sdev->dev, "The received message size is invalid\n"); return; } diff --git a/sound/soc/sof/ipc4-pcm.c b/sound/soc/sof/ipc4-pcm.c index 85d3f390e4b2..07eb5c6d4adf 100644 --- a/sound/soc/sof/ipc4-pcm.c +++ b/sound/soc/sof/ipc4-pcm.c @@ -413,7 +413,18 @@ skip_pause_transition: ret = sof_ipc4_set_multi_pipeline_state(sdev, state, trigger_list); if (ret < 0) { dev_err(sdev->dev, "failed to set final state %d for all pipelines\n", state); - goto free; + /* + * workaround: if the firmware is crashed while setting the + * pipelines to reset state we must ignore the error code and + * reset it to 0. + * Since the firmware is crashed we will not send IPC messages + * and we are going to see errors printed, but the state of the + * widgets will be correct for the next boot. + */ + if (sdev->fw_state != SOF_FW_CRASHED || state != SOF_IPC4_PIPE_RESET) + goto free; + + ret = 0; } /* update RUNNING/RESET state for all pipelines that were just triggered */ diff --git a/sound/usb/midi.c b/sound/usb/midi.c index 6b0993258e03..c1f2e5a03de9 100644 --- a/sound/usb/midi.c +++ b/sound/usb/midi.c @@ -1742,50 +1742,44 @@ static void snd_usbmidi_get_port_info(struct snd_rawmidi *rmidi, int number, } } -static struct usb_midi_in_jack_descriptor *find_usb_in_jack_descriptor( - struct usb_host_interface *hostif, uint8_t jack_id) +/* return iJack for the corresponding jackID */ +static int find_usb_ijack(struct usb_host_interface *hostif, uint8_t jack_id) { unsigned char *extra = hostif->extra; int extralen = hostif->extralen; + struct usb_descriptor_header *h; + struct usb_midi_out_jack_descriptor *outjd; + struct usb_midi_in_jack_descriptor *injd; + size_t sz; while (extralen > 4) { - struct usb_midi_in_jack_descriptor *injd = - (struct usb_midi_in_jack_descriptor *)extra; + h = (struct usb_descriptor_header *)extra; + if (h->bDescriptorType != USB_DT_CS_INTERFACE) + goto next; + outjd = (struct usb_midi_out_jack_descriptor *)h; + if (h->bLength >= sizeof(*outjd) && + outjd->bDescriptorSubtype == UAC_MIDI_OUT_JACK && + outjd->bJackID == jack_id) { + sz = USB_DT_MIDI_OUT_SIZE(outjd->bNrInputPins); + if (outjd->bLength < sz) + goto next; + return *(extra + sz - 1); + } + + injd = (struct usb_midi_in_jack_descriptor *)h; if (injd->bLength >= sizeof(*injd) && - injd->bDescriptorType == USB_DT_CS_INTERFACE && injd->bDescriptorSubtype == UAC_MIDI_IN_JACK && - injd->bJackID == jack_id) - return injd; - if (!extra[0]) - break; - extralen -= extra[0]; - extra += extra[0]; - } - return NULL; -} - -static struct usb_midi_out_jack_descriptor *find_usb_out_jack_descriptor( - struct usb_host_interface *hostif, uint8_t jack_id) -{ - unsigned char *extra = hostif->extra; - int extralen = hostif->extralen; + injd->bJackID == jack_id) + return injd->iJack; - while (extralen > 4) { - struct usb_midi_out_jack_descriptor *outjd = - (struct usb_midi_out_jack_descriptor *)extra; - - if (outjd->bLength >= sizeof(*outjd) && - outjd->bDescriptorType == USB_DT_CS_INTERFACE && - outjd->bDescriptorSubtype == UAC_MIDI_OUT_JACK && - outjd->bJackID == jack_id) - return outjd; +next: if (!extra[0]) break; extralen -= extra[0]; extra += extra[0]; } - return NULL; + return 0; } static void snd_usbmidi_init_substream(struct snd_usb_midi *umidi, @@ -1796,13 +1790,10 @@ static void snd_usbmidi_init_substream(struct snd_usb_midi *umidi, const char *name_format; struct usb_interface *intf; struct usb_host_interface *hostif; - struct usb_midi_in_jack_descriptor *injd; - struct usb_midi_out_jack_descriptor *outjd; uint8_t jack_name_buf[32]; uint8_t *default_jack_name = "MIDI"; uint8_t *jack_name = default_jack_name; uint8_t iJack; - size_t sz; int res; struct snd_rawmidi_substream *substream = @@ -1816,21 +1807,7 @@ static void snd_usbmidi_init_substream(struct snd_usb_midi *umidi, intf = umidi->iface; if (intf && jack_id >= 0) { hostif = intf->cur_altsetting; - iJack = 0; - if (stream != SNDRV_RAWMIDI_STREAM_OUTPUT) { - /* in jacks connect to outs */ - outjd = find_usb_out_jack_descriptor(hostif, jack_id); - if (outjd) { - sz = USB_DT_MIDI_OUT_SIZE(outjd->bNrInputPins); - if (outjd->bLength >= sz) - iJack = *(((uint8_t *) outjd) + sz - sizeof(uint8_t)); - } - } else { - /* and out jacks connect to ins */ - injd = find_usb_in_jack_descriptor(hostif, jack_id); - if (injd) - iJack = injd->iJack; - } + iJack = find_usb_ijack(hostif, jack_id); if (iJack != 0) { res = usb_string(umidi->dev, iJack, jack_name_buf, ARRAY_SIZE(jack_name_buf)); diff --git a/tools/iio/iio_utils.c b/tools/iio/iio_utils.c index 6a00a6eecaef..c5c5082cb24e 100644 --- a/tools/iio/iio_utils.c +++ b/tools/iio/iio_utils.c @@ -376,7 +376,7 @@ int build_channel_array(const char *device_dir, int buffer_idx, goto error_close_dir; } - seekdir(dp, 0); + rewinddir(dp); while (ent = readdir(dp), ent) { if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"), "_en") == 0) { diff --git a/tools/testing/selftests/dt/test_unprobed_devices.sh b/tools/testing/selftests/dt/test_unprobed_devices.sh index b07af2a4c4de..7fae90293a9d 100755 --- a/tools/testing/selftests/dt/test_unprobed_devices.sh +++ b/tools/testing/selftests/dt/test_unprobed_devices.sh @@ -33,8 +33,8 @@ if [[ ! -d "${PDT}" ]]; then fi nodes_compatible=$( - for node_compat in $(find ${PDT} -name compatible); do - node=$(dirname "${node_compat}") + for node in $(find ${PDT} -type d); do + [ ! -f "${node}"/compatible ] && continue # Check if node is available if [[ -e "${node}"/status ]]; then status=$(tr -d '\000' < "${node}"/status) @@ -46,10 +46,11 @@ nodes_compatible=$( nodes_dev_bound=$( IFS=$'\n' - for uevent in $(find /sys/devices -name uevent); do - if [[ -d "$(dirname "${uevent}")"/driver ]]; then - grep '^OF_FULLNAME=' "${uevent}" | sed -e 's|OF_FULLNAME=||' - fi + for dev_dir in $(find /sys/devices -type d); do + [ ! -f "${dev_dir}"/uevent ] && continue + [ ! -d "${dev_dir}"/driver ] && continue + + grep '^OF_FULLNAME=' "${dev_dir}"/uevent | sed -e 's|OF_FULLNAME=||' done ) diff --git a/tools/testing/selftests/kvm/aarch64/arch_timer.c b/tools/testing/selftests/kvm/aarch64/arch_timer.c index 274b8465b42a..2cb8dd1f8275 100644 --- a/tools/testing/selftests/kvm/aarch64/arch_timer.c +++ b/tools/testing/selftests/kvm/aarch64/arch_timer.c @@ -248,7 +248,7 @@ static void *test_vcpu_run(void *arg) REPORT_GUEST_ASSERT(uc); break; default: - TEST_FAIL("Unexpected guest exit\n"); + TEST_FAIL("Unexpected guest exit"); } return NULL; @@ -287,7 +287,7 @@ static int test_migrate_vcpu(unsigned int vcpu_idx) /* Allow the error where the vCPU thread is already finished */ TEST_ASSERT(ret == 0 || ret == ESRCH, - "Failed to migrate the vCPU:%u to pCPU: %u; ret: %d\n", + "Failed to migrate the vCPU:%u to pCPU: %u; ret: %d", vcpu_idx, new_pcpu, ret); return ret; @@ -326,12 +326,12 @@ static void test_run(struct kvm_vm *vm) pthread_mutex_init(&vcpu_done_map_lock, NULL); vcpu_done_map = bitmap_zalloc(test_args.nr_vcpus); - TEST_ASSERT(vcpu_done_map, "Failed to allocate vcpu done bitmap\n"); + TEST_ASSERT(vcpu_done_map, "Failed to allocate vcpu done bitmap"); for (i = 0; i < (unsigned long)test_args.nr_vcpus; i++) { ret = pthread_create(&pt_vcpu_run[i], NULL, test_vcpu_run, (void *)(unsigned long)i); - TEST_ASSERT(!ret, "Failed to create vCPU-%d pthread\n", i); + TEST_ASSERT(!ret, "Failed to create vCPU-%d pthread", i); } /* Spawn a thread to control the vCPU migrations */ @@ -340,7 +340,7 @@ static void test_run(struct kvm_vm *vm) ret = pthread_create(&pt_vcpu_migration, NULL, test_vcpu_migration, NULL); - TEST_ASSERT(!ret, "Failed to create the migration pthread\n"); + TEST_ASSERT(!ret, "Failed to create the migration pthread"); } @@ -384,7 +384,7 @@ static struct kvm_vm *test_vm_create(void) if (kvm_has_cap(KVM_CAP_COUNTER_OFFSET)) vm_ioctl(vm, KVM_ARM_SET_COUNTER_OFFSET, &test_args.offset); else - TEST_FAIL("no support for global offset\n"); + TEST_FAIL("no support for global offset"); } for (i = 0; i < nr_vcpus; i++) diff --git a/tools/testing/selftests/kvm/aarch64/hypercalls.c b/tools/testing/selftests/kvm/aarch64/hypercalls.c index 31f66ba97228..27c10e7a7e01 100644 --- a/tools/testing/selftests/kvm/aarch64/hypercalls.c +++ b/tools/testing/selftests/kvm/aarch64/hypercalls.c @@ -175,18 +175,18 @@ static void test_fw_regs_before_vm_start(struct kvm_vcpu *vcpu) /* First 'read' should be an upper limit of the features supported */ vcpu_get_reg(vcpu, reg_info->reg, &val); TEST_ASSERT(val == FW_REG_ULIMIT_VAL(reg_info->max_feat_bit), - "Expected all the features to be set for reg: 0x%lx; expected: 0x%lx; read: 0x%lx\n", + "Expected all the features to be set for reg: 0x%lx; expected: 0x%lx; read: 0x%lx", reg_info->reg, FW_REG_ULIMIT_VAL(reg_info->max_feat_bit), val); /* Test a 'write' by disabling all the features of the register map */ ret = __vcpu_set_reg(vcpu, reg_info->reg, 0); TEST_ASSERT(ret == 0, - "Failed to clear all the features of reg: 0x%lx; ret: %d\n", + "Failed to clear all the features of reg: 0x%lx; ret: %d", reg_info->reg, errno); vcpu_get_reg(vcpu, reg_info->reg, &val); TEST_ASSERT(val == 0, - "Expected all the features to be cleared for reg: 0x%lx\n", reg_info->reg); + "Expected all the features to be cleared for reg: 0x%lx", reg_info->reg); /* * Test enabling a feature that's not supported. @@ -195,7 +195,7 @@ static void test_fw_regs_before_vm_start(struct kvm_vcpu *vcpu) if (reg_info->max_feat_bit < 63) { ret = __vcpu_set_reg(vcpu, reg_info->reg, BIT(reg_info->max_feat_bit + 1)); TEST_ASSERT(ret != 0 && errno == EINVAL, - "Unexpected behavior or return value (%d) while setting an unsupported feature for reg: 0x%lx\n", + "Unexpected behavior or return value (%d) while setting an unsupported feature for reg: 0x%lx", errno, reg_info->reg); } } @@ -216,7 +216,7 @@ static void test_fw_regs_after_vm_start(struct kvm_vcpu *vcpu) */ vcpu_get_reg(vcpu, reg_info->reg, &val); TEST_ASSERT(val == 0, - "Expected all the features to be cleared for reg: 0x%lx\n", + "Expected all the features to be cleared for reg: 0x%lx", reg_info->reg); /* @@ -226,7 +226,7 @@ static void test_fw_regs_after_vm_start(struct kvm_vcpu *vcpu) */ ret = __vcpu_set_reg(vcpu, reg_info->reg, FW_REG_ULIMIT_VAL(reg_info->max_feat_bit)); TEST_ASSERT(ret != 0 && errno == EBUSY, - "Unexpected behavior or return value (%d) while setting a feature while VM is running for reg: 0x%lx\n", + "Unexpected behavior or return value (%d) while setting a feature while VM is running for reg: 0x%lx", errno, reg_info->reg); } } @@ -265,7 +265,7 @@ static void test_guest_stage(struct kvm_vm **vm, struct kvm_vcpu **vcpu) case TEST_STAGE_HVC_IFACE_FALSE_INFO: break; default: - TEST_FAIL("Unknown test stage: %d\n", prev_stage); + TEST_FAIL("Unknown test stage: %d", prev_stage); } } @@ -294,7 +294,7 @@ static void test_run(void) REPORT_GUEST_ASSERT(uc); break; default: - TEST_FAIL("Unexpected guest exit\n"); + TEST_FAIL("Unexpected guest exit"); } } diff --git a/tools/testing/selftests/kvm/aarch64/page_fault_test.c b/tools/testing/selftests/kvm/aarch64/page_fault_test.c index 08a5ca5bed56..53fddad57cbb 100644 --- a/tools/testing/selftests/kvm/aarch64/page_fault_test.c +++ b/tools/testing/selftests/kvm/aarch64/page_fault_test.c @@ -414,10 +414,10 @@ static bool punch_hole_in_backing_store(struct kvm_vm *vm, if (fd != -1) { ret = fallocate(fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, 0, paging_size); - TEST_ASSERT(ret == 0, "fallocate failed\n"); + TEST_ASSERT(ret == 0, "fallocate failed"); } else { ret = madvise(hva, paging_size, MADV_DONTNEED); - TEST_ASSERT(ret == 0, "madvise failed\n"); + TEST_ASSERT(ret == 0, "madvise failed"); } return true; @@ -501,7 +501,7 @@ static bool handle_cmd(struct kvm_vm *vm, int cmd) void fail_vcpu_run_no_handler(int ret) { - TEST_FAIL("Unexpected vcpu run failure\n"); + TEST_FAIL("Unexpected vcpu run failure"); } void fail_vcpu_run_mmio_no_syndrome_handler(int ret) diff --git a/tools/testing/selftests/kvm/aarch64/smccc_filter.c b/tools/testing/selftests/kvm/aarch64/smccc_filter.c index f4ceae9c8925..2d189f3da228 100644 --- a/tools/testing/selftests/kvm/aarch64/smccc_filter.c +++ b/tools/testing/selftests/kvm/aarch64/smccc_filter.c @@ -178,7 +178,7 @@ static void expect_call_denied(struct kvm_vcpu *vcpu) struct ucall uc; if (get_ucall(vcpu, &uc) != UCALL_SYNC) - TEST_FAIL("Unexpected ucall: %lu\n", uc.cmd); + TEST_FAIL("Unexpected ucall: %lu", uc.cmd); TEST_ASSERT(uc.args[1] == SMCCC_RET_NOT_SUPPORTED, "Unexpected SMCCC return code: %lu", uc.args[1]); diff --git a/tools/testing/selftests/kvm/aarch64/vpmu_counter_access.c b/tools/testing/selftests/kvm/aarch64/vpmu_counter_access.c index 9d51b5691349..5f9713364693 100644 --- a/tools/testing/selftests/kvm/aarch64/vpmu_counter_access.c +++ b/tools/testing/selftests/kvm/aarch64/vpmu_counter_access.c @@ -517,11 +517,11 @@ static void test_create_vpmu_vm_with_pmcr_n(uint64_t pmcr_n, bool expect_fail) if (expect_fail) TEST_ASSERT(pmcr_orig == pmcr, - "PMCR.N modified by KVM to a larger value (PMCR: 0x%lx) for pmcr_n: 0x%lx\n", + "PMCR.N modified by KVM to a larger value (PMCR: 0x%lx) for pmcr_n: 0x%lx", pmcr, pmcr_n); else TEST_ASSERT(pmcr_n == get_pmcr_n(pmcr), - "Failed to update PMCR.N to %lu (received: %lu)\n", + "Failed to update PMCR.N to %lu (received: %lu)", pmcr_n, get_pmcr_n(pmcr)); } @@ -594,12 +594,12 @@ static void run_pmregs_validity_test(uint64_t pmcr_n) */ vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(set_reg_id), ®_val); TEST_ASSERT((reg_val & (~valid_counters_mask)) == 0, - "Initial read of set_reg: 0x%llx has unimplemented counters enabled: 0x%lx\n", + "Initial read of set_reg: 0x%llx has unimplemented counters enabled: 0x%lx", KVM_ARM64_SYS_REG(set_reg_id), reg_val); vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(clr_reg_id), ®_val); TEST_ASSERT((reg_val & (~valid_counters_mask)) == 0, - "Initial read of clr_reg: 0x%llx has unimplemented counters enabled: 0x%lx\n", + "Initial read of clr_reg: 0x%llx has unimplemented counters enabled: 0x%lx", KVM_ARM64_SYS_REG(clr_reg_id), reg_val); /* @@ -611,12 +611,12 @@ static void run_pmregs_validity_test(uint64_t pmcr_n) vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(set_reg_id), ®_val); TEST_ASSERT((reg_val & (~valid_counters_mask)) == 0, - "Read of set_reg: 0x%llx has unimplemented counters enabled: 0x%lx\n", + "Read of set_reg: 0x%llx has unimplemented counters enabled: 0x%lx", KVM_ARM64_SYS_REG(set_reg_id), reg_val); vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(clr_reg_id), ®_val); TEST_ASSERT((reg_val & (~valid_counters_mask)) == 0, - "Read of clr_reg: 0x%llx has unimplemented counters enabled: 0x%lx\n", + "Read of clr_reg: 0x%llx has unimplemented counters enabled: 0x%lx", KVM_ARM64_SYS_REG(clr_reg_id), reg_val); } diff --git a/tools/testing/selftests/kvm/demand_paging_test.c b/tools/testing/selftests/kvm/demand_paging_test.c index 09c116a82a84..bf3609f71854 100644 --- a/tools/testing/selftests/kvm/demand_paging_test.c +++ b/tools/testing/selftests/kvm/demand_paging_test.c @@ -45,10 +45,10 @@ static void vcpu_worker(struct memstress_vcpu_args *vcpu_args) /* Let the guest access its memory */ ret = _vcpu_run(vcpu); - TEST_ASSERT(ret == 0, "vcpu_run failed: %d\n", ret); + TEST_ASSERT(ret == 0, "vcpu_run failed: %d", ret); if (get_ucall(vcpu, NULL) != UCALL_SYNC) { TEST_ASSERT(false, - "Invalid guest sync status: exit_reason=%s\n", + "Invalid guest sync status: exit_reason=%s", exit_reason_str(run->exit_reason)); } diff --git a/tools/testing/selftests/kvm/dirty_log_perf_test.c b/tools/testing/selftests/kvm/dirty_log_perf_test.c index d374dbcf9a53..504f6fe980e8 100644 --- a/tools/testing/selftests/kvm/dirty_log_perf_test.c +++ b/tools/testing/selftests/kvm/dirty_log_perf_test.c @@ -88,9 +88,9 @@ static void vcpu_worker(struct memstress_vcpu_args *vcpu_args) ret = _vcpu_run(vcpu); ts_diff = timespec_elapsed(start); - TEST_ASSERT(ret == 0, "vcpu_run failed: %d\n", ret); + TEST_ASSERT(ret == 0, "vcpu_run failed: %d", ret); TEST_ASSERT(get_ucall(vcpu, NULL) == UCALL_SYNC, - "Invalid guest sync status: exit_reason=%s\n", + "Invalid guest sync status: exit_reason=%s", exit_reason_str(run->exit_reason)); pr_debug("Got sync event from vCPU %d\n", vcpu_idx); diff --git a/tools/testing/selftests/kvm/dirty_log_test.c b/tools/testing/selftests/kvm/dirty_log_test.c index 6cbecf499767..eaad5b20854c 100644 --- a/tools/testing/selftests/kvm/dirty_log_test.c +++ b/tools/testing/selftests/kvm/dirty_log_test.c @@ -262,7 +262,7 @@ static void default_after_vcpu_run(struct kvm_vcpu *vcpu, int ret, int err) "vcpu run failed: errno=%d", err); TEST_ASSERT(get_ucall(vcpu, NULL) == UCALL_SYNC, - "Invalid guest sync status: exit_reason=%s\n", + "Invalid guest sync status: exit_reason=%s", exit_reason_str(run->exit_reason)); vcpu_handle_sync_stop(); @@ -376,7 +376,10 @@ static void dirty_ring_collect_dirty_pages(struct kvm_vcpu *vcpu, int slot, cleared = kvm_vm_reset_dirty_ring(vcpu->vm); - /* Cleared pages should be the same as collected */ + /* + * Cleared pages should be the same as collected, as KVM is supposed to + * clear only the entries that have been harvested. + */ TEST_ASSERT(cleared == count, "Reset dirty pages (%u) mismatch " "with collected (%u)", cleared, count); @@ -410,17 +413,11 @@ static void dirty_ring_after_vcpu_run(struct kvm_vcpu *vcpu, int ret, int err) pr_info("vcpu continues now.\n"); } else { TEST_ASSERT(false, "Invalid guest sync status: " - "exit_reason=%s\n", + "exit_reason=%s", exit_reason_str(run->exit_reason)); } } -static void dirty_ring_before_vcpu_join(void) -{ - /* Kick another round of vcpu just to make sure it will quit */ - sem_post(&sem_vcpu_cont); -} - struct log_mode { const char *name; /* Return true if this mode is supported, otherwise false */ @@ -433,7 +430,6 @@ struct log_mode { uint32_t *ring_buf_idx); /* Hook to call when after each vcpu run */ void (*after_vcpu_run)(struct kvm_vcpu *vcpu, int ret, int err); - void (*before_vcpu_join) (void); } log_modes[LOG_MODE_NUM] = { { .name = "dirty-log", @@ -452,7 +448,6 @@ struct log_mode { .supported = dirty_ring_supported, .create_vm_done = dirty_ring_create_vm_done, .collect_dirty_pages = dirty_ring_collect_dirty_pages, - .before_vcpu_join = dirty_ring_before_vcpu_join, .after_vcpu_run = dirty_ring_after_vcpu_run, }, }; @@ -513,14 +508,6 @@ static void log_mode_after_vcpu_run(struct kvm_vcpu *vcpu, int ret, int err) mode->after_vcpu_run(vcpu, ret, err); } -static void log_mode_before_vcpu_join(void) -{ - struct log_mode *mode = &log_modes[host_log_mode]; - - if (mode->before_vcpu_join) - mode->before_vcpu_join(); -} - static void generate_random_array(uint64_t *guest_array, uint64_t size) { uint64_t i; @@ -719,6 +706,7 @@ static void run_test(enum vm_guest_mode mode, void *arg) struct kvm_vm *vm; unsigned long *bmap; uint32_t ring_buf_idx = 0; + int sem_val; if (!log_mode_supported()) { print_skip("Log mode '%s' not supported", @@ -788,12 +776,22 @@ static void run_test(enum vm_guest_mode mode, void *arg) /* Start the iterations */ iteration = 1; sync_global_to_guest(vm, iteration); - host_quit = false; + WRITE_ONCE(host_quit, false); host_dirty_count = 0; host_clear_count = 0; host_track_next_count = 0; WRITE_ONCE(dirty_ring_vcpu_ring_full, false); + /* + * Ensure the previous iteration didn't leave a dangling semaphore, i.e. + * that the main task and vCPU worker were synchronized and completed + * verification of all iterations. + */ + sem_getvalue(&sem_vcpu_stop, &sem_val); + TEST_ASSERT_EQ(sem_val, 0); + sem_getvalue(&sem_vcpu_cont, &sem_val); + TEST_ASSERT_EQ(sem_val, 0); + pthread_create(&vcpu_thread, NULL, vcpu_worker, vcpu); while (iteration < p->iterations) { @@ -819,15 +817,21 @@ static void run_test(enum vm_guest_mode mode, void *arg) assert(host_log_mode == LOG_MODE_DIRTY_RING || atomic_read(&vcpu_sync_stop_requested) == false); vm_dirty_log_verify(mode, bmap); - sem_post(&sem_vcpu_cont); - iteration++; + /* + * Set host_quit before sem_vcpu_cont in the final iteration to + * ensure that the vCPU worker doesn't resume the guest. As + * above, the dirty ring test may stop and wait even when not + * explicitly request to do so, i.e. would hang waiting for a + * "continue" if it's allowed to resume the guest. + */ + if (++iteration == p->iterations) + WRITE_ONCE(host_quit, true); + + sem_post(&sem_vcpu_cont); sync_global_to_guest(vm, iteration); } - /* Tell the vcpu thread to quit */ - host_quit = true; - log_mode_before_vcpu_join(); pthread_join(vcpu_thread, NULL); pr_info("Total bits checked: dirty (%"PRIu64"), clear (%"PRIu64"), " diff --git a/tools/testing/selftests/kvm/get-reg-list.c b/tools/testing/selftests/kvm/get-reg-list.c index 8274ef04301f..91f05f78e824 100644 --- a/tools/testing/selftests/kvm/get-reg-list.c +++ b/tools/testing/selftests/kvm/get-reg-list.c @@ -152,7 +152,7 @@ static void check_supported(struct vcpu_reg_list *c) continue; __TEST_REQUIRE(kvm_has_cap(s->capability), - "%s: %s not available, skipping tests\n", + "%s: %s not available, skipping tests", config_name(c), s->name); } } diff --git a/tools/testing/selftests/kvm/guest_print_test.c b/tools/testing/selftests/kvm/guest_print_test.c index 41230b746190..3502caa3590c 100644 --- a/tools/testing/selftests/kvm/guest_print_test.c +++ b/tools/testing/selftests/kvm/guest_print_test.c @@ -98,7 +98,7 @@ static void ucall_abort(const char *assert_msg, const char *expected_assert_msg) int offset = len_str - len_substr; TEST_ASSERT(len_substr <= len_str, - "Expected '%s' to be a substring of '%s'\n", + "Expected '%s' to be a substring of '%s'", assert_msg, expected_assert_msg); TEST_ASSERT(strcmp(&assert_msg[offset], expected_assert_msg) == 0, @@ -116,7 +116,7 @@ static void run_test(struct kvm_vcpu *vcpu, const char *expected_printf, vcpu_run(vcpu); TEST_ASSERT(run->exit_reason == UCALL_EXIT_REASON, - "Unexpected exit reason: %u (%s),\n", + "Unexpected exit reason: %u (%s),", run->exit_reason, exit_reason_str(run->exit_reason)); switch (get_ucall(vcpu, &uc)) { @@ -161,11 +161,11 @@ static void test_limits(void) vcpu_run(vcpu); TEST_ASSERT(run->exit_reason == UCALL_EXIT_REASON, - "Unexpected exit reason: %u (%s),\n", + "Unexpected exit reason: %u (%s),", run->exit_reason, exit_reason_str(run->exit_reason)); TEST_ASSERT(get_ucall(vcpu, &uc) == UCALL_ABORT, - "Unexpected ucall command: %lu, Expected: %u (UCALL_ABORT)\n", + "Unexpected ucall command: %lu, Expected: %u (UCALL_ABORT)", uc.cmd, UCALL_ABORT); kvm_vm_free(vm); diff --git a/tools/testing/selftests/kvm/hardware_disable_test.c b/tools/testing/selftests/kvm/hardware_disable_test.c index f5d59b9934f1..decc521fc760 100644 --- a/tools/testing/selftests/kvm/hardware_disable_test.c +++ b/tools/testing/selftests/kvm/hardware_disable_test.c @@ -41,7 +41,7 @@ static void *run_vcpu(void *arg) vcpu_run(vcpu); - TEST_ASSERT(false, "%s: exited with reason %d: %s\n", + TEST_ASSERT(false, "%s: exited with reason %d: %s", __func__, run->exit_reason, exit_reason_str(run->exit_reason)); pthread_exit(NULL); @@ -55,7 +55,7 @@ static void *sleeping_thread(void *arg) fd = open("/dev/null", O_RDWR); close(fd); } - TEST_ASSERT(false, "%s: exited\n", __func__); + TEST_ASSERT(false, "%s: exited", __func__); pthread_exit(NULL); } @@ -118,7 +118,7 @@ static void run_test(uint32_t run) for (i = 0; i < VCPU_NUM; ++i) check_join(threads[i], &b); /* Should not be reached */ - TEST_ASSERT(false, "%s: [%d] child escaped the ninja\n", __func__, run); + TEST_ASSERT(false, "%s: [%d] child escaped the ninja", __func__, run); } void wait_for_child_setup(pid_t pid) diff --git a/tools/testing/selftests/kvm/include/test_util.h b/tools/testing/selftests/kvm/include/test_util.h index 71a41fa924b7..50a5e31ba8da 100644 --- a/tools/testing/selftests/kvm/include/test_util.h +++ b/tools/testing/selftests/kvm/include/test_util.h @@ -195,4 +195,6 @@ __printf(3, 4) int guest_snprintf(char *buf, int n, const char *fmt, ...); char *strdup_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2), nonnull(1))); +char *sys_get_cur_clocksource(void); + #endif /* SELFTEST_KVM_TEST_UTIL_H */ diff --git a/tools/testing/selftests/kvm/include/x86_64/processor.h b/tools/testing/selftests/kvm/include/x86_64/processor.h index a84863503fcb..5bca8c947c82 100644 --- a/tools/testing/selftests/kvm/include/x86_64/processor.h +++ b/tools/testing/selftests/kvm/include/x86_64/processor.h @@ -1271,4 +1271,6 @@ void virt_map_level(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr, #define PFERR_GUEST_PAGE_MASK BIT_ULL(PFERR_GUEST_PAGE_BIT) #define PFERR_IMPLICIT_ACCESS BIT_ULL(PFERR_IMPLICIT_ACCESS_BIT) +bool sys_clocksource_is_based_on_tsc(void); + #endif /* SELFTEST_KVM_PROCESSOR_H */ diff --git a/tools/testing/selftests/kvm/kvm_create_max_vcpus.c b/tools/testing/selftests/kvm/kvm_create_max_vcpus.c index 31b3cb24b9a7..b9e23265e4b3 100644 --- a/tools/testing/selftests/kvm/kvm_create_max_vcpus.c +++ b/tools/testing/selftests/kvm/kvm_create_max_vcpus.c @@ -65,7 +65,7 @@ int main(int argc, char *argv[]) int r = setrlimit(RLIMIT_NOFILE, &rl); __TEST_REQUIRE(r >= 0, - "RLIMIT_NOFILE hard limit is too low (%d, wanted %d)\n", + "RLIMIT_NOFILE hard limit is too low (%d, wanted %d)", old_rlim_max, nr_fds_wanted); } else { TEST_ASSERT(!setrlimit(RLIMIT_NOFILE, &rl), "setrlimit() failed!"); diff --git a/tools/testing/selftests/kvm/kvm_page_table_test.c b/tools/testing/selftests/kvm/kvm_page_table_test.c index e37dc9c21888..e0ba97ac1c56 100644 --- a/tools/testing/selftests/kvm/kvm_page_table_test.c +++ b/tools/testing/selftests/kvm/kvm_page_table_test.c @@ -204,9 +204,9 @@ static void *vcpu_worker(void *data) ret = _vcpu_run(vcpu); ts_diff = timespec_elapsed(start); - TEST_ASSERT(ret == 0, "vcpu_run failed: %d\n", ret); + TEST_ASSERT(ret == 0, "vcpu_run failed: %d", ret); TEST_ASSERT(get_ucall(vcpu, NULL) == UCALL_SYNC, - "Invalid guest sync status: exit_reason=%s\n", + "Invalid guest sync status: exit_reason=%s", exit_reason_str(vcpu->run->exit_reason)); pr_debug("Got sync event from vCPU %d\n", vcpu->id); diff --git a/tools/testing/selftests/kvm/lib/aarch64/processor.c b/tools/testing/selftests/kvm/lib/aarch64/processor.c index 41c776b642c0..43b9a7283360 100644 --- a/tools/testing/selftests/kvm/lib/aarch64/processor.c +++ b/tools/testing/selftests/kvm/lib/aarch64/processor.c @@ -398,7 +398,7 @@ void vcpu_args_set(struct kvm_vcpu *vcpu, unsigned int num, ...) int i; TEST_ASSERT(num >= 1 && num <= 8, "Unsupported number of args,\n" - " num: %u\n", num); + " num: %u", num); va_start(ap, num); diff --git a/tools/testing/selftests/kvm/lib/aarch64/vgic.c b/tools/testing/selftests/kvm/lib/aarch64/vgic.c index b5f28d21a947..184378d593e9 100644 --- a/tools/testing/selftests/kvm/lib/aarch64/vgic.c +++ b/tools/testing/selftests/kvm/lib/aarch64/vgic.c @@ -38,7 +38,7 @@ int vgic_v3_setup(struct kvm_vm *vm, unsigned int nr_vcpus, uint32_t nr_irqs, struct list_head *iter; unsigned int nr_gic_pages, nr_vcpus_created = 0; - TEST_ASSERT(nr_vcpus, "Number of vCPUs cannot be empty\n"); + TEST_ASSERT(nr_vcpus, "Number of vCPUs cannot be empty"); /* * Make sure that the caller is infact calling this @@ -47,7 +47,7 @@ int vgic_v3_setup(struct kvm_vm *vm, unsigned int nr_vcpus, uint32_t nr_irqs, list_for_each(iter, &vm->vcpus) nr_vcpus_created++; TEST_ASSERT(nr_vcpus == nr_vcpus_created, - "Number of vCPUs requested (%u) doesn't match with the ones created for the VM (%u)\n", + "Number of vCPUs requested (%u) doesn't match with the ones created for the VM (%u)", nr_vcpus, nr_vcpus_created); /* Distributor setup */ diff --git a/tools/testing/selftests/kvm/lib/elf.c b/tools/testing/selftests/kvm/lib/elf.c index 266f3876e10a..f34d926d9735 100644 --- a/tools/testing/selftests/kvm/lib/elf.c +++ b/tools/testing/selftests/kvm/lib/elf.c @@ -184,7 +184,7 @@ void kvm_vm_elf_load(struct kvm_vm *vm, const char *filename) "Seek to program segment offset failed,\n" " program header idx: %u errno: %i\n" " offset_rv: 0x%jx\n" - " expected: 0x%jx\n", + " expected: 0x%jx", n1, errno, (intmax_t) offset_rv, (intmax_t) phdr.p_offset); test_read(fd, addr_gva2hva(vm, phdr.p_vaddr), diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index e066d584c656..1b197426f29f 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -27,7 +27,8 @@ int open_path_or_exit(const char *path, int flags) int fd; fd = open(path, flags); - __TEST_REQUIRE(fd >= 0, "%s not available (errno: %d)", path, errno); + __TEST_REQUIRE(fd >= 0 || errno != ENOENT, "Cannot open %s: %s", path, strerror(errno)); + TEST_ASSERT(fd >= 0, "Failed to open '%s'", path); return fd; } @@ -320,7 +321,7 @@ static uint64_t vm_nr_pages_required(enum vm_guest_mode mode, uint64_t nr_pages; TEST_ASSERT(nr_runnable_vcpus, - "Use vm_create_barebones() for VMs that _never_ have vCPUs\n"); + "Use vm_create_barebones() for VMs that _never_ have vCPUs"); TEST_ASSERT(nr_runnable_vcpus <= kvm_check_cap(KVM_CAP_MAX_VCPUS), "nr_vcpus = %d too large for host, max-vcpus = %d", @@ -491,7 +492,7 @@ void kvm_pin_this_task_to_pcpu(uint32_t pcpu) CPU_ZERO(&mask); CPU_SET(pcpu, &mask); r = sched_setaffinity(0, sizeof(mask), &mask); - TEST_ASSERT(!r, "sched_setaffinity() failed for pCPU '%u'.\n", pcpu); + TEST_ASSERT(!r, "sched_setaffinity() failed for pCPU '%u'.", pcpu); } static uint32_t parse_pcpu(const char *cpu_str, const cpu_set_t *allowed_mask) @@ -499,7 +500,7 @@ static uint32_t parse_pcpu(const char *cpu_str, const cpu_set_t *allowed_mask) uint32_t pcpu = atoi_non_negative("CPU number", cpu_str); TEST_ASSERT(CPU_ISSET(pcpu, allowed_mask), - "Not allowed to run on pCPU '%d', check cgroups?\n", pcpu); + "Not allowed to run on pCPU '%d', check cgroups?", pcpu); return pcpu; } @@ -529,7 +530,7 @@ void kvm_parse_vcpu_pinning(const char *pcpus_string, uint32_t vcpu_to_pcpu[], int i, r; cpu_list = strdup(pcpus_string); - TEST_ASSERT(cpu_list, "strdup() allocation failed.\n"); + TEST_ASSERT(cpu_list, "strdup() allocation failed."); r = sched_getaffinity(0, sizeof(allowed_mask), &allowed_mask); TEST_ASSERT(!r, "sched_getaffinity() failed"); @@ -538,7 +539,7 @@ void kvm_parse_vcpu_pinning(const char *pcpus_string, uint32_t vcpu_to_pcpu[], /* 1. Get all pcpus for vcpus. */ for (i = 0; i < nr_vcpus; i++) { - TEST_ASSERT(cpu, "pCPU not provided for vCPU '%d'\n", i); + TEST_ASSERT(cpu, "pCPU not provided for vCPU '%d'", i); vcpu_to_pcpu[i] = parse_pcpu(cpu, &allowed_mask); cpu = strtok(NULL, delim); } @@ -1057,7 +1058,7 @@ void vm_mem_add(struct kvm_vm *vm, enum vm_mem_backing_src_type src_type, TEST_ASSERT(ret == 0, "KVM_SET_USER_MEMORY_REGION2 IOCTL failed,\n" " rc: %i errno: %i\n" " slot: %u flags: 0x%x\n" - " guest_phys_addr: 0x%lx size: 0x%lx guest_memfd: %d\n", + " guest_phys_addr: 0x%lx size: 0x%lx guest_memfd: %d", ret, errno, slot, flags, guest_paddr, (uint64_t) region->region.memory_size, region->region.guest_memfd); @@ -1222,7 +1223,7 @@ void vm_guest_mem_fallocate(struct kvm_vm *vm, uint64_t base, uint64_t size, len = min_t(uint64_t, end - gpa, region->region.memory_size - offset); ret = fallocate(region->region.guest_memfd, mode, fd_offset, len); - TEST_ASSERT(!ret, "fallocate() failed to %s at %lx (len = %lu), fd = %d, mode = %x, offset = %lx\n", + TEST_ASSERT(!ret, "fallocate() failed to %s at %lx (len = %lu), fd = %d, mode = %x, offset = %lx", punch_hole ? "punch hole" : "allocate", gpa, len, region->region.guest_memfd, mode, fd_offset); } @@ -1265,7 +1266,7 @@ struct kvm_vcpu *__vm_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id) struct kvm_vcpu *vcpu; /* Confirm a vcpu with the specified id doesn't already exist. */ - TEST_ASSERT(!vcpu_exists(vm, vcpu_id), "vCPU%d already exists\n", vcpu_id); + TEST_ASSERT(!vcpu_exists(vm, vcpu_id), "vCPU%d already exists", vcpu_id); /* Allocate and initialize new vcpu structure. */ vcpu = calloc(1, sizeof(*vcpu)); diff --git a/tools/testing/selftests/kvm/lib/memstress.c b/tools/testing/selftests/kvm/lib/memstress.c index d05487e5a371..cf2c73971308 100644 --- a/tools/testing/selftests/kvm/lib/memstress.c +++ b/tools/testing/selftests/kvm/lib/memstress.c @@ -192,7 +192,7 @@ struct kvm_vm *memstress_create_vm(enum vm_guest_mode mode, int nr_vcpus, TEST_ASSERT(guest_num_pages < region_end_gfn, "Requested more guest memory than address space allows.\n" " guest pages: %" PRIx64 " max gfn: %" PRIx64 - " nr_vcpus: %d wss: %" PRIx64 "]\n", + " nr_vcpus: %d wss: %" PRIx64 "]", guest_num_pages, region_end_gfn - 1, nr_vcpus, vcpu_memory_bytes); args->gpa = (region_end_gfn - guest_num_pages - 1) * args->guest_page_size; diff --git a/tools/testing/selftests/kvm/lib/riscv/processor.c b/tools/testing/selftests/kvm/lib/riscv/processor.c index 7ca736fb4194..2bb33a8ac03c 100644 --- a/tools/testing/selftests/kvm/lib/riscv/processor.c +++ b/tools/testing/selftests/kvm/lib/riscv/processor.c @@ -327,7 +327,7 @@ void vcpu_args_set(struct kvm_vcpu *vcpu, unsigned int num, ...) int i; TEST_ASSERT(num >= 1 && num <= 8, "Unsupported number of args,\n" - " num: %u\n", num); + " num: %u", num); va_start(ap, num); diff --git a/tools/testing/selftests/kvm/lib/s390x/processor.c b/tools/testing/selftests/kvm/lib/s390x/processor.c index 15945121daf1..f6d227892cbc 100644 --- a/tools/testing/selftests/kvm/lib/s390x/processor.c +++ b/tools/testing/selftests/kvm/lib/s390x/processor.c @@ -198,7 +198,7 @@ void vcpu_args_set(struct kvm_vcpu *vcpu, unsigned int num, ...) int i; TEST_ASSERT(num >= 1 && num <= 5, "Unsupported number of args,\n" - " num: %u\n", + " num: %u", num); va_start(ap, num); diff --git a/tools/testing/selftests/kvm/lib/test_util.c b/tools/testing/selftests/kvm/lib/test_util.c index 5d7f28b02d73..5a8f8becb129 100644 --- a/tools/testing/selftests/kvm/lib/test_util.c +++ b/tools/testing/selftests/kvm/lib/test_util.c @@ -392,3 +392,28 @@ char *strdup_printf(const char *fmt, ...) return str; } + +#define CLOCKSOURCE_PATH "/sys/devices/system/clocksource/clocksource0/current_clocksource" + +char *sys_get_cur_clocksource(void) +{ + char *clk_name; + struct stat st; + FILE *fp; + + fp = fopen(CLOCKSOURCE_PATH, "r"); + TEST_ASSERT(fp, "failed to open clocksource file, errno: %d", errno); + + TEST_ASSERT(!fstat(fileno(fp), &st), "failed to stat clocksource file, errno: %d", + errno); + + clk_name = malloc(st.st_size); + TEST_ASSERT(clk_name, "failed to allocate buffer to read file"); + + TEST_ASSERT(fgets(clk_name, st.st_size, fp), "failed to read clocksource file: %d", + ferror(fp)); + + fclose(fp); + + return clk_name; +} diff --git a/tools/testing/selftests/kvm/lib/userfaultfd_util.c b/tools/testing/selftests/kvm/lib/userfaultfd_util.c index 271f63891581..f4eef6eb2dc2 100644 --- a/tools/testing/selftests/kvm/lib/userfaultfd_util.c +++ b/tools/testing/selftests/kvm/lib/userfaultfd_util.c @@ -69,7 +69,7 @@ static void *uffd_handler_thread_fn(void *arg) if (pollfd[1].revents & POLLIN) { r = read(pollfd[1].fd, &tmp_chr, 1); TEST_ASSERT(r == 1, - "Error reading pipefd in UFFD thread\n"); + "Error reading pipefd in UFFD thread"); break; } diff --git a/tools/testing/selftests/kvm/lib/x86_64/processor.c b/tools/testing/selftests/kvm/lib/x86_64/processor.c index d8288374078e..f639b3e062e3 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/processor.c +++ b/tools/testing/selftests/kvm/lib/x86_64/processor.c @@ -170,10 +170,10 @@ static uint64_t *virt_create_upper_pte(struct kvm_vm *vm, * this level. */ TEST_ASSERT(current_level != target_level, - "Cannot create hugepage at level: %u, vaddr: 0x%lx\n", + "Cannot create hugepage at level: %u, vaddr: 0x%lx", current_level, vaddr); TEST_ASSERT(!(*pte & PTE_LARGE_MASK), - "Cannot create page table at level: %u, vaddr: 0x%lx\n", + "Cannot create page table at level: %u, vaddr: 0x%lx", current_level, vaddr); } return pte; @@ -220,7 +220,7 @@ void __virt_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr, int level) /* Fill in page table entry. */ pte = virt_get_pte(vm, pde, vaddr, PG_LEVEL_4K); TEST_ASSERT(!(*pte & PTE_PRESENT_MASK), - "PTE already present for 4k page at vaddr: 0x%lx\n", vaddr); + "PTE already present for 4k page at vaddr: 0x%lx", vaddr); *pte = PTE_PRESENT_MASK | PTE_WRITABLE_MASK | (paddr & PHYSICAL_PAGE_MASK); } @@ -253,7 +253,7 @@ static bool vm_is_target_pte(uint64_t *pte, int *level, int current_level) if (*pte & PTE_LARGE_MASK) { TEST_ASSERT(*level == PG_LEVEL_NONE || *level == current_level, - "Unexpected hugepage at level %d\n", current_level); + "Unexpected hugepage at level %d", current_level); *level = current_level; } @@ -825,7 +825,7 @@ void vcpu_args_set(struct kvm_vcpu *vcpu, unsigned int num, ...) struct kvm_regs regs; TEST_ASSERT(num >= 1 && num <= 6, "Unsupported number of args,\n" - " num: %u\n", + " num: %u", num); va_start(ap, num); @@ -1299,3 +1299,14 @@ void kvm_selftest_arch_init(void) host_cpu_is_intel = this_cpu_is_intel(); host_cpu_is_amd = this_cpu_is_amd(); } + +bool sys_clocksource_is_based_on_tsc(void) +{ + char *clk_name = sys_get_cur_clocksource(); + bool ret = !strcmp(clk_name, "tsc\n") || + !strcmp(clk_name, "hyperv_clocksource_tsc_page\n"); + + free(clk_name); + + return ret; +} diff --git a/tools/testing/selftests/kvm/lib/x86_64/vmx.c b/tools/testing/selftests/kvm/lib/x86_64/vmx.c index 59d97531c9b1..089b8925b6b2 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/vmx.c +++ b/tools/testing/selftests/kvm/lib/x86_64/vmx.c @@ -54,7 +54,7 @@ int vcpu_enable_evmcs(struct kvm_vcpu *vcpu) /* KVM should return supported EVMCS version range */ TEST_ASSERT(((evmcs_ver >> 8) >= (evmcs_ver & 0xff)) && (evmcs_ver & 0xff) > 0, - "Incorrect EVMCS version range: %x:%x\n", + "Incorrect EVMCS version range: %x:%x", evmcs_ver & 0xff, evmcs_ver >> 8); return evmcs_ver; @@ -387,10 +387,10 @@ static void nested_create_pte(struct kvm_vm *vm, * this level. */ TEST_ASSERT(current_level != target_level, - "Cannot create hugepage at level: %u, nested_paddr: 0x%lx\n", + "Cannot create hugepage at level: %u, nested_paddr: 0x%lx", current_level, nested_paddr); TEST_ASSERT(!pte->page_size, - "Cannot create page table at level: %u, nested_paddr: 0x%lx\n", + "Cannot create page table at level: %u, nested_paddr: 0x%lx", current_level, nested_paddr); } } diff --git a/tools/testing/selftests/kvm/memslot_modification_stress_test.c b/tools/testing/selftests/kvm/memslot_modification_stress_test.c index 9855c41ca811..156361966612 100644 --- a/tools/testing/selftests/kvm/memslot_modification_stress_test.c +++ b/tools/testing/selftests/kvm/memslot_modification_stress_test.c @@ -45,7 +45,7 @@ static void vcpu_worker(struct memstress_vcpu_args *vcpu_args) /* Let the guest access its memory until a stop signal is received */ while (!READ_ONCE(memstress_args.stop_vcpus)) { ret = _vcpu_run(vcpu); - TEST_ASSERT(ret == 0, "vcpu_run failed: %d\n", ret); + TEST_ASSERT(ret == 0, "vcpu_run failed: %d", ret); if (get_ucall(vcpu, NULL) == UCALL_SYNC) continue; diff --git a/tools/testing/selftests/kvm/memslot_perf_test.c b/tools/testing/selftests/kvm/memslot_perf_test.c index 8698d1ab60d0..579a64f97333 100644 --- a/tools/testing/selftests/kvm/memslot_perf_test.c +++ b/tools/testing/selftests/kvm/memslot_perf_test.c @@ -175,11 +175,11 @@ static void wait_for_vcpu(void) struct timespec ts; TEST_ASSERT(!clock_gettime(CLOCK_REALTIME, &ts), - "clock_gettime() failed: %d\n", errno); + "clock_gettime() failed: %d", errno); ts.tv_sec += 2; TEST_ASSERT(!sem_timedwait(&vcpu_ready, &ts), - "sem_timedwait() failed: %d\n", errno); + "sem_timedwait() failed: %d", errno); } static void *vm_gpa2hva(struct vm_data *data, uint64_t gpa, uint64_t *rempages) @@ -336,7 +336,7 @@ static bool prepare_vm(struct vm_data *data, int nslots, uint64_t *maxslots, gpa = vm_phy_pages_alloc(data->vm, npages, guest_addr, slot); TEST_ASSERT(gpa == guest_addr, - "vm_phy_pages_alloc() failed\n"); + "vm_phy_pages_alloc() failed"); data->hva_slots[slot - 1] = addr_gpa2hva(data->vm, guest_addr); memset(data->hva_slots[slot - 1], 0, npages * guest_page_size); diff --git a/tools/testing/selftests/kvm/riscv/get-reg-list.c b/tools/testing/selftests/kvm/riscv/get-reg-list.c index 4fd0f8951574..6435e7a65642 100644 --- a/tools/testing/selftests/kvm/riscv/get-reg-list.c +++ b/tools/testing/selftests/kvm/riscv/get-reg-list.c @@ -177,7 +177,7 @@ void finalize_vcpu(struct kvm_vcpu *vcpu, struct vcpu_reg_list *c) /* Double check whether the desired extension was enabled */ __TEST_REQUIRE(vcpu_has_ext(vcpu, feature), - "%s not available, skipping tests\n", s->name); + "%s not available, skipping tests", s->name); } } diff --git a/tools/testing/selftests/kvm/rseq_test.c b/tools/testing/selftests/kvm/rseq_test.c index f74e76d03b7e..28f97fb52044 100644 --- a/tools/testing/selftests/kvm/rseq_test.c +++ b/tools/testing/selftests/kvm/rseq_test.c @@ -245,7 +245,7 @@ int main(int argc, char *argv[]) } while (snapshot != atomic_read(&seq_cnt)); TEST_ASSERT(rseq_cpu == cpu, - "rseq CPU = %d, sched CPU = %d\n", rseq_cpu, cpu); + "rseq CPU = %d, sched CPU = %d", rseq_cpu, cpu); } /* @@ -256,7 +256,7 @@ int main(int argc, char *argv[]) * migrations given the 1us+ delay in the migration task. */ TEST_ASSERT(i > (NR_TASK_MIGRATIONS / 2), - "Only performed %d KVM_RUNs, task stalled too much?\n", i); + "Only performed %d KVM_RUNs, task stalled too much?", i); pthread_join(migration_thread, NULL); diff --git a/tools/testing/selftests/kvm/s390x/resets.c b/tools/testing/selftests/kvm/s390x/resets.c index e41e2cb8ffa9..357943f2bea8 100644 --- a/tools/testing/selftests/kvm/s390x/resets.c +++ b/tools/testing/selftests/kvm/s390x/resets.c @@ -78,7 +78,7 @@ static void assert_noirq(struct kvm_vcpu *vcpu) * (notably, the emergency call interrupt we have injected) should * be cleared by the resets, so this should be 0. */ - TEST_ASSERT(irqs >= 0, "Could not fetch IRQs: errno %d\n", errno); + TEST_ASSERT(irqs >= 0, "Could not fetch IRQs: errno %d", errno); TEST_ASSERT(!irqs, "IRQ pending"); } @@ -199,7 +199,7 @@ static void inject_irq(struct kvm_vcpu *vcpu) irq->type = KVM_S390_INT_EMERGENCY; irq->u.emerg.code = vcpu->id; irqs = __vcpu_ioctl(vcpu, KVM_S390_SET_IRQ_STATE, &irq_state); - TEST_ASSERT(irqs >= 0, "Error injecting EMERGENCY IRQ errno %d\n", errno); + TEST_ASSERT(irqs >= 0, "Error injecting EMERGENCY IRQ errno %d", errno); } static struct kvm_vm *create_vm(struct kvm_vcpu **vcpu) diff --git a/tools/testing/selftests/kvm/s390x/sync_regs_test.c b/tools/testing/selftests/kvm/s390x/sync_regs_test.c index 636a70ddac1e..43fb25ddc3ec 100644 --- a/tools/testing/selftests/kvm/s390x/sync_regs_test.c +++ b/tools/testing/selftests/kvm/s390x/sync_regs_test.c @@ -39,13 +39,13 @@ static void guest_code(void) #define REG_COMPARE(reg) \ TEST_ASSERT(left->reg == right->reg, \ "Register " #reg \ - " values did not match: 0x%llx, 0x%llx\n", \ + " values did not match: 0x%llx, 0x%llx", \ left->reg, right->reg) #define REG_COMPARE32(reg) \ TEST_ASSERT(left->reg == right->reg, \ "Register " #reg \ - " values did not match: 0x%x, 0x%x\n", \ + " values did not match: 0x%x, 0x%x", \ left->reg, right->reg) @@ -82,14 +82,14 @@ void test_read_invalid(struct kvm_vcpu *vcpu) run->kvm_valid_regs = INVALID_SYNC_FIELD; rv = _vcpu_run(vcpu); TEST_ASSERT(rv < 0 && errno == EINVAL, - "Invalid kvm_valid_regs did not cause expected KVM_RUN error: %d\n", + "Invalid kvm_valid_regs did not cause expected KVM_RUN error: %d", rv); run->kvm_valid_regs = 0; run->kvm_valid_regs = INVALID_SYNC_FIELD | TEST_SYNC_FIELDS; rv = _vcpu_run(vcpu); TEST_ASSERT(rv < 0 && errno == EINVAL, - "Invalid kvm_valid_regs did not cause expected KVM_RUN error: %d\n", + "Invalid kvm_valid_regs did not cause expected KVM_RUN error: %d", rv); run->kvm_valid_regs = 0; } @@ -103,14 +103,14 @@ void test_set_invalid(struct kvm_vcpu *vcpu) run->kvm_dirty_regs = INVALID_SYNC_FIELD; rv = _vcpu_run(vcpu); TEST_ASSERT(rv < 0 && errno == EINVAL, - "Invalid kvm_dirty_regs did not cause expected KVM_RUN error: %d\n", + "Invalid kvm_dirty_regs did not cause expected KVM_RUN error: %d", rv); run->kvm_dirty_regs = 0; run->kvm_dirty_regs = INVALID_SYNC_FIELD | TEST_SYNC_FIELDS; rv = _vcpu_run(vcpu); TEST_ASSERT(rv < 0 && errno == EINVAL, - "Invalid kvm_dirty_regs did not cause expected KVM_RUN error: %d\n", + "Invalid kvm_dirty_regs did not cause expected KVM_RUN error: %d", rv); run->kvm_dirty_regs = 0; } @@ -125,12 +125,12 @@ void test_req_and_verify_all_valid_regs(struct kvm_vcpu *vcpu) /* Request and verify all valid register sets. */ run->kvm_valid_regs = TEST_SYNC_FIELDS; rv = _vcpu_run(vcpu); - TEST_ASSERT(rv == 0, "vcpu_run failed: %d\n", rv); + TEST_ASSERT(rv == 0, "vcpu_run failed: %d", rv); TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_S390_SIEIC); TEST_ASSERT(run->s390_sieic.icptcode == 4 && (run->s390_sieic.ipa >> 8) == 0x83 && (run->s390_sieic.ipb >> 16) == 0x501, - "Unexpected interception code: ic=%u, ipa=0x%x, ipb=0x%x\n", + "Unexpected interception code: ic=%u, ipa=0x%x, ipb=0x%x", run->s390_sieic.icptcode, run->s390_sieic.ipa, run->s390_sieic.ipb); @@ -161,7 +161,7 @@ void test_set_and_verify_various_reg_values(struct kvm_vcpu *vcpu) } rv = _vcpu_run(vcpu); - TEST_ASSERT(rv == 0, "vcpu_run failed: %d\n", rv); + TEST_ASSERT(rv == 0, "vcpu_run failed: %d", rv); TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_S390_SIEIC); TEST_ASSERT(run->s.regs.gprs[11] == 0xBAD1DEA + 1, "r11 sync regs value incorrect 0x%llx.", @@ -193,7 +193,7 @@ void test_clear_kvm_dirty_regs_bits(struct kvm_vcpu *vcpu) run->s.regs.gprs[11] = 0xDEADBEEF; run->s.regs.diag318 = 0x4B1D; rv = _vcpu_run(vcpu); - TEST_ASSERT(rv == 0, "vcpu_run failed: %d\n", rv); + TEST_ASSERT(rv == 0, "vcpu_run failed: %d", rv); TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_S390_SIEIC); TEST_ASSERT(run->s.regs.gprs[11] != 0xDEADBEEF, "r11 sync regs value incorrect 0x%llx.", diff --git a/tools/testing/selftests/kvm/set_memory_region_test.c b/tools/testing/selftests/kvm/set_memory_region_test.c index 075b80dbe237..40337f566eeb 100644 --- a/tools/testing/selftests/kvm/set_memory_region_test.c +++ b/tools/testing/selftests/kvm/set_memory_region_test.c @@ -98,11 +98,11 @@ static void wait_for_vcpu(void) struct timespec ts; TEST_ASSERT(!clock_gettime(CLOCK_REALTIME, &ts), - "clock_gettime() failed: %d\n", errno); + "clock_gettime() failed: %d", errno); ts.tv_sec += 2; TEST_ASSERT(!sem_timedwait(&vcpu_ready, &ts), - "sem_timedwait() failed: %d\n", errno); + "sem_timedwait() failed: %d", errno); /* Wait for the vCPU thread to reenter the guest. */ usleep(100000); @@ -302,7 +302,7 @@ static void test_delete_memory_region(void) if (run->exit_reason == KVM_EXIT_INTERNAL_ERROR) TEST_ASSERT(regs.rip >= final_rip_start && regs.rip < final_rip_end, - "Bad rip, expected 0x%lx - 0x%lx, got 0x%llx\n", + "Bad rip, expected 0x%lx - 0x%lx, got 0x%llx", final_rip_start, final_rip_end, regs.rip); kvm_vm_free(vm); diff --git a/tools/testing/selftests/kvm/system_counter_offset_test.c b/tools/testing/selftests/kvm/system_counter_offset_test.c index 7f5b330b6a1b..513d421a9bff 100644 --- a/tools/testing/selftests/kvm/system_counter_offset_test.c +++ b/tools/testing/selftests/kvm/system_counter_offset_test.c @@ -108,7 +108,7 @@ static void enter_guest(struct kvm_vcpu *vcpu) handle_abort(&uc); return; default: - TEST_ASSERT(0, "unhandled ucall %ld\n", + TEST_ASSERT(0, "unhandled ucall %ld", get_ucall(vcpu, &uc)); } } diff --git a/tools/testing/selftests/kvm/x86_64/amx_test.c b/tools/testing/selftests/kvm/x86_64/amx_test.c index 11329e5ff945..eae521f050e0 100644 --- a/tools/testing/selftests/kvm/x86_64/amx_test.c +++ b/tools/testing/selftests/kvm/x86_64/amx_test.c @@ -221,7 +221,7 @@ int main(int argc, char *argv[]) vm_vaddr_t amx_cfg, tiledata, xstate; struct ucall uc; u32 amx_offset; - int stage, ret; + int ret; /* * Note, all off-by-default features must be enabled before anything @@ -263,7 +263,7 @@ int main(int argc, char *argv[]) memset(addr_gva2hva(vm, xstate), 0, PAGE_SIZE * DIV_ROUND_UP(XSAVE_SIZE, PAGE_SIZE)); vcpu_args_set(vcpu, 3, amx_cfg, tiledata, xstate); - for (stage = 1; ; stage++) { + for (;;) { vcpu_run(vcpu); TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO); @@ -296,7 +296,7 @@ int main(int argc, char *argv[]) void *tiles_data = (void *)addr_gva2hva(vm, tiledata); /* Only check TMM0 register, 1 tile */ ret = memcmp(amx_start, tiles_data, TILE_SIZE); - TEST_ASSERT(ret == 0, "memcmp failed, ret=%d\n", ret); + TEST_ASSERT(ret == 0, "memcmp failed, ret=%d", ret); kvm_x86_state_cleanup(state); break; case 9: diff --git a/tools/testing/selftests/kvm/x86_64/cpuid_test.c b/tools/testing/selftests/kvm/x86_64/cpuid_test.c index 3b34d8156d1c..8c579ce714e9 100644 --- a/tools/testing/selftests/kvm/x86_64/cpuid_test.c +++ b/tools/testing/selftests/kvm/x86_64/cpuid_test.c @@ -84,7 +84,7 @@ static void compare_cpuids(const struct kvm_cpuid2 *cpuid1, TEST_ASSERT(e1->function == e2->function && e1->index == e2->index && e1->flags == e2->flags, - "CPUID entries[%d] mismtach: 0x%x.%d.%x vs. 0x%x.%d.%x\n", + "CPUID entries[%d] mismtach: 0x%x.%d.%x vs. 0x%x.%d.%x", i, e1->function, e1->index, e1->flags, e2->function, e2->index, e2->flags); @@ -170,7 +170,7 @@ static void test_get_cpuid2(struct kvm_vcpu *vcpu) vcpu_ioctl(vcpu, KVM_GET_CPUID2, cpuid); TEST_ASSERT(cpuid->nent == vcpu->cpuid->nent, - "KVM didn't update nent on success, wanted %u, got %u\n", + "KVM didn't update nent on success, wanted %u, got %u", vcpu->cpuid->nent, cpuid->nent); for (i = 0; i < vcpu->cpuid->nent; i++) { diff --git a/tools/testing/selftests/kvm/x86_64/dirty_log_page_splitting_test.c b/tools/testing/selftests/kvm/x86_64/dirty_log_page_splitting_test.c index 634c6bfcd572..ee3b384b991c 100644 --- a/tools/testing/selftests/kvm/x86_64/dirty_log_page_splitting_test.c +++ b/tools/testing/selftests/kvm/x86_64/dirty_log_page_splitting_test.c @@ -92,7 +92,6 @@ static void run_test(enum vm_guest_mode mode, void *unused) uint64_t host_num_pages; uint64_t pages_per_slot; int i; - uint64_t total_4k_pages; struct kvm_page_stats stats_populated; struct kvm_page_stats stats_dirty_logging_enabled; struct kvm_page_stats stats_dirty_pass[ITERATIONS]; @@ -107,6 +106,9 @@ static void run_test(enum vm_guest_mode mode, void *unused) guest_num_pages = vm_adjust_num_guest_pages(mode, guest_num_pages); host_num_pages = vm_num_host_pages(mode, guest_num_pages); pages_per_slot = host_num_pages / SLOTS; + TEST_ASSERT_EQ(host_num_pages, pages_per_slot * SLOTS); + TEST_ASSERT(!(host_num_pages % 512), + "Number of pages, '%lu' not a multiple of 2MiB", host_num_pages); bitmaps = memstress_alloc_bitmaps(SLOTS, pages_per_slot); @@ -165,10 +167,8 @@ static void run_test(enum vm_guest_mode mode, void *unused) memstress_free_bitmaps(bitmaps, SLOTS); memstress_destroy_vm(vm); - /* Make assertions about the page counts. */ - total_4k_pages = stats_populated.pages_4k; - total_4k_pages += stats_populated.pages_2m * 512; - total_4k_pages += stats_populated.pages_1g * 512 * 512; + TEST_ASSERT_EQ((stats_populated.pages_2m * 512 + + stats_populated.pages_1g * 512 * 512), host_num_pages); /* * Check that all huge pages were split. Since large pages can only @@ -180,19 +180,22 @@ static void run_test(enum vm_guest_mode mode, void *unused) */ if (dirty_log_manual_caps) { TEST_ASSERT_EQ(stats_clear_pass[0].hugepages, 0); - TEST_ASSERT_EQ(stats_clear_pass[0].pages_4k, total_4k_pages); + TEST_ASSERT(stats_clear_pass[0].pages_4k >= host_num_pages, + "Expected at least '%lu' 4KiB pages, found only '%lu'", + host_num_pages, stats_clear_pass[0].pages_4k); TEST_ASSERT_EQ(stats_dirty_logging_enabled.hugepages, stats_populated.hugepages); } else { TEST_ASSERT_EQ(stats_dirty_logging_enabled.hugepages, 0); - TEST_ASSERT_EQ(stats_dirty_logging_enabled.pages_4k, total_4k_pages); + TEST_ASSERT(stats_dirty_logging_enabled.pages_4k >= host_num_pages, + "Expected at least '%lu' 4KiB pages, found only '%lu'", + host_num_pages, stats_dirty_logging_enabled.pages_4k); } /* * Once dirty logging is disabled and the vCPUs have touched all their - * memory again, the page counts should be the same as they were + * memory again, the hugepage counts should be the same as they were * right after initial population of memory. */ - TEST_ASSERT_EQ(stats_populated.pages_4k, stats_repopulated.pages_4k); TEST_ASSERT_EQ(stats_populated.pages_2m, stats_repopulated.pages_2m); TEST_ASSERT_EQ(stats_populated.pages_1g, stats_repopulated.pages_1g); } diff --git a/tools/testing/selftests/kvm/x86_64/flds_emulation.h b/tools/testing/selftests/kvm/x86_64/flds_emulation.h index 0a1573d52882..37b1a9f52864 100644 --- a/tools/testing/selftests/kvm/x86_64/flds_emulation.h +++ b/tools/testing/selftests/kvm/x86_64/flds_emulation.h @@ -41,7 +41,7 @@ static inline void handle_flds_emulation_failure_exit(struct kvm_vcpu *vcpu) insn_bytes = run->emulation_failure.insn_bytes; TEST_ASSERT(insn_bytes[0] == 0xd9 && insn_bytes[1] == 0, - "Expected 'flds [eax]', opcode '0xd9 0x00', got opcode 0x%02x 0x%02x\n", + "Expected 'flds [eax]', opcode '0xd9 0x00', got opcode 0x%02x 0x%02x", insn_bytes[0], insn_bytes[1]); vcpu_regs_get(vcpu, ®s); diff --git a/tools/testing/selftests/kvm/x86_64/hyperv_clock.c b/tools/testing/selftests/kvm/x86_64/hyperv_clock.c index f5e1e98f04f9..e058bc676cd6 100644 --- a/tools/testing/selftests/kvm/x86_64/hyperv_clock.c +++ b/tools/testing/selftests/kvm/x86_64/hyperv_clock.c @@ -212,6 +212,7 @@ int main(void) int stage; TEST_REQUIRE(kvm_has_cap(KVM_CAP_HYPERV_TIME)); + TEST_REQUIRE(sys_clocksource_is_based_on_tsc()); vm = vm_create_with_one_vcpu(&vcpu, guest_main); @@ -220,7 +221,7 @@ int main(void) tsc_page_gva = vm_vaddr_alloc_page(vm); memset(addr_gva2hva(vm, tsc_page_gva), 0x0, getpagesize()); TEST_ASSERT((addr_gva2gpa(vm, tsc_page_gva) & (getpagesize() - 1)) == 0, - "TSC page has to be page aligned\n"); + "TSC page has to be page aligned"); vcpu_args_set(vcpu, 2, tsc_page_gva, addr_gva2gpa(vm, tsc_page_gva)); host_check_tsc_msr_rdtsc(vcpu); @@ -237,7 +238,7 @@ int main(void) break; case UCALL_DONE: /* Keep in sync with guest_main() */ - TEST_ASSERT(stage == 11, "Testing ended prematurely, stage %d\n", + TEST_ASSERT(stage == 11, "Testing ended prematurely, stage %d", stage); goto out; default: diff --git a/tools/testing/selftests/kvm/x86_64/hyperv_features.c b/tools/testing/selftests/kvm/x86_64/hyperv_features.c index 4f4193fc74ff..b923a285e96f 100644 --- a/tools/testing/selftests/kvm/x86_64/hyperv_features.c +++ b/tools/testing/selftests/kvm/x86_64/hyperv_features.c @@ -454,7 +454,7 @@ static void guest_test_msrs_access(void) case 44: /* MSR is not available when CPUID feature bit is unset */ if (!has_invtsc) - continue; + goto next_stage; msr->idx = HV_X64_MSR_TSC_INVARIANT_CONTROL; msr->write = false; msr->fault_expected = true; @@ -462,7 +462,7 @@ static void guest_test_msrs_access(void) case 45: /* MSR is vailable when CPUID feature bit is set */ if (!has_invtsc) - continue; + goto next_stage; vcpu_set_cpuid_feature(vcpu, HV_ACCESS_TSC_INVARIANT); msr->idx = HV_X64_MSR_TSC_INVARIANT_CONTROL; msr->write = false; @@ -471,7 +471,7 @@ static void guest_test_msrs_access(void) case 46: /* Writing bits other than 0 is forbidden */ if (!has_invtsc) - continue; + goto next_stage; msr->idx = HV_X64_MSR_TSC_INVARIANT_CONTROL; msr->write = true; msr->write_val = 0xdeadbeef; @@ -480,7 +480,7 @@ static void guest_test_msrs_access(void) case 47: /* Setting bit 0 enables the feature */ if (!has_invtsc) - continue; + goto next_stage; msr->idx = HV_X64_MSR_TSC_INVARIANT_CONTROL; msr->write = true; msr->write_val = 1; @@ -513,6 +513,7 @@ static void guest_test_msrs_access(void) return; } +next_stage: stage++; kvm_vm_free(vm); } diff --git a/tools/testing/selftests/kvm/x86_64/hyperv_ipi.c b/tools/testing/selftests/kvm/x86_64/hyperv_ipi.c index 65e5f4c05068..f1617762c22f 100644 --- a/tools/testing/selftests/kvm/x86_64/hyperv_ipi.c +++ b/tools/testing/selftests/kvm/x86_64/hyperv_ipi.c @@ -289,7 +289,7 @@ int main(int argc, char *argv[]) switch (get_ucall(vcpu[0], &uc)) { case UCALL_SYNC: TEST_ASSERT(uc.args[1] == stage, - "Unexpected stage: %ld (%d expected)\n", + "Unexpected stage: %ld (%d expected)", uc.args[1], stage); break; case UCALL_DONE: diff --git a/tools/testing/selftests/kvm/x86_64/hyperv_tlb_flush.c b/tools/testing/selftests/kvm/x86_64/hyperv_tlb_flush.c index c4443f71f8dd..05b56095cf76 100644 --- a/tools/testing/selftests/kvm/x86_64/hyperv_tlb_flush.c +++ b/tools/testing/selftests/kvm/x86_64/hyperv_tlb_flush.c @@ -658,7 +658,7 @@ int main(int argc, char *argv[]) switch (get_ucall(vcpu[0], &uc)) { case UCALL_SYNC: TEST_ASSERT(uc.args[1] == stage, - "Unexpected stage: %ld (%d expected)\n", + "Unexpected stage: %ld (%d expected)", uc.args[1], stage); break; case UCALL_ABORT: diff --git a/tools/testing/selftests/kvm/x86_64/kvm_clock_test.c b/tools/testing/selftests/kvm/x86_64/kvm_clock_test.c index 1778704360a6..5bc12222d87a 100644 --- a/tools/testing/selftests/kvm/x86_64/kvm_clock_test.c +++ b/tools/testing/selftests/kvm/x86_64/kvm_clock_test.c @@ -92,7 +92,7 @@ static void setup_clock(struct kvm_vm *vm, struct test_case *test_case) break; } while (errno == EINTR); - TEST_ASSERT(!r, "clock_gettime() failed: %d\n", r); + TEST_ASSERT(!r, "clock_gettime() failed: %d", r); data.realtime = ts.tv_sec * NSEC_PER_SEC; data.realtime += ts.tv_nsec; @@ -127,47 +127,11 @@ static void enter_guest(struct kvm_vcpu *vcpu) handle_abort(&uc); return; default: - TEST_ASSERT(0, "unhandled ucall: %ld\n", uc.cmd); + TEST_ASSERT(0, "unhandled ucall: %ld", uc.cmd); } } } -#define CLOCKSOURCE_PATH "/sys/devices/system/clocksource/clocksource0/current_clocksource" - -static void check_clocksource(void) -{ - char *clk_name; - struct stat st; - FILE *fp; - - fp = fopen(CLOCKSOURCE_PATH, "r"); - if (!fp) { - pr_info("failed to open clocksource file: %d; assuming TSC.\n", - errno); - return; - } - - if (fstat(fileno(fp), &st)) { - pr_info("failed to stat clocksource file: %d; assuming TSC.\n", - errno); - goto out; - } - - clk_name = malloc(st.st_size); - TEST_ASSERT(clk_name, "failed to allocate buffer to read file\n"); - - if (!fgets(clk_name, st.st_size, fp)) { - pr_info("failed to read clocksource file: %d; assuming TSC.\n", - ferror(fp)); - goto out; - } - - TEST_ASSERT(!strncmp(clk_name, "tsc\n", st.st_size), - "clocksource not supported: %s", clk_name); -out: - fclose(fp); -} - int main(void) { struct kvm_vcpu *vcpu; @@ -179,7 +143,7 @@ int main(void) flags = kvm_check_cap(KVM_CAP_ADJUST_CLOCK); TEST_REQUIRE(flags & KVM_CLOCK_REALTIME); - check_clocksource(); + TEST_REQUIRE(sys_clocksource_is_based_on_tsc()); vm = vm_create_with_one_vcpu(&vcpu, guest_main); diff --git a/tools/testing/selftests/kvm/x86_64/nx_huge_pages_test.c b/tools/testing/selftests/kvm/x86_64/nx_huge_pages_test.c index 83e25bccc139..17bbb96fc4df 100644 --- a/tools/testing/selftests/kvm/x86_64/nx_huge_pages_test.c +++ b/tools/testing/selftests/kvm/x86_64/nx_huge_pages_test.c @@ -257,9 +257,9 @@ int main(int argc, char **argv) TEST_REQUIRE(kvm_has_cap(KVM_CAP_VM_DISABLE_NX_HUGE_PAGES)); __TEST_REQUIRE(token == MAGIC_TOKEN, - "This test must be run with the magic token %d.\n" - "This is done by nx_huge_pages_test.sh, which\n" - "also handles environment setup for the test.", MAGIC_TOKEN); + "This test must be run with the magic token via '-t %d'.\n" + "Running via nx_huge_pages_test.sh, which also handles " + "environment setup, is strongly recommended.", MAGIC_TOKEN); run_test(reclaim_period_ms, false, reboot_permissions); run_test(reclaim_period_ms, true, reboot_permissions); diff --git a/tools/testing/selftests/kvm/x86_64/platform_info_test.c b/tools/testing/selftests/kvm/x86_64/platform_info_test.c index c9a07963d68a..87011965dc41 100644 --- a/tools/testing/selftests/kvm/x86_64/platform_info_test.c +++ b/tools/testing/selftests/kvm/x86_64/platform_info_test.c @@ -44,7 +44,7 @@ static void test_msr_platform_info_enabled(struct kvm_vcpu *vcpu) get_ucall(vcpu, &uc); TEST_ASSERT(uc.cmd == UCALL_SYNC, - "Received ucall other than UCALL_SYNC: %lu\n", uc.cmd); + "Received ucall other than UCALL_SYNC: %lu", uc.cmd); TEST_ASSERT((uc.args[1] & MSR_PLATFORM_INFO_MAX_TURBO_RATIO) == MSR_PLATFORM_INFO_MAX_TURBO_RATIO, "Expected MSR_PLATFORM_INFO to have max turbo ratio mask: %i.", diff --git a/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c b/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c index 283cc55597a4..a3bd54b925ab 100644 --- a/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c +++ b/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c @@ -866,7 +866,7 @@ static void __test_fixed_counter_bitmap(struct kvm_vcpu *vcpu, uint8_t idx, * userspace doesn't set any pmu filter. */ count = run_vcpu_to_sync(vcpu); - TEST_ASSERT(count, "Unexpected count value: %ld\n", count); + TEST_ASSERT(count, "Unexpected count value: %ld", count); for (i = 0; i < BIT(nr_fixed_counters); i++) { bitmap = BIT(i); diff --git a/tools/testing/selftests/kvm/x86_64/sev_migrate_tests.c b/tools/testing/selftests/kvm/x86_64/sev_migrate_tests.c index c7ef97561038..a49828adf294 100644 --- a/tools/testing/selftests/kvm/x86_64/sev_migrate_tests.c +++ b/tools/testing/selftests/kvm/x86_64/sev_migrate_tests.c @@ -91,7 +91,7 @@ static void sev_migrate_from(struct kvm_vm *dst, struct kvm_vm *src) int ret; ret = __sev_migrate_from(dst, src); - TEST_ASSERT(!ret, "Migration failed, ret: %d, errno: %d\n", ret, errno); + TEST_ASSERT(!ret, "Migration failed, ret: %d, errno: %d", ret, errno); } static void test_sev_migrate_from(bool es) @@ -113,7 +113,7 @@ static void test_sev_migrate_from(bool es) /* Migrate the guest back to the original VM. */ ret = __sev_migrate_from(src_vm, dst_vms[NR_MIGRATE_TEST_VMS - 1]); TEST_ASSERT(ret == -1 && errno == EIO, - "VM that was migrated from should be dead. ret %d, errno: %d\n", ret, + "VM that was migrated from should be dead. ret %d, errno: %d", ret, errno); kvm_vm_free(src_vm); @@ -172,7 +172,7 @@ static void test_sev_migrate_parameters(void) vm_no_sev = aux_vm_create(true); ret = __sev_migrate_from(vm_no_vcpu, vm_no_sev); TEST_ASSERT(ret == -1 && errno == EINVAL, - "Migrations require SEV enabled. ret %d, errno: %d\n", ret, + "Migrations require SEV enabled. ret %d, errno: %d", ret, errno); if (!have_sev_es) @@ -187,25 +187,25 @@ static void test_sev_migrate_parameters(void) ret = __sev_migrate_from(sev_vm, sev_es_vm); TEST_ASSERT( ret == -1 && errno == EINVAL, - "Should not be able migrate to SEV enabled VM. ret: %d, errno: %d\n", + "Should not be able migrate to SEV enabled VM. ret: %d, errno: %d", ret, errno); ret = __sev_migrate_from(sev_es_vm, sev_vm); TEST_ASSERT( ret == -1 && errno == EINVAL, - "Should not be able migrate to SEV-ES enabled VM. ret: %d, errno: %d\n", + "Should not be able migrate to SEV-ES enabled VM. ret: %d, errno: %d", ret, errno); ret = __sev_migrate_from(vm_no_vcpu, sev_es_vm); TEST_ASSERT( ret == -1 && errno == EINVAL, - "SEV-ES migrations require same number of vCPUS. ret: %d, errno: %d\n", + "SEV-ES migrations require same number of vCPUS. ret: %d, errno: %d", ret, errno); ret = __sev_migrate_from(vm_no_vcpu, sev_es_vm_no_vmsa); TEST_ASSERT( ret == -1 && errno == EINVAL, - "SEV-ES migrations require UPDATE_VMSA. ret %d, errno: %d\n", + "SEV-ES migrations require UPDATE_VMSA. ret %d, errno: %d", ret, errno); kvm_vm_free(sev_vm); @@ -227,7 +227,7 @@ static void sev_mirror_create(struct kvm_vm *dst, struct kvm_vm *src) int ret; ret = __sev_mirror_create(dst, src); - TEST_ASSERT(!ret, "Copying context failed, ret: %d, errno: %d\n", ret, errno); + TEST_ASSERT(!ret, "Copying context failed, ret: %d, errno: %d", ret, errno); } static void verify_mirror_allowed_cmds(int vm_fd) @@ -259,7 +259,7 @@ static void verify_mirror_allowed_cmds(int vm_fd) ret = __sev_ioctl(vm_fd, cmd_id, NULL, &fw_error); TEST_ASSERT( ret == -1 && errno == EINVAL, - "Should not be able call command: %d. ret: %d, errno: %d\n", + "Should not be able call command: %d. ret: %d, errno: %d", cmd_id, ret, errno); } @@ -301,18 +301,18 @@ static void test_sev_mirror_parameters(void) ret = __sev_mirror_create(sev_vm, sev_vm); TEST_ASSERT( ret == -1 && errno == EINVAL, - "Should not be able copy context to self. ret: %d, errno: %d\n", + "Should not be able copy context to self. ret: %d, errno: %d", ret, errno); ret = __sev_mirror_create(vm_no_vcpu, vm_with_vcpu); TEST_ASSERT(ret == -1 && errno == EINVAL, - "Copy context requires SEV enabled. ret %d, errno: %d\n", ret, + "Copy context requires SEV enabled. ret %d, errno: %d", ret, errno); ret = __sev_mirror_create(vm_with_vcpu, sev_vm); TEST_ASSERT( ret == -1 && errno == EINVAL, - "SEV copy context requires no vCPUS on the destination. ret: %d, errno: %d\n", + "SEV copy context requires no vCPUS on the destination. ret: %d, errno: %d", ret, errno); if (!have_sev_es) @@ -322,13 +322,13 @@ static void test_sev_mirror_parameters(void) ret = __sev_mirror_create(sev_vm, sev_es_vm); TEST_ASSERT( ret == -1 && errno == EINVAL, - "Should not be able copy context to SEV enabled VM. ret: %d, errno: %d\n", + "Should not be able copy context to SEV enabled VM. ret: %d, errno: %d", ret, errno); ret = __sev_mirror_create(sev_es_vm, sev_vm); TEST_ASSERT( ret == -1 && errno == EINVAL, - "Should not be able copy context to SEV-ES enabled VM. ret: %d, errno: %d\n", + "Should not be able copy context to SEV-ES enabled VM. ret: %d, errno: %d", ret, errno); kvm_vm_free(sev_es_vm); diff --git a/tools/testing/selftests/kvm/x86_64/smaller_maxphyaddr_emulation_test.c b/tools/testing/selftests/kvm/x86_64/smaller_maxphyaddr_emulation_test.c index 06edf00a97d6..1a46dd7bb391 100644 --- a/tools/testing/selftests/kvm/x86_64/smaller_maxphyaddr_emulation_test.c +++ b/tools/testing/selftests/kvm/x86_64/smaller_maxphyaddr_emulation_test.c @@ -74,7 +74,7 @@ int main(int argc, char *argv[]) MEM_REGION_SIZE / PAGE_SIZE, 0); gpa = vm_phy_pages_alloc(vm, MEM_REGION_SIZE / PAGE_SIZE, MEM_REGION_GPA, MEM_REGION_SLOT); - TEST_ASSERT(gpa == MEM_REGION_GPA, "Failed vm_phy_pages_alloc\n"); + TEST_ASSERT(gpa == MEM_REGION_GPA, "Failed vm_phy_pages_alloc"); virt_map(vm, MEM_REGION_GVA, MEM_REGION_GPA, 1); hva = addr_gpa2hva(vm, MEM_REGION_GPA); memset(hva, 0, PAGE_SIZE); @@ -102,7 +102,7 @@ int main(int argc, char *argv[]) case UCALL_DONE: break; default: - TEST_FAIL("Unrecognized ucall: %lu\n", uc.cmd); + TEST_FAIL("Unrecognized ucall: %lu", uc.cmd); } kvm_vm_free(vm); diff --git a/tools/testing/selftests/kvm/x86_64/sync_regs_test.c b/tools/testing/selftests/kvm/x86_64/sync_regs_test.c index 00965ba33f73..a91b5b145fa3 100644 --- a/tools/testing/selftests/kvm/x86_64/sync_regs_test.c +++ b/tools/testing/selftests/kvm/x86_64/sync_regs_test.c @@ -46,7 +46,7 @@ static void compare_regs(struct kvm_regs *left, struct kvm_regs *right) #define REG_COMPARE(reg) \ TEST_ASSERT(left->reg == right->reg, \ "Register " #reg \ - " values did not match: 0x%llx, 0x%llx\n", \ + " values did not match: 0x%llx, 0x%llx", \ left->reg, right->reg) REG_COMPARE(rax); REG_COMPARE(rbx); @@ -230,14 +230,14 @@ int main(int argc, char *argv[]) run->kvm_valid_regs = INVALID_SYNC_FIELD; rv = _vcpu_run(vcpu); TEST_ASSERT(rv < 0 && errno == EINVAL, - "Invalid kvm_valid_regs did not cause expected KVM_RUN error: %d\n", + "Invalid kvm_valid_regs did not cause expected KVM_RUN error: %d", rv); run->kvm_valid_regs = 0; run->kvm_valid_regs = INVALID_SYNC_FIELD | TEST_SYNC_FIELDS; rv = _vcpu_run(vcpu); TEST_ASSERT(rv < 0 && errno == EINVAL, - "Invalid kvm_valid_regs did not cause expected KVM_RUN error: %d\n", + "Invalid kvm_valid_regs did not cause expected KVM_RUN error: %d", rv); run->kvm_valid_regs = 0; @@ -245,14 +245,14 @@ int main(int argc, char *argv[]) run->kvm_dirty_regs = INVALID_SYNC_FIELD; rv = _vcpu_run(vcpu); TEST_ASSERT(rv < 0 && errno == EINVAL, - "Invalid kvm_dirty_regs did not cause expected KVM_RUN error: %d\n", + "Invalid kvm_dirty_regs did not cause expected KVM_RUN error: %d", rv); run->kvm_dirty_regs = 0; run->kvm_dirty_regs = INVALID_SYNC_FIELD | TEST_SYNC_FIELDS; rv = _vcpu_run(vcpu); TEST_ASSERT(rv < 0 && errno == EINVAL, - "Invalid kvm_dirty_regs did not cause expected KVM_RUN error: %d\n", + "Invalid kvm_dirty_regs did not cause expected KVM_RUN error: %d", rv); run->kvm_dirty_regs = 0; diff --git a/tools/testing/selftests/kvm/x86_64/ucna_injection_test.c b/tools/testing/selftests/kvm/x86_64/ucna_injection_test.c index 0ed32ec903d0..dcbb3c29fb8e 100644 --- a/tools/testing/selftests/kvm/x86_64/ucna_injection_test.c +++ b/tools/testing/selftests/kvm/x86_64/ucna_injection_test.c @@ -143,7 +143,7 @@ static void run_vcpu_expect_gp(struct kvm_vcpu *vcpu) TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO); TEST_ASSERT(get_ucall(vcpu, &uc) == UCALL_SYNC, - "Expect UCALL_SYNC\n"); + "Expect UCALL_SYNC"); TEST_ASSERT(uc.args[1] == SYNC_GP, "#GP is expected."); printf("vCPU received GP in guest.\n"); } @@ -188,7 +188,7 @@ static void *run_ucna_injection(void *arg) TEST_ASSERT_KVM_EXIT_REASON(params->vcpu, KVM_EXIT_IO); TEST_ASSERT(get_ucall(params->vcpu, &uc) == UCALL_SYNC, - "Expect UCALL_SYNC\n"); + "Expect UCALL_SYNC"); TEST_ASSERT(uc.args[1] == SYNC_FIRST_UCNA, "Injecting first UCNA."); printf("Injecting first UCNA at %#x.\n", FIRST_UCNA_ADDR); @@ -198,7 +198,7 @@ static void *run_ucna_injection(void *arg) TEST_ASSERT_KVM_EXIT_REASON(params->vcpu, KVM_EXIT_IO); TEST_ASSERT(get_ucall(params->vcpu, &uc) == UCALL_SYNC, - "Expect UCALL_SYNC\n"); + "Expect UCALL_SYNC"); TEST_ASSERT(uc.args[1] == SYNC_SECOND_UCNA, "Injecting second UCNA."); printf("Injecting second UCNA at %#x.\n", SECOND_UCNA_ADDR); @@ -208,7 +208,7 @@ static void *run_ucna_injection(void *arg) TEST_ASSERT_KVM_EXIT_REASON(params->vcpu, KVM_EXIT_IO); if (get_ucall(params->vcpu, &uc) == UCALL_ABORT) { - TEST_ASSERT(false, "vCPU assertion failure: %s.\n", + TEST_ASSERT(false, "vCPU assertion failure: %s.", (const char *)uc.args[0]); } diff --git a/tools/testing/selftests/kvm/x86_64/userspace_io_test.c b/tools/testing/selftests/kvm/x86_64/userspace_io_test.c index 255c50b0dc32..9481cbcf284f 100644 --- a/tools/testing/selftests/kvm/x86_64/userspace_io_test.c +++ b/tools/testing/selftests/kvm/x86_64/userspace_io_test.c @@ -71,7 +71,7 @@ int main(int argc, char *argv[]) break; TEST_ASSERT(run->io.port == 0x80, - "Expected I/O at port 0x80, got port 0x%x\n", run->io.port); + "Expected I/O at port 0x80, got port 0x%x", run->io.port); /* * Modify the rep string count in RCX: 2 => 1 and 3 => 8192. diff --git a/tools/testing/selftests/kvm/x86_64/vmx_apic_access_test.c b/tools/testing/selftests/kvm/x86_64/vmx_apic_access_test.c index 2bed5fb3a0d6..a81a24761aac 100644 --- a/tools/testing/selftests/kvm/x86_64/vmx_apic_access_test.c +++ b/tools/testing/selftests/kvm/x86_64/vmx_apic_access_test.c @@ -99,7 +99,7 @@ int main(int argc, char *argv[]) TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_INTERNAL_ERROR); TEST_ASSERT(run->internal.suberror == KVM_INTERNAL_ERROR_EMULATION, - "Got internal suberror other than KVM_INTERNAL_ERROR_EMULATION: %u\n", + "Got internal suberror other than KVM_INTERNAL_ERROR_EMULATION: %u", run->internal.suberror); break; } diff --git a/tools/testing/selftests/kvm/x86_64/vmx_dirty_log_test.c b/tools/testing/selftests/kvm/x86_64/vmx_dirty_log_test.c index e4ad5fef52ff..7f6f5f23fb9b 100644 --- a/tools/testing/selftests/kvm/x86_64/vmx_dirty_log_test.c +++ b/tools/testing/selftests/kvm/x86_64/vmx_dirty_log_test.c @@ -128,17 +128,17 @@ int main(int argc, char *argv[]) */ kvm_vm_get_dirty_log(vm, TEST_MEM_SLOT_INDEX, bmap); if (uc.args[1]) { - TEST_ASSERT(test_bit(0, bmap), "Page 0 incorrectly reported clean\n"); - TEST_ASSERT(host_test_mem[0] == 1, "Page 0 not written by guest\n"); + TEST_ASSERT(test_bit(0, bmap), "Page 0 incorrectly reported clean"); + TEST_ASSERT(host_test_mem[0] == 1, "Page 0 not written by guest"); } else { - TEST_ASSERT(!test_bit(0, bmap), "Page 0 incorrectly reported dirty\n"); - TEST_ASSERT(host_test_mem[0] == 0xaaaaaaaaaaaaaaaaULL, "Page 0 written by guest\n"); + TEST_ASSERT(!test_bit(0, bmap), "Page 0 incorrectly reported dirty"); + TEST_ASSERT(host_test_mem[0] == 0xaaaaaaaaaaaaaaaaULL, "Page 0 written by guest"); } - TEST_ASSERT(!test_bit(1, bmap), "Page 1 incorrectly reported dirty\n"); - TEST_ASSERT(host_test_mem[4096 / 8] == 0xaaaaaaaaaaaaaaaaULL, "Page 1 written by guest\n"); - TEST_ASSERT(!test_bit(2, bmap), "Page 2 incorrectly reported dirty\n"); - TEST_ASSERT(host_test_mem[8192 / 8] == 0xaaaaaaaaaaaaaaaaULL, "Page 2 written by guest\n"); + TEST_ASSERT(!test_bit(1, bmap), "Page 1 incorrectly reported dirty"); + TEST_ASSERT(host_test_mem[4096 / 8] == 0xaaaaaaaaaaaaaaaaULL, "Page 1 written by guest"); + TEST_ASSERT(!test_bit(2, bmap), "Page 2 incorrectly reported dirty"); + TEST_ASSERT(host_test_mem[8192 / 8] == 0xaaaaaaaaaaaaaaaaULL, "Page 2 written by guest"); break; case UCALL_DONE: done = true; diff --git a/tools/testing/selftests/kvm/x86_64/vmx_exception_with_invalid_guest_state.c b/tools/testing/selftests/kvm/x86_64/vmx_exception_with_invalid_guest_state.c index a9b827c69f32..fad3634fd9eb 100644 --- a/tools/testing/selftests/kvm/x86_64/vmx_exception_with_invalid_guest_state.c +++ b/tools/testing/selftests/kvm/x86_64/vmx_exception_with_invalid_guest_state.c @@ -28,7 +28,7 @@ static void __run_vcpu_with_invalid_state(struct kvm_vcpu *vcpu) TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_INTERNAL_ERROR); TEST_ASSERT(run->emulation_failure.suberror == KVM_INTERNAL_ERROR_EMULATION, - "Expected emulation failure, got %d\n", + "Expected emulation failure, got %d", run->emulation_failure.suberror); } diff --git a/tools/testing/selftests/kvm/x86_64/vmx_nested_tsc_scaling_test.c b/tools/testing/selftests/kvm/x86_64/vmx_nested_tsc_scaling_test.c index e710b6e7fb38..1759fa5cb3f2 100644 --- a/tools/testing/selftests/kvm/x86_64/vmx_nested_tsc_scaling_test.c +++ b/tools/testing/selftests/kvm/x86_64/vmx_nested_tsc_scaling_test.c @@ -116,23 +116,6 @@ static void l1_guest_code(struct vmx_pages *vmx_pages) GUEST_DONE(); } -static bool system_has_stable_tsc(void) -{ - bool tsc_is_stable; - FILE *fp; - char buf[4]; - - fp = fopen("/sys/devices/system/clocksource/clocksource0/current_clocksource", "r"); - if (fp == NULL) - return false; - - tsc_is_stable = fgets(buf, sizeof(buf), fp) && - !strncmp(buf, "tsc", sizeof(buf)); - - fclose(fp); - return tsc_is_stable; -} - int main(int argc, char *argv[]) { struct kvm_vcpu *vcpu; @@ -148,7 +131,7 @@ int main(int argc, char *argv[]) TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_VMX)); TEST_REQUIRE(kvm_has_cap(KVM_CAP_TSC_CONTROL)); - TEST_REQUIRE(system_has_stable_tsc()); + TEST_REQUIRE(sys_clocksource_is_based_on_tsc()); /* * We set L1's scale factor to be a random number from 2 to 10. diff --git a/tools/testing/selftests/kvm/x86_64/xapic_ipi_test.c b/tools/testing/selftests/kvm/x86_64/xapic_ipi_test.c index 67ac2a3292ef..725c206ba0b9 100644 --- a/tools/testing/selftests/kvm/x86_64/xapic_ipi_test.c +++ b/tools/testing/selftests/kvm/x86_64/xapic_ipi_test.c @@ -216,7 +216,7 @@ static void *vcpu_thread(void *arg) "Halting vCPU halted %lu times, woke %lu times, received %lu IPIs.\n" "Halter TPR=%#x PPR=%#x LVR=%#x\n" "Migrations attempted: %lu\n" - "Migrations completed: %lu\n", + "Migrations completed: %lu", vcpu->id, (const char *)uc.args[0], params->data->ipis_sent, params->data->hlt_count, params->data->wake_count, @@ -288,7 +288,7 @@ void do_migrations(struct test_data_page *data, int run_secs, int delay_usecs, } TEST_ASSERT(nodes > 1, - "Did not find at least 2 numa nodes. Can't do migration\n"); + "Did not find at least 2 numa nodes. Can't do migration"); fprintf(stderr, "Migrating amongst %d nodes found\n", nodes); @@ -347,7 +347,7 @@ void do_migrations(struct test_data_page *data, int run_secs, int delay_usecs, wake_count != data->wake_count, "IPI, HLT and wake count have not increased " "in the last %lu seconds. " - "HLTer is likely hung.\n", interval_secs); + "HLTer is likely hung.", interval_secs); ipis_sent = data->ipis_sent; hlt_count = data->hlt_count; @@ -381,7 +381,7 @@ void get_cmdline_args(int argc, char *argv[], int *run_secs, "-m adds calls to migrate_pages while vCPUs are running." " Default is no migrations.\n" "-d <delay microseconds> - delay between migrate_pages() calls." - " Default is %d microseconds.\n", + " Default is %d microseconds.", DEFAULT_RUN_SECS, DEFAULT_DELAY_USECS); } } diff --git a/tools/testing/selftests/kvm/x86_64/xcr0_cpuid_test.c b/tools/testing/selftests/kvm/x86_64/xcr0_cpuid_test.c index dc6217440db3..25a0b0db5c3c 100644 --- a/tools/testing/selftests/kvm/x86_64/xcr0_cpuid_test.c +++ b/tools/testing/selftests/kvm/x86_64/xcr0_cpuid_test.c @@ -116,7 +116,7 @@ int main(int argc, char *argv[]) vcpu_run(vcpu); TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, - "Unexpected exit reason: %u (%s),\n", + "Unexpected exit reason: %u (%s),", run->exit_reason, exit_reason_str(run->exit_reason)); diff --git a/tools/testing/selftests/kvm/x86_64/xss_msr_test.c b/tools/testing/selftests/kvm/x86_64/xss_msr_test.c index e0ddf47362e7..167c97abff1b 100644 --- a/tools/testing/selftests/kvm/x86_64/xss_msr_test.c +++ b/tools/testing/selftests/kvm/x86_64/xss_msr_test.c @@ -29,7 +29,7 @@ int main(int argc, char *argv[]) xss_val = vcpu_get_msr(vcpu, MSR_IA32_XSS); TEST_ASSERT(xss_val == 0, - "MSR_IA32_XSS should be initialized to zero\n"); + "MSR_IA32_XSS should be initialized to zero"); vcpu_set_msr(vcpu, MSR_IA32_XSS, xss_val); diff --git a/tools/testing/selftests/landlock/common.h b/tools/testing/selftests/landlock/common.h index 5b79758cae62..e64bbdf0e86e 100644 --- a/tools/testing/selftests/landlock/common.h +++ b/tools/testing/selftests/landlock/common.h @@ -9,6 +9,7 @@ #include <errno.h> #include <linux/landlock.h> +#include <linux/securebits.h> #include <sys/capability.h> #include <sys/socket.h> #include <sys/syscall.h> @@ -115,11 +116,16 @@ static void _init_caps(struct __test_metadata *const _metadata, bool drop_all) /* clang-format off */ CAP_DAC_OVERRIDE, CAP_MKNOD, + CAP_NET_ADMIN, + CAP_NET_BIND_SERVICE, CAP_SYS_ADMIN, CAP_SYS_CHROOT, - CAP_NET_BIND_SERVICE, /* clang-format on */ }; + const unsigned int noroot = SECBIT_NOROOT | SECBIT_NOROOT_LOCKED; + + if ((cap_get_secbits() & noroot) != noroot) + EXPECT_EQ(0, cap_set_secbits(noroot)); cap_p = cap_get_proc(); EXPECT_NE(NULL, cap_p) @@ -137,6 +143,8 @@ static void _init_caps(struct __test_metadata *const _metadata, bool drop_all) TH_LOG("Failed to cap_set_flag: %s", strerror(errno)); } } + + /* Automatically resets ambient capabilities. */ EXPECT_NE(-1, cap_set_proc(cap_p)) { TH_LOG("Failed to cap_set_proc: %s", strerror(errno)); @@ -145,6 +153,9 @@ static void _init_caps(struct __test_metadata *const _metadata, bool drop_all) { TH_LOG("Failed to cap_free: %s", strerror(errno)); } + + /* Quickly checks that ambient capabilities are cleared. */ + EXPECT_NE(-1, cap_get_ambient(caps[0])); } /* We cannot put such helpers in a library because of kselftest_harness.h . */ @@ -158,8 +169,9 @@ static void __maybe_unused drop_caps(struct __test_metadata *const _metadata) _init_caps(_metadata, true); } -static void _effective_cap(struct __test_metadata *const _metadata, - const cap_value_t caps, const cap_flag_value_t value) +static void _change_cap(struct __test_metadata *const _metadata, + const cap_flag_t flag, const cap_value_t cap, + const cap_flag_value_t value) { cap_t cap_p; @@ -168,7 +180,7 @@ static void _effective_cap(struct __test_metadata *const _metadata, { TH_LOG("Failed to cap_get_proc: %s", strerror(errno)); } - EXPECT_NE(-1, cap_set_flag(cap_p, CAP_EFFECTIVE, 1, &caps, value)) + EXPECT_NE(-1, cap_set_flag(cap_p, flag, 1, &cap, value)) { TH_LOG("Failed to cap_set_flag: %s", strerror(errno)); } @@ -183,15 +195,35 @@ static void _effective_cap(struct __test_metadata *const _metadata, } static void __maybe_unused set_cap(struct __test_metadata *const _metadata, - const cap_value_t caps) + const cap_value_t cap) { - _effective_cap(_metadata, caps, CAP_SET); + _change_cap(_metadata, CAP_EFFECTIVE, cap, CAP_SET); } static void __maybe_unused clear_cap(struct __test_metadata *const _metadata, - const cap_value_t caps) + const cap_value_t cap) +{ + _change_cap(_metadata, CAP_EFFECTIVE, cap, CAP_CLEAR); +} + +static void __maybe_unused +set_ambient_cap(struct __test_metadata *const _metadata, const cap_value_t cap) +{ + _change_cap(_metadata, CAP_INHERITABLE, cap, CAP_SET); + + EXPECT_NE(-1, cap_set_ambient(cap, CAP_SET)) + { + TH_LOG("Failed to set ambient capability %d: %s", cap, + strerror(errno)); + } +} + +static void __maybe_unused clear_ambient_cap( + struct __test_metadata *const _metadata, const cap_value_t cap) { - _effective_cap(_metadata, caps, CAP_CLEAR); + EXPECT_EQ(1, cap_get_ambient(cap)); + _change_cap(_metadata, CAP_INHERITABLE, cap, CAP_CLEAR); + EXPECT_EQ(0, cap_get_ambient(cap)); } /* Receives an FD from a UNIX socket. Returns the received FD, or -errno. */ diff --git a/tools/testing/selftests/landlock/fs_test.c b/tools/testing/selftests/landlock/fs_test.c index 50818904397c..2d6d9b43d958 100644 --- a/tools/testing/selftests/landlock/fs_test.c +++ b/tools/testing/selftests/landlock/fs_test.c @@ -241,9 +241,11 @@ struct mnt_opt { const char *const data; }; -const struct mnt_opt mnt_tmp = { +#define MNT_TMP_DATA "size=4m,mode=700" + +static const struct mnt_opt mnt_tmp = { .type = "tmpfs", - .data = "size=4m,mode=700", + .data = MNT_TMP_DATA, }; static int mount_opt(const struct mnt_opt *const mnt, const char *const target) @@ -4632,7 +4634,10 @@ FIXTURE_VARIANT(layout3_fs) /* clang-format off */ FIXTURE_VARIANT_ADD(layout3_fs, tmpfs) { /* clang-format on */ - .mnt = mnt_tmp, + .mnt = { + .type = "tmpfs", + .data = MNT_TMP_DATA, + }, .file_path = file1_s1d1, }; diff --git a/tools/testing/selftests/landlock/net_test.c b/tools/testing/selftests/landlock/net_test.c index ea5f727dd257..936cfc879f1d 100644 --- a/tools/testing/selftests/landlock/net_test.c +++ b/tools/testing/selftests/landlock/net_test.c @@ -17,6 +17,7 @@ #include <string.h> #include <sys/prctl.h> #include <sys/socket.h> +#include <sys/syscall.h> #include <sys/un.h> #include "common.h" @@ -54,6 +55,11 @@ struct service_fixture { }; }; +static pid_t sys_gettid(void) +{ + return syscall(__NR_gettid); +} + static int set_service(struct service_fixture *const srv, const struct protocol_variant prot, const unsigned short index) @@ -88,7 +94,7 @@ static int set_service(struct service_fixture *const srv, case AF_UNIX: srv->unix_addr.sun_family = prot.domain; sprintf(srv->unix_addr.sun_path, - "_selftests-landlock-net-tid%d-index%d", gettid(), + "_selftests-landlock-net-tid%d-index%d", sys_gettid(), index); srv->unix_addr_len = SUN_LEN(&srv->unix_addr); srv->unix_addr.sun_path[0] = '\0'; @@ -101,8 +107,11 @@ static void setup_loopback(struct __test_metadata *const _metadata) { set_cap(_metadata, CAP_SYS_ADMIN); ASSERT_EQ(0, unshare(CLONE_NEWNET)); - ASSERT_EQ(0, system("ip link set dev lo up")); clear_cap(_metadata, CAP_SYS_ADMIN); + + set_ambient_cap(_metadata, CAP_NET_ADMIN); + ASSERT_EQ(0, system("ip link set dev lo up")); + clear_ambient_cap(_metadata, CAP_NET_ADMIN); } static bool is_restricted(const struct protocol_variant *const prot, diff --git a/tools/testing/selftests/net/config b/tools/testing/selftests/net/config index 3b749addd364..5e4390cac17e 100644 --- a/tools/testing/selftests/net/config +++ b/tools/testing/selftests/net/config @@ -24,10 +24,14 @@ CONFIG_IFB=y CONFIG_INET_DIAG=y CONFIG_INET_ESP=y CONFIG_INET_ESP_OFFLOAD=y +CONFIG_NET_FOU=y +CONFIG_NET_FOU_IP_TUNNELS=y CONFIG_IP_GRE=m CONFIG_NETFILTER=y CONFIG_NETFILTER_ADVANCED=y CONFIG_NF_CONNTRACK=m +CONFIG_IPV6_SIT=y +CONFIG_IP_DCCP=m CONFIG_NF_NAT=m CONFIG_IP6_NF_IPTABLES=m CONFIG_IP_NF_IPTABLES=m @@ -62,6 +66,7 @@ CONFIG_NET_CLS_MATCHALL=m CONFIG_NET_CLS_U32=m CONFIG_NET_IPGRE_DEMUX=m CONFIG_NET_IPGRE=m +CONFIG_NET_IPIP=y CONFIG_NET_SCH_FQ_CODEL=m CONFIG_NET_SCH_HTB=m CONFIG_NET_SCH_FQ=m @@ -78,7 +83,6 @@ CONFIG_TLS=m CONFIG_TRACEPOINTS=y CONFIG_NET_DROP_MONITOR=m CONFIG_NETDEVSIM=m -CONFIG_NET_FOU=m CONFIG_MPLS_ROUTING=m CONFIG_MPLS_IPTUNNEL=m CONFIG_NET_SCH_INGRESS=m diff --git a/tools/testing/selftests/net/forwarding/bridge_locked_port.sh b/tools/testing/selftests/net/forwarding/bridge_locked_port.sh index 9af9f6964808..c62331b2e006 100755 --- a/tools/testing/selftests/net/forwarding/bridge_locked_port.sh +++ b/tools/testing/selftests/net/forwarding/bridge_locked_port.sh @@ -327,10 +327,10 @@ locked_port_mab_redirect() RET=0 check_port_mab_support || return 0 - bridge link set dev $swp1 learning on locked on mab on tc qdisc add dev $swp1 clsact tc filter add dev $swp1 ingress protocol all pref 1 handle 101 flower \ action mirred egress redirect dev $swp2 + bridge link set dev $swp1 learning on locked on mab on ping_do $h1 192.0.2.2 check_err $? "Ping did not work with redirection" @@ -349,8 +349,8 @@ locked_port_mab_redirect() check_err $? "Locked entry not created after deleting filter" bridge fdb del `mac_get $h1` vlan 1 dev $swp1 master - tc qdisc del dev $swp1 clsact bridge link set dev $swp1 learning off locked off mab off + tc qdisc del dev $swp1 clsact log_test "Locked port MAB redirect" } diff --git a/tools/testing/selftests/net/forwarding/bridge_mdb.sh b/tools/testing/selftests/net/forwarding/bridge_mdb.sh index 61348f71728c..d9d587454d20 100755 --- a/tools/testing/selftests/net/forwarding/bridge_mdb.sh +++ b/tools/testing/selftests/net/forwarding/bridge_mdb.sh @@ -329,7 +329,7 @@ __cfg_test_port_ip_star_g() bridge -d -s mdb get dev br0 grp $grp vid 10 | grep -q " 0.00" check_err $? "(*, G) \"permanent\" entry has a pending group timer" - bridge -d -s mdb get dev br0 grp $grp vid 10 | grep -q "\/0.00" + bridge -d -s mdb get dev br0 grp $grp vid 10 | grep -q "/0.00" check_err $? "\"permanent\" source entry has a pending source timer" bridge mdb del dev br0 port $swp1 grp $grp vid 10 @@ -346,7 +346,7 @@ __cfg_test_port_ip_star_g() bridge -d -s mdb get dev br0 grp $grp vid 10 | grep -q " 0.00" check_fail $? "(*, G) EXCLUDE entry does not have a pending group timer" - bridge -d -s mdb get dev br0 grp $grp vid 10 | grep -q "\/0.00" + bridge -d -s mdb get dev br0 grp $grp vid 10 | grep -q "/0.00" check_err $? "\"blocked\" source entry has a pending source timer" bridge mdb del dev br0 port $swp1 grp $grp vid 10 @@ -363,7 +363,7 @@ __cfg_test_port_ip_star_g() bridge -d -s mdb get dev br0 grp $grp vid 10 | grep -q " 0.00" check_err $? "(*, G) INCLUDE entry has a pending group timer" - bridge -d -s mdb get dev br0 grp $grp vid 10 | grep -q "\/0.00" + bridge -d -s mdb get dev br0 grp $grp vid 10 | grep -q "/0.00" check_fail $? "Source entry does not have a pending source timer" bridge mdb del dev br0 port $swp1 grp $grp vid 10 @@ -1252,14 +1252,17 @@ fwd_test() echo log_info "# Forwarding tests" + # Set the Max Response Delay to 100 centiseconds (1 second) so that the + # bridge will start forwarding according to its MDB soon after a + # multicast querier is enabled. + ip link set dev br0 type bridge mcast_query_response_interval 100 + # Forwarding according to MDB entries only takes place when the bridge # detects that there is a valid querier in the network. Set the bridge # as the querier and assign it a valid IPv6 link-local address to be # used as the source address for MLD queries. ip -6 address add fe80::1/64 nodad dev br0 ip link set dev br0 type bridge mcast_querier 1 - # Wait the default Query Response Interval (10 seconds) for the bridge - # to determine that there are no other queriers in the network. sleep 10 fwd_test_host @@ -1267,6 +1270,7 @@ fwd_test() ip link set dev br0 type bridge mcast_querier 0 ip -6 address del fe80::1/64 dev br0 + ip link set dev br0 type bridge mcast_query_response_interval 1000 } ctrl_igmpv3_is_in_test() diff --git a/tools/testing/selftests/net/forwarding/tc_flower_l2_miss.sh b/tools/testing/selftests/net/forwarding/tc_flower_l2_miss.sh index 20a7cb7222b8..c2420bb72c12 100755 --- a/tools/testing/selftests/net/forwarding/tc_flower_l2_miss.sh +++ b/tools/testing/selftests/net/forwarding/tc_flower_l2_miss.sh @@ -209,14 +209,17 @@ test_l2_miss_multicast() # both registered and unregistered multicast traffic. bridge link set dev $swp2 mcast_router 2 + # Set the Max Response Delay to 100 centiseconds (1 second) so that the + # bridge will start forwarding according to its MDB soon after a + # multicast querier is enabled. + ip link set dev br1 type bridge mcast_query_response_interval 100 + # Forwarding according to MDB entries only takes place when the bridge # detects that there is a valid querier in the network. Set the bridge # as the querier and assign it a valid IPv6 link-local address to be # used as the source address for MLD queries. ip link set dev br1 type bridge mcast_querier 1 ip -6 address add fe80::1/64 nodad dev br1 - # Wait the default Query Response Interval (10 seconds) for the bridge - # to determine that there are no other queriers in the network. sleep 10 test_l2_miss_multicast_ipv4 @@ -224,6 +227,7 @@ test_l2_miss_multicast() ip -6 address del fe80::1/64 dev br1 ip link set dev br1 type bridge mcast_querier 0 + ip link set dev br1 type bridge mcast_query_response_interval 1000 bridge link set dev $swp2 mcast_router 1 } diff --git a/tools/testing/selftests/net/gro.sh b/tools/testing/selftests/net/gro.sh index 19352f106c1d..02c21ff4ca81 100755 --- a/tools/testing/selftests/net/gro.sh +++ b/tools/testing/selftests/net/gro.sh @@ -31,6 +31,11 @@ run_test() { 1>>log.txt wait "${server_pid}" exit_code=$? + if [[ ${test} == "large" && -n "${KSFT_MACHINE_SLOW}" && \ + ${exit_code} -ne 0 ]]; then + echo "Ignoring errors due to slow environment" 1>&2 + exit_code=0 + fi if [[ "${exit_code}" -eq 0 ]]; then break; fi diff --git a/tools/testing/selftests/net/ip_local_port_range.c b/tools/testing/selftests/net/ip_local_port_range.c index 0f217a1cc837..6ebd58869a63 100644 --- a/tools/testing/selftests/net/ip_local_port_range.c +++ b/tools/testing/selftests/net/ip_local_port_range.c @@ -16,6 +16,10 @@ #define IP_LOCAL_PORT_RANGE 51 #endif +#ifndef IPPROTO_MPTCP +#define IPPROTO_MPTCP 262 +#endif + static __u32 pack_port_range(__u16 lo, __u16 hi) { return (hi << 16) | (lo << 0); diff --git a/tools/testing/selftests/net/net_helper.sh b/tools/testing/selftests/net/net_helper.sh index 4fe0befa13fb..6596fe03c77f 100644 --- a/tools/testing/selftests/net/net_helper.sh +++ b/tools/testing/selftests/net/net_helper.sh @@ -8,13 +8,16 @@ wait_local_port_listen() local listener_ns="${1}" local port="${2}" local protocol="${3}" - local port_hex + local pattern local i - port_hex="$(printf "%04X" "${port}")" + pattern=":$(printf "%04X" "${port}") " + + # for tcp protocol additionally check the socket state + [ ${protocol} = "tcp" ] && pattern="${pattern}0A" for i in $(seq 10); do - if ip netns exec "${listener_ns}" cat /proc/net/"${protocol}"* | \ - grep -q "${port_hex}"; then + if ip netns exec "${listener_ns}" awk '{print $2" "$4}' \ + /proc/net/"${protocol}"* | grep -q "${pattern}"; then break fi sleep 0.1 diff --git a/tools/testing/selftests/net/openvswitch/openvswitch.sh b/tools/testing/selftests/net/openvswitch/openvswitch.sh index f8499d4c87f3..36e40256ab92 100755 --- a/tools/testing/selftests/net/openvswitch/openvswitch.sh +++ b/tools/testing/selftests/net/openvswitch/openvswitch.sh @@ -502,9 +502,22 @@ test_netlink_checks () { wc -l) == 2 ] || \ return 1 + info "Checking clone depth" ERR_MSG="Flow actions may not be safe on all matching packets" PRE_TEST=$(dmesg | grep -c "${ERR_MSG}") ovs_add_flow "test_netlink_checks" nv0 \ + 'in_port(1),eth(),eth_type(0x800),ipv4()' \ + 'clone(clone(clone(clone(clone(clone(clone(clone(clone(clone(clone(clone(clone(clone(clone(clone(clone(drop)))))))))))))))))' \ + >/dev/null 2>&1 && return 1 + POST_TEST=$(dmesg | grep -c "${ERR_MSG}") + + if [ "$PRE_TEST" == "$POST_TEST" ]; then + info "failed - clone depth too large" + return 1 + fi + + PRE_TEST=$(dmesg | grep -c "${ERR_MSG}") + ovs_add_flow "test_netlink_checks" nv0 \ 'in_port(1),eth(),eth_type(0x0806),arp()' 'drop(0),2' \ &> /dev/null && return 1 POST_TEST=$(dmesg | grep -c "${ERR_MSG}") diff --git a/tools/testing/selftests/net/openvswitch/ovs-dpctl.py b/tools/testing/selftests/net/openvswitch/ovs-dpctl.py index b97e621face9..5e0e539a323d 100644 --- a/tools/testing/selftests/net/openvswitch/ovs-dpctl.py +++ b/tools/testing/selftests/net/openvswitch/ovs-dpctl.py @@ -299,7 +299,7 @@ class ovsactions(nla): ("OVS_ACTION_ATTR_PUSH_NSH", "none"), ("OVS_ACTION_ATTR_POP_NSH", "flag"), ("OVS_ACTION_ATTR_METER", "none"), - ("OVS_ACTION_ATTR_CLONE", "none"), + ("OVS_ACTION_ATTR_CLONE", "recursive"), ("OVS_ACTION_ATTR_CHECK_PKT_LEN", "none"), ("OVS_ACTION_ATTR_ADD_MPLS", "none"), ("OVS_ACTION_ATTR_DEC_TTL", "none"), @@ -465,29 +465,42 @@ class ovsactions(nla): print_str += "pop_mpls" else: datum = self.get_attr(field[0]) - print_str += datum.dpstr(more) + if field[0] == "OVS_ACTION_ATTR_CLONE": + print_str += "clone(" + print_str += datum.dpstr(more) + print_str += ")" + else: + print_str += datum.dpstr(more) return print_str def parse(self, actstr): + totallen = len(actstr) while len(actstr) != 0: parsed = False + parencount = 0 if actstr.startswith("drop"): # If no reason is provided, the implicit drop is used (i.e no # action). If some reason is given, an explicit action is used. - actstr, reason = parse_extract_field( - actstr, - "drop(", - "([0-9]+)", - lambda x: int(x, 0), - False, - None, - ) + reason = None + if actstr.startswith("drop("): + parencount += 1 + + actstr, reason = parse_extract_field( + actstr, + "drop(", + "([0-9]+)", + lambda x: int(x, 0), + False, + None, + ) + if reason is not None: self["attrs"].append(["OVS_ACTION_ATTR_DROP", reason]) parsed = True else: - return + actstr = actstr[len("drop"): ] + return (totallen - len(actstr)) elif parse_starts_block(actstr, "^(\d+)", False, True): actstr, output = parse_extract_field( @@ -504,6 +517,7 @@ class ovsactions(nla): False, 0, ) + parencount += 1 self["attrs"].append(["OVS_ACTION_ATTR_RECIRC", recircid]) parsed = True @@ -516,12 +530,22 @@ class ovsactions(nla): for flat_act in parse_flat_map: if parse_starts_block(actstr, flat_act[0], False): - actstr += len(flat_act[0]) + actstr = actstr[len(flat_act[0]):] self["attrs"].append([flat_act[1]]) actstr = actstr[strspn(actstr, ", ") :] parsed = True - if parse_starts_block(actstr, "ct(", False): + if parse_starts_block(actstr, "clone(", False): + parencount += 1 + subacts = ovsactions() + actstr = actstr[len("clone("):] + parsedLen = subacts.parse(actstr) + lst = [] + self["attrs"].append(("OVS_ACTION_ATTR_CLONE", subacts)) + actstr = actstr[parsedLen:] + parsed = True + elif parse_starts_block(actstr, "ct(", False): + parencount += 1 actstr = actstr[len("ct(") :] ctact = ovsactions.ctact() @@ -553,6 +577,7 @@ class ovsactions(nla): natact = ovsactions.ctact.natattr() if actstr.startswith("("): + parencount += 1 t = None actstr = actstr[1:] if actstr.startswith("src"): @@ -607,15 +632,29 @@ class ovsactions(nla): actstr = actstr[strspn(actstr, ", ") :] ctact["attrs"].append(["OVS_CT_ATTR_NAT", natact]) - actstr = actstr[strspn(actstr, ",) ") :] + actstr = actstr[strspn(actstr, ", ") :] self["attrs"].append(["OVS_ACTION_ATTR_CT", ctact]) parsed = True - actstr = actstr[strspn(actstr, "), ") :] + actstr = actstr[strspn(actstr, ", ") :] + while parencount > 0: + parencount -= 1 + actstr = actstr[strspn(actstr, " "):] + if len(actstr) and actstr[0] != ")": + raise ValueError("Action str: '%s' unbalanced" % actstr) + actstr = actstr[1:] + + if len(actstr) and actstr[0] == ")": + return (totallen - len(actstr)) + + actstr = actstr[strspn(actstr, ", ") :] + if not parsed: raise ValueError("Action str: '%s' not supported" % actstr) + return (totallen - len(actstr)) + class ovskey(nla): nla_flags = NLA_F_NESTED @@ -2111,6 +2150,8 @@ def main(argv): ovsflow = OvsFlow() ndb = NDB() + sys.setrecursionlimit(100000) + if hasattr(args, "showdp"): found = False for iface in ndb.interfaces: diff --git a/tools/testing/selftests/net/pmtu.sh b/tools/testing/selftests/net/pmtu.sh index d65fdd407d73..cfc84958025a 100755 --- a/tools/testing/selftests/net/pmtu.sh +++ b/tools/testing/selftests/net/pmtu.sh @@ -1336,16 +1336,16 @@ test_pmtu_ipvX_over_bridged_vxlanY_or_geneveY_exception() { else TCPDST="TCP:[${dst}]:50000" fi - ${ns_b} socat -T 3 -u -6 TCP-LISTEN:50000 STDOUT > $tmpoutfile & + ${ns_b} socat -T 3 -u -6 TCP-LISTEN:50000,reuseaddr STDOUT > $tmpoutfile & local socat_pid=$! wait_local_port_listen ${NS_B} 50000 tcp dd if=/dev/zero status=none bs=1M count=1 | ${target} socat -T 3 -u STDIN $TCPDST,connect-timeout=3 + wait ${socat_pid} size=$(du -sb $tmpoutfile) size=${size%%/tmp/*} - wait ${socat_pid} [ $size -ne 1048576 ] && err "File size $size mismatches exepcted value in locally bridged vxlan test" && return 1 done diff --git a/tools/testing/selftests/net/so_txtime.sh b/tools/testing/selftests/net/so_txtime.sh index 3f06f4d286a9..5e861ad32a42 100755 --- a/tools/testing/selftests/net/so_txtime.sh +++ b/tools/testing/selftests/net/so_txtime.sh @@ -5,6 +5,7 @@ set -e +readonly ksft_skip=4 readonly DEV="veth0" readonly BIN="./so_txtime" @@ -46,7 +47,7 @@ ip -netns "${NS2}" addr add 192.168.1.2/24 dev "${DEV}" ip -netns "${NS1}" addr add fd::1/64 dev "${DEV}" nodad ip -netns "${NS2}" addr add fd::2/64 dev "${DEV}" nodad -do_test() { +run_test() { local readonly IP="$1" local readonly CLOCK="$2" local readonly TXARGS="$3" @@ -64,12 +65,25 @@ do_test() { fi local readonly START="$(date +%s%N --date="+ 0.1 seconds")" + ip netns exec "${NS2}" "${BIN}" -"${IP}" -c "${CLOCK}" -t "${START}" -S "${SADDR}" -D "${DADDR}" "${RXARGS}" -r & ip netns exec "${NS1}" "${BIN}" -"${IP}" -c "${CLOCK}" -t "${START}" -S "${SADDR}" -D "${DADDR}" "${TXARGS}" wait "$!" } +do_test() { + run_test $@ + [ $? -ne 0 ] && ret=1 +} + +do_fail_test() { + run_test $@ + [ $? -eq 0 ] && ret=1 +} + ip netns exec "${NS1}" tc qdisc add dev "${DEV}" root fq +set +e +ret=0 do_test 4 mono a,-1 a,-1 do_test 6 mono a,0 a,0 do_test 6 mono a,10 a,10 @@ -77,13 +91,20 @@ do_test 4 mono a,10,b,20 a,10,b,20 do_test 6 mono a,20,b,10 b,20,a,20 if ip netns exec "${NS1}" tc qdisc replace dev "${DEV}" root etf clockid CLOCK_TAI delta 400000; then - ! do_test 4 tai a,-1 a,-1 - ! do_test 6 tai a,0 a,0 + do_fail_test 4 tai a,-1 a,-1 + do_fail_test 6 tai a,0 a,0 do_test 6 tai a,10 a,10 do_test 4 tai a,10,b,20 a,10,b,20 do_test 6 tai a,20,b,10 b,10,a,20 else echo "tc ($(tc -V)) does not support qdisc etf. skipping" + [ $ret -eq 0 ] && ret=$ksft_skip fi -echo OK. All tests passed +if [ $ret -eq 0 ]; then + echo OK. All tests passed +elif [[ $ret -ne $ksft_skip && -n "$KSFT_MACHINE_SLOW" ]]; then + echo "Ignoring errors due to slow environment" 1>&2 + ret=0 +fi +exit $ret diff --git a/tools/testing/selftests/net/test_bridge_backup_port.sh b/tools/testing/selftests/net/test_bridge_backup_port.sh index 70a7d87ba2d2..1b3f89e2b86e 100755 --- a/tools/testing/selftests/net/test_bridge_backup_port.sh +++ b/tools/testing/selftests/net/test_bridge_backup_port.sh @@ -124,6 +124,16 @@ tc_check_packets() [[ $pkts == $count ]] } +bridge_link_check() +{ + local ns=$1; shift + local dev=$1; shift + local state=$1; shift + + bridge -n $ns -d -j link show dev $dev | \ + jq -e ".[][\"state\"] == \"$state\"" &> /dev/null +} + ################################################################################ # Setup @@ -259,6 +269,7 @@ backup_port() log_test $? 0 "No forwarding out of vx0" run_cmd "ip -n $sw1 link set dev swp1 carrier off" + busywait $BUSYWAIT_TIMEOUT bridge_link_check $sw1 swp1 disabled log_test $? 0 "swp1 carrier off" run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" @@ -268,6 +279,7 @@ backup_port() log_test $? 0 "No forwarding out of vx0" run_cmd "ip -n $sw1 link set dev swp1 carrier on" + busywait $BUSYWAIT_TIMEOUT bridge_link_check $sw1 swp1 forwarding log_test $? 0 "swp1 carrier on" # Configure vx0 as the backup port of swp1 and check that packets are @@ -284,6 +296,7 @@ backup_port() log_test $? 0 "No forwarding out of vx0" run_cmd "ip -n $sw1 link set dev swp1 carrier off" + busywait $BUSYWAIT_TIMEOUT bridge_link_check $sw1 swp1 disabled log_test $? 0 "swp1 carrier off" run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" @@ -293,6 +306,7 @@ backup_port() log_test $? 0 "Forwarding out of vx0" run_cmd "ip -n $sw1 link set dev swp1 carrier on" + busywait $BUSYWAIT_TIMEOUT bridge_link_check $sw1 swp1 forwarding log_test $? 0 "swp1 carrier on" run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" @@ -314,6 +328,7 @@ backup_port() log_test $? 0 "No forwarding out of vx0" run_cmd "ip -n $sw1 link set dev swp1 carrier off" + busywait $BUSYWAIT_TIMEOUT bridge_link_check $sw1 swp1 disabled log_test $? 0 "swp1 carrier off" run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" @@ -369,6 +384,7 @@ backup_nhid() log_test $? 0 "No forwarding out of vx0" run_cmd "ip -n $sw1 link set dev swp1 carrier off" + busywait $BUSYWAIT_TIMEOUT bridge_link_check $sw1 swp1 disabled log_test $? 0 "swp1 carrier off" run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" @@ -382,6 +398,7 @@ backup_nhid() log_test $? 0 "Forwarding using VXLAN FDB entry" run_cmd "ip -n $sw1 link set dev swp1 carrier on" + busywait $BUSYWAIT_TIMEOUT bridge_link_check $sw1 swp1 forwarding log_test $? 0 "swp1 carrier on" # Configure nexthop ID 10 as the backup nexthop ID of swp1 and check @@ -398,6 +415,7 @@ backup_nhid() log_test $? 0 "No forwarding out of vx0" run_cmd "ip -n $sw1 link set dev swp1 carrier off" + busywait $BUSYWAIT_TIMEOUT bridge_link_check $sw1 swp1 disabled log_test $? 0 "swp1 carrier off" run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" @@ -411,6 +429,7 @@ backup_nhid() log_test $? 0 "No forwarding using VXLAN FDB entry" run_cmd "ip -n $sw1 link set dev swp1 carrier on" + busywait $BUSYWAIT_TIMEOUT bridge_link_check $sw1 swp1 forwarding log_test $? 0 "swp1 carrier on" run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" @@ -441,6 +460,7 @@ backup_nhid() log_test $? 0 "No forwarding using VXLAN FDB entry" run_cmd "ip -n $sw1 link set dev swp1 carrier off" + busywait $BUSYWAIT_TIMEOUT bridge_link_check $sw1 swp1 disabled log_test $? 0 "swp1 carrier off" run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" @@ -497,6 +517,7 @@ backup_nhid_invalid() log_test $? 0 "Valid nexthop as backup nexthop" run_cmd "ip -n $sw1 link set dev swp1 carrier off" + busywait $BUSYWAIT_TIMEOUT bridge_link_check $sw1 swp1 disabled log_test $? 0 "swp1 carrier off" run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" @@ -604,7 +625,9 @@ backup_nhid_ping() run_cmd "bridge -n $sw2 link set dev swp1 backup_nhid 10" run_cmd "ip -n $sw1 link set dev swp1 carrier off" + busywait $BUSYWAIT_TIMEOUT bridge_link_check $sw1 swp1 disabled run_cmd "ip -n $sw2 link set dev swp1 carrier off" + busywait $BUSYWAIT_TIMEOUT bridge_link_check $sw2 swp1 disabled run_cmd "ip netns exec $sw1 ping -i 0.1 -c 10 -w $PING_TIMEOUT 192.0.2.66" log_test $? 0 "Ping with backup nexthop ID" diff --git a/tools/testing/selftests/net/tls.c b/tools/testing/selftests/net/tls.c index 7799e042a971..49c84602707f 100644 --- a/tools/testing/selftests/net/tls.c +++ b/tools/testing/selftests/net/tls.c @@ -1002,12 +1002,12 @@ TEST_F(tls, recv_partial) memset(recv_mem, 0, sizeof(recv_mem)); EXPECT_EQ(send(self->fd, test_str, send_len, 0), send_len); - EXPECT_NE(recv(self->cfd, recv_mem, strlen(test_str_first), - MSG_WAITALL), -1); + EXPECT_EQ(recv(self->cfd, recv_mem, strlen(test_str_first), + MSG_WAITALL), strlen(test_str_first)); EXPECT_EQ(memcmp(test_str_first, recv_mem, strlen(test_str_first)), 0); memset(recv_mem, 0, sizeof(recv_mem)); - EXPECT_NE(recv(self->cfd, recv_mem, strlen(test_str_second), - MSG_WAITALL), -1); + EXPECT_EQ(recv(self->cfd, recv_mem, strlen(test_str_second), + MSG_WAITALL), strlen(test_str_second)); EXPECT_EQ(memcmp(test_str_second, recv_mem, strlen(test_str_second)), 0); } @@ -1874,13 +1874,13 @@ TEST_F(tls_err, poll_partial_rec_async) /* Child should sleep in poll(), never get a wake */ pfd.fd = self->cfd2; pfd.events = POLLIN; - EXPECT_EQ(poll(&pfd, 1, 5), 0); + EXPECT_EQ(poll(&pfd, 1, 20), 0); EXPECT_EQ(write(p[1], &token, 1), 1); /* Barrier #1 */ pfd.fd = self->cfd2; pfd.events = POLLIN; - EXPECT_EQ(poll(&pfd, 1, 5), 1); + EXPECT_EQ(poll(&pfd, 1, 20), 1); exit(!_metadata->passed); } diff --git a/tools/testing/selftests/powerpc/papr_vpd/papr_vpd.c b/tools/testing/selftests/powerpc/papr_vpd/papr_vpd.c index 98cbb9109ee6..505294da1b9f 100644 --- a/tools/testing/selftests/powerpc/papr_vpd/papr_vpd.c +++ b/tools/testing/selftests/powerpc/papr_vpd/papr_vpd.c @@ -263,10 +263,10 @@ static int papr_vpd_system_loc_code(void) off_t size; int fd; - SKIP_IF_MSG(get_system_loc_code(&lc), - "Cannot determine system location code"); SKIP_IF_MSG(devfd < 0 && errno == ENOENT, DEVPATH " not present"); + SKIP_IF_MSG(get_system_loc_code(&lc), + "Cannot determine system location code"); FAIL_IF(devfd < 0); diff --git a/tools/tracing/rtla/Makefile b/tools/tracing/rtla/Makefile index 2456a399eb9a..afd18c678ff5 100644 --- a/tools/tracing/rtla/Makefile +++ b/tools/tracing/rtla/Makefile @@ -28,10 +28,15 @@ FOPTS := -flto=auto -ffat-lto-objects -fexceptions -fstack-protector-strong \ -fasynchronous-unwind-tables -fstack-clash-protection WOPTS := -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -Wno-maybe-uninitialized +ifeq ($(CC),clang) + FOPTS := $(filter-out -ffat-lto-objects, $(FOPTS)) + WOPTS := $(filter-out -Wno-maybe-uninitialized, $(WOPTS)) +endif + TRACEFS_HEADERS := $$($(PKG_CONFIG) --cflags libtracefs) CFLAGS := -O -g -DVERSION=\"$(VERSION)\" $(FOPTS) $(MOPTS) $(WOPTS) $(TRACEFS_HEADERS) $(EXTRA_CFLAGS) -LDFLAGS := -ggdb $(EXTRA_LDFLAGS) +LDFLAGS := -flto=auto -ggdb $(EXTRA_LDFLAGS) LIBS := $$($(PKG_CONFIG) --libs libtracefs) SRC := $(wildcard src/*.c) diff --git a/tools/tracing/rtla/src/osnoise_hist.c b/tools/tracing/rtla/src/osnoise_hist.c index 8f81fa007364..01870d50942a 100644 --- a/tools/tracing/rtla/src/osnoise_hist.c +++ b/tools/tracing/rtla/src/osnoise_hist.c @@ -135,8 +135,7 @@ static void osnoise_hist_update_multiple(struct osnoise_tool *tool, int cpu, if (params->output_divisor) duration = duration / params->output_divisor; - if (data->bucket_size) - bucket = duration / data->bucket_size; + bucket = duration / data->bucket_size; total_duration = duration * count; @@ -480,7 +479,11 @@ static void osnoise_hist_usage(char *usage) for (i = 0; msg[i]; i++) fprintf(stderr, "%s\n", msg[i]); - exit(1); + + if (usage) + exit(EXIT_FAILURE); + + exit(EXIT_SUCCESS); } /* diff --git a/tools/tracing/rtla/src/osnoise_top.c b/tools/tracing/rtla/src/osnoise_top.c index f7c959be8677..457360db0767 100644 --- a/tools/tracing/rtla/src/osnoise_top.c +++ b/tools/tracing/rtla/src/osnoise_top.c @@ -331,7 +331,11 @@ static void osnoise_top_usage(struct osnoise_top_params *params, char *usage) for (i = 0; msg[i]; i++) fprintf(stderr, "%s\n", msg[i]); - exit(1); + + if (usage) + exit(EXIT_FAILURE); + + exit(EXIT_SUCCESS); } /* diff --git a/tools/tracing/rtla/src/timerlat_hist.c b/tools/tracing/rtla/src/timerlat_hist.c index 47d3d8b53cb2..dbf154082f95 100644 --- a/tools/tracing/rtla/src/timerlat_hist.c +++ b/tools/tracing/rtla/src/timerlat_hist.c @@ -178,8 +178,7 @@ timerlat_hist_update(struct osnoise_tool *tool, int cpu, if (params->output_divisor) latency = latency / params->output_divisor; - if (data->bucket_size) - bucket = latency / data->bucket_size; + bucket = latency / data->bucket_size; if (!context) { hist = data->hist[cpu].irq; @@ -546,7 +545,11 @@ static void timerlat_hist_usage(char *usage) for (i = 0; msg[i]; i++) fprintf(stderr, "%s\n", msg[i]); - exit(1); + + if (usage) + exit(EXIT_FAILURE); + + exit(EXIT_SUCCESS); } /* diff --git a/tools/tracing/rtla/src/timerlat_top.c b/tools/tracing/rtla/src/timerlat_top.c index 1640f121baca..3e9af2c38688 100644 --- a/tools/tracing/rtla/src/timerlat_top.c +++ b/tools/tracing/rtla/src/timerlat_top.c @@ -375,7 +375,11 @@ static void timerlat_top_usage(char *usage) for (i = 0; msg[i]; i++) fprintf(stderr, "%s\n", msg[i]); - exit(1); + + if (usage) + exit(EXIT_FAILURE); + + exit(EXIT_SUCCESS); } /* diff --git a/tools/tracing/rtla/src/utils.c b/tools/tracing/rtla/src/utils.c index c769d7b3842c..9ac71a66840c 100644 --- a/tools/tracing/rtla/src/utils.c +++ b/tools/tracing/rtla/src/utils.c @@ -238,12 +238,6 @@ static inline int sched_setattr(pid_t pid, const struct sched_attr *attr, return syscall(__NR_sched_setattr, pid, attr, flags); } -static inline int sched_getattr(pid_t pid, struct sched_attr *attr, - unsigned int size, unsigned int flags) -{ - return syscall(__NR_sched_getattr, pid, attr, size, flags); -} - int __set_sched_attr(int pid, struct sched_attr *attr) { int flags = 0; @@ -479,13 +473,13 @@ int parse_prio(char *arg, struct sched_attr *sched_param) if (prio == INVALID_VAL) return -1; - if (prio < sched_get_priority_min(SCHED_OTHER)) + if (prio < MIN_NICE) return -1; - if (prio > sched_get_priority_max(SCHED_OTHER)) + if (prio > MAX_NICE) return -1; sched_param->sched_policy = SCHED_OTHER; - sched_param->sched_priority = prio; + sched_param->sched_nice = prio; break; default: return -1; @@ -536,7 +530,7 @@ int set_cpu_dma_latency(int32_t latency) */ static const int find_mount(const char *fs, char *mp, int sizeof_mp) { - char mount_point[MAX_PATH]; + char mount_point[MAX_PATH+1]; char type[100]; int found = 0; FILE *fp; diff --git a/tools/tracing/rtla/src/utils.h b/tools/tracing/rtla/src/utils.h index 04ed1e650495..d44513e6c66a 100644 --- a/tools/tracing/rtla/src/utils.h +++ b/tools/tracing/rtla/src/utils.h @@ -9,6 +9,8 @@ */ #define BUFF_U64_STR_SIZE 24 #define MAX_PATH 1024 +#define MAX_NICE 20 +#define MIN_NICE -19 #define container_of(ptr, type, member)({ \ const typeof(((type *)0)->member) *__mptr = (ptr); \ diff --git a/tools/verification/rv/Makefile b/tools/verification/rv/Makefile index 3d0f3888a58c..485f8aeddbe0 100644 --- a/tools/verification/rv/Makefile +++ b/tools/verification/rv/Makefile @@ -28,10 +28,15 @@ FOPTS := -flto=auto -ffat-lto-objects -fexceptions -fstack-protector-strong \ -fasynchronous-unwind-tables -fstack-clash-protection WOPTS := -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -Wno-maybe-uninitialized +ifeq ($(CC),clang) + FOPTS := $(filter-out -ffat-lto-objects, $(FOPTS)) + WOPTS := $(filter-out -Wno-maybe-uninitialized, $(WOPTS)) +endif + TRACEFS_HEADERS := $$($(PKG_CONFIG) --cflags libtracefs) CFLAGS := -O -g -DVERSION=\"$(VERSION)\" $(FOPTS) $(MOPTS) $(WOPTS) $(TRACEFS_HEADERS) $(EXTRA_CFLAGS) -I include -LDFLAGS := -ggdb $(EXTRA_LDFLAGS) +LDFLAGS := -flto=auto -ggdb $(EXTRA_LDFLAGS) LIBS := $$($(PKG_CONFIG) --libs libtracefs) SRC := $(wildcard src/*.c) diff --git a/tools/verification/rv/src/in_kernel.c b/tools/verification/rv/src/in_kernel.c index ad28582bcf2b..f04479ecc96c 100644 --- a/tools/verification/rv/src/in_kernel.c +++ b/tools/verification/rv/src/in_kernel.c @@ -210,9 +210,9 @@ static char *ikm_read_reactor(char *monitor_name) static char *ikm_get_current_reactor(char *monitor_name) { char *reactors = ikm_read_reactor(monitor_name); + char *curr_reactor = NULL; char *start; char *end; - char *curr_reactor; if (!reactors) return NULL; |