diff options
269 files changed, 6086 insertions, 1535 deletions
diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt index 8a47b77abfca..e8c74a6e738b 100644 --- a/Documentation/devicetree/bindings/clock/sunxi.txt +++ b/Documentation/devicetree/bindings/clock/sunxi.txt @@ -18,6 +18,7 @@ Required properties: "allwinner,sun4i-a10-cpu-clk" - for the CPU multiplexer clock "allwinner,sun4i-a10-axi-clk" - for the AXI clock "allwinner,sun8i-a23-axi-clk" - for the AXI clock on A23 + "allwinner,sun4i-a10-gates-clk" - for generic gates on all compatible SoCs "allwinner,sun4i-a10-axi-gates-clk" - for the AXI gates "allwinner,sun4i-a10-ahb-clk" - for the AHB clock "allwinner,sun5i-a13-ahb-clk" - for the AHB clock on A13 @@ -43,6 +44,7 @@ Required properties: "allwinner,sun6i-a31-apb0-gates-clk" - for the APB0 gates on A31 "allwinner,sun7i-a20-apb0-gates-clk" - for the APB0 gates on A20 "allwinner,sun8i-a23-apb0-gates-clk" - for the APB0 gates on A23 + "allwinner,sun8i-h3-apb0-gates-clk" - for the APB0 gates on H3 "allwinner,sun9i-a80-apb0-gates-clk" - for the APB0 gates on A80 "allwinner,sun4i-a10-apb1-clk" - for the APB1 clock "allwinner,sun9i-a80-apb1-clk" - for the APB1 bus clock on A80 diff --git a/Documentation/devicetree/bindings/power/supply/qcom/smb138x-charger.txt b/Documentation/devicetree/bindings/power/supply/qcom/smb138x-charger.txt index 5529e30811fb..92ef23c3a290 100644 --- a/Documentation/devicetree/bindings/power/supply/qcom/smb138x-charger.txt +++ b/Documentation/devicetree/bindings/power/supply/qcom/smb138x-charger.txt @@ -22,8 +22,7 @@ Charger specific properties: Definition: String which indicates the charging mode. Can be one of the following: Standalone/Parallel Master - "qcom,smb138x-charger" - smb138x Parallel Slave - "qcom,smb138x-parallel-slave" - smb1355 Parallel Slave - "qcom,smb1355-parallel-slave", + Parallel Slave - "qcom,smb138x-parallel-slave" - qcom,pmic-revid Usage: required @@ -36,8 +35,7 @@ Charger specific properties: Usage: optional Value type: <u32> Definition: Specifies parallel charging mode. If not specified, MID-MID - option is selected by default. Note that smb1355 can only - run in MID-MID configuration. + option is selected by default. - qcom,suspend-input Usage: optional @@ -127,7 +125,7 @@ Example ======= smb138x_charger: qcom,smb138x-charger { - compatible = "qcom,smb138x-charger"; + compatible = "qcom,qpnp-smb138x-charger"; #address-cells = <1>; #size-cells = <1>; diff --git a/Documentation/devicetree/bindings/regulator/onsemi-ncp6335d.txt b/Documentation/devicetree/bindings/regulator/onsemi-ncp6335d.txt new file mode 100644 index 000000000000..7d492f5d7e25 --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/onsemi-ncp6335d.txt @@ -0,0 +1,72 @@ +ON Semiconductor NCP6335d regulator + +NCP6335d is able to deliver up to 5.0 A, with programmable output voltage from +0.6 V to 1.87 V in 10mV steps, with synchronous rectification and automatic PWM/ +PFM transitions, enable pins and power good/fail signaling. + +The NCP6335d interface is via I2C bus. + +Required Properties: +- compatible: Must be "onnn,ncp6335d-regulator". +- reg: The device 8-bit I2C address. +- regulator-min-microvolt: Minimum voltage in microvolts supported by this + regulator. +- regulator-max-microvolt: Maximum voltage in microvolts supported by this + regulator. +- onnn,min-setpoint: Minimum setpoint voltage in microvolts supported + by this regulator. +- onnn,step-size: The step size of the regulator, in uV. +- onnn,min-slew-ns: Minimum time in ns needed to change voltage by + one step size. This value corresponds to DVS + mode bit of 00b in command register. +- onnn,max-slew-ns: Maximum time in ns needed to change voltage by + one step size. This value corresponds to DVS + mode bit of 11b in command register. +- onnn,vsel: Working vsel register. Supported value are 0 + or 1. +- onnn,slew-ns: Time in ns needed to change voltage by one step + size. Supported value are 333, 666, 1333, 2666. + +Optional Properties: +- onnn,discharge-enable: Present: discharge enabled. + Not Present: discharge disabled. +- onnn,restore-reg: Present: Restore vsel register from backup register. + Not Present: No restore. +- onnn,vsel-gpio: Present: GPIO connects to the VSEL pin and set the + VSEL pin according to device tree flag. + Not Present: No GPIO is connected to vsel pin. +- pinctrl-names: The state name of the VSEL pin configuration. + Only support: "default" +- pinctrl-0: The phandles of the pin configuration node in + pinctrl for VSEL pin. + For details of pinctrl properties, please refer to: + "Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt" +- onnn,sleep-enable: Present: Forced in sleep mode when EN and VSEL + pins are low. + Not Present: Low quiescent current mode when EN and VSEL + pins are low. +- onnn,mode: A string which specifies the initial mode to use for the regulator. + Supported values are "pwm" and "auto". PWM mode is more + robust, but draws more current than auto mode. If this propery + is not specified, then the regulator will be in the hardware default mode. + +Example: + i2c_0 { + ncp6335d-regulator@1c { + compatible = "onnn,ncp6335d-regulator"; + reg = <0x1c>; + onnn,vsel = <0>; + onnn,slew-rate-ns = <2666>; + onnn,discharge-enable; + onnn,step-size = <10000>; + onnn,min-slew-ns = <333>; + onnn,max-slew-ns = <2666>; + pintrl-names = "default"; + pinctrl-0 = <&ext_buck_vsel_default>; + + regulator-min-microvolt = <1050000>; + regulator-max-microvolt = <1350000>; + onnn,min-setpoint = <600000>; + onnn,vsel-gpio = <&msmgpio 2 1>; + }; + }; diff --git a/Documentation/sysctl/fs.txt b/Documentation/sysctl/fs.txt index 302b5ed616a6..35e17f748ca7 100644 --- a/Documentation/sysctl/fs.txt +++ b/Documentation/sysctl/fs.txt @@ -265,6 +265,13 @@ aio-nr can grow to. ============================================================== +mount-max: + +This denotes the maximum number of mounts that may exist +in a mount namespace. + +============================================================== + 2. /proc/sys/fs/binfmt_misc ---------------------------------------------------------- @@ -1,6 +1,6 @@ VERSION = 4 PATCHLEVEL = 4 -SUBLEVEL = 63 +SUBLEVEL = 66 EXTRAVERSION = NAME = Blurry Fish Butt diff --git a/arch/arc/include/asm/entry-arcv2.h b/arch/arc/include/asm/entry-arcv2.h index b5ff87e6f4b7..aee1a77934cf 100644 --- a/arch/arc/include/asm/entry-arcv2.h +++ b/arch/arc/include/asm/entry-arcv2.h @@ -16,6 +16,7 @@ ; ; Now manually save: r12, sp, fp, gp, r25 + PUSH r30 PUSH r12 ; Saving pt_regs->sp correctly requires some extra work due to the way @@ -72,6 +73,7 @@ POPAX AUX_USER_SP 1: POP r12 + POP r30 .endm diff --git a/arch/arc/include/asm/ptrace.h b/arch/arc/include/asm/ptrace.h index 69095da1fcfd..47111d565a95 100644 --- a/arch/arc/include/asm/ptrace.h +++ b/arch/arc/include/asm/ptrace.h @@ -84,7 +84,7 @@ struct pt_regs { unsigned long fp; unsigned long sp; /* user/kernel sp depending on where we came from */ - unsigned long r12; + unsigned long r12, r30; /*------- Below list auto saved by h/w -----------*/ unsigned long r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11; diff --git a/arch/arm/boot/dts/qcom/msm-pm660l.dtsi b/arch/arm/boot/dts/qcom/msm-pm660l.dtsi index 679149a78833..0f18ba5c94c7 100644 --- a/arch/arm/boot/dts/qcom/msm-pm660l.dtsi +++ b/arch/arm/boot/dts/qcom/msm-pm660l.dtsi @@ -380,9 +380,6 @@ qcom,led-name = "led:switch_1"; qcom,led-mask = <4>; qcom,default-led-trigger = "switch1_trigger"; - pinctrl-names = "led_enable","led_disable"; - pinctrl-0 = <&led_enable>; - pinctrl-1 = <&led_disable>; }; }; diff --git a/arch/arm/boot/dts/qcom/msm-pmi8998.dtsi b/arch/arm/boot/dts/qcom/msm-pmi8998.dtsi index 2d2b628ca815..ad32ab01c5fb 100644 --- a/arch/arm/boot/dts/qcom/msm-pmi8998.dtsi +++ b/arch/arm/boot/dts/qcom/msm-pmi8998.dtsi @@ -762,9 +762,6 @@ qcom,led-name = "led:switch_1"; qcom,led-mask = <4>; qcom,default-led-trigger = "switch1_trigger"; - pinctrl-names = "led_enable","led_disable"; - pinctrl-0 = <&led_enable>; - pinctrl-1 = <&led_disable>; }; }; }; diff --git a/arch/arm/boot/dts/qcom/msm8996-regulator.dtsi b/arch/arm/boot/dts/qcom/msm8996-regulator.dtsi index c70003a0a6dd..b86542a174da 100644 --- a/arch/arm/boot/dts/qcom/msm8996-regulator.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996-regulator.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2016, 2017 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1950,4 +1950,21 @@ regulator-ramp-delay = <500>; status = "disabled"; }; + + ncp6335d_vreg: ncp6335d-regulator@68 { + compatible = "onnn,ncp6335d-regulator"; + reg = <0x68>; + vin-supply = <&hl7509_en_vreg>; + onnn,vsel = <0>; + onnn,slew-ns = <2666>; + onnn,step-size = <6250>; + onnn,min-slew-ns = <333>; + onnn,max-slew-ns = <2666>; + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <1143750>; + onnn,min-setpoint = <600000>; + onnn,discharge-enable; + onnn,restore-reg; + status = "disabled"; + }; }; diff --git a/arch/arm/boot/dts/qcom/msm8996pro.dtsi b/arch/arm/boot/dts/qcom/msm8996pro.dtsi index 2f29fabb7d7e..ca89a517df5c 100644 --- a/arch/arm/boot/dts/qcom/msm8996pro.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996pro.dtsi @@ -1505,5 +1505,62 @@ qcom,bus-max = <0>; }; }; + + qcom,gpu-pwrlevels-2 { + #address-cells = <1>; + #size-cells = <0>; + + qcom,speed-bin = <2>; + + qcom,initial-pwrlevel = <3>; + + qcom,gpu-pwrlevel@0 { + reg = <0>; + qcom,gpu-freq = <510000000>; + qcom,bus-freq = <11>; + qcom,bus-min = <11>; + qcom,bus-max = <11>; + }; + + qcom,gpu-pwrlevel@1 { + reg = <1>; + qcom,gpu-freq = <401800000>; + qcom,bus-freq = <8>; + qcom,bus-min = <7>; + qcom,bus-max = <9>; + }; + + qcom,gpu-pwrlevel@2 { + reg = <2>; + qcom,gpu-freq = <315000000>; + qcom,bus-freq = <6>; + qcom,bus-min = <5>; + qcom,bus-max = <7>; + }; + + qcom,gpu-pwrlevel@3 { + reg = <3>; + qcom,gpu-freq = <214000000>; + qcom,bus-freq = <4>; + qcom,bus-min = <3>; + qcom,bus-max = <5>; + }; + + qcom,gpu-pwrlevel@4 { + reg = <4>; + qcom,gpu-freq = <133000000>; + qcom,bus-freq = <3>; + qcom,bus-min = <2>; + qcom,bus-max = <4>; + }; + + qcom,gpu-pwrlevel@5 { + reg = <5>; + qcom,gpu-freq = <27000000>; + qcom,bus-freq = <0>; + qcom,bus-min = <0>; + qcom,bus-max = <0>; + }; + }; }; }; diff --git a/arch/arm/boot/dts/qcom/msm8998-camera-sensor-mtp.dtsi b/arch/arm/boot/dts/qcom/msm8998-camera-sensor-mtp.dtsi index d7372f2bb2e4..2095b4e07069 100644 --- a/arch/arm/boot/dts/qcom/msm8998-camera-sensor-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-camera-sensor-mtp.dtsi @@ -334,19 +334,22 @@ qcom,gpio-no-mux = <0>; pinctrl-names = "cam_default", "cam_suspend"; pinctrl-0 = <&cam_sensor_mclk1_active - &cam_sensor_front_active>; + &cam_sensor_front_active &led_enable>; pinctrl-1 = <&cam_sensor_mclk1_suspend - &cam_sensor_front_suspend>; + &cam_sensor_front_suspend &led_disable>; gpios = <&tlmm 14 0>, <&tlmm 28 0>, - <&pm8998_gpios 9 0>; + <&pm8998_gpios 9 0>, + <&tlmm 21 0>; qcom,gpio-reset = <1>; qcom,gpio-vdig = <2>; - qcom,gpio-req-tbl-num = <0 1 2>; - qcom,gpio-req-tbl-flags = <1 0 0>; + qcom,gpio-flash-en = <3>; + qcom,gpio-req-tbl-num = <0 1 2 3>; + qcom,gpio-req-tbl-flags = <1 0 0 0>; qcom,gpio-req-tbl-label = "CAMIF_MCLK2", "CAM_RESET2", - "CAM_VDIG"; + "CAM_VDIG", + "FLASH_EN"; qcom,sensor-position = <1>; qcom,sensor-mode = <0>; qcom,cci-master = <1>; @@ -356,6 +359,45 @@ clock-names = "cam_src_clk", "cam_clk"; qcom,clock-rates = <24000000 0>; }; + + qcom,camera@3 { + cell-index = <3>; + compatible = "qcom,camera"; + reg = <0x03>; + qcom,csiphy-sd-index = <1>; + qcom,csid-sd-index = <1>; + qcom,mount-angle = <270>; + qcom,led-flash-src = <&led_flash1>; + cam_vio-supply = <&pm8998_lvs1>; + cam_vana-supply = <&pm8998_l22>; + cam_vdig-supply = <&pm8998_s3>; + qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig"; + qcom,cam-vreg-min-voltage = + <0 2864000 1352000>; + qcom,cam-vreg-max-voltage = + <0 2864000 1352000>; + qcom,cam-vreg-op-mode = <0 80000 105000>; + qcom,gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk3_active + &cam_sensor_front_iris_active>; + pinctrl-1 = <&cam_sensor_mclk3_suspend + &cam_sensor_front_iris_suspend>; + gpios = <&tlmm 16 0>, + <&tlmm 23 0>; + qcom,gpio-reset = <1>; + qcom,gpio-req-tbl-num = <0 1>; + qcom,gpio-req-tbl-flags = <1 0>; + qcom,gpio-req-tbl-label = "CAMIF_MCLK3", + "CAM_RESET3"; + qcom,sensor-position = <1>; + qcom,sensor-mode = <0>; + qcom,cci-master = <1>; + clocks = <&clock_mmss clk_mclk3_clk_src>, + <&clock_mmss clk_mmss_camss_mclk3_clk>; + clock-names = "cam_src_clk", "cam_clk"; + qcom,clock-rates = <24000000 0>; + }; }; &pm8998_gpios { gpio@c800 { /* GPIO 9 - CAMERA SENSOR 2 VDIG */ diff --git a/arch/arm/boot/dts/qcom/msm8998-interposer-camera-sensor-mtp.dtsi b/arch/arm/boot/dts/qcom/msm8998-interposer-camera-sensor-mtp.dtsi index 722c18a26388..d00ae0f3730c 100644 --- a/arch/arm/boot/dts/qcom/msm8998-interposer-camera-sensor-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-interposer-camera-sensor-mtp.dtsi @@ -12,6 +12,12 @@ */ &soc { + /delete-node/qcom,camera-flash@0; + /delete-node/qcom,camera-flash@1; + /delete-node/gpio-regulator@0; +}; + +&soc { tlmm: pinctrl@03400000 { cam_sensor_rear_active: cam_sensor_rear_active { /* RESET, STANDBY */ @@ -132,19 +138,17 @@ }; }; -&soc { - /delete-node/gpio-regulator@0; -}; - &cci { /delete-node/qcom,camera@0; /delete-node/qcom,camera@1; /delete-node/qcom,camera@2; + /delete-node/qcom,camera@3; /delete-node/qcom,eeprom@0; /delete-node/qcom,eeprom@1; /delete-node/qcom,eeprom@2; /delete-node/qcom,actuator@0; /delete-node/qcom,actuator@1; + /delete-node/qcom,tof@0; /delete-node/qcom,ois@0; }; diff --git a/arch/arm/boot/dts/qcom/msm8998-interposer-camera-sensor-qrd.dtsi b/arch/arm/boot/dts/qcom/msm8998-interposer-camera-sensor-qrd.dtsi index 8b68ece2239f..42414db3cc48 100644 --- a/arch/arm/boot/dts/qcom/msm8998-interposer-camera-sensor-qrd.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-interposer-camera-sensor-qrd.dtsi @@ -12,6 +12,12 @@ */ &soc { + /delete-node/qcom,camera-flash@0; + /delete-node/qcom,camera-flash@1; + /delete-node/gpio-regulator@0; +}; + +&soc { tlmm: pinctrl@03400000 { cam_sensor_rear_active: cam_sensor_rear_active { /* RESET, STANDBY */ @@ -170,19 +176,17 @@ }; }; -&soc { - /delete-node/gpio-regulator@0; -}; - &cci { /delete-node/qcom,camera@0; /delete-node/qcom,camera@1; /delete-node/qcom,camera@2; + /delete-node/qcom,camera@3; /delete-node/qcom,eeprom@0; /delete-node/qcom,eeprom@1; /delete-node/qcom,eeprom@2; /delete-node/qcom,actuator@0; /delete-node/qcom,actuator@1; + /delete-node/qcom,tof@0; /delete-node/qcom,ois@0; }; diff --git a/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi b/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi index cdf4bede6eb3..318dc5d7c791 100644 --- a/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi @@ -996,7 +996,7 @@ cam_sensor_mclk0_active: cam_sensor_mclk0_active { /* MCLK0 */ mux { - /* CLK, DATA */ + /* CLK */ pins = "gpio13"; function = "cam_mclk"; }; @@ -1011,7 +1011,7 @@ cam_sensor_mclk0_suspend: cam_sensor_mclk0_suspend { /* MCLK0 */ mux { - /* CLK, DATA */ + /* CLK */ pins = "gpio13"; function = "cam_mclk"; }; @@ -1305,7 +1305,7 @@ cam_sensor_mclk1_active: cam_sensor_mclk1_active { /* MCLK1 */ mux { - /* CLK, DATA */ + /* CLK */ pins = "gpio14"; function = "cam_mclk"; }; @@ -1320,7 +1320,7 @@ cam_sensor_mclk1_suspend: cam_sensor_mclk1_suspend { /* MCLK1 */ mux { - /* CLK, DATA */ + /* CLK */ pins = "gpio14"; function = "cam_mclk"; }; @@ -1332,6 +1332,36 @@ }; }; + cam_sensor_mclk3_active: cam_sensor_mclk3_active { + /* MCLK3 */ + mux { + /* CLK */ + pins = "gpio16"; + function = "cam_mclk"; + }; + + config { + pins = "gpio16"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk3_suspend: cam_sensor_mclk3_suspend { + /* MCLK3 */ + mux { + /* CLK */ + pins = "gpio16"; + function = "cam_mclk"; + }; + + config { + pins = "gpio16"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + cam_sensor_rear2_active: cam_sensor_rear2_active { /* RESET, STANDBY */ mux { @@ -1468,7 +1498,7 @@ cam_sensor_mclk2_active: cam_sensor_mclk2_active { /* MCLK1 */ mux { - /* CLK, DATA */ + /* CLK */ pins = "gpio15"; function = "cam_mclk"; }; @@ -1483,7 +1513,7 @@ cam_sensor_mclk2_suspend: cam_sensor_mclk2_suspend { /* MCLK1 */ mux { - /* CLK, DATA */ + /* CLK */ pins = "gpio15"; function = "cam_mclk"; }; @@ -1509,6 +1539,21 @@ }; }; + + cam_sensor_front_iris_active: cam_sensor_front_iris_active { + /* RESET */ + mux { + pins = "gpio23"; + function = "gpio"; + }; + + config { + pins = "gpio23"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + blsp2_uart1_active: blsp2_uart1_active { mux { pins = "gpio53", "gpio54", "gpio55", "gpio56"; @@ -1575,6 +1620,20 @@ }; }; + cam_sensor_front_iris_suspend: cam_sensor_front_iris_suspend { + /* RESET */ + mux { + pins = "gpio23"; + function = "gpio"; + }; + + config { + pins = "gpio23"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + pmx_mdss: pmx_mdss { mdss_dsi_active: mdss_dsi_active { mux { diff --git a/arch/arm/boot/dts/qcom/msm8998.dtsi b/arch/arm/boot/dts/qcom/msm8998.dtsi index c25f3ebcb113..c1d785e42669 100644 --- a/arch/arm/boot/dts/qcom/msm8998.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998.dtsi @@ -3200,6 +3200,10 @@ <&clock_gcc clk_rf_clk3_pin>; clock-names = "rf_clk3_clk", "rf_clk3_pin_clk"; qcom,smmu-support; + qcom,smmu-s1-en; + qcom,smmu-fast-map; + qcom,smmu-coherent; + qcom,smmu-mapping = <0x20000000 0xe0000000>; status = "disabled"; }; diff --git a/arch/arm/boot/dts/qcom/sdm630-mdss.dtsi b/arch/arm/boot/dts/qcom/sdm630-mdss.dtsi index d35704224f45..49e4fd7e5ba7 100644 --- a/arch/arm/boot/dts/qcom/sdm630-mdss.dtsi +++ b/arch/arm/boot/dts/qcom/sdm630-mdss.dtsi @@ -112,13 +112,14 @@ clocks = <&clock_mmss MMSS_MNOC_AHB_CLK>, <&clock_mmss MMSS_MDSS_AHB_CLK>, <&clock_mmss MMSS_MDSS_AXI_CLK>, + <&clock_mmss MMSS_THROTTLE_MDSS_AXI_CLK>, <&clock_mmss MDP_CLK_SRC>, <&clock_mmss MMSS_MDSS_MDP_CLK>, <&clock_mmss MMSS_MDSS_VSYNC_CLK>, <&clock_mmss MDP_CLK_SRC>; clock-names = "mnoc_clk", "iface_clk", "bus_clk", - "core_clk_src", "core_clk", "vsync_clk", - "lut_clk"; + "throttle_bus_clk", "core_clk_src", + "core_clk", "vsync_clk", "lut_clk"; qcom,mdp-settings = <0x01190 0x00000000>, <0x012ac 0xc0000ccc>, diff --git a/arch/arm/boot/dts/qcom/sdm630-qrd.dtsi b/arch/arm/boot/dts/qcom/sdm630-qrd.dtsi index c677df529dd7..5fac5ce2abe2 100644 --- a/arch/arm/boot/dts/qcom/sdm630-qrd.dtsi +++ b/arch/arm/boot/dts/qcom/sdm630-qrd.dtsi @@ -159,6 +159,7 @@ &pm660_fg { qcom,battery-data = <&qrd_batterydata>; qcom,fg-jeita-thresholds = <0 5 55 55>; + qcom,battery-thermal-coefficients = [9d 50 ff]; }; &uartblsp1dm1 { diff --git a/arch/arm/boot/dts/qcom/sdm660-camera-sensor-mtp.dtsi b/arch/arm/boot/dts/qcom/sdm660-camera-sensor-mtp.dtsi index 191beaa4d53b..3d37d169a97c 100644 --- a/arch/arm/boot/dts/qcom/sdm660-camera-sensor-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-camera-sensor-mtp.dtsi @@ -29,6 +29,36 @@ qcom,switch-source = <&pm660l_switch1>; status = "ok"; }; + + cam_avdd_gpio_regulator: cam_avdd_fixed_regulator { + compatible = "regulator-fixed"; + regulator-name = "cam_avdd_gpio_regulator"; + regulator-min-microvolt = <3600000>; + regulator-max-microvolt = <3600000>; + enable-active-high; + gpio = <&tlmm 51 0>; + vin-supply = <&pm660l_bob>; + }; + + cam_dvdd_gpio_regulator: cam_dvdd_fixed_regulator { + compatible = "regulator-fixed"; + regulator-name = "cam_dvdd_gpio_regulator"; + regulator-min-microvolt = <1350000>; + regulator-max-microvolt = <1350000>; + enable-active-high; + gpio = <&pm660l_gpios 3 0>; + vin-supply = <&pm660_s5>; + }; + + cam_rear_dvdd_gpio_regulator: cam_rear_dvdd_fixed_regulator { + compatible = "regulator-fixed"; + regulator-name = "cam_rear_dvdd_gpio_regulator"; + regulator-min-microvolt = <1350000>; + regulator-max-microvolt = <1350000>; + enable-active-high; + gpio = <&pm660l_gpios 4 0>; + vin-supply = <&pm660_s5>; + }; }; &cci { @@ -98,12 +128,12 @@ reg = <0>; compatible = "qcom,eeprom"; cam_vio-supply = <&pm660_l11>; - cam_vana-supply = <&pm660l_bob>; - cam_vdig-supply = <&pm660_s5>; + cam_vana-supply = <&cam_avdd_gpio_regulator>; + cam_vdig-supply = <&cam_rear_dvdd_gpio_regulator>; qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig"; - qcom,cam-vreg-min-voltage = <1780000 3300000 1350000>; - qcom,cam-vreg-max-voltage = <1950000 3600000 1350000>; - qcom,cam-vreg-op-mode = <105000 80000 105000>; + qcom,cam-vreg-min-voltage = <1780000 0 0>; + qcom,cam-vreg-max-voltage = <1950000 0 0>; + qcom,cam-vreg-op-mode = <105000 0 0>; qcom,gpio-no-mux = <0>; pinctrl-names = "cam_default", "cam_suspend"; pinctrl-0 = <&cam_sensor_mclk0_active @@ -114,19 +144,13 @@ &cam_actuator_vaf_suspend>; gpios = <&tlmm 32 0>, <&tlmm 46 0>, - <&pm660l_gpios 4 0>, - <&tlmm 51 0>, <&tlmm 50 0>; qcom,gpio-reset = <1>; - qcom,gpio-vdig = <2>; - qcom,gpio-vana = <3>; - qcom,gpio-vaf = <4>; - qcom,gpio-req-tbl-num = <0 1 2 3 4>; - qcom,gpio-req-tbl-flags = <1 0 0 0 0>; + qcom,gpio-vaf = <2>; + qcom,gpio-req-tbl-num = <0 1 2>; + qcom,gpio-req-tbl-flags = <1 0 0>; qcom,gpio-req-tbl-label = "CAMIF_MCLK0", "CAM_RESET0", - "CAM_VDIG", - "CAM_VANA", "CAM_VAF"; qcom,sensor-position = <0>; qcom,sensor-mode = <0>; @@ -143,12 +167,12 @@ reg = <0x1>; compatible = "qcom,eeprom"; cam_vio-supply = <&pm660_l11>; - cam_vana-supply = <&pm660l_bob>; - cam_vdig-supply = <&pm660_s5>; + cam_vana-supply = <&cam_avdd_gpio_regulator>; + cam_vdig-supply = <&cam_dvdd_gpio_regulator>; qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig"; - qcom,cam-vreg-min-voltage = <1780000 3300000 1350000>; - qcom,cam-vreg-max-voltage = <1950000 3600000 1350000>; - qcom,cam-vreg-op-mode = <105000 80000 105000>; + qcom,cam-vreg-min-voltage = <1780000 0 0>; + qcom,cam-vreg-max-voltage = <1950000 0 0>; + qcom,cam-vreg-op-mode = <105000 0 0>; qcom,gpio-no-mux = <0>; pinctrl-names = "cam_default", "cam_suspend"; pinctrl-0 = <&cam_sensor_mclk2_active @@ -156,18 +180,12 @@ pinctrl-1 = <&cam_sensor_mclk2_suspend &cam_sensor_rear2_suspend>; gpios = <&tlmm 34 0>, - <&tlmm 48 0>, - <&pm660l_gpios 3 0>, - <&tlmm 51 0>; + <&tlmm 48 0>; qcom,gpio-reset = <1>; - qcom,gpio-vdig = <2>; - qcom,gpio-vana = <3>; - qcom,gpio-req-tbl-num = <0 1 2 3>; - qcom,gpio-req-tbl-flags = <1 0 0 0>; + qcom,gpio-req-tbl-num = <0 1>; + qcom,gpio-req-tbl-flags = <1 0>; qcom,gpio-req-tbl-label = "CAMIF_MCLK", - "CAM_RESET", - "CAM_VDIG", - "CAM_VANA"; + "CAM_RESET"; qcom,sensor-position = <0>; qcom,sensor-mode = <0>; qcom,cci-master = <1>; @@ -184,11 +202,11 @@ compatible = "qcom,eeprom"; cam_vio-supply = <&pm660_l11>; cam_vana-supply = <&pm660l_bob>; - cam_vdig-supply = <&pm660_s5>; + cam_vdig-supply = <&cam_dvdd_gpio_regulator>; qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig"; - qcom,cam-vreg-min-voltage = <1780000 3300000 1350000>; - qcom,cam-vreg-max-voltage = <1950000 3600000 1350000>; - qcom,cam-vreg-op-mode = <105000 80000 105000>; + qcom,cam-vreg-min-voltage = <1780000 3300000 0>; + qcom,cam-vreg-max-voltage = <1950000 3600000 0>; + qcom,cam-vreg-op-mode = <105000 80000 0>; qcom,gpio-no-mux = <0>; pinctrl-names = "cam_default", "cam_suspend"; pinctrl-0 = <&cam_sensor_mclk1_active @@ -199,18 +217,15 @@ &cam_actuator_vaf_suspend>; gpios = <&tlmm 33 0>, <&tlmm 47 0>, - <&pm660_gpios 3 0>, <&tlmm 44 0>, <&tlmm 50 0>; qcom,gpio-reset = <1>; - qcom,gpio-vdig = <2>; - qcom,gpio-vana = <3>; - qcom,gpio-vaf = <4>; - qcom,gpio-req-tbl-num = <0 1 2 3 4>; - qcom,gpio-req-tbl-flags = <1 0 0 0 0>; + qcom,gpio-vana = <2>; + qcom,gpio-vaf = <3>; + qcom,gpio-req-tbl-num = <0 1 2 3>; + qcom,gpio-req-tbl-flags = <1 0 0 0>; qcom,gpio-req-tbl-label = "CAMIF_MCLK2", "CAM_RESET2", - "CAM_VDIG", "CAM_VANA", "CAM_VAF"; qcom,sensor-position = <1>; @@ -235,12 +250,12 @@ qcom,ois-src = <&ois0>; qcom,eeprom-src = <&eeprom0>; cam_vio-supply = <&pm660_l11>; - cam_vana-supply = <&pm660l_bob>; - cam_vdig-supply = <&pm660_s5>; + cam_vana-supply = <&cam_avdd_gpio_regulator>; + cam_vdig-supply = <&cam_rear_dvdd_gpio_regulator>; qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig"; - qcom,cam-vreg-min-voltage = <1780000 3300000 1350000>; - qcom,cam-vreg-max-voltage = <1950000 3600000 1350000>; - qcom,cam-vreg-op-mode = <105000 80000 105000>; + qcom,cam-vreg-min-voltage = <1780000 0 0>; + qcom,cam-vreg-max-voltage = <1950000 0 0>; + qcom,cam-vreg-op-mode = <105000 0 0>; qcom,gpio-no-mux = <0>; pinctrl-names = "cam_default", "cam_suspend"; pinctrl-0 = <&cam_sensor_mclk0_active @@ -248,18 +263,12 @@ pinctrl-1 = <&cam_sensor_mclk0_suspend &cam_sensor_rear_suspend>; gpios = <&tlmm 32 0>, - <&tlmm 46 0>, - <&pm660l_gpios 4 0>, - <&tlmm 51 0>; + <&tlmm 46 0>; qcom,gpio-reset = <1>; - qcom,gpio-vdig = <2>; - qcom,gpio-vana = <3>; - qcom,gpio-req-tbl-num = <0 1 2 3>; - qcom,gpio-req-tbl-flags = <1 0 0 0>; + qcom,gpio-req-tbl-num = <0 1>; + qcom,gpio-req-tbl-flags = <1 0>; qcom,gpio-req-tbl-label = "CAMIF_MCLK0", - "CAM_RESET0", - "CAM_VDIG", - "CAM_VANA"; + "CAM_RESET0"; qcom,sensor-position = <0>; qcom,sensor-mode = <0>; qcom,cci-master = <0>; @@ -280,12 +289,12 @@ qcom,actuator-src = <&actuator1>; qcom,eeprom-src = <&eeprom1>; cam_vio-supply = <&pm660_l11>; - cam_vana-supply = <&pm660l_bob>; - cam_vdig-supply = <&pm660_s5>; + cam_vana-supply = <&cam_avdd_gpio_regulator>; + cam_vdig-supply = <&cam_dvdd_gpio_regulator>; qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig"; - qcom,cam-vreg-min-voltage = <1780000 3300000 1350000>; - qcom,cam-vreg-max-voltage = <1950000 3600000 1350000>; - qcom,cam-vreg-op-mode = <105000 80000 105000>; + qcom,cam-vreg-min-voltage = <1780000 0 0>; + qcom,cam-vreg-max-voltage = <1950000 0 0>; + qcom,cam-vreg-op-mode = <105000 0 0>; qcom,gpio-no-mux = <0>; pinctrl-names = "cam_default", "cam_suspend"; pinctrl-0 = <&cam_sensor_mclk2_active @@ -293,18 +302,12 @@ pinctrl-1 = <&cam_sensor_mclk2_suspend &cam_sensor_rear2_suspend>; gpios = <&tlmm 34 0>, - <&tlmm 48 0>, - <&pm660l_gpios 3 0>, - <&tlmm 51 0>; + <&tlmm 48 0>; qcom,gpio-reset = <1>; - qcom,gpio-vdig = <2>; - qcom,gpio-vana = <3>; - qcom,gpio-req-tbl-num = <0 1 2 3>; - qcom,gpio-req-tbl-flags = <1 0 0 0>; + qcom,gpio-req-tbl-num = <0 1>; + qcom,gpio-req-tbl-flags = <1 0>; qcom,gpio-req-tbl-label = "CAMIF_MCLK", - "CAM_RESET", - "CAM_VDIG", - "CAM_VANA"; + "CAM_RESET"; qcom,sensor-position = <0>; qcom,sensor-mode = <0>; qcom,cci-master = <1>; @@ -325,12 +328,12 @@ qcom,actuator-src = <&actuator2>; qcom,eeprom-src = <&eeprom2>; cam_vio-supply = <&pm660_l11>; - cam_vana-supply = <&pm660l_bob>; - cam_vdig-supply = <&pm660_s5>; + cam_vana-supply = <&cam_avdd_gpio_regulator>; + cam_vdig-supply = <&cam_dvdd_gpio_regulator>; qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig"; - qcom,cam-vreg-min-voltage = <1780000 3300000 1350000>; - qcom,cam-vreg-max-voltage = <1950000 3600000 1350000>; - qcom,cam-vreg-op-mode = <105000 80000 105000>; + qcom,cam-vreg-min-voltage = <1780000 0 0>; + qcom,cam-vreg-max-voltage = <1950000 0 0>; + qcom,cam-vreg-op-mode = <105000 0 0>; qcom,gpio-no-mux = <0>; pinctrl-names = "cam_default", "cam_suspend"; pinctrl-0 = <&cam_sensor_mclk1_active @@ -338,18 +341,12 @@ pinctrl-1 = <&cam_sensor_mclk1_suspend &cam_sensor_front_suspend>; gpios = <&tlmm 33 0>, - <&tlmm 47 0>, - <&pm660l_gpios 3 0>, - <&tlmm 51 0>; + <&tlmm 47 0>; qcom,gpio-reset = <1>; - qcom,gpio-vdig = <2>; - qcom,gpio-vana = <3>; - qcom,gpio-req-tbl-num = <0 1 2 3>; - qcom,gpio-req-tbl-flags = <1 0 0 0>; + qcom,gpio-req-tbl-num = <0 1>; + qcom,gpio-req-tbl-flags = <1 0>; qcom,gpio-req-tbl-label = "CAMIF_MCLK2", - "CAM_RESET2", - "CAM_VDIG", - "CAM_VANA"; + "CAM_RESET2"; qcom,sensor-position = <1>; qcom,sensor-mode = <0>; qcom,cci-master = <1>; @@ -359,6 +356,45 @@ clock-names = "cam_src_clk", "cam_clk"; qcom,clock-rates = <24000000 0>; }; + + qcom,camera@3 { + cell-index = <3>; + compatible = "qcom,camera"; + reg = <0x03>; + qcom,csiphy-sd-index = <1>; + qcom,csid-sd-index = <1>; + qcom,mount-angle = <90>; + qcom,led-flash-src = <&led_flash1>; + qcom,actuator-src = <&actuator2>; + qcom,eeprom-src = <&eeprom2>; + cam_vio-supply = <&pm660_l11>; + cam_vana-supply = <&cam_avdd_gpio_regulator>; + cam_vdig-supply = <&cam_dvdd_gpio_regulator>; + qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig"; + qcom,cam-vreg-min-voltage = <1780000 0 0>; + qcom,cam-vreg-max-voltage = <1950000 0 0>; + qcom,cam-vreg-op-mode = <105000 0 0>; + qcom,gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk3_active + &cam_sensor_front_iris_active>; + pinctrl-1 = <&cam_sensor_mclk3_suspend + &cam_sensor_front_iris_suspend>; + gpios = <&tlmm 35 0>, + <&tlmm 52 0>; + qcom,gpio-reset = <1>; + qcom,gpio-req-tbl-num = <0 1>; + qcom,gpio-req-tbl-flags = <1 0>; + qcom,gpio-req-tbl-label = "CAMIF_MCLK3", + "CAM_RESET3"; + qcom,sensor-position = <1>; + qcom,sensor-mode = <0>; + qcom,cci-master = <1>; + clocks = <&clock_mmss MCLK3_CLK_SRC>, + <&clock_mmss MMSS_CAMSS_MCLK3_CLK>; + clock-names = "cam_src_clk", "cam_clk"; + qcom,clock-rates = <24000000 0>; + }; }; &pm660l_gpios { diff --git a/arch/arm/boot/dts/qcom/sdm660-mdss.dtsi b/arch/arm/boot/dts/qcom/sdm660-mdss.dtsi index 787c4f1e2fb6..ab4e71e3cd65 100644 --- a/arch/arm/boot/dts/qcom/sdm660-mdss.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-mdss.dtsi @@ -117,13 +117,14 @@ clocks = <&clock_mmss MMSS_MNOC_AHB_CLK>, <&clock_mmss MMSS_MDSS_AHB_CLK>, <&clock_mmss MMSS_MDSS_AXI_CLK>, + <&clock_mmss MMSS_THROTTLE_MDSS_AXI_CLK>, <&clock_mmss MDP_CLK_SRC>, <&clock_mmss MMSS_MDSS_MDP_CLK>, <&clock_mmss MMSS_MDSS_VSYNC_CLK>, <&clock_mmss MDP_CLK_SRC>; clock-names = "mnoc_clk", "iface_clk", "bus_clk", - "core_clk_src", "core_clk", "vsync_clk", - "lut_clk"; + "throttle_bus_clk", "core_clk_src", + "core_clk", "vsync_clk", "lut_clk"; qcom,mdp-settings = <0x01190 0x00000000>, <0x012ac 0xc0000ccc>, diff --git a/arch/arm/boot/dts/qcom/sdm660-pinctrl.dtsi b/arch/arm/boot/dts/qcom/sdm660-pinctrl.dtsi index efe58563a1f3..d902078b1048 100644 --- a/arch/arm/boot/dts/qcom/sdm660-pinctrl.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-pinctrl.dtsi @@ -1104,7 +1104,7 @@ cam_sensor_mclk0_active: cam_sensor_mclk0_active { /* MCLK0 */ mux { - /* CLK, DATA */ + /* CLK */ pins = "gpio32"; function = "cam_mclk"; }; @@ -1119,7 +1119,7 @@ cam_sensor_mclk0_suspend: cam_sensor_mclk0_suspend { /* MCLK0 */ mux { - /* CLK, DATA */ + /* CLK */ pins = "gpio32"; function = "cam_mclk"; }; @@ -1162,7 +1162,7 @@ cam_sensor_mclk1_active: cam_sensor_mclk1_active { /* MCLK1 */ mux { - /* CLK, DATA */ + /* CLK */ pins = "gpio33"; function = "cam_mclk"; }; @@ -1177,7 +1177,7 @@ cam_sensor_mclk1_suspend: cam_sensor_mclk1_suspend { /* MCLK1 */ mux { - /* CLK, DATA */ + /* CLK */ pins = "gpio33"; function = "cam_mclk"; }; @@ -1219,7 +1219,7 @@ cam_sensor_mclk2_active: cam_sensor_mclk2_active { /* MCLK1 */ mux { - /* CLK, DATA */ + /* CLK */ pins = "gpio34"; function = "cam_mclk"; }; @@ -1234,7 +1234,7 @@ cam_sensor_mclk2_suspend: cam_sensor_mclk2_suspend { /* MCLK1 */ mux { - /* CLK, DATA */ + /* CLK */ pins = "gpio34"; function = "cam_mclk"; }; @@ -1274,6 +1274,64 @@ }; }; + cam_sensor_mclk3_active: cam_sensor_mclk3_active { + /* MCLK3 */ + mux { + /* CLK */ + pins = "gpio35"; + function = "cam_mclk"; + }; + + config { + pins = "gpio35"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk3_suspend: cam_sensor_mclk3_suspend { + /* MCLK3 */ + mux { + /* CLK */ + pins = "gpio35"; + function = "cam_mclk"; + }; + + config { + pins = "gpio35"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_front_iris_active: cam_sensor_front_iris_active { + /* RESET */ + mux { + pins = "gpio52"; + function = "gpio"; + }; + + config { + pins = "gpio52"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_front_iris_suspend: cam_sensor_front_iris_suspend { + /* RESET */ + mux { + pins = "gpio52"; + function = "gpio"; + }; + + config { + pins = "gpio52"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + /* HS UART CONFIGURATION */ blsp1_uart1_active: blsp1_uart1_active { mux { diff --git a/arch/arm/boot/dts/qcom/sdm660-qrd.dtsi b/arch/arm/boot/dts/qcom/sdm660-qrd.dtsi index 3d2cfedc1009..86da804a1b18 100644 --- a/arch/arm/boot/dts/qcom/sdm660-qrd.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-qrd.dtsi @@ -230,6 +230,7 @@ &pm660_fg { qcom,battery-data = <&qrd_batterydata>; qcom,fg-jeita-thresholds = <0 5 55 55>; + qcom,battery-thermal-coefficients = [9d 50 ff]; }; &i2c_2 { diff --git a/arch/arm/configs/sdm660-perf_defconfig b/arch/arm/configs/sdm660-perf_defconfig index a8844dafe592..fe6988ebbb53 100644 --- a/arch/arm/configs/sdm660-perf_defconfig +++ b/arch/arm/configs/sdm660-perf_defconfig @@ -3,6 +3,9 @@ CONFIG_AUDIT=y CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y CONFIG_IRQ_TIME_ACCOUNTING=y +CONFIG_TASKSTATS=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y CONFIG_RCU_EXPERT=y CONFIG_RCU_FAST_NO_HZ=y CONFIG_IKCONFIG=y @@ -242,7 +245,7 @@ CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=8192 CONFIG_QSEECOM=y CONFIG_HDCP_QSEECOM=y -CONFIG_UID_CPUTIME=y +CONFIG_UID_SYS_STATS=y CONFIG_QPNP_MISC=y CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y @@ -527,7 +530,6 @@ CONFIG_MSM_MMCC_660=y CONFIG_CLOCK_CPU_OSM=y CONFIG_QCOM_MDSS_PLL=y CONFIG_REMOTE_SPINLOCK_MSM=y -CONFIG_IOMMU_IO_PGTABLE_FAST=y CONFIG_ARM_SMMU=y CONFIG_IOMMU_DEBUG=y CONFIG_IOMMU_DEBUG_TRACKING=y diff --git a/arch/arm/configs/sdm660_defconfig b/arch/arm/configs/sdm660_defconfig index bff4d8851203..3942da1a768d 100644 --- a/arch/arm/configs/sdm660_defconfig +++ b/arch/arm/configs/sdm660_defconfig @@ -529,8 +529,6 @@ CONFIG_MSM_MMCC_660=y CONFIG_CLOCK_CPU_OSM=y CONFIG_QCOM_MDSS_PLL=y CONFIG_REMOTE_SPINLOCK_MSM=y -CONFIG_IOMMU_IO_PGTABLE_FAST=y -CONFIG_IOMMU_IO_PGTABLE_FAST_SELFTEST=y CONFIG_ARM_SMMU=y CONFIG_IOMMU_DEBUG=y CONFIG_IOMMU_DEBUG_TRACKING=y diff --git a/arch/arm/kvm/mmu.c b/arch/arm/kvm/mmu.c index dd7f20a490c8..33ee522bb76f 100644 --- a/arch/arm/kvm/mmu.c +++ b/arch/arm/kvm/mmu.c @@ -301,6 +301,14 @@ static void unmap_range(struct kvm *kvm, pgd_t *pgdp, next = kvm_pgd_addr_end(addr, end); if (!pgd_none(*pgd)) unmap_puds(kvm, pgd, addr, next); + /* + * If we are dealing with a large range in + * stage2 table, release the kvm->mmu_lock + * to prevent starvation and lockup detector + * warnings. + */ + if (kvm && (next != end)) + cond_resched_lock(&kvm->mmu_lock); } while (pgd++, addr = next, addr != end); } @@ -745,6 +753,7 @@ int kvm_alloc_stage2_pgd(struct kvm *kvm) */ static void unmap_stage2_range(struct kvm *kvm, phys_addr_t start, u64 size) { + assert_spin_locked(&kvm->mmu_lock); unmap_range(kvm, kvm->arch.pgd, start, size); } @@ -831,7 +840,10 @@ void kvm_free_stage2_pgd(struct kvm *kvm) if (kvm->arch.pgd == NULL) return; + spin_lock(&kvm->mmu_lock); unmap_stage2_range(kvm, 0, KVM_PHYS_SIZE); + spin_unlock(&kvm->mmu_lock); + kvm_free_hwpgd(kvm_get_hwpgd(kvm)); if (KVM_PREALLOC_LEVEL > 0) kfree(kvm->arch.pgd); diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c index f86692dbcfd5..83fc403aec3c 100644 --- a/arch/arm/mach-omap2/timer.c +++ b/arch/arm/mach-omap2/timer.c @@ -496,8 +496,7 @@ void __init omap_init_time(void) __omap_sync32k_timer_init(1, "timer_32k_ck", "ti,timer-alwon", 2, "timer_sys_ck", NULL, false); - if (of_have_populated_dt()) - clocksource_probe(); + clocksource_probe(); } #if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_SOC_AM43XX) @@ -505,6 +504,8 @@ void __init omap3_secure_sync32k_timer_init(void) { __omap_sync32k_timer_init(12, "secure_32k_fck", "ti,timer-secure", 2, "timer_sys_ck", NULL, false); + + clocksource_probe(); } #endif /* CONFIG_ARCH_OMAP3 */ @@ -513,6 +514,8 @@ void __init omap3_gptimer_timer_init(void) { __omap_sync32k_timer_init(2, "timer_sys_ck", NULL, 1, "timer_sys_ck", "ti,timer-alwon", true); + + clocksource_probe(); } #endif diff --git a/arch/arm64/configs/msm-auto-perf_defconfig b/arch/arm64/configs/msm-auto-perf_defconfig index 0dbf9fc679f8..eb1ebee6c2a0 100644 --- a/arch/arm64/configs/msm-auto-perf_defconfig +++ b/arch/arm64/configs/msm-auto-perf_defconfig @@ -5,6 +5,9 @@ CONFIG_AUDIT=y CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y CONFIG_IRQ_TIME_ACCOUNTING=y +CONFIG_TASKSTATS=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y CONFIG_RCU_EXPERT=y CONFIG_RCU_FAST_NO_HZ=y CONFIG_IKCONFIG=y @@ -86,7 +89,9 @@ CONFIG_IP_MULTIPLE_TABLES=y CONFIG_IP_ROUTE_VERBOSE=y CONFIG_IP_PNP=y CONFIG_IP_PNP_DHCP=y +CONFIG_INET_AH=y CONFIG_INET_ESP=y +CONFIG_INET_IPCOMP=y # CONFIG_INET_LRO is not set CONFIG_INET_DIAG_DESTROY=y CONFIG_IPV6_ROUTER_PREF=y @@ -214,21 +219,10 @@ CONFIG_SOCKEV_NLMCAST=y CONFIG_CAN=y CONFIG_CAN_RH850=y CONFIG_BT=y -CONFIG_BT_RFCOMM=y -CONFIG_BT_RFCOMM_TTY=y -CONFIG_BT_BNEP=y -CONFIG_BT_BNEP_MC_FILTER=y -CONFIG_BT_BNEP_PROTO_FILTER=y -CONFIG_BT_HIDP=y -# CONFIG_BT_HS is not set -# CONFIG_BT_LE is not set -# CONFIG_BT_DEBUGFS is not set CONFIG_MSM_BT_POWER=y CONFIG_BTFM_SLIM=y CONFIG_BTFM_SLIM_WCN3990=y CONFIG_CFG80211=y -CONFIG_CFG80211_INTERNAL_REGDB=y -# CONFIG_CFG80211_CRDA_SUPPORT is not set CONFIG_RFKILL=y CONFIG_IPC_ROUTER=y CONFIG_IPC_ROUTER_SECURITY=y @@ -242,7 +236,7 @@ CONFIG_BLK_DEV_RAM_SIZE=8192 CONFIG_QSEECOM=y CONFIG_HDCP_QSEECOM=y CONFIG_PROFILER=y -CONFIG_UID_CPUTIME=y +CONFIG_UID_SYS_STATS=y CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_SG=y @@ -270,27 +264,23 @@ CONFIG_RNDIS_IPA=y CONFIG_PPP=y CONFIG_PPP_BSDCOMP=y CONFIG_PPP_DEFLATE=y -CONFIG_PPP_FILTER=y CONFIG_PPP_MPPE=y -CONFIG_PPP_MULTILINK=y -CONFIG_PPPOE=y -CONFIG_PPPOL2TP=y CONFIG_PPPOLAC=y CONFIG_PPPOPNS=y -CONFIG_PPP_ASYNC=y -CONFIG_PPP_SYNC_TTY=y CONFIG_USB_USBNET=y CONFIG_WCNSS_MEM_PRE_ALLOC=y CONFIG_CNSS_CRYPTO=y CONFIG_ATH_CARDS=y CONFIG_WIL6210=m CONFIG_CNSS=y +CONFIG_CNSS_ASYNC=y CONFIG_CLD_LL_CORE=y CONFIG_BUS_AUTO_SUSPEND=y CONFIG_INPUT_EVDEV=y CONFIG_INPUT_KEYRESET=y CONFIG_KEYBOARD_GPIO=y # CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_JOYSTICK=y CONFIG_INPUT_TOUCHSCREEN=y CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_CORE_v21=y CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_v21=y @@ -301,7 +291,6 @@ CONFIG_TOUCHSCREEN_GEN_VKEYS=y CONFIG_INPUT_MISC=y CONFIG_INPUT_HBTP_INPUT=y CONFIG_INPUT_QPNP_POWER_ON=y -CONFIG_INPUT_KEYCHORD=y CONFIG_INPUT_UINPUT=y CONFIG_INPUT_GPIO=y # CONFIG_SERIO_SERPORT is not set @@ -316,7 +305,6 @@ CONFIG_HW_RANDOM=y CONFIG_HW_RANDOM_MSM_LEGACY=y CONFIG_MSM_ADSPRPC=y CONFIG_MSM_RDBG=m -# CONFIG_ACPI_I2C_OPREGION is not set CONFIG_I2C_CHARDEV=y CONFIG_I2C_QUP=y CONFIG_I2C_MSM_V2=y @@ -353,6 +341,7 @@ CONFIG_WCD9335_CODEC=y CONFIG_REGULATOR=y CONFIG_REGULATOR_FIXED_VOLTAGE=y CONFIG_REGULATOR_FAN53555=y +CONFIG_REGULATOR_ONSEMI_NCP6335D=y CONFIG_REGULATOR_RPM_SMD=y CONFIG_REGULATOR_QPNP=y CONFIG_REGULATOR_QPNP_LABIBB=y @@ -425,7 +414,6 @@ CONFIG_HID_MAGICMOUSE=y CONFIG_HID_MICROSOFT=y CONFIG_HID_MULTITOUCH=y CONFIG_USB=y -CONFIG_USB_ANNOUNCE_NEW_DEVICES=y CONFIG_USB_XHCI_HCD=y CONFIG_USB_EHCI_HCD=y CONFIG_USB_EHCI_HCD_PLATFORM=y @@ -434,7 +422,6 @@ CONFIG_USB_OHCI_HCD_PLATFORM=y CONFIG_USB_STORAGE=y CONFIG_USB_DWC3=y CONFIG_USB_ISP1760=y -CONFIG_USB_SERIAL=y CONFIG_USB_QTI_KS_BRIDGE=y CONFIG_NOP_USB_XCEIV=y CONFIG_USB_MSM_SSPHY_QMP=y @@ -442,7 +429,6 @@ CONFIG_MSM_QUSB_PHY=y CONFIG_USB_ULPI=y CONFIG_USB_GADGET=y CONFIG_USB_GADGET_VBUS_DRAW=500 -CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=4 CONFIG_USB_CONFIGFS=y CONFIG_USB_CONFIGFS_SERIAL=y CONFIG_USB_CONFIGFS_NCM=y @@ -467,11 +453,17 @@ CONFIG_MMC_TEST=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_MSM=y +CONFIG_MMC_SPI=y +CONFIG_MMC_DW=y +CONFIG_MMC_DW_EXYNOS=y CONFIG_MMC_CQ_HCI=y CONFIG_LEDS_QPNP=y CONFIG_LEDS_QPNP_FLASH_V2=y CONFIG_LEDS_QPNP_WLED=y +CONFIG_LEDS_SYSCON=y CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_TRIGGER_HEARTBEAT=y +CONFIG_LEDS_TRIGGER_CPU=y CONFIG_SWITCH=y CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_QPNP=y @@ -497,6 +489,10 @@ CONFIG_SPS=y CONFIG_SPS_SUPPORT_NDP_BAM=y CONFIG_IPA=y CONFIG_RMNET_IPA=y +CONFIG_GSI=y +CONFIG_IPA3=y +CONFIG_RMNET_IPA3=y +CONFIG_IPA_UT=y CONFIG_GPIO_USB_DETECT=y CONFIG_MSM_MHI=y CONFIG_MSM_MHI_UCI=y @@ -521,6 +517,7 @@ CONFIG_MSM_SMP2P_TEST=y CONFIG_MSM_QMI_INTERFACE=y CONFIG_MSM_RPM_SMD=y CONFIG_QCOM_BUS_SCALING=y +CONFIG_MSM_SERVICE_LOCATOR=y CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y CONFIG_MSM_SYSMON_GLINK_COMM=y CONFIG_MSM_IPC_ROUTER_MHI_XPRT=y @@ -542,9 +539,12 @@ CONFIG_MSM_PIL=y CONFIG_MSM_PIL_SSR_GENERIC=y CONFIG_MSM_PIL_MSS_QDSP6V5=y CONFIG_TRACER_PKT=y +CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y CONFIG_MSM_MPM_OF=y CONFIG_MSM_EVENT_TIMER=y CONFIG_MSM_AVTIMER=y +CONFIG_QCOM_REMOTEQDSS=y +CONFIG_MSM_SERVICE_NOTIFIER=y CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y CONFIG_MSM_RPM_LOG=y CONFIG_MSM_RPM_STATS_LOG=y @@ -564,6 +564,8 @@ CONFIG_QCOM_DEVFREQ_DEVBW=y CONFIG_EXTCON=y CONFIG_PWM=y CONFIG_PWM_QPNP=y +CONFIG_ARM_GIC_V3_ACL=y +CONFIG_PHY_XGENE=y CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y CONFIG_MSM_TZ_LOG=y @@ -609,8 +611,8 @@ CONFIG_CORESIGHT_QPDI=y CONFIG_CORESIGHT_SOURCE_DUMMY=y CONFIG_PFK=y CONFIG_SECURITY=y -CONFIG_SECURITY_NETWORK=y CONFIG_SECURITY_SELINUX=y +CONFIG_SECURITY_SMACK=y CONFIG_CRYPTO_ECHAINIV=y CONFIG_CRYPTO_XCBC=y CONFIG_CRYPTO_MD4=y diff --git a/arch/arm64/configs/msm-auto_defconfig b/arch/arm64/configs/msm-auto_defconfig index 123e19031f17..e3fbb5166478 100644 --- a/arch/arm64/configs/msm-auto_defconfig +++ b/arch/arm64/configs/msm-auto_defconfig @@ -4,6 +4,9 @@ CONFIG_AUDIT=y CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y CONFIG_IRQ_TIME_ACCOUNTING=y +CONFIG_TASKSTATS=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y CONFIG_RCU_EXPERT=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y @@ -234,7 +237,7 @@ CONFIG_BLK_DEV_RAM_SIZE=8192 CONFIG_QSEECOM=y CONFIG_HDCP_QSEECOM=y CONFIG_PROFILER=y -CONFIG_UID_CPUTIME=y +CONFIG_UID_SYS_STATS=y CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_SG=y @@ -271,6 +274,7 @@ CONFIG_CNSS_CRYPTO=y CONFIG_ATH_CARDS=y CONFIG_WIL6210=m CONFIG_CNSS=y +CONFIG_CNSS_ASYNC=y CONFIG_CLD_LL_CORE=y CONFIG_BUS_AUTO_SUSPEND=y CONFIG_INPUT_EVDEV=y @@ -340,6 +344,7 @@ CONFIG_WCD9335_CODEC=y CONFIG_REGULATOR=y CONFIG_REGULATOR_FIXED_VOLTAGE=y CONFIG_REGULATOR_FAN53555=y +CONFIG_REGULATOR_ONSEMI_NCP6335D=y CONFIG_REGULATOR_RPM_SMD=y CONFIG_REGULATOR_QPNP=y CONFIG_REGULATOR_QPNP_LABIBB=y diff --git a/arch/arm64/configs/msmcortex-perf_defconfig b/arch/arm64/configs/msmcortex-perf_defconfig index a5c58dc66191..778dcfecaf1c 100644 --- a/arch/arm64/configs/msmcortex-perf_defconfig +++ b/arch/arm64/configs/msmcortex-perf_defconfig @@ -65,12 +65,12 @@ CONFIG_CMA=y CONFIG_CMA_DEBUGFS=y CONFIG_ZSMALLOC=y CONFIG_BALANCE_ANON_FILE_RECLAIM=y -CONFIG_FORCE_ALLOC_FROM_DMA_ZONE=y CONFIG_SECCOMP=y CONFIG_ARMV8_DEPRECATED=y CONFIG_SWP_EMULATION=y CONFIG_CP15_BARRIER_EMULATION=y CONFIG_SETEND_EMULATION=y +CONFIG_ARM64_SW_TTBR0_PAN=y CONFIG_RANDOMIZE_BASE=y # CONFIG_RANDOMIZE_MODULE_REGION_FULL is not set # CONFIG_EFI is not set diff --git a/arch/arm64/configs/msmcortex_defconfig b/arch/arm64/configs/msmcortex_defconfig index 7a82377302fe..5c88fd4985e1 100644 --- a/arch/arm64/configs/msmcortex_defconfig +++ b/arch/arm64/configs/msmcortex_defconfig @@ -71,6 +71,7 @@ CONFIG_ARMV8_DEPRECATED=y CONFIG_SWP_EMULATION=y CONFIG_CP15_BARRIER_EMULATION=y CONFIG_SETEND_EMULATION=y +CONFIG_ARM64_SW_TTBR0_PAN=y CONFIG_RANDOMIZE_BASE=y CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set diff --git a/arch/arm64/configs/msmcortex_mediabox-perf_defconfig b/arch/arm64/configs/msmcortex_mediabox-perf_defconfig new file mode 100644 index 000000000000..cb0a5977c167 --- /dev/null +++ b/arch/arm64/configs/msmcortex_mediabox-perf_defconfig @@ -0,0 +1,642 @@ +CONFIG_LOCALVERSION="-perf" +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_AUDIT=y +# CONFIG_AUDITSYSCALL is not set +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_IRQ_TIME_ACCOUNTING=y +CONFIG_RCU_EXPERT=y +CONFIG_RCU_FAST_NO_HZ=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_CPU_MAX_BUF_SHIFT=17 +CONFIG_CGROUP_FREEZER=y +CONFIG_CPUSETS=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_CGROUP_SCHEDTUNE=y +CONFIG_RT_GROUP_SCHED=y +CONFIG_SCHED_HMP=y +CONFIG_SCHED_HMP_CSTATE_AWARE=y +CONFIG_SCHED_CORE_CTL=y +CONFIG_NAMESPACES=y +# CONFIG_UTS_NS is not set +# CONFIG_PID_NS is not set +CONFIG_SCHED_AUTOGROUP=y +CONFIG_SCHED_TUNE=y +CONFIG_BLK_DEV_INITRD=y +# CONFIG_RD_XZ is not set +# CONFIG_RD_LZO is not set +# CONFIG_RD_LZ4 is not set +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_KALLSYMS_ALL=y +# CONFIG_AIO is not set +# CONFIG_MEMBARRIER is not set +CONFIG_EMBEDDED=y +# CONFIG_SLUB_DEBUG is not set +# CONFIG_COMPAT_BRK is not set +CONFIG_PROFILING=y +CONFIG_CC_STACKPROTECTOR_REGULAR=y +CONFIG_ARCH_MMAP_RND_COMPAT_BITS=16 +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_MODVERSIONS=y +CONFIG_MODULE_SIG=y +CONFIG_MODULE_SIG_FORCE=y +CONFIG_MODULE_SIG_SHA512=y +CONFIG_PARTITION_ADVANCED=y +CONFIG_ARCH_QCOM=y +CONFIG_ARCH_MSM8998=y +CONFIG_ARCH_MSMHAMSTER=y +CONFIG_PCI=y +CONFIG_PCI_MSM=y +CONFIG_SCHED_MC=y +CONFIG_NR_CPUS=8 +CONFIG_QCOM_TLB_EL2_HANDLER=y +CONFIG_PREEMPT=y +CONFIG_HZ_100=y +CONFIG_ARM64_REG_REBALANCE_ON_CTX_SW=y +CONFIG_CMA=y +CONFIG_CMA_DEBUGFS=y +CONFIG_ZSMALLOC=y +CONFIG_BALANCE_ANON_FILE_RECLAIM=y +CONFIG_FORCE_ALLOC_FROM_DMA_ZONE=y +CONFIG_SECCOMP=y +CONFIG_ARMV8_DEPRECATED=y +CONFIG_SWP_EMULATION=y +CONFIG_CP15_BARRIER_EMULATION=y +CONFIG_SETEND_EMULATION=y +CONFIG_RANDOMIZE_BASE=y +# CONFIG_RANDOMIZE_MODULE_REGION_FULL is not set +# CONFIG_EFI is not set +CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_COMPAT=y +CONFIG_PM_AUTOSLEEP=y +CONFIG_PM_WAKELOCKS=y +CONFIG_PM_WAKELOCKS_LIMIT=0 +# CONFIG_PM_WAKELOCKS_GC is not set +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_INTERACTIVE=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y +CONFIG_CPU_BOOST=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_XFRM_USER=y +CONFIG_XFRM_STATISTICS=y +CONFIG_NET_KEY=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_INET_AH=y +CONFIG_INET_ESP=y +CONFIG_INET_IPCOMP=y +CONFIG_INET_DIAG_DESTROY=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +CONFIG_INET6_IPCOMP=y +CONFIG_IPV6_MIP6=y +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_IPV6_SUBTREES=y +CONFIG_NETFILTER=y +CONFIG_NF_CONNTRACK=y +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CT_PROTO_DCCP=y +CONFIG_NF_CT_PROTO_SCTP=y +CONFIG_NF_CT_PROTO_UDPLITE=y +CONFIG_NF_CONNTRACK_AMANDA=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_H323=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=y +CONFIG_NF_CONNTRACK_PPTP=y +CONFIG_NF_CONNTRACK_SANE=y +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NF_CT_NETLINK=y +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y +CONFIG_NETFILTER_XT_TARGET_CONNMARK=y +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_HARDIDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_LOG=y +CONFIG_NETFILTER_XT_TARGET_MARK=y +CONFIG_NETFILTER_XT_TARGET_NFLOG=y +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y +CONFIG_NETFILTER_XT_TARGET_NOTRACK=y +CONFIG_NETFILTER_XT_TARGET_TEE=y +CONFIG_NETFILTER_XT_TARGET_TPROXY=y +CONFIG_NETFILTER_XT_TARGET_TRACE=y +CONFIG_NETFILTER_XT_TARGET_SECMARK=y +CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +CONFIG_NETFILTER_XT_MATCH_COMMENT=y +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y +CONFIG_NETFILTER_XT_MATCH_CONNMARK=y +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y +CONFIG_NETFILTER_XT_MATCH_DSCP=y +CONFIG_NETFILTER_XT_MATCH_ESP=y +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y +CONFIG_NETFILTER_XT_MATCH_HELPER=y +CONFIG_NETFILTER_XT_MATCH_IPRANGE=y +# CONFIG_NETFILTER_XT_MATCH_L2TP is not set +CONFIG_NETFILTER_XT_MATCH_LENGTH=y +CONFIG_NETFILTER_XT_MATCH_LIMIT=y +CONFIG_NETFILTER_XT_MATCH_MAC=y +CONFIG_NETFILTER_XT_MATCH_MARK=y +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y +CONFIG_NETFILTER_XT_MATCH_POLICY=y +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_QTAGUID=y +CONFIG_NETFILTER_XT_MATCH_QUOTA=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_SOCKET=y +CONFIG_NETFILTER_XT_MATCH_STATE=y +CONFIG_NETFILTER_XT_MATCH_STATISTIC=y +CONFIG_NETFILTER_XT_MATCH_STRING=y +CONFIG_NETFILTER_XT_MATCH_TIME=y +CONFIG_NETFILTER_XT_MATCH_U32=y +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MATCH_AH=y +CONFIG_IP_NF_MATCH_ECN=y +CONFIG_IP_NF_MATCH_RPFILTER=y +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_NF_NAT=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_IP_NF_MANGLE=y +CONFIG_IP_NF_RAW=y +CONFIG_IP_NF_SECURITY=y +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARP_MANGLE=y +CONFIG_NF_CONNTRACK_IPV6=y +CONFIG_IP6_NF_IPTABLES=y +CONFIG_IP6_NF_MATCH_RPFILTER=y +CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_TARGET_REJECT=y +CONFIG_IP6_NF_MANGLE=y +CONFIG_IP6_NF_RAW=y +CONFIG_BRIDGE_NF_EBTABLES=y +CONFIG_BRIDGE_EBT_BROUTE=y +CONFIG_L2TP=y +CONFIG_L2TP_V3=y +CONFIG_L2TP_IP=y +CONFIG_L2TP_ETH=y +CONFIG_BRIDGE=y +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_HTB=y +CONFIG_NET_SCH_PRIO=y +CONFIG_NET_SCH_MULTIQ=y +CONFIG_NET_SCH_INGRESS=y +CONFIG_NET_CLS_FW=y +CONFIG_NET_CLS_U32=y +CONFIG_CLS_U32_MARK=y +CONFIG_NET_CLS_FLOW=y +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_CMP=y +CONFIG_NET_EMATCH_NBYTE=y +CONFIG_NET_EMATCH_U32=y +CONFIG_NET_EMATCH_META=y +CONFIG_NET_EMATCH_TEXT=y +CONFIG_NET_CLS_ACT=y +CONFIG_NET_ACT_GACT=y +CONFIG_NET_ACT_MIRRED=y +CONFIG_NET_ACT_SKBEDIT=y +CONFIG_RMNET_DATA=y +CONFIG_RMNET_DATA_FC=y +CONFIG_RMNET_DATA_DEBUG_PKT=y +CONFIG_SOCKEV_NLMCAST=y +CONFIG_BT=y +CONFIG_MSM_BT_POWER=y +CONFIG_BTFM_SLIM=y +CONFIG_BTFM_SLIM_WCN3990=y +CONFIG_CFG80211=y +CONFIG_CFG80211_INTERNAL_REGDB=y +CONFIG_CFG80211_WEXT=y +CONFIG_MAC80211=m +CONFIG_MAC80211_MESH=y +CONFIG_MAC80211_LEDS=y +CONFIG_RFKILL=y +CONFIG_NFC_NQ=y +CONFIG_IPC_ROUTER=y +CONFIG_IPC_ROUTER_SECURITY=y +CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y +CONFIG_DMA_CMA=y +# CONFIG_PNP_DEBUG_MESSAGES is not set +CONFIG_ZRAM=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_QSEECOM=y +CONFIG_HDCP_QSEECOM=y +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y +CONFIG_CHR_DEV_SG=y +CONFIG_CHR_DEV_SCH=y +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_UFSHCD=y +CONFIG_SCSI_UFSHCD_PLATFORM=y +CONFIG_SCSI_UFS_QCOM=y +CONFIG_SCSI_UFS_QCOM_ICE=y +CONFIG_MD=y +CONFIG_BLK_DEV_MD=y +CONFIG_MD_LINEAR=y +CONFIG_BLK_DEV_DM=y +CONFIG_DM_CRYPT=y +CONFIG_DM_REQ_CRYPT=y +CONFIG_DM_UEVENT=y +CONFIG_DM_VERITY=y +CONFIG_DM_VERITY_FEC=y +CONFIG_DM_ANDROID_VERITY=y +CONFIG_NETDEVICES=y +CONFIG_BONDING=y +CONFIG_DUMMY=y +CONFIG_TUN=y +CONFIG_SKY2=y +CONFIG_RNDIS_IPA=y +CONFIG_SMSC911X=y +CONFIG_PPP=y +CONFIG_PPP_BSDCOMP=y +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_MPPE=y +CONFIG_PPPOLAC=y +CONFIG_PPPOPNS=y +CONFIG_USB_USBNET=y +CONFIG_WCNSS_MEM_PRE_ALLOC=y +CONFIG_ATH_CARDS=y +CONFIG_WIL6210=m +CONFIG_ATH10K=m +CONFIG_ATH10K_TARGET_SNOC=m +CONFIG_ATH10K_SNOC=y +CONFIG_CLD_LL_CORE=y +CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_KEYRESET=y +CONFIG_KEYBOARD_GPIO=y +# CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_CORE_v21=y +CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_v21=y +CONFIG_SECURE_TOUCH=y +CONFIG_TOUCHSCREEN_ST=y +CONFIG_TOUCHSCREEN_ST_I2C=y +CONFIG_INPUT_MISC=y +CONFIG_INPUT_HBTP_INPUT=y +CONFIG_INPUT_QPNP_POWER_ON=y +CONFIG_INPUT_UINPUT=y +# CONFIG_SERIO_SERPORT is not set +# CONFIG_VT is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_DEVMEM is not set +# CONFIG_DEVKMEM is not set +CONFIG_SERIAL_MSM_HS=y +CONFIG_SERIAL_MSM_SMD=y +CONFIG_DIAG_CHAR=y +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_MSM_LEGACY=y +CONFIG_MSM_ADSPRPC=y +CONFIG_MSM_RDBG=m +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_MSM_V2=y +CONFIG_SLIMBUS_MSM_NGD=y +CONFIG_SOUNDWIRE=y +CONFIG_SPI=y +CONFIG_SPI_QUP=y +CONFIG_SPI_SPIDEV=y +CONFIG_SPMI=y +CONFIG_PINCTRL_MSM8998=y +CONFIG_PINCTRL_SDM660=y +CONFIG_GPIOLIB=y +CONFIG_GPIO_SYSFS=y +CONFIG_GPIO_QPNP_PIN=y +CONFIG_POWER_RESET_QCOM=y +CONFIG_QCOM_DLOAD_MODE=y +CONFIG_POWER_RESET_XGENE=y +CONFIG_POWER_RESET_SYSCON=y +CONFIG_QPNP_FG_GEN3=y +CONFIG_MSM_BCL_CTL=y +CONFIG_MSM_BCL_PERIPHERAL_CTL=y +CONFIG_BATTERY_BCL=y +CONFIG_QPNP_SMB2=y +CONFIG_SMB138X_CHARGER=y +CONFIG_QPNP_QNOVO=y +CONFIG_MSM_PM=y +CONFIG_APSS_CORE_EA=y +CONFIG_MSM_APM=y +CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y +CONFIG_CPU_THERMAL=y +CONFIG_LIMITS_MONITOR=y +CONFIG_LIMITS_LITE_HW=y +CONFIG_THERMAL_MONITOR=y +CONFIG_THERMAL_TSENS8974=y +CONFIG_THERMAL_QPNP=y +CONFIG_THERMAL_QPNP_ADC_TM=y +CONFIG_QCOM_THERMAL_LIMITS_DCVS=y +CONFIG_MFD_SPMI_PMIC=y +CONFIG_MFD_I2C_PMIC=y +CONFIG_WCD9335_CODEC=y +CONFIG_WCD934X_CODEC=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_RPM_SMD=y +CONFIG_REGULATOR_QPNP=y +CONFIG_REGULATOR_QPNP_LABIBB=y +CONFIG_REGULATOR_QPNP_LCDB=y +CONFIG_REGULATOR_SPM=y +CONFIG_REGULATOR_CPR3_HMSS=y +CONFIG_REGULATOR_CPR3_MMSS=y +CONFIG_REGULATOR_CPRH_KBSS=y +CONFIG_REGULATOR_MEM_ACC=y +CONFIG_REGULATOR_PROXY_CONSUMER=y +CONFIG_REGULATOR_STUB=y +CONFIG_MEDIA_SUPPORT=y +CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y +CONFIG_MEDIA_CONTROLLER=y +CONFIG_VIDEO_V4L2_SUBDEV_API=y +CONFIG_VIDEO_ADV_DEBUG=y +CONFIG_VIDEO_FIXED_MINOR_RANGES=y +CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_MSM_CAMERA=y +CONFIG_MSM_CAMERA_DEBUG=y +CONFIG_MSMB_CAMERA=y +CONFIG_MSMB_CAMERA_DEBUG=y +CONFIG_MSM_CAMERA_SENSOR=y +CONFIG_MSM_CPP=y +CONFIG_MSM_CCI=y +CONFIG_MSM_CSI20_HEADER=y +CONFIG_MSM_CSI22_HEADER=y +CONFIG_MSM_CSI30_HEADER=y +CONFIG_MSM_CSI31_HEADER=y +CONFIG_MSM_CSIPHY=y +CONFIG_MSM_CSID=y +CONFIG_MSM_EEPROM=y +CONFIG_MSM_ISPIF=y +CONFIG_IMX134=y +CONFIG_IMX132=y +CONFIG_OV9724=y +CONFIG_OV5648=y +CONFIG_GC0339=y +CONFIG_OV8825=y +CONFIG_OV8865=y +CONFIG_s5k4e1=y +CONFIG_OV12830=y +CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE=y +CONFIG_MSMB_JPEG=y +CONFIG_MSM_FD=y +CONFIG_MSM_JPEGDMA=y +CONFIG_MSM_VIDC_V4L2=y +CONFIG_MSM_VIDC_VMEM=y +CONFIG_MSM_VIDC_GOVERNORS=y +CONFIG_MSM_SDE_ROTATOR=y +CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=y +CONFIG_DVB_MPQ=m +CONFIG_DVB_MPQ_DEMUX=m +CONFIG_DVB_MPQ_MEDIA_BOX_DEMUX=y +CONFIG_TSPP=m +CONFIG_DRM=y +CONFIG_LOGO=y +# CONFIG_LOGO_LINUX_MONO is not set +# CONFIG_LOGO_LINUX_VGA16 is not set +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_SND_USB_AUDIO=y +CONFIG_SND_USB_AUDIO_QMI=y +CONFIG_SND_SOC=y +CONFIG_SND_SOC_MSM8998=y +CONFIG_UHID=y +CONFIG_HID_APPLE=y +CONFIG_HID_ELECOM=y +CONFIG_HID_MAGICMOUSE=y +CONFIG_HID_MICROSOFT=y +CONFIG_HID_MULTITOUCH=y +CONFIG_HID_PLANTRONICS=y +CONFIG_USB=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_HCD_PLATFORM=y +CONFIG_USB_OHCI_HCD=y +CONFIG_USB_OHCI_HCD_PLATFORM=y +CONFIG_USB_STORAGE=y +CONFIG_USB_DWC3=y +CONFIG_USB_ISP1760=y +CONFIG_USB_ISP1760_HOST_ROLE=y +CONFIG_USB_PD_POLICY=y +CONFIG_QPNP_USB_PDPHY=y +CONFIG_USB_EHSET_TEST_FIXTURE=y +CONFIG_USB_OTG_WAKELOCK=y +CONFIG_NOP_USB_XCEIV=y +CONFIG_USB_MSM_SSPHY_QMP=y +CONFIG_MSM_QUSB_PHY=y +CONFIG_DUAL_ROLE_USB_INTF=y +CONFIG_USB_GADGET=y +CONFIG_USB_GADGET_VBUS_DRAW=500 +CONFIG_USB_CONFIGFS=y +CONFIG_USB_CONFIGFS_NCM=y +CONFIG_USB_CONFIGFS_MASS_STORAGE=y +CONFIG_USB_CONFIGFS_F_FS=y +CONFIG_USB_CONFIGFS_F_MTP=y +CONFIG_USB_CONFIGFS_F_PTP=y +CONFIG_USB_CONFIGFS_F_ACC=y +CONFIG_USB_CONFIGFS_UEVENT=y +CONFIG_USB_CONFIGFS_F_MIDI=y +CONFIG_USB_CONFIGFS_F_HID=y +CONFIG_USB_CONFIGFS_F_DIAG=y +CONFIG_USB_CONFIGFS_F_GSI=y +CONFIG_USB_CONFIGFS_F_CDEV=y +CONFIG_USB_CONFIGFS_F_QDSS=y +CONFIG_USB_CONFIGFS_F_CCID=y +CONFIG_MMC=y +CONFIG_MMC_PERF_PROFILING=y +CONFIG_MMC_CLKGATE=y +CONFIG_MMC_BLOCK_MINORS=32 +CONFIG_MMC_TEST=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_MSM=y +CONFIG_LEDS_QPNP=y +CONFIG_LEDS_QPNP_FLASH_V2=y +CONFIG_LEDS_QPNP_WLED=y +CONFIG_LEDS_SYSCON=y +CONFIG_SWITCH=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_QPNP=y +CONFIG_ESOC=y +CONFIG_ESOC_DEV=y +CONFIG_ESOC_CLIENT=y +CONFIG_ESOC_MDM_4x=y +CONFIG_ESOC_MDM_DRV=y +CONFIG_DMADEVICES=y +CONFIG_QCOM_SPS_DMA=y +CONFIG_UIO=y +CONFIG_UIO_MSM_SHAREDMEM=y +CONFIG_STAGING=y +CONFIG_ASHMEM=y +CONFIG_ANDROID_TIMED_GPIO=y +CONFIG_ANDROID_LOW_MEMORY_KILLER=y +CONFIG_ION=y +CONFIG_ION_MSM=y +CONFIG_QPNP_REVID=y +CONFIG_QPNP_COINCELL=y +CONFIG_SPS=y +CONFIG_SPS_SUPPORT_NDP_BAM=y +CONFIG_IPA=y +CONFIG_RMNET_IPA=y +CONFIG_GSI=y +CONFIG_IPA3=y +CONFIG_RMNET_IPA3=y +CONFIG_GPIO_USB_DETECT=y +CONFIG_SEEMP_CORE=y +CONFIG_USB_BAM=y +CONFIG_MSM_MDSS_PLL=y +CONFIG_REMOTE_SPINLOCK_MSM=y +CONFIG_MSM_TIMER_LEAP=y +CONFIG_IOMMU_IO_PGTABLE_FAST=y +CONFIG_ARM_SMMU=y +CONFIG_IOMMU_DEBUG=y +CONFIG_IOMMU_DEBUG_TRACKING=y +CONFIG_IOMMU_TESTS=y +CONFIG_MSM_SMEM=y +CONFIG_QPNP_HAPTIC=y +CONFIG_MSM_SMD=y +CONFIG_MSM_GLINK=y +CONFIG_MSM_GLINK_LOOPBACK_SERVER=y +CONFIG_MSM_GLINK_SMD_XPRT=y +CONFIG_MSM_GLINK_SMEM_NATIVE_XPRT=y +CONFIG_MSM_GLINK_SPI_XPRT=y +CONFIG_MSM_SPCOM=y +CONFIG_MSM_SPSS_UTILS=y +CONFIG_MSM_SMEM_LOGGING=y +CONFIG_MSM_SMP2P=y +CONFIG_MSM_SMP2P_TEST=y +CONFIG_MSM_QMI_INTERFACE=y +CONFIG_MSM_RPM_SMD=y +CONFIG_QCOM_BUS_SCALING=y +CONFIG_MSM_SERVICE_LOCATOR=y +CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y +CONFIG_MSM_SYSMON_GLINK_COMM=y +CONFIG_MSM_IPC_ROUTER_GLINK_XPRT=y +CONFIG_MSM_GLINK_PKT=y +CONFIG_MSM_SPM=y +CONFIG_QCOM_WATCHDOG_V2=y +CONFIG_QCOM_IRQ_HELPER=y +CONFIG_QCOM_MEMORY_DUMP_V2=y +CONFIG_ICNSS=y +CONFIG_MSM_RUN_QUEUE_STATS=y +CONFIG_MSM_BOOT_STATS=y +CONFIG_MSM_ADSP_LOADER=y +CONFIG_MSM_PERFORMANCE=y +CONFIG_MSM_SUBSYSTEM_RESTART=y +CONFIG_MSM_PIL=y +CONFIG_MSM_PIL_SSR_GENERIC=y +CONFIG_MSM_PIL_MSS_QDSP6V5=y +CONFIG_TRACER_PKT=y +CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y +CONFIG_MSM_MPM_OF=y +CONFIG_MSM_EVENT_TIMER=y +CONFIG_MSM_AVTIMER=y +CONFIG_QCOM_REMOTEQDSS=y +CONFIG_MSM_SERVICE_NOTIFIER=y +CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y +CONFIG_MSM_RPM_LOG=y +CONFIG_MSM_RPM_STATS_LOG=y +CONFIG_QSEE_IPC_IRQ_BRIDGE=y +CONFIG_QCOM_SMCINVOKE=y +CONFIG_QCOM_EARLY_RANDOM=y +CONFIG_MEM_SHARE_QMI_SERVICE=y +CONFIG_QCOM_BIMC_BWMON=y +CONFIG_ARM_MEMLAT_MON=y +CONFIG_DEVFREQ_GOV_QCOM_BW_HWMON=y +CONFIG_DEVFREQ_GOV_MEMLAT=y +CONFIG_QCOM_DEVFREQ_DEVBW=y +CONFIG_SPDM_SCM=y +CONFIG_DEVFREQ_SPDM=y +CONFIG_EXTCON=y +CONFIG_IIO=y +CONFIG_QCOM_RRADC=y +CONFIG_QCOM_TADC=y +CONFIG_PWM=y +CONFIG_PWM_QPNP=y +CONFIG_ARM_GIC_V3_ACL=y +CONFIG_ANDROID=y +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_ANDROID_BINDER_DEVICES="binder,hwbinder" +CONFIG_MSM_TZ_LOG=y +CONFIG_SENSORS_SSC=y +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT3_FS=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_EXT4_ENCRYPTION=y +CONFIG_EXT4_FS_ENCRYPTION=y +CONFIG_EXT4_FS_ICE_ENCRYPTION=y +CONFIG_FUSE_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_ECRYPT_FS=y +CONFIG_ECRYPT_FS_MESSAGING=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ISO8859_1=y +CONFIG_PRINTK_TIME=y +CONFIG_DEBUG_INFO=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_PANIC_TIMEOUT=5 +CONFIG_SCHEDSTATS=y +CONFIG_TIMER_STATS=y +# CONFIG_DEBUG_PREEMPT is not set +CONFIG_IPC_LOGGING=y +CONFIG_CPU_FREQ_SWITCH_PROFILER=y +CONFIG_DEBUG_SET_MODULE_RONX=y +CONFIG_DEBUG_ALIGN_RODATA=y +CONFIG_CORESIGHT=y +CONFIG_CORESIGHT_EVENT=y +CONFIG_CORESIGHT_LINK_AND_SINK_TMC=y +CONFIG_CORESIGHT_QCOM_REPLICATOR=y +CONFIG_CORESIGHT_STM=y +CONFIG_CORESIGHT_HWEVENT=y +CONFIG_CORESIGHT_CTI=y +CONFIG_CORESIGHT_TPDA=y +CONFIG_CORESIGHT_TPDM=y +CONFIG_CORESIGHT_QPDI=y +CONFIG_CORESIGHT_SOURCE_DUMMY=y +CONFIG_PFK=y +CONFIG_SECURITY=y +CONFIG_SECURITY_SELINUX=y +CONFIG_SECURITY_SMACK=y +CONFIG_CRYPTO_ECHAINIV=y +CONFIG_CRYPTO_XCBC=y +CONFIG_CRYPTO_MD4=y +CONFIG_CRYPTO_TWOFISH=y +CONFIG_CRYPTO_ANSI_CPRNG=y +CONFIG_CRYPTO_DEV_QCRYPTO=y +CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y +CONFIG_CRYPTO_DEV_QCEDEV=y +CONFIG_CRYPTO_DEV_OTA_CRYPTO=y +CONFIG_CRYPTO_DEV_QCOM_ICE=y +CONFIG_SYSTEM_TRUSTED_KEYS="verity.x509.pem" +CONFIG_ARM64_CRYPTO=y +CONFIG_CRYPTO_SHA1_ARM64_CE=y +CONFIG_CRYPTO_SHA2_ARM64_CE=y +CONFIG_CRYPTO_GHASH_ARM64_CE=y +CONFIG_CRYPTO_AES_ARM64_CE_CCM=y +CONFIG_CRYPTO_AES_ARM64_CE_BLK=y +CONFIG_CRYPTO_AES_ARM64_NEON_BLK=y +CONFIG_CRYPTO_CRC32_ARM64=y +CONFIG_QMI_ENCDEC=y diff --git a/arch/arm64/configs/msmcortex_mediabox_defconfig b/arch/arm64/configs/msmcortex_mediabox_defconfig index 3322f8fa11fc..28d900cf5b18 100644 --- a/arch/arm64/configs/msmcortex_mediabox_defconfig +++ b/arch/arm64/configs/msmcortex_mediabox_defconfig @@ -4,6 +4,9 @@ CONFIG_AUDIT=y CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y CONFIG_IRQ_TIME_ACCOUNTING=y +CONFIG_TASKSTATS=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y CONFIG_RCU_EXPERT=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y @@ -242,7 +245,7 @@ CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=8192 CONFIG_QSEECOM=y CONFIG_HDCP_QSEECOM=y -CONFIG_UID_CPUTIME=y +CONFIG_UID_SYS_STATS=y CONFIG_QPNP_MISC=y CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y diff --git a/arch/arm64/configs/sdm660-perf_defconfig b/arch/arm64/configs/sdm660-perf_defconfig index d293e1390e92..b75b4244aa72 100644 --- a/arch/arm64/configs/sdm660-perf_defconfig +++ b/arch/arm64/configs/sdm660-perf_defconfig @@ -558,7 +558,6 @@ CONFIG_QCOM_MEMORY_DUMP_V2=y CONFIG_ICNSS=y CONFIG_MSM_RUN_QUEUE_STATS=y CONFIG_MSM_BOOT_STATS=y -CONFIG_QCOM_CPUSS_DUMP=y CONFIG_MSM_ADSP_LOADER=y CONFIG_MSM_CDSP_LOADER=y CONFIG_MSM_PERFORMANCE=y diff --git a/arch/mips/kernel/crash.c b/arch/mips/kernel/crash.c index d434d5d5ae6e..610f0f3bdb34 100644 --- a/arch/mips/kernel/crash.c +++ b/arch/mips/kernel/crash.c @@ -14,12 +14,22 @@ static int crashing_cpu = -1; static cpumask_t cpus_in_crash = CPU_MASK_NONE; #ifdef CONFIG_SMP -static void crash_shutdown_secondary(void *ignore) +static void crash_shutdown_secondary(void *passed_regs) { - struct pt_regs *regs; + struct pt_regs *regs = passed_regs; int cpu = smp_processor_id(); - regs = task_pt_regs(current); + /* + * If we are passed registers, use those. Otherwise get the + * regs from the last interrupt, which should be correct, as + * we are in an interrupt. But if the regs are not there, + * pull them from the top of the stack. They are probably + * wrong, but we need something to keep from crashing again. + */ + if (!regs) + regs = get_irq_regs(); + if (!regs) + regs = task_pt_regs(current); if (!cpu_online(cpu)) return; diff --git a/arch/mips/kernel/elf.c b/arch/mips/kernel/elf.c index 4a4d9e067c89..3afffc30ee12 100644 --- a/arch/mips/kernel/elf.c +++ b/arch/mips/kernel/elf.c @@ -206,7 +206,7 @@ int arch_check_elf(void *_ehdr, bool has_interpreter, else if ((prog_req.fr1 && prog_req.frdefault) || (prog_req.single && !prog_req.frdefault)) /* Make sure 64-bit MIPS III/IV/64R1 will not pick FR1 */ - state->overall_fp_mode = ((current_cpu_data.fpu_id & MIPS_FPIR_F64) && + state->overall_fp_mode = ((raw_current_cpu_data.fpu_id & MIPS_FPIR_F64) && cpu_has_mips_r2_r6) ? FP_FR1 : FP_FR0; else if (prog_req.fr1) diff --git a/arch/mips/kernel/kgdb.c b/arch/mips/kernel/kgdb.c index de63d36af895..732d6171ac6a 100644 --- a/arch/mips/kernel/kgdb.c +++ b/arch/mips/kernel/kgdb.c @@ -244,9 +244,6 @@ static int compute_signal(int tt) void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p) { int reg; - struct thread_info *ti = task_thread_info(p); - unsigned long ksp = (unsigned long)ti + THREAD_SIZE - 32; - struct pt_regs *regs = (struct pt_regs *)ksp - 1; #if (KGDB_GDB_REG_SIZE == 32) u32 *ptr = (u32 *)gdb_regs; #else @@ -254,25 +251,46 @@ void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p) #endif for (reg = 0; reg < 16; reg++) - *(ptr++) = regs->regs[reg]; + *(ptr++) = 0; /* S0 - S7 */ - for (reg = 16; reg < 24; reg++) - *(ptr++) = regs->regs[reg]; + *(ptr++) = p->thread.reg16; + *(ptr++) = p->thread.reg17; + *(ptr++) = p->thread.reg18; + *(ptr++) = p->thread.reg19; + *(ptr++) = p->thread.reg20; + *(ptr++) = p->thread.reg21; + *(ptr++) = p->thread.reg22; + *(ptr++) = p->thread.reg23; for (reg = 24; reg < 28; reg++) *(ptr++) = 0; /* GP, SP, FP, RA */ - for (reg = 28; reg < 32; reg++) - *(ptr++) = regs->regs[reg]; - - *(ptr++) = regs->cp0_status; - *(ptr++) = regs->lo; - *(ptr++) = regs->hi; - *(ptr++) = regs->cp0_badvaddr; - *(ptr++) = regs->cp0_cause; - *(ptr++) = regs->cp0_epc; + *(ptr++) = (long)p; + *(ptr++) = p->thread.reg29; + *(ptr++) = p->thread.reg30; + *(ptr++) = p->thread.reg31; + + *(ptr++) = p->thread.cp0_status; + + /* lo, hi */ + *(ptr++) = 0; + *(ptr++) = 0; + + /* + * BadVAddr, Cause + * Ideally these would come from the last exception frame up the stack + * but that requires unwinding, otherwise we can't know much for sure. + */ + *(ptr++) = 0; + *(ptr++) = 0; + + /* + * PC + * use return address (RA), i.e. the moment after return from resume() + */ + *(ptr++) = p->thread.reg31; } void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long pc) diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S index edba294620db..f6fd0332c3a2 100644 --- a/arch/powerpc/kernel/entry_64.S +++ b/arch/powerpc/kernel/entry_64.S @@ -716,7 +716,7 @@ resume_kernel: addi r8,r1,INT_FRAME_SIZE /* Get the kprobed function entry */ - lwz r3,GPR1(r1) + ld r3,GPR1(r1) subi r3,r3,INT_FRAME_SIZE /* dst: Allocate a trampoline exception frame */ mr r4,r1 /* src: current exception frame */ mr r1,r3 /* Reroute the trampoline frame to r1 */ @@ -730,8 +730,8 @@ resume_kernel: addi r6,r6,8 bdnz 2b - /* Do real store operation to complete stwu */ - lwz r5,GPR1(r1) + /* Do real store operation to complete stdu */ + ld r5,GPR1(r1) std r8,0(r5) /* Clear _TIF_EMULATE_STACK_STORE flag */ diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h index 024f85f947ae..e2c0e4eab037 100644 --- a/arch/s390/include/asm/pgtable.h +++ b/arch/s390/include/asm/pgtable.h @@ -829,6 +829,8 @@ static inline void set_pte_at(struct mm_struct *mm, unsigned long addr, { pgste_t pgste; + if (pte_present(entry)) + pte_val(entry) &= ~_PAGE_UNUSED; if (mm_has_pgste(mm)) { pgste = pgste_get_lock(ptep); pgste_val(pgste) &= ~_PGSTE_GPS_ZERO; diff --git a/arch/sparc/include/asm/pgtable_64.h b/arch/sparc/include/asm/pgtable_64.h index 408b715c95a5..9d81579f3d54 100644 --- a/arch/sparc/include/asm/pgtable_64.h +++ b/arch/sparc/include/asm/pgtable_64.h @@ -668,26 +668,27 @@ static inline unsigned long pmd_pfn(pmd_t pmd) return pte_pfn(pte); } -#ifdef CONFIG_TRANSPARENT_HUGEPAGE -static inline unsigned long pmd_dirty(pmd_t pmd) +#define __HAVE_ARCH_PMD_WRITE +static inline unsigned long pmd_write(pmd_t pmd) { pte_t pte = __pte(pmd_val(pmd)); - return pte_dirty(pte); + return pte_write(pte); } -static inline unsigned long pmd_young(pmd_t pmd) +#ifdef CONFIG_TRANSPARENT_HUGEPAGE +static inline unsigned long pmd_dirty(pmd_t pmd) { pte_t pte = __pte(pmd_val(pmd)); - return pte_young(pte); + return pte_dirty(pte); } -static inline unsigned long pmd_write(pmd_t pmd) +static inline unsigned long pmd_young(pmd_t pmd) { pte_t pte = __pte(pmd_val(pmd)); - return pte_write(pte); + return pte_young(pte); } static inline unsigned long pmd_trans_huge(pmd_t pmd) diff --git a/arch/sparc/mm/init_64.c b/arch/sparc/mm/init_64.c index 3d3414c14792..965655afdbb6 100644 --- a/arch/sparc/mm/init_64.c +++ b/arch/sparc/mm/init_64.c @@ -1493,7 +1493,7 @@ bool kern_addr_valid(unsigned long addr) if ((long)addr < 0L) { unsigned long pa = __pa(addr); - if ((addr >> max_phys_bits) != 0UL) + if ((pa >> max_phys_bits) != 0UL) return false; return pfn_valid(pa >> PAGE_SHIFT); diff --git a/arch/x86/include/asm/pmem.h b/arch/x86/include/asm/pmem.h index d8ce3ec816ab..bd8ce6bcdfc9 100644 --- a/arch/x86/include/asm/pmem.h +++ b/arch/x86/include/asm/pmem.h @@ -72,8 +72,8 @@ static inline void arch_wmb_pmem(void) * @size: number of bytes to write back * * Write back a cache range using the CLWB (cache line write back) - * instruction. This function requires explicit ordering with an - * arch_wmb_pmem() call. This API is internal to the x86 PMEM implementation. + * instruction. Note that @size is internally rounded up to be cache + * line size aligned. */ static inline void __arch_wb_cache_pmem(void *vaddr, size_t size) { @@ -87,15 +87,6 @@ static inline void __arch_wb_cache_pmem(void *vaddr, size_t size) clwb(p); } -/* - * copy_from_iter_nocache() on x86 only uses non-temporal stores for iovec - * iterators, so for other types (bvec & kvec) we must do a cache write-back. - */ -static inline bool __iter_needs_pmem_wb(struct iov_iter *i) -{ - return iter_is_iovec(i) == false; -} - /** * arch_copy_from_iter_pmem - copy data from an iterator to PMEM * @addr: PMEM destination address @@ -114,8 +105,36 @@ static inline size_t arch_copy_from_iter_pmem(void __pmem *addr, size_t bytes, /* TODO: skip the write-back by always using non-temporal stores */ len = copy_from_iter_nocache(vaddr, bytes, i); - if (__iter_needs_pmem_wb(i)) - __arch_wb_cache_pmem(vaddr, bytes); + /* + * In the iovec case on x86_64 copy_from_iter_nocache() uses + * non-temporal stores for the bulk of the transfer, but we need + * to manually flush if the transfer is unaligned. A cached + * memory copy is used when destination or size is not naturally + * aligned. That is: + * - Require 8-byte alignment when size is 8 bytes or larger. + * - Require 4-byte alignment when size is 4 bytes. + * + * In the non-iovec case the entire destination needs to be + * flushed. + */ + if (iter_is_iovec(i)) { + unsigned long flushed, dest = (unsigned long) addr; + + if (bytes < 8) { + if (!IS_ALIGNED(dest, 4) || (bytes != 4)) + __arch_wb_cache_pmem(addr, 1); + } else { + if (!IS_ALIGNED(dest, 8)) { + dest = ALIGN(dest, boot_cpu_data.x86_clflush_size); + __arch_wb_cache_pmem(addr, 1); + } + + flushed = dest - (unsigned long) addr; + if (bytes > flushed && !IS_ALIGNED(bytes - flushed, 8)) + __arch_wb_cache_pmem(addr + bytes - 1, 1); + } + } else + __arch_wb_cache_pmem(addr, bytes); return len; } diff --git a/arch/x86/kernel/cpu/mcheck/mce_amd.c b/arch/x86/kernel/cpu/mcheck/mce_amd.c index e99b15077e94..62aca448726a 100644 --- a/arch/x86/kernel/cpu/mcheck/mce_amd.c +++ b/arch/x86/kernel/cpu/mcheck/mce_amd.c @@ -53,7 +53,7 @@ static const char * const th_names[] = { "load_store", "insn_fetch", "combined_unit", - "", + "decode_unit", "northbridge", "execution_unit", }; diff --git a/arch/x86/kernel/ftrace.c b/arch/x86/kernel/ftrace.c index eb6bd34582c6..1b96bfe09d42 100644 --- a/arch/x86/kernel/ftrace.c +++ b/arch/x86/kernel/ftrace.c @@ -977,6 +977,18 @@ void prepare_ftrace_return(unsigned long self_addr, unsigned long *parent, unsigned long return_hooker = (unsigned long) &return_to_handler; + /* + * When resuming from suspend-to-ram, this function can be indirectly + * called from early CPU startup code while the CPU is in real mode, + * which would fail miserably. Make sure the stack pointer is a + * virtual address. + * + * This check isn't as accurate as virt_addr_valid(), but it should be + * good enough for this purpose, and it's fast. + */ + if (unlikely((long)__builtin_frame_address(0) >= 0)) + return; + if (unlikely(ftrace_graph_is_dead())) return; diff --git a/arch/x86/xen/time.c b/arch/x86/xen/time.c index f1ba6a092854..8846257d8792 100644 --- a/arch/x86/xen/time.c +++ b/arch/x86/xen/time.c @@ -343,11 +343,11 @@ static int xen_vcpuop_set_next_event(unsigned long delta, WARN_ON(!clockevent_state_oneshot(evt)); single.timeout_abs_ns = get_abs_timeout(delta); - single.flags = VCPU_SSHOTTMR_future; + /* Get an event anyway, even if the timeout is already expired */ + single.flags = 0; ret = HYPERVISOR_vcpu_op(VCPUOP_set_singleshot_timer, cpu, &single); - - BUG_ON(ret != 0 && ret != -ETIME); + BUG_ON(ret != 0); return ret; } diff --git a/block/genhd.c b/block/genhd.c index 7f1e8f81ceb4..de2a6162e3f3 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -673,7 +673,6 @@ void del_gendisk(struct gendisk *disk) kobject_put(disk->part0.holder_dir); kobject_put(disk->slave_dir); - disk->driverfs_dev = NULL; if (!sysfs_deprecated) sysfs_remove_link(block_depr, dev_name(disk_to_dev(disk))); pm_runtime_set_memalloc_noio(disk_to_dev(disk), false); diff --git a/crypto/testmgr.c b/crypto/testmgr.c index 8374ca8b6579..6d4da8fd24fd 100644 --- a/crypto/testmgr.c +++ b/crypto/testmgr.c @@ -488,6 +488,8 @@ static int __test_aead(struct crypto_aead *tfm, int enc, aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, tcrypt_complete, &result); + iv_len = crypto_aead_ivsize(tfm); + for (i = 0, j = 0; i < tcount; i++) { if (template[i].np) continue; @@ -508,7 +510,6 @@ static int __test_aead(struct crypto_aead *tfm, int enc, memcpy(input, template[i].input, template[i].ilen); memcpy(assoc, template[i].assoc, template[i].alen); - iv_len = crypto_aead_ivsize(tfm); if (template[i].iv) memcpy(iv, template[i].iv, iv_len); else @@ -617,7 +618,7 @@ static int __test_aead(struct crypto_aead *tfm, int enc, j++; if (template[i].iv) - memcpy(iv, template[i].iv, MAX_IVLEN); + memcpy(iv, template[i].iv, iv_len); else memset(iv, 0, MAX_IVLEN); diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index fcd4ce6f78d5..1c2b846c5776 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c @@ -200,6 +200,7 @@ static int acpi_power_get_list_state(struct list_head *list, int *state) return -EINVAL; /* The state of the list is 'on' IFF all resources are 'on'. */ + cur_state = 0; list_for_each_entry(entry, list, node) { struct acpi_power_resource *resource = entry->resource; acpi_handle handle = resource->device.handle; diff --git a/drivers/bluetooth/btfm_slim.h b/drivers/bluetooth/btfm_slim.h index 5d105fba2193..e67c6964ee65 100644 --- a/drivers/bluetooth/btfm_slim.h +++ b/drivers/bluetooth/btfm_slim.h @@ -13,7 +13,7 @@ #define BTFM_SLIM_H #include <linux/slimbus/slimbus.h> -#define BTFMSLIM_DBG(fmt, arg...) pr_debug(fmt "\n", ## arg) +#define BTFMSLIM_DBG(fmt, arg...) pr_debug("%s: " fmt "\n", __func__, ## arg) #define BTFMSLIM_INFO(fmt, arg...) pr_info("%s: " fmt "\n", __func__, ## arg) #define BTFMSLIM_ERR(fmt, arg...) pr_err("%s: " fmt "\n", __func__, ## arg) diff --git a/drivers/bluetooth/btfm_slim_wcn3990.c b/drivers/bluetooth/btfm_slim_wcn3990.c index c93b29281e35..a451ff33103c 100644 --- a/drivers/bluetooth/btfm_slim_wcn3990.c +++ b/drivers/bluetooth/btfm_slim_wcn3990.c @@ -83,19 +83,34 @@ int btfm_slim_chrk_enable_port(struct btfmslim *btfmslim, uint8_t port_num, { int ret = 0; uint8_t reg_val = 0; + uint8_t port_bit = 0; uint16_t reg; BTFMSLIM_DBG("port(%d) enable(%d)", port_num, enable); if (rxport) { + if (enable) { + /* For SCO Rx, A2DP Rx */ + reg_val = 0x1; + port_bit = port_num - 0x10; + reg = CHRK_SB_PGD_RX_PORTn_MULTI_CHNL_0(port_bit); + BTFMSLIM_DBG("writing reg_val (%d) to reg(%x)", + reg_val, reg); + ret = btfm_slim_write(btfmslim, reg, 1, ®_val, IFD); + if (ret) { + BTFMSLIM_ERR("failed to write (%d) reg 0x%x", + ret, reg); + goto error; + } + } /* Port enable */ reg = CHRK_SB_PGD_PORT_RX_CFGN(port_num - 0x10); goto enable_disable_rxport; } - /* txport */ if (!enable) goto enable_disable_txport; - /* Multiple Channel Setting - only for FM Tx */ + /* txport */ + /* Multiple Channel Setting */ if (is_fm_port(port_num)) { reg_val = (0x1 << CHRK_SB_PGD_PORT_TX1_FM) | (0x1 << CHRK_SB_PGD_PORT_TX2_FM); @@ -105,6 +120,18 @@ int btfm_slim_chrk_enable_port(struct btfmslim *btfmslim, uint8_t port_num, BTFMSLIM_ERR("failed to write (%d) reg 0x%x", ret, reg); goto error; } + } else if (port_num == CHRK_SB_PGD_PORT_TX_SCO) { + /* SCO Tx */ + reg_val = 0x1 << CHRK_SB_PGD_PORT_TX_SCO; + reg = CHRK_SB_PGD_TX_PORTn_MULTI_CHNL_0(port_num); + BTFMSLIM_DBG("writing reg_val (%d) to reg(%x)", + reg_val, reg); + ret = btfm_slim_write(btfmslim, reg, 1, ®_val, IFD); + if (ret) { + BTFMSLIM_ERR("failed to write (%d) reg 0x%x", + ret, reg); + goto error; + } } /* Enable Tx port hw auto recovery for underrun or overrun error */ diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c index 7e44b38bbfca..b1432ccf5358 100644 --- a/drivers/char/adsprpc.c +++ b/drivers/char/adsprpc.c @@ -2126,11 +2126,9 @@ void fastrpc_glink_notify_state(void *handle, const void *priv, unsigned event) link->port_state = FASTRPC_LINK_DISCONNECTED; break; case GLINK_REMOTE_DISCONNECTED: - if (me->channel[cid].chan && - link->link_state == FASTRPC_LINK_STATE_UP) { + if (me->channel[cid].chan) { fastrpc_glink_close(me->channel[cid].chan, cid); me->channel[cid].chan = 0; - link->port_state = FASTRPC_LINK_DISCONNECTED; } break; default: @@ -2296,10 +2294,9 @@ static int fastrpc_glink_open(int cid) if (err) goto bail; - if (link->port_state == FASTRPC_LINK_CONNECTED || - link->port_state == FASTRPC_LINK_CONNECTING) { + VERIFY(err, (link->port_state == FASTRPC_LINK_DISCONNECTED)); + if (err) goto bail; - } link->port_state = FASTRPC_LINK_CONNECTING; cfg->priv = (void *)(uintptr_t)cid; @@ -2458,7 +2455,9 @@ static int fastrpc_channel_open(struct fastrpc_file *fl) if ((kref_get_unless_zero(&me->channel[cid].kref) == 0) || (me->channel[cid].chan == 0)) { if (me->glink) { - fastrpc_glink_register(cid, me); + VERIFY(err, 0 == fastrpc_glink_register(cid, me)); + if (err) + goto bail; VERIFY(err, 0 == fastrpc_glink_open(cid)); } else { VERIFY(err, !smd_named_open_on_edge(FASTRPC_SMD_GUID, diff --git a/drivers/char/diag/diag_memorydevice.c b/drivers/char/diag/diag_memorydevice.c index bd34e6cceec0..a5d92c51cc0b 100644 --- a/drivers/char/diag/diag_memorydevice.c +++ b/drivers/char/diag/diag_memorydevice.c @@ -252,6 +252,7 @@ int diag_md_copy_to_user(char __user *buf, int *pret, size_t buf_size, uint8_t drain_again = 0; uint8_t peripheral = 0; struct diag_md_session_t *session_info = NULL; + struct pid *pid_struct = NULL; mutex_lock(&driver->diagfwd_untag_mutex); @@ -278,6 +279,14 @@ int diag_md_copy_to_user(char __user *buf, int *pret, size_t buf_size, if ((info && (info->peripheral_mask & MD_PERIPHERAL_MASK(peripheral)) == 0)) goto drop_data; + pid_struct = find_get_pid(session_info->pid); + if (!pid_struct) { + err = -ESRCH; + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "diag: No such md_session_map[%d] with pid = %d err=%d exists..\n", + peripheral, session_info->pid, err); + goto drop_data; + } /* * If the data is from remote processor, copy the remote * token first @@ -297,27 +306,35 @@ int diag_md_copy_to_user(char __user *buf, int *pret, size_t buf_size, } if (i > 0) { remote_token = diag_get_remote(i); - err = copy_to_user(buf + ret, &remote_token, - sizeof(int)); + if (get_pid_task(pid_struct, PIDTYPE_PID)) { + err = copy_to_user(buf + ret, + &remote_token, + sizeof(int)); + if (err) + goto drop_data; + ret += sizeof(int); + } + } + + /* Copy the length of data being passed */ + if (get_pid_task(pid_struct, PIDTYPE_PID)) { + err = copy_to_user(buf + ret, + (void *)&(entry->len), + sizeof(int)); if (err) goto drop_data; ret += sizeof(int); } - /* Copy the length of data being passed */ - err = copy_to_user(buf + ret, (void *)&(entry->len), - sizeof(int)); - if (err) - goto drop_data; - ret += sizeof(int); - /* Copy the actual data being passed */ - err = copy_to_user(buf + ret, (void *)entry->buf, - entry->len); - if (err) - goto drop_data; - ret += entry->len; - + if (get_pid_task(pid_struct, PIDTYPE_PID)) { + err = copy_to_user(buf + ret, + (void *)entry->buf, + entry->len); + if (err) + goto drop_data; + ret += entry->len; + } /* * The data is now copied to the user space client, * Notify that the write is complete and delete its @@ -339,7 +356,15 @@ drop_data: } *pret = ret; - err = copy_to_user(buf + sizeof(int), (void *)&num_data, sizeof(int)); + if (pid_struct && get_pid_task(pid_struct, PIDTYPE_PID)) { + err = copy_to_user(buf + sizeof(int), + (void *)&num_data, + sizeof(int)); + } else { + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "diag: md_session_map[%d] with pid = %d Exited..\n", + peripheral, driver->md_session_map[peripheral]->pid); + } diag_ws_on_copy_complete(DIAG_WS_MUX); if (drain_again) chk_logging_wakeup(); diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c index 682c035c5bd4..dc2d9fc4282c 100644 --- a/drivers/char/diag/diagchar_core.c +++ b/drivers/char/diag/diagchar_core.c @@ -2341,7 +2341,9 @@ long diagchar_ioctl(struct file *filp, mutex_unlock(&driver->dci_mutex); break; case DIAG_IOCTL_DCI_EVENT_STATUS: + mutex_lock(&driver->dci_mutex); result = diag_ioctl_dci_event_status(ioarg); + mutex_unlock(&driver->dci_mutex); break; case DIAG_IOCTL_DCI_CLEAR_LOGS: mutex_lock(&driver->dci_mutex); diff --git a/drivers/clk/sunxi/clk-simple-gates.c b/drivers/clk/sunxi/clk-simple-gates.c index 0214c6548afd..97cb4221de25 100644 --- a/drivers/clk/sunxi/clk-simple-gates.c +++ b/drivers/clk/sunxi/clk-simple-gates.c @@ -98,6 +98,8 @@ static void __init sunxi_simple_gates_init(struct device_node *node) sunxi_simple_gates_setup(node, NULL, 0); } +CLK_OF_DECLARE(sun4i_a10_gates, "allwinner,sun4i-a10-gates-clk", + sunxi_simple_gates_init); CLK_OF_DECLARE(sun4i_a10_apb0, "allwinner,sun4i-a10-apb0-gates-clk", sunxi_simple_gates_init); CLK_OF_DECLARE(sun4i_a10_apb1, "allwinner,sun4i-a10-apb1-gates-clk", diff --git a/drivers/gpu/drm/amd/amdgpu/kv_dpm.c b/drivers/gpu/drm/amd/amdgpu/kv_dpm.c index 7e9154c7f1db..d1c9525d81eb 100644 --- a/drivers/gpu/drm/amd/amdgpu/kv_dpm.c +++ b/drivers/gpu/drm/amd/amdgpu/kv_dpm.c @@ -2258,7 +2258,7 @@ static void kv_apply_state_adjust_rules(struct amdgpu_device *adev, if (pi->caps_stable_p_state) { stable_p_state_sclk = (max_limits->sclk * 75) / 100; - for (i = table->count - 1; i >= 0; i++) { + for (i = table->count - 1; i >= 0; i--) { if (stable_p_state_sclk >= table->entries[i].clk) { stable_p_state_sclk = table->entries[i].clk; break; diff --git a/drivers/gpu/drm/msm/adreno/a5xx_snapshot.c b/drivers/gpu/drm/msm/adreno/a5xx_snapshot.c index 5a2edb0ea518..690e6f546e60 100644 --- a/drivers/gpu/drm/msm/adreno/a5xx_snapshot.c +++ b/drivers/gpu/drm/msm/adreno/a5xx_snapshot.c @@ -733,6 +733,35 @@ static void a5xx_snapshot_indexed_registers(struct msm_gpu *gpu, } } +static void a5xx_snapshot_preemption(struct msm_gpu *gpu, struct msm_snapshot + *snapshot) +{ + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu); + struct msm_snapshot_gpu_object header = { + .type = SNAPSHOT_GPU_OBJECT_GLOBAL, + .size = A5XX_PREEMPT_RECORD_SIZE >> 2, + .pt_base = 0, + }; + int index; + + if (gpu->nr_rings <= 1) + return; + + for (index = 0; index < gpu->nr_rings; index++) { + + header.gpuaddr = a5xx_gpu->preempt_iova[index]; + + if (!SNAPSHOT_HEADER(snapshot, header, + SNAPSHOT_SECTION_GPU_OBJECT_V2, + A5XX_PREEMPT_RECORD_SIZE >> 2)) + return; + + SNAPSHOT_MEMCPY(snapshot, a5xx_gpu->preempt[index], + A5XX_PREEMPT_RECORD_SIZE); + } +} + int a5xx_snapshot(struct msm_gpu *gpu, struct msm_snapshot *snapshot) { struct crashdump crashdump = { 0 }; @@ -787,6 +816,9 @@ int a5xx_snapshot(struct msm_gpu *gpu, struct msm_snapshot *snapshot) /* CP MERCIU */ a5xx_snapshot_cp_merciu(gpu, snapshot); + /* Preemption records*/ + a5xx_snapshot_preemption(gpu, snapshot); + crashdump_destroy(gpu, &crashdump); snapshot->priv = NULL; diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c index 1ff3ee2bdca6..c377f3759e67 100644 --- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c +++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c @@ -934,7 +934,6 @@ static void _sde_hdmi_hotplug_work(struct work_struct *work) } else sde_free_edid((void **)&sde_hdmi->edid_ctrl); - sde_hdmi_notify_clients(connector, sde_hdmi->connected); drm_helper_hpd_irq_event(connector->dev); } @@ -964,8 +963,7 @@ static void _sde_hdmi_connector_irq(struct sde_hdmi *sde_hdmi) hpd_int_ctrl |= HDMI_HPD_INT_CTRL_INT_CONNECT; hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL, hpd_int_ctrl); - if (!sde_hdmi->non_pluggable) - queue_work(hdmi->workq, &sde_hdmi->hpd_work); + queue_work(hdmi->workq, &sde_hdmi->hpd_work); } } @@ -1054,6 +1052,25 @@ static int _sde_hdmi_get_cable_status(struct platform_device *pdev, u32 vote) return hdmi->power_on && display->connected; } +static void _sde_hdmi_audio_codec_ready(struct platform_device *pdev) +{ + struct sde_hdmi *display = platform_get_drvdata(pdev); + + if (!display) { + SDE_ERROR("invalid param(s), display %pK\n", display); + return; + } + + mutex_lock(&display->display_lock); + if (!display->codec_ready) { + display->codec_ready = true; + + if (display->client_notify_pending) + sde_hdmi_notify_clients(display, display->connected); + } + mutex_unlock(&display->display_lock); +} + static int _sde_hdmi_ext_disp_init(struct sde_hdmi *display) { int rc = 0; @@ -1073,6 +1090,8 @@ static int _sde_hdmi_ext_disp_init(struct sde_hdmi *display) _sde_hdmi_get_audio_edid_blk; display->ext_audio_data.codec_ops.cable_status = _sde_hdmi_get_cable_status; + display->ext_audio_data.codec_ops.codec_ready = + _sde_hdmi_audio_codec_ready; if (!display->pdev->dev.of_node) { SDE_ERROR("[%s]cannot find sde_hdmi of_node\n", display->name); @@ -1101,17 +1120,14 @@ static int _sde_hdmi_ext_disp_init(struct sde_hdmi *display) return rc; } -void sde_hdmi_notify_clients(struct drm_connector *connector, - bool connected) +void sde_hdmi_notify_clients(struct sde_hdmi *display, bool connected) { - struct sde_connector *c_conn = to_sde_connector(connector); - struct sde_hdmi *display = (struct sde_hdmi *)c_conn->display; int state = connected ? EXT_DISPLAY_CABLE_CONNECT : EXT_DISPLAY_CABLE_DISCONNECT; if (display && display->ext_audio_data.intf_ops.hpd) { struct hdmi *hdmi = display->ctrl.ctrl; - u32 flags = MSM_EXT_DISP_HPD_VIDEO; + u32 flags = MSM_EXT_DISP_HPD_ASYNC_VIDEO; if (hdmi->hdmi_mode) flags |= MSM_EXT_DISP_HPD_AUDIO; @@ -1121,21 +1137,6 @@ void sde_hdmi_notify_clients(struct drm_connector *connector, } } -void sde_hdmi_ack_state(struct drm_connector *connector, - enum drm_connector_status status) -{ - struct sde_connector *c_conn = to_sde_connector(connector); - struct sde_hdmi *display = (struct sde_hdmi *)c_conn->display; - - if (display) { - struct hdmi *hdmi = display->ctrl.ctrl; - - if (hdmi->hdmi_mode && display->ext_audio_data.intf_ops.notify) - display->ext_audio_data.intf_ops.notify( - display->ext_pdev, status); - } -} - void sde_hdmi_set_mode(struct hdmi *hdmi, bool power_on) { uint32_t ctrl = 0; @@ -1427,8 +1428,8 @@ int sde_hdmi_get_info(struct msm_display_info *info, MSM_DISPLAY_CAP_EDID | MSM_DISPLAY_CAP_VID_MODE; } info->is_connected = hdmi_display->connected; - info->max_width = 1920; - info->max_height = 1080; + info->max_width = 4096; + info->max_height = 2160; info->compression = MSM_DISPLAY_COMPRESS_NONE; mutex_unlock(&hdmi_display->display_lock); diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h index ecdace10d0c3..ffa9a27e7dfe 100644 --- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h +++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h @@ -84,6 +84,8 @@ struct sde_hdmi_ctrl { * @connected: If HDMI display is connected. * @is_tpg_enabled: TPG state. * @hpd_work: HPD work structure. + * @codec_ready: If audio codec is ready. + * @client_notify_pending: If there is client notification pending. * @root: Debug fs root entry. */ struct sde_hdmi { @@ -109,6 +111,8 @@ struct sde_hdmi { bool is_tpg_enabled; struct work_struct hpd_work; + bool codec_ready; + bool client_notify_pending; /* DEBUG FS */ struct dentry *root; @@ -379,13 +383,12 @@ int sde_hdmi_config_avmute(struct hdmi *hdmi, bool set); /** * sde_hdmi_notify_clients() - notify hdmi clients of the connection status. - * @connector: Handle to the drm_connector. + * @display: Handle to sde_hdmi. * @connected: connection status. * * Return: void. */ -void sde_hdmi_notify_clients(struct drm_connector *connector, - bool connected); +void sde_hdmi_notify_clients(struct sde_hdmi *display, bool connected); /** * sde_hdmi_ack_state() - acknowledge the connection status. diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c index 6c82c3d4826d..34268aaedfc0 100644 --- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c +++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c @@ -372,6 +372,8 @@ static void _sde_hdmi_bridge_pre_enable(struct drm_bridge *bridge) struct sde_hdmi_bridge *sde_hdmi_bridge = to_hdmi_bridge(bridge); struct hdmi *hdmi = sde_hdmi_bridge->hdmi; struct hdmi_phy *phy = hdmi->phy; + struct sde_connector *c_conn = to_sde_connector(hdmi->connector); + struct sde_hdmi *display = (struct sde_hdmi *)c_conn->display; DRM_DEBUG("power up"); @@ -388,41 +390,20 @@ static void _sde_hdmi_bridge_pre_enable(struct drm_bridge *bridge) if (hdmi->hdcp_ctrl && hdmi->is_hdcp_supported) hdmi_hdcp_ctrl_on(hdmi->hdcp_ctrl); - sde_hdmi_ack_state(hdmi->connector, EXT_DISPLAY_CABLE_CONNECT); -} - -static void sde_hdmi_force_update_audio(struct drm_connector *connector, - enum drm_connector_status status) -{ - struct sde_connector *c_conn = to_sde_connector(connector); - struct sde_hdmi *display = (struct sde_hdmi *)c_conn->display; - - if (display && display->non_pluggable) { - display->ext_audio_data.intf_ops.hpd(display->ext_pdev, - display->ext_audio_data.type, - status, - MSM_EXT_DISP_HPD_AUDIO); - } + mutex_lock(&display->display_lock); + if (display->codec_ready) + sde_hdmi_notify_clients(display, display->connected); + else + display->client_notify_pending = true; + mutex_unlock(&display->display_lock); } static void _sde_hdmi_bridge_enable(struct drm_bridge *bridge) { - struct sde_hdmi_bridge *sde_hdmi_bridge = to_hdmi_bridge(bridge); - struct hdmi *hdmi = sde_hdmi_bridge->hdmi; - - /* force update audio ops when there's no HPD event */ - sde_hdmi_force_update_audio(hdmi->connector, - EXT_DISPLAY_CABLE_CONNECT); } static void _sde_hdmi_bridge_disable(struct drm_bridge *bridge) { - struct sde_hdmi_bridge *sde_hdmi_bridge = to_hdmi_bridge(bridge); - struct hdmi *hdmi = sde_hdmi_bridge->hdmi; - - /* force update audio ops when there's no HPD event */ - sde_hdmi_force_update_audio(hdmi->connector, - EXT_DISPLAY_CABLE_DISCONNECT); } static void _sde_hdmi_bridge_post_disable(struct drm_bridge *bridge) @@ -430,6 +411,10 @@ static void _sde_hdmi_bridge_post_disable(struct drm_bridge *bridge) struct sde_hdmi_bridge *sde_hdmi_bridge = to_hdmi_bridge(bridge); struct hdmi *hdmi = sde_hdmi_bridge->hdmi; struct hdmi_phy *phy = hdmi->phy; + struct sde_connector *c_conn = to_sde_connector(hdmi->connector); + struct sde_hdmi *display = (struct sde_hdmi *)c_conn->display; + + sde_hdmi_notify_clients(display, display->connected); if (hdmi->hdcp_ctrl && hdmi->is_hdcp_supported) hdmi_hdcp_ctrl_off(hdmi->hdcp_ctrl); @@ -446,8 +431,6 @@ static void _sde_hdmi_bridge_post_disable(struct drm_bridge *bridge) _sde_hdmi_bridge_power_off(bridge); hdmi->power_on = false; } - - sde_hdmi_ack_state(hdmi->connector, EXT_DISPLAY_CABLE_DISCONNECT); } static void _sde_hdmi_bridge_set_avi_infoframe(struct hdmi *hdmi, diff --git a/drivers/gpu/drm/msm/msm_snapshot.h b/drivers/gpu/drm/msm/msm_snapshot.h index 247e1358c885..fd560b2129f1 100644 --- a/drivers/gpu/drm/msm/msm_snapshot.h +++ b/drivers/gpu/drm/msm/msm_snapshot.h @@ -71,8 +71,8 @@ static inline bool _snapshot_header(struct msm_snapshot *snapshot, */ #define SNAPSHOT_HEADER(_snapshot, _header, _id, _dwords) \ _snapshot_header((_snapshot), \ - (struct msm_snapshot_section_header *) &(header), \ - sizeof(header), (_dwords) << 2, (_id)) + (struct msm_snapshot_section_header *) &(_header), \ + sizeof(_header), (_dwords) << 2, (_id)) struct msm_gpu; diff --git a/drivers/gpu/drm/msm/msm_snapshot_api.h b/drivers/gpu/drm/msm/msm_snapshot_api.h index 9f0adb9ee784..7ad6f0498423 100644 --- a/drivers/gpu/drm/msm/msm_snapshot_api.h +++ b/drivers/gpu/drm/msm/msm_snapshot_api.h @@ -118,4 +118,17 @@ struct msm_snapshot_shader { __u32 size; } __packed; +#define SNAPSHOT_GPU_OBJECT_SHADER 1 +#define SNAPSHOT_GPU_OBJECT_IB 2 +#define SNAPSHOT_GPU_OBJECT_GENERIC 3 +#define SNAPSHOT_GPU_OBJECT_DRAW 4 +#define SNAPSHOT_GPU_OBJECT_GLOBAL 5 + +struct msm_snapshot_gpu_object { + struct msm_snapshot_section_header header; + __u32 type; + __u64 gpuaddr; + __u64 pt_base; + __u64 size; +} __packed; #endif diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c index 41322045ced3..adfe9e54e6f4 100644 --- a/drivers/gpu/drm/msm/sde/sde_crtc.c +++ b/drivers/gpu/drm/msm/sde/sde_crtc.c @@ -1134,12 +1134,12 @@ static int sde_crtc_atomic_check(struct drm_crtc *crtc, /* get plane state for all drm planes associated with crtc state */ drm_atomic_crtc_state_for_each_plane(plane, state) { - pstate = drm_atomic_get_plane_state(state->state, plane); + pstate = drm_atomic_get_existing_plane_state( + state->state, plane); if (IS_ERR_OR_NULL(pstate)) { - rc = PTR_ERR(pstate); - SDE_ERROR("%s: failed to get plane%d state, %d\n", + SDE_DEBUG("%s: failed to get plane%d state, %d\n", sde_crtc->name, plane->base.id, rc); - goto end; + continue; } if (cnt >= ARRAY_SIZE(pstates)) continue; diff --git a/drivers/gpu/drm/msm/sde/sde_rm.c b/drivers/gpu/drm/msm/sde/sde_rm.c index 1d27b27d265c..fca0768e2734 100644 --- a/drivers/gpu/drm/msm/sde/sde_rm.c +++ b/drivers/gpu/drm/msm/sde/sde_rm.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1074,12 +1074,6 @@ void _sde_rm_release_rsvp( } kfree(rsvp); - - (void) msm_property_set_property( - sde_connector_get_propinfo(conn), - sde_connector_get_property_values(conn->state), - CONNECTOR_PROP_TOPOLOGY_NAME, - SDE_RM_TOPOLOGY_UNKNOWN); } void sde_rm_release(struct sde_rm *rm, struct drm_encoder *enc) @@ -1115,6 +1109,12 @@ void sde_rm_release(struct sde_rm *rm, struct drm_encoder *enc) SDE_DEBUG("release rsvp[s%de%d]\n", rsvp->seq, rsvp->enc_id); _sde_rm_release_rsvp(rm, rsvp, conn); + + (void) msm_property_set_property( + sde_connector_get_propinfo(conn), + sde_connector_get_property_values(conn->state), + CONNECTOR_PROP_TOPOLOGY_NAME, + SDE_RM_TOPOLOGY_UNKNOWN); } } @@ -1132,8 +1132,12 @@ static int _sde_rm_commit_rsvp( sde_connector_get_property_values(conn_state), CONNECTOR_PROP_TOPOLOGY_NAME, rsvp->topology); - if (ret) + if (ret) { + SDE_ERROR("failed to set topology name property, ret %d\n", + ret); _sde_rm_release_rsvp(rm, rsvp, conn_state->connector); + return ret; + } /* Swap next rsvp to be the active */ for (type = 0; type < SDE_HW_BLK_MAX; type++) { @@ -1226,6 +1230,12 @@ int sde_rm_reserve( _sde_rm_release_rsvp(rm, rsvp_cur, conn_state->connector); rsvp_cur = NULL; _sde_rm_print_rsvps(rm, SDE_RM_STAGE_AFTER_CLEAR); + (void) msm_property_set_property( + sde_connector_get_propinfo( + conn_state->connector), + sde_connector_get_property_values(conn_state), + CONNECTOR_PROP_TOPOLOGY_NAME, + SDE_RM_TOPOLOGY_UNKNOWN); } /* Check the proposed reservation, store it in hw's "next" field */ diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c index 1ef37c727572..d037454fe7b8 100644 --- a/drivers/hv/channel.c +++ b/drivers/hv/channel.c @@ -73,7 +73,6 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size, void *in, *out; unsigned long flags; int ret, err = 0; - unsigned long t; struct page *page; spin_lock_irqsave(&newchannel->lock, flags); @@ -183,11 +182,7 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size, goto error1; } - t = wait_for_completion_timeout(&open_info->waitevent, 5*HZ); - if (t == 0) { - err = -ETIMEDOUT; - goto error1; - } + wait_for_completion(&open_info->waitevent); spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags); list_del(&open_info->msglistentry); @@ -375,7 +370,7 @@ int vmbus_establish_gpadl(struct vmbus_channel *channel, void *kbuffer, struct vmbus_channel_gpadl_header *gpadlmsg; struct vmbus_channel_gpadl_body *gpadl_body; struct vmbus_channel_msginfo *msginfo = NULL; - struct vmbus_channel_msginfo *submsginfo; + struct vmbus_channel_msginfo *submsginfo, *tmp; u32 msgcount; struct list_head *curr; u32 next_gpadl_handle; @@ -437,6 +432,13 @@ cleanup: list_del(&msginfo->msglistentry); spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags); + if (msgcount > 1) { + list_for_each_entry_safe(submsginfo, tmp, &msginfo->submsglist, + msglistentry) { + kfree(submsginfo); + } + } + kfree(msginfo); return ret; } diff --git a/drivers/hv/connection.c b/drivers/hv/connection.c index 4fc2e8836e60..2bbc53025549 100644 --- a/drivers/hv/connection.c +++ b/drivers/hv/connection.c @@ -429,7 +429,7 @@ int vmbus_post_msg(void *buffer, size_t buflen) union hv_connection_id conn_id; int ret = 0; int retries = 0; - u32 msec = 1; + u32 usec = 1; conn_id.asu32 = 0; conn_id.u.id = VMBUS_MESSAGE_CONNECTION_ID; @@ -462,9 +462,9 @@ int vmbus_post_msg(void *buffer, size_t buflen) } retries++; - msleep(msec); - if (msec < 2048) - msec *= 2; + udelay(usec); + if (usec < 2048) + usec *= 2; } return ret; } diff --git a/drivers/hv/hv.c b/drivers/hv/hv.c index ddbf7e7e0d98..8ce1f2e22912 100644 --- a/drivers/hv/hv.c +++ b/drivers/hv/hv.c @@ -305,9 +305,10 @@ void hv_cleanup(bool crash) hypercall_msr.as_uint64 = 0; wrmsrl(HV_X64_MSR_REFERENCE_TSC, hypercall_msr.as_uint64); - if (!crash) + if (!crash) { vfree(hv_context.tsc_page); - hv_context.tsc_page = NULL; + hv_context.tsc_page = NULL; + } } #endif } diff --git a/drivers/hv/hv_balloon.c b/drivers/hv/hv_balloon.c index 43af91362be5..354da7f207b7 100644 --- a/drivers/hv/hv_balloon.c +++ b/drivers/hv/hv_balloon.c @@ -430,16 +430,27 @@ struct dm_info_msg { * currently hot added. We hot add in multiples of 128M * chunks; it is possible that we may not be able to bring * online all the pages in the region. The range - * covered_end_pfn defines the pages that can + * covered_start_pfn:covered_end_pfn defines the pages that can * be brough online. */ struct hv_hotadd_state { struct list_head list; unsigned long start_pfn; + unsigned long covered_start_pfn; unsigned long covered_end_pfn; unsigned long ha_end_pfn; unsigned long end_pfn; + /* + * A list of gaps. + */ + struct list_head gap_list; +}; + +struct hv_hotadd_gap { + struct list_head list; + unsigned long start_pfn; + unsigned long end_pfn; }; struct balloon_state { @@ -595,18 +606,46 @@ static struct notifier_block hv_memory_nb = { .priority = 0 }; +/* Check if the particular page is backed and can be onlined and online it. */ +static void hv_page_online_one(struct hv_hotadd_state *has, struct page *pg) +{ + unsigned long cur_start_pgp; + unsigned long cur_end_pgp; + struct hv_hotadd_gap *gap; + + cur_start_pgp = (unsigned long)pfn_to_page(has->covered_start_pfn); + cur_end_pgp = (unsigned long)pfn_to_page(has->covered_end_pfn); + + /* The page is not backed. */ + if (((unsigned long)pg < cur_start_pgp) || + ((unsigned long)pg >= cur_end_pgp)) + return; + + /* Check for gaps. */ + list_for_each_entry(gap, &has->gap_list, list) { + cur_start_pgp = (unsigned long) + pfn_to_page(gap->start_pfn); + cur_end_pgp = (unsigned long) + pfn_to_page(gap->end_pfn); + if (((unsigned long)pg >= cur_start_pgp) && + ((unsigned long)pg < cur_end_pgp)) { + return; + } + } -static void hv_bring_pgs_online(unsigned long start_pfn, unsigned long size) + /* This frame is currently backed; online the page. */ + __online_page_set_limits(pg); + __online_page_increment_counters(pg); + __online_page_free(pg); +} + +static void hv_bring_pgs_online(struct hv_hotadd_state *has, + unsigned long start_pfn, unsigned long size) { int i; - for (i = 0; i < size; i++) { - struct page *pg; - pg = pfn_to_page(start_pfn + i); - __online_page_set_limits(pg); - __online_page_increment_counters(pg); - __online_page_free(pg); - } + for (i = 0; i < size; i++) + hv_page_online_one(has, pfn_to_page(start_pfn + i)); } static void hv_mem_hot_add(unsigned long start, unsigned long size, @@ -682,26 +721,25 @@ static void hv_online_page(struct page *pg) list_for_each(cur, &dm_device.ha_region_list) { has = list_entry(cur, struct hv_hotadd_state, list); - cur_start_pgp = (unsigned long)pfn_to_page(has->start_pfn); - cur_end_pgp = (unsigned long)pfn_to_page(has->covered_end_pfn); + cur_start_pgp = (unsigned long) + pfn_to_page(has->start_pfn); + cur_end_pgp = (unsigned long)pfn_to_page(has->end_pfn); - if (((unsigned long)pg >= cur_start_pgp) && - ((unsigned long)pg < cur_end_pgp)) { - /* - * This frame is currently backed; online the - * page. - */ - __online_page_set_limits(pg); - __online_page_increment_counters(pg); - __online_page_free(pg); - } + /* The page belongs to a different HAS. */ + if (((unsigned long)pg < cur_start_pgp) || + ((unsigned long)pg >= cur_end_pgp)) + continue; + + hv_page_online_one(has, pg); + break; } } -static bool pfn_covered(unsigned long start_pfn, unsigned long pfn_cnt) +static int pfn_covered(unsigned long start_pfn, unsigned long pfn_cnt) { struct list_head *cur; struct hv_hotadd_state *has; + struct hv_hotadd_gap *gap; unsigned long residual, new_inc; if (list_empty(&dm_device.ha_region_list)) @@ -716,6 +754,24 @@ static bool pfn_covered(unsigned long start_pfn, unsigned long pfn_cnt) */ if (start_pfn < has->start_pfn || start_pfn >= has->end_pfn) continue; + + /* + * If the current start pfn is not where the covered_end + * is, create a gap and update covered_end_pfn. + */ + if (has->covered_end_pfn != start_pfn) { + gap = kzalloc(sizeof(struct hv_hotadd_gap), GFP_ATOMIC); + if (!gap) + return -ENOMEM; + + INIT_LIST_HEAD(&gap->list); + gap->start_pfn = has->covered_end_pfn; + gap->end_pfn = start_pfn; + list_add_tail(&gap->list, &has->gap_list); + + has->covered_end_pfn = start_pfn; + } + /* * If the current hot add-request extends beyond * our current limit; extend it. @@ -732,19 +788,10 @@ static bool pfn_covered(unsigned long start_pfn, unsigned long pfn_cnt) has->end_pfn += new_inc; } - /* - * If the current start pfn is not where the covered_end - * is, update it. - */ - - if (has->covered_end_pfn != start_pfn) - has->covered_end_pfn = start_pfn; - - return true; - + return 1; } - return false; + return 0; } static unsigned long handle_pg_range(unsigned long pg_start, @@ -783,6 +830,8 @@ static unsigned long handle_pg_range(unsigned long pg_start, if (pgs_ol > pfn_cnt) pgs_ol = pfn_cnt; + has->covered_end_pfn += pgs_ol; + pfn_cnt -= pgs_ol; /* * Check if the corresponding memory block is already * online by checking its last previously backed page. @@ -791,10 +840,8 @@ static unsigned long handle_pg_range(unsigned long pg_start, */ if (start_pfn > has->start_pfn && !PageReserved(pfn_to_page(start_pfn - 1))) - hv_bring_pgs_online(start_pfn, pgs_ol); + hv_bring_pgs_online(has, start_pfn, pgs_ol); - has->covered_end_pfn += pgs_ol; - pfn_cnt -= pgs_ol; } if ((has->ha_end_pfn < has->end_pfn) && (pfn_cnt > 0)) { @@ -832,13 +879,19 @@ static unsigned long process_hot_add(unsigned long pg_start, unsigned long rg_size) { struct hv_hotadd_state *ha_region = NULL; + int covered; if (pfn_cnt == 0) return 0; - if (!dm_device.host_specified_ha_region) - if (pfn_covered(pg_start, pfn_cnt)) + if (!dm_device.host_specified_ha_region) { + covered = pfn_covered(pg_start, pfn_cnt); + if (covered < 0) + return 0; + + if (covered) goto do_pg_range; + } /* * If the host has specified a hot-add range; deal with it first. @@ -850,10 +903,12 @@ static unsigned long process_hot_add(unsigned long pg_start, return 0; INIT_LIST_HEAD(&ha_region->list); + INIT_LIST_HEAD(&ha_region->gap_list); list_add_tail(&ha_region->list, &dm_device.ha_region_list); ha_region->start_pfn = rg_start; ha_region->ha_end_pfn = rg_start; + ha_region->covered_start_pfn = pg_start; ha_region->covered_end_pfn = pg_start; ha_region->end_pfn = rg_start + rg_size; } @@ -1581,6 +1636,7 @@ static int balloon_remove(struct hv_device *dev) struct hv_dynmem_device *dm = hv_get_drvdata(dev); struct list_head *cur, *tmp; struct hv_hotadd_state *has; + struct hv_hotadd_gap *gap, *tmp_gap; if (dm->num_pages_ballooned != 0) pr_warn("Ballooned pages: %d\n", dm->num_pages_ballooned); @@ -1597,6 +1653,10 @@ static int balloon_remove(struct hv_device *dev) #endif list_for_each_safe(cur, tmp, &dm->ha_region_list) { has = list_entry(cur, struct hv_hotadd_state, list); + list_for_each_entry_safe(gap, tmp_gap, &has->gap_list, list) { + list_del(&gap->list); + kfree(gap); + } list_del(&has->list); kfree(has); } diff --git a/drivers/input/misc/hbtp_input.c b/drivers/input/misc/hbtp_input.c index 599605a3cf76..0362095d4c38 100644 --- a/drivers/input/misc/hbtp_input.c +++ b/drivers/input/misc/hbtp_input.c @@ -1452,8 +1452,10 @@ static int __init hbtp_init(void) hbtp->sensor_data = kzalloc(sizeof(struct hbtp_sensor_data), GFP_KERNEL); - if (!hbtp->sensor_data) + if (!hbtp->sensor_data) { + error = -ENOMEM; goto err_sensordata; + } mutex_init(&hbtp->mutex); mutex_init(&hbtp->sensormutex); diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c index 43482ae1e049..1a2b2620421e 100644 --- a/drivers/input/mouse/elantech.c +++ b/drivers/input/mouse/elantech.c @@ -1122,6 +1122,7 @@ static int elantech_get_resolution_v4(struct psmouse *psmouse, * Asus UX32VD 0x361f02 00, 15, 0e clickpad * Avatar AVIU-145A2 0x361f00 ? clickpad * Fujitsu LIFEBOOK E544 0x470f00 d0, 12, 09 2 hw buttons + * Fujitsu LIFEBOOK E547 0x470f00 50, 12, 09 2 hw buttons * Fujitsu LIFEBOOK E554 0x570f01 40, 14, 0c 2 hw buttons * Fujitsu T725 0x470f01 05, 12, 09 2 hw buttons * Fujitsu H730 0x570f00 c0, 14, 0c 3 hw buttons (**) @@ -1528,6 +1529,13 @@ static const struct dmi_system_id elantech_dmi_force_crc_enabled[] = { }, }, { + /* Fujitsu LIFEBOOK E547 does not work with crc_enabled == 0 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), + DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK E547"), + }, + }, + { /* Fujitsu LIFEBOOK E554 does not work with crc_enabled == 0 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h index 25eab453f2b2..e7b96f1ac2c5 100644 --- a/drivers/input/serio/i8042-x86ia64io.h +++ b/drivers/input/serio/i8042-x86ia64io.h @@ -685,6 +685,13 @@ static const struct dmi_system_id __initconst i8042_dmi_reset_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "20046"), }, }, + { + /* Clevo P650RS, 650RP6, Sager NP8152-S, and others */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Notebook"), + DMI_MATCH(DMI_PRODUCT_NAME, "P65xRP"), + }, + }, { } }; diff --git a/drivers/input/touchscreen/st/fts.c b/drivers/input/touchscreen/st/fts.c index bbe872001407..78bdd24af28b 100644 --- a/drivers/input/touchscreen/st/fts.c +++ b/drivers/input/touchscreen/st/fts.c @@ -1252,7 +1252,7 @@ static void fts_event_handler(struct work_struct *work) static int cx_crc_check(void) { unsigned char regAdd1[3] = {FTS_CMD_HW_REG_R, ADDR_CRC_BYTE0, ADDR_CRC_BYTE1}; - unsigned char val; + unsigned char val = 0; unsigned char crc_status; unsigned int error; diff --git a/drivers/input/touchscreen/st/fts_lib/ftsFlash.c b/drivers/input/touchscreen/st/fts_lib/ftsFlash.c index 59c73f4c4edb..f3becac79102 100644 --- a/drivers/input/touchscreen/st/fts_lib/ftsFlash.c +++ b/drivers/input/touchscreen/st/fts_lib/ftsFlash.c @@ -93,7 +93,7 @@ int getFirmwareVersion(u16 *fw_vers, u16 *config_id) int flash_status(void) { u8 cmd[2] = {FLASH_CMD_READSTATUS, 0x00}; - u8 readData; + u8 readData = 0; logError(0, "%s Reading flash_status...\n", tag); if (fts_readCmd(cmd, 2, &readData, FLASH_STATUS_BYTES) < 0) { diff --git a/drivers/input/touchscreen/st/fts_lib/ftsGesture.c b/drivers/input/touchscreen/st/fts_lib/ftsGesture.c index fda4ab281948..ee97a417d4cb 100644 --- a/drivers/input/touchscreen/st/fts_lib/ftsGesture.c +++ b/drivers/input/touchscreen/st/fts_lib/ftsGesture.c @@ -28,7 +28,7 @@ static u8 custom_gesture_index[GESTURE_CUSTOM_NUMBER] = { 0 }; int enableGesture(u8 *mask, int size) { u8 cmd[size+2]; - u8 readData[FIFO_EVENT_SIZE]; + u8 readData[FIFO_EVENT_SIZE] = {0}; int i, res; int event_to_search[4] = {EVENTID_GESTURE, EVENT_TYPE_ENB, 0x00, GESTURE_ENABLE}; @@ -82,7 +82,7 @@ int enableGesture(u8 *mask, int size) int disableGesture(u8 *mask, int size) { u8 cmd[2+GESTURE_MASK_SIZE]; - u8 readData[FIFO_EVENT_SIZE]; + u8 readData[FIFO_EVENT_SIZE] = {0}; u8 temp; int i, res; int event_to_search[4] = { EVENTID_GESTURE, EVENT_TYPE_ENB, 0x00, GESTURE_DISABLE }; @@ -141,7 +141,7 @@ int startAddCustomGesture(u8 gestureID) { u8 cmd[3] = { FTS_CMD_GESTURE_CMD, GESTURE_START_ADD, gestureID }; int res; - u8 readData[FIFO_EVENT_SIZE]; + u8 readData[FIFO_EVENT_SIZE] = {0}; int event_to_search[4] = { EVENTID_GESTURE, EVENT_TYPE_ENB, gestureID, GESTURE_START_ADD }; res = fts_writeFwCmd(cmd, 3); @@ -168,7 +168,7 @@ int finishAddCustomGesture(u8 gestureID) { u8 cmd[3] = { FTS_CMD_GESTURE_CMD, GESTURE_FINISH_ADD, gestureID }; int res; - u8 readData[FIFO_EVENT_SIZE]; + u8 readData[FIFO_EVENT_SIZE] = {0}; int event_to_search[4] = { EVENTID_GESTURE, EVENT_TYPE_ENB, gestureID, GESTURE_FINISH_ADD }; res = fts_writeFwCmd(cmd, 3); @@ -199,7 +199,7 @@ int loadCustomGesture(u8 *template, u8 gestureID) int toWrite, offset = 0; u8 cmd[TEMPLATE_CHUNK + 5]; int event_to_search[4] = { EVENTID_GESTURE, EVENT_TYPE_ENB, gestureID, GESTURE_DATA_ADD }; - u8 readData[FIFO_EVENT_SIZE]; + u8 readData[FIFO_EVENT_SIZE] = {0}; logError(0, "%s Starting adding custom gesture procedure...\n", tag); @@ -359,7 +359,7 @@ int removeCustomGesture(u8 gestureID) int res, index; u8 cmd[3] = { FTS_CMD_GESTURE_CMD, GETURE_REMOVE_CUSTOM, gestureID }; int event_to_search[4] = {EVENTID_GESTURE, EVENT_TYPE_ENB, gestureID, GETURE_REMOVE_CUSTOM }; - u8 readData[FIFO_EVENT_SIZE]; + u8 readData[FIFO_EVENT_SIZE] = {0}; index = gestureID - GESTURE_CUSTOM_OFFSET; diff --git a/drivers/input/touchscreen/st/fts_lib/ftsTest.c b/drivers/input/touchscreen/st/fts_lib/ftsTest.c index 68bd04eff316..3810fd02001a 100644 --- a/drivers/input/touchscreen/st/fts_lib/ftsTest.c +++ b/drivers/input/touchscreen/st/fts_lib/ftsTest.c @@ -301,7 +301,7 @@ int production_test_ito(void) { int res = OK; u8 cmd; - u8 readData[FIFO_EVENT_SIZE]; + u8 readData[FIFO_EVENT_SIZE] = {0}; int eventToSearch[2] = {EVENTID_ERROR_EVENT, EVENT_TYPE_ITO}; /* look for ito event */ logError(0, "%s ITO Production test is starting...\n", tag); @@ -347,7 +347,7 @@ int production_test_initialization(void) { int res; u8 cmd; - u8 readData[FIFO_EVENT_SIZE]; + u8 readData[FIFO_EVENT_SIZE] = {0}; int eventToSearch[2] = {EVENTID_STATUS_UPDATE, EVENT_TYPE_FULL_INITIALIZATION}; logError(0, "%s INITIALIZATION Production test is starting...\n", tag); @@ -397,7 +397,7 @@ int ms_compensation_tuning(void) { int res; u8 cmd; - u8 readData[FIFO_EVENT_SIZE]; + u8 readData[FIFO_EVENT_SIZE] = {0}; int eventToSearch[2] = {EVENTID_STATUS_UPDATE, EVENT_TYPE_MS_TUNING_CMPL}; logError(0, "%s MS INITIALIZATION command sent...\n", tag); @@ -429,7 +429,7 @@ int ss_compensation_tuning(void) { int res; u8 cmd; - u8 readData[FIFO_EVENT_SIZE]; + u8 readData[FIFO_EVENT_SIZE] = {0}; int eventToSearch[2] = {EVENTID_STATUS_UPDATE, EVENT_TYPE_SS_TUNING_CMPL}; logError(0, "%s SS INITIALIZATION command sent...\n", tag); @@ -461,7 +461,7 @@ int lp_timer_calibration(void) { int res; u8 cmd; - u8 readData[FIFO_EVENT_SIZE]; + u8 readData[FIFO_EVENT_SIZE] = {0}; int eventToSearch[2] = {EVENTID_STATUS_UPDATE, EVENT_TYPE_LPTIMER_TUNING_CMPL}; logError(0, "%s LP TIMER CALIBRATION command sent...\n", tag); @@ -493,7 +493,7 @@ int save_cx_tuning(void) { int res; u8 cmd; - u8 readData[FIFO_EVENT_SIZE]; + u8 readData[FIFO_EVENT_SIZE] = {0}; int eventToSearch[2] = {EVENTID_STATUS_UPDATE, EVENT_TYPE_COMP_DATA_SAVED}; logError(0, "%s SAVE CX command sent...\n", tag); diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 7f39ea93e110..dc44b40a85f3 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -522,6 +522,8 @@ static bool arm_smmu_is_slave_side_secure(struct arm_smmu_domain *smmu_domain); static bool arm_smmu_has_secure_vmid(struct arm_smmu_domain *smmu_domain); static bool arm_smmu_is_iova_coherent(struct iommu_domain *domain, dma_addr_t iova); +static uint64_t arm_smmu_iova_to_pte(struct iommu_domain *domain, + dma_addr_t iova); static int arm_smmu_enable_s1_translations(struct arm_smmu_domain *smmu_domain); @@ -2536,6 +2538,23 @@ static int arm_smmu_map(struct iommu_domain *domain, unsigned long iova, return ret; } +static uint64_t arm_smmu_iova_to_pte(struct iommu_domain *domain, + dma_addr_t iova) +{ + uint64_t ret; + unsigned long flags; + struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain); + struct io_pgtable_ops *ops = smmu_domain->pgtbl_ops; + + if (!ops) + return 0; + + flags = arm_smmu_pgtbl_lock(smmu_domain); + ret = ops->iova_to_pte(ops, iova); + arm_smmu_pgtbl_unlock(smmu_domain, flags); + return ret; +} + static size_t arm_smmu_map_sg(struct iommu_domain *domain, unsigned long iova, struct scatterlist *sg, unsigned int nents, int prot) { @@ -3437,6 +3456,7 @@ static struct iommu_ops arm_smmu_ops = { .enable_config_clocks = arm_smmu_enable_config_clocks, .disable_config_clocks = arm_smmu_disable_config_clocks, .is_iova_coherent = arm_smmu_is_iova_coherent, + .iova_to_pte = arm_smmu_iova_to_pte, }; static void arm_smmu_device_reset(struct arm_smmu_device *smmu) diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c index 6a8a9492c771..2d2583c78bdb 100644 --- a/drivers/iommu/io-pgtable-arm.c +++ b/drivers/iommu/io-pgtable-arm.c @@ -903,6 +903,19 @@ found_translation: return 0; } +static uint64_t arm_lpae_iova_get_pte(struct io_pgtable_ops *ops, + unsigned long iova) +{ + struct arm_lpae_io_pgtable *data = io_pgtable_ops_to_data(ops); + arm_lpae_iopte pte; + int lvl; + + if (!arm_lpae_iova_to_pte(data, iova, &lvl, &pte)) + return pte; + + return 0; +} + static phys_addr_t arm_lpae_iova_to_phys(struct io_pgtable_ops *ops, unsigned long iova) { @@ -1033,6 +1046,7 @@ arm_lpae_alloc_pgtable(struct io_pgtable_cfg *cfg) .unmap = arm_lpae_unmap, .iova_to_phys = arm_lpae_iova_to_phys, .is_iova_coherent = arm_lpae_is_iova_coherent, + .iova_to_pte = arm_lpae_iova_get_pte, }; return data; diff --git a/drivers/iommu/io-pgtable.h b/drivers/iommu/io-pgtable.h index e6939c2212d4..2cf213514221 100644 --- a/drivers/iommu/io-pgtable.h +++ b/drivers/iommu/io-pgtable.h @@ -124,6 +124,8 @@ struct io_pgtable_ops { unsigned long iova); bool (*is_iova_coherent)(struct io_pgtable_ops *ops, unsigned long iova); + uint64_t (*iova_to_pte)(struct io_pgtable_ops *ops, + unsigned long iova); }; diff --git a/drivers/iommu/iommu-debug.c b/drivers/iommu/iommu-debug.c index 28a817aba3fc..776e06facc11 100644 --- a/drivers/iommu/iommu-debug.c +++ b/drivers/iommu/iommu-debug.c @@ -470,6 +470,7 @@ static inline void iommu_debug_destroy_tracking(void) { } static LIST_HEAD(iommu_debug_devices); static struct dentry *debugfs_tests_dir; static u32 iters_per_op = 1; +static void *virt_addr; struct iommu_debug_device { struct device *dev; @@ -1537,6 +1538,68 @@ out_domain_free: return -EIO; } +static ssize_t __iommu_debug_dma_attach_write(struct file *file, + const char __user *ubuf, + size_t count, loff_t *offset) +{ + struct iommu_debug_device *ddev = file->private_data; + struct device *dev = ddev->dev; + struct dma_iommu_mapping *dma_mapping; + ssize_t retval = -EINVAL; + int val; + + if (kstrtoint_from_user(ubuf, count, 0, &val)) { + pr_err("Invalid format. Expected a hex or decimal integer"); + retval = -EFAULT; + goto out; + } + + if (val) { + if (dev->archdata.mapping) + if (dev->archdata.mapping->domain) { + pr_err("Already attached.\n"); + retval = -EINVAL; + goto out; + } + if (WARN(dev->archdata.iommu, + "Attachment tracking out of sync with device\n")) { + retval = -EINVAL; + goto out; + } + + dma_mapping = arm_iommu_create_mapping(&platform_bus_type, 0, + (SZ_1G * 4ULL)); + + if (!dma_mapping) + goto out; + + if (arm_iommu_attach_device(dev, dma_mapping)) + goto out_release_mapping; + pr_err("Attached\n"); + } else { + if (!dev->archdata.mapping) { + pr_err("No mapping. Did you already attach?\n"); + retval = -EINVAL; + goto out; + } + if (!dev->archdata.mapping->domain) { + pr_err("No domain. Did you already attach?\n"); + retval = -EINVAL; + goto out; + } + arm_iommu_detach_device(dev); + arm_iommu_release_mapping(dev->archdata.mapping); + pr_err("Detached\n"); + } + retval = count; + return retval; + +out_release_mapping: + arm_iommu_release_mapping(dma_mapping); +out: + return retval; +} + static ssize_t __iommu_debug_attach_write(struct file *file, const char __user *ubuf, size_t count, loff_t *offset, @@ -1585,6 +1648,79 @@ out: return retval; } +static ssize_t iommu_debug_dma_attach_write(struct file *file, + const char __user *ubuf, + size_t count, loff_t *offset) +{ + return __iommu_debug_dma_attach_write(file, ubuf, count, offset); + +} + +static ssize_t iommu_debug_dma_attach_read(struct file *file, char __user *ubuf, + size_t count, loff_t *offset) +{ + struct iommu_debug_device *ddev = file->private_data; + struct device *dev = ddev->dev; + char c[2]; + + if (*offset) + return 0; + + if (!dev->archdata.mapping) + c[0] = '0'; + else + c[0] = dev->archdata.mapping->domain ? '1' : '0'; + + c[1] = '\n'; + if (copy_to_user(ubuf, &c, 2)) { + pr_err("copy_to_user failed\n"); + return -EFAULT; + } + *offset = 1; /* non-zero means we're done */ + + return 2; +} + +static const struct file_operations iommu_debug_dma_attach_fops = { + .open = simple_open, + .write = iommu_debug_dma_attach_write, + .read = iommu_debug_dma_attach_read, +}; + +static ssize_t iommu_debug_virt_addr_read(struct file *file, char __user *ubuf, + size_t count, loff_t *offset) +{ + char buf[100]; + ssize_t retval; + size_t buflen; + + if (*offset) + return 0; + + memset(buf, 0, 100); + + if (!virt_addr) + strlcpy(buf, "FAIL\n", 100); + else + snprintf(buf, 100, "0x%pK\n", virt_addr); + + buflen = strlen(buf); + if (copy_to_user(ubuf, buf, buflen)) { + pr_err("Couldn't copy_to_user\n"); + retval = -EFAULT; + } else { + *offset = 1; /* non-zero means we're done */ + retval = buflen; + } + + return retval; +} + +static const struct file_operations iommu_debug_virt_addr_fops = { + .open = simple_open, + .read = iommu_debug_virt_addr_read, +}; + static ssize_t iommu_debug_attach_write(struct file *file, const char __user *ubuf, size_t count, loff_t *offset) @@ -1635,6 +1771,75 @@ static const struct file_operations iommu_debug_secure_attach_fops = { .read = iommu_debug_attach_read, }; +static ssize_t iommu_debug_pte_write(struct file *file, + const char __user *ubuf, + size_t count, loff_t *offset) +{ + struct iommu_debug_device *ddev = file->private_data; + dma_addr_t iova; + + if (kstrtox_from_user(ubuf, count, 0, &iova)) { + pr_err("Invalid format for iova\n"); + ddev->iova = 0; + return -EINVAL; + } + + ddev->iova = iova; + pr_err("Saved iova=%pa for future PTE commands\n", &iova); + return count; +} + + +static ssize_t iommu_debug_pte_read(struct file *file, char __user *ubuf, + size_t count, loff_t *offset) +{ + struct iommu_debug_device *ddev = file->private_data; + struct device *dev = ddev->dev; + uint64_t pte; + char buf[100]; + ssize_t retval; + size_t buflen; + + if (!dev->archdata.mapping) { + pr_err("No mapping. Did you already attach?\n"); + return -EINVAL; + } + if (!dev->archdata.mapping->domain) { + pr_err("No domain. Did you already attach?\n"); + return -EINVAL; + } + + if (*offset) + return 0; + + memset(buf, 0, 100); + + pte = iommu_iova_to_pte(dev->archdata.mapping->domain, + ddev->iova); + + if (!pte) + strlcpy(buf, "FAIL\n", 100); + else + snprintf(buf, 100, "pte=%016llx\n", pte); + + buflen = strlen(buf); + if (copy_to_user(ubuf, buf, buflen)) { + pr_err("Couldn't copy_to_user\n"); + retval = -EFAULT; + } else { + *offset = 1; /* non-zero means we're done */ + retval = buflen; + } + + return retval; +} + +static const struct file_operations iommu_debug_pte_fops = { + .open = simple_open, + .write = iommu_debug_pte_write, + .read = iommu_debug_pte_read, +}; + static ssize_t iommu_debug_atos_write(struct file *file, const char __user *ubuf, size_t count, loff_t *offset) @@ -1700,6 +1905,55 @@ static const struct file_operations iommu_debug_atos_fops = { .read = iommu_debug_atos_read, }; +static ssize_t iommu_debug_dma_atos_read(struct file *file, char __user *ubuf, + size_t count, loff_t *offset) +{ + struct iommu_debug_device *ddev = file->private_data; + struct device *dev = ddev->dev; + phys_addr_t phys; + char buf[100]; + ssize_t retval; + size_t buflen; + + if (!dev->archdata.mapping) { + pr_err("No mapping. Did you already attach?\n"); + return -EINVAL; + } + if (!dev->archdata.mapping->domain) { + pr_err("No domain. Did you already attach?\n"); + return -EINVAL; + } + + if (*offset) + return 0; + + memset(buf, 0, 100); + + phys = iommu_iova_to_phys_hard(dev->archdata.mapping->domain, + ddev->iova); + if (!phys) + strlcpy(buf, "FAIL\n", 100); + else + snprintf(buf, 100, "%pa\n", &phys); + + buflen = strlen(buf); + if (copy_to_user(ubuf, buf, buflen)) { + pr_err("Couldn't copy_to_user\n"); + retval = -EFAULT; + } else { + *offset = 1; /* non-zero means we're done */ + retval = buflen; + } + + return retval; +} + +static const struct file_operations iommu_debug_dma_atos_fops = { + .open = simple_open, + .write = iommu_debug_atos_write, + .read = iommu_debug_dma_atos_read, +}; + static ssize_t iommu_debug_map_write(struct file *file, const char __user *ubuf, size_t count, loff_t *offset) { @@ -1780,6 +2034,152 @@ static const struct file_operations iommu_debug_map_fops = { .write = iommu_debug_map_write, }; +static ssize_t iommu_debug_dma_map_write(struct file *file, + const char __user *ubuf, size_t count, loff_t *offset) +{ + ssize_t retval = -EINVAL; + int ret; + char *comma1, *comma2; + char buf[100]; + unsigned long addr; + void *v_addr; + dma_addr_t iova; + size_t size; + unsigned int attr; + struct dma_attrs coherent_attr; + struct dma_attrs *dma_attrs = &coherent_attr; + struct iommu_debug_device *ddev = file->private_data; + struct device *dev = ddev->dev; + + init_dma_attrs(dma_attrs); + + if (count >= 100) { + pr_err("Value too large\n"); + return -EINVAL; + } + + if (!dev->archdata.mapping) { + pr_err("No mapping. Did you already attach?\n"); + retval = -EINVAL; + goto out; + } + if (!dev->archdata.mapping->domain) { + pr_err("No domain. Did you already attach?\n"); + retval = -EINVAL; + goto out; + } + + memset(buf, 0, 100); + + if (copy_from_user(buf, ubuf, count)) { + pr_err("Couldn't copy from user\n"); + retval = -EFAULT; + goto out; + } + + comma1 = strnchr(buf, count, ','); + if (!comma1) + goto invalid_format; + + comma2 = strnchr(comma1 + 1, count, ','); + if (!comma2) + goto invalid_format; + + *comma1 = *comma2 = '\0'; + + if (kstrtoul(buf, 0, &addr)) + goto invalid_format; + v_addr = (void *)addr; + + if (kstrtosize_t(comma1 + 1, 0, &size)) + goto invalid_format; + + if (kstrtouint(comma2 + 1, 0, &attr)) + goto invalid_format; + + if (v_addr < virt_addr || v_addr > (virt_addr + SZ_1M - 1)) + goto invalid_addr; + + if (attr == 0) + dma_attrs = NULL; + else if (attr == 1) + dma_set_attr(DMA_ATTR_FORCE_COHERENT, dma_attrs); + else if (attr == 2) + dma_set_attr(DMA_ATTR_FORCE_NON_COHERENT, dma_attrs); + else + goto invalid_format; + + iova = dma_map_single_attrs(dev, v_addr, size, + DMA_TO_DEVICE, dma_attrs); + + if (dma_mapping_error(dev, iova)) { + pr_err("Failed to perform dma_map_single\n"); + ret = -EINVAL; + goto out; + } + + retval = count; + pr_err("Mapped 0x%p to %pa (len=0x%zx)\n", + v_addr, &iova, size); + ddev->iova = iova; + pr_err("Saved iova=%pa for future PTE commands\n", &iova); +out: + return retval; + +invalid_format: + pr_err("Invalid format. Expected: addr,len,dma attr where 'dma attr' is\n0: normal mapping\n1: force coherent\n2: force non-cohernet\n"); + return retval; + +invalid_addr: + pr_err("Invalid addr given! Address should be within 1MB size from start addr returned by doing 'cat virt_addr'.\n"); + return retval; +} + +static ssize_t iommu_debug_dma_map_read(struct file *file, char __user *ubuf, + size_t count, loff_t *offset) +{ + struct iommu_debug_device *ddev = file->private_data; + struct device *dev = ddev->dev; + char buf[100]; + ssize_t retval; + size_t buflen; + dma_addr_t iova; + + if (!dev->archdata.mapping) { + pr_err("No mapping. Did you already attach?\n"); + return -EINVAL; + } + if (!dev->archdata.mapping->domain) { + pr_err("No domain. Did you already attach?\n"); + return -EINVAL; + } + + if (*offset) + return 0; + + memset(buf, 0, 100); + + iova = ddev->iova; + snprintf(buf, 100, "%pa\n", &iova); + + buflen = strlen(buf); + if (copy_to_user(ubuf, buf, buflen)) { + pr_err("Couldn't copy_to_user\n"); + retval = -EFAULT; + } else { + *offset = 1; /* non-zero means we're done */ + retval = buflen; + } + + return retval; +} + +static const struct file_operations iommu_debug_dma_map_fops = { + .open = simple_open, + .write = iommu_debug_dma_map_write, + .read = iommu_debug_dma_map_read, +}; + static ssize_t iommu_debug_unmap_write(struct file *file, const char __user *ubuf, size_t count, loff_t *offset) @@ -1845,6 +2245,92 @@ static const struct file_operations iommu_debug_unmap_fops = { .write = iommu_debug_unmap_write, }; +static ssize_t iommu_debug_dma_unmap_write(struct file *file, + const char __user *ubuf, + size_t count, loff_t *offset) +{ + ssize_t retval = 0; + char *comma1, *comma2; + char buf[100]; + size_t size; + unsigned int attr; + dma_addr_t iova; + struct dma_attrs coherent_attr; + struct dma_attrs *dma_attrs = &coherent_attr; + struct iommu_debug_device *ddev = file->private_data; + struct device *dev = ddev->dev; + + init_dma_attrs(dma_attrs); + + if (count >= 100) { + pr_err("Value too large\n"); + return -EINVAL; + } + + if (!dev->archdata.mapping) { + pr_err("No mapping. Did you already attach?\n"); + retval = -EINVAL; + goto out; + } + if (!dev->archdata.mapping->domain) { + pr_err("No domain. Did you already attach?\n"); + retval = -EINVAL; + goto out; + } + + memset(buf, 0, 100); + + if (copy_from_user(buf, ubuf, count)) { + pr_err("Couldn't copy from user\n"); + retval = -EFAULT; + goto out; + } + + comma1 = strnchr(buf, count, ','); + if (!comma1) + goto invalid_format; + + comma2 = strnchr(comma1 + 1, count, ','); + if (!comma2) + goto invalid_format; + + *comma1 = *comma2 = '\0'; + + if (kstrtoux(buf, 0, &iova)) + goto invalid_format; + + if (kstrtosize_t(comma1 + 1, 0, &size)) + goto invalid_format; + + if (kstrtouint(comma2 + 1, 0, &attr)) + goto invalid_format; + + if (attr == 0) + dma_attrs = NULL; + else if (attr == 1) + dma_set_attr(DMA_ATTR_FORCE_COHERENT, dma_attrs); + else if (attr == 2) + dma_set_attr(DMA_ATTR_FORCE_NON_COHERENT, dma_attrs); + else + goto invalid_format; + + dma_unmap_single_attrs(dev, iova, size, DMA_TO_DEVICE, dma_attrs); + + retval = count; + pr_err("Unmapped %pa (len=0x%zx)\n", &iova, size); +out: + return retval; + +invalid_format: + pr_err("Invalid format. Expected: iova,len, dma attr\n"); + return retval; +} + +static const struct file_operations iommu_debug_dma_unmap_fops = { + .open = simple_open, + .write = iommu_debug_dma_unmap_write, +}; + static ssize_t iommu_debug_config_clocks_write(struct file *file, const char __user *ubuf, size_t count, loff_t *offset) @@ -1923,6 +2409,13 @@ static int snarf_iommu_devices(struct device *dev, const char *name) goto err_rmdir; } + if (!debugfs_create_file("virt_addr", S_IRUSR, dir, ddev, + &iommu_debug_virt_addr_fops)) { + pr_err("Couldn't create iommu/devices/%s/virt_addr debugfs file\n", + name); + goto err_rmdir; + } + if (!debugfs_create_file("profiling", S_IRUSR, dir, ddev, &iommu_debug_profiling_fops)) { pr_err("Couldn't create iommu/devices/%s/profiling debugfs file\n", @@ -1965,6 +2458,13 @@ static int snarf_iommu_devices(struct device *dev, const char *name) goto err_rmdir; } + if (!debugfs_create_file("dma_attach", S_IRUSR, dir, ddev, + &iommu_debug_dma_attach_fops)) { + pr_err("Couldn't create iommu/devices/%s/dma_attach debugfs file\n", + name); + goto err_rmdir; + } + if (!debugfs_create_file("attach", S_IRUSR, dir, ddev, &iommu_debug_attach_fops)) { pr_err("Couldn't create iommu/devices/%s/attach debugfs file\n", @@ -1986,6 +2486,13 @@ static int snarf_iommu_devices(struct device *dev, const char *name) goto err_rmdir; } + if (!debugfs_create_file("dma_atos", S_IWUSR, dir, ddev, + &iommu_debug_dma_atos_fops)) { + pr_err("Couldn't create iommu/devices/%s/dma_atos debugfs file\n", + name); + goto err_rmdir; + } + if (!debugfs_create_file("map", S_IWUSR, dir, ddev, &iommu_debug_map_fops)) { pr_err("Couldn't create iommu/devices/%s/map debugfs file\n", @@ -1993,6 +2500,13 @@ static int snarf_iommu_devices(struct device *dev, const char *name) goto err_rmdir; } + if (!debugfs_create_file("dma_map", S_IWUSR, dir, ddev, + &iommu_debug_dma_map_fops)) { + pr_err("Couldn't create iommu/devices/%s/dma_map debugfs file\n", + name); + goto err_rmdir; + } + if (!debugfs_create_file("unmap", S_IWUSR, dir, ddev, &iommu_debug_unmap_fops)) { pr_err("Couldn't create iommu/devices/%s/unmap debugfs file\n", @@ -2000,6 +2514,20 @@ static int snarf_iommu_devices(struct device *dev, const char *name) goto err_rmdir; } + if (!debugfs_create_file("dma_unmap", S_IWUSR, dir, ddev, + &iommu_debug_dma_unmap_fops)) { + pr_err("Couldn't create iommu/devices/%s/dma_unmap debugfs file\n", + name); + goto err_rmdir; + } + + if (!debugfs_create_file("pte", S_IWUSR, dir, ddev, + &iommu_debug_pte_fops)) { + pr_err("Couldn't create iommu/devices/%s/pte debugfs file\n", + name); + goto err_rmdir; + } + if (!debugfs_create_file("config_clocks", S_IWUSR, dir, ddev, &iommu_debug_config_clocks_fops)) { pr_err("Couldn't create iommu/devices/%s/config_clocks debugfs file\n", @@ -2054,6 +2582,11 @@ static int iommu_debug_init_tests(void) return -ENODEV; } + virt_addr = kzalloc(SZ_1M, GFP_KERNEL); + + if (!virt_addr) + return -ENOMEM; + return iommu_debug_populate_devices(); } diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index a77a45088b9d..b831796b5b7d 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -1336,6 +1336,15 @@ phys_addr_t iommu_iova_to_phys_hard(struct iommu_domain *domain, return domain->ops->iova_to_phys_hard(domain, iova); } +uint64_t iommu_iova_to_pte(struct iommu_domain *domain, + dma_addr_t iova) +{ + if (unlikely(domain->ops->iova_to_pte == NULL)) + return 0; + + return domain->ops->iova_to_pte(domain, iova); +} + bool iommu_is_iova_coherent(struct iommu_domain *domain, dma_addr_t iova) { if (unlikely(domain->ops->is_iova_coherent == NULL)) diff --git a/drivers/md/Makefile b/drivers/md/Makefile index eef9097c60b3..41ba86576d04 100644 --- a/drivers/md/Makefile +++ b/drivers/md/Makefile @@ -71,10 +71,6 @@ ifeq ($(CONFIG_DM_VERITY_FEC),y) dm-verity-objs += dm-verity-fec.o endif -ifeq ($(CONFIG_DM_ANDROID_VERITY),y) -dm-verity-objs += dm-android-verity.o -endif - ifeq ($(CONFIG_DM_VERITY_AVB),y) dm-verity-objs += dm-verity-avb.o endif diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 9be39988bf06..d81be5e471d0 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -570,7 +570,7 @@ static int read_balance(struct r1conf *conf, struct r1bio *r1_bio, int *max_sect if (best_dist_disk < 0) { if (is_badblock(rdev, this_sector, sectors, &first_bad, &bad_sectors)) { - if (first_bad < this_sector) + if (first_bad <= this_sector) /* Cannot use this */ continue; best_good_sectors = first_bad - this_sector; diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h index b283f6277b87..7d19b4e1fbba 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h @@ -469,6 +469,7 @@ struct msm_vfe_axi_stream { */ uint32_t vfe_mask; uint32_t composite_irq[MSM_ISP_COMP_IRQ_MAX]; + int lpm_mode; }; struct msm_vfe_axi_composite_info { diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c index a66ca7e93537..b80ef1dc900b 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c @@ -1859,10 +1859,10 @@ void msm_vfe47_cfg_axi_ub_equal_default( axi_data->free_wm[i]) break; - rdi_ub_offset = ((SRC_TO_INTF( + rdi_ub_offset = (SRC_TO_INTF( HANDLE_TO_IDX(axi_data->free_wm[i])) - - VFE_RAW_0 * 2) + plane) * - axi_data->hw_info->min_wm_ub; + VFE_RAW_0) * + axi_data->hw_info->min_wm_ub * 2; wm_ub_size = axi_data->hw_info->min_wm_ub * 2; msm_camera_io_w(rdi_ub_offset << 16 | (wm_ub_size - 1), vfe_dev->vfe_base + diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c index 63e46125c292..e7b3c56aa1f6 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c @@ -27,6 +27,9 @@ static void __msm_isp_axi_stream_update( struct msm_vfe_axi_stream *stream_info, struct msm_isp_timestamp *ts); +static int msm_isp_update_stream_bandwidth( + struct msm_vfe_axi_stream *stream_info, int enable); + #define DUAL_VFE_AND_VFE1(s, v) ((s->stream_src < RDI_INTF_0) && \ v->is_split && vfe_dev->pdev->id == ISP_VFE1) @@ -2426,46 +2429,42 @@ static void msm_isp_update_intf_stream_cnt( /*Factor in Q2 format*/ #define ISP_DEFAULT_FORMAT_FACTOR 6 #define ISP_BUS_UTILIZATION_FACTOR 6 -static int msm_isp_update_stream_bandwidth(struct vfe_device *vfe_dev) +static int msm_isp_update_stream_bandwidth( + struct msm_vfe_axi_stream *stream_info, int enable) { int i, rc = 0; - struct msm_vfe_axi_stream *stream_info; - uint64_t total_pix_bandwidth = 0, total_rdi_bandwidth = 0; - uint32_t num_pix_streams = 0; + uint64_t total_bandwidth = 0; int vfe_idx; + struct vfe_device *vfe_dev; - for (i = 0; i < VFE_AXI_SRC_MAX; i++) { - stream_info = msm_isp_get_stream_common_data(vfe_dev, i); - if (stream_info->state == ACTIVE || - stream_info->state == START_PENDING) { - vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, - stream_info); - if (stream_info->stream_src < RDI_INTF_0) { - total_pix_bandwidth += + for (i = 0; i < stream_info->num_isp; i++) { + vfe_dev = stream_info->vfe_dev[i]; + vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, + stream_info); + if (enable) { + total_bandwidth = + vfe_dev->total_bandwidth + stream_info->bandwidth[vfe_idx]; - num_pix_streams++; - } else { - total_rdi_bandwidth += + } else { + total_bandwidth = vfe_dev->total_bandwidth - stream_info->bandwidth[vfe_idx]; - } } - } - vfe_dev->total_bandwidth = total_pix_bandwidth + total_rdi_bandwidth; - rc = msm_isp_update_bandwidth(ISP_VFE0 + vfe_dev->pdev->id, - (vfe_dev->total_bandwidth + vfe_dev->hw_info->min_ab), - (vfe_dev->total_bandwidth + vfe_dev->hw_info->min_ib)); - - if (rc < 0) - pr_err("%s: update failed\n", __func__); + vfe_dev->total_bandwidth = total_bandwidth; + rc = msm_isp_update_bandwidth(ISP_VFE0 + vfe_dev->pdev->id, + (total_bandwidth + vfe_dev->hw_info->min_ab), + (total_bandwidth + vfe_dev->hw_info->min_ib)); + if (rc < 0) + pr_err("%s: update failed rc %d stream src %d vfe dev %d\n", + __func__, rc, stream_info->stream_src, + vfe_dev->pdev->id); + } return rc; } int msm_isp_ab_ib_update_lpm_mode(struct vfe_device *vfe_dev, void *arg) { int i, rc = 0; - uint64_t total_bandwidth = 0; - int vfe_idx; uint32_t intf; unsigned long flags; struct msm_vfe_axi_stream *stream_info; @@ -2489,21 +2488,15 @@ int msm_isp_ab_ib_update_lpm_mode(struct vfe_device *vfe_dev, void *arg) intf = SRC_TO_INTF(stream_info->stream_src); vfe_dev->axi_data.src_info[intf].lpm = ab_ib_vote->lpm_mode; - if (stream_info->state == ACTIVE) { - vfe_idx = - msm_isp_get_vfe_idx_for_stream(vfe_dev, - stream_info); - total_bandwidth += - stream_info->bandwidth[ - vfe_idx]; - stream_info->state = PAUSED; + if (stream_info->lpm_mode) { + spin_unlock_irqrestore(&stream_info->lock, + flags); + continue; } + stream_info->lpm_mode = ab_ib_vote->lpm_mode; spin_unlock_irqrestore(&stream_info->lock, flags); + msm_isp_update_stream_bandwidth(stream_info, 0); } - vfe_dev->total_bandwidth -= total_bandwidth; - rc = msm_isp_update_bandwidth(ISP_VFE0 + vfe_dev->pdev->id, - (vfe_dev->total_bandwidth - vfe_dev->hw_info->min_ab), - (vfe_dev->total_bandwidth - vfe_dev->hw_info->min_ib)); } else { for (i = 0; i < ab_ib_vote->num_src; i++) { stream_info = @@ -2515,24 +2508,19 @@ int msm_isp_ab_ib_update_lpm_mode(struct vfe_device *vfe_dev, void *arg) intf = SRC_TO_INTF(stream_info->stream_src); vfe_dev->axi_data.src_info[intf].lpm = ab_ib_vote->lpm_mode; - if (stream_info->state == PAUSED) { - vfe_idx = - msm_isp_get_vfe_idx_for_stream(vfe_dev, - stream_info); - total_bandwidth += - stream_info->bandwidth[ - vfe_idx]; - stream_info->state = ACTIVE; + if (stream_info->lpm_mode == 0) { + spin_unlock_irqrestore(&stream_info->lock, + flags); + continue; } + stream_info->lpm_mode = 0; spin_unlock_irqrestore(&stream_info->lock, flags); + msm_isp_update_stream_bandwidth(stream_info, 1); } - vfe_dev->total_bandwidth += total_bandwidth; - rc = msm_isp_update_bandwidth(ISP_VFE0 + vfe_dev->pdev->id, - (vfe_dev->total_bandwidth + vfe_dev->hw_info->min_ab), - (vfe_dev->total_bandwidth + vfe_dev->hw_info->min_ib)); } return rc; } + static int msm_isp_init_stream_ping_pong_reg( struct msm_vfe_axi_stream *stream_info) { @@ -2941,7 +2929,7 @@ static void __msm_isp_stop_axi_streams(struct vfe_device *vfe_dev, * be INACTIVE */ intf = SRC_TO_INTF(stream_info->stream_src); - if ((!vfe_dev->axi_data.src_info[intf].lpm) || + if (stream_info->lpm_mode == 0 && stream_info->state != PAUSED) { while (stream_info->state != ACTIVE) __msm_isp_axi_stream_update(stream_info, @@ -2959,16 +2947,14 @@ static void __msm_isp_stop_axi_streams(struct vfe_device *vfe_dev, vfe_dev->hw_info->vfe_ops.axi_ops. clear_wm_irq_mask(vfe_dev, stream_info); } - if (stream_info->state == ACTIVE && - !vfe_dev->axi_data.src_info[intf].lpm) { - init_completion(&stream_info->inactive_comp); - stream_info->state = STOP_PENDING; - } else if (vfe_dev->axi_data.src_info[intf].lpm || + init_completion(&stream_info->inactive_comp); + stream_info->state = STOP_PENDING; + if (stream_info->lpm_mode || stream_info->state == PAUSED) { /* don't wait for reg update */ - stream_info->state = STOP_PENDING; - msm_isp_axi_stream_enable_cfg(stream_info); - stream_info->state = INACTIVE; + while (stream_info->state != INACTIVE) + __msm_isp_axi_stream_update(stream_info, + ×tamp); } spin_unlock_irqrestore(&stream_info->lock, flags); } @@ -3029,6 +3015,8 @@ static void __msm_isp_stop_axi_streams(struct vfe_device *vfe_dev, /* clear buffers that are dequeued */ for (i = 0; i < num_streams; i++) { stream_info = streams[i]; + if (stream_info->lpm_mode == 0) + msm_isp_update_stream_bandwidth(stream_info, 0); for (bufq_id = 0; bufq_id < VFE_BUF_QUEUE_MAX; bufq_id++) { bufq_handle = stream_info->bufq_handle[bufq_id]; if (!bufq_handle) @@ -3044,12 +3032,6 @@ static void __msm_isp_stop_axi_streams(struct vfe_device *vfe_dev, } } - for (k = 0; k < MAX_VFE; k++) { - if (!update_vfes[k]) - continue; - msm_isp_update_stream_bandwidth(update_vfes[k]); - } - for (i = 0; i < num_streams; i++) { stream_info = streams[i]; intf = SRC_TO_INTF(stream_info->stream_src); @@ -3143,7 +3125,14 @@ static int msm_isp_start_axi_stream(struct vfe_device *vfe_dev_ioctl, cfg_wm_irq_mask(vfe_dev, stream_info); } } - intf = SRC_TO_INTF(stream_info->stream_src); + intf = SRC_TO_INTF(stream_info->stream_src); + stream_info->lpm_mode = vfe_dev_ioctl-> + axi_data.src_info[intf].lpm; + if (stream_info->lpm_mode == 0) { + spin_unlock_irqrestore(&stream_info->lock, flags); + msm_isp_update_stream_bandwidth(stream_info, 1); + spin_lock_irqsave(&stream_info->lock, flags); + } init_completion(&stream_info->active_comp); stream_info->state = START_PENDING; msm_isp_update_intf_stream_cnt(stream_info, 1); @@ -3153,7 +3142,7 @@ static int msm_isp_start_axi_stream(struct vfe_device *vfe_dev_ioctl, vfe_dev_ioctl->pdev->id); if (src_state) { src_mask |= (1 << SRC_TO_INTF(stream_info->stream_src)); - if (vfe_dev_ioctl->axi_data.src_info[intf].lpm) { + if (stream_info->lpm_mode) { while (stream_info->state != ACTIVE) __msm_isp_axi_stream_update( stream_info, ×tamp); @@ -3187,7 +3176,6 @@ static int msm_isp_start_axi_stream(struct vfe_device *vfe_dev_ioctl, vfe_dev = update_vfes[i]; if (!vfe_dev) continue; - msm_isp_update_stream_bandwidth(vfe_dev); vfe_dev->hw_info->vfe_ops.axi_ops.reload_wm(vfe_dev, vfe_dev->vfe_base, wm_reload_mask[i]); diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c index c8f5c051424e..5d31b9f21339 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c @@ -2225,8 +2225,6 @@ static void msm_vfe_iommu_fault_handler(struct iommu_domain *domain, mutex_lock(&vfe_dev->core_mutex); if (vfe_dev->vfe_open_cnt > 0) { - atomic_set(&vfe_dev->error_info.overflow_state, - HALT_ENFORCED); pr_err_ratelimited("%s: fault address is %lx\n", __func__, iova); msm_isp_process_iommu_page_fault(vfe_dev); @@ -2342,6 +2340,7 @@ int msm_isp_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { long rc = 0; int wm; + int i; struct vfe_device *vfe_dev = v4l2_get_subdevdata(sd); ISP_DBG("%s E open_cnt %u\n", __func__, vfe_dev->vfe_open_cnt); mutex_lock(&vfe_dev->realtime_mutex); @@ -2391,6 +2390,8 @@ int msm_isp_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) msm_isp_end_avtimer(); vfe_dev->vt_enable = 0; } + for (i = 0; i < VFE_SRC_MAX; i++) + vfe_dev->axi_data.src_info[i].lpm = 0; MSM_ISP_DUAL_VFE_MUTEX_UNLOCK(vfe_dev); vfe_dev->is_split = 0; diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c index caf6639f5151..24e3223a79d0 100644 --- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c +++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c @@ -67,6 +67,10 @@ static int pix_overflow_error_count[VFE_MAX] = { 0 }; #define CDBG(fmt, args...) #endif +/* Backward interface compatibility for 3D THRESHOLD calculation */ +#define ISPIF_USE_DEFAULT_THRESHOLD (0) +#define ISPIF_CALCULATE_THRESHOLD (1) + static int msm_ispif_clk_ahb_enable(struct ispif_device *ispif, int enable); static int ispif_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh); static long msm_ispif_subdev_ioctl_unlocked(struct v4l2_subdev *sd, @@ -452,7 +456,7 @@ static int msm_ispif_reset_hw(struct ispif_device *ispif) /* This is set when device is 8974 */ ispif->clk_idx = 1; } - + memset(ispif->stereo_configured, 0, sizeof(ispif->stereo_configured)); atomic_set(&ispif->reset_trig[VFE0], 1); /* initiate reset of ISPIF */ msm_camera_io_w(ISPIF_RST_CMD_MASK, @@ -1009,21 +1013,29 @@ static int msm_ispif_config(struct ispif_device *ispif, } static void msm_ispif_config_stereo(struct ispif_device *ispif, - struct msm_ispif_param_data_ext *params) { + struct msm_ispif_param_data_ext *params, int use_line_width) { int i; enum msm_ispif_vfe_intf vfe_intf; + uint32_t stereo_3d_threshold = STEREO_DEFAULT_3D_THRESHOLD; for (i = 0; i < params->num; i++) { + vfe_intf = params->entries[i].vfe_intf; if (params->entries[i].intftype == PIX0 && - params->stereo_enable && - params->right_entries[i].csid < CSID_MAX) { - vfe_intf = params->entries[i].vfe_intf; + params->stereo_enable && + params->right_entries[i].csid < CSID_MAX && + !ispif->stereo_configured[vfe_intf]) { msm_camera_io_w_mb(0x3, ispif->base + ISPIF_VFE_m_OUTPUT_SEL(vfe_intf)); - msm_camera_io_w_mb(STEREO_DEFAULT_3D_THRESHOLD, + if (use_line_width && + (params->line_width[vfe_intf] > 0)) + stereo_3d_threshold = + (params->line_width[vfe_intf] + + 2 * 6 - 1) / (2 * 6); + msm_camera_io_w_mb(stereo_3d_threshold, ispif->base + ISPIF_VFE_m_3D_THRESHOLD(vfe_intf)); + ispif->stereo_configured[vfe_intf] = 1; } } } @@ -1132,6 +1144,8 @@ static int msm_ispif_stop_immediately(struct ispif_device *ispif, msm_ispif_enable_intf_cids(ispif, params->entries[i].intftype, cid_mask, params->entries[i].vfe_intf, 0); if (params->stereo_enable) { + ispif->stereo_configured[ + params->entries[i].vfe_intf] = 0; cid_mask = msm_ispif_get_right_cids_mask_from_cfg( ¶ms->right_entries[i], params->entries[i].num_cids); @@ -1162,7 +1176,8 @@ static int msm_ispif_start_frame_boundary(struct ispif_device *ispif, rc = -EINVAL; return rc; } - msm_ispif_config_stereo(ispif, params); + + msm_ispif_config_stereo(ispif, params, ISPIF_USE_DEFAULT_THRESHOLD); msm_ispif_intf_cmd(ispif, ISPIF_INTF_CMD_ENABLE_FRAME_BOUNDARY, params); return rc; @@ -1392,6 +1407,8 @@ static int msm_ispif_stop_frame_boundary(struct ispif_device *ispif, if (rc < 0) goto end; if (cid_right_mask) { + ispif->stereo_configured[ + params->entries[i].vfe_intf] = 0; intf_addr = ISPIF_VFE_m_PIX_INTF_n_STATUS(vfe_intf, 1); rc = readl_poll_timeout(ispif->base + intf_addr, stop_flag, @@ -1807,6 +1824,10 @@ static long msm_ispif_dispatch_cmd(enum ispif_cfg_type_t cmd, rc = msm_ispif_config2(ispif, params); msm_ispif_io_dump_reg(ispif); break; + case ISPIF_CFG_STEREO: + msm_ispif_config_stereo(ispif, params, + ISPIF_CALCULATE_THRESHOLD); + break; default: pr_err("%s: invalid cfg_type\n", __func__); rc = -EINVAL; diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.h b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.h index 61e8f1dd7aff..3e6680c63ee5 100644 --- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.h +++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -77,5 +77,6 @@ struct ispif_device { int ispif_vdd_count; struct regulator *vfe_vdd[ISPIF_VFE_VDD_INFO_MAX]; int vfe_vdd_count; + int stereo_configured[VFE_MAX]; }; #endif diff --git a/drivers/media/platform/msm/camera_v2/msm.c b/drivers/media/platform/msm/camera_v2/msm.c index 8596366a70f0..f95cc37f5c2c 100644 --- a/drivers/media/platform/msm/camera_v2/msm.c +++ b/drivers/media/platform/msm/camera_v2/msm.c @@ -1015,11 +1015,9 @@ static int msm_open(struct file *filep) BUG_ON(!pvdev); /* !!! only ONE open is allowed !!! */ - if (atomic_read(&pvdev->opened)) + if (atomic_cmpxchg(&pvdev->opened, 0, 1)) return -EBUSY; - atomic_set(&pvdev->opened, 1); - spin_lock_irqsave(&msm_pid_lock, flags); msm_pid = get_pid(task_pid(current)); spin_unlock_irqrestore(&msm_pid_lock, flags); diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c index 8402e31364b9..b7feb126f707 100644 --- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c +++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c @@ -2542,9 +2542,29 @@ static int msm_cpp_cfg_frame(struct cpp_device *cpp_dev, return -EINVAL; } - if (stripe_base == UINT_MAX || new_frame->num_strips > - (UINT_MAX - 1 - stripe_base) / stripe_size) { - pr_err("Invalid frame message,num_strips %d is large\n", + /* Stripe index starts at zero */ + if ((!new_frame->num_strips) || + (new_frame->first_stripe_index >= new_frame->num_strips) || + (new_frame->last_stripe_index >= new_frame->num_strips) || + (new_frame->first_stripe_index > + new_frame->last_stripe_index)) { + pr_err("Invalid frame message, #stripes=%d, stripe indices=[%d,%d]\n", + new_frame->num_strips, + new_frame->first_stripe_index, + new_frame->last_stripe_index); + return -EINVAL; + } + + if (!stripe_size) { + pr_err("Invalid frame message, invalid stripe_size (%d)!\n", + stripe_size); + return -EINVAL; + } + + if ((stripe_base == UINT_MAX) || + (new_frame->num_strips > + (UINT_MAX - 1 - stripe_base) / stripe_size)) { + pr_err("Invalid frame message, num_strips %d is large\n", new_frame->num_strips); return -EINVAL; } @@ -2785,13 +2805,14 @@ static int msm_cpp_cfg(struct cpp_device *cpp_dev, struct msm_cpp_frame_info_t *frame = NULL; struct msm_cpp_frame_info_t k_frame_info; int32_t rc = 0; - int32_t i = 0; - int32_t num_buff = sizeof(k_frame_info.output_buffer_info)/ + uint32_t i = 0; + uint32_t num_buff = sizeof(k_frame_info.output_buffer_info) / sizeof(struct msm_cpp_buffer_info_t); + if (copy_from_user(&k_frame_info, (void __user *)ioctl_ptr->ioctl_ptr, sizeof(k_frame_info))) - return -EFAULT; + return -EFAULT; frame = msm_cpp_get_frame(ioctl_ptr); if (!frame) { @@ -2953,8 +2974,9 @@ static int msm_cpp_validate_input(unsigned int cmd, void *arg, } *ioctl_ptr = arg; - if ((*ioctl_ptr == NULL) || - ((*ioctl_ptr)->ioctl_ptr == NULL)) { + if (((*ioctl_ptr) == NULL) || + ((*ioctl_ptr)->ioctl_ptr == NULL) || + ((*ioctl_ptr)->len == 0)) { pr_err("Error invalid ioctl argument cmd %u", cmd); return -EINVAL; } @@ -3503,13 +3525,18 @@ STREAM_BUFF_END: if (cpp_dev->iommu_state == CPP_IOMMU_STATE_DETACHED) { struct msm_camera_smmu_attach_type cpp_attach_info; + if (ioctl_ptr->len != + sizeof(struct msm_camera_smmu_attach_type)) { + rc = -EINVAL; + break; + } + memset(&cpp_attach_info, 0, sizeof(cpp_attach_info)); rc = msm_cpp_copy_from_ioctl_ptr(&cpp_attach_info, ioctl_ptr); if (rc < 0) { pr_err("CPP_IOMMU_ATTACH copy from user fail"); - ERR_COPY_FROM_USER(); - return -EINVAL; + break; } cpp_dev->security_mode = cpp_attach_info.attach; @@ -3538,16 +3565,20 @@ STREAM_BUFF_END: case VIDIOC_MSM_CPP_IOMMU_DETACH: { if ((cpp_dev->iommu_state == CPP_IOMMU_STATE_ATTACHED) && (cpp_dev->stream_cnt == 0)) { - struct msm_camera_smmu_attach_type cpp_attach_info; + if (ioctl_ptr->len != + sizeof(struct msm_camera_smmu_attach_type)) { + rc = -EINVAL; + break; + } + memset(&cpp_attach_info, 0, sizeof(cpp_attach_info)); rc = msm_cpp_copy_from_ioctl_ptr(&cpp_attach_info, ioctl_ptr); if (rc < 0) { pr_err("CPP_IOMMU_DETTACH copy from user fail"); - ERR_COPY_FROM_USER(); - return -EINVAL; + break; } cpp_dev->security_mode = cpp_attach_info.attach; @@ -3568,6 +3599,7 @@ STREAM_BUFF_END: } else { pr_err("%s:%d IOMMMU attach triggered in invalid state\n", __func__, __LINE__); + rc = -EINVAL; } break; } @@ -3883,6 +3915,7 @@ static long msm_cpp_subdev_fops_compat_ioctl(struct file *file, struct msm_cpp_stream_buff_info_t k_cpp_buff_info; struct msm_cpp_frame_info32_t k32_frame_info; struct msm_cpp_frame_info_t k64_frame_info; + struct msm_camera_smmu_attach_type kb_cpp_smmu_attach_info; uint32_t identity_k = 0; bool is_copytouser_req = true; void __user *up = (void __user *)arg; @@ -4187,11 +4220,23 @@ static long msm_cpp_subdev_fops_compat_ioctl(struct file *file, break; } case VIDIOC_MSM_CPP_IOMMU_ATTACH32: - cmd = VIDIOC_MSM_CPP_IOMMU_ATTACH; - break; case VIDIOC_MSM_CPP_IOMMU_DETACH32: - cmd = VIDIOC_MSM_CPP_IOMMU_DETACH; + { + if ((kp_ioctl.len != sizeof(struct msm_camera_smmu_attach_type)) + || (copy_from_user(&kb_cpp_smmu_attach_info, + (void __user *)kp_ioctl.ioctl_ptr, + sizeof(kb_cpp_smmu_attach_info)))) { + mutex_unlock(&cpp_dev->mutex); + return -EINVAL; + } + + kp_ioctl.ioctl_ptr = (void *)&kb_cpp_smmu_attach_info; + is_copytouser_req = false; + cmd = (cmd == VIDIOC_MSM_CPP_IOMMU_ATTACH32) ? + VIDIOC_MSM_CPP_IOMMU_ATTACH : + VIDIOC_MSM_CPP_IOMMU_DETACH; break; + } case MSM_SD_NOTIFY_FREEZE: break; case MSM_SD_UNNOTIFY_FREEZE: @@ -4202,7 +4247,8 @@ static long msm_cpp_subdev_fops_compat_ioctl(struct file *file, default: pr_err_ratelimited("%s: unsupported compat type :%x LOAD %lu\n", __func__, cmd, VIDIOC_MSM_CPP_LOAD_FIRMWARE); - break; + mutex_unlock(&cpp_dev->mutex); + return -EINVAL; } mutex_unlock(&cpp_dev->mutex); @@ -4233,7 +4279,7 @@ static long msm_cpp_subdev_fops_compat_ioctl(struct file *file, default: pr_err_ratelimited("%s: unsupported compat type :%d\n", __func__, cmd); - break; + return -EINVAL; } if (is_copytouser_req) { diff --git a/drivers/misc/uid_sys_stats.c b/drivers/misc/uid_sys_stats.c index 618617f3e867..ad21276c8d9e 100644 --- a/drivers/misc/uid_sys_stats.c +++ b/drivers/misc/uid_sys_stats.c @@ -95,9 +95,11 @@ static int uid_cputime_show(struct seq_file *m, void *v) { struct uid_entry *uid_entry; struct task_struct *task, *temp; + struct user_namespace *user_ns = current_user_ns(); cputime_t utime; cputime_t stime; unsigned long bkt; + uid_t uid; rt_mutex_lock(&uid_lock); @@ -108,14 +110,13 @@ static int uid_cputime_show(struct seq_file *m, void *v) read_lock(&tasklist_lock); do_each_thread(temp, task) { - uid_entry = find_or_register_uid(from_kuid_munged( - current_user_ns(), task_uid(task))); + uid = from_kuid_munged(user_ns, task_uid(task)); + uid_entry = find_or_register_uid(uid); if (!uid_entry) { read_unlock(&tasklist_lock); rt_mutex_unlock(&uid_lock); pr_err("%s: failed to find the uid_entry for uid %d\n", - __func__, from_kuid_munged(current_user_ns(), - task_uid(task))); + __func__, uid); return -ENOMEM; } task_cputime_adjusted(task, &utime, &stime); diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index 1f1582f6cccb..8d838779fd1b 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -804,6 +804,7 @@ static int esdhc_change_pinstate(struct sdhci_host *host, switch (uhs) { case MMC_TIMING_UHS_SDR50: + case MMC_TIMING_UHS_DDR50: pinctrl = imx_data->pins_100mhz; break; case MMC_TIMING_UHS_SDR104: diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 987d61bdda2d..ca72ebfd55a3 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -5004,6 +5004,7 @@ static struct platform_driver sdhci_msm_driver = { .driver = { .name = "sdhci_msm", .owner = THIS_MODULE, + .probe_type = PROBE_PREFER_ASYNCHRONOUS, .of_match_table = sdhci_msm_dt_match, .pm = SDHCI_MSM_PMOPS, }, diff --git a/drivers/mtd/ubi/upd.c b/drivers/mtd/ubi/upd.c index 0134ba32a057..39712560b4c1 100644 --- a/drivers/mtd/ubi/upd.c +++ b/drivers/mtd/ubi/upd.c @@ -148,11 +148,11 @@ int ubi_start_update(struct ubi_device *ubi, struct ubi_volume *vol, return err; } - if (bytes == 0) { - err = ubi_wl_flush(ubi, UBI_ALL, UBI_ALL); - if (err) - return err; + err = ubi_wl_flush(ubi, UBI_ALL, UBI_ALL); + if (err) + return err; + if (bytes == 0) { err = clear_update_marker(ubi, vol, 0); if (err) return err; diff --git a/drivers/net/ethernet/cavium/liquidio/lio_main.c b/drivers/net/ethernet/cavium/liquidio/lio_main.c index 7445da218bd9..cc1725616f9d 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_main.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_main.c @@ -2823,7 +2823,7 @@ static int liquidio_xmit(struct sk_buff *skb, struct net_device *netdev) if (!g) { netif_info(lio, tx_err, lio->netdev, "Transmit scatter gather: glist null!\n"); - goto lio_xmit_failed; + goto lio_xmit_dma_failed; } cmdsetup.s.gather = 1; @@ -2894,7 +2894,7 @@ static int liquidio_xmit(struct sk_buff *skb, struct net_device *netdev) else status = octnet_send_nic_data_pkt(oct, &ndata, xmit_more); if (status == IQ_SEND_FAILED) - goto lio_xmit_failed; + goto lio_xmit_dma_failed; netif_info(lio, tx_queued, lio->netdev, "Transmit queued successfully\n"); @@ -2908,12 +2908,13 @@ static int liquidio_xmit(struct sk_buff *skb, struct net_device *netdev) return NETDEV_TX_OK; +lio_xmit_dma_failed: + dma_unmap_single(&oct->pci_dev->dev, ndata.cmd.dptr, + ndata.datasize, DMA_TO_DEVICE); lio_xmit_failed: stats->tx_dropped++; netif_info(lio, tx_err, lio->netdev, "IQ%d Transmit dropped:%llu\n", iq_no, stats->tx_dropped); - dma_unmap_single(&oct->pci_dev->dev, ndata.cmd.dptr, - ndata.datasize, DMA_TO_DEVICE); recv_buffer_free(skb); return NETDEV_TX_OK; } diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 06c8bfeaccd6..40cd86614677 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -1110,6 +1110,7 @@ static int macvlan_port_create(struct net_device *dev) static void macvlan_port_destroy(struct net_device *dev) { struct macvlan_port *port = macvlan_port_get_rtnl(dev); + struct sk_buff *skb; dev->priv_flags &= ~IFF_MACVLAN_PORT; netdev_rx_handler_unregister(dev); @@ -1118,7 +1119,15 @@ static void macvlan_port_destroy(struct net_device *dev) * but we need to cancel it and purge left skbs if any. */ cancel_work_sync(&port->bc_work); - __skb_queue_purge(&port->bc_queue); + + while ((skb = __skb_dequeue(&port->bc_queue))) { + const struct macvlan_dev *src = MACVLAN_SKB_CB(skb)->src; + + if (src) + dev_put(src->dev); + + kfree_skb(skb); + } kfree_rcu(port, rcu); } diff --git a/drivers/net/phy/dp83640.c b/drivers/net/phy/dp83640.c index e6cefd0e3262..84b9cca152eb 100644 --- a/drivers/net/phy/dp83640.c +++ b/drivers/net/phy/dp83640.c @@ -1436,8 +1436,6 @@ static bool dp83640_rxtstamp(struct phy_device *phydev, skb_info->tmo = jiffies + SKB_TIMESTAMP_TIMEOUT; skb_queue_tail(&dp83640->rx_queue, skb); schedule_delayed_work(&dp83640->ts_work, SKB_TIMESTAMP_TIMEOUT); - } else { - netif_rx_ni(skb); } return true; diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index bba0ca786aaa..851c0e121807 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -538,7 +538,7 @@ void phy_stop_machine(struct phy_device *phydev) cancel_delayed_work_sync(&phydev->state_queue); mutex_lock(&phydev->lock); - if (phydev->state > PHY_UP) + if (phydev->state > PHY_UP && phydev->state != PHY_HALTED) phydev->state = PHY_UP; mutex_unlock(&phydev->lock); } diff --git a/drivers/net/ppp/pppolac.c b/drivers/net/ppp/pppolac.c index 0184c96579e9..3a45cf805288 100644 --- a/drivers/net/ppp/pppolac.c +++ b/drivers/net/ppp/pppolac.c @@ -206,7 +206,9 @@ static void pppolac_xmit_core(struct work_struct *delivery_work) while ((skb = skb_dequeue(&delivery_queue))) { struct sock *sk_udp = skb->sk; struct kvec iov = {.iov_base = skb->data, .iov_len = skb->len}; - struct msghdr msg = { 0 }; + struct msghdr msg = { + .msg_flags = MSG_NOSIGNAL | MSG_DONTWAIT, + }; iov_iter_kvec(&msg.msg_iter, WRITE | ITER_KVEC, &iov, 1, skb->len); diff --git a/drivers/net/ppp/pppopns.c b/drivers/net/ppp/pppopns.c index d9e06039794e..cdb4fa1af734 100644 --- a/drivers/net/ppp/pppopns.c +++ b/drivers/net/ppp/pppopns.c @@ -189,7 +189,9 @@ static void pppopns_xmit_core(struct work_struct *delivery_work) while ((skb = skb_dequeue(&delivery_queue))) { struct sock *sk_raw = skb->sk; struct kvec iov = {.iov_base = skb->data, .iov_len = skb->len}; - struct msghdr msg = { 0 }; + struct msghdr msg = { + .msg_flags = MSG_NOSIGNAL | MSG_DONTWAIT, + }; iov_iter_kvec(&msg.msg_iter, WRITE | ITER_KVEC, &iov, 1, skb->len); diff --git a/drivers/net/wireless/ath/wil6210/Kconfig b/drivers/net/wireless/ath/wil6210/Kconfig index 8f0bde5825d5..0e66348e7513 100644 --- a/drivers/net/wireless/ath/wil6210/Kconfig +++ b/drivers/net/wireless/ath/wil6210/Kconfig @@ -44,7 +44,7 @@ config WIL6210_TRACING config WIL6210_WRITE_IOCTL bool "wil6210 write ioctl to the device" depends on WIL6210 - default n + default y ---help--- Say Y here to allow write-access from user-space to the device memory through ioctl. This is useful for diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 37898146f01d..d68d6c926029 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -26,6 +26,10 @@ bool disable_ap_sme; module_param(disable_ap_sme, bool, 0444); MODULE_PARM_DESC(disable_ap_sme, " let user space handle AP mode SME"); +static bool ignore_reg_hints = true; +module_param(ignore_reg_hints, bool, 0444); +MODULE_PARM_DESC(ignore_reg_hints, " Ignore OTA regulatory hints (Default: true)"); + #define CHAN60G(_channel, _flags) { \ .band = IEEE80211_BAND_60GHZ, \ .center_freq = 56160 + (2160 * (_channel)), \ @@ -1650,12 +1654,6 @@ static int wil_cfg80211_set_power_mgmt(struct wiphy *wiphy, { struct wil6210_priv *wil = wiphy_to_wil(wiphy); enum wmi_ps_profile_type ps_profile; - int rc; - - if (!test_bit(WMI_FW_CAPABILITY_PS_CONFIG, wil->fw_capabilities)) { - wil_err(wil, "set_power_mgmt not supported\n"); - return -EOPNOTSUPP; - } wil_dbg_misc(wil, "enabled=%d, timeout=%d\n", enabled, timeout); @@ -1665,11 +1663,7 @@ static int wil_cfg80211_set_power_mgmt(struct wiphy *wiphy, else ps_profile = WMI_PS_PROFILE_TYPE_PS_DISABLED; - rc = wmi_ps_dev_profile_cfg(wil, ps_profile); - if (rc) - wil_err(wil, "wmi_ps_dev_profile_cfg failed (%d)\n", rc); - - return rc; + return wil_ps_update(wil, ps_profile); } static struct cfg80211_ops wil_cfg80211_ops = { @@ -1743,6 +1737,11 @@ static void wil_wiphy_init(struct wiphy *wiphy) wiphy->vendor_commands = wil_nl80211_vendor_commands; wiphy->vendor_events = wil_nl80211_vendor_events; wiphy->n_vendor_events = ARRAY_SIZE(wil_nl80211_vendor_events); + + if (ignore_reg_hints) { + wiphy->regulatory_flags |= REGULATORY_DISABLE_BEACON_HINTS; + wiphy->regulatory_flags |= REGULATORY_COUNTRY_IE_IGNORE; + } } struct wireless_dev *wil_cfg80211_init(struct device *dev) diff --git a/drivers/net/wireless/ath/wil6210/fw_inc.c b/drivers/net/wireless/ath/wil6210/fw_inc.c index f4901587c005..e01acac88825 100644 --- a/drivers/net/wireless/ath/wil6210/fw_inc.c +++ b/drivers/net/wireless/ath/wil6210/fw_inc.c @@ -554,5 +554,7 @@ bool wil_fw_verify_file_exists(struct wil6210_priv *wil, const char *name) rc = request_firmware(&fw, name, wil_to_dev(wil)); if (!rc) release_firmware(fw); - return rc != -ENOENT; + else + wil_dbg_fw(wil, "<%s> not available: %d\n", name, rc); + return !rc; } diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index fca8acffeed5..45a5fb6d23a0 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -576,6 +576,9 @@ int wil_priv_init(struct wil6210_priv *wil) if (rx_ring_overflow_thrsh == WIL6210_RX_HIGH_TRSH_INIT) rx_ring_overflow_thrsh = WIL6210_RX_HIGH_TRSH_DEFAULT; + + wil->ps_profile = WMI_PS_PROFILE_TYPE_DEFAULT; + return 0; out_wmi_wq: @@ -901,6 +904,24 @@ void wil_abort_scan(struct wil6210_priv *wil, bool sync) } } +int wil_ps_update(struct wil6210_priv *wil, enum wmi_ps_profile_type ps_profile) +{ + int rc; + + if (!test_bit(WMI_FW_CAPABILITY_PS_CONFIG, wil->fw_capabilities)) { + wil_err(wil, "set_power_mgmt not supported\n"); + return -EOPNOTSUPP; + } + + rc = wmi_ps_dev_profile_cfg(wil, ps_profile); + if (rc) + wil_err(wil, "wmi_ps_dev_profile_cfg failed (%d)\n", rc); + else + wil->ps_profile = ps_profile; + + return rc; +} + /* * We reset all the structures, and we reset the UMAC. * After calling this routine, you're expected to reload @@ -950,15 +971,15 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) /* Disable device led before reset*/ wmi_led_cfg(wil, false); + mutex_lock(&wil->p2p_wdev_mutex); + wil_abort_scan(wil, false); + mutex_unlock(&wil->p2p_wdev_mutex); + /* prevent NAPI from being scheduled and prevent wmi commands */ mutex_lock(&wil->wmi_mutex); bitmap_zero(wil->status, wil_status_last); mutex_unlock(&wil->wmi_mutex); - mutex_lock(&wil->p2p_wdev_mutex); - wil_abort_scan(wil, false); - mutex_unlock(&wil->p2p_wdev_mutex); - wil_mask_irq(wil); wmi_event_flush(wil); @@ -1035,6 +1056,9 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) return rc; } + if (wil->ps_profile != WMI_PS_PROFILE_TYPE_DEFAULT) + wil_ps_update(wil, wil->ps_profile); + if (wil->tt_data_set) wmi_set_tt_cfg(wil, &wil->tt_data); diff --git a/drivers/net/wireless/ath/wil6210/pmc.c b/drivers/net/wireless/ath/wil6210/pmc.c index b067fdf086d4..2e301b6b32a9 100644 --- a/drivers/net/wireless/ath/wil6210/pmc.c +++ b/drivers/net/wireless/ath/wil6210/pmc.c @@ -200,7 +200,7 @@ void wil_pmc_alloc(struct wil6210_priv *wil, release_pmc_skbs: wil_err(wil, "exit on error: Releasing skbs...\n"); - for (i = 0; pmc->descriptors[i].va && i < num_descriptors; i++) { + for (i = 0; i < num_descriptors && pmc->descriptors[i].va; i++) { dma_free_coherent(dev, descriptor_size, pmc->descriptors[i].va, @@ -283,7 +283,7 @@ void wil_pmc_free(struct wil6210_priv *wil, int send_pmc_cmd) int i; for (i = 0; - pmc->descriptors[i].va && i < pmc->num_descriptors; i++) { + i < pmc->num_descriptors && pmc->descriptors[i].va; i++) { dma_free_coherent(dev, pmc->descriptor_size, pmc->descriptors[i].va, diff --git a/drivers/net/wireless/ath/wil6210/rx_reorder.c b/drivers/net/wireless/ath/wil6210/rx_reorder.c index 7404b6f39c6a..a43cffcf1bbf 100644 --- a/drivers/net/wireless/ath/wil6210/rx_reorder.c +++ b/drivers/net/wireless/ath/wil6210/rx_reorder.c @@ -343,8 +343,16 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) wil_err(wil, "BACK requested unsupported ba_policy == 1\n"); status = WLAN_STATUS_INVALID_QOS_PARAM; } - if (status == WLAN_STATUS_SUCCESS) - agg_wsize = wil_agg_size(wil, req_agg_wsize); + if (status == WLAN_STATUS_SUCCESS) { + if (req_agg_wsize == 0) { + wil_dbg_misc(wil, "Suggest BACK wsize %d\n", + WIL_MAX_AGG_WSIZE); + agg_wsize = WIL_MAX_AGG_WSIZE; + } else { + agg_wsize = min_t(u16, + WIL_MAX_AGG_WSIZE, req_agg_wsize); + } + } rc = wmi_addba_rx_resp(wil, cid, tid, dialog_token, status, agg_amsdu, agg_wsize, agg_timeout); diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 8b5411e4dc34..35bbf3a91f3e 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -37,6 +37,10 @@ bool rx_align_2; module_param(rx_align_2, bool, 0444); MODULE_PARM_DESC(rx_align_2, " align Rx buffers on 4*n+2, default - no"); +bool rx_large_buf; +module_param(rx_large_buf, bool, 0444); +MODULE_PARM_DESC(rx_large_buf, " allocate 8KB RX buffers, default - no"); + static inline uint wil_rx_snaplen(void) { return rx_align_2 ? 6 : 0; @@ -255,7 +259,7 @@ static int wil_vring_alloc_skb(struct wil6210_priv *wil, struct vring *vring, u32 i, int headroom) { struct device *dev = wil_to_dev(wil); - unsigned int sz = mtu_max + ETH_HLEN + wil_rx_snaplen(); + unsigned int sz = wil->rx_buf_len + ETH_HLEN + wil_rx_snaplen(); struct vring_rx_desc dd, *d = ⅆ volatile struct vring_rx_desc *_d = &vring->va[i].rx; dma_addr_t pa; @@ -419,7 +423,7 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil, struct sk_buff *skb; dma_addr_t pa; unsigned int snaplen = wil_rx_snaplen(); - unsigned int sz = mtu_max + ETH_HLEN + snaplen; + unsigned int sz = wil->rx_buf_len + ETH_HLEN + snaplen; u16 dmalen; u8 ftype; int cid; @@ -780,6 +784,20 @@ void wil_rx_handle(struct wil6210_priv *wil, int *quota) wil_rx_refill(wil, v->size); } +static void wil_rx_buf_len_init(struct wil6210_priv *wil) +{ + wil->rx_buf_len = rx_large_buf ? + WIL_MAX_ETH_MTU : TXRX_BUF_LEN_DEFAULT - WIL_MAX_MPDU_OVERHEAD; + if (mtu_max > wil->rx_buf_len) { + /* do not allow RX buffers to be smaller than mtu_max, for + * backward compatibility (mtu_max parameter was also used + * to support receiving large packets) + */ + wil_info(wil, "Override RX buffer to mtu_max(%d)\n", mtu_max); + wil->rx_buf_len = mtu_max; + } +} + int wil_rx_init(struct wil6210_priv *wil, u16 size) { struct vring *vring = &wil->vring_rx; @@ -792,6 +810,8 @@ int wil_rx_init(struct wil6210_priv *wil, u16 size) return -EINVAL; } + wil_rx_buf_len_init(wil); + vring->size = size; rc = wil_vring_alloc(wil, vring); if (rc) diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 0529d10a8268..eee528127e97 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -33,6 +33,7 @@ extern unsigned short rx_ring_overflow_thrsh; extern int agg_wsize; extern u32 vring_idle_trsh; extern bool rx_align_2; +extern bool rx_large_buf; extern bool debug_fw; extern bool disable_ap_sme; @@ -670,6 +671,7 @@ struct wil6210_priv { struct work_struct probe_client_worker; /* DMA related */ struct vring vring_rx; + unsigned int rx_buf_len; struct vring vring_tx[WIL6210_MAX_TX_RINGS]; struct vring_tx_data vring_tx_data[WIL6210_MAX_TX_RINGS]; u8 vring2cid_tid[WIL6210_MAX_TX_RINGS][2]; /* [0] - CID, [1] - TID */ @@ -705,6 +707,8 @@ struct wil6210_priv { /* High Access Latency Policy voting */ struct wil_halp halp; + enum wmi_ps_profile_type ps_profile; + struct wil_ftm_priv ftm; bool tt_data_set; struct wmi_tt_data tt_data; @@ -824,6 +828,8 @@ int wil_if_add(struct wil6210_priv *wil); void wil_if_remove(struct wil6210_priv *wil); int wil_priv_init(struct wil6210_priv *wil); void wil_priv_deinit(struct wil6210_priv *wil); +int wil_ps_update(struct wil6210_priv *wil, + enum wmi_ps_profile_type ps_profile); int wil_reset(struct wil6210_priv *wil, bool no_fw); void wil_fw_error_recovery(struct wil6210_priv *wil); void wil_set_recovery_state(struct wil6210_priv *wil, int state); diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 41afbdc34c18..97e22281314c 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -1436,7 +1436,8 @@ int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring) struct wmi_cfg_rx_chain_cmd cmd = { .action = WMI_RX_CHAIN_ADD, .rx_sw_ring = { - .max_mpdu_size = cpu_to_le16(wil_mtu2macbuf(mtu_max)), + .max_mpdu_size = cpu_to_le16( + wil_mtu2macbuf(wil->rx_buf_len)), .ring_mem_base = cpu_to_le64(vring->pa), .ring_size = cpu_to_le16(vring->size), }, diff --git a/drivers/net/wireless/cnss/Kconfig b/drivers/net/wireless/cnss/Kconfig index 4558dc30fec1..8e69a2b469b9 100644 --- a/drivers/net/wireless/cnss/Kconfig +++ b/drivers/net/wireless/cnss/Kconfig @@ -9,6 +9,15 @@ config CNSS This driver also adds support to integrate WLAN module to subsystem restart framework. +config CNSS_ASYNC + bool "Enable/disable cnss pci platform driver asynchronous probe" + depends on CNSS + ---help--- + If enabled, CNSS PCI platform driver would do asynchronous probe. + Using asynchronous probe will allow CNSS PCI platform driver to + probe in parallel with other device drivers and will help to + reduce kernel boot time. + config CNSS_MAC_BUG bool "Enable/disable 0-4K memory initialization for QCA6174" depends on CNSS diff --git a/drivers/net/wireless/cnss/cnss_pci.c b/drivers/net/wireless/cnss/cnss_pci.c index f53ed2693879..48d358c4722a 100644 --- a/drivers/net/wireless/cnss/cnss_pci.c +++ b/drivers/net/wireless/cnss/cnss_pci.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -3067,6 +3067,9 @@ static struct platform_driver cnss_driver = { .name = "cnss", .owner = THIS_MODULE, .of_match_table = cnss_dt_match, +#ifdef CONFIG_CNSS_ASYNC + .probe_type = PROBE_PREFER_ASYNCHRONOUS, +#endif }, }; diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c index 6df3ee561d52..515aa3f993f3 100644 --- a/drivers/net/wireless/hostap/hostap_hw.c +++ b/drivers/net/wireless/hostap/hostap_hw.c @@ -836,25 +836,30 @@ static int hfa384x_get_rid(struct net_device *dev, u16 rid, void *buf, int len, spin_lock_bh(&local->baplock); res = hfa384x_setup_bap(dev, BAP0, rid, 0); - if (!res) - res = hfa384x_from_bap(dev, BAP0, &rec, sizeof(rec)); + if (res) + goto unlock; + + res = hfa384x_from_bap(dev, BAP0, &rec, sizeof(rec)); + if (res) + goto unlock; if (le16_to_cpu(rec.len) == 0) { /* RID not available */ res = -ENODATA; + goto unlock; } rlen = (le16_to_cpu(rec.len) - 1) * 2; - if (!res && exact_len && rlen != len) { + if (exact_len && rlen != len) { printk(KERN_DEBUG "%s: hfa384x_get_rid - RID len mismatch: " "rid=0x%04x, len=%d (expected %d)\n", dev->name, rid, rlen, len); res = -ENODATA; } - if (!res) - res = hfa384x_from_bap(dev, BAP0, buf, len); + res = hfa384x_from_bap(dev, BAP0, buf, len); +unlock: spin_unlock_bh(&local->baplock); mutex_unlock(&local->rid_bap_mtx); diff --git a/drivers/nfc/nq-nci.c b/drivers/nfc/nq-nci.c index f4ad5bde06a8..538d8f91ce1b 100644 --- a/drivers/nfc/nq-nci.c +++ b/drivers/nfc/nq-nci.c @@ -1206,6 +1206,7 @@ static struct i2c_driver nqx = { .owner = THIS_MODULE, .name = "nq-nci", .of_match_table = msm_match_table, + .probe_type = PROBE_PREFER_ASYNCHRONOUS, .pm = &nfc_pm_ops, }, }; diff --git a/drivers/pci/host/pci-msm.c b/drivers/pci/host/pci-msm.c index 243afbe44df3..8bb759d10074 100644 --- a/drivers/pci/host/pci-msm.c +++ b/drivers/pci/host/pci-msm.c @@ -6449,7 +6449,6 @@ static int msm_pcie_probe(struct platform_device *pdev) } dev_set_drvdata(&msm_pcie_dev[rc_idx].pdev->dev, &msm_pcie_dev[rc_idx]); - msm_pcie_sysfs_init(&msm_pcie_dev[rc_idx]); ret = msm_pcie_get_resources(&msm_pcie_dev[rc_idx], msm_pcie_dev[rc_idx].pdev); @@ -6500,6 +6499,8 @@ static int msm_pcie_probe(struct platform_device *pdev) goto decrease_rc_num; } + msm_pcie_sysfs_init(&msm_pcie_dev[rc_idx]); + msm_pcie_dev[rc_idx].drv_ready = true; if (msm_pcie_dev[rc_idx].boot_option & diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c index e48c19c522a7..cb95f6e98956 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c @@ -80,6 +80,9 @@ const char *ipa_event_name[] = { __stringify(ECM_DISCONNECT), __stringify(IPA_TETHERING_STATS_UPDATE_STATS), __stringify(IPA_TETHERING_STATS_UPDATE_NETWORK_STATS), + __stringify(IPA_QUOTA_REACH), + __stringify(IPA_SSR_BEFORE_SHUTDOWN), + __stringify(IPA_SSR_AFTER_POWERUP), }; const char *ipa_hdr_l2_type_name[] = { diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_i.h b/drivers/platform/msm/ipa/ipa_v2/ipa_i.h index a14d1fee9c35..bb11230c960a 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_i.h +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_i.h @@ -51,6 +51,7 @@ #define IPA_UC_FINISH_MAX 6 #define IPA_UC_WAIT_MIN_SLEEP 1000 #define IPA_UC_WAII_MAX_SLEEP 1200 +#define IPA_BAM_STOP_MAX_RETRY 10 #define IPA_MAX_STATUS_STAT_NUM 30 diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_qmi_service.h b/drivers/platform/msm/ipa/ipa_v2/ipa_qmi_service.h index 96554af9aefd..1f5d619ef573 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_qmi_service.h +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_qmi_service.h @@ -177,6 +177,9 @@ int rmnet_ipa_set_tether_client_pipe(struct wan_ioctl_set_tether_client_pipe int rmnet_ipa_query_tethering_stats(struct wan_ioctl_query_tether_stats *data, bool reset); +int rmnet_ipa_query_tethering_stats_all( + struct wan_ioctl_query_tether_stats_all *data); + int rmnet_ipa_reset_tethering_stats(struct wan_ioctl_reset_tether_stats *data); int ipa_qmi_get_data_stats(struct ipa_get_data_stats_req_msg_v01 *req, diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_uc.c b/drivers/platform/msm/ipa/ipa_v2/ipa_uc.c index 3dd2eb093317..364cd4b7d38a 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_uc.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_uc.c @@ -590,6 +590,7 @@ int ipa_uc_send_cmd(u32 cmd, u32 opcode, u32 expected_status, { int index; union IpaHwCpuCmdCompletedResponseData_t uc_rsp; + int retries = 0; mutex_lock(&ipa_ctx->uc_ctx.uc_lock); @@ -599,6 +600,7 @@ int ipa_uc_send_cmd(u32 cmd, u32 opcode, u32 expected_status, return -EBADF; } +send_cmd: init_completion(&ipa_ctx->uc_ctx.uc_completion); ipa_ctx->uc_ctx.uc_sram_mmio->cmdParams = cmd; @@ -658,6 +660,19 @@ int ipa_uc_send_cmd(u32 cmd, u32 opcode, u32 expected_status, } if (ipa_ctx->uc_ctx.uc_status != expected_status) { + if (IPA_HW_2_CPU_WDI_RX_FSM_TRANSITION_ERROR == + ipa_ctx->uc_ctx.uc_status) { + retries++; + if (retries == IPA_BAM_STOP_MAX_RETRY) { + IPAERR("Failed after %d tries\n", retries); + } else { + /* sleep for short period to flush IPA */ + usleep_range(IPA_UC_WAIT_MIN_SLEEP, + IPA_UC_WAII_MAX_SLEEP); + goto send_cmd; + } + } + IPAERR("Recevied status %u, Expected status %u\n", ipa_ctx->uc_ctx.uc_status, expected_status); ipa_ctx->uc_ctx.pending_cmd = -1; diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_uc_offload_i.h b/drivers/platform/msm/ipa/ipa_v2/ipa_uc_offload_i.h index 3bec471b4656..a98d60249c0e 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_uc_offload_i.h +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_uc_offload_i.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -441,7 +441,7 @@ enum ipa_hw_offload_channel_states { /** - * enum ipa_hw_2_cpu_cmd_resp_status - Values that represent + * enum ipa_hw_2_cpu_offload_cmd_resp_status - Values that represent * offload related command response status to be sent to CPU. */ enum ipa_hw_2_cpu_offload_cmd_resp_status { @@ -478,6 +478,47 @@ enum ipa_hw_2_cpu_offload_cmd_resp_status { }; /** + * enum ipa_hw_2_cpu_cmd_resp_status - Values that represent WDI related + * command response status to be sent to CPU. + */ +enum ipa_hw_2_cpu_cmd_resp_status { + IPA_HW_2_CPU_WDI_CMD_STATUS_SUCCESS = + FEATURE_ENUM_VAL(IPA_HW_FEATURE_WDI, 0), + IPA_HW_2_CPU_MAX_WDI_TX_CHANNELS = + FEATURE_ENUM_VAL(IPA_HW_FEATURE_WDI, 1), + IPA_HW_2_CPU_WDI_CE_RING_OVERRUN_POSSIBILITY = + FEATURE_ENUM_VAL(IPA_HW_FEATURE_WDI, 2), + IPA_HW_2_CPU_WDI_CE_RING_SET_UP_FAILURE = + FEATURE_ENUM_VAL(IPA_HW_FEATURE_WDI, 3), + IPA_HW_2_CPU_WDI_CE_RING_PARAMS_UNALIGNED = + FEATURE_ENUM_VAL(IPA_HW_FEATURE_WDI, 4), + IPA_HW_2_CPU_WDI_COMP_RING_OVERRUN_POSSIBILITY = + FEATURE_ENUM_VAL(IPA_HW_FEATURE_WDI, 5), + IPA_HW_2_CPU_WDI_COMP_RING_SET_UP_FAILURE = + FEATURE_ENUM_VAL(IPA_HW_FEATURE_WDI, 6), + IPA_HW_2_CPU_WDI_COMP_RING_PARAMS_UNALIGNED = + FEATURE_ENUM_VAL(IPA_HW_FEATURE_WDI, 7), + IPA_HW_2_CPU_WDI_UNKNOWN_TX_CHANNEL = + FEATURE_ENUM_VAL(IPA_HW_FEATURE_WDI, 8), + IPA_HW_2_CPU_WDI_TX_INVALID_FSM_TRANSITION = + FEATURE_ENUM_VAL(IPA_HW_FEATURE_WDI, 9), + IPA_HW_2_CPU_WDI_TX_FSM_TRANSITION_ERROR = + FEATURE_ENUM_VAL(IPA_HW_FEATURE_WDI, 10), + IPA_HW_2_CPU_MAX_WDI_RX_CHANNELS = + FEATURE_ENUM_VAL(IPA_HW_FEATURE_WDI, 11), + IPA_HW_2_CPU_WDI_RX_RING_PARAMS_UNALIGNED = + FEATURE_ENUM_VAL(IPA_HW_FEATURE_WDI, 12), + IPA_HW_2_CPU_WDI_RX_RING_SET_UP_FAILURE = + FEATURE_ENUM_VAL(IPA_HW_FEATURE_WDI, 13), + IPA_HW_2_CPU_WDI_UNKNOWN_RX_CHANNEL = + FEATURE_ENUM_VAL(IPA_HW_FEATURE_WDI, 14), + IPA_HW_2_CPU_WDI_RX_INVALID_FSM_TRANSITION = + FEATURE_ENUM_VAL(IPA_HW_FEATURE_WDI, 15), + IPA_HW_2_CPU_WDI_RX_FSM_TRANSITION_ERROR = + FEATURE_ENUM_VAL(IPA_HW_FEATURE_WDI, 16), +}; + +/** * struct IpaHwSetUpCmd - * * diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_uc_wdi.c b/drivers/platform/msm/ipa/ipa_v2/ipa_uc_wdi.c index f60669132865..56b4bf1a2d1e 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_uc_wdi.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_uc_wdi.c @@ -110,47 +110,6 @@ enum ipa_cpu_2_hw_wdi_commands { }; /** - * enum ipa_hw_2_cpu_cmd_resp_status - Values that represent WDI related - * command response status to be sent to CPU. - */ -enum ipa_hw_2_cpu_cmd_resp_status { - IPA_HW_2_CPU_WDI_CMD_STATUS_SUCCESS = - FEATURE_ENUM_VAL(IPA_HW_FEATURE_WDI, 0), - IPA_HW_2_CPU_MAX_WDI_TX_CHANNELS = - FEATURE_ENUM_VAL(IPA_HW_FEATURE_WDI, 1), - IPA_HW_2_CPU_WDI_CE_RING_OVERRUN_POSSIBILITY = - FEATURE_ENUM_VAL(IPA_HW_FEATURE_WDI, 2), - IPA_HW_2_CPU_WDI_CE_RING_SET_UP_FAILURE = - FEATURE_ENUM_VAL(IPA_HW_FEATURE_WDI, 3), - IPA_HW_2_CPU_WDI_CE_RING_PARAMS_UNALIGNED = - FEATURE_ENUM_VAL(IPA_HW_FEATURE_WDI, 4), - IPA_HW_2_CPU_WDI_COMP_RING_OVERRUN_POSSIBILITY = - FEATURE_ENUM_VAL(IPA_HW_FEATURE_WDI, 5), - IPA_HW_2_CPU_WDI_COMP_RING_SET_UP_FAILURE = - FEATURE_ENUM_VAL(IPA_HW_FEATURE_WDI, 6), - IPA_HW_2_CPU_WDI_COMP_RING_PARAMS_UNALIGNED = - FEATURE_ENUM_VAL(IPA_HW_FEATURE_WDI, 7), - IPA_HW_2_CPU_WDI_UNKNOWN_TX_CHANNEL = - FEATURE_ENUM_VAL(IPA_HW_FEATURE_WDI, 8), - IPA_HW_2_CPU_WDI_TX_INVALID_FSM_TRANSITION = - FEATURE_ENUM_VAL(IPA_HW_FEATURE_WDI, 9), - IPA_HW_2_CPU_WDI_TX_FSM_TRANSITION_ERROR = - FEATURE_ENUM_VAL(IPA_HW_FEATURE_WDI, 10), - IPA_HW_2_CPU_MAX_WDI_RX_CHANNELS = - FEATURE_ENUM_VAL(IPA_HW_FEATURE_WDI, 11), - IPA_HW_2_CPU_WDI_RX_RING_PARAMS_UNALIGNED = - FEATURE_ENUM_VAL(IPA_HW_FEATURE_WDI, 12), - IPA_HW_2_CPU_WDI_RX_RING_SET_UP_FAILURE = - FEATURE_ENUM_VAL(IPA_HW_FEATURE_WDI, 13), - IPA_HW_2_CPU_WDI_UNKNOWN_RX_CHANNEL = - FEATURE_ENUM_VAL(IPA_HW_FEATURE_WDI, 14), - IPA_HW_2_CPU_WDI_RX_INVALID_FSM_TRANSITION = - FEATURE_ENUM_VAL(IPA_HW_FEATURE_WDI, 15), - IPA_HW_2_CPU_WDI_RX_FSM_TRANSITION_ERROR = - FEATURE_ENUM_VAL(IPA_HW_FEATURE_WDI, 16), -}; - -/** * enum ipa_hw_wdi_errors - WDI specific error types. * @IPA_HW_WDI_ERROR_NONE : No error persists * @IPA_HW_WDI_CHANNEL_ERROR : Error is specific to channel diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c index d53121292c03..be3c890db25c 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c @@ -946,7 +946,7 @@ int ipa2_get_ep_mapping(enum ipa_client_type client) void ipa2_set_client(int index, enum ipacm_client_enum client, bool uplink) { - if (client >= IPACM_CLIENT_MAX || client < IPACM_CLIENT_USB) { + if (client > IPACM_CLIENT_MAX || client < IPACM_CLIENT_USB) { IPAERR("Bad client number! client =%d\n", client); } else if (index >= IPA_MAX_NUM_PIPES || index < 0) { IPAERR("Bad pipe index! index =%d\n", index); diff --git a/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c index 774077494ea5..da014427852b 100644 --- a/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c +++ b/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c @@ -2334,6 +2334,29 @@ static struct platform_driver rmnet_ipa_driver = { .remove = ipa_wwan_remove, }; +/** + * rmnet_ipa_send_ssr_notification(bool ssr_done) - send SSR notification + * + * This function sends the SSR notification before modem shutdown and + * after_powerup from SSR framework, to user-space module + */ +static void rmnet_ipa_send_ssr_notification(bool ssr_done) +{ + struct ipa_msg_meta msg_meta; + int rc; + + memset(&msg_meta, 0, sizeof(struct ipa_msg_meta)); + if (ssr_done) + msg_meta.msg_type = IPA_SSR_AFTER_POWERUP; + else + msg_meta.msg_type = IPA_SSR_BEFORE_SHUTDOWN; + rc = ipa_send_msg(&msg_meta, NULL, NULL); + if (rc) { + IPAWANERR("ipa_send_msg failed: %d\n", rc); + return; + } +} + static int ssr_notifier_cb(struct notifier_block *this, unsigned long code, void *data) @@ -2341,6 +2364,8 @@ static int ssr_notifier_cb(struct notifier_block *this, if (ipa_rmnet_ctx.ipa_rmnet_ssr) { if (SUBSYS_BEFORE_SHUTDOWN == code) { pr_info("IPA received MPSS BEFORE_SHUTDOWN\n"); + /* send SSR before-shutdown notification to IPACM */ + rmnet_ipa_send_ssr_notification(false); atomic_set(&is_ssr, 1); ipa_q6_pre_shutdown_cleanup(); if (ipa_netdevs[0]) @@ -2517,6 +2542,26 @@ static void rmnet_ipa_get_network_stats_and_update(void) } /** + * rmnet_ipa_send_quota_reach_ind() - send quota_reach notification from + * IPA Modem + * This function sends the quota_reach indication from the IPA Modem driver + * via QMI, to user-space module + */ +static void rmnet_ipa_send_quota_reach_ind(void) +{ + struct ipa_msg_meta msg_meta; + int rc; + + memset(&msg_meta, 0, sizeof(struct ipa_msg_meta)); + msg_meta.msg_type = IPA_QUOTA_REACH; + rc = ipa_send_msg(&msg_meta, NULL, NULL); + if (rc) { + IPAWANERR("ipa_send_msg failed: %d\n", rc); + return; + } +} + +/** * rmnet_ipa_poll_tethering_stats() - Tethering stats polling IOCTL handler * @data - IOCTL data * @@ -2796,7 +2841,7 @@ int rmnet_ipa_query_tethering_stats_modem( IPAWANERR("reset the pipe stats\n"); } else { /* print tethered-client enum */ - IPAWANDBG_LOW("Tethered-client enum(%d)\n", data->ipa_client); + IPAWANDBG("Tethered-client enum(%d)\n", data->ipa_client); } rc = ipa_qmi_get_data_stats(req, resp); @@ -2805,10 +2850,6 @@ int rmnet_ipa_query_tethering_stats_modem( kfree(req); kfree(resp); return rc; - } else if (reset) { - kfree(req); - kfree(resp); - return 0; } if (resp->dl_dst_pipe_stats_list_valid) { @@ -2854,7 +2895,7 @@ int rmnet_ipa_query_tethering_stats_modem( } } } - IPAWANDBG_LOW("v4_rx_p(%lu) v6_rx_p(%lu) v4_rx_b(%lu) v6_rx_b(%lu)\n", + IPAWANDBG("v4_rx_p(%lu) v6_rx_p(%lu) v4_rx_b(%lu) v6_rx_b(%lu)\n", (unsigned long int) data->ipv4_rx_packets, (unsigned long int) data->ipv6_rx_packets, (unsigned long int) data->ipv4_rx_bytes, @@ -2904,7 +2945,7 @@ int rmnet_ipa_query_tethering_stats_modem( } } } - IPAWANDBG_LOW("tx_p_v4(%lu)v6(%lu)tx_b_v4(%lu) v6(%lu)\n", + IPAWANDBG("tx_p_v4(%lu)v6(%lu)tx_b_v4(%lu) v6(%lu)\n", (unsigned long int) data->ipv4_tx_packets, (unsigned long int) data->ipv6_tx_packets, (unsigned long int) data->ipv4_tx_bytes, @@ -2946,6 +2987,49 @@ int rmnet_ipa_query_tethering_stats(struct wan_ioctl_query_tether_stats *data, return rc; } +int rmnet_ipa_query_tethering_stats_all( + struct wan_ioctl_query_tether_stats_all *data) +{ + struct wan_ioctl_query_tether_stats tether_stats; + enum ipa_upstream_type upstream_type; + int rc = 0; + + memset(&tether_stats, 0, sizeof(struct wan_ioctl_query_tether_stats)); + /* get IPA backhaul type */ + upstream_type = find_upstream_type(data->upstreamIface); + + if (upstream_type == IPA_UPSTEAM_MAX) { + IPAWANERR(" Wrong upstreamIface name %s\n", + data->upstreamIface); + } else if (upstream_type == IPA_UPSTEAM_WLAN) { + IPAWANDBG_LOW(" query wifi-backhaul stats\n"); + rc = rmnet_ipa_query_tethering_stats_wifi( + &tether_stats, data->reset_stats); + if (rc) { + IPAWANERR("wlan WAN_IOC_QUERY_TETHER_STATS failed\n"); + return rc; + } + data->tx_bytes = tether_stats.ipv4_tx_bytes + + tether_stats.ipv6_tx_bytes; + data->rx_bytes = tether_stats.ipv4_rx_bytes + + tether_stats.ipv6_rx_bytes; + } else { + IPAWANDBG_LOW(" query modem-backhaul stats\n"); + tether_stats.ipa_client = data->ipa_client; + rc = rmnet_ipa_query_tethering_stats_modem( + &tether_stats, data->reset_stats); + if (rc) { + IPAWANERR("modem WAN_IOC_QUERY_TETHER_STATS failed\n"); + return rc; + } + data->tx_bytes = tether_stats.ipv4_tx_bytes + + tether_stats.ipv6_tx_bytes; + data->rx_bytes = tether_stats.ipv4_rx_bytes + + tether_stats.ipv6_rx_bytes; + } + return rc; +} + int rmnet_ipa_reset_tethering_stats(struct wan_ioctl_reset_tether_stats *data) { enum ipa_upstream_type upstream_type; @@ -3047,6 +3131,8 @@ void ipa_broadcast_quota_reach_ind(u32 mux_id, IPAWANERR("putting nlmsg: <%s> <%s> <%s>\n", alert_msg, iface_name_l, iface_name_m); kobject_uevent_env(&(ipa_netdevs[0]->dev.kobj), KOBJ_CHANGE, envp); + + rmnet_ipa_send_quota_reach_ind(); } /** @@ -3071,6 +3157,9 @@ void ipa_q6_handshake_complete(bool ssr_bootup) */ ipa2_proxy_clk_unvote(); + /* send SSR power-up notification to IPACM */ + rmnet_ipa_send_ssr_notification(true); + /* * It is required to recover the network stats after * SSR recovery diff --git a/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa_fd_ioctl.c b/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa_fd_ioctl.c index 46bfe021eb4b..02bdd0334e7f 100644 --- a/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa_fd_ioctl.c +++ b/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa_fd_ioctl.c @@ -47,6 +47,10 @@ #define WAN_IOC_QUERY_DL_FILTER_STATS32 _IOWR(WAN_IOC_MAGIC, \ WAN_IOCTL_QUERY_DL_FILTER_STATS, \ compat_uptr_t) +#define WAN_IOC_QUERY_TETHER_STATS_ALL32 _IOWR(WAN_IOC_MAGIC, \ + WAN_IOCTL_QUERY_TETHER_STATS_ALL, \ + compat_uptr_t) + #endif static unsigned int dev_num = 1; @@ -238,6 +242,32 @@ static long wan_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) } break; + case WAN_IOC_QUERY_TETHER_STATS_ALL: + IPAWANDBG_LOW("got WAN_IOC_QUERY_TETHER_STATS_ALL :>>>\n"); + pyld_sz = sizeof(struct wan_ioctl_query_tether_stats_all); + param = kzalloc(pyld_sz, GFP_KERNEL); + if (!param) { + retval = -ENOMEM; + break; + } + if (copy_from_user(param, (u8 *)arg, pyld_sz)) { + retval = -EFAULT; + break; + } + + if (rmnet_ipa_query_tethering_stats_all( + (struct wan_ioctl_query_tether_stats_all *)param)) { + IPAWANERR("WAN_IOC_QUERY_TETHER_STATS failed\n"); + retval = -EFAULT; + break; + } + + if (copy_to_user((u8 *)arg, param, pyld_sz)) { + retval = -EFAULT; + break; + } + break; + case WAN_IOC_RESET_TETHER_STATS: IPAWANDBG_LOW("got WAN_IOC_RESET_TETHER_STATS :>>>\n"); pyld_sz = sizeof(struct wan_ioctl_reset_tether_stats); diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_client.c b/drivers/platform/msm/ipa/ipa_v3/ipa_client.c index 81eae05d7ed9..e349ade46075 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_client.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_client.c @@ -857,6 +857,8 @@ static int ipa3_reset_with_open_aggr_frame_wa(u32 clnt_hdl, struct gsi_xfer_elem xfer_elem; int i; int aggr_active_bitmap = 0; + bool pipe_suspended = false; + struct ipa_ep_cfg_ctrl ctrl; IPADBG("Applying reset channel with open aggregation frame WA\n"); ipahal_write_reg(IPA_AGGR_FORCE_CLOSE, (1 << clnt_hdl)); @@ -883,6 +885,15 @@ static int ipa3_reset_with_open_aggr_frame_wa(u32 clnt_hdl, if (result) return -EFAULT; + ipahal_read_reg_n_fields(IPA_ENDP_INIT_CTRL_n, clnt_hdl, &ctrl); + if (ctrl.ipa_ep_suspend) { + IPADBG("pipe is suspended, remove suspend\n"); + pipe_suspended = true; + ctrl.ipa_ep_suspend = false; + ipahal_write_reg_n_fields(IPA_ENDP_INIT_CTRL_n, + clnt_hdl, &ctrl); + } + /* Start channel and put 1 Byte descriptor on it */ gsi_res = gsi_start_channel(ep->gsi_chan_hdl); if (gsi_res != GSI_STATUS_SUCCESS) { @@ -942,6 +953,13 @@ static int ipa3_reset_with_open_aggr_frame_wa(u32 clnt_hdl, */ msleep(IPA_POLL_AGGR_STATE_SLEEP_MSEC); + if (pipe_suspended) { + IPADBG("suspend the pipe again\n"); + ctrl.ipa_ep_suspend = true; + ipahal_write_reg_n_fields(IPA_ENDP_INIT_CTRL_n, + clnt_hdl, &ctrl); + } + /* Restore channels properties */ result = ipa3_restore_channel_properties(ep, &orig_chan_props, &orig_chan_scratch); @@ -956,6 +974,12 @@ queue_xfer_fail: ipa3_stop_gsi_channel(clnt_hdl); dma_free_coherent(ipa3_ctx->pdev, 1, buff, dma_addr); start_chan_fail: + if (pipe_suspended) { + IPADBG("suspend the pipe again\n"); + ctrl.ipa_ep_suspend = true; + ipahal_write_reg_n_fields(IPA_ENDP_INIT_CTRL_n, + clnt_hdl, &ctrl); + } ipa3_restore_channel_properties(ep, &orig_chan_props, &orig_chan_scratch); restore_props_fail: diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c index 72eb3808c7a4..fbf84ab7d2d4 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c @@ -61,6 +61,9 @@ const char *ipa3_event_name[] = { __stringify(ECM_DISCONNECT), __stringify(IPA_TETHERING_STATS_UPDATE_STATS), __stringify(IPA_TETHERING_STATS_UPDATE_NETWORK_STATS), + __stringify(IPA_QUOTA_REACH), + __stringify(IPA_SSR_BEFORE_SHUTDOWN), + __stringify(IPA_SSR_AFTER_POWERUP), }; const char *ipa3_hdr_l2_type_name[] = { diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c index f23062702f28..0492fa27c5b7 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c @@ -1568,7 +1568,7 @@ int ipa3_teardown_sys_pipe(u32 clnt_hdl) BUG(); return result; } - result = gsi_reset_channel(ep->gsi_chan_hdl); + result = ipa3_reset_gsi_channel(clnt_hdl); if (result != GSI_STATUS_SUCCESS) { IPAERR("Failed to reset chan: %d.\n", result); BUG(); diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.h b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.h index 6cd82f84bf13..d5d850309696 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.h @@ -190,6 +190,9 @@ int rmnet_ipa3_set_tether_client_pipe(struct wan_ioctl_set_tether_client_pipe int rmnet_ipa3_query_tethering_stats(struct wan_ioctl_query_tether_stats *data, bool reset); +int rmnet_ipa3_query_tethering_stats_all( + struct wan_ioctl_query_tether_stats_all *data); + int rmnet_ipa3_reset_tethering_stats(struct wan_ioctl_reset_tether_stats *data); int ipa3_qmi_get_data_stats(struct ipa_get_data_stats_req_msg_v01 *req, diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c index 57fa2465c9ea..e49bdc8c7083 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c @@ -1205,6 +1205,8 @@ int ipa3_connect_wdi_pipe(struct ipa_wdi_in_params *in, IPADBG("Skipping endpoint configuration.\n"); } + ipa3_enable_data_path(ipa_ep_idx); + out->clnt_hdl = ipa_ep_idx; if (!ep->skip_ep_cfg && IPA_CLIENT_IS_PROD(in->sys.client)) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c index 5ffc1f23f47c..d19de2a7bdb5 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c @@ -1002,7 +1002,7 @@ u8 ipa3_get_qmb_master_sel(enum ipa_client_type client) void ipa3_set_client(int index, enum ipacm_client_enum client, bool uplink) { - if (client >= IPACM_CLIENT_MAX || client < IPACM_CLIENT_USB) { + if (client > IPACM_CLIENT_MAX || client < IPACM_CLIENT_USB) { IPAERR("Bad client number! client =%d\n", client); } else if (index >= IPA3_MAX_NUM_PIPES || index < 0) { IPAERR("Bad pipe index! index =%d\n", index); diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c index 3855e0d46ca9..585f9e6bd492 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c @@ -646,6 +646,21 @@ static void ipareg_construct_endp_init_ctrl_n(enum ipahal_reg_name reg, IPA_ENDP_INIT_CTRL_n_ENDP_DELAY_BMSK); } +static void ipareg_parse_endp_init_ctrl_n(enum ipahal_reg_name reg, + void *fields, u32 val) +{ + struct ipa_ep_cfg_ctrl *ep_ctrl = + (struct ipa_ep_cfg_ctrl *)fields; + + ep_ctrl->ipa_ep_suspend = + ((val & IPA_ENDP_INIT_CTRL_n_ENDP_SUSPEND_BMSK) >> + IPA_ENDP_INIT_CTRL_n_ENDP_SUSPEND_SHFT); + + ep_ctrl->ipa_ep_delay = + ((val & IPA_ENDP_INIT_CTRL_n_ENDP_DELAY_BMSK) >> + IPA_ENDP_INIT_CTRL_n_ENDP_DELAY_SHFT); +} + static void ipareg_construct_endp_init_ctrl_scnd_n(enum ipahal_reg_name reg, const void *fields, u32 *val) { @@ -1018,7 +1033,8 @@ static struct ipahal_reg_obj ipahal_reg_objs[IPA_HW_MAX][IPA_REG_MAX] = { ipareg_construct_endp_init_nat_n, ipareg_parse_dummy, 0x0000080C, 0x70}, [IPA_HW_v3_0][IPA_ENDP_INIT_CTRL_n] = { - ipareg_construct_endp_init_ctrl_n, ipareg_parse_dummy, + ipareg_construct_endp_init_ctrl_n, + ipareg_parse_endp_init_ctrl_n, 0x00000800, 0x70}, [IPA_HW_v3_0][IPA_ENDP_INIT_CTRL_SCND_n] = { ipareg_construct_endp_init_ctrl_scnd_n, ipareg_parse_dummy, diff --git a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c index 04e5862cd960..1bd4f7fda1b7 100644 --- a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c @@ -2455,6 +2455,29 @@ static struct platform_driver rmnet_ipa_driver = { .remove = ipa3_wwan_remove, }; +/** + * rmnet_ipa_send_ssr_notification(bool ssr_done) - send SSR notification + * + * This function sends the SSR notification before modem shutdown and + * after_powerup from SSR framework, to user-space module + */ +static void rmnet_ipa_send_ssr_notification(bool ssr_done) +{ + struct ipa_msg_meta msg_meta; + int rc; + + memset(&msg_meta, 0, sizeof(struct ipa_msg_meta)); + if (ssr_done) + msg_meta.msg_type = IPA_SSR_AFTER_POWERUP; + else + msg_meta.msg_type = IPA_SSR_BEFORE_SHUTDOWN; + rc = ipa_send_msg(&msg_meta, NULL, NULL); + if (rc) { + IPAWANERR("ipa_send_msg failed: %d\n", rc); + return; + } +} + static int ipa3_ssr_notifier_cb(struct notifier_block *this, unsigned long code, void *data) @@ -2465,6 +2488,8 @@ static int ipa3_ssr_notifier_cb(struct notifier_block *this, switch (code) { case SUBSYS_BEFORE_SHUTDOWN: IPAWANINFO("IPA received MPSS BEFORE_SHUTDOWN\n"); + /* send SSR before-shutdown notification to IPACM */ + rmnet_ipa_send_ssr_notification(false); atomic_set(&rmnet_ipa3_ctx->is_ssr, 1); ipa3_q6_pre_shutdown_cleanup(); if (IPA_NETDEV()) @@ -2641,6 +2666,26 @@ static void rmnet_ipa_get_network_stats_and_update(void) } /** + * rmnet_ipa_send_quota_reach_ind() - send quota_reach notification from + * IPA Modem + * This function sends the quota_reach indication from the IPA Modem driver + * via QMI, to user-space module + */ +static void rmnet_ipa_send_quota_reach_ind(void) +{ + struct ipa_msg_meta msg_meta; + int rc; + + memset(&msg_meta, 0, sizeof(struct ipa_msg_meta)); + msg_meta.msg_type = IPA_QUOTA_REACH; + rc = ipa_send_msg(&msg_meta, NULL, NULL); + if (rc) { + IPAWANERR("ipa_send_msg failed: %d\n", rc); + return; + } +} + +/** * rmnet_ipa3_poll_tethering_stats() - Tethering stats polling IOCTL handler * @data - IOCTL data * @@ -2921,7 +2966,7 @@ static int rmnet_ipa3_query_tethering_stats_modem( IPAWANERR("reset the pipe stats\n"); } else { /* print tethered-client enum */ - IPAWANDBG_LOW("Tethered-client enum(%d)\n", data->ipa_client); + IPAWANDBG("Tethered-client enum(%d)\n", data->ipa_client); } rc = ipa3_qmi_get_data_stats(req, resp); @@ -2930,10 +2975,6 @@ static int rmnet_ipa3_query_tethering_stats_modem( kfree(req); kfree(resp); return rc; - } else if (reset) { - kfree(req); - kfree(resp); - return 0; } if (resp->dl_dst_pipe_stats_list_valid) { @@ -3071,6 +3112,49 @@ int rmnet_ipa3_query_tethering_stats(struct wan_ioctl_query_tether_stats *data, return rc; } +int rmnet_ipa3_query_tethering_stats_all( + struct wan_ioctl_query_tether_stats_all *data) +{ + struct wan_ioctl_query_tether_stats tether_stats; + enum ipa_upstream_type upstream_type; + int rc = 0; + + memset(&tether_stats, 0, sizeof(struct wan_ioctl_query_tether_stats)); + /* get IPA backhaul type */ + upstream_type = find_upstream_type(data->upstreamIface); + + if (upstream_type == IPA_UPSTEAM_MAX) { + IPAWANERR(" Wrong upstreamIface name %s\n", + data->upstreamIface); + } else if (upstream_type == IPA_UPSTEAM_WLAN) { + IPAWANDBG_LOW(" query wifi-backhaul stats\n"); + rc = rmnet_ipa3_query_tethering_stats_wifi( + &tether_stats, data->reset_stats); + if (rc) { + IPAWANERR("wlan WAN_IOC_QUERY_TETHER_STATS failed\n"); + return rc; + } + data->tx_bytes = tether_stats.ipv4_tx_bytes + + tether_stats.ipv6_tx_bytes; + data->rx_bytes = tether_stats.ipv4_rx_bytes + + tether_stats.ipv6_rx_bytes; + } else { + IPAWANDBG_LOW(" query modem-backhaul stats\n"); + tether_stats.ipa_client = data->ipa_client; + rc = rmnet_ipa3_query_tethering_stats_modem( + &tether_stats, data->reset_stats); + if (rc) { + IPAWANERR("modem WAN_IOC_QUERY_TETHER_STATS failed\n"); + return rc; + } + data->tx_bytes = tether_stats.ipv4_tx_bytes + + tether_stats.ipv6_tx_bytes; + data->rx_bytes = tether_stats.ipv4_rx_bytes + + tether_stats.ipv6_rx_bytes; + } + return rc; +} + int rmnet_ipa3_reset_tethering_stats(struct wan_ioctl_reset_tether_stats *data) { enum ipa_upstream_type upstream_type; @@ -3168,6 +3252,8 @@ void ipa3_broadcast_quota_reach_ind(u32 mux_id, alert_msg, iface_name_l, iface_name_m); kobject_uevent_env(&(IPA_NETDEV()->dev.kobj), KOBJ_CHANGE, envp); + + rmnet_ipa_send_quota_reach_ind(); } /** @@ -3192,6 +3278,9 @@ void ipa3_q6_handshake_complete(bool ssr_bootup) */ ipa3_proxy_clk_unvote(); + /* send SSR power-up notification to IPACM */ + rmnet_ipa_send_ssr_notification(true); + /* * It is required to recover the network stats after * SSR recovery diff --git a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa_fd_ioctl.c b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa_fd_ioctl.c index ffd127a21ed1..51bbec464e4d 100644 --- a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa_fd_ioctl.c +++ b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa_fd_ioctl.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -47,6 +47,9 @@ #define WAN_IOC_QUERY_DL_FILTER_STATS32 _IOWR(WAN_IOC_MAGIC, \ WAN_IOCTL_QUERY_DL_FILTER_STATS, \ compat_uptr_t) +#define WAN_IOC_QUERY_TETHER_STATS_ALL32 _IOWR(WAN_IOC_MAGIC, \ + WAN_IOCTL_QUERY_TETHER_STATS_ALL, \ + compat_uptr_t) #endif static unsigned int dev_num = 1; @@ -265,6 +268,32 @@ static long ipa3_wan_ioctl(struct file *filp, } break; + case WAN_IOC_QUERY_TETHER_STATS_ALL: + IPAWANDBG_LOW("got WAN_IOC_QUERY_TETHER_STATS_ALL :>>>\n"); + pyld_sz = sizeof(struct wan_ioctl_query_tether_stats_all); + param = kzalloc(pyld_sz, GFP_KERNEL); + if (!param) { + retval = -ENOMEM; + break; + } + if (copy_from_user(param, (u8 *)arg, pyld_sz)) { + retval = -EFAULT; + break; + } + + if (rmnet_ipa3_query_tethering_stats_all( + (struct wan_ioctl_query_tether_stats_all *)param)) { + IPAWANERR("WAN_IOC_QUERY_TETHER_STATS failed\n"); + retval = -EFAULT; + break; + } + + if (copy_to_user((u8 *)arg, param, pyld_sz)) { + retval = -EFAULT; + break; + } + break; + case WAN_IOC_RESET_TETHER_STATS: IPAWANDBG_LOW("device %s got WAN_IOC_RESET_TETHER_STATS :>>>\n", DRIVER_NAME); diff --git a/drivers/platform/msm/msm_ext_display.c b/drivers/platform/msm/msm_ext_display.c index 6f9a13040cd5..c7c1b1567bf3 100644 --- a/drivers/platform/msm/msm_ext_display.c +++ b/drivers/platform/msm/msm_ext_display.c @@ -654,6 +654,7 @@ int msm_ext_disp_register_audio_codec(struct platform_device *pdev, { int ret = 0; struct msm_ext_disp *ext_disp = NULL; + struct msm_ext_disp_list *node = NULL; if (!pdev || !ops) { pr_err("Invalid params\n"); @@ -671,17 +672,23 @@ int msm_ext_disp_register_audio_codec(struct platform_device *pdev, if ((ext_disp->current_disp != EXT_DISPLAY_TYPE_MAX) && ext_disp->ops) { pr_err("Codec already registered\n"); - ret = -EINVAL; - goto end; + mutex_unlock(&ext_disp->lock); + return -EINVAL; } ext_disp->ops = ops; - pr_debug("audio codec registered\n"); - -end: mutex_unlock(&ext_disp->lock); + list_for_each_entry(node, &ext_disp->display_list, list) { + struct msm_ext_disp_init_data *data = node->data; + + if (data->codec_ops.codec_ready) + data->codec_ops.codec_ready(data->pdev); + } + + pr_debug("audio codec registered\n"); + return ret; } diff --git a/drivers/platform/msm/seemp_core/seemp_logk.c b/drivers/platform/msm/seemp_core/seemp_logk.c index d0f21943cb0f..264db54f0d6e 100644 --- a/drivers/platform/msm/seemp_core/seemp_logk.c +++ b/drivers/platform/msm/seemp_core/seemp_logk.c @@ -287,7 +287,7 @@ static bool seemp_logk_get_bit_from_vector(__u8 *pVec, __u32 index) unsigned int bit_num = index%8; unsigned char byte; - if (DIV_ROUND_UP(index, 8) > MASK_BUFFER_SIZE) + if (byte_num >= MASK_BUFFER_SIZE) return false; byte = pVec[byte_num]; diff --git a/drivers/power/reset/msm-poweroff.c b/drivers/power/reset/msm-poweroff.c index 8d038ba0770d..acea4f213484 100644 --- a/drivers/power/reset/msm-poweroff.c +++ b/drivers/power/reset/msm-poweroff.c @@ -497,13 +497,13 @@ static size_t store_dload_mode(struct kobject *kobj, struct attribute *attr, if (sysfs_streq(buf, "full")) { dload_type = SCM_DLOAD_FULLDUMP; } else if (sysfs_streq(buf, "mini")) { - if (!msm_minidump_enabled()) { - pr_info("Minidump is not enabled\n"); + if (!minidump_enabled) { + pr_err("Minidump is not enabled\n"); return -ENODEV; } dload_type = SCM_DLOAD_MINIDUMP; } else { - pr_info("Invalid value. Use 'full' or 'mini'\n"); + pr_err("Invalid value. Use 'full' or 'mini'\n"); return -EINVAL; } diff --git a/drivers/power/supply/qcom/qpnp-fg-gen3.c b/drivers/power/supply/qcom/qpnp-fg-gen3.c index 4368709118ac..d0f7a5e1e227 100644 --- a/drivers/power/supply/qcom/qpnp-fg-gen3.c +++ b/drivers/power/supply/qcom/qpnp-fg-gen3.c @@ -3366,6 +3366,16 @@ static int fg_hw_init(struct fg_chip *chip) return rc; } + if (is_debug_batt_id(chip)) { + val = ESR_NO_PULL_DOWN; + rc = fg_masked_write(chip, BATT_INFO_ESR_PULL_DN_CFG(chip), + ESR_PULL_DOWN_MODE_MASK, val); + if (rc < 0) { + pr_err("Error in writing esr_pull_down, rc=%d\n", rc); + return rc; + } + } + return 0; } diff --git a/drivers/power/supply/qcom/qpnp-smb2.c b/drivers/power/supply/qcom/qpnp-smb2.c index 024c968e484a..94b9e9c4d912 100644 --- a/drivers/power/supply/qcom/qpnp-smb2.c +++ b/drivers/power/supply/qcom/qpnp-smb2.c @@ -427,6 +427,7 @@ static enum power_supply_property smb2_usb_props[] = { POWER_SUPPLY_PROP_PE_START, POWER_SUPPLY_PROP_CTM_CURRENT_MAX, POWER_SUPPLY_PROP_HW_CURRENT_MAX, + POWER_SUPPLY_PROP_REAL_TYPE, }; static int smb2_usb_get_prop(struct power_supply *psy, @@ -446,6 +447,16 @@ static int smb2_usb_get_prop(struct power_supply *psy, break; case POWER_SUPPLY_PROP_ONLINE: rc = smblib_get_prop_usb_online(chg, val); + if (!val->intval) + break; + + rc = smblib_get_prop_typec_mode(chg, val); + if ((val->intval == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT || + chg->micro_usb_mode) && + chg->real_charger_type == POWER_SUPPLY_TYPE_USB) + val->intval = 0; + else + val->intval = 1; break; case POWER_SUPPLY_PROP_VOLTAGE_MIN: val->intval = chg->voltage_min_uv; @@ -463,10 +474,13 @@ static int smb2_usb_get_prop(struct power_supply *psy, rc = smblib_get_prop_usb_current_max(chg, val); break; case POWER_SUPPLY_PROP_TYPE: + val->intval = POWER_SUPPLY_TYPE_USB_PD; + break; + case POWER_SUPPLY_PROP_REAL_TYPE: if (chip->bad_part) - val->intval = POWER_SUPPLY_TYPE_USB; + val->intval = POWER_SUPPLY_TYPE_USB_PD; else - val->intval = chg->usb_psy_desc.type; + val->intval = chg->real_charger_type; break; case POWER_SUPPLY_PROP_TYPEC_MODE: if (chg->micro_usb_mode) @@ -608,7 +622,7 @@ static int smb2_init_usb_psy(struct smb2 *chip) struct smb_charger *chg = &chip->chg; chg->usb_psy_desc.name = "usb"; - chg->usb_psy_desc.type = POWER_SUPPLY_TYPE_UNKNOWN; + chg->usb_psy_desc.type = POWER_SUPPLY_TYPE_USB_PD; chg->usb_psy_desc.properties = smb2_usb_props; chg->usb_psy_desc.num_properties = ARRAY_SIZE(smb2_usb_props); chg->usb_psy_desc.get_property = smb2_usb_get_prop; @@ -628,6 +642,97 @@ static int smb2_init_usb_psy(struct smb2 *chip) return 0; } +/******************************** + * USB PC_PORT PSY REGISTRATION * + ********************************/ +static enum power_supply_property smb2_usb_port_props[] = { + POWER_SUPPLY_PROP_TYPE, + POWER_SUPPLY_PROP_ONLINE, +}; + +static int smb2_usb_port_get_prop(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct smb2 *chip = power_supply_get_drvdata(psy); + struct smb_charger *chg = &chip->chg; + int rc = 0; + + switch (psp) { + case POWER_SUPPLY_PROP_TYPE: + val->intval = POWER_SUPPLY_TYPE_USB; + break; + case POWER_SUPPLY_PROP_ONLINE: + rc = smblib_get_prop_usb_online(chg, val); + if (!val->intval) + break; + + rc = smblib_get_prop_typec_mode(chg, val); + if ((val->intval == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT || + chg->micro_usb_mode) && + chg->real_charger_type == POWER_SUPPLY_TYPE_USB) + val->intval = 1; + else + val->intval = 0; + break; + default: + pr_err_ratelimited("Get prop %d is not supported in pc_port\n", + psp); + return -EINVAL; + } + + if (rc < 0) { + pr_debug("Couldn't get prop %d rc = %d\n", psp, rc); + return -ENODATA; + } + + return 0; +} + +static int smb2_usb_port_set_prop(struct power_supply *psy, + enum power_supply_property psp, + const union power_supply_propval *val) +{ + int rc = 0; + + switch (psp) { + default: + pr_err_ratelimited("Set prop %d is not supported in pc_port\n", + psp); + rc = -EINVAL; + break; + } + + return rc; +} + +static const struct power_supply_desc usb_port_psy_desc = { + .name = "pc_port", + .type = POWER_SUPPLY_TYPE_USB, + .properties = smb2_usb_port_props, + .num_properties = ARRAY_SIZE(smb2_usb_port_props), + .get_property = smb2_usb_port_get_prop, + .set_property = smb2_usb_port_set_prop, +}; + +static int smb2_init_usb_port_psy(struct smb2 *chip) +{ + struct power_supply_config usb_port_cfg = {}; + struct smb_charger *chg = &chip->chg; + + usb_port_cfg.drv_data = chip; + usb_port_cfg.of_node = chg->dev->of_node; + chg->usb_port_psy = power_supply_register(chg->dev, + &usb_port_psy_desc, + &usb_port_cfg); + if (IS_ERR(chg->usb_port_psy)) { + pr_err("Couldn't register USB pc_port power supply\n"); + return PTR_ERR(chg->usb_port_psy); + } + + return 0; +} + /***************************** * USB MAIN PSY REGISTRATION * *****************************/ @@ -1061,6 +1166,9 @@ static int smb2_batt_set_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_DP_DM: rc = smblib_dp_dm(chg, val->intval); break; + case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED: + rc = smblib_set_prop_input_current_limited(chg, val); + break; default: rc = -EINVAL; } @@ -1078,6 +1186,7 @@ static int smb2_batt_prop_is_writeable(struct power_supply *psy, case POWER_SUPPLY_PROP_PARALLEL_DISABLE: case POWER_SUPPLY_PROP_DP_DM: case POWER_SUPPLY_PROP_RERUN_AICL: + case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED: return 1; default: break; @@ -2266,7 +2375,13 @@ static int smb2_probe(struct platform_device *pdev) rc = smb2_init_usb_main_psy(chip); if (rc < 0) { - pr_err("Couldn't initialize usb psy rc=%d\n", rc); + pr_err("Couldn't initialize usb main psy rc=%d\n", rc); + goto cleanup; + } + + rc = smb2_init_usb_port_psy(chip); + if (rc < 0) { + pr_err("Couldn't initialize usb pc_port psy rc=%d\n", rc); goto cleanup; } @@ -2324,7 +2439,7 @@ static int smb2_probe(struct platform_device *pdev) device_init_wakeup(chg->dev, true); pr_info("QPNP SMB2 probed successfully usb:present=%d type=%d batt:present = %d health = %d charge = %d\n", - usb_present, chg->usb_psy_desc.type, + usb_present, chg->real_charger_type, batt_present, batt_health, batt_charge_type); return rc; @@ -2336,6 +2451,8 @@ cleanup: power_supply_unregister(chg->usb_main_psy); if (chg->usb_psy) power_supply_unregister(chg->usb_psy); + if (chg->usb_port_psy) + power_supply_unregister(chg->usb_port_psy); if (chg->dc_psy) power_supply_unregister(chg->dc_psy); if (chg->vconn_vreg && chg->vconn_vreg->rdev) @@ -2356,6 +2473,7 @@ static int smb2_remove(struct platform_device *pdev) power_supply_unregister(chg->batt_psy); power_supply_unregister(chg->usb_psy); + power_supply_unregister(chg->usb_port_psy); regulator_unregister(chg->vconn_vreg->rdev); regulator_unregister(chg->vbus_vreg->rdev); diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c index ecfb532e5b3c..a191391a3904 100644 --- a/drivers/power/supply/qcom/smb-lib.c +++ b/drivers/power/supply/qcom/smb-lib.c @@ -550,9 +550,9 @@ static const struct apsd_result *smblib_update_usb_type(struct smb_charger *chg) /* if PD is active, APSD is disabled so won't have a valid result */ if (chg->pd_active) - chg->usb_psy_desc.type = POWER_SUPPLY_TYPE_USB_PD; + chg->real_charger_type = POWER_SUPPLY_TYPE_USB_PD; else - chg->usb_psy_desc.type = apsd_result->pst; + chg->real_charger_type = apsd_result->pst; smblib_dbg(chg, PR_MISC, "APSD=%s PD=%d\n", apsd_result->name, chg->pd_active); @@ -858,7 +858,7 @@ int smblib_set_icl_current(struct smb_charger *chg, int icl_ua) /* configure current */ if (pval.intval == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT - && (chg->usb_psy_desc.type == POWER_SUPPLY_TYPE_USB)) { + && (chg->real_charger_type == POWER_SUPPLY_TYPE_USB)) { rc = set_sdp_current(chg, icl_ua); if (rc < 0) { smblib_err(chg, "Couldn't set SDP ICL rc=%d\n", rc); @@ -879,10 +879,10 @@ override_suspend_config: /* remove override if no voters - hw defaults is desired */ override = false; } else if (pval.intval == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT) { - if (chg->usb_psy_desc.type == POWER_SUPPLY_TYPE_USB) + if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB) /* For std cable with type = SDP never override */ override = false; - else if (chg->usb_psy_desc.type == POWER_SUPPLY_TYPE_USB_CDP + else if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_CDP && icl_ua == 1500000) /* * For std cable with type = CDP override only if @@ -1707,6 +1707,11 @@ int smblib_get_prop_input_current_limited(struct smb_charger *chg, u8 stat; int rc; + if (chg->fake_input_current_limited >= 0) { + val->intval = chg->fake_input_current_limited; + return 0; + } + rc = smblib_read(chg, AICL_STATUS_REG, &stat); if (rc < 0) { smblib_err(chg, "Couldn't read AICL_STATUS rc=%d\n", rc); @@ -1898,6 +1903,13 @@ int smblib_set_prop_charge_qnovo_enable(struct smb_charger *chg, return rc; } +int smblib_set_prop_input_current_limited(struct smb_charger *chg, + const union power_supply_propval *val) +{ + chg->fake_input_current_limited = val->intval; + return 0; +} + int smblib_rerun_aicl(struct smb_charger *chg) { int rc, settled_icl_ua; @@ -3314,7 +3326,7 @@ static void smblib_hvdcp_adaptive_voltage_change(struct smb_charger *chg) int pulses; power_supply_changed(chg->usb_main_psy); - if (chg->usb_psy_desc.type == POWER_SUPPLY_TYPE_USB_HVDCP) { + if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_HVDCP) { rc = smblib_read(chg, QC_CHANGE_STATUS_REG, &stat); if (rc < 0) { smblib_err(chg, @@ -3342,7 +3354,7 @@ static void smblib_hvdcp_adaptive_voltage_change(struct smb_charger *chg) } } - if (chg->usb_psy_desc.type == POWER_SUPPLY_TYPE_USB_HVDCP_3) { + if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_HVDCP_3) { rc = smblib_read(chg, QC_PULSE_COUNT_STATUS_REG, &stat); if (rc < 0) { smblib_err(chg, @@ -4471,6 +4483,7 @@ int smblib_init(struct smb_charger *chg) INIT_DELAYED_WORK(&chg->pl_enable_work, smblib_pl_enable_work); INIT_WORK(&chg->legacy_detection_work, smblib_legacy_detection_work); chg->fake_capacity = -EINVAL; + chg->fake_input_current_limited = -EINVAL; switch (chg->mode) { case PARALLEL_MASTER: diff --git a/drivers/power/supply/qcom/smb-lib.h b/drivers/power/supply/qcom/smb-lib.h index d14ea86bf0c6..5dc60ecb9436 100644 --- a/drivers/power/supply/qcom/smb-lib.h +++ b/drivers/power/supply/qcom/smb-lib.h @@ -244,6 +244,8 @@ struct smb_charger { struct power_supply *bms_psy; struct power_supply_desc usb_psy_desc; struct power_supply *usb_main_psy; + struct power_supply *usb_port_psy; + enum power_supply_type real_charger_type; /* notifiers */ struct notifier_block nb; @@ -316,6 +318,7 @@ struct smb_charger { bool typec_present; u8 typec_status[5]; bool typec_legacy_valid; + int fake_input_current_limited; /* workaround flag */ u32 wa_flags; @@ -419,6 +422,8 @@ int smblib_set_prop_batt_capacity(struct smb_charger *chg, const union power_supply_propval *val); int smblib_set_prop_system_temp_level(struct smb_charger *chg, const union power_supply_propval *val); +int smblib_set_prop_input_current_limited(struct smb_charger *chg, + const union power_supply_propval *val); int smblib_get_prop_dc_present(struct smb_charger *chg, union power_supply_propval *val); diff --git a/drivers/power/supply/qcom/smb-reg.h b/drivers/power/supply/qcom/smb-reg.h index 3f260a407721..167666a8c548 100644 --- a/drivers/power/supply/qcom/smb-reg.h +++ b/drivers/power/supply/qcom/smb-reg.h @@ -1025,14 +1025,4 @@ enum { /* CHGR FREQ Peripheral registers */ #define FREQ_CLK_DIV_REG (CHGR_FREQ_BASE + 0x50) -/* SMB1355 specific registers */ -#define SMB1355_TEMP_COMP_STATUS_REG (MISC_BASE + 0x07) -#define SKIN_TEMP_RST_HOT_BIT BIT(6) -#define SKIN_TEMP_UB_HOT_BIT BIT(5) -#define SKIN_TEMP_LB_HOT_BIT BIT(4) -#define DIE_TEMP_TSD_HOT_BIT BIT(3) -#define DIE_TEMP_RST_HOT_BIT BIT(2) -#define DIE_TEMP_UB_HOT_BIT BIT(1) -#define DIE_TEMP_LB_HOT_BIT BIT(0) - #endif /* __SMB2_CHARGER_REG_H */ diff --git a/drivers/power/supply/qcom/smb138x-charger.c b/drivers/power/supply/qcom/smb138x-charger.c index e4a876126444..694591c3ec56 100644 --- a/drivers/power/supply/qcom/smb138x-charger.c +++ b/drivers/power/supply/qcom/smb138x-charger.c @@ -104,8 +104,6 @@ struct smb138x { struct smb_dt_props dt; struct power_supply *parallel_psy; u32 wa_flags; - struct pmic_revid_data *pmic_rev_id; - char *name; }; static int __debug_mask; @@ -169,14 +167,6 @@ static int smb138x_parse_dt(struct smb138x *chip) if (rc < 0) chip->dt.pl_mode = POWER_SUPPLY_PL_USBMID_USBMID; - /* check that smb1355 is configured to run in mid-mid mode */ - if (chip->pmic_rev_id->pmic_subtype == SMB1355_SUBTYPE - && chip->dt.pl_mode != POWER_SUPPLY_PL_USBMID_USBMID) { - pr_err("Smb1355 can only run in MID-MID mode, saw = %d mode\n", - chip->dt.pl_mode); - return -EINVAL; - } - chip->dt.suspend_input = of_property_read_bool(node, "qcom,suspend-input"); @@ -489,30 +479,6 @@ static int smb138x_init_batt_psy(struct smb138x *chip) * PARALLEL PSY REGISTRATION * *****************************/ -static int smb1355_get_prop_connector_health(struct smb138x *chip) -{ - struct smb_charger *chg = &chip->chg; - u8 temp; - int rc; - - rc = smblib_read(chg, SMB1355_TEMP_COMP_STATUS_REG, &temp); - if (rc < 0) { - pr_err("Couldn't read comp stat reg rc = %d\n", rc); - return POWER_SUPPLY_HEALTH_UNKNOWN; - } - - if (temp & SKIN_TEMP_RST_HOT_BIT) - return POWER_SUPPLY_HEALTH_OVERHEAT; - - if (temp & SKIN_TEMP_UB_HOT_BIT) - return POWER_SUPPLY_HEALTH_HOT; - - if (temp & SKIN_TEMP_LB_HOT_BIT) - return POWER_SUPPLY_HEALTH_WARM; - - return POWER_SUPPLY_HEALTH_COOL; -} - static int smb138x_get_prop_connector_health(struct smb138x *chip) { struct smb_charger *chg = &chip->chg; @@ -570,54 +536,18 @@ static enum power_supply_property smb138x_parallel_props[] = { POWER_SUPPLY_PROP_PIN_ENABLED, POWER_SUPPLY_PROP_INPUT_SUSPEND, POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED, + POWER_SUPPLY_PROP_CURRENT_MAX, POWER_SUPPLY_PROP_VOLTAGE_MAX, POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, - POWER_SUPPLY_PROP_MODEL_NAME, - POWER_SUPPLY_PROP_PARALLEL_MODE, - POWER_SUPPLY_PROP_CONNECTOR_HEALTH, - POWER_SUPPLY_PROP_SET_SHIP_MODE, + POWER_SUPPLY_PROP_CURRENT_NOW, POWER_SUPPLY_PROP_CHARGER_TEMP, POWER_SUPPLY_PROP_CHARGER_TEMP_MAX, - POWER_SUPPLY_PROP_CURRENT_NOW, - POWER_SUPPLY_PROP_CURRENT_MAX, -}; - -static enum power_supply_property smb1355_parallel_props[] = { - POWER_SUPPLY_PROP_CHARGE_TYPE, - POWER_SUPPLY_PROP_CHARGING_ENABLED, - POWER_SUPPLY_PROP_PIN_ENABLED, - POWER_SUPPLY_PROP_INPUT_SUSPEND, - POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED, - POWER_SUPPLY_PROP_VOLTAGE_MAX, - POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, POWER_SUPPLY_PROP_MODEL_NAME, POWER_SUPPLY_PROP_PARALLEL_MODE, POWER_SUPPLY_PROP_CONNECTOR_HEALTH, POWER_SUPPLY_PROP_SET_SHIP_MODE, - POWER_SUPPLY_PROP_CHARGER_TEMP, - POWER_SUPPLY_PROP_CHARGER_TEMP_MAX, }; -static int smb138x_get_parallel_charging(struct smb138x *chip, int *disabled) -{ - struct smb_charger *chg = &chip->chg; - int rc = 0; - u8 cfg2; - - rc = smblib_read(chg, CHGR_CFG2_REG, &cfg2); - if (rc < 0) { - pr_err("Couldn't read en_cmg_reg rc=%d\n", rc); - return rc; - } - - if (cfg2 & CHG_EN_SRC_BIT) - *disabled = 0; - else - *disabled = 1; - - return 0; -} - static int smb138x_parallel_get_prop(struct power_supply *psy, enum power_supply_property prop, union power_supply_propval *val) @@ -644,7 +574,7 @@ static int smb138x_parallel_get_prop(struct power_supply *psy, val->intval = !(temp & DISABLE_CHARGING_BIT); break; case POWER_SUPPLY_PROP_INPUT_SUSPEND: - rc = smb138x_get_parallel_charging(chip, &val->intval); + rc = smblib_get_usb_suspend(chg, &val->intval); break; case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED: if ((chip->dt.pl_mode == POWER_SUPPLY_PL_USBIN_USBIN) @@ -653,6 +583,14 @@ static int smb138x_parallel_get_prop(struct power_supply *psy, else val->intval = 0; break; + case POWER_SUPPLY_PROP_CURRENT_MAX: + if ((chip->dt.pl_mode == POWER_SUPPLY_PL_USBIN_USBIN) + || (chip->dt.pl_mode == POWER_SUPPLY_PL_USBIN_USBIN_EXT)) + rc = smblib_get_charge_param(chg, &chg->param.usb_icl, + &val->intval); + else + val->intval = 0; + break; case POWER_SUPPLY_PROP_VOLTAGE_MAX: rc = smblib_get_charge_param(chg, &chg->param.fv, &val->intval); break; @@ -660,46 +598,28 @@ static int smb138x_parallel_get_prop(struct power_supply *psy, rc = smblib_get_charge_param(chg, &chg->param.fcc, &val->intval); break; + case POWER_SUPPLY_PROP_CURRENT_NOW: + rc = smblib_get_prop_slave_current_now(chg, val); + break; + case POWER_SUPPLY_PROP_CHARGER_TEMP: + rc = smb138x_get_prop_charger_temp(chip, val); + break; + case POWER_SUPPLY_PROP_CHARGER_TEMP_MAX: + rc = smblib_get_prop_charger_temp_max(chg, val); + break; case POWER_SUPPLY_PROP_MODEL_NAME: - val->strval = chip->name; + val->strval = "smb138x"; break; case POWER_SUPPLY_PROP_PARALLEL_MODE: val->intval = chip->dt.pl_mode; break; case POWER_SUPPLY_PROP_CONNECTOR_HEALTH: - if (chip->pmic_rev_id->pmic_subtype != SMB1355_SUBTYPE) - val->intval = smb138x_get_prop_connector_health(chip); - else - val->intval = smb1355_get_prop_connector_health(chip); + val->intval = smb138x_get_prop_connector_health(chip); break; case POWER_SUPPLY_PROP_SET_SHIP_MODE: /* Not in ship mode as long as device is active */ val->intval = 0; break; - case POWER_SUPPLY_PROP_CHARGER_TEMP: - if (chip->pmic_rev_id->pmic_subtype != SMB1355_SUBTYPE) - rc = smb138x_get_prop_charger_temp(chip, val); - else - rc = smblib_get_prop_charger_temp(chg, val); - break; - case POWER_SUPPLY_PROP_CHARGER_TEMP_MAX: - rc = smblib_get_prop_charger_temp_max(chg, val); - break; - case POWER_SUPPLY_PROP_CURRENT_NOW: - if (chip->pmic_rev_id->pmic_subtype != SMB1355_SUBTYPE) - rc = smblib_get_prop_slave_current_now(chg, val); - else - rc = -ENODATA; - break; - case POWER_SUPPLY_PROP_CURRENT_MAX: - if ((chip->pmic_rev_id->pmic_subtype != SMB1355_SUBTYPE) - && ((chip->dt.pl_mode == POWER_SUPPLY_PL_USBIN_USBIN) - || (chip->dt.pl_mode == POWER_SUPPLY_PL_USBIN_USBIN_EXT))) - rc = smblib_get_charge_param(chg, &chg->param.usb_icl, - &val->intval); - else - rc = -ENODATA; - break; default: pr_err("parallel power supply get prop %d not supported\n", prop); @@ -714,33 +634,28 @@ static int smb138x_parallel_get_prop(struct power_supply *psy, return rc; } -static int smb138x_set_parallel_charging(struct smb138x *chip, bool disable) +static int smb138x_set_parallel_suspend(struct smb138x *chip, bool suspend) { struct smb_charger *chg = &chip->chg; int rc = 0; rc = smblib_masked_write(chg, WD_CFG_REG, WDOG_TIMER_EN_BIT, - disable ? 0 : WDOG_TIMER_EN_BIT); + suspend ? 0 : WDOG_TIMER_EN_BIT); if (rc < 0) { pr_err("Couldn't %s watchdog rc=%d\n", - disable ? "disable" : "enable", rc); - disable = true; + suspend ? "disable" : "enable", rc); + suspend = true; } - /* - * Configure charge enable for high polarity and - * When disabling charging set it to cmd register control(cmd bit=0) - * When enabling charging set it to pin control - */ - rc = smblib_masked_write(chg, CHGR_CFG2_REG, - CHG_EN_POLARITY_BIT | CHG_EN_SRC_BIT, - disable ? 0 : CHG_EN_SRC_BIT); + rc = smblib_masked_write(chg, USBIN_CMD_IL_REG, USBIN_SUSPEND_BIT, + suspend ? USBIN_SUSPEND_BIT : 0); if (rc < 0) { - pr_err("Couldn't configure charge enable source rc=%d\n", rc); + pr_err("Couldn't %s parallel charger rc=%d\n", + suspend ? "suspend" : "resume", rc); return rc; } - return 0; + return rc; } static int smb138x_parallel_set_prop(struct power_supply *psy, @@ -753,7 +668,7 @@ static int smb138x_parallel_set_prop(struct power_supply *psy, switch (prop) { case POWER_SUPPLY_PROP_INPUT_SUSPEND: - rc = smb138x_set_parallel_charging(chip, (bool)val->intval); + rc = smb138x_set_parallel_suspend(chip, (bool)val->intval); break; case POWER_SUPPLY_PROP_CURRENT_MAX: if ((chip->dt.pl_mode == POWER_SUPPLY_PL_USBIN_USBIN) @@ -788,7 +703,7 @@ static int smb138x_parallel_prop_is_writeable(struct power_supply *psy, return 0; } -static struct power_supply_desc parallel_psy_desc = { +static const struct power_supply_desc parallel_psy_desc = { .name = "parallel", .type = POWER_SUPPLY_TYPE_PARALLEL, .properties = smb138x_parallel_props, @@ -816,28 +731,6 @@ static int smb138x_init_parallel_psy(struct smb138x *chip) return 0; } -static int smb1355_init_parallel_psy(struct smb138x *chip) -{ - struct power_supply_config parallel_cfg = {}; - struct smb_charger *chg = &chip->chg; - - parallel_cfg.drv_data = chip; - parallel_cfg.of_node = chg->dev->of_node; - - /* change to smb1355's property list */ - parallel_psy_desc.properties = smb1355_parallel_props; - parallel_psy_desc.num_properties = ARRAY_SIZE(smb1355_parallel_props); - chip->parallel_psy = devm_power_supply_register(chg->dev, - ¶llel_psy_desc, - ¶llel_cfg); - if (IS_ERR(chip->parallel_psy)) { - pr_err("Couldn't register parallel power supply\n"); - return PTR_ERR(chip->parallel_psy); - } - - return 0; -} - /****************************** * VBUS REGULATOR REGISTRATION * ******************************/ @@ -971,32 +864,35 @@ static int smb138x_init_slave_hw(struct smb138x *chip) return rc; } - /* disable the charging path when under s/w control */ - rc = smblib_masked_write(chg, CHARGING_ENABLE_CMD_REG, - CHARGING_ENABLE_CMD_BIT, 0); + /* suspend parallel charging */ + rc = smb138x_set_parallel_suspend(chip, true); if (rc < 0) { - pr_err("Couldn't disable charging rc=%d\n", rc); + pr_err("Couldn't suspend parallel charging rc=%d\n", rc); return rc; } - /* disable parallel charging path */ - rc = smb138x_set_parallel_charging(chip, true); + /* initialize FCC to 0 */ + rc = smblib_set_charge_param(chg, &chg->param.fcc, 0); if (rc < 0) { - pr_err("Couldn't disable parallel path rc=%d\n", rc); + pr_err("Couldn't set 0 FCC rc=%d\n", rc); return rc; } - /* unsuspend parallel charging */ - rc = smblib_masked_write(chg, USBIN_CMD_IL_REG, USBIN_SUSPEND_BIT, 0); + /* enable the charging path */ + rc = smblib_masked_write(chg, CHARGING_ENABLE_CMD_REG, + CHARGING_ENABLE_CMD_BIT, + CHARGING_ENABLE_CMD_BIT); if (rc < 0) { - pr_err("Couldn't unsuspend parallel charging rc=%d\n", rc); + pr_err("Couldn't enable charging rc=%d\n", rc); return rc; } - /* initialize FCC to 0 */ - rc = smblib_set_charge_param(chg, &chg->param.fcc, 0); + /* configure charge enable for software control; active high */ + rc = smblib_masked_write(chg, CHGR_CFG2_REG, + CHG_EN_POLARITY_BIT | CHG_EN_SRC_BIT, 0); if (rc < 0) { - pr_err("Couldn't set 0 FCC rc=%d\n", rc); + pr_err("Couldn't configure charge enable source rc=%d\n", + rc); return rc; } @@ -1154,6 +1050,7 @@ static int smb138x_init_hw(struct smb138x *chip) static int smb138x_setup_wa_flags(struct smb138x *chip) { + struct pmic_revid_data *pmic_rev_id; struct device_node *revid_dev_node; revid_dev_node = of_parse_phandle(chip->chg.dev->of_node, @@ -1163,8 +1060,8 @@ static int smb138x_setup_wa_flags(struct smb138x *chip) return -EINVAL; } - chip->pmic_rev_id = get_revid_data(revid_dev_node); - if (IS_ERR_OR_NULL(chip->pmic_rev_id)) { + pmic_rev_id = get_revid_data(revid_dev_node); + if (IS_ERR_OR_NULL(pmic_rev_id)) { /* * the revid peripheral must be registered, any failure * here only indicates that the rev-id module has not @@ -1173,14 +1070,14 @@ static int smb138x_setup_wa_flags(struct smb138x *chip) return -EPROBE_DEFER; } - switch (chip->pmic_rev_id->pmic_subtype) { + switch (pmic_rev_id->pmic_subtype) { case SMB1381_SUBTYPE: - if (chip->pmic_rev_id->rev4 < 2) /* SMB1381 rev 1.0 */ + if (pmic_rev_id->rev4 < 2) /* SMB1381 rev 1.0 */ chip->wa_flags |= OOB_COMP_WA_BIT; break; default: pr_err("PMIC subtype %d not supported\n", - chip->pmic_rev_id->pmic_subtype); + pmic_rev_id->pmic_subtype); return -EINVAL; } @@ -1478,7 +1375,6 @@ static int smb138x_master_probe(struct smb138x *chip) chg->param = v1_params; - chip->name = "smb1381"; rc = smblib_init(chg); if (rc < 0) { pr_err("Couldn't initialize smblib rc=%d\n", rc); @@ -1539,7 +1435,7 @@ static int smb138x_master_probe(struct smb138x *chip) return rc; } -static int smb1355_slave_probe(struct smb138x *chip) +static int smb138x_slave_probe(struct smb138x *chip) { struct smb_charger *chg = &chip->chg; int rc = 0; @@ -1552,55 +1448,6 @@ static int smb1355_slave_probe(struct smb138x *chip) goto cleanup; } - rc = smb138x_parse_dt(chip); - if (rc < 0) { - pr_err("Couldn't parse device tree rc=%d\n", rc); - goto cleanup; - } - - rc = smb138x_init_slave_hw(chip); - if (rc < 0) { - pr_err("Couldn't initialize hardware rc=%d\n", rc); - goto cleanup; - } - - rc = smb1355_init_parallel_psy(chip); - if (rc < 0) { - pr_err("Couldn't initialize parallel psy rc=%d\n", rc); - goto cleanup; - } - - rc = smb138x_determine_initial_slave_status(chip); - if (rc < 0) { - pr_err("Couldn't determine initial status rc=%d\n", rc); - goto cleanup; - } - - rc = smb138x_request_interrupts(chip); - if (rc < 0) { - pr_err("Couldn't request interrupts rc=%d\n", rc); - goto cleanup; - } - - return 0; - -cleanup: - smblib_deinit(chg); - return rc; -} - -static int smb1381_slave_probe(struct smb138x *chip) -{ - struct smb_charger *chg = &chip->chg; - int rc = 0; - - chg->param = v1_params; - - rc = smblib_init(chg); - if (rc < 0) { - pr_err("Couldn't initialize smblib rc=%d\n", rc); - goto cleanup; - } chg->iio.temp_max_chan = iio_channel_get(chg->dev, "charger_temp_max"); if (IS_ERR(chg->iio.temp_max_chan)) { rc = PTR_ERR(chg->iio.temp_max_chan); @@ -1668,71 +1515,25 @@ static int smb1381_slave_probe(struct smb138x *chip) goto cleanup; } - return 0; + return rc; cleanup: smblib_deinit(chg); + if (chip->parallel_psy) + power_supply_unregister(chip->parallel_psy); + if (chg->vbus_vreg && chg->vbus_vreg->rdev) + regulator_unregister(chg->vbus_vreg->rdev); return rc; } -static int slave_probe(struct smb138x *chip) -{ - struct device_node *revid_dev_node; - int rc = 0; - - revid_dev_node = of_parse_phandle(chip->chg.dev->of_node, - "qcom,pmic-revid", 0); - if (!revid_dev_node) { - pr_err("Missing qcom,pmic-revid property\n"); - return -EINVAL; - } - - chip->pmic_rev_id = get_revid_data(revid_dev_node); - if (IS_ERR_OR_NULL(chip->pmic_rev_id)) { - /* - * the revid peripheral must be registered, any failure - * here only indicates that the rev-id module has not - * probed yet. - */ - return -EPROBE_DEFER; - } - - switch (chip->pmic_rev_id->pmic_subtype) { - case SMB1355_SUBTYPE: - chip->name = "smb1355"; - rc = smb1355_slave_probe(chip); - break; - case SMB1381_SUBTYPE: - chip->name = "smb1381"; - rc = smb1381_slave_probe(chip); - break; - default: - pr_err("Unsupported pmic subtype = 0x%02x\n", - chip->pmic_rev_id->pmic_subtype); - rc = -EINVAL; - } - - if (rc < 0) { - if (rc != -EPROBE_DEFER) - pr_err("Couldn't probe SMB138X rc=%d\n", rc); - return rc; - } - - return 0; -} - static const struct of_device_id match_table[] = { { - .compatible = "qcom,smb138x-charger", - .data = (void *) PARALLEL_MASTER, - }, - { - .compatible = "qcom,smb138x-parallel-slave", - .data = (void *) PARALLEL_SLAVE, + .compatible = "qcom,smb138x-charger", + .data = (void *) PARALLEL_MASTER }, { - .compatible = "qcom,smb1355-parallel-slave", - .data = (void *) PARALLEL_SLAVE, + .compatible = "qcom,smb138x-parallel-slave", + .data = (void *) PARALLEL_SLAVE }, { }, }; @@ -1779,7 +1580,7 @@ static int smb138x_probe(struct platform_device *pdev) rc = smb138x_master_probe(chip); break; case PARALLEL_SLAVE: - rc = slave_probe(chip); + rc = smb138x_slave_probe(chip); break; default: pr_err("Couldn't find a matching mode %d\n", chip->chg.mode); @@ -1793,8 +1594,7 @@ static int smb138x_probe(struct platform_device *pdev) goto cleanup; } - pr_info("%s probed successfully mode=%d pl_mode = %d\n", - chip->name, chip->chg.mode, chip->dt.pl_mode); + pr_info("SMB138X probed successfully mode=%d\n", chip->chg.mode); return rc; cleanup: diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index e5ba63171eba..88956d3ba674 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -472,6 +472,15 @@ config REGULATOR_MT6397 This driver supports the control of different power rails of device through regulator interface. +config REGULATOR_ONSEMI_NCP6335D + tristate "OnSemi NCP6335D regulator support" + depends on I2C + help + This driver supports the OnSemi NCP6335D switching voltage regulator + (buck converter). The regulator is controlled using an I2C interface + and supports a programmable voltage range from 0.6V to 1.4V in steps + of 6.25mV. + config REGULATOR_PALMAS tristate "TI Palmas PMIC Regulators" depends on MFD_PALMAS diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 20cf304a4714..e345f10f94af 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -65,6 +65,7 @@ obj-$(CONFIG_REGULATOR_MT6397) += mt6397-regulator.o obj-$(CONFIG_REGULATOR_QCOM_RPM) += qcom_rpm-regulator.o obj-$(CONFIG_REGULATOR_QCOM_SMD_RPM) += qcom_smd-regulator.o obj-$(CONFIG_REGULATOR_QCOM_SPMI) += qcom_spmi-regulator.o +obj-$(CONFIG_REGULATOR_ONSEMI_NCP6335D) += onsemi-ncp6335d.o obj-$(CONFIG_REGULATOR_PALMAS) += palmas-regulator.o obj-$(CONFIG_REGULATOR_PFUZE100) += pfuze100-regulator.o obj-$(CONFIG_REGULATOR_PWM) += pwm-regulator.o diff --git a/drivers/regulator/onsemi-ncp6335d.c b/drivers/regulator/onsemi-ncp6335d.c new file mode 100644 index 000000000000..3b4ca4f81527 --- /dev/null +++ b/drivers/regulator/onsemi-ncp6335d.c @@ -0,0 +1,775 @@ +/* Copyright (c) 2012-2014, 2017 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/module.h> +#include <linux/err.h> +#include <linux/gpio.h> +#include <linux/kernel.h> +#include <linux/delay.h> +#include <linux/i2c.h> +#include <linux/log2.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/of_regulator.h> +#include <linux/of.h> +#include <linux/of_gpio.h> +#include <linux/regmap.h> +#include <linux/debugfs.h> +#include <linux/regulator/onsemi-ncp6335d.h> +#include <linux/string.h> + +/* registers */ +#define REG_NCP6335D_PID 0x03 +#define REG_NCP6335D_PROGVSEL1 0x10 +#define REG_NCP6335D_PROGVSEL0 0x11 +#define REG_NCP6335D_PGOOD 0x12 +#define REG_NCP6335D_TIMING 0x13 +#define REG_NCP6335D_COMMAND 0x14 + +/* constraints */ +#define NCP6335D_MIN_VOLTAGE_UV 600000 +#define NCP6335D_STEP_VOLTAGE_UV 6250 +#define NCP6335D_VOLTAGE_STEPS 128 +#define NCP6335D_MIN_SLEW_NS 166 +#define NCP6335D_MAX_SLEW_NS 1333 + +/* bits */ +#define NCP6335D_ENABLE BIT(7) +#define NCP6335D_DVS_PWM_MODE BIT(5) +#define NCP6335D_PWM_MODE1 BIT(6) +#define NCP6335D_PWM_MODE0 BIT(7) +#define NCP6335D_PGOOD_DISCHG BIT(4) +#define NCP6335D_SLEEP_MODE BIT(4) + +#define NCP6335D_VOUT_SEL_MASK 0x7F +#define NCP6335D_SLEW_MASK 0x18 +#define NCP6335D_SLEW_SHIFT 0x3 + +struct ncp6335d_info { + struct regulator_dev *regulator; + struct regulator_init_data *init_data; + struct regmap *regmap; + struct device *dev; + unsigned int vsel_reg; + unsigned int vsel_backup_reg; + unsigned int mode_bit; + int curr_voltage; + int slew_rate; + + unsigned int step_size; + unsigned int min_voltage; + unsigned int min_slew_ns; + unsigned int max_slew_ns; + unsigned int peek_poke_address; + + struct dentry *debug_root; +}; + +static int delay_array[] = {10, 20, 30, 40, 50}; + +static int ncp6335x_read(struct ncp6335d_info *dd, unsigned int reg, + unsigned int *val) +{ + int i = 0, rc = 0; + + rc = regmap_read(dd->regmap, reg, val); + for (i = 0; rc && i < ARRAY_SIZE(delay_array); i++) { + pr_debug("Failed reading reg=%u - retry(%d)\n", reg, i); + msleep(delay_array[i]); + rc = regmap_read(dd->regmap, reg, val); + } + + if (rc) + pr_err("Failed reading reg=%u rc=%d\n", reg, rc); + + return rc; +} + +static int ncp6335x_write(struct ncp6335d_info *dd, unsigned int reg, + unsigned int val) +{ + int i = 0, rc = 0; + + rc = regmap_write(dd->regmap, reg, val); + for (i = 0; rc && i < ARRAY_SIZE(delay_array); i++) { + pr_debug("Failed writing reg=%u - retry(%d)\n", reg, i); + msleep(delay_array[i]); + rc = regmap_write(dd->regmap, reg, val); + } + + if (rc) + pr_err("Failed writing reg=%u rc=%d\n", reg, rc); + + return rc; +} + +static int ncp6335x_update_bits(struct ncp6335d_info *dd, unsigned int reg, + unsigned int mask, unsigned int val) +{ + int i = 0, rc = 0; + + rc = regmap_update_bits(dd->regmap, reg, mask, val); + for (i = 0; rc && i < ARRAY_SIZE(delay_array); i++) { + pr_debug("Failed updating reg=%u- retry(%d)\n", reg, i); + msleep(delay_array[i]); + rc = regmap_update_bits(dd->regmap, reg, mask, val); + } + + if (rc) + pr_err("Failed updating reg=%u rc=%d\n", reg, rc); + + return rc; +} + +static void dump_registers(struct ncp6335d_info *dd, + unsigned int reg, const char *func) +{ + unsigned int val = 0; + + ncp6335x_read(dd, reg, &val); + dev_dbg(dd->dev, "%s: NCP6335D: Reg = %x, Val = %x\n", func, reg, val); +} + +static void ncp633d_slew_delay(struct ncp6335d_info *dd, + int prev_uV, int new_uV) +{ + u8 val; + int delay; + + val = abs(prev_uV - new_uV) / dd->step_size; + delay = ((val * dd->slew_rate) / 1000) + 1; + + dev_dbg(dd->dev, "Slew Delay = %d\n", delay); + + udelay(delay); +} + +static int ncp6335d_is_enabled(struct regulator_dev *rdev) +{ + int rc, val = 0; + struct ncp6335d_info *dd = rdev_get_drvdata(rdev); + + rc = ncp6335x_read(dd, dd->vsel_reg, &val); + if (rc) + dev_err(dd->dev, "Unable to read enable register rc(%d)", rc); + + dump_registers(dd, dd->vsel_reg, __func__); + + return ((val & NCP6335D_ENABLE) ? 1 : 0); +} + +static int ncp6335d_enable(struct regulator_dev *rdev) +{ + int rc; + struct ncp6335d_info *dd = rdev_get_drvdata(rdev); + + rc = ncp6335x_update_bits(dd, dd->vsel_reg, + NCP6335D_ENABLE, NCP6335D_ENABLE); + if (rc) + dev_err(dd->dev, "Unable to enable regualtor rc(%d)", rc); + + dump_registers(dd, dd->vsel_reg, __func__); + + return rc; +} + +static int ncp6335d_disable(struct regulator_dev *rdev) +{ + int rc; + struct ncp6335d_info *dd = rdev_get_drvdata(rdev); + + rc = ncp6335x_update_bits(dd, dd->vsel_reg, + NCP6335D_ENABLE, 0); + if (rc) + dev_err(dd->dev, "Unable to disable regualtor rc(%d)", rc); + + dump_registers(dd, dd->vsel_reg, __func__); + + return rc; +} + +static int ncp6335d_get_voltage(struct regulator_dev *rdev) +{ + unsigned int val; + int rc; + struct ncp6335d_info *dd = rdev_get_drvdata(rdev); + + rc = ncp6335x_read(dd, dd->vsel_reg, &val); + if (rc) { + dev_err(dd->dev, "Unable to get volatge rc(%d)", rc); + return rc; + } + dd->curr_voltage = ((val & NCP6335D_VOUT_SEL_MASK) * dd->step_size) + + dd->min_voltage; + + dump_registers(dd, dd->vsel_reg, __func__); + + return dd->curr_voltage; +} + +static int ncp6335d_set_voltage(struct regulator_dev *rdev, + int min_uV, int max_uV, unsigned *selector) +{ + int rc, set_val, new_uV; + struct ncp6335d_info *dd = rdev_get_drvdata(rdev); + + set_val = DIV_ROUND_UP(min_uV - dd->min_voltage, dd->step_size); + new_uV = (set_val * dd->step_size) + dd->min_voltage; + if (new_uV > max_uV) { + dev_err(dd->dev, "Unable to set volatge (%d %d)\n", + min_uV, max_uV); + return -EINVAL; + } + + rc = ncp6335x_update_bits(dd, dd->vsel_reg, + NCP6335D_VOUT_SEL_MASK, (set_val & NCP6335D_VOUT_SEL_MASK)); + if (rc) { + dev_err(dd->dev, "Unable to set volatge (%d %d)\n", + min_uV, max_uV); + } else { + ncp633d_slew_delay(dd, dd->curr_voltage, new_uV); + dd->curr_voltage = new_uV; + } + + dump_registers(dd, dd->vsel_reg, __func__); + + return rc; +} + +static int ncp6335d_list_voltage(struct regulator_dev *rdev, + unsigned selector) +{ + struct ncp6335d_info *dd = rdev_get_drvdata(rdev); + + if (selector >= NCP6335D_VOLTAGE_STEPS) + return 0; + + return selector * dd->step_size + dd->min_voltage; +} + +static int ncp6335d_set_mode(struct regulator_dev *rdev, + unsigned int mode) +{ + int rc; + struct ncp6335d_info *dd = rdev_get_drvdata(rdev); + + /* only FAST and NORMAL mode types are supported */ + if (mode != REGULATOR_MODE_FAST && mode != REGULATOR_MODE_NORMAL) { + dev_err(dd->dev, "Mode %d not supported\n", mode); + return -EINVAL; + } + + rc = ncp6335x_update_bits(dd, REG_NCP6335D_COMMAND, dd->mode_bit, + (mode == REGULATOR_MODE_FAST) ? dd->mode_bit : 0); + if (rc) { + dev_err(dd->dev, "Unable to set operating mode rc(%d)", rc); + return rc; + } + + rc = ncp6335x_update_bits(dd, REG_NCP6335D_COMMAND, + NCP6335D_DVS_PWM_MODE, + (mode == REGULATOR_MODE_FAST) ? + NCP6335D_DVS_PWM_MODE : 0); + if (rc) + dev_err(dd->dev, "Unable to set DVS trans. mode rc(%d)", rc); + + dump_registers(dd, REG_NCP6335D_COMMAND, __func__); + + return rc; +} + +static unsigned int ncp6335d_get_mode(struct regulator_dev *rdev) +{ + unsigned int val; + int rc; + struct ncp6335d_info *dd = rdev_get_drvdata(rdev); + + rc = ncp6335x_read(dd, REG_NCP6335D_COMMAND, &val); + if (rc) { + dev_err(dd->dev, "Unable to get regulator mode rc(%d)\n", rc); + return rc; + } + + dump_registers(dd, REG_NCP6335D_COMMAND, __func__); + + if (val & dd->mode_bit) + return REGULATOR_MODE_FAST; + + return REGULATOR_MODE_NORMAL; +} + +static struct regulator_ops ncp6335d_ops = { + .set_voltage = ncp6335d_set_voltage, + .get_voltage = ncp6335d_get_voltage, + .list_voltage = ncp6335d_list_voltage, + .is_enabled = ncp6335d_is_enabled, + .enable = ncp6335d_enable, + .disable = ncp6335d_disable, + .set_mode = ncp6335d_set_mode, + .get_mode = ncp6335d_get_mode, +}; + +static struct regulator_desc rdesc = { + .name = "ncp6335d", + .supply_name = "vin", + .owner = THIS_MODULE, + .n_voltages = NCP6335D_VOLTAGE_STEPS, + .ops = &ncp6335d_ops, +}; + +static int ncp6335d_restore_working_reg(struct device_node *node, + struct ncp6335d_info *dd) +{ + int ret; + unsigned int val; + + /* Restore register from back up register */ + ret = ncp6335x_read(dd, dd->vsel_backup_reg, &val); + if (ret < 0) { + dev_err(dd->dev, "Failed to get backup data from reg %d, ret = %d\n", + dd->vsel_backup_reg, ret); + return ret; + } + + ret = ncp6335x_update_bits(dd, dd->vsel_reg, + NCP6335D_VOUT_SEL_MASK, val); + if (ret < 0) { + dev_err(dd->dev, "Failed to update working reg %d, ret = %d\n", + dd->vsel_reg, ret); + return ret; + } + + return ret; +} + +static int ncp6335d_parse_gpio(struct device_node *node, + struct ncp6335d_info *dd) +{ + int ret = 0, gpio; + enum of_gpio_flags flags; + + if (!of_find_property(node, "onnn,vsel-gpio", NULL)) + return ret; + + /* Get GPIO connected to vsel and set its output */ + gpio = of_get_named_gpio_flags(node, + "onnn,vsel-gpio", 0, &flags); + if (!gpio_is_valid(gpio)) { + if (gpio != -EPROBE_DEFER) + dev_err(dd->dev, "Could not get vsel, ret = %d\n", + gpio); + return gpio; + } + + ret = devm_gpio_request(dd->dev, gpio, "ncp6335d_vsel"); + if (ret) { + dev_err(dd->dev, "Failed to obtain gpio %d ret = %d\n", + gpio, ret); + return ret; + } + + ret = gpio_direction_output(gpio, flags & OF_GPIO_ACTIVE_LOW ? 0 : 1); + if (ret) { + dev_err(dd->dev, "Failed to set GPIO %d to: %s, ret = %d", + gpio, flags & OF_GPIO_ACTIVE_LOW ? + "GPIO_LOW" : "GPIO_HIGH", ret); + return ret; + } + + return ret; +} + +static int ncp6335d_init(struct i2c_client *client, struct ncp6335d_info *dd, + const struct ncp6335d_platform_data *pdata) +{ + int rc; + unsigned int val; + + switch (pdata->default_vsel) { + case NCP6335D_VSEL0: + dd->vsel_reg = REG_NCP6335D_PROGVSEL0; + dd->vsel_backup_reg = REG_NCP6335D_PROGVSEL1; + dd->mode_bit = NCP6335D_PWM_MODE0; + break; + case NCP6335D_VSEL1: + dd->vsel_reg = REG_NCP6335D_PROGVSEL1; + dd->vsel_backup_reg = REG_NCP6335D_PROGVSEL0; + dd->mode_bit = NCP6335D_PWM_MODE1; + break; + default: + dev_err(dd->dev, "Invalid VSEL ID %d\n", pdata->default_vsel); + return -EINVAL; + } + + if (of_property_read_bool(client->dev.of_node, "onnn,restore-reg")) { + rc = ncp6335d_restore_working_reg(client->dev.of_node, dd); + if (rc) + return rc; + } + + rc = ncp6335d_parse_gpio(client->dev.of_node, dd); + if (rc) + return rc; + + /* get the current programmed voltage */ + rc = ncp6335x_read(dd, dd->vsel_reg, &val); + if (rc) { + dev_err(dd->dev, "Unable to get volatge rc(%d)", rc); + return rc; + } + dd->curr_voltage = ((val & NCP6335D_VOUT_SEL_MASK) * + dd->step_size) + dd->min_voltage; + + /* set discharge */ + rc = ncp6335x_update_bits(dd, REG_NCP6335D_PGOOD, + NCP6335D_PGOOD_DISCHG, + (pdata->discharge_enable ? + NCP6335D_PGOOD_DISCHG : 0)); + if (rc) { + dev_err(dd->dev, "Unable to set Active Discharge rc(%d)\n", rc); + return -EINVAL; + } + + /* set slew rate */ + if (pdata->slew_rate_ns < dd->min_slew_ns || + pdata->slew_rate_ns > dd->max_slew_ns) { + dev_err(dd->dev, "Invalid slew rate %d\n", pdata->slew_rate_ns); + return -EINVAL; + } + + dd->slew_rate = pdata->slew_rate_ns; + val = DIV_ROUND_UP(pdata->slew_rate_ns, dd->min_slew_ns); + val = ilog2(val); + + rc = ncp6335x_update_bits(dd, REG_NCP6335D_TIMING, + NCP6335D_SLEW_MASK, val << NCP6335D_SLEW_SHIFT); + if (rc) + dev_err(dd->dev, "Unable to set slew rate rc(%d)\n", rc); + + /* Set Sleep mode bit */ + rc = ncp6335x_update_bits(dd, REG_NCP6335D_COMMAND, + NCP6335D_SLEEP_MODE, pdata->sleep_enable ? + NCP6335D_SLEEP_MODE : 0); + if (rc) + dev_err(dd->dev, "Unable to set sleep mode (%d)\n", rc); + + dump_registers(dd, REG_NCP6335D_COMMAND, __func__); + dump_registers(dd, REG_NCP6335D_PROGVSEL0, __func__); + dump_registers(dd, REG_NCP6335D_TIMING, __func__); + dump_registers(dd, REG_NCP6335D_PGOOD, __func__); + + return rc; +} + +static struct regmap_config ncp6335d_regmap_config = { + .reg_bits = 8, + .val_bits = 8, +}; + +static int ncp6335d_parse_dt(struct i2c_client *client, + struct ncp6335d_info *dd) +{ + int rc; + + rc = of_property_read_u32(client->dev.of_node, + "onnn,step-size", &dd->step_size); + if (rc < 0) { + dev_err(&client->dev, "step size missing: rc = %d.\n", rc); + return rc; + } + + rc = of_property_read_u32(client->dev.of_node, + "onnn,min-slew-ns", &dd->min_slew_ns); + if (rc < 0) { + dev_err(&client->dev, "min slew us missing: rc = %d.\n", rc); + return rc; + } + + rc = of_property_read_u32(client->dev.of_node, + "onnn,max-slew-ns", &dd->max_slew_ns); + if (rc < 0) { + dev_err(&client->dev, "max slew us missing: rc = %d.\n", rc); + return rc; + } + + rc = of_property_read_u32(client->dev.of_node, + "onnn,min-setpoint", &dd->min_voltage); + if (rc < 0) { + dev_err(&client->dev, "min set point missing: rc = %d.\n", rc); + return rc; + } + + return rc; +} + +static struct ncp6335d_platform_data * + ncp6335d_get_of_platform_data(struct i2c_client *client) +{ + struct ncp6335d_platform_data *pdata = NULL; + struct regulator_init_data *init_data; + const char *mode_name; + int rc; + + init_data = of_get_regulator_init_data(&client->dev, + client->dev.of_node, &rdesc); + if (!init_data) { + dev_err(&client->dev, "regulator init data is missing\n"); + return pdata; + } + + pdata = devm_kzalloc(&client->dev, + sizeof(struct ncp6335d_platform_data), GFP_KERNEL); + if (!pdata) + return pdata; + + rc = of_property_read_u32(client->dev.of_node, + "onnn,vsel", &pdata->default_vsel); + if (rc < 0) { + dev_err(&client->dev, "onnn,vsel property missing: rc = %d.\n", + rc); + return NULL; + } + + rc = of_property_read_u32(client->dev.of_node, + "onnn,slew-ns", &pdata->slew_rate_ns); + if (rc < 0) { + dev_err(&client->dev, "onnn,slew-ns property missing: rc = %d.\n", + rc); + return NULL; + } + + pdata->discharge_enable = of_property_read_bool(client->dev.of_node, + "onnn,discharge-enable"); + + pdata->sleep_enable = of_property_read_bool(client->dev.of_node, + "onnn,sleep-enable"); + + pdata->init_data = init_data; + + init_data->constraints.input_uV = init_data->constraints.max_uV; + init_data->constraints.valid_ops_mask = + REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS | + REGULATOR_CHANGE_MODE; + init_data->constraints.valid_modes_mask = + REGULATOR_MODE_NORMAL | + REGULATOR_MODE_FAST; + + rc = of_property_read_string(client->dev.of_node, "onnn,mode", + &mode_name); + if (!rc) { + if (strcmp("pwm", mode_name) == 0) { + init_data->constraints.initial_mode = + REGULATOR_MODE_FAST; + } else if (strcmp("auto", mode_name) == 0) { + init_data->constraints.initial_mode = + REGULATOR_MODE_NORMAL; + } else { + dev_err(&client->dev, "onnn,mode, unknown regulator mode: %s\n", + mode_name); + return NULL; + } + } + + return pdata; +} + +static int get_reg(void *data, u64 *val) +{ + struct ncp6335d_info *dd = data; + int rc; + unsigned int temp = 0; + + rc = ncp6335x_read(dd, dd->peek_poke_address, &temp); + if (rc < 0) + dev_err(dd->dev, "Couldn't read reg %x rc = %d\n", + dd->peek_poke_address, rc); + else + *val = temp; + + return rc; +} + +static int set_reg(void *data, u64 val) +{ + struct ncp6335d_info *dd = data; + int rc; + unsigned int temp = 0; + + temp = (unsigned int) val; + rc = ncp6335x_write(dd, dd->peek_poke_address, temp); + if (rc < 0) + dev_err(dd->dev, "Couldn't write 0x%02x to 0x%02x rc= %d\n", + dd->peek_poke_address, temp, rc); + + return rc; +} +DEFINE_SIMPLE_ATTRIBUTE(poke_poke_debug_ops, get_reg, set_reg, "0x%02llx\n"); + +static int ncp6335d_regulator_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int rc; + unsigned int val = 0; + struct ncp6335d_info *dd; + const struct ncp6335d_platform_data *pdata; + struct regulator_config config = { }; + + if (client->dev.of_node) + pdata = ncp6335d_get_of_platform_data(client); + else + pdata = client->dev.platform_data; + + if (!pdata) { + dev_err(&client->dev, "Platform data not specified\n"); + return -EINVAL; + } + + dd = devm_kzalloc(&client->dev, sizeof(*dd), GFP_KERNEL); + if (!dd) + return -ENOMEM; + + if (client->dev.of_node) { + rc = ncp6335d_parse_dt(client, dd); + if (rc) + return rc; + } else { + dd->step_size = NCP6335D_STEP_VOLTAGE_UV; + dd->min_voltage = NCP6335D_MIN_VOLTAGE_UV; + dd->min_slew_ns = NCP6335D_MIN_SLEW_NS; + dd->max_slew_ns = NCP6335D_MAX_SLEW_NS; + } + + dd->regmap = devm_regmap_init_i2c(client, &ncp6335d_regmap_config); + if (IS_ERR(dd->regmap)) { + dev_err(&client->dev, "Error allocating regmap\n"); + return PTR_ERR(dd->regmap); + } + + rc = ncp6335x_read(dd, REG_NCP6335D_PID, &val); + if (rc) { + dev_err(&client->dev, "Unable to identify NCP6335D, rc(%d)\n", + rc); + return rc; + } + dev_info(&client->dev, "Detected Regulator NCP6335D PID = %d\n", val); + + dd->init_data = pdata->init_data; + dd->dev = &client->dev; + i2c_set_clientdata(client, dd); + + rc = ncp6335d_init(client, dd, pdata); + if (rc) { + dev_err(&client->dev, "Unable to initialize the regulator\n"); + return -EINVAL; + } + + config.dev = &client->dev; + config.init_data = dd->init_data; + config.regmap = dd->regmap; + config.driver_data = dd; + config.of_node = client->dev.of_node; + + dd->regulator = regulator_register(&rdesc, &config); + + if (IS_ERR(dd->regulator)) { + dev_err(&client->dev, "Unable to register regulator rc(%ld)", + PTR_ERR(dd->regulator)); + + return PTR_ERR(dd->regulator); + } + + dd->debug_root = debugfs_create_dir("ncp6335x", NULL); + if (!dd->debug_root) + dev_err(&client->dev, "Couldn't create debug dir\n"); + + if (dd->debug_root) { + struct dentry *ent; + + ent = debugfs_create_x32("address", S_IFREG | S_IWUSR | S_IRUGO, + dd->debug_root, + &(dd->peek_poke_address)); + if (!ent) + dev_err(&client->dev, "Couldn't create address debug file rc = %d\n", + rc); + + ent = debugfs_create_file("data", S_IFREG | S_IWUSR | S_IRUGO, + dd->debug_root, dd, + &poke_poke_debug_ops); + if (!ent) + dev_err(&client->dev, "Couldn't create data debug file rc = %d\n", + rc); + } + + return 0; +} + +static int ncp6335d_regulator_remove(struct i2c_client *client) +{ + struct ncp6335d_info *dd = i2c_get_clientdata(client); + + regulator_unregister(dd->regulator); + + debugfs_remove_recursive(dd->debug_root); + + return 0; +} + +static const struct of_device_id ncp6335d_match_table[] = { + { .compatible = "onnn,ncp6335d-regulator", }, + {}, +}; +MODULE_DEVICE_TABLE(of, ncp6335d_match_table); + +static const struct i2c_device_id ncp6335d_id[] = { + {"ncp6335d", -1}, + { }, +}; + +static struct i2c_driver ncp6335d_regulator_driver = { + .driver = { + .name = "ncp6335d-regulator", + .owner = THIS_MODULE, + .of_match_table = ncp6335d_match_table, + }, + .probe = ncp6335d_regulator_probe, + .remove = ncp6335d_regulator_remove, + .id_table = ncp6335d_id, +}; + +/** + * ncp6335d_regulator_init() - initialized ncp6335d regulator driver + * This function registers the ncp6335d regulator platform driver. + * + * Returns 0 on success or errno on failure. + */ +int __init ncp6335d_regulator_init(void) +{ + static bool initialized; + + if (initialized) + return 0; + + initialized = true; + + return i2c_add_driver(&ncp6335d_regulator_driver); +} +EXPORT_SYMBOL(ncp6335d_regulator_init); +subsys_initcall(ncp6335d_regulator_init); + +static void __exit ncp6335d_regulator_exit(void) +{ + i2c_del_driver(&ncp6335d_regulator_driver); +} +module_exit(ncp6335d_regulator_exit); +MODULE_DESCRIPTION("OnSemi-NCP6335D regulator driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/scsi/ufs/Kconfig b/drivers/scsi/ufs/Kconfig index b3ed361eff26..fb2f2159c0e1 100644 --- a/drivers/scsi/ufs/Kconfig +++ b/drivers/scsi/ufs/Kconfig @@ -106,3 +106,15 @@ config SCSI_UFS_TEST The UFS unit-tests register as a block device test utility to the test-iosched and will be initiated when the test-iosched will be chosen to be the active I/O scheduler. + +config SCSI_UFSHCD_CMD_LOGGING + bool "Universal Flash Storage host controller driver layer command logging support" + depends on SCSI_UFSHCD + help + This selects the UFS host controller driver layer command logging. + UFS host controller driver layer command logging records all the + command information sent from UFS host controller for debugging + purpose. + + Select this if you want above mentioned debug information captured. + If unsure, say N. diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index c5393d517432..9e64e0c34f57 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -516,14 +516,145 @@ static inline void ufshcd_remove_non_printable(char *val) *val = ' '; } +#define UFSHCD_MAX_CMD_LOGGING 100 + #ifdef CONFIG_TRACEPOINTS -static void ufshcd_add_command_trace(struct ufs_hba *hba, - unsigned int tag, const char *str) +static inline void ufshcd_add_command_trace(struct ufs_hba *hba, + struct ufshcd_cmd_log_entry *entry, u8 opcode) +{ + if (trace_ufshcd_command_enabled()) { + u32 intr = ufshcd_readl(hba, REG_INTERRUPT_STATUS); + + trace_ufshcd_command(dev_name(hba->dev), entry->str, entry->tag, + entry->doorbell, entry->transfer_len, intr, + entry->lba, opcode); + } +} +#else +static inline void ufshcd_add_command_trace(struct ufs_hba *hba, + struct ufshcd_cmd_log_entry *entry, u8 opcode) +{ +} +#endif + +#ifdef CONFIG_SCSI_UFSHCD_CMD_LOGGING +static void ufshcd_cmd_log_init(struct ufs_hba *hba) +{ + /* Allocate log entries */ + if (!hba->cmd_log.entries) { + hba->cmd_log.entries = kzalloc(UFSHCD_MAX_CMD_LOGGING * + sizeof(struct ufshcd_cmd_log_entry), GFP_KERNEL); + if (!hba->cmd_log.entries) + return; + dev_dbg(hba->dev, "%s: cmd_log.entries initialized\n", + __func__); + } +} + +static void __ufshcd_cmd_log(struct ufs_hba *hba, char *str, char *cmd_type, + unsigned int tag, u8 cmd_id, u8 idn, u8 lun, + sector_t lba, int transfer_len, u8 opcode) +{ + struct ufshcd_cmd_log_entry *entry; + + if (!hba->cmd_log.entries) + return; + + entry = &hba->cmd_log.entries[hba->cmd_log.pos]; + entry->lun = lun; + entry->str = str; + entry->cmd_type = cmd_type; + entry->cmd_id = cmd_id; + entry->lba = lba; + entry->transfer_len = transfer_len; + entry->idn = idn; + entry->doorbell = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL); + entry->tag = tag; + entry->tstamp = ktime_get(); + entry->outstanding_reqs = hba->outstanding_reqs; + entry->seq_num = hba->cmd_log.seq_num; + hba->cmd_log.seq_num++; + hba->cmd_log.pos = + (hba->cmd_log.pos + 1) % UFSHCD_MAX_CMD_LOGGING; + + ufshcd_add_command_trace(hba, entry, opcode); +} + +static void ufshcd_cmd_log(struct ufs_hba *hba, char *str, char *cmd_type, + unsigned int tag, u8 cmd_id, u8 idn) +{ + __ufshcd_cmd_log(hba, str, cmd_type, tag, cmd_id, idn, + 0xff, (sector_t)-1, -1, -1); +} + +static void ufshcd_dme_cmd_log(struct ufs_hba *hba, char *str, u8 cmd_id) +{ + ufshcd_cmd_log(hba, str, "dme", 0xff, cmd_id, 0xff); +} + +static void ufshcd_cmd_log_print(struct ufs_hba *hba) +{ + int i; + int pos; + struct ufshcd_cmd_log_entry *p; + + if (!hba->cmd_log.entries) + return; + + pos = hba->cmd_log.pos; + for (i = 0; i < UFSHCD_MAX_CMD_LOGGING; i++) { + p = &hba->cmd_log.entries[pos]; + pos = (pos + 1) % UFSHCD_MAX_CMD_LOGGING; + + if (ktime_to_us(p->tstamp)) { + pr_err("%s: %s: seq_no=%u lun=0x%x cmd_id=0x%02x lba=0x%llx txfer_len=%d tag=%u, doorbell=0x%x outstanding=0x%x idn=%d time=%lld us\n", + p->cmd_type, p->str, p->seq_num, + p->lun, p->cmd_id, (unsigned long long)p->lba, + p->transfer_len, p->tag, p->doorbell, + p->outstanding_reqs, p->idn, + ktime_to_us(p->tstamp)); + usleep_range(1000, 1100); + } + } +} +#else +static void ufshcd_cmd_log_init(struct ufs_hba *hba) +{ +} + +static void __ufshcd_cmd_log(struct ufs_hba *hba, char *str, char *cmd_type, + unsigned int tag, u8 cmd_id, u8 idn, u8 lun, + sector_t lba, int transfer_len, u8 opcode) +{ + struct ufshcd_cmd_log_entry entry; + + entry.str = str; + entry.lba = lba; + entry.transfer_len = transfer_len; + entry.doorbell = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL); + entry.tag = tag; + + ufshcd_add_command_trace(hba, &entry, opcode); +} + +static void ufshcd_dme_cmd_log(struct ufs_hba *hba, char *str, u8 cmd_id) +{ +} + +static void ufshcd_cmd_log_print(struct ufs_hba *hba) +{ +} +#endif + +#ifdef CONFIG_TRACEPOINTS +static inline void ufshcd_cond_add_cmd_trace(struct ufs_hba *hba, + unsigned int tag, const char *str) { - sector_t lba = -1; - u8 opcode = 0; - u32 intr, doorbell; struct ufshcd_lrb *lrbp; + char *cmd_type; + u8 opcode = 0; + u8 cmd_id, idn = 0; + sector_t lba = -1; int transfer_len = -1; lrbp = &hba->lrb[tag]; @@ -537,23 +668,28 @@ static void ufshcd_add_command_trace(struct ufs_hba *hba, */ if (lrbp->cmd->request && lrbp->cmd->request->bio) lba = - lrbp->cmd->request->bio->bi_iter.bi_sector; + lrbp->cmd->request->bio->bi_iter.bi_sector; transfer_len = be32_to_cpu( lrbp->ucd_req_ptr->sc.exp_data_transfer_len); } } - intr = ufshcd_readl(hba, REG_INTERRUPT_STATUS); - doorbell = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL); - trace_ufshcd_command(dev_name(hba->dev), str, tag, - doorbell, transfer_len, intr, lba, opcode); -} + if (lrbp->command_type == UTP_CMD_TYPE_SCSI) { + cmd_type = "scsi"; + cmd_id = (u8)(*lrbp->cmd->cmnd); + } else if (lrbp->command_type == UTP_CMD_TYPE_DEV_MANAGE) { + if (hba->dev_cmd.type == DEV_CMD_TYPE_NOP) { + cmd_type = "nop"; + cmd_id = 0; + } else if (hba->dev_cmd.type == DEV_CMD_TYPE_QUERY) { + cmd_type = "query"; + cmd_id = hba->dev_cmd.query.request.upiu_req.opcode; + idn = hba->dev_cmd.query.request.upiu_req.idn; + } + } -static inline void ufshcd_cond_add_cmd_trace(struct ufs_hba *hba, - unsigned int tag, const char *str) -{ - if (trace_ufshcd_command_enabled()) - ufshcd_add_command_trace(hba, tag, str); + __ufshcd_cmd_log(hba, (char *) str, cmd_type, tag, cmd_id, idn, + lrbp->lun, lba, transfer_len, opcode); } #else static inline void ufshcd_cond_add_cmd_trace(struct ufs_hba *hba, @@ -1370,6 +1506,7 @@ start: } spin_unlock_irqrestore(hba->host->host_lock, flags); out: + hba->ufs_stats.clk_hold.ts = ktime_get(); return rc; } EXPORT_SYMBOL_GPL(ufshcd_hold); @@ -1474,6 +1611,7 @@ static void __ufshcd_release(struct ufs_hba *hba, bool no_sched) hba->clk_gating.state = REQ_CLKS_OFF; trace_ufshcd_clk_gating(dev_name(hba->dev), hba->clk_gating.state); + hba->ufs_stats.clk_rel.ts = ktime_get(); hrtimer_start(&hba->clk_gating.gate_hrtimer, ms_to_ktime(hba->clk_gating.delay_ms), @@ -1920,8 +2058,10 @@ static void ufshcd_hibern8_exit_work(struct work_struct *work) /* Exit from hibern8 */ if (ufshcd_is_link_hibern8(hba)) { + hba->ufs_stats.clk_hold.ctx = H8_EXIT_WORK; ufshcd_hold(hba, false); ret = ufshcd_uic_hibern8_exit(hba); + hba->ufs_stats.clk_rel.ctx = H8_EXIT_WORK; ufshcd_release(hba, false); if (!ret) { spin_lock_irqsave(hba->host->host_lock, flags); @@ -2263,6 +2403,7 @@ ufshcd_dispatch_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd) hba->active_uic_cmd = uic_cmd; + ufshcd_dme_cmd_log(hba, "send", hba->active_uic_cmd->command); /* Write Args */ ufshcd_writel(hba, uic_cmd->argument1, REG_UIC_COMMAND_ARG_1); ufshcd_writel(hba, uic_cmd->argument2, REG_UIC_COMMAND_ARG_2); @@ -2296,6 +2437,8 @@ ufshcd_wait_for_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd) if (ret) ufsdbg_set_err_state(hba); + ufshcd_dme_cmd_log(hba, "cmp1", hba->active_uic_cmd->command); + spin_lock_irqsave(hba->host->host_lock, flags); hba->active_uic_cmd = NULL; spin_unlock_irqrestore(hba->host->host_lock, flags); @@ -2344,6 +2487,7 @@ ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd) int ret; unsigned long flags; + hba->ufs_stats.clk_hold.ctx = UIC_CMD_SEND; ufshcd_hold_all(hba); mutex_lock(&hba->uic_cmd_mutex); ufshcd_add_delay_before_dme_cmd(hba); @@ -2357,6 +2501,7 @@ ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd) ufshcd_save_tstamp_of_last_dme_cmd(hba); mutex_unlock(&hba->uic_cmd_mutex); ufshcd_release_all(hba); + hba->ufs_stats.clk_rel.ctx = UIC_CMD_SEND; ufsdbg_error_inject_dispatcher(hba, ERR_INJECT_UIC, 0, &ret); @@ -2834,6 +2979,7 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) goto out; } + hba->ufs_stats.clk_hold.ctx = QUEUE_CMD; err = ufshcd_hold(hba, true); if (err) { err = SCSI_MLQUEUE_HOST_BUSY; @@ -2847,6 +2993,7 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) if (err) { clear_bit_unlock(tag, &hba->lrb_in_use); err = SCSI_MLQUEUE_HOST_BUSY; + hba->ufs_stats.clk_rel.ctx = QUEUE_CMD; ufshcd_release(hba, true); goto out; } @@ -4113,6 +4260,8 @@ static int ufshcd_uic_pwr_ctrl(struct ufs_hba *hba, struct uic_command *cmd) cmd->command, status); ret = (status != PWR_OK) ? status : -1; } + ufshcd_dme_cmd_log(hba, "cmp2", hba->active_uic_cmd->command); + out: if (ret) { ufsdbg_set_err_state(hba); @@ -4216,8 +4365,10 @@ static int ufshcd_uic_change_pwr_mode(struct ufs_hba *hba, u8 mode) uic_cmd.command = UIC_CMD_DME_SET; uic_cmd.argument1 = UIC_ARG_MIB(PA_PWRMODE); uic_cmd.argument3 = mode; + hba->ufs_stats.clk_hold.ctx = PWRCTL_CMD_SEND; ufshcd_hold_all(hba); ret = ufshcd_uic_pwr_ctrl(hba, &uic_cmd); + hba->ufs_stats.clk_rel.ctx = PWRCTL_CMD_SEND; ufshcd_release_all(hba); out: return ret; @@ -5385,6 +5536,7 @@ static void __ufshcd_transfer_req_compl(struct ufs_hba *hba, update_req_stats(hba, lrbp); /* Mark completed command as NULL in LRB */ lrbp->cmd = NULL; + hba->ufs_stats.clk_rel.ctx = XFR_REQ_COMPL; __ufshcd_release(hba, false); __ufshcd_hibern8_release(hba, false); if (cmd->request) { @@ -5421,7 +5573,7 @@ static void __ufshcd_transfer_req_compl(struct ufs_hba *hba, } else if (lrbp->command_type == UTP_CMD_TYPE_DEV_MANAGE) { if (hba->dev_cmd.complete) { ufshcd_cond_add_cmd_trace(hba, index, - "dev_complete"); + "dcmp"); complete(hba->dev_cmd.complete); } } @@ -5907,6 +6059,7 @@ static void ufshcd_err_handler(struct work_struct *work) if (unlikely((hba->clk_gating.state != CLKS_ON) && ufshcd_is_auto_hibern8_supported(hba))) { spin_unlock_irqrestore(hba->host->host_lock, flags); + hba->ufs_stats.clk_hold.ctx = ERR_HNDLR_WORK; ufshcd_hold(hba, false); spin_lock_irqsave(hba->host->host_lock, flags); clks_enabled = true; @@ -5943,6 +6096,7 @@ static void ufshcd_err_handler(struct work_struct *work) ufshcd_print_host_state(hba); ufshcd_print_pwr_info(hba); ufshcd_print_tmrs(hba, hba->outstanding_tasks); + ufshcd_cmd_log_print(hba); spin_lock_irqsave(hba->host->host_lock, flags); } } @@ -6049,8 +6203,10 @@ skip_err_handling: hba->silence_err_logs = false; - if (clks_enabled) + if (clks_enabled) { __ufshcd_release(hba, false); + hba->ufs_stats.clk_rel.ctx = ERR_HNDLR_WORK; + } out: ufshcd_clear_eh_in_progress(hba); spin_unlock_irqrestore(hba->host->host_lock, flags); @@ -6286,7 +6442,8 @@ static irqreturn_t ufshcd_intr(int irq, void *__hba) spin_lock(hba->host->host_lock); intr_status = ufshcd_readl(hba, REG_INTERRUPT_STATUS); - + hba->ufs_stats.last_intr_status = intr_status; + hba->ufs_stats.last_intr_ts = ktime_get(); /* * There could be max of hba->nutrs reqs in flight and in worst case * if the reqs get finished 1 by 1 after the interrupt status is @@ -6365,6 +6522,7 @@ static int ufshcd_issue_tm_cmd(struct ufs_hba *hba, int lun_id, int task_id, * the maximum wait time is bounded by %TM_CMD_TIMEOUT. */ wait_event(hba->tm_tag_wq, ufshcd_get_tm_free_slot(hba, &free_slot)); + hba->ufs_stats.clk_hold.ctx = TM_CMD_SEND; ufshcd_hold_all(hba); spin_lock_irqsave(host->host_lock, flags); @@ -6422,6 +6580,7 @@ static int ufshcd_issue_tm_cmd(struct ufs_hba *hba, int lun_id, int task_id, clear_bit(free_slot, &hba->tm_condition); ufshcd_put_tm_slot(hba, free_slot); wake_up(&hba->tm_tag_wq); + hba->ufs_stats.clk_rel.ctx = TM_CMD_SEND; ufshcd_release_all(hba); return err; @@ -6449,6 +6608,7 @@ static int ufshcd_eh_device_reset_handler(struct scsi_cmnd *cmd) hba = shost_priv(host); tag = cmd->request->tag; + ufshcd_cmd_log_print(hba); lrbp = &hba->lrb[tag]; err = ufshcd_issue_tm_cmd(hba, lrbp->lun, 0, UFS_LOGICAL_RESET, &resp); if (err || resp != UPIU_TASK_MANAGEMENT_FUNC_COMPL) { @@ -9315,6 +9475,7 @@ static int ufshcd_devfreq_scale(struct ufs_hba *hba, bool scale_up) int ret = 0; /* let's not get into low power until clock scaling is completed */ + hba->ufs_stats.clk_hold.ctx = CLK_SCALE_WORK; ufshcd_hold_all(hba); ret = ufshcd_clock_scaling_prepare(hba); @@ -9378,6 +9539,7 @@ scale_up_gear: clk_scaling_unprepare: ufshcd_clock_scaling_unprepare(hba); out: + hba->ufs_stats.clk_rel.ctx = CLK_SCALE_WORK; ufshcd_release_all(hba); return ret; } @@ -9809,6 +9971,8 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) */ ufshcd_set_ufs_dev_active(hba); + ufshcd_cmd_log_init(hba); + async_schedule(ufshcd_async_scan, hba); ufsdbg_add_debugfs(hba); diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index c34a998aac17..d66205ff9f5d 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -3,7 +3,7 @@ * * This code is based on drivers/scsi/ufs/ufshcd.h * Copyright (C) 2011-2013 Samsung India Software Operations - * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. * * Authors: * Santosh Yaraganavi <santosh.sy@samsung.com> @@ -519,7 +519,7 @@ struct ufs_init_prefetch { u32 icc_level; }; -#define UIC_ERR_REG_HIST_LENGTH 8 +#define UIC_ERR_REG_HIST_LENGTH 20 /** * struct ufs_uic_err_reg_hist - keeps history of uic errors * @pos: index to indicate cyclic buffer position @@ -588,6 +588,22 @@ struct ufshcd_req_stat { }; #endif +enum ufshcd_ctx { + QUEUE_CMD, + ERR_HNDLR_WORK, + H8_EXIT_WORK, + UIC_CMD_SEND, + PWRCTL_CMD_SEND, + TM_CMD_SEND, + XFR_REQ_COMPL, + CLK_SCALE_WORK, +}; + +struct ufshcd_clk_ctx { + ktime_t ts; + enum ufshcd_ctx ctx; +}; + /** * struct ufs_stats - keeps usage/err statistics * @enabled: enable tag stats for debugfs @@ -616,6 +632,10 @@ struct ufs_stats { int query_stats_arr[UPIU_QUERY_OPCODE_MAX][MAX_QUERY_IDN]; #endif + u32 last_intr_status; + ktime_t last_intr_ts; + struct ufshcd_clk_ctx clk_hold; + struct ufshcd_clk_ctx clk_rel; u32 hibern8_exit_cnt; ktime_t last_hibern8_exit_tstamp; struct ufs_uic_err_reg_hist pa_err; @@ -641,6 +661,27 @@ struct ufs_stats { UFSHCD_DBG_PRINT_TMRS_EN | UFSHCD_DBG_PRINT_PWR_EN | \ UFSHCD_DBG_PRINT_HOST_STATE_EN) +struct ufshcd_cmd_log_entry { + char *str; /* context like "send", "complete" */ + char *cmd_type; /* "scsi", "query", "nop", "dme" */ + u8 lun; + u8 cmd_id; + sector_t lba; + int transfer_len; + u8 idn; /* used only for query idn */ + u32 doorbell; + u32 outstanding_reqs; + u32 seq_num; + unsigned int tag; + ktime_t tstamp; +}; + +struct ufshcd_cmd_log { + struct ufshcd_cmd_log_entry *entries; + int pos; + u32 seq_num; +}; + /** * struct ufs_hba - per adapter private structure * @mmio_base: UFSHCI base register address @@ -856,6 +897,7 @@ struct ufs_hba { struct ufs_clk_gating clk_gating; struct ufs_hibern8_on_idle hibern8_on_idle; + struct ufshcd_cmd_log cmd_log; /* Control to enable/disable host capabilities */ u32 caps; diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c index 69e0ebc78f6f..8c242bc7a702 100644 --- a/drivers/soc/qcom/icnss.c +++ b/drivers/soc/qcom/icnss.c @@ -691,6 +691,8 @@ static int icnss_qmi_pin_connect_result_ind(void *msg, unsigned int msg_len) goto out; } + memset(&ind_msg, 0, sizeof(ind_msg)); + ind_desc.msg_id = QMI_WLFW_PIN_CONNECT_RESULT_IND_V01; ind_desc.max_msg_len = WLFW_PIN_CONNECT_RESULT_IND_MSG_V01_MAX_MSG_LEN; ind_desc.ei_array = wlfw_pin_connect_result_ind_msg_v01_ei; diff --git a/drivers/soc/qcom/icnss_utils.c b/drivers/soc/qcom/icnss_utils.c index 5e187d5df8b3..a7a0ffa2c18e 100644 --- a/drivers/soc/qcom/icnss_utils.c +++ b/drivers/soc/qcom/icnss_utils.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -16,7 +16,7 @@ #define ICNSS_MAX_CH_NUM 45 static DEFINE_MUTEX(unsafe_channel_list_lock); -static DEFINE_MUTEX(dfs_nol_info_lock); +static DEFINE_SPINLOCK(dfs_nol_info_lock); static struct icnss_unsafe_channel_list { u16 unsafe_ch_count; @@ -77,27 +77,24 @@ EXPORT_SYMBOL(icnss_get_wlan_unsafe_channel); int icnss_wlan_set_dfs_nol(const void *info, u16 info_len) { void *temp; + void *old_nol_info; struct icnss_dfs_nol_info *dfs_info; - mutex_lock(&dfs_nol_info_lock); - if (!info || !info_len) { - mutex_unlock(&dfs_nol_info_lock); + if (!info || !info_len) return -EINVAL; - } - temp = kmalloc(info_len, GFP_KERNEL); - if (!temp) { - mutex_unlock(&dfs_nol_info_lock); + temp = kmalloc(info_len, GFP_ATOMIC); + if (!temp) return -ENOMEM; - } memcpy(temp, info, info_len); + spin_lock_bh(&dfs_nol_info_lock); dfs_info = &dfs_nol_info; - kfree(dfs_info->dfs_nol_info); - + old_nol_info = dfs_info->dfs_nol_info; dfs_info->dfs_nol_info = temp; dfs_info->dfs_nol_info_len = info_len; - mutex_unlock(&dfs_nol_info_lock); + spin_unlock_bh(&dfs_nol_info_lock); + kfree(old_nol_info); return 0; } @@ -108,24 +105,21 @@ int icnss_wlan_get_dfs_nol(void *info, u16 info_len) int len; struct icnss_dfs_nol_info *dfs_info; - mutex_lock(&dfs_nol_info_lock); - if (!info || !info_len) { - mutex_unlock(&dfs_nol_info_lock); + if (!info || !info_len) return -EINVAL; - } - dfs_info = &dfs_nol_info; + spin_lock_bh(&dfs_nol_info_lock); + dfs_info = &dfs_nol_info; if (dfs_info->dfs_nol_info == NULL || dfs_info->dfs_nol_info_len == 0) { - mutex_unlock(&dfs_nol_info_lock); + spin_unlock_bh(&dfs_nol_info_lock); return -ENOENT; } len = min(info_len, dfs_info->dfs_nol_info_len); - memcpy(info, dfs_info->dfs_nol_info, len); - mutex_unlock(&dfs_nol_info_lock); + spin_unlock_bh(&dfs_nol_info_lock); return len; } diff --git a/drivers/soc/qcom/memory_dump_v2.c b/drivers/soc/qcom/memory_dump_v2.c index 092b1c1af44b..924c826208dd 100644 --- a/drivers/soc/qcom/memory_dump_v2.c +++ b/drivers/soc/qcom/memory_dump_v2.c @@ -95,7 +95,7 @@ int msm_dump_data_add_minidump(struct msm_dump_entry *entry) data = (struct msm_dump_data *)(phys_to_virt(entry->addr)); if (!strcmp(data->name, "")) { - pr_info("Entry name is NULL, Use ID %d for minidump\n", + pr_debug("Entry name is NULL, Use ID %d for minidump\n", entry->id); snprintf(md_entry.name, sizeof(md_entry.name), "KMDT0x%X", entry->id); @@ -133,7 +133,7 @@ int msm_dump_data_register(enum msm_dump_table_ids id, dmac_flush_range(table, (void *)table + sizeof(struct msm_dump_table)); if (msm_dump_data_add_minidump(entry)) - pr_info("Failed to add entry in Minidump table\n"); + pr_err("Failed to add entry in Minidump table\n"); return 0; } diff --git a/drivers/soc/qcom/memshare/msm_memshare.c b/drivers/soc/qcom/memshare/msm_memshare.c index b8417513ca55..c11114528d2a 100644 --- a/drivers/soc/qcom/memshare/msm_memshare.c +++ b/drivers/soc/qcom/memshare/msm_memshare.c @@ -498,6 +498,7 @@ static int handle_alloc_generic_req(void *req_h, void *req, void *conn_h) struct mem_alloc_generic_resp_msg_v01 *alloc_resp; int rc, resp = 0; int client_id; + uint32_t size = 0; alloc_req = (struct mem_alloc_generic_req_msg_v01 *)req; pr_debug("memshare: alloc request client id: %d proc _id: %d\n", @@ -528,7 +529,11 @@ static int handle_alloc_generic_req(void *req_h, void *req, void *conn_h) __func__, memblock[client_id].client_id, memblock[client_id].free_memory); if (!memblock[client_id].alloted) { - rc = memshare_alloc(memsh_drv->dev, alloc_req->num_bytes, + if (alloc_req->client_id == 1 && alloc_req->num_bytes > 0) + size = alloc_req->num_bytes + MEMSHARE_GUARD_BYTES; + else + size = alloc_req->num_bytes; + rc = memshare_alloc(memsh_drv->dev, size, &memblock[client_id]); if (rc) { pr_err("In %s,Unable to allocate memory for requested client\n", @@ -963,8 +968,10 @@ static int memshare_child_probe(struct platform_device *pdev) * Memshare allocation for guaranteed clients */ if (memblock[num_clients].guarantee) { + if (client_id == 1 && size > 0) + size += MEMSHARE_GUARD_BYTES; rc = memshare_alloc(memsh_child->dev, - memblock[num_clients].size, + size, &memblock[num_clients]); if (rc) { pr_err("In %s, Unable to allocate memory for guaranteed clients, rc: %d\n", diff --git a/drivers/soc/qcom/memshare/msm_memshare.h b/drivers/soc/qcom/memshare/msm_memshare.h index 398907532977..c7123fb1314b 100644 --- a/drivers/soc/qcom/memshare/msm_memshare.h +++ b/drivers/soc/qcom/memshare/msm_memshare.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -24,6 +24,7 @@ #define GPS 0 #define CHECK 0 #define FREE 1 +#define MEMSHARE_GUARD_BYTES (4*1024) struct mem_blocks { /* Client Id information */ diff --git a/drivers/soc/qcom/msm_minidump.c b/drivers/soc/qcom/msm_minidump.c index 1cb36bf98555..300233085161 100644 --- a/drivers/soc/qcom/msm_minidump.c +++ b/drivers/soc/qcom/msm_minidump.c @@ -62,24 +62,31 @@ struct md_table { struct md_region entry[MAX_NUM_ENTRIES]; }; +/* + * md_elfhdr: Minidump table elf header + * @md_ehdr: elf main header + * @shdr: Section header + * @phdr: Program header + * @elf_offset: section offset in elf + * @strtable_idx: string table current index position + */ +struct md_elfhdr { + struct elfhdr *md_ehdr; + struct elf_shdr *shdr; + struct elf_phdr *phdr; + u64 elf_offset; + u64 strtable_idx; +}; + /* Protect elfheader and smem table from deferred calls contention */ static DEFINE_SPINLOCK(mdt_lock); -static bool minidump_enabled; -static struct md_table minidump_table; +static struct md_table minidump_table; +static struct md_elfhdr minidump_elfheader; + +bool minidump_enabled; static unsigned int pendings; static unsigned int region_idx = 1; /* First entry is ELF header*/ -/* ELF Header */ -static struct elfhdr *md_ehdr; -/* ELF Program header */ -static struct elf_phdr *phdr; -/* ELF Section header */ -static struct elf_shdr *shdr; -/* Section offset in elf image */ -static u64 elf_offset; -/* String table index, first byte must be '\0' */ -static unsigned int stringtable_idx = 1; - static inline struct elf_shdr *elf_sheader(struct elfhdr *hdr) { return (struct elf_shdr *)((size_t)hdr + (size_t)hdr->e_shoff); @@ -90,6 +97,16 @@ static inline struct elf_shdr *elf_section(struct elfhdr *hdr, int idx) return &elf_sheader(hdr)[idx]; } +static inline struct elf_phdr *elf_pheader(struct elfhdr *hdr) +{ + return (struct elf_phdr *)((size_t)hdr + (size_t)hdr->e_phoff); +} + +static inline struct elf_phdr *elf_program(struct elfhdr *hdr, int idx) +{ + return &elf_pheader(hdr)[idx]; +} + static inline char *elf_str_table(struct elfhdr *hdr) { if (hdr->e_shstrndx == SHN_UNDEF) @@ -101,23 +118,24 @@ static inline char *elf_lookup_string(struct elfhdr *hdr, int offset) { char *strtab = elf_str_table(hdr); - if ((strtab == NULL) | (stringtable_idx < offset)) + if ((strtab == NULL) || (minidump_elfheader.strtable_idx < offset)) return NULL; return strtab + offset; } static inline unsigned int set_section_name(const char *name) { - char *strtab = elf_str_table(md_ehdr); + char *strtab = elf_str_table(minidump_elfheader.md_ehdr); + int idx = minidump_elfheader.strtable_idx; int ret = 0; - if ((strtab == NULL) | (name == NULL)) + if ((strtab == NULL) || (name == NULL)) return 0; - ret = stringtable_idx; - stringtable_idx += strlcpy((strtab + stringtable_idx), - name, MAX_NAME_LENGTH); - stringtable_idx += 1; + ret = idx; + idx += strlcpy((strtab + idx), name, MAX_NAME_LENGTH); + minidump_elfheader.strtable_idx = idx + 1; + return ret; } @@ -137,11 +155,9 @@ static inline bool md_check_name(const char *name) static int md_update_smem_table(const struct md_region *entry) { struct md_smem_region *mdr; - - if (!minidump_enabled) { - pr_info("Table in smem is not setup\n"); - return -ENODEV; - } + struct elfhdr *hdr = minidump_elfheader.md_ehdr; + struct elf_shdr *shdr = elf_section(hdr, hdr->e_shnum++); + struct elf_phdr *phdr = elf_program(hdr, hdr->e_phnum++); mdr = &minidump_table.region[region_idx++]; @@ -155,36 +171,21 @@ static int md_update_smem_table(const struct md_region *entry) shdr->sh_addr = (elf_addr_t)entry->virt_addr; shdr->sh_size = mdr->size; shdr->sh_flags = SHF_WRITE; - shdr->sh_offset = elf_offset; + shdr->sh_offset = minidump_elfheader.elf_offset; shdr->sh_entsize = 0; phdr->p_type = PT_LOAD; - phdr->p_offset = elf_offset; + phdr->p_offset = minidump_elfheader.elf_offset; phdr->p_vaddr = entry->virt_addr; phdr->p_paddr = entry->phys_addr; phdr->p_filesz = phdr->p_memsz = mdr->size; phdr->p_flags = PF_R | PF_W; - md_ehdr->e_shnum += 1; - md_ehdr->e_phnum += 1; - elf_offset += shdr->sh_size; - shdr++; - phdr++; + minidump_elfheader.elf_offset += shdr->sh_size; return 0; } -bool msm_minidump_enabled(void) -{ - bool ret; - - spin_lock(&mdt_lock); - ret = minidump_enabled; - spin_unlock(&mdt_lock); - return ret; -} -EXPORT_SYMBOL(msm_minidump_enabled); - int msm_minidump_add_region(const struct md_region *entry) { u32 entries; @@ -196,19 +197,19 @@ int msm_minidump_add_region(const struct md_region *entry) if (((strlen(entry->name) > MAX_NAME_LENGTH) || md_check_name(entry->name)) && !entry->virt_addr) { - pr_info("Invalid entry details\n"); + pr_err("Invalid entry details\n"); return -EINVAL; } if (!IS_ALIGNED(entry->size, 4)) { - pr_info("size should be 4 byte aligned\n"); + pr_err("size should be 4 byte aligned\n"); return -EINVAL; } spin_lock(&mdt_lock); entries = minidump_table.num_regions; if (entries >= MAX_NUM_ENTRIES) { - pr_info("Maximum entries reached.\n"); + pr_err("Maximum entries reached.\n"); spin_unlock(&mdt_lock); return -ENOMEM; } @@ -238,23 +239,32 @@ EXPORT_SYMBOL(msm_minidump_add_region); static int msm_minidump_add_header(void) { struct md_smem_region *mdreg = &minidump_table.region[0]; - char *banner; + struct elfhdr *md_ehdr; + struct elf_shdr *shdr; + struct elf_phdr *phdr; unsigned int strtbl_off, elfh_size, phdr_off; + char *banner; + /* Header buffer contains: + * elf header, MAX_NUM_ENTRIES+1 of section and program elf headers, + * string table section and linux banner. + */ elfh_size = sizeof(*md_ehdr) + MAX_STRTBL_SIZE + MAX_MEM_LENGTH + ((sizeof(*shdr) + sizeof(*phdr)) * (MAX_NUM_ENTRIES + 1)); - md_ehdr = kzalloc(elfh_size, GFP_KERNEL); - if (!md_ehdr) + minidump_elfheader.md_ehdr = kzalloc(elfh_size, GFP_KERNEL); + if (!minidump_elfheader.md_ehdr) return -ENOMEM; strlcpy(mdreg->name, "KELF_HEADER", sizeof(mdreg->name)); - mdreg->address = virt_to_phys(md_ehdr); + mdreg->address = virt_to_phys(minidump_elfheader.md_ehdr); mdreg->size = elfh_size; - /* Section headers*/ - shdr = (struct elf_shdr *)(md_ehdr + 1); - phdr = (struct elf_phdr *)(shdr + MAX_NUM_ENTRIES); + md_ehdr = minidump_elfheader.md_ehdr; + /* Assign section/program headers offset */ + minidump_elfheader.shdr = shdr = (struct elf_shdr *)(md_ehdr + 1); + minidump_elfheader.phdr = phdr = + (struct elf_phdr *)(shdr + MAX_NUM_ENTRIES); phdr_off = sizeof(*md_ehdr) + (sizeof(*shdr) * MAX_NUM_ENTRIES); memcpy(md_ehdr->e_ident, ELFMAG, SELFMAG); @@ -268,18 +278,19 @@ static int msm_minidump_add_header(void) md_ehdr->e_ehsize = sizeof(*md_ehdr); md_ehdr->e_phoff = phdr_off; md_ehdr->e_phentsize = sizeof(*phdr); - md_ehdr->e_phnum = 1; md_ehdr->e_shoff = sizeof(*md_ehdr); md_ehdr->e_shentsize = sizeof(*shdr); - md_ehdr->e_shnum = 3; /* NULL, STR TABLE, Linux banner */ md_ehdr->e_shstrndx = 1; - elf_offset = elfh_size; + minidump_elfheader.elf_offset = elfh_size; + + /* + * First section header should be NULL, + * 2nd section is string table. + */ + minidump_elfheader.strtable_idx = 1; strtbl_off = sizeof(*md_ehdr) + ((sizeof(*phdr) + sizeof(*shdr)) * MAX_NUM_ENTRIES); - /* First section header should be NULL - * 2nd entry for string table - */ shdr++; shdr->sh_type = SHT_STRTAB; shdr->sh_offset = (elf_addr_t)strtbl_off; @@ -289,7 +300,15 @@ static int msm_minidump_add_header(void) shdr->sh_name = set_section_name("STR_TBL"); shdr++; - /* 3rd entry for linux banner */ + /* 3rd section is for minidump_table VA, used by parsers */ + shdr->sh_type = SHT_PROGBITS; + shdr->sh_entsize = 0; + shdr->sh_flags = 0; + shdr->sh_addr = (elf_addr_t)&minidump_table; + shdr->sh_name = set_section_name("minidump_table"); + shdr++; + + /* 4th section is linux banner */ banner = (char *)md_ehdr + strtbl_off + MAX_STRTBL_SIZE; strlcpy(banner, linux_banner, MAX_MEM_LENGTH); @@ -300,7 +319,6 @@ static int msm_minidump_add_header(void) shdr->sh_entsize = 0; shdr->sh_flags = SHF_WRITE; shdr->sh_name = set_section_name("linux_banner"); - shdr++; phdr->p_type = PT_LOAD; phdr->p_offset = (elf_addr_t)(strtbl_off + MAX_STRTBL_SIZE); @@ -309,8 +327,9 @@ static int msm_minidump_add_header(void) phdr->p_filesz = phdr->p_memsz = strlen(linux_banner) + 1; phdr->p_flags = PF_R | PF_W; - md_ehdr->e_phnum += 1; - phdr++; + /* Update headers count*/ + md_ehdr->e_phnum = 1; + md_ehdr->e_shnum = 4; return 0; } @@ -325,13 +344,13 @@ static int __init msm_minidump_init(void) smem_table = smem_get_entry(SMEM_MINIDUMP_TABLE_ID, &size, 0, SMEM_ANY_HOST_FLAG); if (IS_ERR_OR_NULL(smem_table)) { - pr_info("SMEM is not initialized.\n"); + pr_err("SMEM is not initialized.\n"); return -ENODEV; } if ((smem_table->next_avail_offset + MAX_MEM_LENGTH) > smem_table->smem_length) { - pr_info("SMEM memory not available.\n"); + pr_err("SMEM memory not available.\n"); return -ENOMEM; } @@ -353,10 +372,10 @@ static int __init msm_minidump_init(void) for (i = 0; i < pendings; i++) { mdr = &minidump_table.entry[i]; if (md_update_smem_table(mdr)) { - pr_info("Unable to add entry %s to smem table\n", + pr_err("Unable to add entry %s to smem table\n", mdr->name); spin_unlock(&mdt_lock); - return -ENODEV; + return -ENOENT; } } diff --git a/drivers/soc/qcom/qbt1000.c b/drivers/soc/qcom/qbt1000.c index 4ba92436bd06..6e7d34ac9163 100644 --- a/drivers/soc/qcom/qbt1000.c +++ b/drivers/soc/qcom/qbt1000.c @@ -377,6 +377,12 @@ static long qbt1000_ioctl(struct file *file, unsigned cmd, unsigned long arg) drvdata = file->private_data; + if (IS_ERR(priv_arg)) { + dev_err(drvdata->dev, "%s: invalid user space pointer %lu\n", + __func__, arg); + return -EINVAL; + } + mutex_lock(&drvdata->mutex); pr_debug("qbt1000_ioctl %d\n", cmd); @@ -401,6 +407,13 @@ static long qbt1000_ioctl(struct file *file, unsigned cmd, unsigned long arg) goto end; } + if (strcmp(app.name, FP_APP_NAME)) { + dev_err(drvdata->dev, "%s: Invalid app name\n", + __func__); + rc = -EINVAL; + goto end; + } + if (drvdata->app_handle) { dev_err(drvdata->dev, "%s: LOAD app already loaded, unloading first\n", __func__); @@ -414,6 +427,7 @@ static long qbt1000_ioctl(struct file *file, unsigned cmd, unsigned long arg) } pr_debug("app %s load before\n", app.name); + app.name[MAX_NAME_SIZE - 1] = '\0'; /* start the TZ app */ rc = qseecom_start_app( @@ -427,7 +441,8 @@ static long qbt1000_ioctl(struct file *file, unsigned cmd, unsigned long arg) pr_err("App %s failed to set bw\n", app.name); } } else { - pr_err("app %s failed to load\n", app.name); + dev_err(drvdata->dev, "%s: Fingerprint Trusted App failed to load\n", + __func__); goto end; } @@ -447,9 +462,7 @@ static long qbt1000_ioctl(struct file *file, unsigned cmd, unsigned long arg) pr_debug("app %s load after\n", app.name); - if (!strcmp(app.name, FP_APP_NAME)) - drvdata->fp_app_handle = drvdata->app_handle; - + drvdata->fp_app_handle = drvdata->app_handle; break; } case QBT1000_UNLOAD_APP: diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c index 58bf3d2f52bd..bfb7dd2d920d 100644 --- a/drivers/staging/android/ion/ion.c +++ b/drivers/staging/android/ion/ion.c @@ -3,7 +3,7 @@ * drivers/staging/android/ion/ion.c * * Copyright (C) 2011 Google, Inc. - * Copyright (c) 2011-2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -122,8 +122,6 @@ struct ion_handle { int id; }; -static struct ion_device *ion_dev; - bool ion_buffer_fault_user_mappings(struct ion_buffer *buffer) { return (buffer->flags & ION_FLAG_CACHED) && @@ -844,32 +842,45 @@ void ion_unmap_kernel(struct ion_client *client, struct ion_handle *handle) } EXPORT_SYMBOL(ion_unmap_kernel); -static int ion_debug_client_show(struct seq_file *s, void *unused) +static struct mutex debugfs_mutex; +static struct rb_root *ion_root_client; +static int is_client_alive(struct ion_client *client) { - struct ion_client *client = s->private; - struct rb_node *n, *cnode; - bool found = false; - - down_write(&ion_dev->lock); + struct rb_node *node; + struct ion_client *tmp; + struct ion_device *dev; - if (!client || (client->dev != ion_dev)) { - up_write(&ion_dev->lock); - return -EINVAL; - } + node = ion_root_client->rb_node; + dev = container_of(ion_root_client, struct ion_device, clients); - cnode = rb_first(&ion_dev->clients); - for ( ; cnode; cnode = rb_next(cnode)) { - struct ion_client *c = rb_entry(cnode, - struct ion_client, node); - if (client == c) { - found = true; - break; + down_read(&dev->lock); + while (node) { + tmp = rb_entry(node, struct ion_client, node); + if (client < tmp) { + node = node->rb_left; + } else if (client > tmp) { + node = node->rb_right; + } else { + up_read(&dev->lock); + return 1; } } - if (!found) { - up_write(&ion_dev->lock); - return -EINVAL; + up_read(&dev->lock); + return 0; +} + +static int ion_debug_client_show(struct seq_file *s, void *unused) +{ + struct ion_client *client = s->private; + struct rb_node *n; + + mutex_lock(&debugfs_mutex); + if (!is_client_alive(client)) { + seq_printf(s, "ion_client 0x%pK dead, can't dump its buffers\n", + client); + mutex_unlock(&debugfs_mutex); + return 0; } seq_printf(s, "%16.16s: %16.16s : %16.16s : %12.12s\n", @@ -890,7 +901,7 @@ static int ion_debug_client_show(struct seq_file *s, void *unused) seq_printf(s, "\n"); } mutex_unlock(&client->lock); - up_write(&ion_dev->lock); + mutex_unlock(&debugfs_mutex); return 0; } @@ -1021,7 +1032,7 @@ void ion_client_destroy(struct ion_client *client) struct rb_node *n; pr_debug("%s: %d\n", __func__, __LINE__); - mutex_lock(&client->lock); + mutex_lock(&debugfs_mutex); while ((n = rb_first(&client->handles))) { struct ion_handle *handle = rb_entry(n, struct ion_handle, node); @@ -1029,7 +1040,6 @@ void ion_client_destroy(struct ion_client *client) } idr_destroy(&client->idr); - mutex_unlock(&client->lock); down_write(&dev->lock); if (client->task) @@ -1042,6 +1052,7 @@ void ion_client_destroy(struct ion_client *client) kfree(client->display_name); kfree(client->name); kfree(client); + mutex_unlock(&debugfs_mutex); } EXPORT_SYMBOL(ion_client_destroy); @@ -1838,7 +1849,7 @@ static int ion_debug_heap_show(struct seq_file *s, void *unused) seq_printf(s, "%16s %16s %16s\n", "client", "pid", "size"); seq_puts(s, "----------------------------------------------------\n"); - down_read(&dev->lock); + mutex_lock(&debugfs_mutex); for (n = rb_first(&dev->clients); n; n = rb_next(n)) { struct ion_client *client = rb_entry(n, struct ion_client, node); @@ -1857,7 +1868,8 @@ static int ion_debug_heap_show(struct seq_file *s, void *unused) client->pid, size); } } - up_read(&dev->lock); + mutex_unlock(&debugfs_mutex); + seq_puts(s, "----------------------------------------------------\n"); seq_puts(s, "orphaned allocations (info is from last known client):\n"); mutex_lock(&dev->buffer_lock); @@ -2095,7 +2107,8 @@ debugfs_done: init_rwsem(&idev->lock); plist_head_init(&idev->heaps); idev->clients = RB_ROOT; - ion_dev = idev; + ion_root_client = &idev->clients; + mutex_init(&debugfs_mutex); return idev; } EXPORT_SYMBOL(ion_device_create); diff --git a/drivers/tty/nozomi.c b/drivers/tty/nozomi.c index 80f9de907563..5cc80b80c82b 100644 --- a/drivers/tty/nozomi.c +++ b/drivers/tty/nozomi.c @@ -823,7 +823,7 @@ static int receive_data(enum port_type index, struct nozomi *dc) struct tty_struct *tty = tty_port_tty_get(&port->port); int i, ret; - read_mem32((u32 *) &size, addr, 4); + size = __le32_to_cpu(readl(addr)); /* DBG1( "%d bytes port: %d", size, index); */ if (tty && test_bit(TTY_THROTTLED, &tty->flags)) { diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c index e394f123f918..ad9d6cc4e23f 100644 --- a/drivers/usb/dwc3/dwc3-msm.c +++ b/drivers/usb/dwc3/dwc3-msm.c @@ -3597,7 +3597,8 @@ static int dwc3_msm_gadget_vbus_draw(struct dwc3_msm *mdwc, unsigned mA) } } - power_supply_get_property(mdwc->usb_psy, POWER_SUPPLY_PROP_TYPE, &pval); + power_supply_get_property(mdwc->usb_psy, + POWER_SUPPLY_PROP_REAL_TYPE, &pval); if (pval.intval != POWER_SUPPLY_TYPE_USB) return 0; diff --git a/drivers/usb/gadget/function/f_midi.c b/drivers/usb/gadget/function/f_midi.c index 4ebd744434c6..79f554f1fb23 100644 --- a/drivers/usb/gadget/function/f_midi.c +++ b/drivers/usb/gadget/function/f_midi.c @@ -370,7 +370,9 @@ static int f_midi_set_alt(struct usb_function *f, unsigned intf, unsigned alt) /* allocate a bunch of read buffers and queue them all at once. */ for (i = 0; i < midi->qlen && err == 0; i++) { struct usb_request *req = - midi_alloc_ep_req(midi->out_ep, midi->buflen); + midi_alloc_ep_req(midi->out_ep, + max_t(unsigned, midi->buflen, + bulk_out_desc.wMaxPacketSize)); if (req == NULL) return -ENOMEM; diff --git a/drivers/usb/gadget/function/f_mtp.c b/drivers/usb/gadget/function/f_mtp.c index 4a0b3a0aa65e..6ee21d039415 100644 --- a/drivers/usb/gadget/function/f_mtp.c +++ b/drivers/usb/gadget/function/f_mtp.c @@ -1490,6 +1490,7 @@ mtp_function_bind(struct usb_configuration *c, struct usb_function *f) mtp_fullspeed_out_desc.bEndpointAddress; } + fi_mtp->func_inst.f = &dev->function; DBG(cdev, "%s speed %s: IN/%s, OUT/%s\n", gadget_is_superspeed(c->cdev->gadget) ? "super" : (gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full"), @@ -1501,9 +1502,10 @@ static void mtp_function_unbind(struct usb_configuration *c, struct usb_function *f) { struct mtp_dev *dev = func_to_mtp(f); + struct mtp_instance *fi_mtp; struct usb_request *req; int i; - + fi_mtp = container_of(f->fi, struct mtp_instance, func_inst); mtp_string_defs[INTERFACE_STRING_INDEX].id = 0; mutex_lock(&dev->read_mutex); while ((req = mtp_req_get(dev, &dev->tx_idle))) @@ -1517,6 +1519,7 @@ mtp_function_unbind(struct usb_configuration *c, struct usb_function *f) dev->is_ptp = false; kfree(f->os_desc_table); f->os_desc_n = 0; + fi_mtp->func_inst.f = NULL; } static int mtp_function_set_alt(struct usb_function *f, @@ -1854,6 +1857,8 @@ struct usb_function_instance *alloc_inst_mtp_ptp(bool mtp_config) config_group_init_type_name(&fi_mtp->func_inst.group, "", &mtp_func_type); + mutex_init(&fi_mtp->dev->read_mutex); + return &fi_mtp->func_inst; } EXPORT_SYMBOL_GPL(alloc_inst_mtp_ptp); @@ -1914,9 +1919,7 @@ struct usb_function *function_alloc_mtp_ptp(struct usb_function_instance *fi, dev->function.setup = mtp_ctrlreq_configfs; dev->function.free_func = mtp_free; dev->is_ptp = !mtp_config; - fi->f = &dev->function; - mutex_init(&dev->read_mutex); return &dev->function; } EXPORT_SYMBOL_GPL(function_alloc_mtp_ptp); diff --git a/drivers/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c index c76ca5a94557..055c6203577a 100644 --- a/drivers/usb/pd/policy_engine.c +++ b/drivers/usb/pd/policy_engine.c @@ -2365,7 +2365,7 @@ static int psy_changed(struct notifier_block *nb, unsigned long evt, void *ptr) pd->vbus_present = val.intval; ret = power_supply_get_property(pd->usb_psy, - POWER_SUPPLY_PROP_TYPE, &val); + POWER_SUPPLY_PROP_REAL_TYPE, &val); if (ret) { usbpd_err(&pd->dev, "Unable to read USB TYPE: %d\n", ret); return ret; diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c index 9982cb176ce8..830e2fd47642 100644 --- a/drivers/vfio/pci/vfio_pci.c +++ b/drivers/vfio/pci/vfio_pci.c @@ -562,8 +562,9 @@ static long vfio_pci_ioctl(void *device_data, } else if (cmd == VFIO_DEVICE_SET_IRQS) { struct vfio_irq_set hdr; + size_t size; u8 *data = NULL; - int ret = 0; + int max, ret = 0; minsz = offsetofend(struct vfio_irq_set, count); @@ -571,23 +572,31 @@ static long vfio_pci_ioctl(void *device_data, return -EFAULT; if (hdr.argsz < minsz || hdr.index >= VFIO_PCI_NUM_IRQS || + hdr.count >= (U32_MAX - hdr.start) || hdr.flags & ~(VFIO_IRQ_SET_DATA_TYPE_MASK | VFIO_IRQ_SET_ACTION_TYPE_MASK)) return -EINVAL; - if (!(hdr.flags & VFIO_IRQ_SET_DATA_NONE)) { - size_t size; - int max = vfio_pci_get_irq_count(vdev, hdr.index); + max = vfio_pci_get_irq_count(vdev, hdr.index); + if (hdr.start >= max || hdr.start + hdr.count > max) + return -EINVAL; - if (hdr.flags & VFIO_IRQ_SET_DATA_BOOL) - size = sizeof(uint8_t); - else if (hdr.flags & VFIO_IRQ_SET_DATA_EVENTFD) - size = sizeof(int32_t); - else - return -EINVAL; + switch (hdr.flags & VFIO_IRQ_SET_DATA_TYPE_MASK) { + case VFIO_IRQ_SET_DATA_NONE: + size = 0; + break; + case VFIO_IRQ_SET_DATA_BOOL: + size = sizeof(uint8_t); + break; + case VFIO_IRQ_SET_DATA_EVENTFD: + size = sizeof(int32_t); + break; + default: + return -EINVAL; + } - if (hdr.argsz - minsz < hdr.count * size || - hdr.start >= max || hdr.start + hdr.count > max) + if (size) { + if (hdr.argsz - minsz < hdr.count * size) return -EINVAL; data = memdup_user((void __user *)(arg + minsz), diff --git a/drivers/vfio/pci/vfio_pci_intrs.c b/drivers/vfio/pci/vfio_pci_intrs.c index 20e9a86d2dcf..5c8f767b6368 100644 --- a/drivers/vfio/pci/vfio_pci_intrs.c +++ b/drivers/vfio/pci/vfio_pci_intrs.c @@ -255,7 +255,7 @@ static int vfio_msi_enable(struct vfio_pci_device *vdev, int nvec, bool msix) if (!is_irq_none(vdev)) return -EINVAL; - vdev->ctx = kzalloc(nvec * sizeof(struct vfio_pci_irq_ctx), GFP_KERNEL); + vdev->ctx = kcalloc(nvec, sizeof(struct vfio_pci_irq_ctx), GFP_KERNEL); if (!vdev->ctx) return -ENOMEM; diff --git a/drivers/video/fbdev/msm/dsi_status_6g.c b/drivers/video/fbdev/msm/dsi_status_6g.c index 869ff1d9df37..d24b19ea77ad 100644 --- a/drivers/video/fbdev/msm/dsi_status_6g.c +++ b/drivers/video/fbdev/msm/dsi_status_6g.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -17,6 +17,7 @@ #include "mdss_dsi.h" #include "mdss_mdp.h" +#include "mdss_debug.h" /* * mdss_check_te_status() - Check the status of panel for TE based ESD. @@ -157,6 +158,7 @@ void mdss_check_dsi_ctrl_status(struct work_struct *work, uint32_t interval) ctl->ops.wait_pingpong(ctl, NULL); pr_debug("%s: DSI ctrl wait for ping pong done\n", __func__); + MDSS_XLOG(mipi->mode); mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON); ret = ctrl_pdata->check_status(ctrl_pdata); diff --git a/drivers/video/fbdev/msm/mdss.h b/drivers/video/fbdev/msm/mdss.h index 796246a856b4..1c984d02755e 100644 --- a/drivers/video/fbdev/msm/mdss.h +++ b/drivers/video/fbdev/msm/mdss.h @@ -45,6 +45,7 @@ enum mdss_mdp_clk_type { MDSS_CLK_MDP_LUT, MDSS_CLK_MDP_VSYNC, MDSS_CLK_MNOC_AHB, + MDSS_CLK_THROTTLE_AXI, MDSS_MAX_CLK }; diff --git a/drivers/video/fbdev/msm/mdss_compat_utils.c b/drivers/video/fbdev/msm/mdss_compat_utils.c index e9ba77501b38..2b9c71441d68 100644 --- a/drivers/video/fbdev/msm/mdss_compat_utils.c +++ b/drivers/video/fbdev/msm/mdss_compat_utils.c @@ -119,6 +119,9 @@ static unsigned int __do_compat_ioctl_nr(unsigned int cmd32) static void __copy_atomic_commit_struct(struct mdp_layer_commit *commit, struct mdp_layer_commit32 *commit32) { + unsigned int destSize = sizeof(commit->commit_v1.reserved); + unsigned int srcSize = sizeof(commit32->commit_v1.reserved); + unsigned int count = (destSize <= srcSize ? destSize : srcSize); commit->version = commit32->version; commit->commit_v1.flags = commit32->commit_v1.flags; commit->commit_v1.input_layer_cnt = @@ -127,7 +130,7 @@ static void __copy_atomic_commit_struct(struct mdp_layer_commit *commit, commit->commit_v1.right_roi = commit32->commit_v1.right_roi; commit->commit_v1.bl_level = commit32->commit_v1.bl_level; memcpy(&commit->commit_v1.reserved, &commit32->commit_v1.reserved, - sizeof(commit32->commit_v1.reserved)); + count); } static struct mdp_input_layer32 *__create_layer_list32( @@ -220,6 +223,7 @@ static struct mdp_input_layer *__create_layer_list( layer->flags = layer32->flags; layer->pipe_ndx = layer32->pipe_ndx; + layer->rect_num = layer32->rect_num; layer->horz_deci = layer32->horz_deci; layer->vert_deci = layer32->vert_deci; layer->z_order = layer32->z_order; diff --git a/drivers/video/fbdev/msm/mdss_compat_utils.h b/drivers/video/fbdev/msm/mdss_compat_utils.h index 4f44cd1c9471..b7fa401f52d2 100644 --- a/drivers/video/fbdev/msm/mdss_compat_utils.h +++ b/drivers/video/fbdev/msm/mdss_compat_utils.h @@ -515,7 +515,8 @@ struct mdp_input_layer32 { struct mdp_layer_buffer buffer; compat_caddr_t pp_info; int error_code; - uint32_t reserved[6]; + uint32_t rect_num; + uint32_t reserved[5]; }; struct mdp_output_layer32 { diff --git a/drivers/video/fbdev/msm/mdss_debug.c b/drivers/video/fbdev/msm/mdss_debug.c index ddb7a4c31f68..8cb6c7157230 100644 --- a/drivers/video/fbdev/msm/mdss_debug.c +++ b/drivers/video/fbdev/msm/mdss_debug.c @@ -1077,7 +1077,7 @@ static ssize_t mdss_debug_perf_bw_limit_read(struct file *file, struct mdss_data_type *mdata = file->private_data; struct mdss_max_bw_settings *temp_settings; int len = 0, i; - char buf[256]; + char buf[256] = {'\0'}; if (!mdata) return -ENODEV; diff --git a/drivers/video/fbdev/msm/mdss_debug_xlog.c b/drivers/video/fbdev/msm/mdss_debug_xlog.c index bf4117650e3c..aeefc81657b0 100644 --- a/drivers/video/fbdev/msm/mdss_debug_xlog.c +++ b/drivers/video/fbdev/msm/mdss_debug_xlog.c @@ -93,6 +93,48 @@ static inline bool mdss_xlog_is_enabled(u32 flag) (flag == MDSS_XLOG_ALL && mdss_dbg_xlog.xlog_enable); } +static void __halt_vbif_xin(void) +{ + struct mdss_data_type *mdata = mdss_mdp_get_mdata(); + + pr_err("Halting VBIF-XIN\n"); + MDSS_VBIF_WRITE(mdata, MMSS_VBIF_XIN_HALT_CTRL0, 0xFFFFFFFF, false); +} + +static void __halt_vbif_axi(void) +{ + struct mdss_data_type *mdata = mdss_mdp_get_mdata(); + + pr_err("Halting VBIF-AXI\n"); + MDSS_VBIF_WRITE(mdata, MMSS_VBIF_AXI_HALT_CTRL0, 0xFFFFFFFF, false); +} + +static void __dump_vbif_state(void) +{ + struct mdss_data_type *mdata = mdss_mdp_get_mdata(); + unsigned int reg_vbif_src_err, reg_vbif_err_info, + reg_vbif_xin_halt_ctrl0, reg_vbif_xin_halt_ctrl1, + reg_vbif_axi_halt_ctrl0, reg_vbif_axi_halt_ctrl1; + + reg_vbif_src_err = MDSS_VBIF_READ(mdata, + MMSS_VBIF_SRC_ERR, false); + reg_vbif_err_info = MDSS_VBIF_READ(mdata, + MMSS_VBIF_ERR_INFO, false); + reg_vbif_xin_halt_ctrl0 = MDSS_VBIF_READ(mdata, + MMSS_VBIF_XIN_HALT_CTRL0, false); + reg_vbif_xin_halt_ctrl1 = MDSS_VBIF_READ(mdata, + MMSS_VBIF_XIN_HALT_CTRL1, false); + reg_vbif_axi_halt_ctrl0 = MDSS_VBIF_READ(mdata, + MMSS_VBIF_AXI_HALT_CTRL0, false); + reg_vbif_axi_halt_ctrl1 = MDSS_VBIF_READ(mdata, + MMSS_VBIF_AXI_HALT_CTRL1, false); + pr_err("VBIF SRC_ERR=%x, ERR_INFO=%x\n", + reg_vbif_src_err, reg_vbif_err_info); + pr_err("VBIF XIN_HALT_CTRL0=%x, XIN_HALT_CTRL1=%x, AXI_HALT_CTRL0=%x, AXI_HALT_CTRL1=%x\n" + , reg_vbif_xin_halt_ctrl0, reg_vbif_xin_halt_ctrl1, + reg_vbif_axi_halt_ctrl0, reg_vbif_axi_halt_ctrl1); +} + void mdss_xlog(const char *name, int line, int flag, ...) { unsigned long flags; @@ -611,8 +653,17 @@ static void mdss_xlog_dump_array(struct mdss_debug_base *blk_arr[], mdss_dump_dsi_debug_bus(mdss_dbg_xlog.enable_dsi_dbgbus_dump, &mdss_dbg_xlog.dsi_dbgbus_dump); - if (dead && mdss_dbg_xlog.panic_on_err) + if (dead && mdss_dbg_xlog.panic_on_err) { + mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON); + __dump_vbif_state(); + __halt_vbif_xin(); + usleep_range(10000, 10010); + __halt_vbif_axi(); + usleep_range(10000, 10010); + __dump_vbif_state(); + mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF); panic(name); + } } static void xlog_debug_work(struct work_struct *work) diff --git a/drivers/video/fbdev/msm/mdss_fb.c b/drivers/video/fbdev/msm/mdss_fb.c index 698c5633cf6a..4eca9cb39223 100644 --- a/drivers/video/fbdev/msm/mdss_fb.c +++ b/drivers/video/fbdev/msm/mdss_fb.c @@ -2121,6 +2121,7 @@ static int mdss_fb_blank(int blank_mode, struct fb_info *info) mdss_mdp_enable_panel_disable_mode(mfd, false); ret = mdss_fb_blank_sub(blank_mode, info, mfd->op_enable); + MDSS_XLOG(blank_mode); end: mutex_unlock(&mfd->mdss_sysfs_lock); diff --git a/drivers/video/fbdev/msm/mdss_hdmi_edid.c b/drivers/video/fbdev/msm/mdss_hdmi_edid.c index 599f6cb44c63..102c22cba7dd 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_edid.c +++ b/drivers/video/fbdev/msm/mdss_hdmi_edid.c @@ -1283,6 +1283,7 @@ static void hdmi_edid_extract_speaker_allocation_data( static void hdmi_edid_extract_sink_caps(struct hdmi_edid_ctrl *edid_ctrl, const u8 *in_buf) { + u8 len; const u8 *vsd = NULL; if (!edid_ctrl) { @@ -1297,13 +1298,29 @@ static void hdmi_edid_extract_sink_caps(struct hdmi_edid_ctrl *edid_ctrl, edid_ctrl->basic_audio_supp = false; pr_debug("%s: basic audio supported: %s\n", __func__, edid_ctrl->basic_audio_supp ? "true" : "false"); + vsd = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, + VENDOR_SPECIFIC_DATA_BLOCK, &len); + + if (vsd == NULL || len == 0 || len > MAX_DATA_BLOCK_SIZE) + return; + + /* Max TMDS clock is in multiples of 5Mhz. */ + edid_ctrl->sink_caps.max_pclk_in_hz = vsd[7] * 5000000; vsd = hdmi_edid_find_hfvsdb(in_buf); if (vsd) { - /* Max pixel clock is in multiples of 5Mhz. */ - edid_ctrl->sink_caps.max_pclk_in_hz = - vsd[5]*5000000; + /* + * HF-VSDB define larger TMDS clock than VSDB. If sink + * supports TMDS Character Rates > 340M, the sink shall + * set Max_TMDS_Character_Rates appropriately and non-zero. + * Or, if sink dose not support TMDS Character Rates > 340M, + * the sink shall set this filed to 0. The max TMDS support + * clock Rate = Max_TMDS_Character_Rates * 5Mhz. + */ + if (vsd[5] != 0) + edid_ctrl->sink_caps.max_pclk_in_hz = + vsd[5] * 5000000; edid_ctrl->sink_caps.scdc_present = (vsd[6] & 0x80) ? true : false; edid_ctrl->sink_caps.scramble_support = @@ -2425,6 +2442,25 @@ bool hdmi_edid_is_dvi_mode(void *input) } /** + * hdmi_edid_get_sink_caps_max_tmds_clk() - get max tmds clock supported. + * Sink side's limitation should be concerned as well. + * @input: edid parser data + * + * Return: max tmds clock + */ +u32 hdmi_edid_get_sink_caps_max_tmds_clk(void *input) +{ + struct hdmi_edid_ctrl *edid_ctrl = (struct hdmi_edid_ctrl *)input; + + if (!edid_ctrl) { + DEV_ERR("%s: invalid input\n", __func__); + return 0; + } + + return edid_ctrl->sink_caps.max_pclk_in_hz; +} + +/** * hdmi_edid_get_deep_color() - get deep color info supported by sink * @input: edid parser data * diff --git a/drivers/video/fbdev/msm/mdss_hdmi_edid.h b/drivers/video/fbdev/msm/mdss_hdmi_edid.h index 557e9326a81d..af802bb45f89 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_edid.h +++ b/drivers/video/fbdev/msm/mdss_hdmi_edid.h @@ -81,5 +81,6 @@ void hdmi_edid_config_override(void *input, bool enable, struct hdmi_edid_override_data *data); void hdmi_edid_set_max_pclk_rate(void *input, u32 max_pclk_khz); bool hdmi_edid_is_audio_supported(void *input); +u32 hdmi_edid_get_sink_caps_max_tmds_clk(void *input); #endif /* __HDMI_EDID_H__ */ diff --git a/drivers/video/fbdev/msm/mdss_hdmi_tx.c b/drivers/video/fbdev/msm/mdss_hdmi_tx.c index 42845f9ff192..8fa229aaa174 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_tx.c +++ b/drivers/video/fbdev/msm/mdss_hdmi_tx.c @@ -2224,6 +2224,14 @@ static int hdmi_tx_read_sink_info(struct hdmi_tx_ctrl *hdmi_ctrl) status = hdmi_edid_parser(data); if (status) DEV_ERR("%s: edid parse failed\n", __func__); + else + /* + * Updata HDMI max supported TMDS clock, consider + * both sink and source capicity. + */ + hdmi_edid_set_max_pclk_rate(data, + min(hdmi_edid_get_sink_caps_max_tmds_clk(data) / 1000, + hdmi_ctrl->max_pclk_khz)); } bail: if (hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_DDC_PM, false)) diff --git a/drivers/video/fbdev/msm/mdss_mdp.c b/drivers/video/fbdev/msm/mdss_mdp.c index a645a3495593..d88d87bd2092 100644 --- a/drivers/video/fbdev/msm/mdss_mdp.c +++ b/drivers/video/fbdev/msm/mdss_mdp.c @@ -1373,7 +1373,9 @@ static inline void __mdss_mdp_reg_access_clk_enable( mdss_mdp_clk_update(MDSS_CLK_AHB, 1); mdss_mdp_clk_update(MDSS_CLK_AXI, 1); mdss_mdp_clk_update(MDSS_CLK_MDP_CORE, 1); + mdss_mdp_clk_update(MDSS_CLK_THROTTLE_AXI, 1); } else { + mdss_mdp_clk_update(MDSS_CLK_THROTTLE_AXI, 0); mdss_mdp_clk_update(MDSS_CLK_MDP_CORE, 0); mdss_mdp_clk_update(MDSS_CLK_AXI, 0); mdss_mdp_clk_update(MDSS_CLK_AHB, 0); @@ -1415,6 +1417,7 @@ static void __mdss_mdp_clk_control(struct mdss_data_type *mdata, bool enable) mdss_mdp_clk_update(MDSS_CLK_AXI, 1); mdss_mdp_clk_update(MDSS_CLK_MDP_CORE, 1); mdss_mdp_clk_update(MDSS_CLK_MDP_LUT, 1); + mdss_mdp_clk_update(MDSS_CLK_THROTTLE_AXI, 1); if (mdata->vsync_ena) mdss_mdp_clk_update(MDSS_CLK_MDP_VSYNC, 1); } else { @@ -1430,6 +1433,7 @@ static void __mdss_mdp_clk_control(struct mdss_data_type *mdata, bool enable) mdss_mdp_clk_update(MDSS_CLK_AXI, 0); mdss_mdp_clk_update(MDSS_CLK_AHB, 0); mdss_mdp_clk_update(MDSS_CLK_MNOC_AHB, 0); + mdss_mdp_clk_update(MDSS_CLK_THROTTLE_AXI, 0); /* release iommu control */ mdss_iommu_ctrl(0); @@ -1915,8 +1919,7 @@ static int mdss_mdp_irq_clk_setup(struct mdss_data_type *mdata) if (mdss_mdp_irq_clk_register(mdata, "bus_clk", MDSS_CLK_AXI) || mdss_mdp_irq_clk_register(mdata, "iface_clk", MDSS_CLK_AHB) || - mdss_mdp_irq_clk_register(mdata, "core_clk", - MDSS_CLK_MDP_CORE)) + mdss_mdp_irq_clk_register(mdata, "core_clk", MDSS_CLK_MDP_CORE)) return -EINVAL; /* lut_clk is not present on all MDSS revisions */ @@ -1928,6 +1931,10 @@ static int mdss_mdp_irq_clk_setup(struct mdss_data_type *mdata) /* this clk is not present on all MDSS revisions */ mdss_mdp_irq_clk_register(mdata, "mnoc_clk", MDSS_CLK_MNOC_AHB); + /* this clk is not present on all MDSS revisions */ + mdss_mdp_irq_clk_register(mdata, "throttle_bus_clk", + MDSS_CLK_THROTTLE_AXI); + /* Setting the default clock rate to the max supported.*/ mdss_mdp_set_clk_rate(mdata->max_mdp_clk_rate, false); pr_debug("mdp clk rate=%ld\n", diff --git a/drivers/video/fbdev/msm/mdss_mdp.h b/drivers/video/fbdev/msm/mdss_mdp.h index a2139f495f52..fd2c2cdb3820 100644 --- a/drivers/video/fbdev/msm/mdss_mdp.h +++ b/drivers/video/fbdev/msm/mdss_mdp.h @@ -2023,6 +2023,8 @@ void mdss_mdp_set_supported_formats(struct mdss_data_type *mdata); int mdss_mdp_dest_scaler_setup_locked(struct mdss_mdp_mixer *mixer); void *mdss_mdp_intf_get_ctx_base(struct mdss_mdp_ctl *ctl, int intf_num); +int mdss_mdp_mixer_get_hw_num(struct mdss_mdp_mixer *mixer); + #ifdef CONFIG_FB_MSM_MDP_NONE struct mdss_data_type *mdss_mdp_get_mdata(void) { diff --git a/drivers/video/fbdev/msm/mdss_mdp_ctl.c b/drivers/video/fbdev/msm/mdss_mdp_ctl.c index 1f29a9f86e24..c062de3c1e59 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_ctl.c +++ b/drivers/video/fbdev/msm/mdss_mdp_ctl.c @@ -4802,7 +4802,7 @@ static void __mdss_mdp_mixer_get_offsets(u32 mixer_num, offsets[2] = MDSS_MDP_REG_CTL_LAYER_EXTN2(mixer_num); } -static inline int __mdss_mdp_mixer_get_hw_num(struct mdss_mdp_mixer *mixer) +int mdss_mdp_mixer_get_hw_num(struct mdss_mdp_mixer *mixer) { struct mdss_data_type *mdata = mdss_mdp_get_mdata(); @@ -4858,7 +4858,7 @@ static void __mdss_mdp_mixer_write_cfg(struct mdss_mdp_mixer *mixer, if (!mixer) return; - mixer_num = __mdss_mdp_mixer_get_hw_num(mixer); + mixer_num = mdss_mdp_mixer_get_hw_num(mixer); if (cfg) { for (i = 0; i < NUM_MIXERCFG_REGS; i++) @@ -4905,7 +4905,7 @@ bool mdss_mdp_mixer_reg_has_pipe(struct mdss_mdp_mixer *mixer, memset(&mixercfg, 0, sizeof(mixercfg)); - mixer_num = __mdss_mdp_mixer_get_hw_num(mixer); + mixer_num = mdss_mdp_mixer_get_hw_num(mixer); __mdss_mdp_mixer_get_offsets(mixer_num, offs, NUM_MIXERCFG_REGS); for (i = 0; i < NUM_MIXERCFG_REGS; i++) @@ -5130,7 +5130,7 @@ static void mdss_mdp_mixer_setup(struct mdss_mdp_ctl *master_ctl, mixercfg.cursor_enabled = true; update_mixer: - mixer_num = __mdss_mdp_mixer_get_hw_num(mixer_hw); + mixer_num = mdss_mdp_mixer_get_hw_num(mixer_hw); ctl_hw->flush_bits |= BIT(mixer_num < 5 ? 6 + mixer_num : 20); /* Read GC enable/disable status on LM */ @@ -5775,6 +5775,7 @@ int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg, mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON); if (ctl->ops.avr_ctrl_fnc) { + /* avr_ctrl_fnc will configure both master & slave */ ret = ctl->ops.avr_ctrl_fnc(ctl, true); if (ret) { pr_err("error configuring avr ctrl registers ctl=%d err=%d\n", @@ -5784,16 +5785,6 @@ int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg, } } - if (sctl && sctl->ops.avr_ctrl_fnc) { - ret = sctl->ops.avr_ctrl_fnc(sctl, true); - if (ret) { - pr_err("error configuring avr ctrl registers sctl=%d err=%d\n", - sctl->num, ret); - mutex_unlock(&ctl->lock); - return ret; - } - } - mutex_lock(&ctl->flush_lock); /* @@ -6046,6 +6037,10 @@ int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg, ctl_flush_bits |= ctl->flush_bits; ATRACE_BEGIN("flush_kickoff"); + + MDSS_XLOG(ctl->intf_num, ctl_flush_bits, sctl_flush_bits, + mdss_mdp_ctl_read(ctl, MDSS_MDP_REG_CTL_FLUSH), split_lm_valid); + mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_FLUSH, ctl_flush_bits); if (sctl) { if (sctl_flush_bits) { @@ -6057,8 +6052,6 @@ int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg, } ctl->commit_in_progress = false; - MDSS_XLOG(ctl->intf_num, ctl_flush_bits, sctl_flush_bits, - split_lm_valid); wmb(); ctl->flush_reg_data = ctl_flush_bits; ctl->flush_bits = 0; diff --git a/drivers/video/fbdev/msm/mdss_mdp_debug.c b/drivers/video/fbdev/msm/mdss_mdp_debug.c index 1ad6810a6bb6..1035d23fe9ce 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_debug.c +++ b/drivers/video/fbdev/msm/mdss_mdp_debug.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1757,6 +1757,8 @@ void mdss_mdp_hw_rev_debug_caps_init(struct mdss_data_type *mdata) break; case MDSS_MDP_HW_REV_300: case MDSS_MDP_HW_REV_301: + case MDSS_MDP_HW_REV_320: + case MDSS_MDP_HW_REV_330: mdata->dbg_bus = dbg_bus_msm8998; mdata->dbg_bus_size = ARRAY_SIZE(dbg_bus_msm8998); mdata->vbif_dbg_bus = vbif_dbg_bus_msm8998; diff --git a/drivers/video/fbdev/msm/mdss_mdp_hwio.h b/drivers/video/fbdev/msm/mdss_mdp_hwio.h index d9e2b042bfc3..78bfab7d8ce8 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_hwio.h +++ b/drivers/video/fbdev/msm/mdss_mdp_hwio.h @@ -829,6 +829,8 @@ enum mdss_mdp_pingpong_index { #define MMSS_VBIF_WR_LIM_CONF 0x0C0 #define MDSS_VBIF_WRITE_GATHER_EN 0x0AC +#define MMSS_VBIF_SRC_ERR 0x194 +#define MMSS_VBIF_ERR_INFO 0x1A0 #define MMSS_VBIF_XIN_HALT_CTRL0 0x200 #define MMSS_VBIF_XIN_HALT_CTRL1 0x204 #define MMSS_VBIF_AXI_HALT_CTRL0 0x208 diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_video.c b/drivers/video/fbdev/msm/mdss_mdp_intf_video.c index 13c70822e266..587150bbc9fa 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_intf_video.c +++ b/drivers/video/fbdev/msm/mdss_mdp_intf_video.c @@ -72,6 +72,7 @@ struct mdss_mdp_video_ctx { u8 ref_cnt; u8 timegen_en; + bool timegen_flush_pending; bool polling_en; u32 poll_cnt; struct completion vsync_comp; @@ -451,13 +452,32 @@ static int mdss_mdp_video_intf_recovery(void *data, int event) } } +static int mdss_mdp_video_wait_one_frame(struct mdss_mdp_ctl *ctl) +{ + u32 frame_time, frame_rate; + int ret = 0; + struct mdss_panel_data *pdata = ctl->panel_data; + + if (pdata == NULL) { + frame_rate = DEFAULT_FRAME_RATE; + } else { + frame_rate = mdss_panel_get_framerate(&pdata->panel_info); + if (!(frame_rate >= 24 && frame_rate <= 240)) + frame_rate = 24; + } + + frame_time = ((1000/frame_rate) + 1); + + msleep(frame_time); + + return ret; +} + static void mdss_mdp_video_avr_vtotal_setup(struct mdss_mdp_ctl *ctl, struct intf_timing_params *p, struct mdss_mdp_video_ctx *ctx) { struct mdss_data_type *mdata = ctl->mdata; - struct mdss_mdp_ctl *sctl = NULL; - struct mdss_mdp_video_ctx *sctx = NULL; if (test_bit(MDSS_CAPS_AVR_SUPPORTED, mdata->mdss_caps_map)) { struct mdss_panel_data *pdata = ctl->panel_data; @@ -484,14 +504,11 @@ static void mdss_mdp_video_avr_vtotal_setup(struct mdss_mdp_ctl *ctl, /* * Make sure config goes through + * and queue timegen flush */ wmb(); - sctl = mdss_mdp_get_split_ctl(ctl); - if (sctl) - sctx = (struct mdss_mdp_video_ctx *) - sctl->intf_ctx[MASTER_CTX]; - mdss_mdp_video_timegen_flush(ctl, sctx); + ctx->timegen_flush_pending = true; MDSS_XLOG(pinfo->min_fps, pinfo->default_fps, avr_vtotal); } @@ -687,8 +704,10 @@ static void mdss_mdp_video_timegen_flush(struct mdss_mdp_ctl *ctl, ctl_flush |= (BIT(31) >> (sctx->intf_num - MDSS_MDP_INTF0)); } + MDSS_XLOG(ctl->intf_num, sctx?sctx->intf_num:0xf00, ctl_flush, + mdss_mdp_ctl_read(ctl, MDSS_MDP_REG_CTL_FLUSH)); mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_FLUSH, ctl_flush); - MDSS_XLOG(ctl->intf_num, sctx?sctx->intf_num:0xf00, ctl_flush); + } static inline void video_vsync_irq_enable(struct mdss_mdp_ctl *ctl, bool clear) @@ -2464,25 +2483,41 @@ static int mdss_mdp_video_early_wake_up(struct mdss_mdp_ctl *ctl) static int mdss_mdp_video_avr_ctrl(struct mdss_mdp_ctl *ctl, bool enable) { struct mdss_mdp_video_ctx *ctx = NULL, *sctx = NULL; + struct mdss_mdp_ctl *sctl; ctx = (struct mdss_mdp_video_ctx *) ctl->intf_ctx[MASTER_CTX]; if (!ctx || !ctx->ref_cnt) { pr_err("invalid master ctx\n"); return -EINVAL; } - mdss_mdp_video_avr_ctrl_setup(ctx, ctl, ctl->is_master, - enable); - if (is_pingpong_split(ctl->mfd)) { + sctl = mdss_mdp_get_split_ctl(ctl); + if (sctl) { + sctx = (struct mdss_mdp_video_ctx *) sctl->intf_ctx[MASTER_CTX]; + } else if (is_pingpong_split(ctl->mfd)) { sctx = (struct mdss_mdp_video_ctx *) ctl->intf_ctx[SLAVE_CTX]; if (!sctx || !sctx->ref_cnt) { pr_err("invalid slave ctx\n"); return -EINVAL; } - mdss_mdp_video_avr_ctrl_setup(sctx, ctl, false, - enable); } + if (ctx->timegen_flush_pending) { + mdss_mdp_video_timegen_flush(ctl, sctx); + + /* wait a frame for flush to be completed */ + mdss_mdp_video_wait_one_frame(ctl); + + ctx->timegen_flush_pending = false; + if (sctx) + sctx->timegen_flush_pending = false; + } + + mdss_mdp_video_avr_ctrl_setup(ctx, ctl, ctl->is_master, enable); + + if (sctx) + mdss_mdp_video_avr_ctrl_setup(sctx, ctl, false, enable); + return 0; } diff --git a/drivers/video/fbdev/msm/mdss_mdp_layer.c b/drivers/video/fbdev/msm/mdss_mdp_layer.c index 09a34223c2a5..472f1e8e8e3b 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_layer.c +++ b/drivers/video/fbdev/msm/mdss_mdp_layer.c @@ -2160,115 +2160,157 @@ static int __multirect_validate_mode(struct msm_fb_data_type *mfd, return 0; } -static int __update_multirect_info(struct msm_fb_data_type *mfd, - struct mdss_mdp_validate_info_t *validate_info_list, - struct mdp_input_layer *layer_list, int ndx, int layer_cnt) +/* + * linear search for a layer with given source pipe and rectangle number. + * If rectangle number is invalid, it's dropped from search criteria + */ +static int find_layer(enum mdss_mdp_sspp_index pnum, + int rect_num, + struct mdp_input_layer *layer_list, + size_t layer_cnt, int start_index) { - struct mdss_data_type *mdata = mdss_mdp_get_mdata(); - struct mdss_mdp_validate_info_t *vinfo[MDSS_MDP_PIPE_MAX_RECTS]; - int i, ptype, max_rects, mode; - int cnt = 1; + int i; - mode = __multirect_layer_flags_to_mode(layer_list[ndx].flags); - if (IS_ERR_VALUE(mode)) - return mode; + if (start_index < 0) + start_index = 0; - pr_debug("layer #%d pipe_ndx=%d multirect mode=%d\n", - ndx, layer_list[ndx].pipe_ndx, mode); + if (start_index >= layer_cnt) + return -EINVAL; - vinfo[0] = &validate_info_list[ndx]; - vinfo[0]->layer = &layer_list[ndx]; - vinfo[0]->multirect.mode = mode; - vinfo[0]->multirect.num = MDSS_MDP_PIPE_RECT0; - vinfo[0]->multirect.next = NULL; + for (i = start_index; i < layer_cnt; i++) { + if (get_pipe_num_from_ndx(layer_list[i].pipe_ndx) == pnum && + (rect_num < MDSS_MDP_PIPE_RECT0 || + rect_num >= MDSS_MDP_PIPE_MAX_RECTS || + layer_list[i].rect_num == rect_num)) + return i; + } - /* nothing to be done if multirect is disabled */ - if (mode == MDSS_MDP_PIPE_MULTIRECT_NONE) - return cnt; + return -ENOENT; /* no match found */ +} - ptype = get_pipe_type_from_ndx(layer_list[ndx].pipe_ndx); - if (ptype == MDSS_MDP_PIPE_TYPE_INVALID) { - pr_err("invalid pipe ndx %d\n", layer_list[ndx].pipe_ndx); - return -EINVAL; - } +static int __validate_multirect_param(struct msm_fb_data_type *mfd, + struct mdss_mdp_validate_info_t *validate_info_list, + struct mdp_input_layer *layer_list, + int ndx, size_t layer_count) +{ + int multirect_mode; + int pnum; + int rect_num; + + /* populate v_info with default values */ + validate_info_list[ndx].layer = &layer_list[ndx]; + validate_info_list[ndx].multirect.max_rects = MDSS_MDP_PIPE_MAX_RECTS; + validate_info_list[ndx].multirect.next = NULL; + validate_info_list[ndx].multirect.num = MDSS_MDP_PIPE_RECT0; + validate_info_list[ndx].multirect.mode = MDSS_MDP_PIPE_MULTIRECT_NONE; + + multirect_mode = __multirect_layer_flags_to_mode( + layer_list[ndx].flags); + if (IS_ERR_VALUE(multirect_mode)) + return multirect_mode; - max_rects = mdata->rects_per_sspp[ptype] ? : 1; + /* nothing to be done if multirect is disabled */ + if (multirect_mode == MDSS_MDP_PIPE_MULTIRECT_NONE) + return 0; - for (i = ndx + 1; i < layer_cnt; i++) { - if (layer_list[ndx].pipe_ndx == layer_list[i].pipe_ndx) { - if (cnt >= max_rects) { - pr_err("more than %d layers of type %d with same pipe_ndx=%d indexes=%d %d\n", - max_rects, ptype, - layer_list[ndx].pipe_ndx, ndx, i); - return -EINVAL; - } + validate_info_list[ndx].multirect.mode = multirect_mode; - mode = __multirect_layer_flags_to_mode( - layer_list[i].flags); - if (IS_ERR_VALUE(mode)) - return mode; + pnum = get_pipe_num_from_ndx(layer_list[ndx].pipe_ndx); + if (get_pipe_type_from_num(pnum) != MDSS_MDP_PIPE_TYPE_DMA) { + pr_err("Multirect not supported on pipe ndx 0x%x\n", + layer_list[ndx].pipe_ndx); + return -EINVAL; + } - if (mode != vinfo[0]->multirect.mode) { - pr_err("unable to set different multirect modes for pipe_ndx=%d (%d %d)\n", - layer_list[ndx].pipe_ndx, ndx, i); - return -EINVAL; - } + rect_num = layer_list[ndx].rect_num; + if (rect_num >= MDSS_MDP_PIPE_MAX_RECTS) + return -EINVAL; + validate_info_list[ndx].multirect.num = rect_num; - pr_debug("found matching pair for pipe_ndx=%d (%d %d)\n", - layer_list[i].pipe_ndx, ndx, i); + return 0; +} - vinfo[cnt] = &validate_info_list[i]; - vinfo[cnt]->multirect.num = cnt; - vinfo[cnt]->multirect.next = vinfo[0]->layer; - vinfo[cnt]->multirect.mode = mode; - vinfo[cnt]->layer = &layer_list[i]; +static int __update_multirect_info(struct msm_fb_data_type *mfd, + struct mdss_mdp_validate_info_t *validate_info_list, + struct mdp_input_layer *layer_list, + int ndx, size_t layer_cnt, int is_rect_num_valid) +{ + int ret; + int pair_rect_num = -1; + int pair_index; + + if (!is_rect_num_valid) + layer_list[ndx].rect_num = MDSS_MDP_PIPE_RECT0; + + ret = __validate_multirect_param(mfd, validate_info_list, + layer_list, ndx, layer_cnt); + /* return if we hit error or multirectangle mode is disabled. */ + if (IS_ERR_VALUE(ret) || + (!ret && validate_info_list[ndx].multirect.mode == + MDSS_MDP_PIPE_MULTIRECT_NONE)) + return ret; - vinfo[cnt - 1]->multirect.next = vinfo[cnt]->layer; - cnt++; - } - } + if (is_rect_num_valid) + pair_rect_num = (validate_info_list[ndx].multirect.num == + MDSS_MDP_PIPE_RECT0) ? MDSS_MDP_PIPE_RECT1 : + MDSS_MDP_PIPE_RECT0; - if (cnt == 1) { - pr_err("multirect mode enabled but unable to find extra rects for pipe_ndx=%x\n", + pair_index = find_layer(get_pipe_num_from_ndx( + layer_list[ndx].pipe_ndx), pair_rect_num, + layer_list, layer_cnt, ndx + 1); + if (IS_ERR_VALUE(pair_index)) { + pr_err("Multirect pair not found for pipe ndx 0x%x\n", layer_list[ndx].pipe_ndx); return -EINVAL; } - return cnt; + if (!is_rect_num_valid) + layer_list[pair_index].rect_num = MDSS_MDP_PIPE_RECT1; + + ret = __validate_multirect_param(mfd, validate_info_list, + layer_list, pair_index, layer_cnt); + if (IS_ERR_VALUE(ret) || + (validate_info_list[ndx].multirect.mode != + validate_info_list[pair_index].multirect.mode)) + return -EINVAL; + + validate_info_list[ndx].multirect.next = &layer_list[pair_index]; + validate_info_list[pair_index].multirect.next = &layer_list[ndx]; + + return 0; } static int __validate_multirect(struct msm_fb_data_type *mfd, - struct mdss_mdp_validate_info_t *validate_info_list, - struct mdp_input_layer *layer_list, int ndx, int layer_cnt) + struct mdss_mdp_validate_info_t *validate_info_list, + struct mdp_input_layer *layer_list, + int ndx, size_t layer_cnt, int is_rect_num_valid) { - struct mdp_input_layer *layers[MDSS_MDP_PIPE_MAX_RECTS] = { 0 }; - int i, cnt, rc; - - cnt = __update_multirect_info(mfd, validate_info_list, - layer_list, ndx, layer_cnt); - if (IS_ERR_VALUE(cnt)) - return cnt; - - if (cnt <= 1) { - /* nothing to validate in single rect mode */ - return 0; - } else if (cnt > 2) { - pr_err("unsupported multirect configuration, multirect cnt=%d\n", - cnt); - return -EINVAL; - } + int ret; + int i; + struct mdp_input_layer *layers[MDSS_MDP_PIPE_MAX_RECTS]; + struct mdp_input_layer *pair_layer; + + ret = __update_multirect_info(mfd, validate_info_list, + layer_list, ndx, layer_cnt, is_rect_num_valid); + /* return if we hit error or multirectangle mode is disabled. */ + if (IS_ERR_VALUE(ret) || + (!ret && validate_info_list[ndx].multirect.mode == + MDSS_MDP_PIPE_MULTIRECT_NONE)) + return ret; - layers[0] = validate_info_list[ndx].layer; - layers[1] = validate_info_list[ndx].multirect.next; + layers[validate_info_list[ndx].multirect.num] = &layer_list[ndx]; + pair_layer = validate_info_list[ndx].multirect.next; + layers[pair_layer->rect_num] = pair_layer; + /* check against smart DMA v1.0 restrictions */ for (i = 0; i < ARRAY_SIZE(__multirect_validators); i++) { - if (!__multirect_validators[i](layers, cnt)) + if (!__multirect_validators[i](layers, + MDSS_MDP_PIPE_MAX_RECTS)) return -EINVAL; } - - rc = __multirect_validate_mode(mfd, layers, cnt); - if (IS_ERR_VALUE(rc)) - return rc; + ret = __multirect_validate_mode(mfd, layers, MDSS_MDP_PIPE_MAX_RECTS); + if (IS_ERR_VALUE(ret)) + return ret; return 0; } @@ -2416,14 +2458,14 @@ static int __validate_layers(struct msm_fb_data_type *mfd, if (!validate_info_list[i].layer) { ret = __validate_multirect(mfd, validate_info_list, - layer_list, i, layer_count); + layer_list, i, layer_count, + !!(commit->flags & MDP_COMMIT_RECT_NUM)); if (ret) { pr_err("error validating multirect config. ret=%d i=%d\n", ret, i); goto end; } } - rect_num = validate_info_list[i].multirect.num; BUG_ON(rect_num >= MDSS_MDP_PIPE_MAX_RECTS); @@ -2782,7 +2824,8 @@ int mdss_mdp_layer_pre_commit(struct msm_fb_data_type *mfd, for (i = 0; i < layer_count; i++) { if (!validate_info_list[i].layer) { ret = __update_multirect_info(mfd, validate_info_list, - layer_list, i, layer_count); + layer_list, i, layer_count, + !!(commit->flags & MDP_COMMIT_RECT_NUM)); if (IS_ERR_VALUE(ret)) { pr_err("error updating multirect config. ret=%d i=%d\n", ret, i); @@ -3035,6 +3078,12 @@ int mdss_mdp_layer_pre_commit_wfd(struct msm_fb_data_type *mfd, wfd = mdp5_data->wfd; output_layer = commit->output_layer; + if (output_layer->buffer.plane_count > MAX_PLANES) { + pr_err("Output buffer plane_count exceeds MAX_PLANES limit:%d\n", + output_layer->buffer.plane_count); + return -EINVAL; + } + data = mdss_mdp_wfd_add_data(wfd, output_layer); if (IS_ERR_OR_NULL(data)) return PTR_ERR(data); diff --git a/drivers/video/fbdev/msm/mdss_mdp_overlay.c b/drivers/video/fbdev/msm/mdss_mdp_overlay.c index 8c612e2b83fb..87fff44af389 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_overlay.c +++ b/drivers/video/fbdev/msm/mdss_mdp_overlay.c @@ -3053,6 +3053,13 @@ static void mdss_mdp_overlay_pan_display(struct msm_fb_data_type *mfd) goto pipe_release; } + if (l_pipe_allocated && + (l_pipe->multirect.num == MDSS_MDP_PIPE_RECT1)) { + pr_err("Invalid: L_Pipe-%d is assigned for RECT-%d\n", + l_pipe->num, l_pipe->multirect.num); + goto pipe_release; + } + if (mdss_mdp_pipe_map(l_pipe)) { pr_err("unable to map base pipe\n"); goto pipe_release; @@ -3100,6 +3107,16 @@ static void mdss_mdp_overlay_pan_display(struct msm_fb_data_type *mfd) goto iommu_disable; } + if (l_pipe_allocated && r_pipe_allocated && + (l_pipe->num != r_pipe->num) && + (r_pipe->multirect.num == + MDSS_MDP_PIPE_RECT1)) { + pr_err("Invalid: L_Pipe-%d,RECT-%d R_Pipe-%d,RECT-%d\n", + l_pipe->num, l_pipe->multirect.num, + r_pipe->num, l_pipe->multirect.num); + goto iommu_disable; + } + if (mdss_mdp_pipe_map(r_pipe)) { pr_err("unable to map right base pipe\n"); goto iommu_disable; diff --git a/drivers/video/fbdev/msm/mdss_mdp_pp.c b/drivers/video/fbdev/msm/mdss_mdp_pp.c index f128f82fab04..2e85072c4cf7 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_pp.c +++ b/drivers/video/fbdev/msm/mdss_mdp_pp.c @@ -2599,6 +2599,7 @@ int mdss_mdp_dest_scaler_setup_locked(struct mdss_mdp_mixer *mixer) u32 op_mode; u32 mask; char *ds_offset; + int mixer_num = 0; if (!mixer || !mixer->ctl || !mixer->ctl->mdata) return -EINVAL; @@ -2658,6 +2659,14 @@ int mdss_mdp_dest_scaler_setup_locked(struct mdss_mdp_mixer *mixer) pr_err("Failed setup destination scaler\n"); return ret; } + /* Set LM Flush in order to update DS registers */ + if (ds->flags & DS_SCALE_UPDATE) { + mutex_lock(&ctl->flush_lock); + mixer_num = mdss_mdp_mixer_get_hw_num(mixer); + ctl->flush_bits |= + BIT(mixer_num < 5 ? 6 + mixer_num : 20); + mutex_unlock(&ctl->flush_lock); + } /* * Clearing the flag because we don't need to program the block * for each commit if there is no change. diff --git a/drivers/video/fbdev/msm/mdss_mdp_util.c b/drivers/video/fbdev/msm/mdss_mdp_util.c index d0bf61679f61..22656175edf8 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_util.c +++ b/drivers/video/fbdev/msm/mdss_mdp_util.c @@ -1095,7 +1095,7 @@ static int mdss_mdp_get_img(struct msmfb_data *img, return ret; } } - if (!*start) { + if (start && !*start) { pr_err("start address is zero!\n"); mdss_mdp_put_img(data, rotator, dir); return -ENOMEM; diff --git a/drivers/video/fbdev/msm/mdss_mdp_wfd.c b/drivers/video/fbdev/msm/mdss_mdp_wfd.c index 71a07f6b7d39..7868dc0f1999 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_wfd.c +++ b/drivers/video/fbdev/msm/mdss_mdp_wfd.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -322,6 +322,12 @@ int mdss_mdp_wb_import_data(struct device *device, if (wfd_data->layer.flags & MDP_LAYER_SECURE_SESSION) flags = MDP_SECURE_OVERLAY_SESSION; + if (buffer->plane_count > MAX_PLANES) { + pr_err("buffer plane_count exceeds MAX_PLANES limit:%d", + buffer->plane_count); + return -EINVAL; + } + memset(planes, 0, sizeof(planes)); for (i = 0; i < buffer->plane_count; i++) { diff --git a/drivers/video/fbdev/msm/mdss_rotator.c b/drivers/video/fbdev/msm/mdss_rotator.c index fdd1c0153ce0..399a12e3dcc8 100644 --- a/drivers/video/fbdev/msm/mdss_rotator.c +++ b/drivers/video/fbdev/msm/mdss_rotator.c @@ -501,6 +501,12 @@ static int mdss_rotator_import_buffer(struct mdp_layer_buffer *buffer, memset(planes, 0, sizeof(planes)); + if (buffer->plane_count > MAX_PLANES) { + pr_err("buffer plane_count exceeds MAX_PLANES limit:%d\n", + buffer->plane_count); + return -EINVAL; + } + for (i = 0; i < buffer->plane_count; i++) { planes[i].memory_id = buffer->planes[i].fd; planes[i].offset = buffer->planes[i].offset; @@ -2104,6 +2110,20 @@ struct mdss_rot_entry_container *mdss_rotator_req_init( struct mdss_rot_entry_container *req; int size, i; + /* + * Check input and output plane_count from each given item + * are within the MAX_PLANES limit + */ + for (i = 0 ; i < count; i++) { + if ((items[i].input.plane_count > MAX_PLANES) || + (items[i].output.plane_count > MAX_PLANES)) { + pr_err("Input/Output plane_count exceeds MAX_PLANES limit, input:%d, output:%d\n", + items[i].input.plane_count, + items[i].output.plane_count); + return ERR_PTR(-EINVAL); + } + } + size = sizeof(struct mdss_rot_entry_container); size += sizeof(struct mdss_rot_entry) * count; req = devm_kzalloc(&mgr->pdev->dev, size, GFP_KERNEL); diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index b76883606e4b..94906aaa9b7c 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -906,7 +906,6 @@ struct cifs_tcon { bool use_persistent:1; /* use persistent instead of durable handles */ #ifdef CONFIG_CIFS_SMB2 bool print:1; /* set if connection to printer share */ - bool bad_network_name:1; /* set if ret status STATUS_BAD_NETWORK_NAME */ __le32 capabilities; __u32 share_flags; __u32 maximal_access; diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c index fc537c29044e..87b87e091e8e 100644 --- a/fs/cifs/smb1ops.c +++ b/fs/cifs/smb1ops.c @@ -1015,6 +1015,15 @@ cifs_dir_needs_close(struct cifsFileInfo *cfile) return !cfile->srch_inf.endOfSearch && !cfile->invalidHandle; } +static bool +cifs_can_echo(struct TCP_Server_Info *server) +{ + if (server->tcpStatus == CifsGood) + return true; + + return false; +} + struct smb_version_operations smb1_operations = { .send_cancel = send_nt_cancel, .compare_fids = cifs_compare_fids, @@ -1049,6 +1058,7 @@ struct smb_version_operations smb1_operations = { .get_dfs_refer = CIFSGetDFSRefer, .qfs_tcon = cifs_qfs_tcon, .is_path_accessible = cifs_is_path_accessible, + .can_echo = cifs_can_echo, .query_path_info = cifs_query_path_info, .query_file_info = cifs_query_file_info, .get_srv_inum = cifs_get_srv_inum, diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 6cb5c4b30e78..6cb2603f8a5c 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -932,9 +932,6 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree, else return -EIO; - if (tcon && tcon->bad_network_name) - return -ENOENT; - if ((tcon && tcon->seal) && ((ses->server->capabilities & SMB2_GLOBAL_CAP_ENCRYPTION) == 0)) { cifs_dbg(VFS, "encryption requested but no server support"); @@ -1036,8 +1033,6 @@ tcon_exit: tcon_error_exit: if (rsp->hdr.Status == STATUS_BAD_NETWORK_NAME) { cifs_dbg(VFS, "BAD_NETWORK_NAME: %s\n", tree); - if (tcon) - tcon->bad_network_name = true; } goto tcon_exit; } diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 106dda1e743d..d2e75fe2e072 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -918,6 +918,79 @@ loff_t max_file_size(unsigned bits) return result; } +static inline bool sanity_check_area_boundary(struct super_block *sb, + struct f2fs_super_block *raw_super) +{ + u32 segment0_blkaddr = le32_to_cpu(raw_super->segment0_blkaddr); + u32 cp_blkaddr = le32_to_cpu(raw_super->cp_blkaddr); + u32 sit_blkaddr = le32_to_cpu(raw_super->sit_blkaddr); + u32 nat_blkaddr = le32_to_cpu(raw_super->nat_blkaddr); + u32 ssa_blkaddr = le32_to_cpu(raw_super->ssa_blkaddr); + u32 main_blkaddr = le32_to_cpu(raw_super->main_blkaddr); + u32 segment_count_ckpt = le32_to_cpu(raw_super->segment_count_ckpt); + u32 segment_count_sit = le32_to_cpu(raw_super->segment_count_sit); + u32 segment_count_nat = le32_to_cpu(raw_super->segment_count_nat); + u32 segment_count_ssa = le32_to_cpu(raw_super->segment_count_ssa); + u32 segment_count_main = le32_to_cpu(raw_super->segment_count_main); + u32 segment_count = le32_to_cpu(raw_super->segment_count); + u32 log_blocks_per_seg = le32_to_cpu(raw_super->log_blocks_per_seg); + + if (segment0_blkaddr != cp_blkaddr) { + f2fs_msg(sb, KERN_INFO, + "Mismatch start address, segment0(%u) cp_blkaddr(%u)", + segment0_blkaddr, cp_blkaddr); + return true; + } + + if (cp_blkaddr + (segment_count_ckpt << log_blocks_per_seg) != + sit_blkaddr) { + f2fs_msg(sb, KERN_INFO, + "Wrong CP boundary, start(%u) end(%u) blocks(%u)", + cp_blkaddr, sit_blkaddr, + segment_count_ckpt << log_blocks_per_seg); + return true; + } + + if (sit_blkaddr + (segment_count_sit << log_blocks_per_seg) != + nat_blkaddr) { + f2fs_msg(sb, KERN_INFO, + "Wrong SIT boundary, start(%u) end(%u) blocks(%u)", + sit_blkaddr, nat_blkaddr, + segment_count_sit << log_blocks_per_seg); + return true; + } + + if (nat_blkaddr + (segment_count_nat << log_blocks_per_seg) != + ssa_blkaddr) { + f2fs_msg(sb, KERN_INFO, + "Wrong NAT boundary, start(%u) end(%u) blocks(%u)", + nat_blkaddr, ssa_blkaddr, + segment_count_nat << log_blocks_per_seg); + return true; + } + + if (ssa_blkaddr + (segment_count_ssa << log_blocks_per_seg) != + main_blkaddr) { + f2fs_msg(sb, KERN_INFO, + "Wrong SSA boundary, start(%u) end(%u) blocks(%u)", + ssa_blkaddr, main_blkaddr, + segment_count_ssa << log_blocks_per_seg); + return true; + } + + if (main_blkaddr + (segment_count_main << log_blocks_per_seg) != + segment0_blkaddr + (segment_count << log_blocks_per_seg)) { + f2fs_msg(sb, KERN_INFO, + "Wrong MAIN_AREA boundary, start(%u) end(%u) blocks(%u)", + main_blkaddr, + segment0_blkaddr + (segment_count << log_blocks_per_seg), + segment_count_main << log_blocks_per_seg); + return true; + } + + return false; +} + static int sanity_check_raw_super(struct super_block *sb, struct f2fs_super_block *raw_super) { @@ -947,6 +1020,14 @@ static int sanity_check_raw_super(struct super_block *sb, return 1; } + /* check log blocks per segment */ + if (le32_to_cpu(raw_super->log_blocks_per_seg) != 9) { + f2fs_msg(sb, KERN_INFO, + "Invalid log blocks per segment (%u)\n", + le32_to_cpu(raw_super->log_blocks_per_seg)); + return 1; + } + /* Currently, support 512/1024/2048/4096 bytes sector size */ if (le32_to_cpu(raw_super->log_sectorsize) > F2FS_MAX_LOG_SECTOR_SIZE || @@ -965,6 +1046,23 @@ static int sanity_check_raw_super(struct super_block *sb, le32_to_cpu(raw_super->log_sectorsize)); return 1; } + + /* check reserved ino info */ + if (le32_to_cpu(raw_super->node_ino) != 1 || + le32_to_cpu(raw_super->meta_ino) != 2 || + le32_to_cpu(raw_super->root_ino) != 3) { + f2fs_msg(sb, KERN_INFO, + "Invalid Fs Meta Ino: node(%u) meta(%u) root(%u)", + le32_to_cpu(raw_super->node_ino), + le32_to_cpu(raw_super->meta_ino), + le32_to_cpu(raw_super->root_ino)); + return 1; + } + + /* check CP/SIT/NAT/SSA/MAIN_AREA area boundary */ + if (sanity_check_area_boundary(sb, raw_super)) + return 1; + return 0; } diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index ad8a5b757cc7..a443c6e54412 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -760,7 +760,7 @@ static int get_first_leaf(struct gfs2_inode *dip, u32 index, int error; error = get_leaf_nr(dip, index, &leaf_no); - if (!error) + if (!IS_ERR_VALUE(error)) error = get_leaf(dip, leaf_no, bh_out); return error; @@ -976,7 +976,7 @@ static int dir_split_leaf(struct inode *inode, const struct qstr *name) index = name->hash >> (32 - dip->i_depth); error = get_leaf_nr(dip, index, &leaf_no); - if (error) + if (IS_ERR_VALUE(error)) return error; /* Get the old leaf block */ diff --git a/fs/mbcache.c b/fs/mbcache.c index 187477ded6b3..ab1da987d1ae 100644 --- a/fs/mbcache.c +++ b/fs/mbcache.c @@ -262,7 +262,6 @@ mb_cache_shrink_scan(struct shrinker *shrink, struct shrink_control *sc) list_del_init(&ce->e_lru_list); if (ce->e_used || ce->e_queued || atomic_read(&ce->e_refcnt)) continue; - spin_unlock(&mb_cache_spinlock); /* Prevent any find or get operation on the entry */ hlist_bl_lock(ce->e_block_hash_p); hlist_bl_lock(ce->e_index_hash_p); @@ -271,10 +270,10 @@ mb_cache_shrink_scan(struct shrinker *shrink, struct shrink_control *sc) !list_empty(&ce->e_lru_list)) { hlist_bl_unlock(ce->e_index_hash_p); hlist_bl_unlock(ce->e_block_hash_p); - spin_lock(&mb_cache_spinlock); continue; } __mb_cache_entry_unhash_unlock(ce); + spin_unlock(&mb_cache_spinlock); list_add_tail(&ce->e_lru_list, &free_list); spin_lock(&mb_cache_spinlock); } @@ -516,7 +515,6 @@ mb_cache_entry_alloc(struct mb_cache *cache, gfp_t gfp_flags) if (ce->e_used || ce->e_queued || atomic_read(&ce->e_refcnt)) continue; - spin_unlock(&mb_cache_spinlock); /* * Prevent any find or get operation on the * entry. @@ -530,13 +528,13 @@ mb_cache_entry_alloc(struct mb_cache *cache, gfp_t gfp_flags) hlist_bl_unlock(ce->e_index_hash_p); hlist_bl_unlock(ce->e_block_hash_p); l = &mb_cache_lru_list; - spin_lock(&mb_cache_spinlock); continue; } mb_assert(list_empty(&ce->e_lru_list)); mb_assert(!(ce->e_used || ce->e_queued || atomic_read(&ce->e_refcnt))); __mb_cache_entry_unhash_unlock(ce); + spin_unlock(&mb_cache_spinlock); goto found; } } @@ -670,6 +668,7 @@ mb_cache_entry_get(struct mb_cache *cache, struct block_device *bdev, cache->c_bucket_bits); block_hash_p = &cache->c_block_hash[bucket]; /* First serialize access to the block corresponding hash chain. */ + spin_lock(&mb_cache_spinlock); hlist_bl_lock(block_hash_p); hlist_bl_for_each_entry(ce, l, block_hash_p, e_block_list) { mb_assert(ce->e_block_hash_p == block_hash_p); @@ -678,9 +677,11 @@ mb_cache_entry_get(struct mb_cache *cache, struct block_device *bdev, * Prevent a free from removing the entry. */ atomic_inc(&ce->e_refcnt); + if (!list_empty(&ce->e_lru_list)) + list_del_init(&ce->e_lru_list); hlist_bl_unlock(block_hash_p); + spin_unlock(&mb_cache_spinlock); __spin_lock_mb_cache_entry(ce); - atomic_dec(&ce->e_refcnt); if (ce->e_used > 0) { DEFINE_WAIT(wait); while (ce->e_used > 0) { @@ -695,13 +696,9 @@ mb_cache_entry_get(struct mb_cache *cache, struct block_device *bdev, finish_wait(&mb_cache_queue, &wait); } ce->e_used += 1 + MB_CACHE_WRITER; + atomic_dec(&ce->e_refcnt); __spin_unlock_mb_cache_entry(ce); - if (!list_empty(&ce->e_lru_list)) { - spin_lock(&mb_cache_spinlock); - list_del_init(&ce->e_lru_list); - spin_unlock(&mb_cache_spinlock); - } if (!__mb_cache_entry_is_block_hashed(ce)) { __mb_cache_entry_release(ce); return NULL; @@ -710,6 +707,7 @@ mb_cache_entry_get(struct mb_cache *cache, struct block_device *bdev, } } hlist_bl_unlock(block_hash_p); + spin_unlock(&mb_cache_spinlock); return NULL; } diff --git a/fs/mount.h b/fs/mount.h index 3dc7dea5a357..13a4ebbbaa74 100644 --- a/fs/mount.h +++ b/fs/mount.h @@ -13,6 +13,8 @@ struct mnt_namespace { u64 seq; /* Sequence number to prevent loops */ wait_queue_head_t poll; u64 event; + unsigned int mounts; /* # of mounts in the namespace */ + unsigned int pending_mounts; }; struct mnt_pcp { diff --git a/fs/namespace.c b/fs/namespace.c index c1477882a853..a22959c97384 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -27,6 +27,9 @@ #include "pnode.h" #include "internal.h" +/* Maximum number of mounts in a mount namespace */ +unsigned int sysctl_mount_max __read_mostly = 100000; + static unsigned int m_hash_mask __read_mostly; static unsigned int m_hash_shift __read_mostly; static unsigned int mp_hash_mask __read_mostly; @@ -926,6 +929,9 @@ static void commit_tree(struct mount *mnt) list_splice(&head, n->list.prev); + n->mounts += n->pending_mounts; + n->pending_mounts = 0; + __attach_mnt(mnt, parent); touch_mnt_namespace(n); } @@ -1465,11 +1471,16 @@ static void umount_tree(struct mount *mnt, enum umount_tree_flags how) propagate_umount(&tmp_list); while (!list_empty(&tmp_list)) { + struct mnt_namespace *ns; bool disconnect; p = list_first_entry(&tmp_list, struct mount, mnt_list); list_del_init(&p->mnt_expire); list_del_init(&p->mnt_list); - __touch_mnt_namespace(p->mnt_ns); + ns = p->mnt_ns; + if (ns) { + ns->mounts--; + __touch_mnt_namespace(ns); + } p->mnt_ns = NULL; if (how & UMOUNT_SYNC) p->mnt.mnt_flags |= MNT_SYNC_UMOUNT; @@ -1870,6 +1881,28 @@ static int invent_group_ids(struct mount *mnt, bool recurse) return 0; } +int count_mounts(struct mnt_namespace *ns, struct mount *mnt) +{ + unsigned int max = READ_ONCE(sysctl_mount_max); + unsigned int mounts = 0, old, pending, sum; + struct mount *p; + + for (p = mnt; p; p = next_mnt(p, mnt)) + mounts++; + + old = ns->mounts; + pending = ns->pending_mounts; + sum = old + pending; + if ((old > sum) || + (pending > sum) || + (max < sum) || + (mounts > (max - sum))) + return -ENOSPC; + + ns->pending_mounts = pending + mounts; + return 0; +} + /* * @source_mnt : mount tree to be attached * @nd : place the mount tree @source_mnt is attached @@ -1939,6 +1972,7 @@ static int attach_recursive_mnt(struct mount *source_mnt, struct path *parent_path) { HLIST_HEAD(tree_list); + struct mnt_namespace *ns = dest_mnt->mnt_ns; struct mountpoint *smp; struct mount *child, *p; struct hlist_node *n; @@ -1951,6 +1985,13 @@ static int attach_recursive_mnt(struct mount *source_mnt, if (IS_ERR(smp)) return PTR_ERR(smp); + /* Is there space to add these mounts to the mount namespace? */ + if (!parent_path) { + err = count_mounts(ns, source_mnt); + if (err) + goto out; + } + if (IS_MNT_SHARED(dest_mnt)) { err = invent_group_ids(source_mnt, true); if (err) @@ -1990,11 +2031,14 @@ static int attach_recursive_mnt(struct mount *source_mnt, out_cleanup_ids: while (!hlist_empty(&tree_list)) { child = hlist_entry(tree_list.first, struct mount, mnt_hash); + child->mnt_parent->mnt_ns->pending_mounts = 0; umount_tree(child, UMOUNT_SYNC); } unlock_mount_hash(); cleanup_group_ids(source_mnt, NULL); out: + ns->pending_mounts = 0; + read_seqlock_excl(&mount_lock); put_mountpoint(smp); read_sequnlock_excl(&mount_lock); @@ -2830,6 +2874,8 @@ static struct mnt_namespace *alloc_mnt_ns(struct user_namespace *user_ns) init_waitqueue_head(&new_ns->poll); new_ns->event = 0; new_ns->user_ns = get_user_ns(user_ns); + new_ns->mounts = 0; + new_ns->pending_mounts = 0; return new_ns; } @@ -2879,6 +2925,7 @@ struct mnt_namespace *copy_mnt_ns(unsigned long flags, struct mnt_namespace *ns, q = new; while (p) { q->mnt_ns = new_ns; + new_ns->mounts++; if (new_fs) { if (&p->mnt == new_fs->root.mnt) { new_fs->root.mnt = mntget(&q->mnt); @@ -2917,6 +2964,7 @@ static struct mnt_namespace *create_mnt_ns(struct vfsmount *m) struct mount *mnt = real_mount(m); mnt->mnt_ns = new_ns; new_ns->root = mnt; + new_ns->mounts++; list_add(&mnt->mnt_list, &new_ns->list); } else { mntput(m); diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index ad4e2377dd63..5be1fa6b676d 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -656,6 +656,37 @@ static __be32 map_new_errors(u32 vers, __be32 nfserr) return nfserr; } +/* + * A write procedure can have a large argument, and a read procedure can + * have a large reply, but no NFSv2 or NFSv3 procedure has argument and + * reply that can both be larger than a page. The xdr code has taken + * advantage of this assumption to be a sloppy about bounds checking in + * some cases. Pending a rewrite of the NFSv2/v3 xdr code to fix that + * problem, we enforce these assumptions here: + */ +static bool nfs_request_too_big(struct svc_rqst *rqstp, + struct svc_procedure *proc) +{ + /* + * The ACL code has more careful bounds-checking and is not + * susceptible to this problem: + */ + if (rqstp->rq_prog != NFS_PROGRAM) + return false; + /* + * Ditto NFSv4 (which can in theory have argument and reply both + * more than a page): + */ + if (rqstp->rq_vers >= 4) + return false; + /* The reply will be small, we're OK: */ + if (proc->pc_xdrressize > 0 && + proc->pc_xdrressize < XDR_QUADLEN(PAGE_SIZE)) + return false; + + return rqstp->rq_arg.len > PAGE_SIZE; +} + int nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp) { @@ -668,6 +699,11 @@ nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp) rqstp->rq_vers, rqstp->rq_proc); proc = rqstp->rq_procinfo; + if (nfs_request_too_big(rqstp, proc)) { + dprintk("nfsd: NFSv%d argument too large\n", rqstp->rq_vers); + *statp = rpc_garbage_args; + return 1; + } /* * Give the xdr decoder a chance to change this if it wants * (necessary in the NFSv4.0 compound case) diff --git a/fs/pnode.c b/fs/pnode.c index 1d16bb3bdf5e..b5f97c605d98 100644 --- a/fs/pnode.c +++ b/fs/pnode.c @@ -259,7 +259,7 @@ static int propagate_one(struct mount *m) read_sequnlock_excl(&mount_lock); } hlist_add_head(&child->mnt_hash, list); - return 0; + return count_mounts(m->mnt_ns, child); } /* diff --git a/fs/pnode.h b/fs/pnode.h index f41fc9a6c48e..a9a6576540ad 100644 --- a/fs/pnode.h +++ b/fs/pnode.h @@ -55,4 +55,5 @@ void mnt_change_mountpoint(struct mount *parent, struct mountpoint *mp, struct mount *copy_tree(struct mount *, struct dentry *, int); bool is_path_reachable(struct mount *, struct dentry *, const struct path *root); +int count_mounts(struct mnt_namespace *ns, struct mount *mnt); #endif /* _LINUX_PNODE_H */ diff --git a/fs/sdcardfs/dentry.c b/fs/sdcardfs/dentry.c index 8e31d1a80f0c..7a19e77fce99 100644 --- a/fs/sdcardfs/dentry.c +++ b/fs/sdcardfs/dentry.c @@ -60,6 +60,14 @@ static int sdcardfs_d_revalidate(struct dentry *dentry, unsigned int flags) lower_dentry = lower_path.dentry; lower_cur_parent_dentry = dget_parent(lower_dentry); + if ((lower_dentry->d_flags & DCACHE_OP_REVALIDATE)) { + err = lower_dentry->d_op->d_revalidate(lower_dentry, flags); + if (err == 0) { + d_drop(dentry); + goto out; + } + } + spin_lock(&lower_dentry->d_lock); if (d_unhashed(lower_dentry)) { spin_unlock(&lower_dentry->d_lock); diff --git a/fs/sdcardfs/derived_perm.c b/fs/sdcardfs/derived_perm.c index cddfc79ea365..b4595aab5713 100644 --- a/fs/sdcardfs/derived_perm.c +++ b/fs/sdcardfs/derived_perm.c @@ -215,16 +215,16 @@ void fixup_lower_ownership(struct dentry *dentry, const char *name) gid = AID_MEDIA_OBB; break; case PERM_ANDROID_PACKAGE: - if (info->d_uid != 0) + if (uid_is_app(info->d_uid)) gid = multiuser_get_ext_gid(info->d_uid); else - gid = multiuser_get_uid(info->userid, uid); + gid = multiuser_get_uid(info->userid, AID_MEDIA_RW); break; case PERM_ANDROID_PACKAGE_CACHE: - if (info->d_uid != 0) + if (uid_is_app(info->d_uid)) gid = multiuser_get_ext_cache_gid(info->d_uid); else - gid = multiuser_get_uid(info->userid, uid); + gid = multiuser_get_uid(info->userid, AID_MEDIA_RW); break; case PERM_PRE_ROOT: default: diff --git a/fs/sdcardfs/file.c b/fs/sdcardfs/file.c index 1f6921e2ffbf..6076c342dae6 100644 --- a/fs/sdcardfs/file.c +++ b/fs/sdcardfs/file.c @@ -358,9 +358,12 @@ ssize_t sdcardfs_read_iter(struct kiocb *iocb, struct iov_iter *iter) get_file(lower_file); /* prevent lower_file from being released */ iocb->ki_filp = lower_file; err = lower_file->f_op->read_iter(iocb, iter); - /* ? wait IO finish to update atime as ecryptfs ? */ iocb->ki_filp = file; fput(lower_file); + /* update upper inode atime as needed */ + if (err >= 0 || err == -EIOCBQUEUED) + fsstack_copy_attr_atime(file->f_path.dentry->d_inode, + file_inode(lower_file)); out: return err; } @@ -384,6 +387,13 @@ ssize_t sdcardfs_write_iter(struct kiocb *iocb, struct iov_iter *iter) err = lower_file->f_op->write_iter(iocb, iter); iocb->ki_filp = file; fput(lower_file); + /* update upper inode times/sizes as needed */ + if (err >= 0 || err == -EIOCBQUEUED) { + fsstack_copy_inode_size(file->f_path.dentry->d_inode, + file_inode(lower_file)); + fsstack_copy_attr_times(file->f_path.dentry->d_inode, + file_inode(lower_file)); + } out: return err; } diff --git a/fs/sdcardfs/lookup.c b/fs/sdcardfs/lookup.c index a0f221501b4c..509d5fbcb472 100644 --- a/fs/sdcardfs/lookup.c +++ b/fs/sdcardfs/lookup.c @@ -366,19 +366,22 @@ put_name: /* instatiate a new negative dentry */ dname.name = name->name; dname.len = name->len; - dname.hash = full_name_hash(dname.name, dname.len); - lower_dentry = d_lookup(lower_dir_dentry, &dname); - if (lower_dentry) - goto setup_lower; - lower_dentry = d_alloc(lower_dir_dentry, &dname); + /* See if the low-level filesystem might want + * to use its own hash + */ + lower_dentry = d_hash_and_lookup(lower_dir_dentry, &dname); + if (IS_ERR(lower_dentry)) + return lower_dentry; if (!lower_dentry) { - err = -ENOMEM; + /* We called vfs_path_lookup earlier, and did not get a negative + * dentry then. Don't confuse the lower filesystem by forcing + * one on it now... + */ + err = -ENOENT; goto out; } - d_add(lower_dentry, NULL); /* instantiate and hash */ -setup_lower: lower_path.dentry = lower_dentry; lower_path.mnt = mntget(lower_dir_mnt); sdcardfs_set_lower_path(dentry, &lower_path); diff --git a/fs/sdcardfs/multiuser.h b/fs/sdcardfs/multiuser.h index d0c925cda299..85341e753f8c 100644 --- a/fs/sdcardfs/multiuser.h +++ b/fs/sdcardfs/multiuser.h @@ -35,6 +35,13 @@ static inline uid_t multiuser_get_uid(userid_t user_id, appid_t app_id) return (user_id * AID_USER_OFFSET) + (app_id % AID_USER_OFFSET); } +static inline bool uid_is_app(uid_t uid) +{ + appid_t appid = uid % AID_USER_OFFSET; + + return appid >= AID_APP_START && appid <= AID_APP_END; +} + static inline gid_t multiuser_get_ext_cache_gid(uid_t uid) { return uid - AID_APP_START + AID_EXT_CACHE_GID_START; diff --git a/include/linux/iommu.h b/include/linux/iommu.h index 55ae8b928411..2767fcdec5a1 100644 --- a/include/linux/iommu.h +++ b/include/linux/iommu.h @@ -235,6 +235,8 @@ struct iommu_ops { void (*tlbi_domain)(struct iommu_domain *domain); int (*enable_config_clocks)(struct iommu_domain *domain); void (*disable_config_clocks)(struct iommu_domain *domain); + uint64_t (*iova_to_pte)(struct iommu_domain *domain, + dma_addr_t iova); #ifdef CONFIG_OF_IOMMU int (*of_xlate)(struct device *dev, struct of_phandle_args *args); @@ -334,6 +336,9 @@ extern int iommu_domain_window_enable(struct iommu_domain *domain, u32 wnd_nr, phys_addr_t offset, u64 size, int prot); extern void iommu_domain_window_disable(struct iommu_domain *domain, u32 wnd_nr); + +extern uint64_t iommu_iova_to_pte(struct iommu_domain *domain, + dma_addr_t iova); /** * report_iommu_fault() - report about an IOMMU fault to the IOMMU framework * @domain: the iommu domain where the fault has happened diff --git a/include/linux/mount.h b/include/linux/mount.h index 0e9b0977237a..b606d8f57adf 100644 --- a/include/linux/mount.h +++ b/include/linux/mount.h @@ -96,4 +96,6 @@ extern void mark_mounts_for_expiry(struct list_head *mounts); extern dev_t name_to_dev_t(const char *name); +extern unsigned int sysctl_mount_max; + #endif /* _LINUX_MOUNT_H */ diff --git a/include/linux/msm_ext_display.h b/include/linux/msm_ext_display.h index fc53e861eba4..9a03b79e09d7 100644 --- a/include/linux/msm_ext_display.h +++ b/include/linux/msm_ext_display.h @@ -114,6 +114,7 @@ struct msm_ext_disp_intf_ops { * @cable_status: cable connected/disconnected * @get_intf_id: id of connected interface * @acknowledge: acknowledge audio status + * @codec_ready: notify when codec is ready */ struct msm_ext_disp_audio_codec_ops { int (*audio_info_setup)(struct platform_device *pdev, @@ -124,6 +125,7 @@ struct msm_ext_disp_audio_codec_ops { int (*get_intf_id)(struct platform_device *pdev); void (*teardown_done)(struct platform_device *pdev); int (*acknowledge)(struct platform_device *pdev, u32 ack); + void (*codec_ready)(struct platform_device *pdev); }; /* diff --git a/include/linux/regulator/onsemi-ncp6335d.h b/include/linux/regulator/onsemi-ncp6335d.h new file mode 100644 index 000000000000..399742f7e2ac --- /dev/null +++ b/include/linux/regulator/onsemi-ncp6335d.h @@ -0,0 +1,35 @@ +/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __NCP6335D_H__ +#define __NCP6335D_H__ + +enum { + NCP6335D_VSEL0, + NCP6335D_VSEL1, +}; + +struct ncp6335d_platform_data { + struct regulator_init_data *init_data; + int default_vsel; + int slew_rate_ns; + int discharge_enable; + bool sleep_enable; +}; + +#ifdef CONFIG_REGULATOR_ONSEMI_NCP6335D +int __init ncp6335d_regulator_init(void); +#else +static inline int __init ncp6335d_regulator_init(void) { return 0; } +#endif + +#endif diff --git a/include/soc/qcom/minidump.h b/include/soc/qcom/minidump.h index 9d993a17fb89..2db61a40e2cc 100644 --- a/include/soc/qcom/minidump.h +++ b/include/soc/qcom/minidump.h @@ -37,7 +37,7 @@ struct md_region { */ #ifdef CONFIG_QCOM_MINIDUMP extern int msm_minidump_add_region(const struct md_region *entry); -extern bool msm_minidump_enabled(void); +extern bool minidump_enabled; #else static inline int msm_minidump_add_region(const struct md_region *entry) { diff --git a/include/soc/qcom/profiler.h b/include/soc/qcom/profiler.h index c53b510fc149..ffcf6ec91187 100644 --- a/include/soc/qcom/profiler.h +++ b/include/soc/qcom/profiler.h @@ -17,15 +17,15 @@ struct profiler_bw_cntrs_req { uint32_t total; - uint32_t gpu; uint32_t cpu; + uint32_t gpu; uint32_t cmd; }; struct compat_profiler_bw_cntrs_req { compat_uint_t total; - compat_uint_t gpu; compat_uint_t cpu; + compat_uint_t gpu; compat_uint_t cmd; }; diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h index bcb53faaf678..40cd9a752c53 100644 --- a/include/sound/apr_audio-v2.h +++ b/include/sound/apr_audio-v2.h @@ -15,6 +15,7 @@ #define _APR_AUDIO_V2_H_ #include <linux/qdsp6v2/apr.h> +#include <linux/msm_audio.h> /* size of header needed for passing data out of band */ #define APR_CMD_OB_HDR_SZ 12 @@ -447,6 +448,18 @@ struct adm_param_data_v5 { #define ASM_STREAM_PP_EVENT 0x00013214 #define DSP_STREAM_CMD "ADSP Stream Cmd" #define DSP_STREAM_CALLBACK "ADSP Stream Callback Event" +#define DSP_STREAM_CALLBACK_QUEUE_SIZE 1024 + +struct dsp_stream_callback_list { + struct list_head list; + struct msm_adsp_event_data event; +}; + +struct dsp_stream_callback_prtd { + uint16_t event_count; + struct list_head event_queue; + spinlock_t prtd_spin_lock; +}; /* set customized mixing on matrix mixer */ #define ADM_CMD_SET_PSPD_MTMX_STRTR_PARAMS_V5 0x00010344 @@ -10320,10 +10333,33 @@ struct asm_session_mtmx_strtr_param_clk_rec_t { u32 flags; } __packed; + +/* Parameter used by #ASM_SESSION_MTMX_STRTR_MODULE_ID_AVSYNC to + * realize smoother adjustment of audio session clock for a specified session. + * The desired audio session clock adjustment(in micro seconds) is specified + * using the command #ASM_SESSION_CMD_ADJUST_SESSION_CLOCK_V2. + * Delaying/Advancing the session clock would be implemented by inserting + * interpolated/dropping audio samples in the playback path respectively. + * Also, this parameter has to be configured before the Audio Session is put + * to RUN state to avoid cold start latency/glitches in the playback. + */ + +#define ASM_SESSION_MTMX_PARAM_ADJUST_SESSION_TIME_CTL 0x00013217 + +struct asm_session_mtmx_param_adjust_session_time_ctl_t { + /* Specifies whether the module is enabled or not + * @values + * 0 -- disabled + * 1 -- enabled + */ + u32 enable; +}; + union asm_session_mtmx_strtr_param_config { struct asm_session_mtmx_strtr_param_window_v2_t window_param; struct asm_session_mtmx_strtr_param_render_mode_t render_param; struct asm_session_mtmx_strtr_param_clk_rec_t clk_rec_param; + struct asm_session_mtmx_param_adjust_session_time_ctl_t adj_time_param; } __packed; struct asm_mtmx_strtr_params { diff --git a/include/sound/q6asm-v2.h b/include/sound/q6asm-v2.h index 41fcdeb50831..b2bb8d493839 100644 --- a/include/sound/q6asm-v2.h +++ b/include/sound/q6asm-v2.h @@ -655,6 +655,10 @@ int q6asm_send_mtmx_strtr_render_mode(struct audio_client *ac, int q6asm_send_mtmx_strtr_clk_rec_mode(struct audio_client *ac, uint32_t clk_rec_mode); +/* Enable adjust session clock in DSP */ +int q6asm_send_mtmx_strtr_enable_adjust_session_clock(struct audio_client *ac, + bool enable); + /* Retrieve the current DSP path delay */ int q6asm_get_path_delay(struct audio_client *ac); @@ -662,4 +666,8 @@ int q6asm_get_path_delay(struct audio_client *ac); uint8_t q6asm_get_buf_index_from_token(uint32_t token); uint8_t q6asm_get_stream_id_from_token(uint32_t token); +/* Adjust session clock in DSP */ +int q6asm_adjust_session_clock(struct audio_client *ac, + uint32_t adjust_time_lsw, + uint32_t adjust_time_msw); #endif /* __Q6_ASM_H__ */ diff --git a/include/uapi/drm/drm.h b/include/uapi/drm/drm.h index 3801584a0c53..24c76d138317 100644 --- a/include/uapi/drm/drm.h +++ b/include/uapi/drm/drm.h @@ -58,6 +58,10 @@ typedef unsigned long drm_handle_t; #endif +#if defined(__cplusplus) +extern "C" { +#endif + #define DRM_NAME "drm" /**< Name in kernel, /dev, and /proc */ #define DRM_MIN_ORDER 5 /**< At least 2^5 bytes = 32 bytes */ #define DRM_MAX_ORDER 22 /**< Up to 2^22 bytes = 4MB */ @@ -372,7 +376,11 @@ struct drm_buf_pub { */ struct drm_buf_map { int count; /**< Length of the buffer list */ +#ifdef __cplusplus + void __user *virt; +#else void __user *virtual; /**< Mmap'd area in user-virtual */ +#endif struct drm_buf_pub __user *list; /**< Buffer information */ }; @@ -679,7 +687,15 @@ struct drm_prime_handle { __s32 fd; }; -#include <drm/drm_mode.h> +#if defined(__cplusplus) +} +#endif + +#include "drm_mode.h" + +#if defined(__cplusplus) +extern "C" { +#endif #define DRM_IOCTL_BASE 'd' #define DRM_IO(nr) _IO(DRM_IOCTL_BASE,nr) @@ -874,4 +890,8 @@ typedef struct drm_scatter_gather drm_scatter_gather_t; typedef struct drm_set_version drm_set_version_t; #endif +#if defined(__cplusplus) +} +#endif + #endif diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h index 53d7c80f5eb0..7f203a5f83cb 100644 --- a/include/uapi/drm/drm_fourcc.h +++ b/include/uapi/drm/drm_fourcc.h @@ -26,6 +26,10 @@ #include <linux/types.h> +#if defined(__cplusplus) +extern "C" { +#endif + #define fourcc_code(a, b, c, d) ((__u32)(a) | ((__u32)(b) << 8) | \ ((__u32)(c) << 16) | ((__u32)(d) << 24)) @@ -237,4 +241,8 @@ */ #define DRM_FORMAT_MOD_QCOM_COMPRESSED fourcc_mod_code(QCOM, 1) +#if defined(__cplusplus) +} +#endif + #endif /* DRM_FOURCC_H */ diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h index 1c5e74f1ea39..0630e0f64b9c 100644 --- a/include/uapi/drm/drm_mode.h +++ b/include/uapi/drm/drm_mode.h @@ -29,6 +29,10 @@ #include <linux/types.h> +#if defined(__cplusplus) +extern "C" { +#endif + #define DRM_DISPLAY_INFO_LEN 32 #define DRM_CONNECTOR_NAME_LEN 32 #define DRM_DISPLAY_MODE_LEN 32 @@ -599,4 +603,8 @@ struct drm_mode_destroy_blob { __u32 blob_id; }; +#if defined(__cplusplus) +} +#endif + #endif diff --git a/include/uapi/drm/drm_sarea.h b/include/uapi/drm/drm_sarea.h index 413a5642d49f..12285bc929a1 100644 --- a/include/uapi/drm/drm_sarea.h +++ b/include/uapi/drm/drm_sarea.h @@ -34,6 +34,10 @@ #include <drm/drm.h> +#if defined(__cplusplus) +extern "C" { +#endif + /* SAREA area needs to be at least a page */ #if defined(__alpha__) #define SAREA_MAX 0x2000U @@ -83,4 +87,8 @@ typedef struct drm_sarea_frame drm_sarea_frame_t; typedef struct drm_sarea drm_sarea_t; #endif +#if defined(__cplusplus) +} +#endif + #endif /* _DRM_SAREA_H_ */ diff --git a/include/uapi/linux/ipv6_route.h b/include/uapi/linux/ipv6_route.h index f6598d1c886e..316e838b7470 100644 --- a/include/uapi/linux/ipv6_route.h +++ b/include/uapi/linux/ipv6_route.h @@ -34,7 +34,7 @@ #define RTF_PREF(pref) ((pref) << 27) #define RTF_PREF_MASK 0x18000000 -#define RTF_PCPU 0x40000000 +#define RTF_PCPU 0x40000000 /* read-only: can not be set by user */ #define RTF_LOCAL 0x80000000 diff --git a/include/uapi/linux/msm_audio.h b/include/uapi/linux/msm_audio.h index 36b66c7cde76..f306949eb5e6 100644 --- a/include/uapi/linux/msm_audio.h +++ b/include/uapi/linux/msm_audio.h @@ -460,4 +460,14 @@ struct msm_hwacc_effects_config { __s32 topology; }; +#define ADSP_STREAM_PP_EVENT 0 +#define ADSP_STREAM_ENCDEC_EVENT 1 +#define ADSP_STREAM_EVENT_MAX 2 + +struct msm_adsp_event_data { + __u32 event_type; + __u32 payload_len; + __u8 payload[0]; +}; + #endif diff --git a/include/uapi/linux/msm_ipa.h b/include/uapi/linux/msm_ipa.h index 16e4b8e30b07..51569b7e7aa0 100644 --- a/include/uapi/linux/msm_ipa.h +++ b/include/uapi/linux/msm_ipa.h @@ -394,10 +394,20 @@ enum ipa_tethering_stats_event { IPA_TETHERING_STATS_UPDATE_STATS = IPA_ECM_EVENT_MAX, IPA_TETHERING_STATS_UPDATE_NETWORK_STATS, IPA_TETHERING_STATS_EVENT_MAX, - IPA_EVENT_MAX_NUM = IPA_TETHERING_STATS_EVENT_MAX }; -#define IPA_EVENT_MAX ((int)IPA_EVENT_MAX_NUM) +enum ipa_quota_event { + IPA_QUOTA_REACH = IPA_TETHERING_STATS_EVENT_MAX, + IPA_QUOTA_EVENT_MAX, +}; + +enum ipa_ssr_event { + IPA_SSR_BEFORE_SHUTDOWN = IPA_QUOTA_EVENT_MAX, + IPA_SSR_AFTER_POWERUP, + IPA_SSR_EVENT_MAX +}; + +#define IPA_EVENT_MAX_NUM ((int)IPA_SSR_EVENT_MAX) /** * enum ipa_rm_resource_name - IPA RM clients identification names diff --git a/include/uapi/linux/msm_mdp_ext.h b/include/uapi/linux/msm_mdp_ext.h index 35029f227f8b..da9ee3bcc525 100644 --- a/include/uapi/linux/msm_mdp_ext.h +++ b/include/uapi/linux/msm_mdp_ext.h @@ -178,6 +178,12 @@ VALIDATE/COMMIT FLAG CONFIGURATION */ #define MDP_COMMIT_CWB_DSPP 0x1000 +/* + * Flag to indicate that rectangle number is being assigned + * by userspace in multi-rectangle mode + */ +#define MDP_COMMIT_RECT_NUM 0x2000 + #define MDP_COMMIT_VERSION_1_0 0x00010000 #define OUT_LAYER_COLOR_SPACE @@ -425,8 +431,14 @@ struct mdp_input_layer { */ int error_code; + /* + * For source pipes supporting multi-rectangle, this field identifies + * the rectangle index of the source pipe. + */ + uint32_t rect_num; + /* 32bits reserved value for future usage. */ - uint32_t reserved[6]; + uint32_t reserved[5]; }; struct mdp_output_layer { diff --git a/include/uapi/linux/rmnet_ipa_fd_ioctl.h b/include/uapi/linux/rmnet_ipa_fd_ioctl.h index 228bfe8274c6..f04ac495a5c0 100644 --- a/include/uapi/linux/rmnet_ipa_fd_ioctl.h +++ b/include/uapi/linux/rmnet_ipa_fd_ioctl.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -32,6 +32,7 @@ #define WAN_IOCTL_RESET_TETHER_STATS 7 #define WAN_IOCTL_QUERY_DL_FILTER_STATS 8 #define WAN_IOCTL_ADD_FLT_RULE_EX 9 +#define WAN_IOCTL_QUERY_TETHER_STATS_ALL 10 /* User space may not have this defined. */ #ifndef IFNAMSIZ @@ -99,6 +100,16 @@ struct wan_ioctl_query_tether_stats { uint64_t ipv6_rx_bytes; }; +struct wan_ioctl_query_tether_stats_all { + /* Name of the upstream interface */ + char upstreamIface[IFNAMSIZ]; + /* enum of tether interface */ + enum ipacm_client_enum ipa_client; + uint8_t reset_stats; + uint64_t tx_bytes; + uint64_t rx_bytes; +}; + struct wan_ioctl_reset_tether_stats { /* Name of the upstream interface, not support now */ char upstreamIface[IFNAMSIZ]; @@ -155,4 +166,8 @@ struct wan_ioctl_query_dl_filter_stats { WAN_IOCTL_ADD_FLT_RULE_EX, \ struct ipa_install_fltr_rule_req_ex_msg_v01 *) +#define WAN_IOC_QUERY_TETHER_STATS_ALL _IOWR(WAN_IOC_MAGIC, \ + WAN_IOCTL_QUERY_TETHER_STATS_ALL, \ + struct wan_ioctl_query_tether_stats_all *) + #endif /* _RMNET_IPA_FD_IOCTL_H */ diff --git a/include/uapi/media/msmb_ispif.h b/include/uapi/media/msmb_ispif.h index c3a6e006b2ff..d532037427cc 100644 --- a/include/uapi/media/msmb_ispif.h +++ b/include/uapi/media/msmb_ispif.h @@ -112,6 +112,7 @@ struct msm_ispif_param_data_ext { struct msm_ispif_pack_cfg pack_cfg[CID_MAX]; struct msm_ispif_right_param_entry right_entries[MAX_PARAM_ENTRIES]; uint32_t stereo_enable; + uint16_t line_width[VFE_MAX]; }; struct msm_ispif_param_data { @@ -143,6 +144,7 @@ enum ispif_cfg_type_t { ISPIF_ENABLE_REG_DUMP, ISPIF_SET_VFE_INFO, ISPIF_CFG2, + ISPIF_CFG_STEREO, }; struct ispif_cfg_data { @@ -165,6 +167,8 @@ struct ispif_cfg_data_ext { #define ISPIF_3D_SUPPORT 1 +#define ISPIF_LINE_WIDTH_SUPPORT 1 + #define VIDIOC_MSM_ISPIF_CFG \ _IOWR('V', BASE_VIDIOC_PRIVATE, struct ispif_cfg_data) diff --git a/include/uapi/sound/compress_offload.h b/include/uapi/sound/compress_offload.h index 30481056cce1..866ec3d2af69 100644 --- a/include/uapi/sound/compress_offload.h +++ b/include/uapi/sound/compress_offload.h @@ -149,6 +149,8 @@ struct snd_compr_audio_info { * @SNDRV_COMPRESS_CLK_REC_MODE: clock recovery mode ( none or auto) * @SNDRV_COMPRESS_RENDER_WINDOW: render window * @SNDRV_COMPRESS_START_DELAY: start delay + * @SNDRV_COMPRESS_ENABLE_ADJUST_SESSION_CLOCK: enable dsp drift correction + * @SNDRV_COMPRESS_ADJUST_SESSION_CLOCK: set drift correction value */ enum sndrv_compress_encoder { SNDRV_COMPRESS_ENCODER_PADDING = 1, @@ -160,6 +162,8 @@ enum sndrv_compress_encoder { SNDRV_COMPRESS_CLK_REC_MODE = 7, SNDRV_COMPRESS_RENDER_WINDOW = 8, SNDRV_COMPRESS_START_DELAY = 9, + SNDRV_COMPRESS_ENABLE_ADJUST_SESSION_CLOCK = 10, + SNDRV_COMPRESS_ADJUST_SESSION_CLOCK = 11, }; #define SNDRV_COMPRESS_PATH_DELAY SNDRV_COMPRESS_PATH_DELAY @@ -167,6 +171,9 @@ enum sndrv_compress_encoder { #define SNDRV_COMPRESS_CLK_REC_MODE SNDRV_COMPRESS_CLK_REC_MODE #define SNDRV_COMPRESS_RENDER_WINDOW SNDRV_COMPRESS_RENDER_WINDOW #define SNDRV_COMPRESS_START_DELAY SNDRV_COMPRESS_START_DELAY +#define SNDRV_COMPRESS_ENABLE_ADJUST_SESSION_CLOCK \ + SNDRV_COMPRESS_ENABLE_ADJUST_SESSION_CLOCK +#define SNDRV_COMPRESS_ADJUST_SESSION_CLOCK SNDRV_COMPRESS_ADJUST_SESSION_CLOCK /** * struct snd_compr_metadata - compressed stream metadata diff --git a/kernel/cgroup.c b/kernel/cgroup.c index b52f88e44182..25cf44889559 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -2693,7 +2693,7 @@ static int cgroup_procs_write_permission(struct task_struct *task, if (!uid_eq(cred->euid, GLOBAL_ROOT_UID) && !uid_eq(cred->euid, tcred->uid) && !uid_eq(cred->euid, tcred->suid) && - !ns_capable(tcred->user_ns, CAP_SYS_RESOURCE)) + !ns_capable(tcred->user_ns, CAP_SYS_NICE)) ret = -EACCES; if (!ret && cgroup_on_dfl(dst_cgrp)) { diff --git a/kernel/events/core.c b/kernel/events/core.c index 06db8b64129d..95c447e658f7 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -8454,6 +8454,37 @@ static int perf_event_set_clock(struct perf_event *event, clockid_t clk_id) return 0; } +/* + * Variation on perf_event_ctx_lock_nested(), except we take two context + * mutexes. + */ +static struct perf_event_context * +__perf_event_ctx_lock_double(struct perf_event *group_leader, + struct perf_event_context *ctx) +{ + struct perf_event_context *gctx; + +again: + rcu_read_lock(); + gctx = READ_ONCE(group_leader->ctx); + if (!atomic_inc_not_zero(&gctx->refcount)) { + rcu_read_unlock(); + goto again; + } + rcu_read_unlock(); + + mutex_lock_double(&gctx->mutex, &ctx->mutex); + + if (group_leader->ctx != gctx) { + mutex_unlock(&ctx->mutex); + mutex_unlock(&gctx->mutex); + put_ctx(gctx); + goto again; + } + + return gctx; +} + /** * sys_perf_event_open - open a performance event, associate it to a task/cpu * @@ -8707,8 +8738,26 @@ SYSCALL_DEFINE5(perf_event_open, } if (move_group) { - gctx = group_leader->ctx; - mutex_lock_double(&gctx->mutex, &ctx->mutex); + gctx = __perf_event_ctx_lock_double(group_leader, ctx); + + /* + * Check if we raced against another sys_perf_event_open() call + * moving the software group underneath us. + */ + if (!(group_leader->group_flags & PERF_GROUP_SOFTWARE)) { + /* + * If someone moved the group out from under us, check + * if this new event wound up on the same ctx, if so + * its the regular !move_group case, otherwise fail. + */ + if (gctx != ctx) { + err = -EINVAL; + goto err_locked; + } else { + perf_event_ctx_unlock(group_leader, gctx); + move_group = 0; + } + } } else { mutex_lock(&ctx->mutex); } @@ -8803,7 +8852,7 @@ SYSCALL_DEFINE5(perf_event_open, perf_unpin_context(ctx); if (move_group) - mutex_unlock(&gctx->mutex); + perf_event_ctx_unlock(group_leader, gctx); mutex_unlock(&ctx->mutex); if (group_leader) mutex_unlock(&group_leader->group_leader_mutex); @@ -8833,7 +8882,7 @@ SYSCALL_DEFINE5(perf_event_open, err_locked: if (move_group) - mutex_unlock(&gctx->mutex); + perf_event_ctx_unlock(group_leader, gctx); mutex_unlock(&ctx->mutex); /* err_file: */ fput(event_file); diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 8cc5167e4b04..816999804a16 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -65,6 +65,7 @@ #include <linux/sched/sysctl.h> #include <linux/kexec.h> #include <linux/bpf.h> +#include <linux/mount.h> #include <asm/uaccess.h> #include <asm/processor.h> @@ -2077,6 +2078,14 @@ static struct ctl_table fs_table[] = { .mode = 0644, .proc_handler = proc_doulongvec_minmax, }, + { + .procname = "mount-max", + .data = &sysctl_mount_max, + .maxlen = sizeof(unsigned int), + .mode = 0644, + .proc_handler = proc_dointvec_minmax, + .extra1 = &one, + }, { } }; diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index 7d7f99b0db47..1275175b0946 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c @@ -3440,11 +3440,23 @@ EXPORT_SYMBOL_GPL(ring_buffer_iter_reset); int ring_buffer_iter_empty(struct ring_buffer_iter *iter) { struct ring_buffer_per_cpu *cpu_buffer; + struct buffer_page *reader; + struct buffer_page *head_page; + struct buffer_page *commit_page; + unsigned commit; cpu_buffer = iter->cpu_buffer; - return iter->head_page == cpu_buffer->commit_page && - iter->head == rb_commit_index(cpu_buffer); + /* Remember, trace recording is off when iterator is in use */ + reader = cpu_buffer->reader_page; + head_page = cpu_buffer->head_page; + commit_page = cpu_buffer->commit_page; + commit = rb_page_commit(commit_page); + + return ((iter->head_page == commit_page && iter->head == commit) || + (iter->head_page == reader && commit_page == head_page && + head_page->read == commit && + iter->head == rb_page_commit(cpu_buffer->reader_page))); } EXPORT_SYMBOL_GPL(ring_buffer_iter_empty); diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index c0c10a335b3b..60d246c4eefa 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -6170,11 +6170,13 @@ ftrace_trace_snapshot_callback(struct ftrace_hash *hash, return ret; out_reg: - ret = register_ftrace_function_probe(glob, ops, count); + ret = alloc_snapshot(&global_trace); + if (ret < 0) + goto out; - if (ret >= 0) - alloc_snapshot(&global_trace); + ret = register_ftrace_function_probe(glob, ops, count); + out: return ret < 0 ? ret : 0; } diff --git a/net/9p/client.c b/net/9p/client.c index ea79ee9a7348..f5feac4ff4ec 100644 --- a/net/9p/client.c +++ b/net/9p/client.c @@ -2101,6 +2101,10 @@ int p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset) trace_9p_protocol_dump(clnt, req->rc); goto free_and_error; } + if (rsize < count) { + pr_err("bogus RREADDIR count (%d > %d)\n", count, rsize); + count = rsize; + } p9_debug(P9_DEBUG_9P, "<<< RREADDIR count %d\n", count); diff --git a/net/core/neighbour.c b/net/core/neighbour.c index f1e575d7f21a..54ab748238d1 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -859,7 +859,8 @@ static void neigh_probe(struct neighbour *neigh) if (skb) skb = skb_clone(skb, GFP_ATOMIC); write_unlock(&neigh->lock); - neigh->ops->solicit(neigh, skb); + if (neigh->ops->solicit) + neigh->ops->solicit(neigh, skb); atomic_inc(&neigh->probes); kfree_skb(skb); } diff --git a/net/core/netpoll.c b/net/core/netpoll.c index 94acfc89ad97..440aa9f6e0a8 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -105,15 +105,21 @@ static void queue_process(struct work_struct *work) while ((skb = skb_dequeue(&npinfo->txq))) { struct net_device *dev = skb->dev; struct netdev_queue *txq; + unsigned int q_index; if (!netif_device_present(dev) || !netif_running(dev)) { kfree_skb(skb); continue; } - txq = skb_get_tx_queue(dev, skb); - local_irq_save(flags); + /* check if skb->queue_mapping is still valid */ + q_index = skb_get_queue_mapping(skb); + if (unlikely(q_index >= dev->real_num_tx_queues)) { + q_index = q_index % dev->real_num_tx_queues; + skb_set_queue_mapping(skb, q_index); + } + txq = netdev_get_tx_queue(dev, q_index); HARD_TX_LOCK(dev, txq, smp_processor_id()); if (netif_xmit_frozen_or_stopped(txq) || netpoll_start_xmit(skb, dev, txq) != NETDEV_TX_OK) { diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c index 3a2b21e22629..72e1e831589a 100644 --- a/net/ipv4/ping.c +++ b/net/ipv4/ping.c @@ -154,17 +154,18 @@ void ping_hash(struct sock *sk) void ping_unhash(struct sock *sk) { struct inet_sock *isk = inet_sk(sk); + pr_debug("ping_unhash(isk=%p,isk->num=%u)\n", isk, isk->inet_num); + write_lock_bh(&ping_table.lock); if (sk_hashed(sk)) { - write_lock_bh(&ping_table.lock); hlist_nulls_del(&sk->sk_nulls_node); sk_nulls_node_init(&sk->sk_nulls_node); sock_put(sk); isk->inet_num = 0; isk->inet_sport = 0; sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); - write_unlock_bh(&ping_table.lock); } + write_unlock_bh(&ping_table.lock); } EXPORT_SYMBOL_GPL(ping_unhash); diff --git a/net/ipv4/route.c b/net/ipv4/route.c index d162ce41f761..7e31491e9396 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -2571,7 +2571,7 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh) skb_reset_network_header(skb); /* Bugfix: need to give ip_route_input enough of an IP header to not gag. */ - ip_hdr(skb)->protocol = IPPROTO_ICMP; + ip_hdr(skb)->protocol = IPPROTO_UDP; skb_reserve(skb, MAX_HEADER + sizeof(struct iphdr)); src = tb[RTA_SRC] ? nla_get_in_addr(tb[RTA_SRC]) : 0; diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 4ab7735e43ab..62815497f29c 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -2269,6 +2269,7 @@ int tcp_disconnect(struct sock *sk, int flags) tcp_init_send_head(sk); memset(&tp->rx_opt, 0, sizeof(tp->rx_opt)); __sk_dst_reset(sk); + tcp_saved_syn_free(tp); WARN_ON(inet->inet_num && !icsk->icsk_bind_hash); diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index 8b11a49c7dd7..600975c5eacf 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -1049,7 +1049,7 @@ static int ip6_tnl_xmit2(struct sk_buff *skb, struct ip6_tnl *t = netdev_priv(dev); struct net *net = t->net; struct net_device_stats *stats = &t->dev->stats; - struct ipv6hdr *ipv6h = ipv6_hdr(skb); + struct ipv6hdr *ipv6h; struct ipv6_tel_txoption opt; struct dst_entry *dst = NULL, *ndst = NULL; struct net_device *tdev; @@ -1061,26 +1061,28 @@ static int ip6_tnl_xmit2(struct sk_buff *skb, /* NBMA tunnel */ if (ipv6_addr_any(&t->parms.raddr)) { - struct in6_addr *addr6; - struct neighbour *neigh; - int addr_type; + if (skb->protocol == htons(ETH_P_IPV6)) { + struct in6_addr *addr6; + struct neighbour *neigh; + int addr_type; - if (!skb_dst(skb)) - goto tx_err_link_failure; + if (!skb_dst(skb)) + goto tx_err_link_failure; - neigh = dst_neigh_lookup(skb_dst(skb), - &ipv6_hdr(skb)->daddr); - if (!neigh) - goto tx_err_link_failure; + neigh = dst_neigh_lookup(skb_dst(skb), + &ipv6_hdr(skb)->daddr); + if (!neigh) + goto tx_err_link_failure; - addr6 = (struct in6_addr *)&neigh->primary_key; - addr_type = ipv6_addr_type(addr6); + addr6 = (struct in6_addr *)&neigh->primary_key; + addr_type = ipv6_addr_type(addr6); - if (addr_type == IPV6_ADDR_ANY) - addr6 = &ipv6_hdr(skb)->daddr; + if (addr_type == IPV6_ADDR_ANY) + addr6 = &ipv6_hdr(skb)->daddr; - memcpy(&fl6->daddr, addr6, sizeof(fl6->daddr)); - neigh_release(neigh); + memcpy(&fl6->daddr, addr6, sizeof(fl6->daddr)); + neigh_release(neigh); + } } else if (!(t->parms.flags & (IP6_TNL_F_USE_ORIG_TCLASS | IP6_TNL_F_USE_ORIG_FWMARK))) { /* enable the cache only only if the routing decision does diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index d9843e5a667f..8361d73ab653 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c @@ -774,7 +774,8 @@ failure: * Delete a VIF entry */ -static int mif6_delete(struct mr6_table *mrt, int vifi, struct list_head *head) +static int mif6_delete(struct mr6_table *mrt, int vifi, int notify, + struct list_head *head) { struct mif_device *v; struct net_device *dev; @@ -820,7 +821,7 @@ static int mif6_delete(struct mr6_table *mrt, int vifi, struct list_head *head) dev->ifindex, &in6_dev->cnf); } - if (v->flags & MIFF_REGISTER) + if ((v->flags & MIFF_REGISTER) && !notify) unregister_netdevice_queue(dev, head); dev_put(dev); @@ -1330,7 +1331,6 @@ static int ip6mr_device_event(struct notifier_block *this, struct mr6_table *mrt; struct mif_device *v; int ct; - LIST_HEAD(list); if (event != NETDEV_UNREGISTER) return NOTIFY_DONE; @@ -1339,10 +1339,9 @@ static int ip6mr_device_event(struct notifier_block *this, v = &mrt->vif6_table[0]; for (ct = 0; ct < mrt->maxvif; ct++, v++) { if (v->dev == dev) - mif6_delete(mrt, ct, &list); + mif6_delete(mrt, ct, 1, NULL); } } - unregister_netdevice_many(&list); return NOTIFY_DONE; } @@ -1551,7 +1550,7 @@ static void mroute_clean_tables(struct mr6_table *mrt, bool all) for (i = 0; i < mrt->maxvif; i++) { if (!all && (mrt->vif6_table[i].flags & VIFF_STATIC)) continue; - mif6_delete(mrt, i, &list); + mif6_delete(mrt, i, 0, &list); } unregister_netdevice_many(&list); @@ -1704,7 +1703,7 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, uns if (copy_from_user(&mifi, optval, sizeof(mifi_t))) return -EFAULT; rtnl_lock(); - ret = mif6_delete(mrt, mifi, NULL); + ret = mif6_delete(mrt, mifi, 0, NULL); rtnl_unlock(); return ret; diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index d503b7f373a3..6896830feabb 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -1145,8 +1145,7 @@ static int rawv6_ioctl(struct sock *sk, int cmd, unsigned long arg) spin_lock_bh(&sk->sk_receive_queue.lock); skb = skb_peek(&sk->sk_receive_queue); if (skb) - amount = skb_tail_pointer(skb) - - skb_transport_header(skb); + amount = skb->len; spin_unlock_bh(&sk->sk_receive_queue.lock); return put_user(amount, (int __user *)arg); } diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 31e172cd84ac..ff1499293938 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -1756,6 +1756,10 @@ static struct rt6_info *ip6_route_info_create(struct fib6_config *cfg) int addr_type; int err = -EINVAL; + /* RTF_PCPU is an internal flag; can not be set by userspace */ + if (cfg->fc_flags & RTF_PCPU) + goto out; + if (cfg->fc_dst_len > 128 || cfg->fc_src_len > 128) goto out; #ifndef CONFIG_IPV6_SUBTREES diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c index ec17cbe8a02b..d3dec414fd44 100644 --- a/net/l2tp/l2tp_core.c +++ b/net/l2tp/l2tp_core.c @@ -278,7 +278,8 @@ struct l2tp_session *l2tp_session_find(struct net *net, struct l2tp_tunnel *tunn } EXPORT_SYMBOL_GPL(l2tp_session_find); -struct l2tp_session *l2tp_session_find_nth(struct l2tp_tunnel *tunnel, int nth) +struct l2tp_session *l2tp_session_get_nth(struct l2tp_tunnel *tunnel, int nth, + bool do_ref) { int hash; struct l2tp_session *session; @@ -288,6 +289,9 @@ struct l2tp_session *l2tp_session_find_nth(struct l2tp_tunnel *tunnel, int nth) for (hash = 0; hash < L2TP_HASH_SIZE; hash++) { hlist_for_each_entry(session, &tunnel->session_hlist[hash], hlist) { if (++count > nth) { + l2tp_session_inc_refcount(session); + if (do_ref && session->ref) + session->ref(session); read_unlock_bh(&tunnel->hlist_lock); return session; } @@ -298,7 +302,7 @@ struct l2tp_session *l2tp_session_find_nth(struct l2tp_tunnel *tunnel, int nth) return NULL; } -EXPORT_SYMBOL_GPL(l2tp_session_find_nth); +EXPORT_SYMBOL_GPL(l2tp_session_get_nth); /* Lookup a session by interface name. * This is very inefficient but is only used by management interfaces. diff --git a/net/l2tp/l2tp_core.h b/net/l2tp/l2tp_core.h index 763e8e241ce3..555d962a62d2 100644 --- a/net/l2tp/l2tp_core.h +++ b/net/l2tp/l2tp_core.h @@ -243,7 +243,8 @@ out: struct l2tp_session *l2tp_session_find(struct net *net, struct l2tp_tunnel *tunnel, u32 session_id); -struct l2tp_session *l2tp_session_find_nth(struct l2tp_tunnel *tunnel, int nth); +struct l2tp_session *l2tp_session_get_nth(struct l2tp_tunnel *tunnel, int nth, + bool do_ref); struct l2tp_session *l2tp_session_find_by_ifname(struct net *net, char *ifname); struct l2tp_tunnel *l2tp_tunnel_find(struct net *net, u32 tunnel_id); struct l2tp_tunnel *l2tp_tunnel_find_nth(struct net *net, int nth); diff --git a/net/l2tp/l2tp_debugfs.c b/net/l2tp/l2tp_debugfs.c index 2d6760a2ae34..d100aed3d06f 100644 --- a/net/l2tp/l2tp_debugfs.c +++ b/net/l2tp/l2tp_debugfs.c @@ -53,7 +53,7 @@ static void l2tp_dfs_next_tunnel(struct l2tp_dfs_seq_data *pd) static void l2tp_dfs_next_session(struct l2tp_dfs_seq_data *pd) { - pd->session = l2tp_session_find_nth(pd->tunnel, pd->session_idx); + pd->session = l2tp_session_get_nth(pd->tunnel, pd->session_idx, true); pd->session_idx++; if (pd->session == NULL) { @@ -238,10 +238,14 @@ static int l2tp_dfs_seq_show(struct seq_file *m, void *v) } /* Show the tunnel or session context */ - if (pd->session == NULL) + if (!pd->session) { l2tp_dfs_seq_tunnel_show(m, pd->tunnel); - else + } else { l2tp_dfs_seq_session_show(m, pd->session); + if (pd->session->deref) + pd->session->deref(pd->session); + l2tp_session_dec_refcount(pd->session); + } out: return 0; diff --git a/net/l2tp/l2tp_netlink.c b/net/l2tp/l2tp_netlink.c index 2caaa84ce92d..665cc74df5c5 100644 --- a/net/l2tp/l2tp_netlink.c +++ b/net/l2tp/l2tp_netlink.c @@ -827,7 +827,7 @@ static int l2tp_nl_cmd_session_dump(struct sk_buff *skb, struct netlink_callback goto out; } - session = l2tp_session_find_nth(tunnel, si); + session = l2tp_session_get_nth(tunnel, si, false); if (session == NULL) { ti++; tunnel = NULL; @@ -837,8 +837,11 @@ static int l2tp_nl_cmd_session_dump(struct sk_buff *skb, struct netlink_callback if (l2tp_nl_session_send(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, NLM_F_MULTI, - session, L2TP_CMD_SESSION_GET) < 0) + session, L2TP_CMD_SESSION_GET) < 0) { + l2tp_session_dec_refcount(session); break; + } + l2tp_session_dec_refcount(session); si++; } diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c index 1ad18c55064c..8ab9c5d74416 100644 --- a/net/l2tp/l2tp_ppp.c +++ b/net/l2tp/l2tp_ppp.c @@ -467,6 +467,10 @@ static void pppol2tp_session_close(struct l2tp_session *session) static void pppol2tp_session_destruct(struct sock *sk) { struct l2tp_session *session = sk->sk_user_data; + + skb_queue_purge(&sk->sk_receive_queue); + skb_queue_purge(&sk->sk_write_queue); + if (session) { sk->sk_user_data = NULL; BUG_ON(session->magic != L2TP_SESSION_MAGIC); @@ -505,9 +509,6 @@ static int pppol2tp_release(struct socket *sock) l2tp_session_queue_purge(session); sock_put(sk); } - skb_queue_purge(&sk->sk_receive_queue); - skb_queue_purge(&sk->sk_write_queue); - release_sock(sk); /* This will delete the session context via @@ -1574,7 +1575,7 @@ static void pppol2tp_next_tunnel(struct net *net, struct pppol2tp_seq_data *pd) static void pppol2tp_next_session(struct net *net, struct pppol2tp_seq_data *pd) { - pd->session = l2tp_session_find_nth(pd->tunnel, pd->session_idx); + pd->session = l2tp_session_get_nth(pd->tunnel, pd->session_idx, true); pd->session_idx++; if (pd->session == NULL) { @@ -1701,10 +1702,14 @@ static int pppol2tp_seq_show(struct seq_file *m, void *v) /* Show the tunnel or session context. */ - if (pd->session == NULL) + if (!pd->session) { pppol2tp_seq_tunnel_show(m, pd->tunnel); - else + } else { pppol2tp_seq_session_show(m, pd->session); + if (pd->session->deref) + pd->session->deref(pd->session); + l2tp_session_dec_refcount(pd->session); + } out: return 0; @@ -1863,4 +1868,4 @@ MODULE_DESCRIPTION("PPP over L2TP over UDP"); MODULE_LICENSE("GPL"); MODULE_VERSION(PPPOL2TP_DRV_VERSION); MODULE_ALIAS("pppox-proto-" __stringify(PX_PROTO_OL2TP)); -MODULE_ALIAS_L2TP_PWTYPE(11); +MODULE_ALIAS_L2TP_PWTYPE(7); diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 4f4c45ba7b70..25b5bacaa434 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -3397,6 +3397,27 @@ static bool ieee80211_accept_frame(struct ieee80211_rx_data *rx) !ether_addr_equal(bssid, hdr->addr1)) return false; } + + /* + * 802.11-2016 Table 9-26 says that for data frames, A1 must be + * the BSSID - we've checked that already but may have accepted + * the wildcard (ff:ff:ff:ff:ff:ff). + * + * It also says: + * The BSSID of the Data frame is determined as follows: + * a) If the STA is contained within an AP or is associated + * with an AP, the BSSID is the address currently in use + * by the STA contained in the AP. + * + * So we should not accept data frames with an address that's + * multicast. + * + * Accepting it also opens a security problem because stations + * could encrypt it with the GTK and inject traffic that way. + */ + if (ieee80211_is_data(hdr->frame_control) && multicast) + return false; + return true; case NL80211_IFTYPE_WDS: if (bssid || !ieee80211_is_data(hdr->frame_control)) diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index d76800108ddb..f8d6a0ca9c03 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -3626,6 +3626,8 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv return -EBUSY; if (copy_from_user(&val, optval, sizeof(val))) return -EFAULT; + if (val > INT_MAX) + return -EINVAL; po->tp_reserve = val; return 0; } @@ -4150,6 +4152,8 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u, rb->frames_per_block = req->tp_block_size / req->tp_frame_size; if (unlikely(rb->frames_per_block == 0)) goto out; + if (unlikely(req->tp_block_size > UINT_MAX / req->tp_block_nr)) + goto out; if (unlikely((rb->frames_per_block * req->tp_block_nr) != req->tp_frame_nr)) goto out; diff --git a/net/rds/cong.c b/net/rds/cong.c index e6144b8246fd..6641bcf7c185 100644 --- a/net/rds/cong.c +++ b/net/rds/cong.c @@ -299,7 +299,7 @@ void rds_cong_set_bit(struct rds_cong_map *map, __be16 port) i = be16_to_cpu(port) / RDS_CONG_MAP_PAGE_BITS; off = be16_to_cpu(port) % RDS_CONG_MAP_PAGE_BITS; - __set_bit_le(off, (void *)map->m_page_addrs[i]); + set_bit_le(off, (void *)map->m_page_addrs[i]); } void rds_cong_clear_bit(struct rds_cong_map *map, __be16 port) @@ -313,7 +313,7 @@ void rds_cong_clear_bit(struct rds_cong_map *map, __be16 port) i = be16_to_cpu(port) / RDS_CONG_MAP_PAGE_BITS; off = be16_to_cpu(port) % RDS_CONG_MAP_PAGE_BITS; - __clear_bit_le(off, (void *)map->m_page_addrs[i]); + clear_bit_le(off, (void *)map->m_page_addrs[i]); } static int rds_cong_test_bit(struct rds_cong_map *map, __be16 port) diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c index e384d6aefa3a..1090a52c03cd 100644 --- a/net/sched/act_mirred.c +++ b/net/sched/act_mirred.c @@ -36,14 +36,15 @@ static DEFINE_SPINLOCK(mirred_list_lock); static void tcf_mirred_release(struct tc_action *a, int bind) { struct tcf_mirred *m = to_mirred(a); - struct net_device *dev = rcu_dereference_protected(m->tcfm_dev, 1); + struct net_device *dev; /* We could be called either in a RCU callback or with RTNL lock held. */ spin_lock_bh(&mirred_list_lock); list_del(&m->tcfm_list); - spin_unlock_bh(&mirred_list_lock); + dev = rcu_dereference_protected(m->tcfm_dev, 1); if (dev) dev_put(dev); + spin_unlock_bh(&mirred_list_lock); } static const struct nla_policy mirred_policy[TCA_MIRRED_MAX + 1] = { diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 5758818435f3..c96d666cef29 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -6394,6 +6394,9 @@ int sctp_inet_listen(struct socket *sock, int backlog) if (sock->state != SS_UNCONNECTED) goto out; + if (!sctp_sstate(sk, LISTENING) && !sctp_sstate(sk, CLOSED)) + goto out; + /* If backlog is zero, disable listening. */ if (!backlog) { if (sctp_sstate(sk, CLOSED)) diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c index 648f2a67f314..cb1381513c82 100644 --- a/net/tipc/bearer.c +++ b/net/tipc/bearer.c @@ -381,6 +381,10 @@ int tipc_enable_l2_media(struct net *net, struct tipc_bearer *b, dev = dev_get_by_name(net, driver_name); if (!dev) return -ENODEV; + if (tipc_mtu_bad(dev, 0)) { + dev_put(dev); + return -EINVAL; + } /* Associate TIPC bearer with L2 bearer */ rcu_assign_pointer(b->media_ptr, dev); @@ -570,14 +574,19 @@ static int tipc_l2_device_event(struct notifier_block *nb, unsigned long evt, if (!b_ptr) return NOTIFY_DONE; - b_ptr->mtu = dev->mtu; - switch (evt) { case NETDEV_CHANGE: if (netif_carrier_ok(dev)) break; case NETDEV_GOING_DOWN: + tipc_reset_bearer(net, b_ptr); + break; case NETDEV_CHANGEMTU: + if (tipc_mtu_bad(dev, 0)) { + bearer_disable(net, b_ptr); + break; + } + b_ptr->mtu = dev->mtu; tipc_reset_bearer(net, b_ptr); break; case NETDEV_CHANGEADDR: diff --git a/net/tipc/bearer.h b/net/tipc/bearer.h index 552185bc4773..5f11e18b1fa1 100644 --- a/net/tipc/bearer.h +++ b/net/tipc/bearer.h @@ -39,6 +39,7 @@ #include "netlink.h" #include "core.h" +#include "msg.h" #include <net/genetlink.h> #define MAX_MEDIA 3 @@ -61,6 +62,9 @@ #define TIPC_MEDIA_TYPE_IB 2 #define TIPC_MEDIA_TYPE_UDP 3 +/* minimum bearer MTU */ +#define TIPC_MIN_BEARER_MTU (MAX_H_SIZE + INT_H_SIZE) + /** * struct tipc_node_map - set of node identifiers * @count: # of nodes in set @@ -226,4 +230,13 @@ void tipc_bearer_xmit(struct net *net, u32 bearer_id, void tipc_bearer_bc_xmit(struct net *net, u32 bearer_id, struct sk_buff_head *xmitq); +/* check if device MTU is too low for tipc headers */ +static inline bool tipc_mtu_bad(struct net_device *dev, unsigned int reserve) +{ + if (dev->mtu >= TIPC_MIN_BEARER_MTU + reserve) + return false; + netdev_warn(dev, "MTU too low for tipc bearer\n"); + return true; +} + #endif /* _TIPC_BEARER_H */ diff --git a/net/tipc/core.c b/net/tipc/core.c index 03a842870c52..e2bdb07a49a2 100644 --- a/net/tipc/core.c +++ b/net/tipc/core.c @@ -69,6 +69,7 @@ static int __net_init tipc_init_net(struct net *net) if (err) goto out_nametbl; + INIT_LIST_HEAD(&tn->dist_queue); err = tipc_topsrv_start(net); if (err) goto out_subscr; diff --git a/net/tipc/core.h b/net/tipc/core.h index 18e95a8020cd..fe3b89e9cde4 100644 --- a/net/tipc/core.h +++ b/net/tipc/core.h @@ -103,6 +103,9 @@ struct tipc_net { spinlock_t nametbl_lock; struct name_table *nametbl; + /* Name dist queue */ + struct list_head dist_queue; + /* Topology subscription server */ struct tipc_server *topsrv; atomic_t subscription_count; diff --git a/net/tipc/name_distr.c b/net/tipc/name_distr.c index f51c8bdbea1c..c4c151bc000c 100644 --- a/net/tipc/name_distr.c +++ b/net/tipc/name_distr.c @@ -40,11 +40,6 @@ int sysctl_tipc_named_timeout __read_mostly = 2000; -/** - * struct tipc_dist_queue - queue holding deferred name table updates - */ -static struct list_head tipc_dist_queue = LIST_HEAD_INIT(tipc_dist_queue); - struct distr_queue_item { struct distr_item i; u32 dtype; @@ -67,6 +62,8 @@ static void publ_to_item(struct distr_item *i, struct publication *p) /** * named_prepare_buf - allocate & initialize a publication message + * + * The buffer returned is of size INT_H_SIZE + payload size */ static struct sk_buff *named_prepare_buf(struct net *net, u32 type, u32 size, u32 dest) @@ -171,9 +168,9 @@ static void named_distribute(struct net *net, struct sk_buff_head *list, struct publication *publ; struct sk_buff *skb = NULL; struct distr_item *item = NULL; - uint msg_dsz = (tipc_node_get_mtu(net, dnode, 0) / ITEM_SIZE) * - ITEM_SIZE; - uint msg_rem = msg_dsz; + u32 msg_dsz = ((tipc_node_get_mtu(net, dnode, 0) - INT_H_SIZE) / + ITEM_SIZE) * ITEM_SIZE; + u32 msg_rem = msg_dsz; list_for_each_entry(publ, pls, local_list) { /* Prepare next buffer: */ @@ -340,9 +337,11 @@ static bool tipc_update_nametbl(struct net *net, struct distr_item *i, * tipc_named_add_backlog - add a failed name table update to the backlog * */ -static void tipc_named_add_backlog(struct distr_item *i, u32 type, u32 node) +static void tipc_named_add_backlog(struct net *net, struct distr_item *i, + u32 type, u32 node) { struct distr_queue_item *e; + struct tipc_net *tn = net_generic(net, tipc_net_id); unsigned long now = get_jiffies_64(); e = kzalloc(sizeof(*e), GFP_ATOMIC); @@ -352,7 +351,7 @@ static void tipc_named_add_backlog(struct distr_item *i, u32 type, u32 node) e->node = node; e->expires = now + msecs_to_jiffies(sysctl_tipc_named_timeout); memcpy(e, i, sizeof(*i)); - list_add_tail(&e->next, &tipc_dist_queue); + list_add_tail(&e->next, &tn->dist_queue); } /** @@ -362,10 +361,11 @@ static void tipc_named_add_backlog(struct distr_item *i, u32 type, u32 node) void tipc_named_process_backlog(struct net *net) { struct distr_queue_item *e, *tmp; + struct tipc_net *tn = net_generic(net, tipc_net_id); char addr[16]; unsigned long now = get_jiffies_64(); - list_for_each_entry_safe(e, tmp, &tipc_dist_queue, next) { + list_for_each_entry_safe(e, tmp, &tn->dist_queue, next) { if (time_after(e->expires, now)) { if (!tipc_update_nametbl(net, &e->i, e->node, e->dtype)) continue; @@ -405,7 +405,7 @@ void tipc_named_rcv(struct net *net, struct sk_buff_head *inputq) node = msg_orignode(msg); while (count--) { if (!tipc_update_nametbl(net, item, node, mtype)) - tipc_named_add_backlog(item, mtype, node); + tipc_named_add_backlog(net, item, mtype, node); item++; } kfree_skb(skb); diff --git a/net/tipc/node.c b/net/tipc/node.c index 3926b561f873..2df0b98d4a32 100644 --- a/net/tipc/node.c +++ b/net/tipc/node.c @@ -102,9 +102,10 @@ static unsigned int tipc_hashfn(u32 addr) static void tipc_node_kref_release(struct kref *kref) { - struct tipc_node *node = container_of(kref, struct tipc_node, kref); + struct tipc_node *n = container_of(kref, struct tipc_node, kref); - tipc_node_delete(node); + kfree(n->bc_entry.link); + kfree_rcu(n, rcu); } void tipc_node_put(struct tipc_node *node) @@ -216,21 +217,20 @@ static void tipc_node_delete(struct tipc_node *node) { list_del_rcu(&node->list); hlist_del_rcu(&node->hash); - kfree(node->bc_entry.link); - kfree_rcu(node, rcu); + tipc_node_put(node); + + del_timer_sync(&node->timer); + tipc_node_put(node); } void tipc_node_stop(struct net *net) { - struct tipc_net *tn = net_generic(net, tipc_net_id); + struct tipc_net *tn = tipc_net(net); struct tipc_node *node, *t_node; spin_lock_bh(&tn->node_list_lock); - list_for_each_entry_safe(node, t_node, &tn->node_list, list) { - if (del_timer(&node->timer)) - tipc_node_put(node); - tipc_node_put(node); - } + list_for_each_entry_safe(node, t_node, &tn->node_list, list) + tipc_node_delete(node); spin_unlock_bh(&tn->node_list_lock); } @@ -313,9 +313,7 @@ static void tipc_node_timeout(unsigned long data) if (rc & TIPC_LINK_DOWN_EVT) tipc_node_link_down(n, bearer_id, false); } - if (!mod_timer(&n->timer, jiffies + n->keepalive_intv)) - tipc_node_get(n); - tipc_node_put(n); + mod_timer(&n->timer, jiffies + n->keepalive_intv); } /** @@ -730,7 +728,7 @@ static void tipc_node_fsm_evt(struct tipc_node *n, int evt) state = SELF_UP_PEER_UP; break; case SELF_LOST_CONTACT_EVT: - state = SELF_DOWN_PEER_LEAVING; + state = SELF_DOWN_PEER_DOWN; break; case SELF_ESTABL_CONTACT_EVT: case PEER_LOST_CONTACT_EVT: @@ -749,7 +747,7 @@ static void tipc_node_fsm_evt(struct tipc_node *n, int evt) state = SELF_UP_PEER_UP; break; case PEER_LOST_CONTACT_EVT: - state = SELF_LEAVING_PEER_DOWN; + state = SELF_DOWN_PEER_DOWN; break; case SELF_LOST_CONTACT_EVT: case PEER_ESTABL_CONTACT_EVT: diff --git a/net/tipc/socket.c b/net/tipc/socket.c index b26b7a127773..65171f8e8c45 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -777,9 +777,11 @@ void tipc_sk_mcast_rcv(struct net *net, struct sk_buff_head *arrvq, * @tsk: receiving socket * @skb: pointer to message buffer. */ -static void tipc_sk_proto_rcv(struct tipc_sock *tsk, struct sk_buff *skb) +static void tipc_sk_proto_rcv(struct tipc_sock *tsk, struct sk_buff *skb, + struct sk_buff_head *xmitq) { struct sock *sk = &tsk->sk; + u32 onode = tsk_own_node(tsk); struct tipc_msg *hdr = buf_msg(skb); int mtyp = msg_type(hdr); int conn_cong; @@ -792,7 +794,8 @@ static void tipc_sk_proto_rcv(struct tipc_sock *tsk, struct sk_buff *skb) if (mtyp == CONN_PROBE) { msg_set_type(hdr, CONN_PROBE_REPLY); - tipc_sk_respond(sk, skb, TIPC_OK); + if (tipc_msg_reverse(onode, &skb, TIPC_OK)) + __skb_queue_tail(xmitq, skb); return; } else if (mtyp == CONN_ACK) { conn_cong = tsk_conn_cong(tsk); @@ -1647,7 +1650,8 @@ static unsigned int rcvbuf_limit(struct sock *sk, struct sk_buff *buf) * * Returns true if message was added to socket receive queue, otherwise false */ -static bool filter_rcv(struct sock *sk, struct sk_buff *skb) +static bool filter_rcv(struct sock *sk, struct sk_buff *skb, + struct sk_buff_head *xmitq) { struct socket *sock = sk->sk_socket; struct tipc_sock *tsk = tipc_sk(sk); @@ -1657,7 +1661,7 @@ static bool filter_rcv(struct sock *sk, struct sk_buff *skb) int usr = msg_user(hdr); if (unlikely(msg_user(hdr) == CONN_MANAGER)) { - tipc_sk_proto_rcv(tsk, skb); + tipc_sk_proto_rcv(tsk, skb, xmitq); return false; } @@ -1700,7 +1704,8 @@ static bool filter_rcv(struct sock *sk, struct sk_buff *skb) return true; reject: - tipc_sk_respond(sk, skb, err); + if (tipc_msg_reverse(tsk_own_node(tsk), &skb, err)) + __skb_queue_tail(xmitq, skb); return false; } @@ -1716,9 +1721,24 @@ reject: static int tipc_backlog_rcv(struct sock *sk, struct sk_buff *skb) { unsigned int truesize = skb->truesize; + struct sk_buff_head xmitq; + u32 dnode, selector; - if (likely(filter_rcv(sk, skb))) + __skb_queue_head_init(&xmitq); + + if (likely(filter_rcv(sk, skb, &xmitq))) { atomic_add(truesize, &tipc_sk(sk)->dupl_rcvcnt); + return 0; + } + + if (skb_queue_empty(&xmitq)) + return 0; + + /* Send response/rejected message */ + skb = __skb_dequeue(&xmitq); + dnode = msg_destnode(buf_msg(skb)); + selector = msg_origport(buf_msg(skb)); + tipc_node_xmit_skb(sock_net(sk), skb, dnode, selector); return 0; } @@ -1732,12 +1752,13 @@ static int tipc_backlog_rcv(struct sock *sk, struct sk_buff *skb) * Caller must hold socket lock */ static void tipc_sk_enqueue(struct sk_buff_head *inputq, struct sock *sk, - u32 dport) + u32 dport, struct sk_buff_head *xmitq) { + unsigned long time_limit = jiffies + 2; + struct sk_buff *skb; unsigned int lim; atomic_t *dcnt; - struct sk_buff *skb; - unsigned long time_limit = jiffies + 2; + u32 onode; while (skb_queue_len(inputq)) { if (unlikely(time_after_eq(jiffies, time_limit))) @@ -1749,20 +1770,22 @@ static void tipc_sk_enqueue(struct sk_buff_head *inputq, struct sock *sk, /* Add message directly to receive queue if possible */ if (!sock_owned_by_user(sk)) { - filter_rcv(sk, skb); + filter_rcv(sk, skb, xmitq); continue; } /* Try backlog, compensating for double-counted bytes */ dcnt = &tipc_sk(sk)->dupl_rcvcnt; - if (sk->sk_backlog.len) + if (!sk->sk_backlog.len) atomic_set(dcnt, 0); lim = rcvbuf_limit(sk, skb) + atomic_read(dcnt); if (likely(!sk_add_backlog(sk, skb, lim))) continue; /* Overload => reject message back to sender */ - tipc_sk_respond(sk, skb, TIPC_ERR_OVERLOAD); + onode = tipc_own_addr(sock_net(sk)); + if (tipc_msg_reverse(onode, &skb, TIPC_ERR_OVERLOAD)) + __skb_queue_tail(xmitq, skb); break; } } @@ -1775,12 +1798,14 @@ static void tipc_sk_enqueue(struct sk_buff_head *inputq, struct sock *sk, */ void tipc_sk_rcv(struct net *net, struct sk_buff_head *inputq) { + struct sk_buff_head xmitq; u32 dnode, dport = 0; int err; struct tipc_sock *tsk; struct sock *sk; struct sk_buff *skb; + __skb_queue_head_init(&xmitq); while (skb_queue_len(inputq)) { dport = tipc_skb_peek_port(inputq, dport); tsk = tipc_sk_lookup(net, dport); @@ -1788,9 +1813,14 @@ void tipc_sk_rcv(struct net *net, struct sk_buff_head *inputq) if (likely(tsk)) { sk = &tsk->sk; if (likely(spin_trylock_bh(&sk->sk_lock.slock))) { - tipc_sk_enqueue(inputq, sk, dport); + tipc_sk_enqueue(inputq, sk, dport, &xmitq); spin_unlock_bh(&sk->sk_lock.slock); } + /* Send pending response/rejected messages, if any */ + while ((skb = __skb_dequeue(&xmitq))) { + dnode = msg_destnode(buf_msg(skb)); + tipc_node_xmit_skb(net, skb, dnode, dport); + } sock_put(sk); continue; } diff --git a/net/tipc/udp_media.c b/net/tipc/udp_media.c index 6af78c6276b4..78d6b78de29d 100644 --- a/net/tipc/udp_media.c +++ b/net/tipc/udp_media.c @@ -52,7 +52,7 @@ /* IANA assigned UDP port */ #define UDP_PORT_DEFAULT 6118 -#define UDP_MIN_HEADROOM 28 +#define UDP_MIN_HEADROOM 48 static const struct nla_policy tipc_nl_udp_policy[TIPC_NLA_UDP_MAX + 1] = { [TIPC_NLA_UDP_UNSPEC] = {.type = NLA_UNSPEC}, @@ -376,6 +376,11 @@ static int tipc_udp_enable(struct net *net, struct tipc_bearer *b, udp_conf.local_ip.s_addr = htonl(INADDR_ANY); udp_conf.use_udp_checksums = false; ub->ifindex = dev->ifindex; + if (tipc_mtu_bad(dev, sizeof(struct iphdr) + + sizeof(struct udphdr))) { + err = -EINVAL; + goto err; + } b->mtu = dev->mtu - sizeof(struct iphdr) - sizeof(struct udphdr); #if IS_ENABLED(CONFIG_IPV6) diff --git a/net/vmw_vsock/vmci_transport.c b/net/vmw_vsock/vmci_transport.c index 0a369bb440e7..662bdd20a748 100644 --- a/net/vmw_vsock/vmci_transport.c +++ b/net/vmw_vsock/vmci_transport.c @@ -842,7 +842,7 @@ static void vmci_transport_peer_detach_cb(u32 sub_id, * qp_handle. */ if (vmci_handle_is_invalid(e_payload->handle) || - vmci_handle_is_equal(trans->qp_handle, e_payload->handle)) + !vmci_handle_is_equal(trans->qp_handle, e_payload->handle)) return; /* We don't ask for delayed CBs when we subscribe to this event (we @@ -2154,7 +2154,7 @@ module_exit(vmci_transport_exit); MODULE_AUTHOR("VMware, Inc."); MODULE_DESCRIPTION("VMCI transport for Virtual Sockets"); -MODULE_VERSION("1.0.2.0-k"); +MODULE_VERSION("1.0.3.0-k"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("vmware_vsock"); MODULE_ALIAS_NETPROTO(PF_VSOCK); diff --git a/net/wireless/db.txt b/net/wireless/db.txt index 44cb3dc1b2de..3c431e49aef1 100644 --- a/net/wireless/db.txt +++ b/net/wireless/db.txt @@ -84,7 +84,7 @@ country AT: DFS-ETSI (5900 - 5920 @ 10), (30) (5910 - 5930 @ 10), (30) # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (40), NO-OUTDOOR + (57000 - 66000 @ 2160), (40) country AU: DFS-FCC (2402 - 2482 @ 40), (20) @@ -93,7 +93,6 @@ country AU: DFS-FCC (5490 - 5590 @ 80), (24), DFS (5650 - 5730 @ 80), (24), DFS (5735 - 5835 @ 80), (30) - # 60 gHz band channels 1-4 (57240 - 65880 @ 2160), (43), NO-OUTDOOR @@ -139,7 +138,7 @@ country BE: DFS-ETSI (5900 - 5920 @ 10), (30) (5910 - 5930 @ 10), (30) # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (40) + (57000 - 66000 @ 2160), (40) country BF: DFS-FCC (2402 - 2482 @ 40), (20) @@ -163,7 +162,7 @@ country BG: DFS-ETSI (5900 - 5920 @ 10), (30) (5910 - 5930 @ 10), (30) # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (40), NO-OUTDOOR + (57000 - 66000 @ 2160), (40) country BH: (2402 - 2482 @ 40), (20) @@ -193,7 +192,6 @@ country BO: DFS-ETSI (2402 - 2482 @ 40), (20) (5250 - 5330 @ 80), (30), DFS (5735 - 5835 @ 80), (30) - # 60 gHz band channels 1-3, FCC (57240 - 63720 @ 2160), (40) @@ -203,7 +201,6 @@ country BR: DFS-FCC (5250 - 5330 @ 80), (24), DFS, AUTO-BW (5490 - 5730 @ 160), (24), DFS (5735 - 5835 @ 80), (30) - # 60 gHz band channels 1-3 (57240 - 63720 @ 2160), (40) @@ -239,7 +236,6 @@ country CA: DFS-FCC (5490 - 5590 @ 80), (24), DFS (5650 - 5730 @ 80), (24), DFS (5735 - 5835 @ 80), (30) - # 60 gHz band channels 1-3 (57240 - 63720 @ 2160), (40) @@ -264,9 +260,8 @@ country CH: DFS-ETSI (5890 - 5910 @ 10), (30) (5900 - 5920 @ 10), (30) (5910 - 5930 @ 10), (30) - # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (40), NO-OUTDOOR + (57000 - 66000 @ 2160), (40) country CI: DFS-FCC (2402 - 2482 @ 40), (20) @@ -279,7 +274,6 @@ country CL: (2402 - 2482 @ 40), (20) (5170 - 5330 @ 160), (20) (5735 - 5835 @ 80), (20) - # 60 gHz band channels 1-3 (57240 - 63720 @ 2160), (50), NO-OUTDOOR @@ -304,7 +298,6 @@ country CR: DFS-FCC (5250 - 5330 @ 20), (24), DFS (5490 - 5730 @ 20), (24), DFS (5735 - 5835 @ 20), (30) - # 60 gHz band channels 1-3 (57240 - 63720 @ 2160), (30) @@ -330,7 +323,7 @@ country CY: DFS-ETSI (5900 - 5920 @ 10), (30) (5910 - 5930 @ 10), (30) # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (40), NO-OUTDOOR + (57000 - 66000 @ 2160), (40) # Data from http://www.ctu.eu/164/download/VOR/VOR-12-08-2005-34.pdf # and http://www.ctu.eu/164/download/VOR/VOR-12-05-2007-6-AN.pdf @@ -349,7 +342,7 @@ country CZ: DFS-ETSI (5900 - 5920 @ 10), (30) (5910 - 5930 @ 10), (30) # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (40), NO-OUTDOOR + (57000 - 66000 @ 2160), (40) # Data from "Frequenznutzungsplan" (as published in April 2008), downloaded from # http://www.bundesnetzagentur.de/cae/servlet/contentblob/38448/publicationFile/2659/Frequenznutzungsplan2008_Id17448pdf.pdf @@ -372,7 +365,7 @@ country DE: DFS-ETSI (5900 - 5920 @ 10), (30) (5910 - 5930 @ 10), (30) # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (40), NO-OUTDOOR + (57000 - 66000 @ 2160), (40) country DK: DFS-ETSI (2402 - 2482 @ 40), (20) @@ -389,7 +382,7 @@ country DK: DFS-ETSI (5900 - 5920 @ 10), (30) (5910 - 5930 @ 10), (30) # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (40), NO-OUTDOOR + (57000 - 66000 @ 2160), (40) country DM: DFS-FCC (2402 - 2472 @ 40), (30) @@ -415,7 +408,6 @@ country EC: DFS-FCC (5250 - 5330 @ 20), (24), DFS (5490 - 5730 @ 20), (24), DFS (5735 - 5835 @ 20), (30) - # 60 gHz band channels 1-3, FCC (57240 - 63720 @ 2160), (40) @@ -434,7 +426,7 @@ country EE: DFS-ETSI (5900 - 5920 @ 10), (30) (5910 - 5930 @ 10), (30) # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (40), NO-OUTDOOR + (57000 - 66000 @ 2160), (40) country EG: DFS-ETSI (2402 - 2482 @ 40), (20) @@ -456,7 +448,7 @@ country ES: DFS-ETSI (5900 - 5920 @ 10), (30) (5910 - 5930 @ 10), (30) # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (40), NO-OUTDOOR + (57000 - 66000 @ 2160), (40) country ET: DFS-ETSI (2402 - 2482 @ 40), (20) @@ -479,7 +471,7 @@ country FI: DFS-ETSI (5900 - 5920 @ 10), (30) (5910 - 5930 @ 10), (30) # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (40), NO-OUTDOOR + (57000 - 66000 @ 2160), (40) country FM: DFS-FCC (2402 - 2472 @ 40), (30) @@ -503,7 +495,7 @@ country FR: DFS-ETSI (5900 - 5920 @ 10), (30) (5910 - 5930 @ 10), (30) # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (40), NO-OUTDOOR + (57000 - 66000 @ 2160), (40) country GB: DFS-ETSI (2402 - 2482 @ 40), (20) @@ -520,7 +512,7 @@ country GB: DFS-ETSI (5900 - 5920 @ 10), (30) (5910 - 5930 @ 10), (30) # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (40), NO-OUTDOOR + (57000 - 66000 @ 2160), (40) country GD: DFS-FCC (2402 - 2472 @ 40), (30) @@ -574,7 +566,7 @@ country GR: DFS-ETSI (5900 - 5920 @ 10), (30) (5910 - 5930 @ 10), (30) # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (40), NO-OUTDOOR + (57000 - 66000 @ 2160), (40) country GT: DFS-ETSI (2402 - 2482 @ 40), (20) @@ -588,7 +580,6 @@ country GU: DFS-FCC (5250 - 5330 @ 80), (24), DFS, AUTO-BW (5490 - 5730 @ 160), (24), DFS (5735 - 5835 @ 80), (30) - # 60 gHz band channels 1-3, FCC (57240 - 63720 @ 2160), (40) @@ -602,7 +593,6 @@ country HK: DFS-FCC (5250 - 5330 @ 80), (24), DFS, AUTO-BW (5490 - 5730 @ 160), (24), DFS (5735 - 5835 @ 80), (30) - # 60 gHz band channels 1-4, ref: FCC/EU (57240 - 65880 @ 2160), (40) @@ -611,7 +601,6 @@ country HN: (5170 - 5330 @ 160), (24) (5490 - 5730 @ 160), (24) (5735 - 5835 @ 80), (30) - # 60 gHz band channels 1-3, FCC (57240 - 63720 @ 2160), (40) @@ -630,7 +619,7 @@ country HR: DFS-ETSI (5900 - 5920 @ 10), (30) (5910 - 5930 @ 10), (30) # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (40), NO-OUTDOOR + (57000 - 66000 @ 2160), (40) country HT: DFS-FCC (2402 - 2472 @ 40), (30) @@ -654,7 +643,7 @@ country HU: DFS-ETSI (5900 - 5920 @ 10), (30) (5910 - 5930 @ 10), (30) # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (40), NO-OUTDOOR + (57000 - 66000 @ 2160), (40) country ID: # ref: http://www.postel.go.id/content/ID/regulasi/standardisasi/kepdir/bwa%205,8%20ghz.pdf @@ -676,15 +665,14 @@ country IE: DFS-ETSI (5900 - 5920 @ 10), (30) (5910 - 5930 @ 10), (30) # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (40), NO-OUTDOOR + (57000 - 66000 @ 2160), (40) country IL: DFS-ETSI (2402 - 2482 @ 40), (20) (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW - # 60 gHz band channels 1-4, base on Etsi En 302 567 - (57240 - 65880 @ 2160), (40), NO-OUTDOOR + (57000 - 66000 @ 2160), (40) country IN: (2402 - 2482 @ 40), (20) @@ -710,7 +698,7 @@ country IS: DFS-ETSI (5900 - 5920 @ 10), (30) (5910 - 5930 @ 10), (30) # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (40), NO-OUTDOOR + (57000 - 66000 @ 2160), (40) country IT: DFS-ETSI (2402 - 2482 @ 40), (20) @@ -727,7 +715,7 @@ country IT: DFS-ETSI (5900 - 5920 @ 10), (30) (5910 - 5930 @ 10), (30) # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (40), NO-OUTDOOR + (57000 - 66000 @ 2160), (40) country JM: DFS-FCC (2402 - 2482 @ 40), (20) @@ -735,7 +723,6 @@ country JM: DFS-FCC (5250 - 5330 @ 80), (24), DFS, AUTO-BW (5490 - 5730 @ 160), (24), DFS (5735 - 5835 @ 80), (30) - # 60 gHz band channels 1-3, FCC (57240 - 63720 @ 2160), (40) @@ -743,9 +730,8 @@ country JO: (2402 - 2482 @ 40), (20) (5170 - 5250 @ 80), (23) (5735 - 5835 @ 80), (23) - # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (40), NO-OUTDOOR + ((57000 - 66000 @ 2160), (40) country JP: DFS-JP (2402 - 2482 @ 40), (20) @@ -835,9 +821,8 @@ country LI: DFS-ETSI (5890 - 5910 @ 10), (30) (5900 - 5920 @ 10), (30) (5910 - 5930 @ 10), (30) - # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (40), NO-OUTDOOR + (57000 - 66000 @ 2160), (40) country LK: DFS-FCC (2402 - 2482 @ 40), (20) @@ -867,7 +852,7 @@ country LT: DFS-ETSI (5900 - 5920 @ 10), (30) (5910 - 5930 @ 10), (30) # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (40), NO-OUTDOOR + (57000 - 66000 @ 2160), (40) country LU: DFS-ETSI (2402 - 2482 @ 40), (20) @@ -884,7 +869,7 @@ country LU: DFS-ETSI (5900 - 5920 @ 10), (30) (5910 - 5930 @ 10), (30) # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (40), NO-OUTDOOR + (57000 - 66000 @ 2160), (40) country LV: DFS-ETSI (2402 - 2482 @ 40), (20) @@ -900,17 +885,15 @@ country LV: DFS-ETSI (5890 - 5910 @ 10), (30) (5900 - 5920 @ 10), (30) (5910 - 5930 @ 10), (30) - # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (40), NO-OUTDOOR + (57000 - 66000 @ 2160), (40) country MA: DFS-ETSI (2402 - 2482 @ 40), (20) (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW - # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (40), NO-OUTDOOR + (57000 - 66000 @ 2160), (40) country MC: DFS-ETSI (2402 - 2482 @ 40), (20) @@ -997,7 +980,7 @@ country MT: DFS-ETSI (5900 - 5920 @ 10), (30) (5910 - 5930 @ 10), (30) # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (40), NO-OUTDOOR + (57000 - 66000 @ 2160), (40) country MU: DFS-FCC (2402 - 2482 @ 40), (20) @@ -1024,7 +1007,6 @@ country MX: DFS-FCC (5250 - 5330 @ 80), (24), DFS, AUTO-BW (5490 - 5730 @ 160), (24), DFS (5735 - 5835 @ 80), (30) - # 60 gHz band channels 1-3, FCC (57240 - 63720 @ 2160), (40) @@ -1034,7 +1016,6 @@ country MY: DFS-FCC (5250 - 5330 @ 80), (24), DFS, AUTO-BW (5490 - 5650 @ 160), (24), DFS (5735 - 5815 @ 80), (24) - # 60 gHz band channels 1-3 (57240 - 63720 @ 2160), (40) @@ -1056,7 +1037,6 @@ country NI: DFS-FCC (5250 - 5330 @ 80), (24), DFS, AUTO-BW (5490 - 5730 @ 160), (24), DFS (5735 - 5835 @ 80), (30) - # 60 gHz band channels 1-3, FCC (57240 - 63720 @ 2160), (40) @@ -1075,7 +1055,7 @@ country NL: DFS-ETSI (5900 - 5920 @ 10), (30) (5910 - 5930 @ 10), (30) # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (40), NO-OUTDOOR + (57000 - 66000 @ 2160), (40) country NO: DFS-ETSI (2402 - 2482 @ 40), (20) @@ -1092,7 +1072,7 @@ country NO: DFS-ETSI (5900 - 5920 @ 10), (30) (5910 - 5930 @ 10), (30) # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (40), NO-OUTDOOR + (57000 - 66000 @ 2160), (40) country NP: (2402 - 2482 @ 40), (20) @@ -1105,9 +1085,8 @@ country NZ: DFS-FCC (5250 - 5330 @ 80), (24), DFS, AUTO-BW (5490 - 5730 @ 160), (24), DFS (5735 - 5835 @ 80), (30) - # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (40), NO-OUTDOOR + (57000 - 66000 @ 2160), (40) country OM: DFS-ETSI (2402 - 2482 @ 40), (20) @@ -1147,9 +1126,8 @@ country PH: DFS-FCC (5250 - 5330 @ 80), (24), DFS, AUTO-BW (5490 - 5730 @ 160), (24), DFS (5735 - 5835 @ 80), (30) - # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (40), NO-OUTDOOR + (57000 - 66000 @ 2160), (40) country PK: (2402 - 2482 @ 40), (30) @@ -1170,7 +1148,7 @@ country PL: DFS-ETSI (5900 - 5920 @ 10), (30) (5910 - 5930 @ 10), (30) # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (40), NO-OUTDOOR + (57000 - 66000 @ 2160), (40) country PM: DFS-ETSI (2402 - 2482 @ 40), (20) @@ -1207,7 +1185,7 @@ country PT: DFS-ETSI (5900 - 5920 @ 10), (30) (5910 - 5930 @ 10), (30) # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (40), NO-OUTDOOR + (57000 - 66000 @ 2160), (40) country PW: DFS-FCC (2402 - 2472 @ 40), (30) @@ -1222,7 +1200,6 @@ country PY: DFS-FCC (5250 - 5330 @ 80), (24), DFS, AUTO-BW (5490 - 5730 @ 160), (24), DFS (5735 - 5835 @ 80), (30) - # 60 gHz band channels 1-3, FCC (57240 - 63720 @ 2160), (40) @@ -1251,7 +1228,7 @@ country RO: DFS-ETSI (5900 - 5920 @ 10), (30) (5910 - 5930 @ 10), (30) # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (40), NO-OUTDOOR + (57000 - 66000 @ 2160), (40) # Source: # http://www.ratel.rs/upload/documents/Plan_namene/Plan_namene-sl_glasnik.pdf @@ -1261,14 +1238,13 @@ country RS: DFS-ETSI (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (40), NO-OUTDOOR + (57000 - 66000 @ 2160), (40) country RU: (2402 - 2482 @ 40), (20) (5170 - 5330 @ 160), (23) (5490 - 5730 @ 160), (30) (5735 - 5835 @ 80), (30) - # 60 gHz band channels 1-4 (57240 - 65880 @ 2160), (40) @@ -1300,7 +1276,7 @@ country SE: DFS-ETSI (5900 - 5920 @ 10), (30) (5910 - 5930 @ 10), (30) # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (40), NO-OUTDOOR + (57000 - 66000 @ 2160), (40) country SG: DFS-FCC (2402 - 2482 @ 40), (20) @@ -1308,9 +1284,8 @@ country SG: DFS-FCC (5250 - 5330 @ 80), (24), DFS, AUTO-BW (5490 - 5730 @ 160), (24), DFS (5735 - 5835 @ 80), (30) - # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (40), NO-OUTDOOR + (57000 - 66000 @ 2160), (40), NO-OUTDOOR country SI: DFS-ETSI (2402 - 2482 @ 40), (20) @@ -1327,7 +1302,7 @@ country SI: DFS-ETSI (5900 - 5920 @ 10), (30) (5910 - 5930 @ 10), (30) # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (40), NO-OUTDOOR + (57000 - 66000 @ 2160), (40) country SK: DFS-ETSI (2402 - 2482 @ 40), (20) @@ -1344,7 +1319,7 @@ country SK: DFS-ETSI (5900 - 5920 @ 10), (30) (5910 - 5930 @ 10), (30) # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (40), NO-OUTDOOR + (57000 - 66000 @ 2160), (40) country SN: (2402 - 2482 @ 40), (20) @@ -1392,7 +1367,6 @@ country TH: DFS-FCC (5250 - 5330 @ 80), (24), DFS, AUTO-BW (5490 - 5730 @ 160), (24), DFS (5735 - 5835 @ 80), (30) - # 60 gHz band channels 1-4 (57240 - 65880 @ 2160), (40) @@ -1412,7 +1386,6 @@ country TT: (5170 - 5330 @ 160), (27) (5490 - 5730 @ 160), (36) (5735 - 5835 @ 80), (36) - # 60 gHz band channels 1-3, FCC (57240 - 63720 @ 2160), (40) @@ -1422,7 +1395,6 @@ country TW: DFS-FCC (5250 - 5330 @ 80), (24), DFS, AUTO-BW (5490 - 5730 @ 160), (24), DFS (5735 - 5835 @ 80), (30) - # 60 gHz band channels 1-3, FCC (57240 - 63720 @ 2160), (40) @@ -1481,7 +1453,6 @@ country UY: DFS-FCC (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5735 - 5835 @ 80), (30) - # 60 gHz band channels 1-4 (57240 - 65880 @ 2160), (40) @@ -1515,7 +1486,6 @@ country VN: DFS-FCC (5250 - 5330 @ 80), (24), DFS, AUTO-BW (5490 - 5730 @ 160), (24), DFS (5735 - 5835 @ 80), (30) - # 60 gHz band channels 1-4 (57240 - 65880 @ 2160), (40) @@ -1560,7 +1530,6 @@ country ZA: DFS-FCC (5250 - 5330 @ 80), (24), DFS, AUTO-BW (5490 - 5730 @ 160), (24), DFS (5735 - 5835 @ 80), (30) - # 60 gHz band channels 1-4 (57240 - 65880 @ 2160), (40), NO-OUTDOOR diff --git a/security/keys/gc.c b/security/keys/gc.c index addf060399e0..9cb4fe4478a1 100644 --- a/security/keys/gc.c +++ b/security/keys/gc.c @@ -46,7 +46,7 @@ static unsigned long key_gc_flags; * immediately unlinked. */ struct key_type key_type_dead = { - .name = "dead", + .name = ".dead", }; /* diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index 1c3872aeed14..442e350c209d 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c @@ -271,7 +271,8 @@ error: * Create and join an anonymous session keyring or join a named session * keyring, creating it if necessary. A named session keyring must have Search * permission for it to be joined. Session keyrings without this permit will - * be skipped over. + * be skipped over. It is not permitted for userspace to create or join + * keyrings whose name begin with a dot. * * If successful, the ID of the joined session keyring will be returned. */ @@ -288,12 +289,16 @@ long keyctl_join_session_keyring(const char __user *_name) ret = PTR_ERR(name); goto error; } + + ret = -EPERM; + if (name[0] == '.') + goto error_name; } /* join the session */ ret = join_session_keyring(name); +error_name: kfree(name); - error: return ret; } @@ -1223,8 +1228,8 @@ error: * Read or set the default keyring in which request_key() will cache keys and * return the old setting. * - * If a process keyring is specified then this will be created if it doesn't - * yet exist. The old setting will be returned if successful. + * If a thread or process keyring is specified then it will be created if it + * doesn't yet exist. The old setting will be returned if successful. */ long keyctl_set_reqkey_keyring(int reqkey_defl) { @@ -1249,11 +1254,8 @@ long keyctl_set_reqkey_keyring(int reqkey_defl) case KEY_REQKEY_DEFL_PROCESS_KEYRING: ret = install_process_keyring_to_cred(new); - if (ret < 0) { - if (ret != -EEXIST) - goto error; - ret = 0; - } + if (ret < 0) + goto error; goto set; case KEY_REQKEY_DEFL_DEFAULT: diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c index e6d50172872f..4ed909142956 100644 --- a/security/keys/process_keys.c +++ b/security/keys/process_keys.c @@ -125,13 +125,18 @@ error: } /* - * Install a fresh thread keyring directly to new credentials. This keyring is - * allowed to overrun the quota. + * Install a thread keyring to the given credentials struct if it didn't have + * one already. This is allowed to overrun the quota. + * + * Return: 0 if a thread keyring is now present; -errno on failure. */ int install_thread_keyring_to_cred(struct cred *new) { struct key *keyring; + if (new->thread_keyring) + return 0; + keyring = keyring_alloc("_tid", new->uid, new->gid, new, KEY_POS_ALL | KEY_USR_VIEW, KEY_ALLOC_QUOTA_OVERRUN, NULL); @@ -143,7 +148,9 @@ int install_thread_keyring_to_cred(struct cred *new) } /* - * Install a fresh thread keyring, discarding the old one. + * Install a thread keyring to the current task if it didn't have one already. + * + * Return: 0 if a thread keyring is now present; -errno on failure. */ static int install_thread_keyring(void) { @@ -154,8 +161,6 @@ static int install_thread_keyring(void) if (!new) return -ENOMEM; - BUG_ON(new->thread_keyring); - ret = install_thread_keyring_to_cred(new); if (ret < 0) { abort_creds(new); @@ -166,17 +171,17 @@ static int install_thread_keyring(void) } /* - * Install a process keyring directly to a credentials struct. + * Install a process keyring to the given credentials struct if it didn't have + * one already. This is allowed to overrun the quota. * - * Returns -EEXIST if there was already a process keyring, 0 if one installed, - * and other value on any other error + * Return: 0 if a process keyring is now present; -errno on failure. */ int install_process_keyring_to_cred(struct cred *new) { struct key *keyring; if (new->process_keyring) - return -EEXIST; + return 0; keyring = keyring_alloc("_pid", new->uid, new->gid, new, KEY_POS_ALL | KEY_USR_VIEW, @@ -189,11 +194,9 @@ int install_process_keyring_to_cred(struct cred *new) } /* - * Make sure a process keyring is installed for the current process. The - * existing process keyring is not replaced. + * Install a process keyring to the current task if it didn't have one already. * - * Returns 0 if there is a process keyring by the end of this function, some - * error otherwise. + * Return: 0 if a process keyring is now present; -errno on failure. */ static int install_process_keyring(void) { @@ -207,14 +210,18 @@ static int install_process_keyring(void) ret = install_process_keyring_to_cred(new); if (ret < 0) { abort_creds(new); - return ret != -EEXIST ? ret : 0; + return ret; } return commit_creds(new); } /* - * Install a session keyring directly to a credentials struct. + * Install the given keyring as the session keyring of the given credentials + * struct, replacing the existing one if any. If the given keyring is NULL, + * then install a new anonymous session keyring. + * + * Return: 0 on success; -errno on failure. */ int install_session_keyring_to_cred(struct cred *cred, struct key *keyring) { @@ -249,8 +256,11 @@ int install_session_keyring_to_cred(struct cred *cred, struct key *keyring) } /* - * Install a session keyring, discarding the old one. If a keyring is not - * supplied, an empty one is invented. + * Install the given keyring as the session keyring of the current task, + * replacing the existing one if any. If the given keyring is NULL, then + * install a new anonymous session keyring. + * + * Return: 0 on success; -errno on failure. */ static int install_session_keyring(struct key *keyring) { diff --git a/sound/core/seq/seq_lock.c b/sound/core/seq/seq_lock.c index 3b693e924db7..12ba83367b1b 100644 --- a/sound/core/seq/seq_lock.c +++ b/sound/core/seq/seq_lock.c @@ -28,19 +28,16 @@ /* wait until all locks are released */ void snd_use_lock_sync_helper(snd_use_lock_t *lockp, const char *file, int line) { - int max_count = 5 * HZ; + int warn_count = 5 * HZ; if (atomic_read(lockp) < 0) { pr_warn("ALSA: seq_lock: lock trouble [counter = %d] in %s:%d\n", atomic_read(lockp), file, line); return; } while (atomic_read(lockp) > 0) { - if (max_count == 0) { - pr_warn("ALSA: seq_lock: timeout [%d left] in %s:%d\n", atomic_read(lockp), file, line); - break; - } + if (warn_count-- == 0) + pr_warn("ALSA: seq_lock: waiting [%d left] in %s:%d\n", atomic_read(lockp), file, line); schedule_timeout_uninterruptible(1); - max_count--; } } diff --git a/sound/firewire/lib.h b/sound/firewire/lib.h index f3f6f84c48d6..bb5f8cdea3e2 100644 --- a/sound/firewire/lib.h +++ b/sound/firewire/lib.h @@ -42,7 +42,7 @@ struct snd_fw_async_midi_port { struct snd_rawmidi_substream *substream; snd_fw_async_midi_port_fill fill; - unsigned int consume_bytes; + int consume_bytes; }; int snd_fw_async_midi_port_init(struct snd_fw_async_midi_port *port, diff --git a/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c b/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c index c6074570bb50..6c702c8fc35f 100644 --- a/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c +++ b/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c @@ -30,6 +30,7 @@ #include "msm-digital-cdc.h" #include "msm-cdc-common.h" #include "../../msm/sdm660-common.h" +#include "../../../../drivers/base/regmap/internal.h" #define DRV_NAME "msm_digital_codec" #define MCLK_RATE_9P6MHZ 9600000 @@ -71,6 +72,8 @@ static int msm_digcdc_clock_control(bool flag) { int ret = -EINVAL; struct msm_asoc_mach_data *pdata = NULL; + struct msm_dig_priv *msm_dig_cdc = + snd_soc_codec_get_drvdata(registered_digcodec); pdata = snd_soc_card_get_drvdata(registered_digcodec->component.card); @@ -84,6 +87,12 @@ static int msm_digcdc_clock_control(bool flag) if (ret < 0) { pr_err("%s:failed to enable the MCLK\n", __func__); + /* + * Avoid access to lpass register + * as clock enable failed during SSR. + */ + if (ret == -ENODEV) + msm_dig_cdc->regmap->cache_only = true; mutex_unlock(&pdata->cdc_int_mclk0_mutex); return ret; } diff --git a/sound/soc/codecs/wsa881x-analog.c b/sound/soc/codecs/wsa881x-analog.c index fa1d099e082a..ff160dcb0952 100644 --- a/sound/soc/codecs/wsa881x-analog.c +++ b/sound/soc/codecs/wsa881x-analog.c @@ -1309,7 +1309,6 @@ static int wsa881x_i2c_probe(struct i2c_client *client, ret = -EINVAL; goto err; } - i2c_set_clientdata(client, pdata); dev_set_drvdata(&client->dev, client); pdata->regmap[WSA881X_DIGITAL_SLAVE] = @@ -1367,7 +1366,7 @@ err: static int wsa881x_i2c_remove(struct i2c_client *client) { - struct wsa881x_pdata *wsa881x = i2c_get_clientdata(client); + struct wsa881x_pdata *wsa881x = client->dev.platform_data; snd_soc_unregister_codec(&client->dev); i2c_set_clientdata(client, NULL); @@ -1414,6 +1413,7 @@ static struct i2c_driver wsa881x_codec_driver = { .driver = { .name = "wsa881x-i2c-codec", .owner = THIS_MODULE, + .probe_type = PROBE_PREFER_ASYNCHRONOUS, #ifdef CONFIG_PM_SLEEP .pm = &wsa881x_i2c_pm_ops, #endif diff --git a/sound/soc/msm/qdsp6v2/audio_cal_utils.c b/sound/soc/msm/qdsp6v2/audio_cal_utils.c index 0194dc4d58f1..4f2531a3da63 100644 --- a/sound/soc/msm/qdsp6v2/audio_cal_utils.c +++ b/sound/soc/msm/qdsp6v2/audio_cal_utils.c @@ -643,7 +643,9 @@ done: return cal_block; err: kfree(cal_block->cal_info); + cal_block->cal_info = NULL; kfree(cal_block->client_info); + cal_block->client_info = NULL; kfree(cal_block); cal_block = NULL; return cal_block; diff --git a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c index 5bd3b6d7014e..426b4d0b0a35 100644 --- a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c @@ -302,6 +302,39 @@ exit: return ret; } +static int msm_compr_enable_adjust_session_clock(struct audio_client *ac, + bool enable) +{ + int ret; + + pr_debug("%s, enable adjust_session %d\n", __func__, enable); + + ret = q6asm_send_mtmx_strtr_enable_adjust_session_clock(ac, enable); + if (ret) + pr_err("%s, adjust session clock can't be set error %d\n", + __func__, ret); + + return ret; +} + +static int msm_compr_adjust_session_clock(struct audio_client *ac, + uint32_t adjust_session_lsw, uint32_t adjust_session_msw) +{ + int ret; + + pr_debug("%s, adjust_session_time_msw 0x%x adjust_session_time_lsw 0x%x\n", + __func__, adjust_session_msw, adjust_session_lsw); + + ret = q6asm_adjust_session_clock(ac, + adjust_session_lsw, + adjust_session_msw); + if (ret) + pr_err("%s, adjust session clock can't be set error %d\n", + __func__, ret); + + return ret; +} + static int msm_compr_set_volume(struct snd_compr_stream *cstream, uint32_t volume_l, uint32_t volume_r) { @@ -716,8 +749,7 @@ static void compr_event_handler(uint32_t opcode, return; } - ret = msm_adsp_inform_mixer_ctl(rtd, DSP_STREAM_CALLBACK, - payload); + ret = msm_adsp_inform_mixer_ctl(rtd, payload); if (ret) { pr_err("%s: failed to inform mixer ctrl. err = %d\n", __func__, ret); @@ -1550,6 +1582,7 @@ static int msm_compr_playback_open(struct snd_compr_stream *cstream) pr_debug("%s: session ID %d\n", __func__, prtd->audio_client->session); prtd->audio_client->perf_mode = false; prtd->session_id = prtd->audio_client->session; + msm_adsp_init_mixer_ctl_pp_event_queue(rtd); return 0; } @@ -1705,7 +1738,7 @@ static int msm_compr_playback_free(struct snd_compr_stream *cstream) q6asm_audio_client_buf_free_contiguous(dir, ac); q6asm_audio_client_free(ac); - + msm_adsp_clean_mixer_ctl_pp_event_queue(soc_prtd); kfree(pdata->audio_effects[soc_prtd->dai_link->be_id]); pdata->audio_effects[soc_prtd->dai_link->be_id] = NULL; kfree(pdata->dec_params[soc_prtd->dai_link->be_id]); @@ -2875,6 +2908,14 @@ static int msm_compr_set_metadata(struct snd_compr_stream *cstream, } else if (metadata->key == SNDRV_COMPRESS_START_DELAY) { prtd->start_delay_lsw = metadata->value[0]; prtd->start_delay_msw = metadata->value[1]; + } else if (metadata->key == + SNDRV_COMPRESS_ENABLE_ADJUST_SESSION_CLOCK) { + return msm_compr_enable_adjust_session_clock(ac, + metadata->value[0]); + } else if (metadata->key == SNDRV_COMPRESS_ADJUST_SESSION_CLOCK) { + return msm_compr_adjust_session_clock(ac, + metadata->value[0], + metadata->value[1]); } return 0; @@ -3937,7 +3978,6 @@ static int msm_compr_add_audio_adsp_stream_callback_control( .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, .info = msm_adsp_stream_callback_info, .get = msm_adsp_stream_callback_get, - .put = msm_adsp_stream_callback_put, .private_value = 0, } }; @@ -3978,6 +4018,7 @@ static int msm_compr_add_audio_adsp_stream_callback_control( } kctl->private_data = NULL; + free_mixer_str: kfree(mixer_str); done: diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-hdmi-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-hdmi-v2.c index 26b7f3f26b26..45868f508a60 100644 --- a/sound/soc/msm/qdsp6v2/msm-dai-q6-hdmi-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-hdmi-v2.c @@ -174,7 +174,7 @@ static const struct snd_kcontrol_new hdmi_config_controls[] = { { .access = SNDRV_CTL_ELEM_ACCESS_READ, .iface = SNDRV_CTL_ELEM_IFACE_PCM, - .name = "HDMI RX Drift", + .name = "HDMI Drift", .info = msm_dai_q6_ext_disp_drift_info, .get = msm_dai_q6_ext_disp_drift_get, }, @@ -191,7 +191,7 @@ static const struct snd_kcontrol_new display_port_config_controls[] = { { .access = SNDRV_CTL_ELEM_ACCESS_READ, .iface = SNDRV_CTL_ELEM_IFACE_PCM, - .name = "DISPLAY Port RX Drift", + .name = "DISPLAY_PORT Drift", .info = msm_dai_q6_ext_disp_drift_info, .get = msm_dai_q6_ext_disp_drift_get, }, diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c index 201ca652c10b..9ed61288a3e4 100644 --- a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c @@ -2321,6 +2321,44 @@ static const struct snd_kcontrol_new afe_enc_config_controls[] = { msm_dai_q6_afe_input_bit_format_put), }; +static int msm_dai_q6_slim_rx_drift_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; + uinfo->count = sizeof(struct afe_param_id_dev_timing_stats); + + return 0; +} + +static int msm_dai_q6_slim_rx_drift_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int ret = -EINVAL; + struct afe_param_id_dev_timing_stats timing_stats; + struct snd_soc_dai *dai = kcontrol->private_data; + struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev); + + if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) { + pr_err("%s: afe port not started. dai_data->status_mask = %ld\n", + __func__, *dai_data->status_mask); + goto done; + } + + memset(&timing_stats, 0, sizeof(struct afe_param_id_dev_timing_stats)); + ret = afe_get_av_dev_drift(&timing_stats, dai->id); + if (ret) { + pr_err("%s: Error getting AFE Drift for port %d, err=%d\n", + __func__, dai->id, ret); + + goto done; + } + + memcpy(ucontrol->value.bytes.data, (void *)&timing_stats, + sizeof(struct afe_param_id_dev_timing_stats)); +done: + return ret; +} + static const char * const afe_cal_mode_text[] = { "CAL_MODE_DEFAULT", "CAL_MODE_NONE" }; @@ -2373,6 +2411,29 @@ static const struct snd_kcontrol_new usb_audio_cfg_controls[] = { msm_dai_q6_usb_audio_endian_cfg_put), }; +static const struct snd_kcontrol_new avd_drift_config_controls[] = { + { + .access = SNDRV_CTL_ELEM_ACCESS_READ, + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "SLIMBUS_0_RX DRIFT", + .info = msm_dai_q6_slim_rx_drift_info, + .get = msm_dai_q6_slim_rx_drift_get, + }, + { + .access = SNDRV_CTL_ELEM_ACCESS_READ, + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "SLIMBUS_6_RX DRIFT", + .info = msm_dai_q6_slim_rx_drift_info, + .get = msm_dai_q6_slim_rx_drift_get, + }, + { + .access = SNDRV_CTL_ELEM_ACCESS_READ, + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "SLIMBUS_7_RX DRIFT", + .info = msm_dai_q6_slim_rx_drift_info, + .get = msm_dai_q6_slim_rx_drift_get, + }, +}; static int msm_dai_q6_dai_probe(struct snd_soc_dai *dai) { struct msm_dai_q6_dai_data *dai_data; @@ -2422,6 +2483,9 @@ static int msm_dai_q6_dai_probe(struct snd_soc_dai *dai) rc = snd_ctl_add(dai->component->card->snd_card, snd_ctl_new1(&afe_enc_config_controls[2], dai_data)); + rc = snd_ctl_add(dai->component->card->snd_card, + snd_ctl_new1(&avd_drift_config_controls[2], + dai)); break; case RT_PROXY_DAI_001_RX: rc = snd_ctl_add(dai->component->card->snd_card, @@ -2449,6 +2513,16 @@ static int msm_dai_q6_dai_probe(struct snd_soc_dai *dai) snd_ctl_new1(&usb_audio_cfg_controls[3], dai_data)); break; + case SLIMBUS_0_RX: + rc = snd_ctl_add(dai->component->card->snd_card, + snd_ctl_new1(&avd_drift_config_controls[0], + dai)); + break; + case SLIMBUS_6_RX: + rc = snd_ctl_add(dai->component->card->snd_card, + snd_ctl_new1(&avd_drift_config_controls[1], + dai)); + break; } if (IS_ERR_VALUE(rc)) dev_err(dai->dev, "%s: err add config ctl, DAI = %s\n", diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c index 73eadfa4eebb..8f43aee3974c 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c @@ -239,8 +239,7 @@ static void event_handler(uint32_t opcode, return; } - ret = msm_adsp_inform_mixer_ctl(rtd, DSP_STREAM_CALLBACK, - payload); + ret = msm_adsp_inform_mixer_ctl(rtd, payload); if (ret) { pr_err("%s: failed to inform mixer ctl. err = %d\n", __func__, ret); @@ -691,6 +690,7 @@ static int msm_pcm_open(struct snd_pcm_substream *substream) prtd->set_channel_map = false; prtd->reset_event = false; runtime->private_data = prtd; + msm_adsp_init_mixer_ctl_pp_event_queue(soc_prtd); return 0; } @@ -833,6 +833,7 @@ static int msm_pcm_playback_close(struct snd_pcm_substream *substream) } msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->be_id, SNDRV_PCM_STREAM_PLAYBACK); + msm_adsp_clean_mixer_ctl_pp_event_queue(soc_prtd); kfree(prtd); runtime->private_data = NULL; @@ -1187,7 +1188,6 @@ static int msm_pcm_add_audio_adsp_stream_callback_control( .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, .info = msm_adsp_stream_callback_info, .get = msm_adsp_stream_callback_get, - .put = msm_adsp_stream_callback_put, .private_value = 0, } }; @@ -1231,6 +1231,7 @@ static int msm_pcm_add_audio_adsp_stream_callback_control( } kctl->private_data = NULL; + free_mixer_str: kfree(mixer_str); done: diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c index e199a6a0de0b..0f63fd6bbd00 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c @@ -8115,6 +8115,9 @@ static const struct snd_kcontrol_new primary_mi2s_rx_port_mixer_controls[] = { SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_PRI_MI2S_RX, MSM_BACKEND_DAI_SLIMBUS_0_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), + SOC_SINGLE_EXT("SLIM_8_TX", MSM_BACKEND_DAI_PRI_MI2S_RX, + MSM_BACKEND_DAI_SLIMBUS_8_TX, 1, 0, msm_routing_get_port_mixer, + msm_routing_put_port_mixer), }; static const struct snd_kcontrol_new usb_rx_port_mixer_controls[] = { @@ -8145,6 +8148,9 @@ static const struct snd_kcontrol_new quat_mi2s_rx_port_mixer_controls[] = { SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), + SOC_SINGLE_EXT("SLIM_8_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, + MSM_BACKEND_DAI_SLIMBUS_8_TX, 1, 0, msm_routing_get_port_mixer, + msm_routing_put_port_mixer), }; static const struct snd_kcontrol_new pri_tdm_rx_0_port_mixer_controls[] = { @@ -9235,6 +9241,9 @@ static const struct snd_kcontrol_new tert_mi2s_rx_port_mixer_controls[] = { SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_RX, MSM_BACKEND_DAI_SECONDARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), + SOC_SINGLE_EXT("SLIM_8_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_RX, + MSM_BACKEND_DAI_SLIMBUS_8_TX, 1, 0, msm_routing_get_port_mixer, + msm_routing_put_port_mixer), }; static const struct snd_kcontrol_new sec_mi2s_rx_port_mixer_controls[] = { @@ -9256,6 +9265,9 @@ static const struct snd_kcontrol_new sec_mi2s_rx_port_mixer_controls[] = { SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_SECONDARY_MI2S_RX, MSM_BACKEND_DAI_INT_FM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), + SOC_SINGLE_EXT("SLIM_8_TX", MSM_BACKEND_DAI_SECONDARY_MI2S_RX, + MSM_BACKEND_DAI_SLIMBUS_8_TX, 1, 0, msm_routing_get_port_mixer, + msm_routing_put_port_mixer), }; static const struct snd_kcontrol_new lsm1_mixer_controls[] = { @@ -13881,6 +13893,7 @@ static const struct snd_soc_dapm_route intercon[] = { {"PRI_MI2S_RX Port Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"}, {"PRI_MI2S_RX Port Mixer", "INTERNAL_FM_TX", "INT_FM_TX"}, {"PRI_MI2S_RX Port Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"}, + {"PRI_MI2S_RX Port Mixer", "SLIM_8_TX", "SLIMBUS_8_TX"}, {"PRI_MI2S_RX", NULL, "PRI_MI2S_RX Port Mixer"}, {"SEC_MI2S_RX Port Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"}, @@ -13889,6 +13902,7 @@ static const struct snd_soc_dapm_route intercon[] = { {"SEC_MI2S_RX Port Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"}, {"SEC_MI2S_RX Port Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"}, {"SEC_MI2S_RX Port Mixer", "INTERNAL_FM_TX", "INT_FM_TX"}, + {"SEC_MI2S_RX Port Mixer", "SLIM_8_TX", "SLIMBUS_8_TX"}, {"SEC_MI2S_RX", NULL, "SEC_MI2S_RX Port Mixer"}, {"TERT_MI2S_RX Port Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"}, @@ -13896,6 +13910,7 @@ static const struct snd_soc_dapm_route intercon[] = { {"TERT_MI2S_RX Port Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"}, {"TERT_MI2S_RX Port Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"}, {"TERT_MI2S_RX Port Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"}, + {"TERT_MI2S_RX Port Mixer", "SLIM_8_TX", "SLIMBUS_8_TX"}, {"TERT_MI2S_RX", NULL, "TERT_MI2S_RX Port Mixer"}, {"QUAT_MI2S_RX Port Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"}, @@ -13905,6 +13920,7 @@ static const struct snd_soc_dapm_route intercon[] = { {"QUAT_MI2S_RX Port Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"}, {"QUAT_MI2S_RX Port Mixer", "INTERNAL_FM_TX", "INT_FM_TX"}, {"QUAT_MI2S_RX Port Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"}, + {"QUAT_MI2S_RX Port Mixer", "SLIM_8_TX", "SLIMBUS_8_TX"}, {"QUAT_MI2S_RX", NULL, "QUAT_MI2S_RX Port Mixer"}, /* Backend Enablement */ diff --git a/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c b/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c index d4e78604f868..cac28f43e5ae 100644 --- a/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c +++ b/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c @@ -45,21 +45,6 @@ enum { EQ_BAND_MAX, }; -struct msm_audio_eq_band { - uint16_t band_idx; /* The band index, 0 .. 11 */ - uint32_t filter_type; /* Filter band type */ - uint32_t center_freq_hz; /* Filter band center frequency */ - uint32_t filter_gain; /* Filter band initial gain (dB) */ - /* Range is +12 dB to -12 dB with 1dB increments. */ - uint32_t q_factor; -} __packed; - -struct msm_audio_eq_stream_config { - uint32_t enable; /* Number of consequtive bands specified */ - uint32_t num_bands; - struct msm_audio_eq_band eq_bands[EQ_BAND_MAX]; -} __packed; - /* Audio Sphere data structures */ struct msm_audio_pp_asphere_state_s { uint32_t enabled; @@ -817,18 +802,133 @@ static int msm_qti_pp_asphere_set(struct snd_kcontrol *kcontrol, return 0; } +int msm_adsp_init_mixer_ctl_pp_event_queue(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_kcontrol *kctl; + const char *deviceNo = "NN"; + char *mixer_str = NULL; + int ctl_len = 0, ret = 0; + const char *mixer_ctl_name = DSP_STREAM_CALLBACK; + struct dsp_stream_callback_prtd *kctl_prtd = NULL; + + if (!rtd) { + pr_err("%s: rtd is NULL\n", __func__); + ret = -EINVAL; + goto done; + } + + ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1; + mixer_str = kzalloc(ctl_len, GFP_KERNEL); + if (!mixer_str) { + ret = -EINVAL; + goto done; + } + + snprintf(mixer_str, ctl_len, "%s %d", mixer_ctl_name, + rtd->pcm->device); + kctl = snd_soc_card_get_kcontrol(rtd->card, mixer_str); + kfree(mixer_str); + if (!kctl) { + pr_err("%s: failed to get kctl.\n", __func__); + ret = -EINVAL; + goto done; + } + + if (kctl->private_data != NULL) { + pr_err("%s: kctl_prtd is not NULL at initialization.\n", + __func__); + return -EINVAL; + } + + kctl_prtd = kzalloc(sizeof(struct dsp_stream_callback_prtd), + GFP_KERNEL); + if (!kctl_prtd) { + ret = -ENOMEM; + goto done; + } + + spin_lock_init(&kctl_prtd->prtd_spin_lock); + INIT_LIST_HEAD(&kctl_prtd->event_queue); + kctl_prtd->event_count = 0; + kctl->private_data = kctl_prtd; + +done: + return ret; +} + +int msm_adsp_clean_mixer_ctl_pp_event_queue(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_kcontrol *kctl; + const char *deviceNo = "NN"; + char *mixer_str = NULL; + int ctl_len = 0, ret = 0; + struct dsp_stream_callback_list *node, *n; + unsigned long spin_flags; + const char *mixer_ctl_name = DSP_STREAM_CALLBACK; + struct dsp_stream_callback_prtd *kctl_prtd = NULL; + + if (!rtd) { + pr_err("%s: rtd is NULL\n", __func__); + ret = -EINVAL; + goto done; + } + + ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1; + mixer_str = kzalloc(ctl_len, GFP_KERNEL); + if (!mixer_str) { + ret = -EINVAL; + goto done; + } + + snprintf(mixer_str, ctl_len, "%s %d", mixer_ctl_name, + rtd->pcm->device); + kctl = snd_soc_card_get_kcontrol(rtd->card, mixer_str); + kfree(mixer_str); + if (!kctl) { + pr_err("%s: failed to get kctl.\n", __func__); + ret = -EINVAL; + goto done; + } + + kctl_prtd = (struct dsp_stream_callback_prtd *) + kctl->private_data; + if (kctl_prtd != NULL) { + spin_lock_irqsave(&kctl_prtd->prtd_spin_lock, spin_flags); + /* clean the queue */ + list_for_each_entry_safe(node, n, + &kctl_prtd->event_queue, list) { + list_del(&node->list); + kctl_prtd->event_count--; + pr_debug("%s: %d remaining events after del.\n", + __func__, kctl_prtd->event_count); + kfree(node); + } + spin_unlock_irqrestore(&kctl_prtd->prtd_spin_lock, spin_flags); + } + + kfree(kctl_prtd); + kctl->private_data = NULL; + +done: + return ret; +} int msm_adsp_inform_mixer_ctl(struct snd_soc_pcm_runtime *rtd, - const char *mixer_ctl_name, uint32_t *payload) { /* adsp pp event notifier */ struct snd_kcontrol *kctl; struct snd_ctl_elem_value control; - uint32_t payload_size = 0; const char *deviceNo = "NN"; char *mixer_str = NULL; int ctl_len = 0, ret = 0; + struct dsp_stream_callback_list *new_event; + struct dsp_stream_callback_list *oldest_event; + unsigned long spin_flags; + struct dsp_stream_callback_prtd *kctl_prtd = NULL; + struct msm_adsp_event_data *event_data = NULL; + const char *mixer_ctl_name = DSP_STREAM_CALLBACK; + struct snd_ctl_elem_info kctl_info; if (!rtd || !payload) { pr_err("%s: %s is NULL\n", __func__, @@ -837,6 +937,12 @@ int msm_adsp_inform_mixer_ctl(struct snd_soc_pcm_runtime *rtd, goto done; } + if (rtd->card->snd_card == NULL) { + pr_err("%s: snd_card is null.\n", __func__); + ret = -EINVAL; + goto done; + } + ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1; mixer_str = kzalloc(ctl_len, GFP_ATOMIC); if (!mixer_str) { @@ -854,21 +960,59 @@ int msm_adsp_inform_mixer_ctl(struct snd_soc_pcm_runtime *rtd, goto done; } - control.id = kctl->id; - payload_size = payload[0]; - /* Copy complete payload */ - memcpy(control.value.bytes.data, (void *)payload, - sizeof(payload_size) + payload_size); - kctl->put(kctl, &control); - if (rtd->card->snd_card == NULL) { - pr_err("%s: snd_card is null.\n", __func__); + event_data = (struct msm_adsp_event_data *)payload; + kctl->info(kctl, &kctl_info); + if (sizeof(struct msm_adsp_event_data) + + event_data->payload_len > kctl_info.count) { + pr_err("%s: payload length exceeds limit of %u bytes.\n", + __func__, kctl_info.count); ret = -EINVAL; goto done; } + kctl_prtd = (struct dsp_stream_callback_prtd *) + kctl->private_data; + if (kctl_prtd == NULL) { + /* queue is not initialized */ + ret = -EINVAL; + pr_err("%s: event queue is not initialized.\n", __func__); + goto done; + } + + new_event = kzalloc(sizeof(struct dsp_stream_callback_list) + + event_data->payload_len, + GFP_ATOMIC); + if (new_event == NULL) { + ret = -ENOMEM; + goto done; + } + memcpy((void *)&new_event->event, (void *)payload, + event_data->payload_len + + sizeof(struct msm_adsp_event_data)); + + spin_lock_irqsave(&kctl_prtd->prtd_spin_lock, spin_flags); + while (kctl_prtd->event_count >= DSP_STREAM_CALLBACK_QUEUE_SIZE) { + pr_info("%s: queue of size %d is full. delete oldest one.\n", + __func__, DSP_STREAM_CALLBACK_QUEUE_SIZE); + oldest_event = list_first_entry(&kctl_prtd->event_queue, + struct dsp_stream_callback_list, list); + pr_info("%s: event deleted: type %d length %d\n", + __func__, oldest_event->event.event_type, + oldest_event->event.payload_len); + list_del(&oldest_event->list); + kctl_prtd->event_count--; + kfree(oldest_event); + } + + list_add_tail(&new_event->list, &kctl_prtd->event_queue); + kctl_prtd->event_count++; + spin_unlock_irqrestore(&kctl_prtd->prtd_spin_lock, spin_flags); + + control.id = kctl->id; snd_ctl_notify(rtd->card->snd_card, SNDRV_CTL_EVENT_MASK_INFO, &control.id); + done: return ret; } @@ -877,44 +1021,8 @@ int msm_adsp_stream_cmd_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; - uinfo->count = 512; - - return 0; -} - -int msm_adsp_stream_callback_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - uint32_t payload_size = 0, last_payload_size = 0; - - /* fetch payload size in first four bytes */ - memcpy(&payload_size, ucontrol->value.bytes.data, sizeof(uint32_t)); - - if (kcontrol->private_data == NULL) { - /* buffer is empty */ - kcontrol->private_data = - kzalloc(payload_size + sizeof(payload_size), - GFP_ATOMIC); - if (kcontrol->private_data == NULL) - return -ENOMEM; - } else { - memcpy(&last_payload_size, kcontrol->private_data, - sizeof(uint32_t)); - if (last_payload_size < payload_size) { - /* new payload size exceeds old one. - * reallocate buffer - */ - kfree(kcontrol->private_data); - kcontrol->private_data = - kzalloc(payload_size + sizeof(payload_size), - GFP_ATOMIC); - if (kcontrol->private_data == NULL) - return -ENOMEM; - } - } - - memcpy(kcontrol->private_data, ucontrol->value.bytes.data, - sizeof(uint32_t) + payload_size); + uinfo->count = + sizeof(((struct snd_ctl_elem_value *)0)->value.bytes.data); return 0; } @@ -923,26 +1031,53 @@ int msm_adsp_stream_callback_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { uint32_t payload_size = 0; + struct dsp_stream_callback_list *oldest_event; + unsigned long spin_flags; + struct dsp_stream_callback_prtd *kctl_prtd = NULL; + int ret = 0; - if (kcontrol->private_data == NULL) { - pr_err("%s: ASM Stream PP Event Data Unavailable\n", __func__); - return -EINVAL; + kctl_prtd = (struct dsp_stream_callback_prtd *) + kcontrol->private_data; + if (kctl_prtd == NULL) { + pr_err("%s: ASM Stream PP event queue is not initialized.\n", + __func__); + ret = -EINVAL; + goto done; + } + + spin_lock_irqsave(&kctl_prtd->prtd_spin_lock, spin_flags); + pr_debug("%s: %d events in queue.\n", __func__, kctl_prtd->event_count); + if (list_empty(&kctl_prtd->event_queue)) { + pr_err("%s: ASM Stream PP event queue is empty.\n", __func__); + ret = -EINVAL; + spin_unlock_irqrestore(&kctl_prtd->prtd_spin_lock, spin_flags); + goto done; } - memcpy(&payload_size, kcontrol->private_data, sizeof(uint32_t)); - memcpy(ucontrol->value.bytes.data, kcontrol->private_data, - sizeof(uint32_t) + payload_size); - kfree(kcontrol->private_data); - kcontrol->private_data = NULL; + oldest_event = list_first_entry(&kctl_prtd->event_queue, + struct dsp_stream_callback_list, list); + list_del(&oldest_event->list); + kctl_prtd->event_count--; + spin_unlock_irqrestore(&kctl_prtd->prtd_spin_lock, spin_flags); - return 0; + payload_size = oldest_event->event.payload_len; + pr_debug("%s: event fetched: type %d length %d\n", + __func__, oldest_event->event.event_type, + oldest_event->event.payload_len); + memcpy(ucontrol->value.bytes.data, &oldest_event->event, + sizeof(struct msm_adsp_event_data) + payload_size); + kfree(oldest_event); + +done: + return ret; } int msm_adsp_stream_callback_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; - uinfo->count = 512; + uinfo->count = + sizeof(((struct snd_ctl_elem_value *)0)->value.bytes.data); return 0; } diff --git a/sound/soc/msm/qdsp6v2/msm-qti-pp-config.h b/sound/soc/msm/qdsp6v2/msm-qti-pp-config.h index 70ce20fbd8f8..6ffcbdbd543e 100644 --- a/sound/soc/msm/qdsp6v2/msm-qti-pp-config.h +++ b/sound/soc/msm/qdsp6v2/msm-qti-pp-config.h @@ -14,12 +14,11 @@ #include <sound/soc.h> int msm_adsp_inform_mixer_ctl(struct snd_soc_pcm_runtime *rtd, - const char *mixer_ctl_name, uint32_t *payload); +int msm_adsp_init_mixer_ctl_pp_event_queue(struct snd_soc_pcm_runtime *rtd); +int msm_adsp_clean_mixer_ctl_pp_event_queue(struct snd_soc_pcm_runtime *rtd); int msm_adsp_stream_cmd_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo); -int msm_adsp_stream_callback_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol); int msm_adsp_stream_callback_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); int msm_adsp_stream_callback_info(struct snd_kcontrol *kcontrol, diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c index 0cf386a3c2fc..4aebcb6fa77e 100644 --- a/sound/soc/msm/qdsp6v2/q6asm.c +++ b/sound/soc/msm/qdsp6v2/q6asm.c @@ -1675,7 +1675,7 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) int32_t ret = 0; union asm_token_struct asm_token; uint8_t buf_index; - char *pp_event_package = NULL; + struct msm_adsp_event_data *pp_event_package = NULL; uint32_t payload_size = 0; if (ac == NULL) { @@ -2046,22 +2046,29 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) pr_debug("%s: ASM_STREAM_PP_EVENT payload[0][0x%x] payload[1][0x%x]", __func__, payload[0], payload[1]); /* repack payload for asm_stream_pp_event - * package is composed of size + actual payload + * package is composed of event type + size + actual payload */ payload_size = data->payload_size; - pp_event_package = - kzalloc(payload_size + sizeof(payload_size), + pp_event_package = kzalloc(payload_size + + sizeof(struct msm_adsp_event_data), GFP_ATOMIC); if (!pp_event_package) return -ENOMEM; - memcpy((void *)pp_event_package, - &payload_size, sizeof(payload_size)); - memcpy((void *)pp_event_package + sizeof(payload_size), + + pp_event_package->event_type = ASM_STREAM_PP_EVENT; + pp_event_package->payload_len = payload_size; + memcpy((void *)pp_event_package->payload, data->payload, payload_size); ac->cb(data->opcode, data->token, (void *)pp_event_package, ac->priv); kfree(pp_event_package); return 0; + case ASM_SESSION_CMDRSP_ADJUST_SESSION_CLOCK_V2: + pr_debug("%s: ASM_SESSION_CMDRSP_ADJUST_SESSION_CLOCK_V2 sesion %d status 0x%x msw %u lsw %u\n", + __func__, ac->session, payload[0], payload[2], + payload[1]); + wake_up(&ac->cmd_wait); + break; case ASM_SESSION_CMDRSP_GET_PATH_DELAY_V2: pr_debug("%s: ASM_SESSION_CMDRSP_GET_PATH_DELAY_V2 session %d status 0x%x msw %u lsw %u\n", __func__, ac->session, payload[0], payload[2], @@ -2602,7 +2609,9 @@ int q6asm_open_write_compressed(struct audio_client *ac, uint32_t format, case FORMAT_GEN_COMPR: open.fmt_id = ASM_MEDIA_FMT_GENERIC_COMPRESSED; break; - + case FORMAT_TRUEHD: + open.fmt_id = ASM_MEDIA_FMT_TRUEHD; + break; default: pr_err("%s: Invalid format[%d]\n", __func__, format); rc = -EINVAL; @@ -2775,9 +2784,6 @@ static int __q6asm_open_write(struct audio_client *ac, uint32_t format, case FORMAT_GEN_COMPR: open.dec_fmt_id = ASM_MEDIA_FMT_GENERIC_COMPRESSED; break; - case FORMAT_TRUEHD: - open.dec_fmt_id = ASM_MEDIA_FMT_TRUEHD; - break; default: pr_err("%s: Invalid format 0x%x\n", __func__, format); rc = -EINVAL; @@ -8039,6 +8045,80 @@ exit: return rc; } +int q6asm_send_mtmx_strtr_enable_adjust_session_clock(struct audio_client *ac, + bool enable) +{ + struct asm_mtmx_strtr_params matrix; + struct asm_session_mtmx_param_adjust_session_time_ctl_t adjust_time; + int sz = 0; + int rc = 0; + + pr_debug("%s: adjust session enable %d\n", __func__, enable); + + if (!ac) { + pr_err("%s: audio client handle is NULL\n", __func__); + rc = -EINVAL; + goto exit; + } + + if (ac->apr == NULL) { + pr_err("%s: ac->apr is NULL\n", __func__); + rc = -EINVAL; + goto exit; + } + + adjust_time.enable = enable; + memset(&matrix, 0, sizeof(struct asm_mtmx_strtr_params)); + sz = sizeof(struct asm_mtmx_strtr_params); + q6asm_add_hdr(ac, &matrix.hdr, sz, TRUE); + atomic_set(&ac->cmd_state, -1); + matrix.hdr.opcode = ASM_SESSION_CMD_SET_MTMX_STRTR_PARAMS_V2; + + matrix.param.data_payload_addr_lsw = 0; + matrix.param.data_payload_addr_msw = 0; + matrix.param.mem_map_handle = 0; + matrix.param.data_payload_size = + sizeof(struct asm_stream_param_data_v2) + + sizeof(struct asm_session_mtmx_param_adjust_session_time_ctl_t); + matrix.param.direction = 0; /* RX */ + matrix.data.module_id = ASM_SESSION_MTMX_STRTR_MODULE_ID_AVSYNC; + matrix.data.param_id = ASM_SESSION_MTMX_PARAM_ADJUST_SESSION_TIME_CTL; + matrix.data.param_size = + sizeof(struct asm_session_mtmx_param_adjust_session_time_ctl_t); + matrix.data.reserved = 0; + matrix.config.adj_time_param.enable = adjust_time.enable; + + rc = apr_send_pkt(ac->apr, (uint32_t *) &matrix); + if (rc < 0) { + pr_err("%s: enable adjust session failed failed paramid [0x%x]\n", + __func__, matrix.data.param_id); + rc = -EINVAL; + goto exit; + } + + rc = wait_event_timeout(ac->cmd_wait, + (atomic_read(&ac->cmd_state) >= 0), 5*HZ); + if (!rc) { + pr_err("%s: enable adjust session failed failed paramid [0x%x]\n", + __func__, matrix.data.param_id); + rc = -ETIMEDOUT; + goto exit; + } + + if (atomic_read(&ac->cmd_state) > 0) { + pr_err("%s: DSP returned error[%s]\n", + __func__, adsp_err_get_err_str( + atomic_read(&ac->cmd_state))); + rc = adsp_err_get_lnx_err_code( + atomic_read(&ac->cmd_state)); + goto exit; + } + rc = 0; +exit: + return rc; +} + + static int __q6asm_cmd(struct audio_client *ac, int cmd, uint32_t stream_id) { struct apr_hdr hdr; @@ -8428,6 +8508,68 @@ fail_cmd: return -EINVAL; } +int q6asm_adjust_session_clock(struct audio_client *ac, + uint32_t adjust_time_lsw, + uint32_t adjust_time_msw) +{ + int rc = 0; + int sz = 0; + struct asm_session_cmd_adjust_session_clock_v2 adjust_clock; + + pr_debug("%s: adjust_time_lsw is %x, adjust_time_msw is %x\n", __func__, + adjust_time_lsw, adjust_time_msw); + + if (!ac) { + pr_err("%s: audio client handle is NULL\n", __func__); + rc = -EINVAL; + goto fail_cmd; + } + + if (ac->apr == NULL) { + pr_err("%s: ac->apr is NULL", __func__); + rc = -EINVAL; + goto fail_cmd; + } + + sz = sizeof(struct asm_session_cmd_adjust_session_clock_v2); + q6asm_add_hdr(ac, &adjust_clock.hdr, sz, TRUE); + atomic_set(&ac->cmd_state, -1); + adjust_clock.hdr.opcode = ASM_SESSION_CMD_ADJUST_SESSION_CLOCK_V2; + + adjust_clock.adjustime_lsw = adjust_time_lsw; + adjust_clock.adjustime_msw = adjust_time_msw; + + + rc = apr_send_pkt(ac->apr, (uint32_t *) &adjust_clock); + if (rc < 0) { + pr_err("%s: adjust_clock send failed paramid [0x%x]\n", + __func__, adjust_clock.hdr.opcode); + rc = -EINVAL; + goto fail_cmd; + } + + rc = wait_event_timeout(ac->cmd_wait, + (atomic_read(&ac->cmd_state) >= 0), 5*HZ); + if (!rc) { + pr_err("%s: timeout, adjust_clock paramid[0x%x]\n", + __func__, adjust_clock.hdr.opcode); + rc = -ETIMEDOUT; + goto fail_cmd; + } + + if (atomic_read(&ac->cmd_state) > 0) { + pr_err("%s: DSP returned error[%s]\n", + __func__, adsp_err_get_err_str( + atomic_read(&ac->cmd_state))); + rc = adsp_err_get_lnx_err_code( + atomic_read(&ac->cmd_state)); + goto fail_cmd; + } + rc = 0; +fail_cmd: + return rc; +} + /* * q6asm_get_path_delay() - get the path delay for an audio session * @ac: audio client handle diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c index 0d9f48ec42bb..bc7adb84e679 100644 --- a/tools/hv/hv_kvp_daemon.c +++ b/tools/hv/hv_kvp_daemon.c @@ -1433,7 +1433,7 @@ int main(int argc, char *argv[]) openlog("KVP", 0, LOG_USER); syslog(LOG_INFO, "KVP starting; pid is:%d", getpid()); - kvp_fd = open("/dev/vmbus/hv_kvp", O_RDWR); + kvp_fd = open("/dev/vmbus/hv_kvp", O_RDWR | O_CLOEXEC); if (kvp_fd < 0) { syslog(LOG_ERR, "open /dev/vmbus/hv_kvp failed; error: %d %s", |
