diff options
56 files changed, 920 insertions, 592 deletions
diff --git a/Documentation/devicetree/bindings/eeprom/at24.yaml b/Documentation/devicetree/bindings/eeprom/at24.yaml index 50af7ccf6e21..c21282634780 100644 --- a/Documentation/devicetree/bindings/eeprom/at24.yaml +++ b/Documentation/devicetree/bindings/eeprom/at24.yaml @@ -131,6 +131,7 @@ properties: - const: atmel,24c32 - items: - enum: + - belling,bl24s64 - onnn,n24s64b - puya,p24c64f - const: atmel,24c64 diff --git a/Documentation/devicetree/bindings/i2c/i2c-rk3x.yaml b/Documentation/devicetree/bindings/i2c/i2c-rk3x.yaml index 4ac5a40a3886..91805fe8f393 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-rk3x.yaml +++ b/Documentation/devicetree/bindings/i2c/i2c-rk3x.yaml @@ -37,6 +37,7 @@ properties: - rockchip,px30-i2c - rockchip,rk3308-i2c - rockchip,rk3328-i2c + - rockchip,rk3506-i2c - rockchip,rk3528-i2c - rockchip,rk3562-i2c - rockchip,rk3568-i2c diff --git a/Documentation/devicetree/bindings/i2c/qcom,i2c-cci.yaml b/Documentation/devicetree/bindings/i2c/qcom,i2c-cci.yaml index 9bc99d736343..33852a5ffca8 100644 --- a/Documentation/devicetree/bindings/i2c/qcom,i2c-cci.yaml +++ b/Documentation/devicetree/bindings/i2c/qcom,i2c-cci.yaml @@ -15,6 +15,7 @@ properties: oneOf: - enum: - qcom,msm8226-cci + - qcom,msm8953-cci - qcom,msm8974-cci - qcom,msm8996-cci @@ -25,6 +26,7 @@ properties: - items: - enum: + - qcom,kaanapali-cci - qcom,qcm2290-cci - qcom,sa8775p-cci - qcom,sc7280-cci @@ -128,6 +130,7 @@ allOf: compatible: contains: enum: + - qcom,kaanapali-cci - qcom,qcm2290-cci then: properties: @@ -146,6 +149,7 @@ allOf: - contains: enum: - qcom,msm8916-cci + - qcom,msm8953-cci - const: qcom,msm8996-cci then: diff --git a/Documentation/devicetree/bindings/input/ti,twl4030-keypad.yaml b/Documentation/devicetree/bindings/input/ti,twl4030-keypad.yaml new file mode 100644 index 000000000000..c69aa7f5cca7 --- /dev/null +++ b/Documentation/devicetree/bindings/input/ti,twl4030-keypad.yaml @@ -0,0 +1,59 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/input/ti,twl4030-keypad.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Texas Instruments TWL4030-family Keypad Controller + +maintainers: + - Peter Ujfalusi <peter.ujfalusi@gmail.com> + +description: + TWL4030's Keypad controller is used to interface a SoC with a matrix-type + keypad device. The keypad controller supports multiple row and column lines. + A key can be placed at each intersection of a unique row and a unique column. + The keypad controller can sense a key-press and key-release and report the + event using a interrupt to the cpu. + +allOf: + - $ref: matrix-keymap.yaml# + +properties: + compatible: + const: ti,twl4030-keypad + + interrupts: + maxItems: 1 + +required: + - compatible + - interrupts + - keypad,num-rows + - keypad,num-columns + - linux,keymap + +unevaluatedProperties: false + +examples: + - | + #include <dt-bindings/input/input.h> + + keypad { + compatible = "ti,twl4030-keypad"; + interrupts = <1>; + keypad,num-rows = <8>; + keypad,num-columns = <8>; + linux,keymap = < + /* row 0 */ + MATRIX_KEY(0, 0, KEY_1) + MATRIX_KEY(0, 1, KEY_2) + MATRIX_KEY(0, 2, KEY_3) + + /* ...and so on for a full 8x8 matrix... */ + + /* row 7 */ + MATRIX_KEY(7, 6, KEY_Y) + MATRIX_KEY(7, 7, KEY_Z) + >; + }; diff --git a/Documentation/devicetree/bindings/input/touchscreen/ar1021.txt b/Documentation/devicetree/bindings/input/touchscreen/ar1021.txt deleted file mode 100644 index 82019bd6094e..000000000000 --- a/Documentation/devicetree/bindings/input/touchscreen/ar1021.txt +++ /dev/null @@ -1,15 +0,0 @@ -* Microchip AR1020 and AR1021 touchscreen interface (I2C) - -Required properties: -- compatible : "microchip,ar1021-i2c" -- reg : I2C slave address -- interrupts : touch controller interrupt - -Example: - - touchscreen@4d { - compatible = "microchip,ar1021-i2c"; - reg = <0x4d>; - interrupt-parent = <&gpio3>; - interrupts = <11 IRQ_TYPE_LEVEL_HIGH>; - }; diff --git a/Documentation/devicetree/bindings/input/touchscreen/azoteq,iqs5xx.yaml b/Documentation/devicetree/bindings/input/touchscreen/azoteq,iqs5xx.yaml deleted file mode 100644 index b5f377215c09..000000000000 --- a/Documentation/devicetree/bindings/input/touchscreen/azoteq,iqs5xx.yaml +++ /dev/null @@ -1,75 +0,0 @@ -# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) -%YAML 1.2 ---- -$id: http://devicetree.org/schemas/input/touchscreen/azoteq,iqs5xx.yaml# -$schema: http://devicetree.org/meta-schemas/core.yaml# - -title: Azoteq IQS550/572/525 Trackpad/Touchscreen Controller - -maintainers: - - Jeff LaBundy <jeff@labundy.com> - -description: | - The Azoteq IQS550, IQS572 and IQS525 trackpad and touchscreen controllers - employ projected-capacitance sensing and can track up to five independent - contacts. - - Link to datasheet: https://www.azoteq.com/ - -allOf: - - $ref: touchscreen.yaml# - -properties: - compatible: - enum: - - azoteq,iqs550 - - azoteq,iqs572 - - azoteq,iqs525 - - reg: - maxItems: 1 - - interrupts: - maxItems: 1 - - reset-gpios: - maxItems: 1 - - wakeup-source: true - - touchscreen-size-x: true - touchscreen-size-y: true - touchscreen-inverted-x: true - touchscreen-inverted-y: true - touchscreen-swapped-x-y: true - -required: - - compatible - - reg - - interrupts - -additionalProperties: false - -examples: - - | - #include <dt-bindings/gpio/gpio.h> - #include <dt-bindings/interrupt-controller/irq.h> - - i2c { - #address-cells = <1>; - #size-cells = <0>; - - touchscreen@74 { - compatible = "azoteq,iqs550"; - reg = <0x74>; - interrupt-parent = <&gpio>; - interrupts = <27 IRQ_TYPE_LEVEL_HIGH>; - reset-gpios = <&gpio 22 (GPIO_ACTIVE_LOW | - GPIO_PUSH_PULL)>; - - touchscreen-size-x = <800>; - touchscreen-size-y = <480>; - }; - }; - -... diff --git a/Documentation/devicetree/bindings/input/touchscreen/himax,hx83112b.yaml b/Documentation/devicetree/bindings/input/touchscreen/himax,hx83112b.yaml deleted file mode 100644 index f5cfacb5e966..000000000000 --- a/Documentation/devicetree/bindings/input/touchscreen/himax,hx83112b.yaml +++ /dev/null @@ -1,64 +0,0 @@ -# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) -%YAML 1.2 ---- -$id: http://devicetree.org/schemas/input/touchscreen/himax,hx83112b.yaml# -$schema: http://devicetree.org/meta-schemas/core.yaml# - -title: Himax hx83112b touchscreen controller - -maintainers: - - Job Noorman <job@noorman.info> - -allOf: - - $ref: touchscreen.yaml# - -properties: - compatible: - enum: - - himax,hx83100a - - himax,hx83112b - - reg: - maxItems: 1 - - interrupts: - maxItems: 1 - - reset-gpios: - maxItems: 1 - - touchscreen-inverted-x: true - touchscreen-inverted-y: true - touchscreen-size-x: true - touchscreen-size-y: true - touchscreen-swapped-x-y: true - -additionalProperties: false - -required: - - compatible - - reg - - interrupts - - reset-gpios - - touchscreen-size-x - - touchscreen-size-y - -examples: - - | - #include <dt-bindings/interrupt-controller/irq.h> - #include <dt-bindings/gpio/gpio.h> - i2c { - #address-cells = <1>; - #size-cells = <0>; - touchscreen@48 { - compatible = "himax,hx83112b"; - reg = <0x48>; - interrupt-parent = <&tlmm>; - interrupts = <65 IRQ_TYPE_LEVEL_LOW>; - touchscreen-size-x = <1080>; - touchscreen-size-y = <2160>; - reset-gpios = <&tlmm 64 GPIO_ACTIVE_LOW>; - }; - }; - -... diff --git a/Documentation/devicetree/bindings/input/touchscreen/hynitron,cstxxx.yaml b/Documentation/devicetree/bindings/input/touchscreen/hynitron,cstxxx.yaml deleted file mode 100644 index 9cb5d4af00f7..000000000000 --- a/Documentation/devicetree/bindings/input/touchscreen/hynitron,cstxxx.yaml +++ /dev/null @@ -1,65 +0,0 @@ -# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) -%YAML 1.2 ---- -$id: http://devicetree.org/schemas/input/touchscreen/hynitron,cstxxx.yaml# -$schema: http://devicetree.org/meta-schemas/core.yaml# - -title: Hynitron cstxxx series touchscreen controller - -description: | - Bindings for Hynitron cstxxx series multi-touch touchscreen - controllers. - -maintainers: - - Chris Morgan <macromorgan@hotmail.com> - -allOf: - - $ref: touchscreen.yaml# - -properties: - compatible: - enum: - - hynitron,cst340 - - reg: - maxItems: 1 - - interrupts: - maxItems: 1 - - reset-gpios: - maxItems: 1 - - touchscreen-size-x: true - touchscreen-size-y: true - touchscreen-inverted-x: true - touchscreen-inverted-y: true - touchscreen-swapped-x-y: true - -additionalProperties: false - -required: - - compatible - - reg - - interrupts - - reset-gpios - -examples: - - | - #include <dt-bindings/gpio/gpio.h> - #include <dt-bindings/interrupt-controller/arm-gic.h> - i2c { - #address-cells = <1>; - #size-cells = <0>; - touchscreen@1a { - compatible = "hynitron,cst340"; - reg = <0x1a>; - interrupt-parent = <&gpio4>; - interrupts = <9 IRQ_TYPE_EDGE_FALLING>; - reset-gpios = <&gpio4 6 GPIO_ACTIVE_LOW>; - touchscreen-size-x = <640>; - touchscreen-size-y = <480>; - }; - }; - -... diff --git a/Documentation/devicetree/bindings/input/touchscreen/ilitek_ts_i2c.yaml b/Documentation/devicetree/bindings/input/touchscreen/ilitek_ts_i2c.yaml deleted file mode 100644 index 9f7328999756..000000000000 --- a/Documentation/devicetree/bindings/input/touchscreen/ilitek_ts_i2c.yaml +++ /dev/null @@ -1,76 +0,0 @@ -# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) -%YAML 1.2 ---- -$id: http://devicetree.org/schemas/input/touchscreen/ilitek_ts_i2c.yaml# -$schema: http://devicetree.org/meta-schemas/core.yaml# - -title: Ilitek I2C Touchscreen Controller - -maintainers: - - Dmitry Torokhov <dmitry.torokhov@gmail.com> - -allOf: - - $ref: touchscreen.yaml# - -properties: - compatible: - enum: - - ilitek,ili210x - - ilitek,ili2117 - - ilitek,ili2120 - - ilitek,ili2130 - - ilitek,ili2131 - - ilitek,ili2132 - - ilitek,ili2316 - - ilitek,ili2322 - - ilitek,ili2323 - - ilitek,ili2326 - - ilitek,ili251x - - ilitek,ili2520 - - ilitek,ili2521 - - reg: - maxItems: 1 - - interrupts: - maxItems: 1 - - reset-gpios: - maxItems: 1 - - wakeup-source: - type: boolean - description: touchscreen can be used as a wakeup source. - - touchscreen-size-x: true - touchscreen-size-y: true - touchscreen-inverted-x: true - touchscreen-inverted-y: true - touchscreen-swapped-x-y: true - -additionalProperties: false - -required: - - compatible - - reg - - interrupts - -examples: - - | - #include <dt-bindings/interrupt-controller/irq.h> - #include <dt-bindings/gpio/gpio.h> - i2c { - #address-cells = <1>; - #size-cells = <0>; - - touchscreen@41 { - compatible = "ilitek,ili2520"; - reg = <0x41>; - - interrupt-parent = <&gpio1>; - interrupts = <7 IRQ_TYPE_LEVEL_LOW>; - reset-gpios = <&gpio1 8 GPIO_ACTIVE_LOW>; - touchscreen-inverted-y; - wakeup-source; - }; - }; diff --git a/Documentation/devicetree/bindings/input/touchscreen/maxim,max11801.yaml b/Documentation/devicetree/bindings/input/touchscreen/maxim,max11801.yaml deleted file mode 100644 index 4f528d220199..000000000000 --- a/Documentation/devicetree/bindings/input/touchscreen/maxim,max11801.yaml +++ /dev/null @@ -1,46 +0,0 @@ -# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) -%YAML 1.2 ---- -$id: http://devicetree.org/schemas/input/touchscreen/maxim,max11801.yaml# -$schema: http://devicetree.org/meta-schemas/core.yaml# - -title: MAXI MAX11801 Resistive touch screen controller with i2c interface - -maintainers: - - Frank Li <Frank.Li@nxp.com> - -properties: - compatible: - const: maxim,max11801 - - reg: - maxItems: 1 - - interrupts: - maxItems: 1 - -allOf: - - $ref: touchscreen.yaml - -required: - - compatible - - reg - - interrupts - -unevaluatedProperties: false - -examples: - - | - #include <dt-bindings/interrupt-controller/irq.h> - - i2c { - #address-cells = <1>; - #size-cells = <0>; - - touchscreen@48 { - compatible = "maxim,max11801"; - reg = <0x48>; - interrupt-parent = <&gpio3>; - interrupts = <31 IRQ_TYPE_EDGE_FALLING>; - }; - }; diff --git a/Documentation/devicetree/bindings/input/touchscreen/melfas,mip4_ts.yaml b/Documentation/devicetree/bindings/input/touchscreen/melfas,mip4_ts.yaml new file mode 100644 index 000000000000..314be65c56ca --- /dev/null +++ b/Documentation/devicetree/bindings/input/touchscreen/melfas,mip4_ts.yaml @@ -0,0 +1,56 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/input/touchscreen/melfas,mip4_ts.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MELFAS MIP4 Touchscreen + +maintainers: + - Ariel D'Alessandro <ariel.dalessandro@collabora.com> + +properties: + compatible: + const: melfas,mip4_ts + + reg: + description: I2C address of the chip (0x48 or 0x34) + maxItems: 1 + + interrupts: + maxItems: 1 + + ce-gpios: + description: + GPIO connected to the CE (chip enable) pin of the chip (active high) + maxItems: 1 + +required: + - compatible + - reg + - interrupts + +additionalProperties: false + +examples: + - | + #include <dt-bindings/gpio/gpio.h> + #include <dt-bindings/interrupt-controller/irq.h> + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + touchscreen@34 { + compatible = "melfas,mip4_ts"; + reg = <0x34>; + + interrupts-extended = <&tlmm 13 IRQ_TYPE_EDGE_FALLING>; + ce-gpios = <&tlmm 12 GPIO_ACTIVE_HIGH>; + + pinctrl-0 = <&touchscreen_default>; + pinctrl-names = "default"; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/input/touchscreen/melfas_mip4.txt b/Documentation/devicetree/bindings/input/touchscreen/melfas_mip4.txt deleted file mode 100644 index b2ab5498e519..000000000000 --- a/Documentation/devicetree/bindings/input/touchscreen/melfas_mip4.txt +++ /dev/null @@ -1,20 +0,0 @@ -* MELFAS MIP4 Touchscreen - -Required properties: -- compatible: must be "melfas,mip4_ts" -- reg: I2C slave address of the chip (0x48 or 0x34) -- interrupts: interrupt to which the chip is connected - -Optional properties: -- ce-gpios: GPIO connected to the CE (chip enable) pin of the chip - -Example: - i2c@00000000 { - touchscreen: melfas_mip4@48 { - compatible = "melfas,mip4_ts"; - reg = <0x48>; - interrupt-parent = <&gpio>; - interrupts = <0 IRQ_TYPE_EDGE_FALLING>; - ce-gpios = <&gpio 0 GPIO_ACTIVE_HIGH>; - }; - }; diff --git a/Documentation/devicetree/bindings/input/touchscreen/semtech,sx8654.yaml b/Documentation/devicetree/bindings/input/touchscreen/semtech,sx8654.yaml deleted file mode 100644 index b2554064b688..000000000000 --- a/Documentation/devicetree/bindings/input/touchscreen/semtech,sx8654.yaml +++ /dev/null @@ -1,52 +0,0 @@ -# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) -%YAML 1.2 ---- -$id: http://devicetree.org/schemas/input/touchscreen/semtech,sx8654.yaml# -$schema: http://devicetree.org/meta-schemas/core.yaml# - -title: Semtech SX8654 I2C Touchscreen Controller - -maintainers: - - Frank Li <Frank.Li@nxp.com> - -properties: - compatible: - enum: - - semtech,sx8650 - - semtech,sx8654 - - semtech,sx8655 - - semtech,sx8656 - - reg: - maxItems: 1 - - interrupts: - maxItems: 1 - - reset-gpios: - maxItems: 1 - -required: - - compatible - - reg - - interrupts - -additionalProperties: false - -examples: - - | - #include <dt-bindings/gpio/gpio.h> - #include <dt-bindings/interrupt-controller/irq.h> - - i2c { - #address-cells = <1>; - #size-cells = <0>; - - touchscreen@48 { - compatible = "semtech,sx8654"; - reg = <0x48>; - interrupt-parent = <&gpio6>; - interrupts = <3 IRQ_TYPE_EDGE_FALLING>; - reset-gpios = <&gpio4 2 GPIO_ACTIVE_LOW>; - }; - }; diff --git a/Documentation/devicetree/bindings/input/touchscreen/trivial-touch.yaml b/Documentation/devicetree/bindings/input/touchscreen/trivial-touch.yaml new file mode 100644 index 000000000000..fa27c6754ca4 --- /dev/null +++ b/Documentation/devicetree/bindings/input/touchscreen/trivial-touch.yaml @@ -0,0 +1,84 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/input/touchscreen/trivial-touch.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Trivial touch screen controller with i2c interface + +maintainers: + - Frank Li <Frank.Li@nxp.com> + +properties: + compatible: + enum: + # The Azoteq IQS550, IQS572 and IQS525 trackpad and touchscreen controllers + - azoteq,iqs550 + - azoteq,iqs572 + - azoteq,iqs525 + # Himax hx83100a touchscreen controller + - himax,hx83100a + # Himax hx83112b touchscreen controller + - himax,hx83112b + # Hynitron cstxxx series touchscreen controller + - hynitron,cst340 + # Ilitek I2C Touchscreen Controller + - ilitek,ili210x + - ilitek,ili2117 + - ilitek,ili2120 + - ilitek,ili2130 + - ilitek,ili2131 + - ilitek,ili2132 + - ilitek,ili2316 + - ilitek,ili2322 + - ilitek,ili2323 + - ilitek,ili2326 + - ilitek,ili251x + - ilitek,ili2520 + - ilitek,ili2521 + # MAXI MAX11801 Resistive touch screen controller with i2c interface + - maxim,max11801 + # Microchip AR1020 and AR1021 touchscreen interface (I2C) + - microchip,ar1021-i2c + # Trivial touch screen controller with i2c interface + - semtech,sx8650 + - semtech,sx8654 + - semtech,sx8655 + - semtech,sx8656 + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + reset-gpios: + maxItems: 1 + + wakeup-source: true + +allOf: + - $ref: touchscreen.yaml + +required: + - compatible + - reg + - interrupts + +unevaluatedProperties: false + +examples: + - | + #include <dt-bindings/interrupt-controller/irq.h> + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + touchscreen@48 { + compatible = "maxim,max11801"; + reg = <0x48>; + interrupt-parent = <&gpio3>; + interrupts = <31 IRQ_TYPE_EDGE_FALLING>; + }; + }; diff --git a/Documentation/devicetree/bindings/input/twl4030-keypad.txt b/Documentation/devicetree/bindings/input/twl4030-keypad.txt deleted file mode 100644 index e4be2f76a717..000000000000 --- a/Documentation/devicetree/bindings/input/twl4030-keypad.txt +++ /dev/null @@ -1,27 +0,0 @@ -* TWL4030's Keypad Controller device tree bindings - -TWL4030's Keypad controller is used to interface a SoC with a matrix-type -keypad device. The keypad controller supports multiple row and column lines. -A key can be placed at each intersection of a unique row and a unique column. -The keypad controller can sense a key-press and key-release and report the -event using a interrupt to the cpu. - -This binding is based on the matrix-keymap binding with the following -changes: - - * keypad,num-rows and keypad,num-columns are required. - -Required SoC Specific Properties: -- compatible: should be one of the following - - "ti,twl4030-keypad": For controllers compatible with twl4030 keypad - controller. -- interrupt: should be one of the following - - <1>: For controllers compatible with twl4030 keypad controller. - -Example: - twl_keypad: keypad { - compatible = "ti,twl4030-keypad"; - interrupts = <1>; - keypad,num-rows = <8>; - keypad,num-columns = <8>; - }; diff --git a/Documentation/i2c/busses/i2c-i801.rst b/Documentation/i2c/busses/i2c-i801.rst index 36c563ad3f06..c939a5bfc8d0 100644 --- a/Documentation/i2c/busses/i2c-i801.rst +++ b/Documentation/i2c/busses/i2c-i801.rst @@ -51,6 +51,7 @@ Supported adapters: * Intel Arrow Lake (SOC) * Intel Panther Lake (SOC) * Intel Wildcat Lake (SOC) + * Intel Diamond Rapids (SOC) Datasheets: Publicly available at the Intel website diff --git a/MAINTAINERS b/MAINTAINERS index d3f88aab8ba0..aff3e162180d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -26455,6 +26455,7 @@ F: include/trace/ F: kernel/trace/ F: kernel/tracepoint.c F: scripts/tracing/ +F: scripts/tracepoint-update.c F: tools/testing/selftests/ftrace/ TRACING MMIO ACCESSES (MMIOTRACE) diff --git a/arch/csky/abiv1/inc/abi/regdef.h b/arch/csky/abiv1/inc/abi/regdef.h index 7b386fd67070..c75ecf2cafd7 100644 --- a/arch/csky/abiv1/inc/abi/regdef.h +++ b/arch/csky/abiv1/inc/abi/regdef.h @@ -3,7 +3,7 @@ #ifndef __ASM_CSKY_REGDEF_H #define __ASM_CSKY_REGDEF_H -#ifdef __ASSEMBLY__ +#ifdef __ASSEMBLER__ #define syscallid r1 #else #define syscallid "r1" diff --git a/arch/csky/abiv2/inc/abi/regdef.h b/arch/csky/abiv2/inc/abi/regdef.h index 0933addbc27b..fc08d56ccdbe 100644 --- a/arch/csky/abiv2/inc/abi/regdef.h +++ b/arch/csky/abiv2/inc/abi/regdef.h @@ -3,7 +3,7 @@ #ifndef __ASM_CSKY_REGDEF_H #define __ASM_CSKY_REGDEF_H -#ifdef __ASSEMBLY__ +#ifdef __ASSEMBLER__ #define syscallid r7 #else #define syscallid "r7" diff --git a/arch/csky/include/asm/barrier.h b/arch/csky/include/asm/barrier.h index 15de58b10aec..c33fdcfe3770 100644 --- a/arch/csky/include/asm/barrier.h +++ b/arch/csky/include/asm/barrier.h @@ -3,7 +3,7 @@ #ifndef __ASM_CSKY_BARRIER_H #define __ASM_CSKY_BARRIER_H -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #define nop() asm volatile ("nop\n":::"memory") @@ -84,5 +84,5 @@ #include <asm-generic/barrier.h> -#endif /* __ASSEMBLY__ */ +#endif /* __ASSEMBLER__ */ #endif /* __ASM_CSKY_BARRIER_H */ diff --git a/arch/csky/include/asm/cache.h b/arch/csky/include/asm/cache.h index 4b5c09bf1d25..d575482e0fce 100644 --- a/arch/csky/include/asm/cache.h +++ b/arch/csky/include/asm/cache.h @@ -10,7 +10,7 @@ #define ARCH_DMA_MINALIGN L1_CACHE_BYTES -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ void dcache_wb_line(unsigned long start); diff --git a/arch/csky/include/asm/ftrace.h b/arch/csky/include/asm/ftrace.h index 00f9f7647e3f..21532f218058 100644 --- a/arch/csky/include/asm/ftrace.h +++ b/arch/csky/include/asm/ftrace.h @@ -11,7 +11,7 @@ #define MCOUNT_ADDR ((unsigned long)_mcount) -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ extern void _mcount(unsigned long); @@ -28,5 +28,5 @@ struct dyn_arch_ftrace { void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr, unsigned long frame_pointer); -#endif /* !__ASSEMBLY__ */ +#endif /* !__ASSEMBLER__ */ #endif /* __ASM_CSKY_FTRACE_H */ diff --git a/arch/csky/include/asm/jump_label.h b/arch/csky/include/asm/jump_label.h index ef2e37a10a0f..603b0caa8024 100644 --- a/arch/csky/include/asm/jump_label.h +++ b/arch/csky/include/asm/jump_label.h @@ -3,7 +3,7 @@ #ifndef __ASM_CSKY_JUMP_LABEL_H #define __ASM_CSKY_JUMP_LABEL_H -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #include <linux/types.h> @@ -48,5 +48,5 @@ void arch_jump_label_transform_static(struct jump_entry *entry, enum jump_label_type type); #define arch_jump_label_transform_static arch_jump_label_transform_static -#endif /* __ASSEMBLY__ */ +#endif /* __ASSEMBLER__ */ #endif /* __ASM_CSKY_JUMP_LABEL_H */ diff --git a/arch/csky/include/asm/page.h b/arch/csky/include/asm/page.h index 4911d0892b71..76774dbce869 100644 --- a/arch/csky/include/asm/page.h +++ b/arch/csky/include/asm/page.h @@ -26,7 +26,7 @@ #define PHYS_OFFSET_OFFSET (CONFIG_DRAM_BASE & (SSEG_SIZE - 1)) -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #include <linux/pfn.h> @@ -84,5 +84,5 @@ static inline unsigned long virt_to_pfn(const void *kaddr) #include <asm-generic/memory_model.h> #include <asm-generic/getorder.h> -#endif /* !__ASSEMBLY__ */ +#endif /* !__ASSEMBLER__ */ #endif /* __ASM_CSKY_PAGE_H */ diff --git a/arch/csky/include/asm/ptrace.h b/arch/csky/include/asm/ptrace.h index 0634b7895d81..5f01839e1184 100644 --- a/arch/csky/include/asm/ptrace.h +++ b/arch/csky/include/asm/ptrace.h @@ -8,7 +8,7 @@ #include <linux/types.h> #include <linux/compiler.h> -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #define PS_S 0x80000000 /* Supervisor Mode */ @@ -98,5 +98,5 @@ static inline unsigned long regs_get_register(struct pt_regs *regs, asmlinkage int syscall_trace_enter(struct pt_regs *regs); asmlinkage void syscall_trace_exit(struct pt_regs *regs); -#endif /* __ASSEMBLY__ */ +#endif /* __ASSEMBLER__ */ #endif /* __ASM_CSKY_PTRACE_H */ diff --git a/arch/csky/include/asm/sections.h b/arch/csky/include/asm/sections.h index 83e82b7c0f6c..ee5cdf226a9b 100644 --- a/arch/csky/include/asm/sections.h +++ b/arch/csky/include/asm/sections.h @@ -8,5 +8,6 @@ extern char _start[]; asmlinkage void csky_start(unsigned int unused, void *dtb_start); +asmlinkage void csky_start_secondary(void); #endif /* __ASM_SECTIONS_H */ diff --git a/arch/csky/include/asm/string.h b/arch/csky/include/asm/string.h index a0d81e9d6b8f..82e99f52b547 100644 --- a/arch/csky/include/asm/string.h +++ b/arch/csky/include/asm/string.h @@ -3,7 +3,7 @@ #ifndef _CSKY_STRING_MM_H_ #define _CSKY_STRING_MM_H_ -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #include <linux/types.h> #include <linux/compiler.h> #include <abi/string.h> diff --git a/arch/csky/include/asm/thread_info.h b/arch/csky/include/asm/thread_info.h index b5ed788f0c68..fdd4f8ad45ac 100644 --- a/arch/csky/include/asm/thread_info.h +++ b/arch/csky/include/asm/thread_info.h @@ -3,7 +3,7 @@ #ifndef _ASM_CSKY_THREAD_INFO_H #define _ASM_CSKY_THREAD_INFO_H -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #include <asm/types.h> #include <asm/page.h> @@ -51,7 +51,7 @@ static inline struct thread_info *current_thread_info(void) return (struct thread_info *)(sp & ~(THREAD_SIZE - 1)); } -#endif /* !__ASSEMBLY__ */ +#endif /* !__ASSEMBLER__ */ #define TIF_SIGPENDING 0 /* signal pending */ #define TIF_NOTIFY_RESUME 1 /* callback before returning to user */ diff --git a/arch/csky/include/uapi/asm/ptrace.h b/arch/csky/include/uapi/asm/ptrace.h index 3be9c14334a6..90a5c36e4345 100644 --- a/arch/csky/include/uapi/asm/ptrace.h +++ b/arch/csky/include/uapi/asm/ptrace.h @@ -3,7 +3,7 @@ #ifndef _CSKY_PTRACE_H #define _CSKY_PTRACE_H -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ struct pt_regs { unsigned long tls; @@ -47,5 +47,5 @@ struct user_fp { unsigned long reserved; }; -#endif /* __ASSEMBLY__ */ +#endif /* __ASSEMBLER__ */ #endif /* _CSKY_PTRACE_H */ diff --git a/arch/csky/mm/fault.c b/arch/csky/mm/fault.c index a6ca7dff4215..7ff401108985 100644 --- a/arch/csky/mm/fault.c +++ b/arch/csky/mm/fault.c @@ -45,8 +45,8 @@ static inline void csky_cmpxchg_fixup(struct pt_regs *regs) if (trap_no(regs) != VEC_TLBMODIFIED) return; - if (instruction_pointer(regs) == csky_cmpxchg_stw) - instruction_pointer_set(regs, csky_cmpxchg_ldw); + if (instruction_pointer(regs) == (unsigned long)&csky_cmpxchg_stw) + instruction_pointer_set(regs, (unsigned long)&csky_cmpxchg_ldw); return; } #endif diff --git a/drivers/i2c/algos/i2c-algo-pcf.c b/drivers/i2c/algos/i2c-algo-pcf.c index fd563e845d4b..a87ecea7f510 100644 --- a/drivers/i2c/algos/i2c-algo-pcf.c +++ b/drivers/i2c/algos/i2c-algo-pcf.c @@ -23,17 +23,8 @@ #include "i2c-algo-pcf.h" -#define DEB2(x) if (i2c_debug >= 2) x -#define DEB3(x) if (i2c_debug >= 3) x /* print several statistical values */ -#define DEBPROTO(x) if (i2c_debug >= 9) x; - /* debug the protocol by showing transferred bits */ #define DEF_TIMEOUT 16 -/* - * module parameters: - */ -static int i2c_debug; - /* setting states on the bus with the right timing: */ #define set_pcf(adap, ctl, val) adap->setpcf(adap->data, ctl, val) @@ -47,27 +38,21 @@ static int i2c_debug; static void i2c_start(struct i2c_algo_pcf_data *adap) { - DEBPROTO(printk(KERN_DEBUG "S ")); set_pcf(adap, 1, I2C_PCF_START); } static void i2c_repstart(struct i2c_algo_pcf_data *adap) { - DEBPROTO(printk(" Sr ")); set_pcf(adap, 1, I2C_PCF_REPSTART); } static void i2c_stop(struct i2c_algo_pcf_data *adap) { - DEBPROTO(printk("P\n")); set_pcf(adap, 1, I2C_PCF_STOP); } static void handle_lab(struct i2c_algo_pcf_data *adap, const int *status) { - DEB2(printk(KERN_INFO - "i2c-algo-pcf.o: lost arbitration (CSR 0x%02x)\n", - *status)); /* * Cleanup from LAB -- reset and enable ESO. * This resets the PCF8584; since we've lost the bus, no @@ -88,9 +73,6 @@ static void handle_lab(struct i2c_algo_pcf_data *adap, const int *status) if (adap->lab_mdelay) mdelay(adap->lab_mdelay); - DEB2(printk(KERN_INFO - "i2c-algo-pcf.o: reset LAB condition (CSR 0x%02x)\n", - get_pcf(adap, 1))); } static int wait_for_bb(struct i2c_algo_pcf_data *adap) @@ -147,56 +129,48 @@ static int wait_for_pin(struct i2c_algo_pcf_data *adap, int *status) * * vdovikin: added detect code for PCF8584 */ -static int pcf_init_8584 (struct i2c_algo_pcf_data *adap) +static int pcf_init_8584(struct i2c_algo_pcf_data *adap) { unsigned char temp; - DEB3(printk(KERN_DEBUG "i2c-algo-pcf.o: PCF state 0x%02x\n", - get_pcf(adap, 1))); - /* S1=0x80: S0 selected, serial interface off */ set_pcf(adap, 1, I2C_PCF_PIN); /* * check to see S1 now used as R/W ctrl - * PCF8584 does that when ESO is zero */ - if (((temp = get_pcf(adap, 1)) & 0x7f) != (0)) { - DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't select S0 (0x%02x).\n", temp)); + temp = get_pcf(adap, 1); + if ((temp & 0x7f) != 0) return -ENXIO; /* definitely not PCF8584 */ - } /* load own address in S0, effective address is (own << 1) */ i2c_outb(adap, get_own(adap)); /* check it's really written */ - if ((temp = i2c_inb(adap)) != get_own(adap)) { - DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't set S0 (0x%02x).\n", temp)); + temp = i2c_inb(adap); + if (temp != get_own(adap)) return -ENXIO; - } /* S1=0xA0, next byte in S2 */ set_pcf(adap, 1, I2C_PCF_PIN | I2C_PCF_ES1); /* check to see S2 now selected */ - if (((temp = get_pcf(adap, 1)) & 0x7f) != I2C_PCF_ES1) { - DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't select S2 (0x%02x).\n", temp)); + temp = get_pcf(adap, 1); + if ((temp & 0x7f) != I2C_PCF_ES1) return -ENXIO; - } /* load clock register S2 */ i2c_outb(adap, get_clock(adap)); /* check it's really written, the only 5 lowest bits does matter */ - if (((temp = i2c_inb(adap)) & 0x1f) != get_clock(adap)) { - DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't set S2 (0x%02x).\n", temp)); + temp = i2c_inb(adap); + if ((temp & 0x1f) != get_clock(adap)) return -ENXIO; - } /* Enable serial interface, idle, S0 selected */ set_pcf(adap, 1, I2C_PCF_IDLE); /* check to see PCF is really idled and we can access status register */ - if ((temp = get_pcf(adap, 1)) != (I2C_PCF_PIN | I2C_PCF_BB)) { - DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't select S1` (0x%02x).\n", temp)); + temp = get_pcf(adap, 1); + if (temp != (I2C_PCF_PIN | I2C_PCF_BB)) return -ENXIO; - } printk(KERN_DEBUG "i2c-algo-pcf.o: detected and initialized PCF8584.\n"); @@ -209,9 +183,7 @@ static int pcf_sendbytes(struct i2c_adapter *i2c_adap, const char *buf, struct i2c_algo_pcf_data *adap = i2c_adap->algo_data; int wrcount, status, timeout; - for (wrcount=0; wrcount<count; ++wrcount) { - DEB2(dev_dbg(&i2c_adap->dev, "i2c_write: writing %2.2X\n", - buf[wrcount] & 0xff)); + for (wrcount = 0; wrcount < count; ++wrcount) { i2c_outb(adap, buf[wrcount]); timeout = wait_for_pin(adap, &status); if (timeout) { @@ -246,7 +218,8 @@ static int pcf_readbytes(struct i2c_adapter *i2c_adap, char *buf, /* increment number of bytes to read by one -- read dummy byte */ for (i = 0; i <= count; i++) { - if ((wfp = wait_for_pin(adap, &status))) { + wfp = wait_for_pin(adap, &status); + if (wfp) { if (wfp == -EINTR) return -EINTR; /* arbitration lost */ @@ -280,7 +253,7 @@ static int pcf_readbytes(struct i2c_adapter *i2c_adap, char *buf, } -static int pcf_doAddress(struct i2c_algo_pcf_data *adap, +static void pcf_send_address(struct i2c_algo_pcf_data *adap, struct i2c_msg *msg) { unsigned char addr = i2c_8bit_addr_from_msg(msg); @@ -288,8 +261,6 @@ static int pcf_doAddress(struct i2c_algo_pcf_data *adap, if (msg->flags & I2C_M_REV_DIR_ADDR) addr ^= 1; i2c_outb(adap, addr); - - return 0; } static int pcf_xfer(struct i2c_adapter *i2c_adap, @@ -299,7 +270,7 @@ static int pcf_xfer(struct i2c_adapter *i2c_adap, struct i2c_algo_pcf_data *adap = i2c_adap->algo_data; struct i2c_msg *pmsg; int i; - int ret=0, timeout, status; + int timeout, status; if (adap->xfer_begin) adap->xfer_begin(adap->data); @@ -307,20 +278,15 @@ static int pcf_xfer(struct i2c_adapter *i2c_adap, /* Check for bus busy */ timeout = wait_for_bb(adap); if (timeout) { - DEB2(printk(KERN_ERR "i2c-algo-pcf.o: " - "Timeout waiting for BB in pcf_xfer\n");) i = -EIO; goto out; } - for (i = 0;ret >= 0 && i < num; i++) { - pmsg = &msgs[i]; - - DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: Doing %s %d bytes to 0x%02x - %d of %d messages\n", - str_read_write(pmsg->flags & I2C_M_RD), - pmsg->len, pmsg->addr, i + 1, num);) + for (i = 0; i < num; i++) { + int ret; - ret = pcf_doAddress(adap, pmsg); + pmsg = &msgs[i]; + pcf_send_address(adap, pmsg); /* Send START */ if (i == 0) @@ -335,8 +301,6 @@ static int pcf_xfer(struct i2c_adapter *i2c_adap, goto out; } i2c_stop(adap); - DEB2(printk(KERN_ERR "i2c-algo-pcf.o: Timeout waiting " - "for PIN(1) in pcf_xfer\n");) i = -EREMOTEIO; goto out; } @@ -344,35 +308,21 @@ static int pcf_xfer(struct i2c_adapter *i2c_adap, /* Check LRB (last rcvd bit - slave ack) */ if (status & I2C_PCF_LRB) { i2c_stop(adap); - DEB2(printk(KERN_ERR "i2c-algo-pcf.o: No LRB(1) in pcf_xfer\n");) i = -EREMOTEIO; goto out; } - DEB3(printk(KERN_DEBUG "i2c-algo-pcf.o: Msg %d, addr=0x%x, flags=0x%x, len=%d\n", - i, msgs[i].addr, msgs[i].flags, msgs[i].len);) if (pmsg->flags & I2C_M_RD) { ret = pcf_readbytes(i2c_adap, pmsg->buf, pmsg->len, (i + 1 == num)); - - if (ret != pmsg->len) { - DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: fail: " - "only read %d bytes.\n",ret)); - } else { - DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: read %d bytes.\n",ret)); - } } else { ret = pcf_sendbytes(i2c_adap, pmsg->buf, pmsg->len, (i + 1 == num)); - - if (ret != pmsg->len) { - DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: fail: " - "only wrote %d bytes.\n",ret)); - } else { - DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: wrote %d bytes.\n",ret)); - } } + + if (ret < 0) + goto out; } out: @@ -401,12 +351,11 @@ int i2c_pcf_add_bus(struct i2c_adapter *adap) struct i2c_algo_pcf_data *pcf_adap = adap->algo_data; int rval; - DEB2(dev_dbg(&adap->dev, "hw routines registered.\n")); - /* register new adapter to i2c module... */ adap->algo = &pcf_algo; - if ((rval = pcf_init_8584(pcf_adap))) + rval = pcf_init_8584(pcf_adap); + if (rval) return rval; rval = i2c_add_adapter(adap); @@ -418,7 +367,3 @@ EXPORT_SYMBOL(i2c_pcf_add_bus); MODULE_AUTHOR("Hans Berglund <hb@spacetec.no>"); MODULE_DESCRIPTION("I2C-Bus PCF8584 algorithm"); MODULE_LICENSE("GPL"); - -module_param(i2c_debug, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(i2c_debug, - "debug level - 0 off; 1 normal; 2,3 more verbose; 9 pcf-protocol"); diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index fd81e49638aa..cea87fcb4a1a 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -166,6 +166,7 @@ config I2C_I801 Arrow Lake (SOC) Panther Lake (SOC) Wildcat Lake (SOC) + Diamond Rapids (SOC) This driver can also be built as a module. If so, the module will be called i2c-i801. @@ -1474,7 +1475,7 @@ config I2C_ACORN config I2C_ELEKTOR tristate "Elektor ISA card" - depends on ISA && HAS_IOPORT_MAP && BROKEN_ON_SMP + depends on ISA && HAS_IOPORT_MAP select I2C_ALGOPCF help This supports the PCF8584 ISA bus I2C adapter. Say Y if you own diff --git a/drivers/i2c/busses/i2c-amd-mp2-pci.c b/drivers/i2c/busses/i2c-amd-mp2-pci.c index ef7370d3dbea..60edbabc2986 100644 --- a/drivers/i2c/busses/i2c-amd-mp2-pci.c +++ b/drivers/i2c/busses/i2c-amd-mp2-pci.c @@ -458,13 +458,16 @@ struct amd_mp2_dev *amd_mp2_find_device(void) { struct device *dev; struct pci_dev *pci_dev; + struct amd_mp2_dev *mp2_dev; dev = driver_find_next_device(&amd_mp2_pci_driver.driver, NULL); if (!dev) return NULL; pci_dev = to_pci_dev(dev); - return (struct amd_mp2_dev *)pci_get_drvdata(pci_dev); + mp2_dev = (struct amd_mp2_dev *)pci_get_drvdata(pci_dev); + put_device(dev); + return mp2_dev; } EXPORT_SYMBOL_GPL(amd_mp2_find_device); diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c index 8554e790f8e3..0d7e2654a534 100644 --- a/drivers/i2c/busses/i2c-bcm2835.c +++ b/drivers/i2c/busses/i2c-bcm2835.c @@ -137,12 +137,14 @@ static int clk_bcm2835_i2c_set_rate(struct clk_hw *hw, unsigned long rate, return 0; } -static long clk_bcm2835_i2c_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int clk_bcm2835_i2c_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { - u32 divider = clk_bcm2835_i2c_calc_divider(rate, *parent_rate); + u32 divider = clk_bcm2835_i2c_calc_divider(req->rate, req->best_parent_rate); - return DIV_ROUND_UP(*parent_rate, divider); + req->rate = DIV_ROUND_UP(req->best_parent_rate, divider); + + return 0; } static unsigned long clk_bcm2835_i2c_recalc_rate(struct clk_hw *hw, @@ -156,7 +158,7 @@ static unsigned long clk_bcm2835_i2c_recalc_rate(struct clk_hw *hw, static const struct clk_ops clk_bcm2835_i2c_ops = { .set_rate = clk_bcm2835_i2c_set_rate, - .round_rate = clk_bcm2835_i2c_round_rate, + .determine_rate = clk_bcm2835_i2c_determine_rate, .recalc_rate = clk_bcm2835_i2c_recalc_rate, }; diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h index 347843b4f5dd..bb5ce0a382f9 100644 --- a/drivers/i2c/busses/i2c-designware-core.h +++ b/drivers/i2c/busses/i2c-designware-core.h @@ -78,6 +78,7 @@ #define DW_IC_TX_ABRT_SOURCE 0x80 #define DW_IC_ENABLE_STATUS 0x9c #define DW_IC_CLR_RESTART_DET 0xa8 +#define DW_IC_SMBUS_INTR_MASK 0xcc #define DW_IC_COMP_PARAM_1 0xf4 #define DW_IC_COMP_VERSION 0xf8 #define DW_IC_SDA_HOLD_MIN_VERS 0x3131312A /* "111*" == v1.11* */ @@ -330,7 +331,6 @@ struct dw_i2c_dev { struct i2c_dw_semaphore_callbacks { int (*probe)(struct dw_i2c_dev *dev); - void (*remove)(struct dw_i2c_dev *dev); }; int i2c_dw_init_regmap(struct dw_i2c_dev *dev); diff --git a/drivers/i2c/busses/i2c-designware-master.c b/drivers/i2c/busses/i2c-designware-master.c index 41e9b5ecad20..45bfca05bb30 100644 --- a/drivers/i2c/busses/i2c-designware-master.c +++ b/drivers/i2c/busses/i2c-designware-master.c @@ -220,6 +220,13 @@ static int i2c_dw_init_master(struct dw_i2c_dev *dev) /* Disable the adapter */ __i2c_dw_disable(dev); + /* + * Mask SMBus interrupts to block storms from broken + * firmware that leaves IC_SMBUS=1; the handler never + * services them. + */ + regmap_write(dev->map, DW_IC_SMBUS_INTR_MASK, 0); + /* Write standard speed timing parameters */ regmap_write(dev->map, DW_IC_SS_SCL_HCNT, dev->ss_hcnt); regmap_write(dev->map, DW_IC_SS_SCL_LCNT, dev->ss_lcnt); diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c index 34d881572351..7be99656a67d 100644 --- a/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/drivers/i2c/busses/i2c-designware-platdrv.c @@ -197,15 +197,6 @@ static int i2c_dw_probe_lock_support(struct dw_i2c_dev *dev) return 0; } -static void i2c_dw_remove_lock_support(struct dw_i2c_dev *dev) -{ - if (dev->semaphore_idx < 0) - return; - - if (i2c_dw_semaphore_cb_table[dev->semaphore_idx].remove) - i2c_dw_semaphore_cb_table[dev->semaphore_idx].remove(dev); -} - static int dw_i2c_plat_probe(struct platform_device *pdev) { u32 flags = (uintptr_t)device_get_match_data(&pdev->dev); @@ -248,7 +239,7 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) ret = i2c_dw_probe_lock_support(dev); if (ret) { - ret = dev_err_probe(device, ret, "failed to probe lock support\n"); + dev_err_probe(device, ret, "failed to probe lock support\n"); goto exit_reset; } @@ -339,8 +330,6 @@ static void dw_i2c_plat_remove(struct platform_device *pdev) i2c_dw_prepare_clk(dev, false); - i2c_dw_remove_lock_support(dev); - reset_control_assert(dev->rst); } diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 57fbec1259be..81e6e2d7ad3d 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -84,6 +84,7 @@ * Panther Lake-H (SOC) 0xe322 32 hard yes yes yes * Panther Lake-P (SOC) 0xe422 32 hard yes yes yes * Wildcat Lake-U (SOC) 0x4d22 32 hard yes yes yes + * Diamond Rapids (SOC) 0x5827 32 hard yes yes yes * * Features supported by this driver: * Software PEC no @@ -242,6 +243,7 @@ #define PCI_DEVICE_ID_INTEL_ALDER_LAKE_P_SMBUS 0x51a3 #define PCI_DEVICE_ID_INTEL_ALDER_LAKE_M_SMBUS 0x54a3 #define PCI_DEVICE_ID_INTEL_BIRCH_STREAM_SMBUS 0x5796 +#define PCI_DEVICE_ID_INTEL_DIAMOND_RAPIDS_SMBUS 0x5827 #define PCI_DEVICE_ID_INTEL_BROXTON_SMBUS 0x5ad4 #define PCI_DEVICE_ID_INTEL_ARROW_LAKE_H_SMBUS 0x7722 #define PCI_DEVICE_ID_INTEL_RAPTOR_LAKE_S_SMBUS 0x7a23 @@ -1054,6 +1056,7 @@ static const struct pci_device_id i801_ids[] = { { PCI_DEVICE_DATA(INTEL, METEOR_LAKE_SOC_S_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, { PCI_DEVICE_DATA(INTEL, METEOR_LAKE_PCH_S_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, { PCI_DEVICE_DATA(INTEL, BIRCH_STREAM_SMBUS, FEATURES_ICH5) }, + { PCI_DEVICE_DATA(INTEL, DIAMOND_RAPIDS_SMBUS, FEATURES_ICH5) }, { PCI_DEVICE_DATA(INTEL, ARROW_LAKE_H_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, { PCI_DEVICE_DATA(INTEL, PANTHER_LAKE_H_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, { PCI_DEVICE_DATA(INTEL, PANTHER_LAKE_P_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, diff --git a/drivers/i2c/busses/i2c-k1.c b/drivers/i2c/busses/i2c-k1.c index 6b918770e612..d42c03ef5db5 100644 --- a/drivers/i2c/busses/i2c-k1.c +++ b/drivers/i2c/busses/i2c-k1.c @@ -158,11 +158,16 @@ static int spacemit_i2c_handle_err(struct spacemit_i2c_dev *i2c) { dev_dbg(i2c->dev, "i2c error status: 0x%08x\n", i2c->status); - if (i2c->status & (SPACEMIT_SR_BED | SPACEMIT_SR_ALD)) { + /* Arbitration Loss Detected */ + if (i2c->status & SPACEMIT_SR_ALD) { spacemit_i2c_reset(i2c); return -EAGAIN; } + /* Bus Error No ACK/NAK */ + if (i2c->status & SPACEMIT_SR_BED) + spacemit_i2c_reset(i2c); + return i2c->status & SPACEMIT_SR_ACKNAK ? -ENXIO : -EIO; } @@ -224,6 +229,12 @@ static void spacemit_i2c_check_bus_release(struct spacemit_i2c_dev *i2c) } } +static inline void +spacemit_i2c_clear_int_status(struct spacemit_i2c_dev *i2c, u32 mask) +{ + writel(mask & SPACEMIT_I2C_INT_STATUS_MASK, i2c->base + SPACEMIT_ISR); +} + static void spacemit_i2c_init(struct spacemit_i2c_dev *i2c) { u32 val; @@ -267,12 +278,8 @@ static void spacemit_i2c_init(struct spacemit_i2c_dev *i2c) val = readl(i2c->base + SPACEMIT_IRCR); val |= SPACEMIT_RCR_SDA_GLITCH_NOFIX; writel(val, i2c->base + SPACEMIT_IRCR); -} -static inline void -spacemit_i2c_clear_int_status(struct spacemit_i2c_dev *i2c, u32 mask) -{ - writel(mask & SPACEMIT_I2C_INT_STATUS_MASK, i2c->base + SPACEMIT_ISR); + spacemit_i2c_clear_int_status(i2c, SPACEMIT_I2C_INT_STATUS_MASK); } static void spacemit_i2c_start(struct spacemit_i2c_dev *i2c) diff --git a/drivers/i2c/busses/i2c-qcom-cci.c b/drivers/i2c/busses/i2c-qcom-cci.c index e631d79baf14..884055df1560 100644 --- a/drivers/i2c/busses/i2c-qcom-cci.c +++ b/drivers/i2c/busses/i2c-qcom-cci.c @@ -783,8 +783,54 @@ static const struct cci_data cci_v2_data = { }, }; +static const struct cci_data cci_msm8953_data = { + .num_masters = 2, + .queue_size = { 64, 16 }, + .quirks = { + .max_write_len = 11, + .max_read_len = 12, + }, + .params[I2C_MODE_STANDARD] = { + .thigh = 78, + .tlow = 114, + .tsu_sto = 28, + .tsu_sta = 28, + .thd_dat = 10, + .thd_sta = 77, + .tbuf = 118, + .scl_stretch_en = 0, + .trdhld = 6, + .tsp = 1 + }, + .params[I2C_MODE_FAST] = { + .thigh = 20, + .tlow = 28, + .tsu_sto = 21, + .tsu_sta = 21, + .thd_dat = 13, + .thd_sta = 18, + .tbuf = 32, + .scl_stretch_en = 0, + .trdhld = 6, + .tsp = 3 + }, + .params[I2C_MODE_FAST_PLUS] = { + .thigh = 16, + .tlow = 22, + .tsu_sto = 17, + .tsu_sta = 18, + .thd_dat = 16, + .thd_sta = 15, + .tbuf = 19, + .scl_stretch_en = 1, + .trdhld = 3, + .tsp = 3 + }, +}; + static const struct of_device_id cci_dt_match[] = { { .compatible = "qcom,msm8226-cci", .data = &cci_v1_data}, + { .compatible = "qcom,msm8953-cci", .data = &cci_msm8953_data}, { .compatible = "qcom,msm8974-cci", .data = &cci_v1_5_data}, { .compatible = "qcom,msm8996-cci", .data = &cci_v2_data}, diff --git a/drivers/i2c/busses/i2c-stm32.c b/drivers/i2c/busses/i2c-stm32.c index f84ec056e36d..becf8977979f 100644 --- a/drivers/i2c/busses/i2c-stm32.c +++ b/drivers/i2c/busses/i2c-stm32.c @@ -27,8 +27,8 @@ struct stm32_i2c_dma *stm32_i2c_dma_request(struct device *dev, if (IS_ERR(dma->chan_tx)) { ret = PTR_ERR(dma->chan_tx); if (ret != -ENODEV) - ret = dev_err_probe(dev, ret, - "can't request DMA tx channel\n"); + dev_err_probe(dev, ret, "can't request DMA tx channel\n"); + goto fail_al; } @@ -48,8 +48,7 @@ struct stm32_i2c_dma *stm32_i2c_dma_request(struct device *dev, if (IS_ERR(dma->chan_rx)) { ret = PTR_ERR(dma->chan_rx); if (ret != -ENODEV) - ret = dev_err_probe(dev, ret, - "can't request DMA rx channel\n"); + dev_err_probe(dev, ret, "can't request DMA rx channel\n"); goto fail_tx; } diff --git a/drivers/input/misc/qnap-mcu-input.c b/drivers/input/misc/qnap-mcu-input.c index 76e62f0816c1..3be899bfc114 100644 --- a/drivers/input/misc/qnap-mcu-input.c +++ b/drivers/input/misc/qnap-mcu-input.c @@ -103,7 +103,7 @@ static int qnap_mcu_input_probe(struct platform_device *pdev) input = devm_input_allocate_device(dev); if (!input) - return dev_err_probe(dev, -ENOMEM, "no memory for input device\n"); + return -ENOMEM; idev->input = input; idev->dev = dev; diff --git a/drivers/input/touchscreen/cyttsp5.c b/drivers/input/touchscreen/cyttsp5.c index 071b7c9bf566..47f4271395a6 100644 --- a/drivers/input/touchscreen/cyttsp5.c +++ b/drivers/input/touchscreen/cyttsp5.c @@ -923,8 +923,8 @@ static int cyttsp5_i2c_probe(struct i2c_client *client) regmap = devm_regmap_init_i2c(client, &config); if (IS_ERR(regmap)) { - dev_err(&client->dev, "regmap allocation failed: %ld\n", - PTR_ERR(regmap)); + dev_err(&client->dev, "regmap allocation failed: %pe\n", + regmap); return PTR_ERR(regmap); } diff --git a/drivers/input/touchscreen/ti_am335x_tsc.c b/drivers/input/touchscreen/ti_am335x_tsc.c index 93d659ff90aa..d6edfab16770 100644 --- a/drivers/input/touchscreen/ti_am335x_tsc.c +++ b/drivers/input/touchscreen/ti_am335x_tsc.c @@ -389,6 +389,10 @@ static int titsc_parse_dt(struct platform_device *pdev, dev_warn(&pdev->dev, "invalid co-ordinate readouts, resetting it to 5\n"); ts_dev->coordinate_readouts = 5; + } else if (ts_dev->coordinate_readouts > 6) { + dev_warn(&pdev->dev, + "co-ordinate readouts too large, limiting to 6\n"); + ts_dev->coordinate_readouts = 6; } err = of_property_read_u32(node, "ti,charge-delay", diff --git a/drivers/input/touchscreen/zforce_ts.c b/drivers/input/touchscreen/zforce_ts.c index df42fdf36ae3..a360749fa076 100644 --- a/drivers/input/touchscreen/zforce_ts.c +++ b/drivers/input/touchscreen/zforce_ts.c @@ -747,8 +747,7 @@ static int zforce_probe(struct i2c_client *client) input_dev = devm_input_allocate_device(&client->dev); if (!input_dev) - return dev_err_probe(&client->dev, -ENOMEM, - "could not allocate input device\n"); + return -ENOMEM; ts->client = client; ts->input = input_dev; diff --git a/include/linux/restart_block.h b/include/linux/restart_block.h index 36ddfa1ec301..67d2bf579942 100644 --- a/include/linux/restart_block.h +++ b/include/linux/restart_block.h @@ -32,7 +32,7 @@ struct restart_block { u32 val; u32 flags; u32 bitset; - u64 time; + ktime_t time; u32 __user *uaddr2; } futex; /* For nanosleep */ diff --git a/include/uapi/linux/i2c.h b/include/uapi/linux/i2c.h index a2db2a56c8b0..2a226657d9f8 100644 --- a/include/uapi/linux/i2c.h +++ b/include/uapi/linux/i2c.h @@ -36,7 +36,7 @@ * * Only if I2C_FUNC_NOSTART is set: * %I2C_M_NOSTART: skip repeated start sequence - + * * Only if I2C_FUNC_PROTOCOL_MANGLING is set: * %I2C_M_NO_RD_ACK: in a read message, master ACK/NACK bit is skipped * %I2C_M_IGNORE_NAK: treat NACK from client as ACK diff --git a/kernel/futex/waitwake.c b/kernel/futex/waitwake.c index e2bbe5509ec2..1c2dd03f11ec 100644 --- a/kernel/futex/waitwake.c +++ b/kernel/futex/waitwake.c @@ -738,12 +738,11 @@ int futex_wait(u32 __user *uaddr, unsigned int flags, u32 val, ktime_t *abs_time static long futex_wait_restart(struct restart_block *restart) { u32 __user *uaddr = restart->futex.uaddr; - ktime_t t, *tp = NULL; + ktime_t *tp = NULL; + + if (restart->futex.flags & FLAGS_HAS_TIMEOUT) + tp = &restart->futex.time; - if (restart->futex.flags & FLAGS_HAS_TIMEOUT) { - t = restart->futex.time; - tp = &t; - } restart->fn = do_no_restart_syscall; return (long)futex_wait(uaddr, restart->futex.flags, diff --git a/scripts/package/install-extmod-build b/scripts/package/install-extmod-build index 054fdf45cc37..2576cf7902db 100755 --- a/scripts/package/install-extmod-build +++ b/scripts/package/install-extmod-build @@ -63,7 +63,7 @@ if [ "${CC}" != "${HOSTCC}" ]; then # Clear VPATH and srcroot because the source files reside in the output # directory. # shellcheck disable=SC2016 # $(MAKE) and $(build) will be expanded by Make - "${MAKE}" run-command KBUILD_RUN_COMMAND='+$(MAKE) HOSTCC='"${CC}"' VPATH= srcroot=. $(build)='"$(realpath --relative-to=. "${destdir}")"/scripts + "${MAKE}" run-command KBUILD_RUN_COMMAND='+$(MAKE) HOSTCC="'"${CC}"'" VPATH= srcroot=. $(build)='"$(realpath --relative-to=. "${destdir}")"/scripts rm -f "${destdir}/scripts/Kbuild" fi diff --git a/scripts/tracepoint-update.c b/scripts/tracepoint-update.c index 7f7d90df14ce..90046aedc97b 100644 --- a/scripts/tracepoint-update.c +++ b/scripts/tracepoint-update.c @@ -210,6 +210,9 @@ static int process_tracepoints(bool mod, void *addr, const char *fname) } if (!tracepoint_data_sec) { + /* A module may reference only exported tracepoints */ + if (mod) + return 0; fprintf(stderr, "no __tracepoint_strings in file: %s\n", fname); return -1; } diff --git a/tools/testing/selftests/futex/functional/.gitignore b/tools/testing/selftests/futex/functional/.gitignore index 776ad658f75e..23b9fea8d190 100644 --- a/tools/testing/selftests/futex/functional/.gitignore +++ b/tools/testing/selftests/futex/functional/.gitignore @@ -12,3 +12,4 @@ futex_wait_uninitialized_heap futex_wait_wouldblock futex_waitv futex_numa +robust_list diff --git a/tools/testing/selftests/futex/functional/Makefile b/tools/testing/selftests/futex/functional/Makefile index 490ace1f017e..af7ec309ea78 100644 --- a/tools/testing/selftests/futex/functional/Makefile +++ b/tools/testing/selftests/futex/functional/Makefile @@ -22,7 +22,8 @@ TEST_GEN_PROGS := \ futex_priv_hash \ futex_numa_mpol \ futex_waitv \ - futex_numa + futex_numa \ + robust_list TEST_PROGS := run.sh diff --git a/tools/testing/selftests/futex/functional/futex_numa_mpol.c b/tools/testing/selftests/futex/functional/futex_numa_mpol.c index ab8555752137..220ef219c823 100644 --- a/tools/testing/selftests/futex/functional/futex_numa_mpol.c +++ b/tools/testing/selftests/futex/functional/futex_numa_mpol.c @@ -131,11 +131,6 @@ static void test_futex(void *futex_ptr, int err_value) __test_futex(futex_ptr, err_value, FUTEX2_SIZE_U32 | FUTEX_PRIVATE_FLAG | FUTEX2_NUMA); } -static void test_futex_mpol(void *futex_ptr, int err_value) -{ - __test_futex(futex_ptr, err_value, FUTEX2_SIZE_U32 | FUTEX_PRIVATE_FLAG | FUTEX2_NUMA | FUTEX2_MPOL); -} - TEST(futex_numa_mpol) { struct futex32_numa *futex_numa; diff --git a/tools/testing/selftests/futex/functional/futex_wait.c b/tools/testing/selftests/futex/functional/futex_wait.c index 0e69c53524c1..7b8879409007 100644 --- a/tools/testing/selftests/futex/functional/futex_wait.c +++ b/tools/testing/selftests/futex/functional/futex_wait.c @@ -71,6 +71,8 @@ TEST(anon_page) /* Testing an anon page shared memory */ shm_id = shmget(IPC_PRIVATE, 4096, IPC_CREAT | 0666); if (shm_id < 0) { + if (errno == ENOSYS) + ksft_exit_skip("shmget syscall not supported\n"); perror("shmget"); exit(1); } @@ -108,14 +110,14 @@ TEST(file_backed) /* Testing a file backed shared memory */ fd = open(SHM_PATH, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); if (fd < 0) - ksft_exit_fail_msg("open"); + ksft_exit_fail_msg("open\n"); if (ftruncate(fd, sizeof(f_private))) - ksft_exit_fail_msg("ftruncate"); + ksft_exit_fail_msg("ftruncate\n"); shm = mmap(NULL, sizeof(f_private), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (shm == MAP_FAILED) - ksft_exit_fail_msg("mmap"); + ksft_exit_fail_msg("mmap\n"); memcpy(shm, &f_private, sizeof(f_private)); diff --git a/tools/testing/selftests/futex/functional/futex_waitv.c b/tools/testing/selftests/futex/functional/futex_waitv.c index d60876164d4b..b5ada9fdb26f 100644 --- a/tools/testing/selftests/futex/functional/futex_waitv.c +++ b/tools/testing/selftests/futex/functional/futex_waitv.c @@ -86,6 +86,8 @@ TEST(shared_waitv) int shm_id = shmget(IPC_PRIVATE, 4096, IPC_CREAT | 0666); if (shm_id < 0) { + if (errno == ENOSYS) + ksft_exit_skip("shmget syscall not supported\n"); perror("shmget"); exit(1); } diff --git a/tools/testing/selftests/futex/functional/robust_list.c b/tools/testing/selftests/futex/functional/robust_list.c new file mode 100644 index 000000000000..e7d1254e18ca --- /dev/null +++ b/tools/testing/selftests/futex/functional/robust_list.c @@ -0,0 +1,552 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2025 Igalia S.L. + * + * Robust list test by André Almeida <andrealmeid@igalia.com> + * + * The robust list uAPI allows userspace to create "robust" locks, in the sense + * that if the lock holder thread dies, the remaining threads that are waiting + * for the lock won't block forever, waiting for a lock that will never be + * released. + * + * This is achieve by userspace setting a list where a thread can enter all the + * locks (futexes) that it is holding. The robust list is a linked list, and + * userspace register the start of the list with the syscall set_robust_list(). + * If such thread eventually dies, the kernel will walk this list, waking up one + * thread waiting for each futex and marking the futex word with the flag + * FUTEX_OWNER_DIED. + * + * See also + * man set_robust_list + * Documententation/locking/robust-futex-ABI.rst + * Documententation/locking/robust-futexes.rst + */ + +#define _GNU_SOURCE + +#include "futextest.h" +#include "../../kselftest_harness.h" + +#include <errno.h> +#include <pthread.h> +#include <signal.h> +#include <stdatomic.h> +#include <stdbool.h> +#include <stddef.h> +#include <sys/mman.h> +#include <sys/wait.h> + +#define STACK_SIZE (1024 * 1024) + +#define FUTEX_TIMEOUT 3 + +#define SLEEP_US 100 + +static pthread_barrier_t barrier, barrier2; + +static int set_robust_list(struct robust_list_head *head, size_t len) +{ + return syscall(SYS_set_robust_list, head, len); +} + +static int get_robust_list(int pid, struct robust_list_head **head, size_t *len_ptr) +{ + return syscall(SYS_get_robust_list, pid, head, len_ptr); +} + +/* + * Basic lock struct, contains just the futex word and the robust list element + * Real implementations have also a *prev to easily walk in the list + */ +struct lock_struct { + _Atomic(unsigned int) futex; + struct robust_list list; +}; + +/* + * Helper function to spawn a child thread. Returns -1 on error, pid on success + */ +static int create_child(int (*fn)(void *arg), void *arg) +{ + char *stack; + pid_t pid; + + stack = mmap(NULL, STACK_SIZE, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0); + if (stack == MAP_FAILED) + return -1; + + stack += STACK_SIZE; + + pid = clone(fn, stack, CLONE_VM | SIGCHLD, arg); + + if (pid == -1) + return -1; + + return pid; +} + +/* + * Helper function to prepare and register a robust list + */ +static int set_list(struct robust_list_head *head) +{ + int ret; + + ret = set_robust_list(head, sizeof(*head)); + if (ret) + return ret; + + head->futex_offset = (size_t) offsetof(struct lock_struct, futex) - + (size_t) offsetof(struct lock_struct, list); + head->list.next = &head->list; + head->list_op_pending = NULL; + + return 0; +} + +/* + * A basic (and incomplete) mutex lock function with robustness + */ +static int mutex_lock(struct lock_struct *lock, struct robust_list_head *head, bool error_inject) +{ + _Atomic(unsigned int) *futex = &lock->futex; + unsigned int zero = 0; + pid_t tid = gettid(); + int ret = -1; + + /* + * Set list_op_pending before starting the lock, so the kernel can catch + * the case where the thread died during the lock operation + */ + head->list_op_pending = &lock->list; + + if (atomic_compare_exchange_strong(futex, &zero, tid)) { + /* + * We took the lock, insert it in the robust list + */ + struct robust_list *list = &head->list; + + /* Error injection to test list_op_pending */ + if (error_inject) + return 0; + + while (list->next != &head->list) + list = list->next; + + list->next = &lock->list; + lock->list.next = &head->list; + + ret = 0; + } else { + /* + * We didn't take the lock, wait until the owner wakes (or dies) + */ + struct timespec to; + + to.tv_sec = FUTEX_TIMEOUT; + to.tv_nsec = 0; + + tid = atomic_load(futex); + /* Kernel ignores futexes without the waiters flag */ + tid |= FUTEX_WAITERS; + atomic_store(futex, tid); + + ret = futex_wait((futex_t *) futex, tid, &to, 0); + + /* + * A real mutex_lock() implementation would loop here to finally + * take the lock. We don't care about that, so we stop here. + */ + } + + head->list_op_pending = NULL; + + return ret; +} + +/* + * This child thread will succeed taking the lock, and then will exit holding it + */ +static int child_fn_lock(void *arg) +{ + struct lock_struct *lock = arg; + struct robust_list_head head; + int ret; + + ret = set_list(&head); + if (ret) { + ksft_test_result_fail("set_robust_list error\n"); + return ret; + } + + ret = mutex_lock(lock, &head, false); + if (ret) { + ksft_test_result_fail("mutex_lock error\n"); + return ret; + } + + pthread_barrier_wait(&barrier); + + /* + * There's a race here: the parent thread needs to be inside + * futex_wait() before the child thread dies, otherwise it will miss the + * wakeup from handle_futex_death() that this child will emit. We wait a + * little bit just to make sure that this happens. + */ + usleep(SLEEP_US); + + return 0; +} + +/* + * Spawns a child thread that will set a robust list, take the lock, register it + * in the robust list and die. The parent thread will wait on this futex, and + * should be waken up when the child exits. + */ +TEST(test_robustness) +{ + struct lock_struct lock = { .futex = 0 }; + _Atomic(unsigned int) *futex = &lock.futex; + struct robust_list_head head; + int ret, pid, wstatus; + + ret = set_list(&head); + ASSERT_EQ(ret, 0); + + /* + * Lets use a barrier to ensure that the child thread takes the lock + * before the parent + */ + ret = pthread_barrier_init(&barrier, NULL, 2); + ASSERT_EQ(ret, 0); + + pid = create_child(&child_fn_lock, &lock); + ASSERT_NE(pid, -1); + + pthread_barrier_wait(&barrier); + ret = mutex_lock(&lock, &head, false); + + /* + * futex_wait() should return 0 and the futex word should be marked with + * FUTEX_OWNER_DIED + */ + ASSERT_EQ(ret, 0); + + ASSERT_TRUE(*futex & FUTEX_OWNER_DIED); + + wait(&wstatus); + pthread_barrier_destroy(&barrier); + + /* Pass only if the child hasn't return error */ + if (!WEXITSTATUS(wstatus)) + ksft_test_result_pass("%s\n", __func__); +} + +/* + * The only valid value for len is sizeof(*head) + */ +TEST(test_set_robust_list_invalid_size) +{ + struct robust_list_head head; + size_t head_size = sizeof(head); + int ret; + + ret = set_robust_list(&head, head_size); + ASSERT_EQ(ret, 0); + + ret = set_robust_list(&head, head_size * 2); + ASSERT_EQ(ret, -1); + ASSERT_EQ(errno, EINVAL); + + ret = set_robust_list(&head, head_size - 1); + ASSERT_EQ(ret, -1); + ASSERT_EQ(errno, EINVAL); + + ret = set_robust_list(&head, 0); + ASSERT_EQ(ret, -1); + ASSERT_EQ(errno, EINVAL); + + ksft_test_result_pass("%s\n", __func__); +} + +/* + * Test get_robust_list with pid = 0, getting the list of the running thread + */ +TEST(test_get_robust_list_self) +{ + struct robust_list_head head, head2, *get_head; + size_t head_size = sizeof(head), len_ptr; + int ret; + + ret = set_robust_list(&head, head_size); + ASSERT_EQ(ret, 0); + + ret = get_robust_list(0, &get_head, &len_ptr); + ASSERT_EQ(ret, 0); + ASSERT_EQ(get_head, &head); + ASSERT_EQ(head_size, len_ptr); + + ret = set_robust_list(&head2, head_size); + ASSERT_EQ(ret, 0); + + ret = get_robust_list(0, &get_head, &len_ptr); + ASSERT_EQ(ret, 0); + ASSERT_EQ(get_head, &head2); + ASSERT_EQ(head_size, len_ptr); + + ksft_test_result_pass("%s\n", __func__); +} + +static int child_list(void *arg) +{ + struct robust_list_head *head = arg; + int ret; + + ret = set_robust_list(head, sizeof(*head)); + if (ret) { + ksft_test_result_fail("set_robust_list error\n"); + return -1; + } + + /* + * After setting the list head, wait until the main thread can call + * get_robust_list() for this thread before exiting. + */ + pthread_barrier_wait(&barrier); + pthread_barrier_wait(&barrier2); + + return 0; +} + +/* + * Test get_robust_list from another thread. We use two barriers here to ensure + * that: + * 1) the child thread set the list before we try to get it from the + * parent + * 2) the child thread still alive when we try to get the list from it + */ +TEST(test_get_robust_list_child) +{ + struct robust_list_head head, *get_head; + int ret, wstatus; + size_t len_ptr; + pid_t tid; + + ret = pthread_barrier_init(&barrier, NULL, 2); + ret = pthread_barrier_init(&barrier2, NULL, 2); + ASSERT_EQ(ret, 0); + + tid = create_child(&child_list, &head); + ASSERT_NE(tid, -1); + + pthread_barrier_wait(&barrier); + + ret = get_robust_list(tid, &get_head, &len_ptr); + ASSERT_EQ(ret, 0); + ASSERT_EQ(&head, get_head); + + pthread_barrier_wait(&barrier2); + + wait(&wstatus); + pthread_barrier_destroy(&barrier); + pthread_barrier_destroy(&barrier2); + + /* Pass only if the child hasn't return error */ + if (!WEXITSTATUS(wstatus)) + ksft_test_result_pass("%s\n", __func__); +} + +static int child_fn_lock_with_error(void *arg) +{ + struct lock_struct *lock = arg; + struct robust_list_head head; + int ret; + + ret = set_list(&head); + if (ret) { + ksft_test_result_fail("set_robust_list error\n"); + return -1; + } + + ret = mutex_lock(lock, &head, true); + if (ret) { + ksft_test_result_fail("mutex_lock error\n"); + return -1; + } + + pthread_barrier_wait(&barrier); + + /* See comment at child_fn_lock() */ + usleep(SLEEP_US); + + return 0; +} + +/* + * Same as robustness test, but inject an error where the mutex_lock() exits + * earlier, just after setting list_op_pending and taking the lock, to test the + * list_op_pending mechanism + */ +TEST(test_set_list_op_pending) +{ + struct lock_struct lock = { .futex = 0 }; + _Atomic(unsigned int) *futex = &lock.futex; + struct robust_list_head head; + int ret, wstatus; + + ret = set_list(&head); + ASSERT_EQ(ret, 0); + + ret = pthread_barrier_init(&barrier, NULL, 2); + ASSERT_EQ(ret, 0); + + ret = create_child(&child_fn_lock_with_error, &lock); + ASSERT_NE(ret, -1); + + pthread_barrier_wait(&barrier); + ret = mutex_lock(&lock, &head, false); + + ASSERT_EQ(ret, 0); + + ASSERT_TRUE(*futex & FUTEX_OWNER_DIED); + + wait(&wstatus); + pthread_barrier_destroy(&barrier); + + /* Pass only if the child hasn't return error */ + if (!WEXITSTATUS(wstatus)) + ksft_test_result_pass("%s\n", __func__); + else + ksft_test_result_fail("%s\n", __func__); +} + +#define CHILD_NR 10 + +static int child_lock_holder(void *arg) +{ + struct lock_struct *locks = arg; + struct robust_list_head head; + int i; + + set_list(&head); + + for (i = 0; i < CHILD_NR; i++) { + locks[i].futex = 0; + mutex_lock(&locks[i], &head, false); + } + + pthread_barrier_wait(&barrier); + pthread_barrier_wait(&barrier2); + + /* See comment at child_fn_lock() */ + usleep(SLEEP_US); + + return 0; +} + +static int child_wait_lock(void *arg) +{ + struct lock_struct *lock = arg; + struct robust_list_head head; + int ret; + + pthread_barrier_wait(&barrier2); + ret = mutex_lock(lock, &head, false); + + if (ret) { + ksft_test_result_fail("mutex_lock error\n"); + return -1; + } + + if (!(lock->futex & FUTEX_OWNER_DIED)) { + ksft_test_result_fail("futex not marked with FUTEX_OWNER_DIED\n"); + return -1; + } + + return 0; +} + +/* + * Test a robust list of more than one element. All the waiters should wake when + * the holder dies + */ +TEST(test_robust_list_multiple_elements) +{ + struct lock_struct locks[CHILD_NR]; + pid_t pids[CHILD_NR + 1]; + int i, ret, wstatus; + + ret = pthread_barrier_init(&barrier, NULL, 2); + ASSERT_EQ(ret, 0); + ret = pthread_barrier_init(&barrier2, NULL, CHILD_NR + 1); + ASSERT_EQ(ret, 0); + + pids[0] = create_child(&child_lock_holder, &locks); + + /* Wait until the locker thread takes the look */ + pthread_barrier_wait(&barrier); + + for (i = 0; i < CHILD_NR; i++) + pids[i+1] = create_child(&child_wait_lock, &locks[i]); + + /* Wait for all children to return */ + ret = 0; + + for (i = 0; i < CHILD_NR; i++) { + waitpid(pids[i], &wstatus, 0); + if (WEXITSTATUS(wstatus)) + ret = -1; + } + + pthread_barrier_destroy(&barrier); + pthread_barrier_destroy(&barrier2); + + /* Pass only if the child hasn't return error */ + if (!ret) + ksft_test_result_pass("%s\n", __func__); +} + +static int child_circular_list(void *arg) +{ + static struct robust_list_head head; + struct lock_struct a, b, c; + int ret; + + ret = set_list(&head); + if (ret) { + ksft_test_result_fail("set_list error\n"); + return -1; + } + + head.list.next = &a.list; + + /* + * The last element should point to head list, but we short circuit it + */ + a.list.next = &b.list; + b.list.next = &c.list; + c.list.next = &a.list; + + return 0; +} + +/* + * Create a circular robust list. The kernel should be able to destroy the list + * while processing it so it won't be trapped in an infinite loop while handling + * a process exit + */ +TEST(test_circular_list) +{ + int wstatus; + + create_child(child_circular_list, NULL); + + wait(&wstatus); + + /* Pass only if the child hasn't return error */ + if (!WEXITSTATUS(wstatus)) + ksft_test_result_pass("%s\n", __func__); +} + +TEST_HARNESS_MAIN |
