diff options
69 files changed, 1705 insertions, 669 deletions
diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu.txt b/Documentation/devicetree/bindings/iommu/arm,smmu.txt index d00a5c1ce502..9e512d1ea763 100644 --- a/Documentation/devicetree/bindings/iommu/arm,smmu.txt +++ b/Documentation/devicetree/bindings/iommu/arm,smmu.txt @@ -139,8 +139,8 @@ conditions. time. This should be a list of 2-tuples of the format: <offset reg_value>. -- qcom,bus-master-id : The master ID of the bus, if a bus vote is needed. - See include/dt-bindings/msm/msm-bus-ids.h. +Optional bus bindings as defined in +Documentation/devicetree/bindings/arm/msm/msm_bus.txt may also be present. Example: diff --git a/arch/arm/boot/dts/qcom/msm-arm-smmu-8998.dtsi b/arch/arm/boot/dts/qcom/msm-arm-smmu-8998.dtsi index 0ba86e81887f..ecfff13f9355 100644 --- a/arch/arm/boot/dts/qcom/msm-arm-smmu-8998.dtsi +++ b/arch/arm/boot/dts/qcom/msm-arm-smmu-8998.dtsi @@ -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 @@ -29,9 +29,14 @@ <GIC_SPI 367 IRQ_TYPE_EDGE_RISING>, <GIC_SPI 368 IRQ_TYPE_EDGE_RISING>, <GIC_SPI 369 IRQ_TYPE_EDGE_RISING>; - clocks = <&clock_gcc clk_aggre1_noc_clk>; - clock-names = "smmu_aggre1_noc_clk"; - #clock-cells = <1>; + qcom,msm-bus,name = "smmu-bus-client-anoc1"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,active-only; + qcom,msm-bus,num-paths = <1>; + /* aggre1_noc_clk */ + qcom,msm-bus,vectors-KBps = + <84 10062 0 0>, + <84 10062 0 1000>; }; anoc2_smmu: arm,smmu-anoc2@16c0000 { @@ -52,9 +57,14 @@ <GIC_SPI 463 IRQ_TYPE_EDGE_RISING>, <GIC_SPI 464 IRQ_TYPE_EDGE_RISING>, <GIC_SPI 465 IRQ_TYPE_EDGE_RISING>; - clocks = <&clock_gcc clk_aggre2_noc_clk>; - clock-names = "smmu_aggre2_noc_clk"; - #clock-cells = <1>; + qcom,msm-bus,name = "smmu-bus-client-anoc2"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,active-only; + qcom,msm-bus,num-paths = <1>; + /* aggre2_noc_clk */ + qcom,msm-bus,vectors-KBps = + <117 10065 0 0>, + <117 10065 0 1000>; }; lpass_q6_smmu: arm,smmu-lpass_q6@5100000 { @@ -116,15 +126,20 @@ <GIC_SPI 272 IRQ_TYPE_LEVEL_HIGH>; vdd-supply = <&gdsc_bimc_smmu>; clocks = <&clock_mmss clk_mmss_mnoc_ahb_clk>, - <&clock_gcc clk_mmssnoc_axi_clk>, <&clock_mmss clk_mmss_bimc_smmu_ahb_clk>, <&clock_mmss clk_mmss_bimc_smmu_axi_clk>; clock-names = "mmss_mnoc_ahb_clk", - "mmssnoc_axi_clk", "mmss_bimc_smmu_ahb_clk", "mmss_bimc_smmu_axi_clk"; #clock-cells = <1>; - qcom,bus-master-id = <MSM_BUS_MNOC_BIMC_MAS>; + qcom,msm-bus,name = "smmu-bus-client-mmss"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,active-only; + qcom,msm-bus,num-paths = <2>; + /* ahb_clk_src, mmssnoc_axi_clk */ + qcom,msm-bus,vectors-KBps = + <102 722 0 0>, <29 512 0 0>, + <102 722 0 1000>, <29 512 0 1000>; }; kgsl_smmu: arm,smmu-kgsl@5040000 { diff --git a/arch/arm/boot/dts/qcom/msm8998-gpu.dtsi b/arch/arm/boot/dts/qcom/msm8998-gpu.dtsi index 9a497a473a56..45ab53ccc2c2 100644 --- a/arch/arm/boot/dts/qcom/msm8998-gpu.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-gpu.dtsi @@ -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 @@ -98,6 +98,7 @@ qcom,gpubw-dev = <&gpubw>; qcom,bus-control; qcom,msm-bus,name = "grp3d"; + qcom,bus-width = <32>; qcom,msm-bus,num-cases = <13>; qcom,msm-bus,num-paths = <1>; qcom,msm-bus,vectors-KBps = diff --git a/arch/arm/boot/dts/qcom/sdm660-bus.dtsi b/arch/arm/boot/dts/qcom/sdm660-bus.dtsi index 93c615639be9..68ff96829d4f 100644 --- a/arch/arm/boot/dts/qcom/sdm660-bus.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-bus.dtsi @@ -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 @@ -34,7 +34,6 @@ label = "fab-a2noc"; qcom,fab-dev; qcom,base-name = "a2noc-base"; - qcom,bypass-qos-prg; qcom,bus-type = <1>; qcom,qos-off = <4096>; qcom,base-offset = <16384>; @@ -44,16 +43,16 @@ qcom,node-qos-clks { clock-names = "clk-ipa-clk", - "clk-sdcc1-ahb-no-rate", - "clk-sdcc2-ahb-no-rate", - "clk-blsp1-ahb-no-rate", - "clk-blsp2-ahb-no-rate"; + "clk-ufs-axi-clk", + "clk-aggre2-ufs-axi-no-rate", + "clk-aggre2-usb3-axi-cfg-no-rate", + "clk-cfg-noc-usb2-axi-no-rate"; clocks = <&clock_rpmcc RPM_IPA_CLK>, - <&clock_gcc GCC_SDCC1_AHB_CLK>, - <&clock_gcc GCC_SDCC2_AHB_CLK>, - <&clock_gcc GCC_BLSP1_AHB_CLK>, - <&clock_gcc GCC_BLSP2_AHB_CLK>; + <&clock_gcc GCC_UFS_AXI_CLK>, + <&clock_gcc GCC_AGGRE2_UFS_AXI_CLK>, + <&clock_gcc GCC_AGGRE2_USB3_AXI_CLK>, + <&clock_gcc GCC_CFG_NOC_USB2_AXI_CLK>; }; }; @@ -63,7 +62,6 @@ qcom,fab-dev; qcom,base-name = "bimc-base"; qcom,bus-type = <2>; - qcom,bypass-qos-prg; qcom,util-fact = <153>; clock-names = "bus_clk", "bus_a_clk"; clocks = <&clock_rpmcc BIMC_MSMBUS_CLK>, @@ -75,7 +73,6 @@ label = "fab-cnoc"; qcom,fab-dev; qcom,base-name = "cnoc-base"; - qcom,bypass-qos-prg; qcom,bus-type = <1>; clock-names = "bus_clk", "bus_a_clk"; clocks = <&clock_rpmcc CNOC_MSMBUS_CLK>, @@ -87,7 +84,6 @@ label = "fab-gnoc"; qcom,virt-dev; qcom,base-name = "gnoc-base"; - qcom,bypass-qos-prg; }; fab_mnoc: fab-mnoc { @@ -95,7 +91,6 @@ label = "fab-mnoc"; qcom,fab-dev; qcom,base-name = "mnoc-base"; - qcom,bypass-qos-prg; qcom,bus-type = <1>; qcom,qos-off = <4096>; qcom,base-offset = <20480>; @@ -103,27 +98,13 @@ clock-names = "bus_clk", "bus_a_clk"; clocks = <&clock_rpmcc MMSSNOC_AXI_CLK>, <&clock_rpmcc MMSSNOC_AXI_A_CLK>; - clk-camss-ahb-no-rate-supply = - <&gdsc_camss_top>; - clk-video-ahb-no-rate-supply = - <&gdsc_venus>; - clk-video-axi-no-rate-supply = - <&gdsc_venus>; qcom,node-qos-clks { clock-names = "clk-mmssnoc-axi-no-rate", - "clk-noc-cfg-ahb-no-rate", - "clk-mnoc-ahb-no-rate", - "clk-camss-ahb-no-rate", - "clk-video-ahb-no-rate", - "clk-video-axi-no-rate"; + "clk-mmss-noc-cfg-ahb-no-rate"; clocks = <&clock_rpmcc MMSSNOC_AXI_CLK>, - <&clock_gcc GCC_MMSS_NOC_CFG_AHB_CLK>, - <&clock_mmss MMSS_MNOC_AHB_CLK>, - <&clock_mmss MMSS_CAMSS_AHB_CLK>, - <&clock_mmss MMSS_VIDEO_AHB_CLK>, - <&clock_mmss MMSS_VIDEO_AXI_CLK>; + <&clock_gcc GCC_MMSS_NOC_CFG_AHB_CLK>; }; }; @@ -132,7 +113,6 @@ label = "fab-snoc"; qcom,fab-dev; qcom,base-name = "snoc-base"; - qcom,bypass-qos-prg; qcom,bus-type = <1>; qcom,qos-off = <4096>; qcom,base-offset = <24576>; @@ -146,7 +126,6 @@ label = "fab-mnoc-ahb"; qcom,fab-dev; qcom,base-name = "mmnoc-ahb-base"; - qcom,bypass-qos-prg; qcom,setrate-only-clk; qcom,bus-type = <1>; clock-names = "bus_clk", "bus_a_clk"; @@ -483,18 +462,6 @@ qcom,bus-dev = <&fab_mnoc>; qcom,vrail-comp = <50>; qcom,mas-rpm-id = <ICBID_MASTER_MDP0>; - clk-mdss-axi-no-rate-supply = - <&gdsc_mdss>; - clk-mdss-ahb-no-rate-supply = - <&gdsc_mdss>; - qcom,node-qos-clks { - clock-names = - "clk-mdss-ahb-no-rate", - "clk-mdss-axi-no-rate"; - clocks = - <&clock_mmss MMSS_MDSS_AHB_CLK>, - <&clock_mmss MMSS_MDSS_AXI_CLK>; - }; }; mas_mdp_p1: mas-mdp-p1 { diff --git a/arch/arm/boot/dts/qcom/sdm660-camera-sensor-qrd.dtsi b/arch/arm/boot/dts/qcom/sdm660-camera-sensor-qrd.dtsi index ae8da056d12b..f44d59e021d2 100644 --- a/arch/arm/boot/dts/qcom/sdm660-camera-sensor-qrd.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-camera-sensor-qrd.dtsi @@ -21,7 +21,7 @@ status = "ok"; }; - cam_avdd_gpio_regulator:fixed_regulator@1 { + cam_avdd_gpio_regulator:cam_avdd_fixed_regulator { compatible = "regulator-fixed"; regulator-name = "cam_vadd_gpio_regulator"; regulator-min-microvolt = <2800000>; @@ -31,17 +31,7 @@ vin-supply = <&pm660l_bob>; }; - cam_dvdd_gpio_regulator:fixed_regulator@1 { - compatible = "regulator-fixed"; - regulator-name = "cam_vadd_gpio_regulator"; - regulator-min-microvolt = <1050000>; - regulator-max-microvolt = <1050000>; - enable-active-high; - gpio = <&pm660l_gpios 4>; - vin-supply = <&pm660_s5>; - }; - - cam_vaf_gpio_regulator:fixed_regulator@2 { + cam_vaf_gpio_regulator:cam_vaf_fixed_regulator { compatible = "regulator-fixed"; regulator-name = "cam_vaf_gpio_regulator"; regulator-min-microvolt = <2800000>; @@ -182,11 +172,11 @@ compatible = "qcom,eeprom"; cam_vio-supply = <&pm660_l11>; cam_vana-supply = <&cam_avdd_gpio_regulator>; - cam_vdig-supply = <&cam_dvdd_gpio_regulator>; + cam_vdig-supply = <&pm660_s5>; qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig"; - qcom,cam-vreg-min-voltage = <1750000 0 0>; - qcom,cam-vreg-max-voltage = <1980000 0 0>; - qcom,cam-vreg-op-mode = <105000 0 0>; + qcom,cam-vreg-min-voltage = <1780000 0 1350000>; + qcom,cam-vreg-max-voltage = <1950000 0 1350000>; + qcom,cam-vreg-op-mode = <105000 0 105000>; qcom,gpio-no-mux = <0>; pinctrl-names = "cam_default", "cam_suspend"; pinctrl-0 = <&cam_sensor_mclk0_active @@ -194,12 +184,15 @@ pinctrl-1 = <&cam_sensor_mclk0_suspend &cam_sensor_rear_suspend>; gpios = <&tlmm 32 0>, - <&tlmm 46 0>; + <&tlmm 46 0>, + <&pm660l_gpios 4 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_MCLK0", - "CAM_RESET0"; + qcom,gpio-vdig = <2>; + qcom,gpio-req-tbl-num = <0 1 1>; + qcom,gpio-req-tbl-flags = <1 0 0>; + qcom,gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET0", + "CAM_VDIG"; qcom,sensor-position = <0>; qcom,sensor-mode = <0>; qcom,cci-master = <0>; @@ -216,11 +209,11 @@ compatible = "qcom,eeprom"; cam_vio-supply = <&pm660_l11>; cam_vana-supply = <&cam_avdd_gpio_regulator>; - cam_vdig-supply = <&cam_dvdd_gpio_regulator>; + cam_vdig-supply = <&pm660_s5>; qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig"; - qcom,cam-vreg-min-voltage = <1750000 0 0>; - qcom,cam-vreg-max-voltage = <1980000 0 0>; - qcom,cam-vreg-op-mode = <105000 0 0>; + qcom,cam-vreg-min-voltage = <1780000 0 1350000>; + qcom,cam-vreg-max-voltage = <1950000 0 1350000>; + qcom,cam-vreg-op-mode = <105000 0 105000>; qcom,gpio-no-mux = <0>; pinctrl-names = "cam_default", "cam_suspend"; pinctrl-0 = <&cam_sensor_mclk2_active @@ -228,15 +221,18 @@ pinctrl-1 = <&cam_sensor_mclk2_suspend &cam_sensor_rear2_suspend>; gpios = <&tlmm 34 0>, - <&tlmm 48 0>; + <&tlmm 48 0>, + <&pm660l_gpios 4 0>; qcom,gpio-reset = <1>; - qcom,gpio-req-tbl-num = <0 1>; - qcom,gpio-req-tbl-flags = <1 0>; + qcom,gpio-vdig = <2>; + qcom,gpio-req-tbl-num = <0 1 1>; + qcom,gpio-req-tbl-flags = <1 0 0>; qcom,gpio-req-tbl-label = "CAMIF_MCLK1", - "CAM_RESET1"; + "CAM_RESET1", + "CAM_VDIG"; qcom,sensor-position = <0>; qcom,sensor-mode = <0>; - qcom,cci-master = <0>; + qcom,cci-master = <1>; status = "ok"; clocks = <&clock_mmss MCLK2_CLK_SRC>, <&clock_mmss MMSS_CAMSS_MCLK2_CLK>; @@ -287,18 +283,18 @@ reg = <0x0>; qcom,csiphy-sd-index = <0>; qcom,csid-sd-index = <0>; - qcom,mount-angle = <90>; + qcom,mount-angle = <270>; qcom,led-flash-src = <&led_flash0>; qcom,actuator-src = <&actuator0>; qcom,ois-src = <&ois0>; qcom,eeprom-src = <&eeprom0>; cam_vio-supply = <&pm660_l11>; cam_vana-supply = <&cam_avdd_gpio_regulator>; - cam_vdig-supply = <&cam_dvdd_gpio_regulator>; + cam_vdig-supply = <&pm660_s5>; 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,cam-vreg-min-voltage = <1780000 0 1350000>; + qcom,cam-vreg-max-voltage = <1950000 0 1350000>; + qcom,cam-vreg-op-mode = <105000 0 105000>; qcom,gpio-no-mux = <0>; pinctrl-names = "cam_default", "cam_suspend"; pinctrl-0 = <&cam_sensor_mclk0_active @@ -306,12 +302,15 @@ pinctrl-1 = <&cam_sensor_mclk0_suspend &cam_sensor_rear_suspend>; gpios = <&tlmm 32 0>, - <&tlmm 46 0>; + <&tlmm 46 0>, + <&pm660l_gpios 4 0>; qcom,gpio-reset = <1>; - qcom,gpio-req-tbl-num = <0 1>; - qcom,gpio-req-tbl-flags = <1 0>; + qcom,gpio-vdig = <2>; + qcom,gpio-req-tbl-num = <0 1 1>; + qcom,gpio-req-tbl-flags = <1 0 0>; qcom,gpio-req-tbl-label = "CAMIF_MCLK2", - "CAM_RESET0"; + "CAM_RESET0", + "CAM_VDIG"; qcom,sensor-position = <0>; qcom,sensor-mode = <0>; qcom,cci-master = <0>; @@ -328,16 +327,16 @@ reg = <0x1>; qcom,csiphy-sd-index = <1>; qcom,csid-sd-index = <1>; - qcom,mount-angle = <90>; + qcom,mount-angle = <270>; qcom,actuator-src = <&actuator1>; qcom,eeprom-src = <&eeprom1>; cam_vio-supply = <&pm660_l11>; cam_vana-supply = <&cam_avdd_gpio_regulator>; - cam_vdig-supply = <&cam_dvdd_gpio_regulator>; + cam_vdig-supply = <&pm660_s5>; 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,cam-vreg-min-voltage = <1780000 0 1350000>; + qcom,cam-vreg-max-voltage = <1950000 0 1350000>; + qcom,cam-vreg-op-mode = <105000 0 105000>; qcom,gpio-no-mux = <0>; pinctrl-names = "cam_default", "cam_suspend"; pinctrl-0 = <&cam_sensor_mclk2_active @@ -345,15 +344,18 @@ pinctrl-1 = <&cam_sensor_mclk2_suspend &cam_sensor_rear2_suspend>; gpios = <&tlmm 34 0>, - <&tlmm 48 0>; + <&tlmm 48 0>, + <&pm660l_gpios 4 0>; qcom,gpio-reset = <1>; - qcom,gpio-req-tbl-num = <0 1>; - qcom,gpio-req-tbl-flags = <1 0>; + qcom,gpio-vdig = <2>; + qcom,gpio-req-tbl-num = <0 1 1>; + qcom,gpio-req-tbl-flags = <1 0 0>; qcom,gpio-req-tbl-label = "CAMIF_MCLK1", - "CAM_RESET1"; + "CAM_RESET1", + "CAM_VDIG"; qcom,sensor-position = <0>; qcom,sensor-mode = <0>; - qcom,cci-master = <0>; + qcom,cci-master = <1>; status = "ok"; clocks = <&clock_mmss MCLK2_CLK_SRC>, <&clock_mmss MMSS_CAMSS_MCLK2_CLK>; diff --git a/arch/arm/boot/dts/qcom/sdm660-gpu.dtsi b/arch/arm/boot/dts/qcom/sdm660-gpu.dtsi index d347f033b12d..1e62a2423e38 100644 --- a/arch/arm/boot/dts/qcom/sdm660-gpu.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-gpu.dtsi @@ -32,21 +32,26 @@ * subsystem is inactive */ qcom,active-only; + /* + * IB votes in MBPS, derived using below formula + * IB = (DDR frequency * DDR bus width in Bytes * Dual rate) + * Note: IB vote is per DDR channel vote + */ qcom,bw-tbl = < 0 /* off */ >, - < 762 /* 100 MHz */ >, - < 1144 /* 150 MHz */ >, - < 1525 /* 200 MHz */ >, - < 2288 /* 300 MHz */ >, - < 3143 /* 412 MHz */ >, - < 4173 /* 547 MHz */ >, - < 5195 /* 681 MHz */ >, - < 5859 /* 768 MHz */ >, - < 7759 /* 1017 MHz */ >, - < 9887 /* 1296 MHz */ >, - < 10327 /* 1353 MHz */ >, - < 11863 /* 1555 MHz */ >, - < 13763 /* 1804 MHz */ >; + < 381 /* 100 MHz */ >, + < 572 /* 150 MHz */ >, + < 762 /* 200 MHz */ >, + < 1144 /* 300 MHz */ >, + < 1571 /* 412 MHz */ >, + < 2086 /* 547 MHz */ >, + < 2597 /* 681 MHz */ >, + < 2929 /* 768 MHz */ >, + < 3879 /* 1017 MHz */ >, + < 4943 /* 1296 MHz */ >, + < 5161 /* 1353 MHz */ >, + < 5931 /* 1555 MHz */ >, + < 6881 /* 1804 MHz */ >; }; msm_gpu: qcom,kgsl-3d0@5000000 { @@ -85,26 +90,27 @@ /* Bus Scale Settings */ qcom,gpubw-dev = <&gpubw>; qcom,bus-control; - qcom,bus-width = <16>; + /* GPU to BIMC bus width, VBIF data transfer in 1 cycle */ + qcom,bus-width = <32>; qcom,msm-bus,name = "grp3d"; qcom,msm-bus,num-cases = <14>; qcom,msm-bus,num-paths = <1>; qcom,msm-bus,vectors-KBps = <26 512 0 0>, - <26 512 0 800000>, /* 1 bus=100 */ - <26 512 0 1200000>, /* 2 bus=150 */ - <26 512 0 1600000>, /* 3 bus=200 */ - <26 512 0 2400000>, /* 4 bus=300 */ - <26 512 0 3296000>, /* 5 bus=412 */ - <26 512 0 4376000>, /* 6 bus=547 */ - <26 512 0 5448000>, /* 7 bus=681 */ - <26 512 0 6144000>, /* 8 bus=768 */ - <26 512 0 8136000>, /* 9 bus=1017 */ - <26 512 0 10368000>, /* 10 bus=1296 */ - <26 512 0 10824000>, /* 11 bus=1353 */ - <26 512 0 12440000>, /* 12 bus=1555 */ - <26 512 0 14432000>; /* 13 bus=1804 */ + <26 512 0 400000>, /* 1 bus=100 */ + <26 512 0 600000>, /* 2 bus=150 */ + <26 512 0 800000>, /* 3 bus=200 */ + <26 512 0 1200000>, /* 4 bus=300 */ + <26 512 0 1648000>, /* 5 bus=412 */ + <26 512 0 2188000>, /* 6 bus=547 */ + <26 512 0 2724000>, /* 7 bus=681 */ + <26 512 0 3072000>, /* 8 bus=768 */ + <26 512 0 4068000>, /* 9 bus=1017 */ + <26 512 0 5184000>, /* 10 bus=1296 */ + <26 512 0 5412000>, /* 11 bus=1353 */ + <26 512 0 6220000>, /* 12 bus=1555 */ + <26 512 0 7216000>; /* 13 bus=1804 */ /* GDSC regulator names */ regulator-names = "vddcx", "vdd"; @@ -161,8 +167,8 @@ qcom,gpu-pwrlevel@0 { reg = <0>; qcom,gpu-freq = <750000000>; - qcom,bus-freq = <12>; - qcom,bus-min = <11>; + qcom,bus-freq = <13>; + qcom,bus-min = <12>; qcom,bus-max = <13>; }; @@ -171,7 +177,7 @@ reg = <1>; qcom,gpu-freq = <700000000>; qcom,bus-freq = <11>; - qcom,bus-min = <10>; + qcom,bus-min = <11>; qcom,bus-max = <13>; }; @@ -179,7 +185,7 @@ qcom,gpu-pwrlevel@2 { reg = <2>; qcom,gpu-freq = <647000000>; - qcom,bus-freq = <10>; + qcom,bus-freq = <11>; qcom,bus-min = <10>; qcom,bus-max = <12>; }; @@ -188,9 +194,9 @@ qcom,gpu-pwrlevel@3 { reg = <3>; qcom,gpu-freq = <588000000>; - qcom,bus-freq = <9>; + qcom,bus-freq = <10>; qcom,bus-min = <9>; - qcom,bus-max = <11>; + qcom,bus-max = <12>; }; /* SVS_L1 */ @@ -198,7 +204,7 @@ reg = <4>; qcom,gpu-freq = <465000000>; qcom,bus-freq = <9>; - qcom,bus-min = <7>; + qcom,bus-min = <8>; qcom,bus-max = <11>; }; @@ -206,8 +212,8 @@ qcom,gpu-pwrlevel@5 { reg = <5>; qcom,gpu-freq = <370000000>; - qcom,bus-freq = <7>; - qcom,bus-min = <5>; + qcom,bus-freq = <8>; + qcom,bus-min = <6>; qcom,bus-max = <9>; }; @@ -225,7 +231,7 @@ reg = <7>; qcom,gpu-freq = <160000000>; qcom,bus-freq = <3>; - qcom,bus-min = <2>; + qcom,bus-min = <3>; qcom,bus-max = <5>; }; diff --git a/arch/arm/boot/dts/qcom/sdm660.dtsi b/arch/arm/boot/dts/qcom/sdm660.dtsi index 42db8c60f681..772a7ff0a868 100644 --- a/arch/arm/boot/dts/qcom/sdm660.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660.dtsi @@ -436,7 +436,6 @@ interrupt-controller; #interrupt-cells = <4>; cell-index = <0>; - qcom,not-wakeup; /* Needed until Full-boot-chain enabled */ status = "ok"; }; @@ -1011,19 +1010,19 @@ qcom,src-dst-ports = <1 512>; qcom,active-only; qcom,bw-tbl = - < 762 /* 100 MHz */ >, - < 1144 /* 150 MHz */ >, - < 1525 /* 200 MHz */ >, - < 2288 /* 300 MHz */ >, - < 3143 /* 412 MHz */ >, - < 4173 /* 547 MHz */ >, - < 5195 /* 681 MHz */ >, - < 5859 /* 768 MHz */ >, - < 7759 /* 1017 MHz */ >, - < 9887 /* 1296 MHz */ >, - < 10327 /* 1353 MHz */ >, - < 11863 /* 1555 MHz */ >, - < 13763 /* 1804 MHz */ >; + < 381 /* 100 MHz */ >, + < 572 /* 150 MHz */ >, + < 762 /* 200 MHz */ >, + < 1144 /* 300 MHz */ >, + < 1571 /* 412 MHz */ >, + < 2086 /* 547 MHz */ >, + < 2597 /* 681 MHz */ >, + < 2929 /* 768 MHz */ >, + < 3879 /* 1017 MHz */ >, + < 4943 /* 1296 MHz */ >, + < 5163 /* 1353 MHz */ >, + < 5931 /* 1555 MHz */ >, + < 6881 /* 1804 MHz */ >; }; bwmon: qcom,cpu-bwmon { @@ -1042,19 +1041,19 @@ qcom,src-dst-ports = <1 512>; qcom,active-only; qcom,bw-tbl = - < 762 /* 100 MHz */ >, - < 1144 /* 150 MHz */ >, - < 1525 /* 200 MHz */ >, - < 2288 /* 300 MHz */ >, - < 3143 /* 412 MHz */ >, - < 4173 /* 547 MHz */ >, - < 5195 /* 681 MHz */ >, - < 5859 /* 768 MHz */ >, - < 7759 /* 1017 MHz */ >, - < 9887 /* 1296 MHz */ >, - < 10327 /* 1353 MHz */ >, - < 11863 /* 1555 MHz */ >, - < 13763 /* 1804 MHz */ >; + < 381 /* 100 MHz */ >, + < 572 /* 150 MHz */ >, + < 762 /* 200 MHz */ >, + < 1144 /* 300 MHz */ >, + < 1571 /* 412 MHz */ >, + < 2086 /* 547 MHz */ >, + < 2597 /* 681 MHz */ >, + < 2929 /* 768 MHz */ >, + < 3879 /* 1017 MHz */ >, + < 4943 /* 1296 MHz */ >, + < 5163 /* 1353 MHz */ >, + < 5931 /* 1555 MHz */ >, + < 6881 /* 1804 MHz */ >; }; memlat_cpu0: qcom,memlat-cpu0 { @@ -1063,19 +1062,19 @@ qcom,src-dst-ports = <1 512>; qcom,active-only; qcom,bw-tbl = - < 762 /* 100 MHz */ >, - < 1144 /* 150 MHz */ >, - < 1525 /* 200 MHz */ >, - < 2288 /* 300 MHz */ >, - < 3143 /* 412 MHz */ >, - < 4173 /* 547 MHz */ >, - < 5195 /* 681 MHz */ >, - < 5859 /* 768 MHz */ >, - < 7759 /* 1017 MHz */ >, - < 9887 /* 1296 MHz */ >, - < 10327 /* 1353 MHz */ >, - < 11863 /* 1555 MHz */ >, - < 13763 /* 1804 MHz */ >; + < 381 /* 100 MHz */ >, + < 572 /* 150 MHz */ >, + < 762 /* 200 MHz */ >, + < 1144 /* 300 MHz */ >, + < 1571 /* 412 MHz */ >, + < 2086 /* 547 MHz */ >, + < 2597 /* 681 MHz */ >, + < 2929 /* 768 MHz */ >, + < 3879 /* 1017 MHz */ >, + < 4943 /* 1296 MHz */ >, + < 5163 /* 1353 MHz */ >, + < 5931 /* 1555 MHz */ >, + < 6881 /* 1804 MHz */ >; }; memlat_cpu4: qcom,memlat-cpu4 { @@ -1084,19 +1083,19 @@ qcom,src-dst-ports = <1 512>; qcom,active-only; qcom,bw-tbl = - < 762 /* 100 MHz */ >, - < 1144 /* 150 MHz */ >, - < 1525 /* 200 MHz */ >, - < 2288 /* 300 MHz */ >, - < 3143 /* 412 MHz */ >, - < 4173 /* 547 MHz */ >, - < 5195 /* 681 MHz */ >, - < 5859 /* 768 MHz */ >, - < 7759 /* 1017 MHz */ >, - < 9887 /* 1296 MHz */ >, - < 10327 /* 1353 MHz */ >, - < 11863 /* 1555 MHz */ >, - < 13763 /* 1804 MHz */ >; + < 381 /* 100 MHz */ >, + < 572 /* 150 MHz */ >, + < 762 /* 200 MHz */ >, + < 1144 /* 300 MHz */ >, + < 1571 /* 412 MHz */ >, + < 2086 /* 547 MHz */ >, + < 2597 /* 681 MHz */ >, + < 2929 /* 768 MHz */ >, + < 3879 /* 1017 MHz */ >, + < 4943 /* 1296 MHz */ >, + < 5163 /* 1353 MHz */ >, + < 5931 /* 1555 MHz */ >, + < 6881 /* 1804 MHz */ >; }; devfreq_memlat_0: qcom,arm-memlat-mon-0 { @@ -1104,9 +1103,9 @@ qcom,cpulist = <&CPU0 &CPU1 &CPU2 &CPU3>; qcom,target-dev = <&memlat_cpu0>; qcom,core-dev-table = - < 633600 1525 >, - < 1401600 4173 >, - < 1881600 7759 >; + < 633600 762 >, + < 1401600 2086 >, + < 1881600 3879 >; }; devfreq_memlat_4: qcom,arm-memlat-mon-4 { @@ -1114,25 +1113,25 @@ qcom,cpulist = <&CPU4 &CPU5 &CPU6 &CPU7>; qcom,target-dev = <&memlat_cpu4>; qcom,core-dev-table = - < 1113600 1525 >, - < 1401600 7759 >, - < 2150400 11863 >, - < 2457600 13763 >; + < 1113600 762 >, + < 1401600 3879 >, + < 2150400 5931 >, + < 2457600 6881 >; }; devfreq_cpufreq: devfreq-cpufreq { mincpubw-cpufreq { target-dev = <&mincpubw>; cpu-to-dev-map-0 = - < 633600 1525 >, - < 1401600 3143 >, - < 1881600 5859 >; + < 633600 762 >, + < 1401600 1571 >, + < 1881600 2929 >; cpu-to-dev-map-4 = - < 1113600 1525 >, - < 1401600 4173 >, - < 1747200 5859 >, - < 2150400 7759 >, - < 2457600 13763 >; + < 1113600 762 >, + < 1401600 2086 >, + < 1747200 2929 >, + < 2150400 3879 >, + < 2457600 6881 >; }; }; @@ -1276,8 +1275,10 @@ 100000000 200000000 400000000 4294967295>; clocks = <&clock_gcc GCC_SDCC1_AHB_CLK>, - <&clock_gcc GCC_SDCC1_APPS_CLK>; - clock-names = "iface_clk", "core_clk"; + <&clock_gcc GCC_SDCC1_APPS_CLK>, + <&clock_gcc GCC_SDCC1_ICE_CORE_CLK>; + clock-names = "iface_clk", "core_clk", "ice_core_clk"; + qcom,ice-clk-rates = <300000000 150000000>; status = "disabled"; }; diff --git a/arch/arm/configs/msmcortex_defconfig b/arch/arm/configs/msmcortex_defconfig index fec429d7bd0c..2cfe647855c3 100644 --- a/arch/arm/configs/msmcortex_defconfig +++ b/arch/arm/configs/msmcortex_defconfig @@ -293,12 +293,13 @@ CONFIG_PINCTRL_SDM660=y CONFIG_GPIO_SYSFS=y CONFIG_GPIO_QPNP_PIN=y CONFIG_POWER_SUPPLY=y -CONFIG_QPNP_FG_GEN3=y +CONFIG_QPNP_SMBCHARGER=y +CONFIG_SMB135X_CHARGER=y +CONFIG_SMB1351_USB_CHARGER=y CONFIG_MSM_BCL_CTL=y CONFIG_MSM_BCL_PERIPHERAL_CTL=y CONFIG_QPNP_SMB2=y CONFIG_SMB138X_CHARGER=y -CONFIG_QPNP_QNOVO=y CONFIG_APSS_CORE_EA=y CONFIG_MSM_APM=y CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y @@ -477,7 +478,6 @@ CONFIG_QCOM_DEVFREQ_DEVBW=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 diff --git a/block/Kconfig b/block/Kconfig index 161491d0a879..39e956942b9d 100644 --- a/block/Kconfig +++ b/block/Kconfig @@ -33,7 +33,7 @@ config LBDAF This option is required to support the full capacity of large (2TB+) block devices, including RAID, disk, Network Block Device, Logical Volume Manager (LVM) and loopback. - + This option also enables support for single files larger than 2TB. @@ -111,6 +111,13 @@ config BLK_CMDLINE_PARSER See Documentation/block/cmdline-partition.txt for more information. +config BLOCK_PERF_FRAMEWORK + bool "Enable Block device performance measurement framework" + default n + ---help--- + Enabling this option allows you to measure the performance at the + block layer. + menu "Partition Types" source "block/partitions/Kconfig" diff --git a/block/bio.c b/block/bio.c index b9829b6504c8..02c4d9bf1590 100644 --- a/block/bio.c +++ b/block/bio.c @@ -31,6 +31,8 @@ #include <trace/events/block.h> +#include "blk.h" + /* * Test patch to inline a certain number of bi_io_vec's inside the bio * itself, to shrink a bio data allocation from two mempool calls to one @@ -1765,8 +1767,10 @@ void bio_endio(struct bio *bio) bio_put(bio); bio = parent; } else { - if (bio->bi_end_io) + if (bio->bi_end_io) { + blk_update_perf_stats(bio); bio->bi_end_io(bio); + } bio = NULL; } } diff --git a/block/blk-core.c b/block/blk-core.c index 450da06fa27e..4162327d8804 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -11,6 +11,12 @@ /* * This handles all read/write requests to block devices */ + +#ifdef CONFIG_BLOCK_PERF_FRAMEWORK +#define DRIVER_NAME "Block" +#define pr_fmt(fmt) DRIVER_NAME ": %s: " fmt, __func__ +#endif + #include <linux/kernel.h> #include <linux/module.h> #include <linux/backing-dev.h> @@ -34,6 +40,12 @@ #include <linux/pm_runtime.h> #include <linux/blk-cgroup.h> +#ifdef CONFIG_BLOCK_PERF_FRAMEWORK +#include <linux/ktime.h> +#include <linux/spinlock.h> +#include <linux/debugfs.h> +#endif + #define CREATE_TRACE_POINTS #include <trace/events/block.h> @@ -2111,6 +2123,456 @@ static inline struct task_struct *get_dirty_task(struct bio *bio) } #endif +#ifdef CONFIG_BLOCK_PERF_FRAMEWORK +#define BLK_PERF_SIZE (1024 * 15) +#define BLK_PERF_HIST_SIZE (sizeof(u32) * BLK_PERF_SIZE) + +struct blk_perf_stats { + u32 *read_hist; + u32 *write_hist; + u32 *flush_hist; + int buffers_alloced; + ktime_t max_read_time; + ktime_t max_write_time; + ktime_t max_flush_time; + ktime_t min_write_time; + ktime_t min_read_time; + ktime_t min_flush_time; + ktime_t total_write_time; + ktime_t total_read_time; + u64 total_read_size; + u64 total_write_size; + spinlock_t lock; + int is_enabled; +}; + +static struct blk_perf_stats blk_perf; +static struct dentry *blk_perf_debug_dir; + +static int alloc_histogram_buffers(void) +{ + int ret = 0; + + if (!blk_perf.read_hist) + blk_perf.read_hist = kzalloc(BLK_PERF_HIST_SIZE, GFP_KERNEL); + + if (!blk_perf.write_hist) + blk_perf.write_hist = kzalloc(BLK_PERF_HIST_SIZE, GFP_KERNEL); + + if (!blk_perf.flush_hist) + blk_perf.flush_hist = kzalloc(BLK_PERF_HIST_SIZE, GFP_KERNEL); + + if (!blk_perf.read_hist || !blk_perf.write_hist || !blk_perf.flush_hist) + ret = -ENOMEM; + + if (!ret) + blk_perf.buffers_alloced = 1; + return ret; +} + +static void clear_histogram_buffers(void) +{ + if (!blk_perf.buffers_alloced) + return; + memset(blk_perf.read_hist, 0, BLK_PERF_HIST_SIZE); + memset(blk_perf.write_hist, 0, BLK_PERF_HIST_SIZE); + memset(blk_perf.flush_hist, 0, BLK_PERF_HIST_SIZE); +} + +static int enable_perf(void *data, u64 val) +{ + int ret; + + if (!blk_perf.buffers_alloced) + ret = alloc_histogram_buffers(); + + if (ret) + return ret; + + spin_lock(&blk_perf.lock); + blk_perf.is_enabled = val; + spin_unlock(&blk_perf.lock); + return 0; +} + +static int is_perf_enabled(void *data, u64 *val) +{ + spin_lock(&blk_perf.lock); + *val = blk_perf.is_enabled; + spin_unlock(&blk_perf.lock); + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(enable_perf_fops, is_perf_enabled, enable_perf, + "%llu\n"); + +static char *blk_debug_buffer; +static u32 blk_debug_data_size; +static DEFINE_MUTEX(blk_perf_debug_buffer_mutex); + +static ssize_t blk_perf_read(struct file *file, char __user *buf, + size_t count, loff_t *file_pos) +{ + ssize_t ret = 0; + + mutex_lock(&blk_perf_debug_buffer_mutex); + ret = simple_read_from_buffer(buf, count, file_pos, blk_debug_buffer, + blk_debug_data_size); + mutex_unlock(&blk_perf_debug_buffer_mutex); + + return ret; +} + +static int blk_debug_buffer_alloc(u32 buffer_size) +{ + int ret = 0; + + mutex_lock(&blk_perf_debug_buffer_mutex); + if (blk_debug_buffer != NULL) { + pr_err("blk_debug_buffer is in use\n"); + ret = -EBUSY; + goto end; + } + blk_debug_buffer = kzalloc(buffer_size, GFP_KERNEL); + if (!blk_debug_buffer) + ret = -ENOMEM; +end: + mutex_unlock(&blk_perf_debug_buffer_mutex); + return ret; +} + +static int blk_perf_close(struct inode *inode, struct file *file) +{ + mutex_lock(&blk_perf_debug_buffer_mutex); + blk_debug_data_size = 0; + kfree(blk_debug_buffer); + blk_debug_buffer = NULL; + mutex_unlock(&blk_perf_debug_buffer_mutex); + return 0; +} + +static u32 fill_basic_perf_info(char *buffer, u32 buffer_size) +{ + u32 size = 0; + + size += scnprintf(buffer + size, buffer_size - size, "\n"); + + spin_lock(&blk_perf.lock); + size += scnprintf(buffer + size, buffer_size - size, + "max_read_time_ms: %llu\n", + ktime_to_ms(blk_perf.max_read_time)); + + size += scnprintf(buffer + size, buffer_size - size, + "min_read_time_ms: %llu\n", + ktime_to_ms(blk_perf.min_read_time)); + + size += scnprintf(buffer + size, buffer_size - size, + "total_read_time_ms: %llu\n", + ktime_to_ms(blk_perf.total_read_time)); + + size += scnprintf(buffer + size, buffer_size - size, + "total_read_size: %llu\n\n", + blk_perf.total_read_size); + + size += scnprintf(buffer + size, buffer_size - size, + "max_write_time_ms: %llu\n", + ktime_to_ms(blk_perf.max_write_time)); + + size += scnprintf(buffer + size, buffer_size - size, + "min_write_time_ms: %llu\n", + ktime_to_ms(blk_perf.min_write_time)); + + size += scnprintf(buffer + size, buffer_size - size, + "total_write_time_ms: %llu\n", + ktime_to_ms(blk_perf.total_write_time)); + + size += scnprintf(buffer + size, buffer_size - size, + "total_write_size: %llu\n\n", + blk_perf.total_write_size); + + size += scnprintf(buffer + size, buffer_size - size, + "max_flush_time_ms: %llu\n", + ktime_to_ms(blk_perf.max_flush_time)); + + size += scnprintf(buffer + size, buffer_size - size, + "min_flush_time_ms: %llu\n\n", + ktime_to_ms(blk_perf.min_flush_time)); + + spin_unlock(&blk_perf.lock); + + return size; +} + +static int basic_perf_open(struct inode *inode, struct file *file) +{ + u32 buffer_size; + int ret; + + buffer_size = BLK_PERF_HIST_SIZE; + ret = blk_debug_buffer_alloc(buffer_size); + if (ret) + return ret; + + mutex_lock(&blk_perf_debug_buffer_mutex); + blk_debug_data_size = fill_basic_perf_info(blk_debug_buffer, + buffer_size); + mutex_unlock(&blk_perf_debug_buffer_mutex); + return 0; +} + + +static const struct file_operations basic_perf_ops = { + .read = blk_perf_read, + .release = blk_perf_close, + .open = basic_perf_open, +}; + +static int hist_open_helper(void *hist_buf) +{ + int ret; + + if (!blk_perf.buffers_alloced) + return -EINVAL; + + ret = blk_debug_buffer_alloc(BLK_PERF_HIST_SIZE); + if (ret) + return ret; + + spin_lock(&blk_perf.lock); + memcpy(blk_debug_buffer, hist_buf, BLK_PERF_HIST_SIZE); + spin_unlock(&blk_perf.lock); + + mutex_lock(&blk_perf_debug_buffer_mutex); + blk_debug_data_size = BLK_PERF_HIST_SIZE; + mutex_unlock(&blk_perf_debug_buffer_mutex); + return 0; +} + +static int write_hist_open(struct inode *inode, struct file *file) +{ + return hist_open_helper(blk_perf.write_hist); +} + +static const struct file_operations write_hist_ops = { + .read = blk_perf_read, + .release = blk_perf_close, + .open = write_hist_open, +}; + + +static int read_hist_open(struct inode *inode, struct file *file) +{ + return hist_open_helper(blk_perf.read_hist); +} + +static const struct file_operations read_hist_ops = { + .read = blk_perf_read, + .release = blk_perf_close, + .open = read_hist_open, +}; + +static int flush_hist_open(struct inode *inode, struct file *file) +{ + return hist_open_helper(blk_perf.flush_hist); +} + +static const struct file_operations flush_hist_ops = { + .read = blk_perf_read, + .release = blk_perf_close, + .open = flush_hist_open, +}; + +static void clear_perf_stats_helper(void) +{ + spin_lock(&blk_perf.lock); + blk_perf.max_write_time = ktime_set(0, 0); + blk_perf.max_read_time = ktime_set(0, 0); + blk_perf.max_flush_time = ktime_set(0, 0); + blk_perf.min_write_time = ktime_set(KTIME_MAX, 0); + blk_perf.min_read_time = ktime_set(KTIME_MAX, 0); + blk_perf.min_flush_time = ktime_set(KTIME_MAX, 0); + blk_perf.total_write_time = ktime_set(0, 0); + blk_perf.total_read_time = ktime_set(0, 0); + blk_perf.total_read_size = 0; + blk_perf.total_write_size = 0; + blk_perf.is_enabled = 0; + clear_histogram_buffers(); + spin_unlock(&blk_perf.lock); +} + +static int clear_perf_stats(void *data, u64 val) +{ + clear_perf_stats_helper(); + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(clear_perf_stats_fops, NULL, clear_perf_stats, + "%llu\n"); + +static void blk_debugfs_init(void) +{ + struct dentry *f_ent; + + blk_perf_debug_dir = debugfs_create_dir("block_perf", NULL); + if (IS_ERR(blk_perf_debug_dir)) { + pr_err("Failed to create block_perf debug_fs directory\n"); + return; + } + + f_ent = debugfs_create_file("basic_perf", 0400, blk_perf_debug_dir, + NULL, &basic_perf_ops); + if (IS_ERR(f_ent)) { + pr_err("Failed to create debug_fs basic_perf file\n"); + return; + } + + f_ent = debugfs_create_file("write_hist", 0400, blk_perf_debug_dir, + NULL, &write_hist_ops); + if (IS_ERR(f_ent)) { + pr_err("Failed to create debug_fs write_hist file\n"); + return; + } + + f_ent = debugfs_create_file("read_hist", 0400, blk_perf_debug_dir, + NULL, &read_hist_ops); + if (IS_ERR(f_ent)) { + pr_err("Failed to create debug_fs read_hist file\n"); + return; + } + + f_ent = debugfs_create_file("flush_hist", 0400, blk_perf_debug_dir, + NULL, &flush_hist_ops); + if (IS_ERR(f_ent)) { + pr_err("Failed to create debug_fs flush_hist file\n"); + return; + } + + f_ent = debugfs_create_file("enable_perf", 0600, blk_perf_debug_dir, + NULL, &enable_perf_fops); + if (IS_ERR(f_ent)) { + pr_err("Failed to create debug_fs enable_perf file\n"); + return; + } + + f_ent = debugfs_create_file("clear_perf_stats", 0200, + blk_perf_debug_dir, NULL, + &clear_perf_stats_fops); + if (IS_ERR(f_ent)) { + pr_err("Failed to create debug_fs clear_perf_stats file\n"); + return; + } +} + +static void blk_init_perf(void) +{ + blk_debugfs_init(); + spin_lock_init(&blk_perf.lock); + + clear_perf_stats_helper(); +} + + +static void set_submit_info(struct bio *bio, unsigned int count) +{ + ktime_t submit_time; + + if (unlikely(blk_perf.is_enabled)) { + submit_time = ktime_get(); + bio->submit_time.tv64 = submit_time.tv64; + bio->blk_sector_count = count; + return; + } + + bio->submit_time.tv64 = 0; + bio->blk_sector_count = 0; +} + +void blk_update_perf_read_write_stats(ktime_t bio_process_time, int is_write, + int count) +{ + u32 bio_process_time_ms; + + bio_process_time_ms = ktime_to_ms(bio_process_time); + if (bio_process_time_ms >= BLK_PERF_SIZE) + bio_process_time_ms = BLK_PERF_SIZE - 1; + + if (is_write) { + if (ktime_after(bio_process_time, blk_perf.max_write_time)) + blk_perf.max_write_time = bio_process_time; + + if (ktime_before(bio_process_time, blk_perf.min_write_time)) + blk_perf.min_write_time = bio_process_time; + blk_perf.total_write_time = + ktime_add(blk_perf.total_write_time, bio_process_time); + blk_perf.total_write_size += count; + blk_perf.write_hist[bio_process_time_ms] += count; + + } else { + if (ktime_after(bio_process_time, blk_perf.max_read_time)) + blk_perf.max_read_time = bio_process_time; + + if (ktime_before(bio_process_time, blk_perf.min_read_time)) + blk_perf.min_read_time = bio_process_time; + blk_perf.total_read_time = + ktime_add(blk_perf.total_read_time, bio_process_time); + blk_perf.total_read_size += count; + blk_perf.read_hist[bio_process_time_ms] += count; + } +} +void blk_update_perf_stats(struct bio *bio) +{ + ktime_t bio_process_time; + u32 bio_process_time_ms; + u32 count; + + spin_lock(&blk_perf.lock); + if (likely(!blk_perf.is_enabled)) + goto end; + if (!bio->submit_time.tv64) + goto end; + bio_process_time = ktime_sub(ktime_get(), bio->submit_time); + + count = bio->blk_sector_count; + + if (count) { + int is_write = 0; + + if (bio->bi_rw & WRITE || + unlikely(bio->bi_rw & REQ_WRITE_SAME)) + is_write = 1; + + blk_update_perf_read_write_stats(bio_process_time, is_write, + count); + } else { + + bio_process_time_ms = ktime_to_ms(bio_process_time); + if (bio_process_time_ms >= BLK_PERF_SIZE) + bio_process_time_ms = BLK_PERF_SIZE - 1; + + if (ktime_after(bio_process_time, blk_perf.max_flush_time)) + blk_perf.max_flush_time = bio_process_time; + + if (ktime_before(bio_process_time, blk_perf.min_flush_time)) + blk_perf.min_flush_time = bio_process_time; + + blk_perf.flush_hist[bio_process_time_ms] += 1; + } +end: + spin_unlock(&blk_perf.lock); + +} +#else +static inline void set_submit_info(struct bio *bio, unsigned int count) +{ + (void) bio; + (void) count; +} + +static inline void blk_init_perf(void) +{ +} +#endif /* #ifdef CONFIG_BLOCK_PERF_FRAMEWORK */ + /** * submit_bio - submit a bio to the block device layer for I/O * @rw: whether to %READ or %WRITE, or maybe to %READA (read ahead) @@ -2123,6 +2585,7 @@ static inline struct task_struct *get_dirty_task(struct bio *bio) */ blk_qc_t submit_bio(int rw, struct bio *bio) { + unsigned int count = 0; bio->bi_rw |= rw; /* @@ -2130,8 +2593,6 @@ blk_qc_t submit_bio(int rw, struct bio *bio) * go through the normal accounting stuff before submission. */ if (bio_has_data(bio)) { - unsigned int count; - if (unlikely(rw & REQ_WRITE_SAME)) count = bdev_logical_block_size(bio->bi_bdev) >> 9; else @@ -2158,6 +2619,7 @@ blk_qc_t submit_bio(int rw, struct bio *bio) } } + set_submit_info(bio, count); return generic_make_request(bio); } EXPORT_SYMBOL(submit_bio); @@ -3578,7 +4040,7 @@ int __init blk_dev_init(void) blk_requestq_cachep = kmem_cache_create("blkdev_queue", sizeof(struct request_queue), 0, SLAB_PANIC, NULL); - + blk_init_perf(); return 0; } diff --git a/block/blk.h b/block/blk.h index ce2287639ab3..6ceebbd61afd 100644 --- a/block/blk.h +++ b/block/blk.h @@ -112,6 +112,15 @@ void blk_account_io_start(struct request *req, bool new_io); void blk_account_io_completion(struct request *req, unsigned int bytes); void blk_account_io_done(struct request *req); +#ifdef CONFIG_BLOCK_PERF_FRAMEWORK +void blk_update_perf_stats(struct bio *bio); +#else +static inline void blk_update_perf_stats(struct bio *bio) +{ + (void) bio; +} +#endif + /* * Internal atomic flags for request handling */ diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 8e3bff9c7fe9..ebbe31fee7ae 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -607,7 +607,7 @@ source "drivers/char/xillybus/Kconfig" config MSM_ADSPRPC tristate "QTI ADSP RPC driver" - depends on MSM_SMD + depends on MSM_GLINK help Provides a communication mechanism that allows for clients to make remote method invocations across processor boundary to diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c index 03429b18825b..95dca75efde9 100644 --- a/drivers/char/adsprpc.c +++ b/drivers/char/adsprpc.c @@ -25,7 +25,6 @@ #include <linux/hash.h> #include <linux/msm_ion.h> #include <soc/qcom/secure_buffer.h> -#include <soc/qcom/smd.h> #include <soc/qcom/glink.h> #include <soc/qcom/subsystem_notif.h> #include <soc/qcom/subsystem_restart.h> @@ -48,6 +47,7 @@ #include "adsprpc_compat.h" #include "adsprpc_shared.h" #include <soc/qcom/ramdump.h> +#include <linux/debugfs.h> #define TZ_PIL_PROTECT_MEM_SUBSYS_ID 0x0C #define TZ_PIL_CLEAR_PROTECT_MEM_SUBSYS_ID 0x0D @@ -55,6 +55,7 @@ #define ADSP_MMAP_HEAP_ADDR 4 #define FASTRPC_ENOSUCH 39 #define VMID_SSC_Q6 5 +#define DEBUGFS_SIZE 1024 #define RPC_TIMEOUT (5 * HZ) #define BALIGN 128 @@ -90,6 +91,8 @@ static int fastrpc_glink_open(int cid); static void fastrpc_glink_close(void *chan, int cid); +static struct dentry *debugfs_root; +static struct dentry *debugfs_global_file; static inline uint64_t buf_page_start(uint64_t buf) { @@ -207,7 +210,6 @@ struct fastrpc_channel_ctx { struct completion work; struct notifier_block nb; struct kref kref; - int channel; int sesscount; int ssrcount; void *handle; @@ -231,7 +233,6 @@ struct fastrpc_apps { spinlock_t hlock; struct ion_client *client; struct device *dev; - bool glink; }; struct fastrpc_mmap { @@ -283,6 +284,7 @@ struct fastrpc_file { int pd; struct fastrpc_apps *apps; struct fastrpc_perf perf; + struct dentry *debugfs_file; }; static struct fastrpc_apps gfa; @@ -291,21 +293,18 @@ static struct fastrpc_channel_ctx gcinfo[NUM_CHANNELS] = { { .name = "adsprpc-smd", .subsys = "adsp", - .channel = SMD_APPS_QDSP, .link.link_info.edge = "lpass", .link.link_info.transport = "smem", }, { .name = "mdsprpc-smd", .subsys = "modem", - .channel = SMD_APPS_MODEM, .link.link_info.edge = "mpss", .link.link_info.transport = "smem", }, { .name = "sdsprpc-smd", .subsys = "slpi", - .channel = SMD_APPS_DSPS, .link.link_info.edge = "dsps", .link.link_info.transport = "smem", .vmid = VMID_SSC_Q6, @@ -1348,7 +1347,7 @@ static int fastrpc_invoke_send(struct smq_invoke_ctx *ctx, struct smq_msg *msg = &ctx->msg; struct fastrpc_file *fl = ctx->fl; struct fastrpc_channel_ctx *channel_ctx = &fl->apps->channel[fl->cid]; - int err = 0, len; + int err = 0; VERIFY(err, 0 != channel_ctx->chan); if (err) @@ -1363,64 +1362,21 @@ static int fastrpc_invoke_send(struct smq_invoke_ctx *ctx, msg->invoke.page.addr = ctx->buf ? ctx->buf->phys : 0; msg->invoke.page.size = buf_page_size(ctx->used); - if (fl->apps->glink) { - if (fl->ssrcount != channel_ctx->ssrcount) { - err = -ECONNRESET; - goto bail; - } - VERIFY(err, channel_ctx->link.port_state == - FASTRPC_LINK_CONNECTED); - if (err) - goto bail; - err = glink_tx(channel_ctx->chan, - (void *)&fl->apps->channel[fl->cid], msg, sizeof(*msg), - GLINK_TX_REQ_INTENT); - } else { - spin_lock(&fl->apps->hlock); - len = smd_write((smd_channel_t *) - channel_ctx->chan, - msg, sizeof(*msg)); - spin_unlock(&fl->apps->hlock); - VERIFY(err, len == sizeof(*msg)); + if (fl->ssrcount != channel_ctx->ssrcount) { + err = -ECONNRESET; + goto bail; } + VERIFY(err, channel_ctx->link.port_state == + FASTRPC_LINK_CONNECTED); + if (err) + goto bail; + err = glink_tx(channel_ctx->chan, + (void *)&fl->apps->channel[fl->cid], msg, sizeof(*msg), + GLINK_TX_REQ_INTENT); bail: return err; } -static void fastrpc_smd_read_handler(int cid) -{ - struct fastrpc_apps *me = &gfa; - struct smq_invoke_rsp rsp = {0}; - int ret = 0; - - do { - ret = smd_read_from_cb(me->channel[cid].chan, &rsp, - sizeof(rsp)); - if (ret != sizeof(rsp)) - break; - rsp.ctx = rsp.ctx & ~1; - context_notify_user(uint64_to_ptr(rsp.ctx), rsp.retval); - } while (ret == sizeof(rsp)); -} - -static void smd_event_handler(void *priv, unsigned event) -{ - struct fastrpc_apps *me = &gfa; - int cid = (int)(uintptr_t)priv; - - switch (event) { - case SMD_EVENT_OPEN: - complete(&me->channel[cid].work); - break; - case SMD_EVENT_CLOSE: - fastrpc_notify_drivers(me, cid); - break; - case SMD_EVENT_DATA: - fastrpc_smd_read_handler(cid); - break; - } -} - static void fastrpc_init(struct fastrpc_apps *me) { int i; @@ -1883,11 +1839,7 @@ static void fastrpc_channel_close(struct kref *kref) ctx = container_of(kref, struct fastrpc_channel_ctx, kref); cid = ctx - &gcinfo[0]; - if (!me->glink) { - smd_close(ctx->chan); - } else { - fastrpc_glink_close(ctx->chan, cid); - } + fastrpc_glink_close(ctx->chan, cid); ctx->chan = 0; mutex_unlock(&me->smd_mutex); pr_info("'closed /dev/%s c %d %d'\n", gcinfo[cid].name, @@ -2042,6 +1994,8 @@ static int fastrpc_device_release(struct inode *inode, struct file *file) struct fastrpc_file *fl = (struct fastrpc_file *)file->private_data; if (fl) { + if (fl->debugfs_file != NULL) + debugfs_remove(fl->debugfs_file); fastrpc_file_free(fl); file->private_data = 0; } @@ -2158,9 +2112,124 @@ bail: return err; } +static int fastrpc_debugfs_open(struct inode *inode, struct file *filp) +{ + filp->private_data = inode->i_private; + return 0; +} + +static ssize_t fastrpc_debugfs_read(struct file *filp, char __user *buffer, + size_t count, loff_t *position) +{ + struct fastrpc_file *fl = filp->private_data; + struct hlist_node *n; + struct fastrpc_buf *buf = 0; + struct fastrpc_mmap *map = 0; + struct smq_invoke_ctx *ictx = 0; + struct fastrpc_channel_ctx *chan; + struct fastrpc_session_ctx *sess; + unsigned int len = 0; + int i, j, ret = 0; + char *fileinfo = NULL; + + fileinfo = kzalloc(DEBUGFS_SIZE, GFP_KERNEL); + if (!fileinfo) + goto bail; + if (fl == NULL) { + for (i = 0; i < NUM_CHANNELS; i++) { + chan = &gcinfo[i]; + len += scnprintf(fileinfo + len, + DEBUGFS_SIZE - len, "%s\n\n", + chan->name); + len += scnprintf(fileinfo + len, + DEBUGFS_SIZE - len, "%s %d\n", + "sesscount:", chan->sesscount); + for (j = 0; j < chan->sesscount; j++) { + sess = &chan->session[j]; + len += scnprintf(fileinfo + len, + DEBUGFS_SIZE - len, + "%s%d\n\n", "SESSION", j); + len += scnprintf(fileinfo + len, + DEBUGFS_SIZE - len, + "%s %d\n", "sid:", + sess->smmu.cb); + len += scnprintf(fileinfo + len, + DEBUGFS_SIZE - len, + "%s %d\n", "SECURE:", + sess->smmu.secure); + } + } + } else { + len += scnprintf(fileinfo + len, DEBUGFS_SIZE - len, + "%s %d\n\n", + "PROCESS_ID:", fl->tgid); + len += scnprintf(fileinfo + len, DEBUGFS_SIZE - len, + "%s %d\n\n", + "CHANNEL_ID:", fl->cid); + len += scnprintf(fileinfo + len, DEBUGFS_SIZE - len, + "%s %d\n\n", + "SSRCOUNT:", fl->ssrcount); + len += scnprintf(fileinfo + len, DEBUGFS_SIZE - len, + "%s\n", + "LIST OF BUFS:"); + spin_lock(&fl->hlock); + hlist_for_each_entry_safe(buf, n, &fl->bufs, hn) { + len += scnprintf(fileinfo + len, DEBUGFS_SIZE - len, + "%s %p %s %p %s %llx\n", "buf:", + buf, "buf->virt:", buf->virt, + "buf->phys:", buf->phys); + } + len += scnprintf(fileinfo + len, DEBUGFS_SIZE - len, + "\n%s\n", + "LIST OF MAPS:"); + hlist_for_each_entry_safe(map, n, &fl->maps, hn) { + len += scnprintf(fileinfo + len, DEBUGFS_SIZE - len, + "%s %p %s %lx %s %llx\n", + "map:", map, + "map->va:", map->va, + "map->phys:", map->phys); + } + len += scnprintf(fileinfo + len, DEBUGFS_SIZE - len, + "\n%s\n", + "LIST OF PENDING SMQCONTEXTS:"); + hlist_for_each_entry_safe(ictx, n, &fl->clst.pending, hn) { + len += scnprintf(fileinfo + len, DEBUGFS_SIZE - len, + "%s %p %s %u %s %u %s %u\n", + "smqcontext:", ictx, + "sc:", ictx->sc, + "tid:", ictx->pid, + "handle", ictx->rpra->h); + } + len += scnprintf(fileinfo + len, DEBUGFS_SIZE - len, + "\n%s\n", + "LIST OF INTERRUPTED SMQCONTEXTS:"); + hlist_for_each_entry_safe(ictx, n, &fl->clst.interrupted, hn) { + len += scnprintf(fileinfo + len, DEBUGFS_SIZE - len, + "%s %p %s %u %s %u %s %u\n", + "smqcontext:", ictx, + "sc:", ictx->sc, + "tid:", ictx->pid, + "handle", ictx->rpra->h); + } + spin_unlock(&fl->hlock); + } + if (len > DEBUGFS_SIZE) + len = DEBUGFS_SIZE; + ret = simple_read_from_buffer(buffer, count, position, fileinfo, len); + kfree(fileinfo); +bail: + return ret; +} + +static const struct file_operations debugfs_fops = { + .open = fastrpc_debugfs_open, + .read = fastrpc_debugfs_read, +}; + static int fastrpc_device_open(struct inode *inode, struct file *filp) { int cid = MINOR(inode->i_rdev); + struct dentry *debugfs_file; int err = 0; struct fastrpc_apps *me = &gfa; struct fastrpc_file *fl = 0; @@ -2173,6 +2242,8 @@ static int fastrpc_device_open(struct inode *inode, struct file *filp) mutex_lock(&me->smd_mutex); + debugfs_file = debugfs_create_file(current->comm, 0644, debugfs_root, + fl, &debugfs_fops); context_list_ctor(&fl->clst); spin_lock_init(&fl->hlock); INIT_HLIST_HEAD(&fl->maps); @@ -2181,6 +2252,8 @@ static int fastrpc_device_open(struct inode *inode, struct file *filp) fl->tgid = current->tgid; fl->apps = me; fl->cid = cid; + if (debugfs_file != NULL) + fl->debugfs_file = debugfs_file; memset(&fl->perf, 0, sizeof(fl->perf)); VERIFY(err, !fastrpc_session_alloc_locked(&me->channel[cid], 0, @@ -2191,16 +2264,8 @@ static int fastrpc_device_open(struct inode *inode, struct file *filp) fl->ssrcount = me->channel[cid].ssrcount; 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_open(cid)); - } else { - VERIFY(err, !smd_named_open_on_edge(FASTRPC_SMD_GUID, - gcinfo[cid].channel, - (smd_channel_t **)&me->channel[cid].chan, - (void *)(uintptr_t)cid, - smd_event_handler)); - } + fastrpc_glink_register(cid, me); + VERIFY(err, 0 == fastrpc_glink_open(cid)); if (err) goto bail; @@ -2387,11 +2452,7 @@ static int fastrpc_restart_notifier_cb(struct notifier_block *nb, mutex_lock(&me->smd_mutex); ctx->ssrcount++; if (ctx->chan) { - if (me->glink) { - fastrpc_glink_close(ctx->chan, cid); - } else { - smd_close(ctx->chan); - } + fastrpc_glink_close(ctx->chan, cid); ctx->chan = 0; pr_info("'restart notifier: closed /dev/%s c %d %d'\n", gcinfo[cid].name, MAJOR(me->dev_no), cid); @@ -2496,6 +2557,8 @@ static int fastrpc_cb_probe(struct device *dev) sess->dev = dev; sess->smmu.enabled = 1; chan->sesscount++; + debugfs_global_file = debugfs_create_file("global", 0644, debugfs_root, + NULL, &debugfs_fops); bail: return err; } @@ -2610,8 +2673,6 @@ static int fastrpc_probe(struct platform_device *pdev) return 0; } - me->glink = of_property_read_bool(dev->of_node, "qcom,fastrpc-glink"); - VERIFY(err, !of_platform_populate(pdev->dev.of_node, fastrpc_match_table, NULL, &pdev->dev)); @@ -2706,6 +2767,7 @@ static int __init fastrpc_device_init(void) VERIFY(err, !IS_ERR_OR_NULL(me->client)); if (err) goto device_create_bail; + debugfs_root = debugfs_create_dir("adsprpc", NULL); return 0; device_create_bail: for (i = 0; i < NUM_CHANNELS; i++) { @@ -2744,6 +2806,7 @@ static void __exit fastrpc_device_exit(void) cdev_del(&me->cdev); unregister_chrdev_region(me->dev_no, NUM_CHANNELS); ion_client_destroy(me->client); + debugfs_remove_recursive(debugfs_root); } late_initcall(fastrpc_device_init); diff --git a/drivers/clk/msm/clock-debug.c b/drivers/clk/msm/clock-debug.c index 00a86ba55171..0fe93ede17cc 100644 --- a/drivers/clk/msm/clock-debug.c +++ b/drivers/clk/msm/clock-debug.c @@ -1,6 +1,7 @@ /* * Copyright (C) 2007 Google, Inc. - * Copyright (c) 2007-2014, 2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2007-2014, 2016-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 @@ -77,6 +78,7 @@ static int clock_debug_measure_get(void *data, u64 *val) else is_hw_gated = 0; + mutex_lock(&clock->prepare_lock); ret = clk_set_parent(measure, clock); if (!ret) { /* @@ -107,6 +109,7 @@ static int clock_debug_measure_get(void *data, u64 *val) */ meas_rate = clk_get_rate(clock); sw_rate = clk_get_rate(measure->parent); + mutex_unlock(&clock->prepare_lock); if (sw_rate && meas_rate >= (sw_rate * 2)) *val *= DIV_ROUND_CLOSEST(meas_rate, sw_rate); diff --git a/drivers/clk/msm/clock-mmss-8998.c b/drivers/clk/msm/clock-mmss-8998.c index 2a112aad1fa3..eb543010c17b 100644 --- a/drivers/clk/msm/clock-mmss-8998.c +++ b/drivers/clk/msm/clock-mmss-8998.c @@ -527,6 +527,7 @@ static struct clk_freq_tbl ftbl_csiphy_clk_src[] = { static struct clk_freq_tbl ftbl_csiphy_clk_src_vq[] = { F_MM( 164570000, mmpll10_pll_out, 3.5, 0, 0), F_MM( 256000000, mmpll4_pll_out, 3, 0, 0), + F_MM( 274290000, mmpll7_pll_out, 3.5, 0, 0), F_MM( 300000000, mmsscc_gpll0, 2, 0, 0), F_MM( 384000000, mmpll4_pll_out, 2, 0, 0), F_END diff --git a/drivers/clk/qcom/gcc-sdm660.c b/drivers/clk/qcom/gcc-sdm660.c index 076ff3565ef4..d8ae85b65a47 100644 --- a/drivers/clk/qcom/gcc-sdm660.c +++ b/drivers/clk/qcom/gcc-sdm660.c @@ -818,7 +818,7 @@ static struct clk_rcg2 hmss_rbcpr_clk_src = { .parent_names = gcc_parent_names_ao_1, .num_parents = 3, .ops = &clk_rcg2_ops, - VDD_DIG_FMAX_MAP2( + VDD_DIG_FMAX_MAP2_AO( LOWER, 19200000, NOMINAL, 50000000), }, diff --git a/drivers/clk/qcom/vdd-level-660.h b/drivers/clk/qcom/vdd-level-660.h index f98a96033ea9..53317fe6d294 100644 --- a/drivers/clk/qcom/vdd-level-660.h +++ b/drivers/clk/qcom/vdd-level-660.h @@ -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 @@ -95,6 +95,14 @@ }, \ .num_rate_max = VDD_DIG_NUM +#define VDD_DIG_FMAX_MAP2_AO(l1, f1, l2, f2) \ + .vdd_class = &vdd_dig_ao, \ + .rate_max = (unsigned long[VDD_DIG_NUM]) { \ + [VDD_DIG_##l1] = (f1), \ + [VDD_DIG_##l2] = (f2), \ + }, \ + .num_rate_max = VDD_DIG_NUM + #define VDD_DIG_FMAX_MAP3_AO(l1, f1, l2, f2, l3, f3) \ .vdd_class = &vdd_dig_ao, \ .rate_max = (unsigned long[VDD_DIG_NUM]) { \ diff --git a/drivers/crypto/msm/qcedev.c b/drivers/crypto/msm/qcedev.c index 433e4783d1d1..9ab03209b680 100644 --- a/drivers/crypto/msm/qcedev.c +++ b/drivers/crypto/msm/qcedev.c @@ -1,6 +1,6 @@ /* Qualcomm CE device driver. * - * Copyright (c) 2010-2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2010-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 @@ -1381,7 +1381,7 @@ static int qcedev_check_cipher_key(struct qcedev_cipher_op_req *req, /* if not using HW key make sure key * length is valid */ - if ((req->mode == QCEDEV_AES_MODE_XTS)) { + if (req->mode == QCEDEV_AES_MODE_XTS) { if ((req->encklen != QCEDEV_AES_KEY_128*2) && (req->encklen != QCEDEV_AES_KEY_256*2)) { pr_err("%s: unsupported key size: %d\n", diff --git a/drivers/gpu/msm/adreno_a5xx_snapshot.c b/drivers/gpu/msm/adreno_a5xx_snapshot.c index bd93ded07131..bc7c0badf189 100644 --- a/drivers/gpu/msm/adreno_a5xx_snapshot.c +++ b/drivers/gpu/msm/adreno_a5xx_snapshot.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 @@ -943,11 +943,13 @@ void a5xx_snapshot(struct adreno_device *adreno_dev, a5xx_snapshot_debugbus(device, snapshot); /* Preemption record */ - FOR_EACH_RINGBUFFER(adreno_dev, rb, i) { - kgsl_snapshot_add_section(device, - KGSL_SNAPSHOT_SECTION_GPU_OBJECT_V2, - snapshot, snapshot_preemption_record, - &rb->preemption_desc); + if (adreno_is_preemption_enabled(adreno_dev)) { + FOR_EACH_RINGBUFFER(adreno_dev, rb, i) { + kgsl_snapshot_add_section(device, + KGSL_SNAPSHOT_SECTION_GPU_OBJECT_V2, + snapshot, snapshot_preemption_record, + &rb->preemption_desc); + } } } diff --git a/drivers/gpu/msm/kgsl_pool.c b/drivers/gpu/msm/kgsl_pool.c index bd1e432d8c7d..bb92b8b79d93 100644 --- a/drivers/gpu/msm/kgsl_pool.c +++ b/drivers/gpu/msm/kgsl_pool.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 @@ -299,6 +299,7 @@ int kgsl_pool_alloc_page(int *page_size, struct page **pages, struct page *p = NULL; int order = get_order(*page_size); int pool_idx; + size_t size = 0; if ((pages == NULL) || pages_len < (*page_size >> PAGE_SHIFT)) return -EINVAL; @@ -311,11 +312,8 @@ int kgsl_pool_alloc_page(int *page_size, struct page **pages, if (page == NULL) { /* Retry with lower order pages */ if (order > 0) { - size_t size = PAGE_SIZE << --order; - *page_size = kgsl_get_page_size(size, - ilog2(size)); - *align = ilog2(*page_size); - return -EAGAIN; + size = PAGE_SIZE << --order; + goto eagain; } else return -ENOMEM; @@ -325,8 +323,25 @@ int kgsl_pool_alloc_page(int *page_size, struct page **pages, } pool = _kgsl_get_pool_from_order(order); - if (pool == NULL) - return -EINVAL; + if (pool == NULL) { + /* Retry with lower order pages */ + if (order > 0) { + size = PAGE_SIZE << --order; + goto eagain; + } else { + /* + * Fall back to direct allocation in case + * pool with zero order is not present + */ + gfp_t gfp_mask = kgsl_gfp_mask(order); + + page = alloc_pages(gfp_mask, order); + if (page == NULL) + return -ENOMEM; + _kgsl_pool_zero_page(page, order); + goto done; + } + } pool_idx = kgsl_pool_idx_lookup(order); page = _kgsl_pool_get_page(pool); @@ -337,10 +352,9 @@ int kgsl_pool_alloc_page(int *page_size, struct page **pages, /* Only allocate non-reserved memory for certain pools */ if (!pool->allocation_allowed && pool_idx > 0) { - *page_size = PAGE_SIZE << + size = PAGE_SIZE << kgsl_pools[pool_idx-1].pool_order; - *align = ilog2(*page_size); - return -EAGAIN; + goto eagain; } page = alloc_pages(gfp_mask, order); @@ -348,10 +362,9 @@ int kgsl_pool_alloc_page(int *page_size, struct page **pages, if (!page) { if (pool_idx > 0) { /* Retry with lower order pages */ - *page_size = PAGE_SIZE << + size = PAGE_SIZE << kgsl_pools[pool_idx-1].pool_order; - *align = ilog2(*page_size); - return -EAGAIN; + goto eagain; } else return -ENOMEM; } @@ -367,6 +380,12 @@ done: } return pcount; + +eagain: + *page_size = kgsl_get_page_size(size, + ilog2(size)); + *align = ilog2(*page_size); + return -EAGAIN; } void kgsl_pool_free_page(struct page *page) diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c index cd9a82a9bf4a..fe6aa45901d0 100644 --- a/drivers/gpu/msm/kgsl_pwrctrl.c +++ b/drivers/gpu/msm/kgsl_pwrctrl.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2010-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 @@ -1994,6 +1994,42 @@ static int _isense_clk_set_rate(struct kgsl_pwrctrl *pwr, int level) return clk_set_rate(pwr->grp_clks[pwr->isense_clk_indx], rate); } +static inline void _close_pcl(struct kgsl_pwrctrl *pwr) +{ + if (pwr->pcl) + msm_bus_scale_unregister_client(pwr->pcl); + + pwr->pcl = 0; +} + +static inline void _close_ocmem_pcl(struct kgsl_pwrctrl *pwr) +{ + if (pwr->ocmem_pcl) + msm_bus_scale_unregister_client(pwr->ocmem_pcl); + + pwr->ocmem_pcl = 0; +} + +static inline void _close_regulators(struct kgsl_pwrctrl *pwr) +{ + int i; + + for (i = 0; i < KGSL_MAX_REGULATORS; i++) + pwr->regulators[i].reg = NULL; +} + +static inline void _close_clks(struct kgsl_device *device) +{ + struct kgsl_pwrctrl *pwr = &device->pwrctrl; + int i; + + for (i = 0; i < KGSL_MAX_CLKS; i++) + pwr->grp_clks[i] = NULL; + + if (pwr->gpu_bimc_int_clk) + devm_clk_put(&device->pdev->dev, pwr->gpu_bimc_int_clk); +} + int kgsl_pwrctrl_init(struct kgsl_device *device) { int i, k, m, n = 0, result; @@ -2011,7 +2047,7 @@ int kgsl_pwrctrl_init(struct kgsl_device *device) result = _get_clocks(device); if (result) - return result; + goto error_cleanup_clks; /* Make sure we have a source clk for freq setting */ if (pwr->grp_clks[0] == NULL) @@ -2029,7 +2065,8 @@ int kgsl_pwrctrl_init(struct kgsl_device *device) if (pwr->num_pwrlevels == 0) { KGSL_PWR_ERR(device, "No power levels are defined\n"); - return -EINVAL; + result = -EINVAL; + goto error_cleanup_clks; } /* Initialize the user and thermal clock constraints */ @@ -2059,7 +2096,7 @@ int kgsl_pwrctrl_init(struct kgsl_device *device) result = get_regulators(device); if (result) - return result; + goto error_cleanup_regulators; pwr->power_flags = 0; @@ -2079,8 +2116,10 @@ int kgsl_pwrctrl_init(struct kgsl_device *device) pwr->ocmem_pcl = msm_bus_scale_register_client (ocmem_scale_table); - if (!pwr->ocmem_pcl) - return -EINVAL; + if (!pwr->ocmem_pcl) { + result = -EINVAL; + goto error_disable_pm; + } } /* Bus width in bytes, set it to zero if not found */ @@ -2110,14 +2149,18 @@ int kgsl_pwrctrl_init(struct kgsl_device *device) * from the driver. */ pwr->pcl = msm_bus_scale_register_client(bus_scale_table); - if (pwr->pcl == 0) - return -EINVAL; + if (pwr->pcl == 0) { + result = -EINVAL; + goto error_cleanup_ocmem_pcl; + } } pwr->bus_ib = kzalloc(bus_scale_table->num_usecases * sizeof(*pwr->bus_ib), GFP_KERNEL); - if (pwr->bus_ib == NULL) - return -ENOMEM; + if (pwr->bus_ib == NULL) { + result = -ENOMEM; + goto error_cleanup_pcl; + } /* * Pull the BW vote out of the bus table. They will be used to @@ -2175,36 +2218,26 @@ int kgsl_pwrctrl_init(struct kgsl_device *device) &pwr->tsens_name); return result; + +error_cleanup_pcl: + _close_pcl(pwr); +error_cleanup_ocmem_pcl: + _close_ocmem_pcl(pwr); +error_disable_pm: + pm_runtime_disable(&pdev->dev); +error_cleanup_regulators: + _close_regulators(pwr); +error_cleanup_clks: + _close_clks(device); + return result; } void kgsl_pwrctrl_close(struct kgsl_device *device) { struct kgsl_pwrctrl *pwr = &device->pwrctrl; - int i; KGSL_PWR_INFO(device, "close device %d\n", device->id); - pm_runtime_disable(&device->pdev->dev); - - if (pwr->pcl) - msm_bus_scale_unregister_client(pwr->pcl); - - pwr->pcl = 0; - - if (pwr->ocmem_pcl) - msm_bus_scale_unregister_client(pwr->ocmem_pcl); - - pwr->ocmem_pcl = 0; - - for (i = 0; i < KGSL_MAX_REGULATORS; i++) - pwr->regulators[i].reg = NULL; - - for (i = 0; i < KGSL_MAX_REGULATORS; i++) - pwr->grp_clks[i] = NULL; - - if (pwr->gpu_bimc_int_clk) - devm_clk_put(&device->pdev->dev, pwr->gpu_bimc_int_clk); - pwr->power_flags = 0; if (!IS_ERR_OR_NULL(pwr->sysfs_pwr_limit)) { @@ -2213,6 +2246,16 @@ void kgsl_pwrctrl_close(struct kgsl_device *device) pwr->sysfs_pwr_limit = NULL; } kfree(pwr->bus_ib); + + _close_pcl(pwr); + + _close_ocmem_pcl(pwr); + + pm_runtime_disable(&device->pdev->dev); + + _close_regulators(pwr); + + _close_clks(device); } /** diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 70766e208217..ce15e150277e 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -410,8 +410,8 @@ struct arm_smmu_device { struct mutex power_lock; unsigned int power_count; - struct msm_bus_client_handle *bus_client; - char *bus_client_name; + u32 bus_client; + struct msm_bus_scale_pdata *bus_pdata; enum tz_smmu_device_id sec_id; }; @@ -912,14 +912,14 @@ static int arm_smmu_request_bus(struct arm_smmu_device *smmu) { if (!smmu->bus_client) return 0; - return msm_bus_scale_update_bw(smmu->bus_client, 0, 1000); + return msm_bus_scale_client_update_request(smmu->bus_client, 1); } static int arm_smmu_unrequest_bus(struct arm_smmu_device *smmu) { if (!smmu->bus_client) return 0; - return msm_bus_scale_update_bw(smmu->bus_client, 0, 0); + return msm_bus_scale_client_update_request(smmu->bus_client, 0); } static int arm_smmu_disable_regulators(struct arm_smmu_device *smmu) @@ -3531,8 +3531,10 @@ static int arm_smmu_init_clocks(struct arm_smmu_device *smmu) smmu->num_clocks = of_property_count_strings(dev->of_node, "clock-names"); - if (smmu->num_clocks < 1) + if (smmu->num_clocks < 1) { + smmu->num_clocks = 0; return 0; + } smmu->clocks = devm_kzalloc( dev, sizeof(*smmu->clocks) * smmu->num_clocks, @@ -3569,34 +3571,37 @@ static int arm_smmu_init_clocks(struct arm_smmu_device *smmu) static int arm_smmu_init_bus_scaling(struct platform_device *pdev, struct arm_smmu_device *smmu) { - u32 master_id; - - if (of_property_read_u32(pdev->dev.of_node, "qcom,bus-master-id", - &master_id)) { - dev_dbg(smmu->dev, "No bus scaling info\n"); + if (!of_find_property(pdev->dev.of_node, "qcom,msm-bus,name", NULL)) { + dev_dbg(&pdev->dev, "No bus scaling info\n"); return 0; } - smmu->bus_client_name = devm_kasprintf( - smmu->dev, GFP_KERNEL, "smmu-bus-client-%s", - dev_name(smmu->dev)); - - if (!smmu->bus_client_name) - return -ENOMEM; - - smmu->bus_client = msm_bus_scale_register( - master_id, MSM_BUS_SLAVE_EBI_CH0, smmu->bus_client_name, true); - if (IS_ERR(&smmu->bus_client)) { - int ret = PTR_ERR(smmu->bus_client); + smmu->bus_pdata = msm_bus_cl_get_pdata(pdev); + if (!smmu->bus_pdata) { + dev_err(&pdev->dev, "Unable to read bus-scaling from DT\n"); + return -EINVAL; + } - if (ret != -EPROBE_DEFER) - dev_err(smmu->dev, "Bus client registration failed\n"); - return ret; + smmu->bus_client = msm_bus_scale_register_client(smmu->bus_pdata); + if (!smmu->bus_client) { + dev_err(&pdev->dev, "Bus client registration failed\n"); + return -EINVAL; } return 0; } +static void arm_smmu_exit_bus_scaling(struct arm_smmu_device *smmu) +{ + if (smmu->bus_client) + msm_bus_scale_unregister_client(smmu->bus_client); + if (smmu->bus_pdata) + msm_bus_cl_clear_pdata(smmu->bus_pdata); + + smmu->bus_client = 0; + smmu->bus_pdata = NULL; +} + static int arm_smmu_parse_impl_def_registers(struct arm_smmu_device *smmu) { struct device *dev = smmu->dev; @@ -4033,6 +4038,7 @@ out_free_irqs: free_irq(smmu->irqs[i], smmu); out_put_masters: + arm_smmu_exit_bus_scaling(smmu); for (node = rb_first(&smmu->masters); node; node = rb_next(node)) { struct arm_smmu_master *master = container_of(node, struct arm_smmu_master, node); @@ -4084,7 +4090,7 @@ static int arm_smmu_device_remove(struct platform_device *pdev) arm_smmu_power_off(smmu); mutex_unlock(&smmu->attach_lock); - msm_bus_scale_unregister(smmu->bus_client); + arm_smmu_exit_bus_scaling(smmu); return 0; } diff --git a/drivers/mfd/qcom-i2c-pmic.c b/drivers/mfd/qcom-i2c-pmic.c index ea5ac972b096..590e4c1a3f52 100644 --- a/drivers/mfd/qcom-i2c-pmic.c +++ b/drivers/mfd/qcom-i2c-pmic.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 @@ -467,12 +467,29 @@ static int i2c_pmic_parse_dt(struct i2c_pmic *chip) return rc; } +#define MAX_I2C_RETRIES 3 +static int i2c_pmic_read(struct regmap *map, unsigned int reg, void *val, + size_t val_count) +{ + int rc, retries = 0; + + do { + rc = regmap_bulk_read(map, reg, val, val_count); + } while (rc == -ENOTCONN && retries++ < MAX_I2C_RETRIES); + + if (retries > 1) + pr_err("i2c_pmic_read failed for %d retries, rc = %d\n", + retries - 1, rc); + + return rc; +} + static int i2c_pmic_determine_initial_status(struct i2c_pmic *chip) { int rc, i; for (i = 0; i < chip->num_periphs; i++) { - rc = regmap_bulk_read(chip->regmap, + rc = i2c_pmic_read(chip->regmap, chip->periph[i].addr | INT_SET_TYPE_OFFSET, chip->periph[i].cached, IRQ_MAX_REGS); if (rc < 0) { diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c index 3d346d85d45a..1653f7e1ae99 100644 --- a/drivers/misc/qseecom.c +++ b/drivers/misc/qseecom.c @@ -4432,6 +4432,7 @@ int qseecom_start_app(struct qseecom_handle **handle, strlcpy(entry->app_name, app_name, MAX_APP_NAME_SIZE); if (__qseecom_get_fw_size(app_name, &fw_size, &app_arch)) { ret = -EIO; + kfree(entry); goto err; } entry->app_arch = app_arch; diff --git a/drivers/mmc/core/Kconfig b/drivers/mmc/core/Kconfig index 57cc6b29b2d0..9e0ccdc44d6b 100644 --- a/drivers/mmc/core/Kconfig +++ b/drivers/mmc/core/Kconfig @@ -2,6 +2,17 @@ # MMC core configuration # +config MMC_RING_BUFFER + bool "MMC_RING_BUFFER" + depends on MMC + default n + help + This enables the ring buffer tracing of significant + events for mmc driver to provide command history for + debugging purpose. + + If unsure, say N. + config MMC_EMBEDDED_SDIO boolean "MMC embedded SDIO device support (EXPERIMENTAL)" help diff --git a/drivers/mmc/core/Makefile b/drivers/mmc/core/Makefile index 2c25138f28b7..60781dd192ab 100644 --- a/drivers/mmc/core/Makefile +++ b/drivers/mmc/core/Makefile @@ -10,3 +10,4 @@ mmc_core-y := core.o bus.o host.o \ quirks.o slot-gpio.o mmc_core-$(CONFIG_OF) += pwrseq.o pwrseq_simple.o pwrseq_emmc.o mmc_core-$(CONFIG_DEBUG_FS) += debugfs.o +obj-$(CONFIG_MMC_RING_BUFFER) += ring_buffer.o diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c index c894f64c2e38..a0d31ded04db 100644 --- a/drivers/mmc/core/debugfs.c +++ b/drivers/mmc/core/debugfs.c @@ -32,6 +32,26 @@ module_param(fail_request, charp, 0); #endif /* CONFIG_FAIL_MMC_REQUEST */ /* The debugfs functions are optimized away when CONFIG_DEBUG_FS isn't set. */ +static int mmc_ring_buffer_show(struct seq_file *s, void *data) +{ + struct mmc_host *mmc = s->private; + + mmc_dump_trace_buffer(mmc, s); + return 0; +} + +static int mmc_ring_buffer_open(struct inode *inode, struct file *file) +{ + return single_open(file, mmc_ring_buffer_show, inode->i_private); +} + +static const struct file_operations mmc_ring_buffer_fops = { + .open = mmc_ring_buffer_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + static int mmc_ios_show(struct seq_file *s, void *data) { static const char *vdd_str[] = { @@ -368,6 +388,11 @@ void mmc_add_host_debugfs(struct mmc_host *host) &host->cmdq_thist_enabled)) goto err_node; +#ifdef CONFIG_MMC_RING_BUFFER + if (!debugfs_create_file("ring_buffer", S_IRUSR, + root, host, &mmc_ring_buffer_fops)) + goto err_node; +#endif #ifdef CONFIG_MMC_CLKGATE if (!debugfs_create_u32("clk_delay", (S_IRUSR | S_IWUSR), root, &host->clk_delay)) diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index f6a54a8e1076..333f691a73c7 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -26,6 +26,8 @@ #include <linux/mmc/host.h> #include <linux/mmc/card.h> +#include <linux/mmc/ring_buffer.h> + #include <linux/mmc/slot-gpio.h> #include "core.h" @@ -869,6 +871,7 @@ int mmc_add_host(struct mmc_host *host) mmc_add_host_debugfs(host); #endif mmc_host_clk_sysfs_init(host); + mmc_trace_init(host); err = sysfs_create_group(&host->class_dev.kobj, &clk_scaling_attr_grp); if (err) diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 449514bae4f3..414877874190 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -2635,6 +2635,7 @@ static int mmc_suspend(struct mmc_host *host) int err; ktime_t start = ktime_get(); + MMC_TRACE(host, "%s: Enter\n", __func__); err = _mmc_suspend(host, true); if (!err) { pm_runtime_disable(&host->card->dev); @@ -2643,6 +2644,7 @@ static int mmc_suspend(struct mmc_host *host) trace_mmc_suspend(mmc_hostname(host), err, ktime_to_us(ktime_sub(ktime_get(), start))); + MMC_TRACE(host, "%s: Exit err: %d\n", __func__, err); return err; } @@ -2718,6 +2720,7 @@ static int mmc_resume(struct mmc_host *host) int err = 0; ktime_t start = ktime_get(); + MMC_TRACE(host, "%s: Enter\n", __func__); if (!(host->caps & MMC_CAP_RUNTIME_RESUME)) { err = _mmc_resume(host); pm_runtime_set_active(&host->card->dev); @@ -2727,7 +2730,7 @@ static int mmc_resume(struct mmc_host *host) trace_mmc_resume(mmc_hostname(host), err, ktime_to_us(ktime_sub(ktime_get(), start))); - + MMC_TRACE(host, "%s: Exit err: %d\n", __func__, err); return err; } diff --git a/drivers/mmc/core/ring_buffer.c b/drivers/mmc/core/ring_buffer.c new file mode 100644 index 000000000000..83945e1cae40 --- /dev/null +++ b/drivers/mmc/core/ring_buffer.c @@ -0,0 +1,123 @@ +/* + * Copyright (c) 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/mmc/ring_buffer.h> +#include <linux/mmc/host.h> + +void mmc_stop_tracing(struct mmc_host *mmc) +{ + mmc->trace_buf.stop_tracing = true; +} + +void mmc_trace_write(struct mmc_host *mmc, + const char *fmt, ...) +{ + unsigned int idx; + va_list args; + char *event; + unsigned long flags; + char str[MMC_TRACE_EVENT_SZ]; + + if (unlikely(!mmc->trace_buf.data) || + unlikely(mmc->trace_buf.stop_tracing)) + return; + + /* + * Here an increment and modulus is used to keep + * index within array bounds. The cast to unsigned is + * necessary so increment and rolover wraps to 0 correctly + */ + spin_lock_irqsave(&mmc->trace_buf.trace_lock, flags); + mmc->trace_buf.wr_idx += 1; + idx = ((unsigned int)mmc->trace_buf.wr_idx) & + (MMC_TRACE_RBUF_NUM_EVENTS - 1); + spin_unlock_irqrestore(&mmc->trace_buf.trace_lock, flags); + + /* Catch some unlikely machine specific wrap-around bug */ + if (unlikely(idx > (MMC_TRACE_RBUF_NUM_EVENTS - 1))) { + pr_err("%s: %s: Invalid idx:%d for mmc trace, tracing stopped !\n", + mmc_hostname(mmc), __func__, idx); + mmc_stop_tracing(mmc); + return; + } + + event = &mmc->trace_buf.data[idx * MMC_TRACE_EVENT_SZ]; + va_start(args, fmt); + snprintf(str, MMC_TRACE_EVENT_SZ, "<%d> %lld: %s: %s", + raw_smp_processor_id(), + ktime_to_ns(ktime_get()), + mmc_hostname(mmc), fmt); + memset(event, '\0', MMC_TRACE_EVENT_SZ); + vscnprintf(event, MMC_TRACE_EVENT_SZ, str, args); + va_end(args); +} + +void mmc_trace_init(struct mmc_host *mmc) +{ + BUILD_BUG_ON_NOT_POWER_OF_2(MMC_TRACE_RBUF_NUM_EVENTS); + + mmc->trace_buf.data = (char *) + __get_free_pages(GFP_KERNEL|__GFP_ZERO, + MMC_TRACE_RBUF_SZ_ORDER); + + if (!mmc->trace_buf.data) { + pr_err("%s: %s: Unable to allocate trace for mmc\n", + __func__, mmc_hostname(mmc)); + return; + } + + spin_lock_init(&mmc->trace_buf.trace_lock); + mmc->trace_buf.wr_idx = -1; +} + +void mmc_trace_free(struct mmc_host *mmc) +{ + if (mmc->trace_buf.data) + free_pages((unsigned long)mmc->trace_buf.data, + MMC_TRACE_RBUF_SZ_ORDER); +} + +void mmc_dump_trace_buffer(struct mmc_host *mmc, struct seq_file *s) +{ + unsigned int idx, cur_idx; + unsigned int N = MMC_TRACE_RBUF_NUM_EVENTS - 1; + char *event; + unsigned long flags; + + if (!mmc->trace_buf.data) + return; + + spin_lock_irqsave(&mmc->trace_buf.trace_lock, flags); + idx = ((unsigned int)mmc->trace_buf.wr_idx) & N; + cur_idx = (idx + 1) & N; + + do { + event = &mmc->trace_buf.data[cur_idx * MMC_TRACE_EVENT_SZ]; + if (s) + seq_printf(s, "%s", (char *)event); + else + pr_err("%s", (char *)event); + cur_idx = (cur_idx + 1) & N; + if (cur_idx == idx) { + event = + &mmc->trace_buf.data[cur_idx * MMC_TRACE_EVENT_SZ]; + if (s) + seq_printf(s, "latest_event: %s", + (char *)event); + else + pr_err("latest_event: %s", (char *)event); + break; + } + } while (1); + spin_unlock_irqrestore(&mmc->trace_buf.trace_lock, flags); +} diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index 7b84030ffe92..7e7d7eb4da2a 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -1222,11 +1222,13 @@ static int mmc_sd_suspend(struct mmc_host *host) { int err; + MMC_TRACE(host, "%s: Enter\n", __func__); err = _mmc_sd_suspend(host); if (!err) { pm_runtime_disable(&host->card->dev); pm_runtime_set_suspended(&host->card->dev); } + MMC_TRACE(host, "%s: Exit err: %d\n", __func__, err); return err; } @@ -1292,12 +1294,14 @@ static int mmc_sd_resume(struct mmc_host *host) { int err = 0; + MMC_TRACE(host, "%s: Enter\n", __func__); if (!(host->caps & MMC_CAP_RUNTIME_RESUME)) { err = _mmc_sd_resume(host); pm_runtime_set_active(&host->card->dev); pm_runtime_mark_last_busy(&host->card->dev); } pm_runtime_enable(&host->card->dev); + MMC_TRACE(host, "%s: Exit err: %d\n", __func__, err); return err; } diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 5fedab49cf34..13a2f2d14d12 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -998,6 +998,7 @@ static int mmc_sdio_pre_suspend(struct mmc_host *host) */ static int mmc_sdio_suspend(struct mmc_host *host) { + MMC_TRACE(host, "%s: Enter\n", __func__); mmc_claim_host(host); if (mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)) @@ -1013,7 +1014,7 @@ static int mmc_sdio_suspend(struct mmc_host *host) } mmc_release_host(host); - + MMC_TRACE(host, "%s: Exit\n", __func__); return 0; } @@ -1024,6 +1025,7 @@ static int mmc_sdio_resume(struct mmc_host *host) BUG_ON(!host); BUG_ON(!host->card); + MMC_TRACE(host, "%s: Enter\n", __func__); /* Basic card reinitialization. */ mmc_claim_host(host); @@ -1079,6 +1081,7 @@ static int mmc_sdio_resume(struct mmc_host *host) host->pm_flags &= ~MMC_PM_KEEP_POWER; host->pm_flags &= ~MMC_PM_WAKE_SDIO_IRQ; + MMC_TRACE(host, "%s: Exit err: %d\n", __func__, err); return err; } diff --git a/drivers/mmc/host/cmdq_hci.c b/drivers/mmc/host/cmdq_hci.c index 52427815722b..d712f29da9f1 100644 --- a/drivers/mmc/host/cmdq_hci.c +++ b/drivers/mmc/host/cmdq_hci.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 @@ -198,6 +198,14 @@ static void cmdq_dumpregs(struct cmdq_host *cq_host) { struct mmc_host *mmc = cq_host->mmc; + MMC_TRACE(mmc, + "%s: 0x0C=0x%08x 0x10=0x%08x 0x14=0x%08x 0x18=0x%08x 0x28=0x%08x 0x2C=0x%08x 0x30=0x%08x 0x34=0x%08x 0x54=0x%08x 0x58=0x%08x 0x5C=0x%08x 0x48=0x%08x\n", + __func__, cmdq_readl(cq_host, CQCTL), cmdq_readl(cq_host, CQIS), + cmdq_readl(cq_host, CQISTE), cmdq_readl(cq_host, CQISGE), + cmdq_readl(cq_host, CQTDBR), cmdq_readl(cq_host, CQTCN), + cmdq_readl(cq_host, CQDQS), cmdq_readl(cq_host, CQDPT), + cmdq_readl(cq_host, CQTERRI), cmdq_readl(cq_host, CQCRI), + cmdq_readl(cq_host, CQCRA), cmdq_readl(cq_host, CQCRDCT)); pr_err(DRV_NAME ": ========== REGISTER DUMP (%s)==========\n", mmc_hostname(mmc)); @@ -426,6 +434,7 @@ static int cmdq_enable(struct mmc_host *mmc) pm_ref_count: cmdq_runtime_pm_put(cq_host); out: + MMC_TRACE(mmc, "%s: CQ enabled err: %d\n", __func__, err); return err; } @@ -443,6 +452,7 @@ static void cmdq_disable_nosync(struct mmc_host *mmc, bool soft) cq_host->enabled = false; mmc_host_set_cq_disable(mmc); + MMC_TRACE(mmc, "%s: CQ disabled\n", __func__); } static void cmdq_disable(struct mmc_host *mmc, bool soft) @@ -525,6 +535,12 @@ static void cmdq_prep_task_desc(struct mmc_request *mrq, REL_WRITE(!!(req_flags & REL_WR)) | BLK_COUNT(mrq->cmdq_req->data.blocks) | BLK_ADDR((u64)mrq->cmdq_req->blk_addr); + + MMC_TRACE(mrq->host, + "%s: Task: 0x%08x | Args: 0x%08x | cnt: 0x%08x\n", __func__, + lower_32_bits(*data), + upper_32_bits(*data), + mrq->cmdq_req->data.blocks); } static int cmdq_dma_map(struct mmc_host *host, struct mmc_request *mrq) @@ -665,6 +681,11 @@ static void cmdq_prep_dcmd_desc(struct mmc_host *mmc, dataddr = (__le64 __force *)(desc + 4); dataddr[0] = cpu_to_le64((u64)mrq->cmd->arg); cmdq_log_task_desc_history(cq_host, *task_desc, true); + MMC_TRACE(mrq->host, + "%s: DCMD: Task: 0x%08x | Args: 0x%08x\n", + __func__, + lower_32_bits(*task_desc), + upper_32_bits(*task_desc)); } static void cmdq_pm_qos_vote(struct sdhci_host *host, struct mmc_request *mrq) @@ -743,6 +764,7 @@ ring_doorbell: cmdq_dumpregs(cq_host); BUG_ON(1); } + MMC_TRACE(mmc, "%s: tag: %d\n", __func__, tag); cmdq_writel(cq_host, 1 << tag, CQTDBR); /* Commit the doorbell write immediately */ wmb(); @@ -785,6 +807,8 @@ irqreturn_t cmdq_irq(struct mmc_host *mmc, int err) if (!status && !err) return IRQ_NONE; + MMC_TRACE(mmc, "%s: CQIS: 0x%x err: %d\n", + __func__, status, err); if (err || (status & CQIS_RED)) { err_info = cmdq_readl(cq_host, CQTERRI); @@ -920,7 +944,9 @@ skip_cqterri: /* complete the corresponding mrq */ pr_debug("%s: completing tag -> %lu\n", mmc_hostname(mmc), tag); - cmdq_finish_data(mmc, tag); + MMC_TRACE(mmc, "%s: completing tag -> %lu\n", + __func__, tag); + cmdq_finish_data(mmc, tag); } } @@ -997,6 +1023,8 @@ static int cmdq_halt(struct mmc_host *mmc, bool halt) retries--; continue; } else { + MMC_TRACE(mmc, "%s: halt done , retries: %d\n", + __func__, retries); /* halt done: re-enable legacy interrupts */ if (cq_host->ops->clear_set_irqs) cq_host->ops->clear_set_irqs(mmc, @@ -1014,6 +1042,7 @@ static int cmdq_halt(struct mmc_host *mmc, bool halt) cq_host->ops->set_data_timeout(mmc, 0xf); if (cq_host->ops->clear_set_irqs) cq_host->ops->clear_set_irqs(mmc, true); + MMC_TRACE(mmc, "%s: unhalt done\n", __func__); cmdq_writel(cq_host, cmdq_readl(cq_host, CQCTL) & ~HALT, CQCTL); } diff --git a/drivers/mmc/host/sdhci-msm-ice.c b/drivers/mmc/host/sdhci-msm-ice.c index abf2ae2020c9..2ef459582aae 100644 --- a/drivers/mmc/host/sdhci-msm-ice.c +++ b/drivers/mmc/host/sdhci-msm-ice.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 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 @@ -102,7 +102,7 @@ int sdhci_msm_ice_init(struct sdhci_host *host) struct sdhci_msm_host *msm_host = pltfm_host->priv; int err = 0; - if (msm_host->ice.vops->config) { + if (msm_host->ice.vops->init) { err = msm_host->ice.vops->init(msm_host->ice.pdev, msm_host, sdhci_msm_ice_error_cb); @@ -148,9 +148,10 @@ int sdhci_msm_ice_cfg(struct sdhci_host *host, struct mmc_request *mrq, req = mrq->req; if (req) { lba = req->__sector; - if (msm_host->ice.vops->config) { - err = msm_host->ice.vops->config(msm_host->ice.pdev, - req, &ice_set); + if (msm_host->ice.vops->config_start) { + err = msm_host->ice.vops->config_start( + msm_host->ice.pdev, + req, &ice_set, false); if (err) { pr_err("%s: ice config failed %d\n", mmc_hostname(host->mmc), err); diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 203daf3bd5eb..466e0a2c8483 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -2,7 +2,7 @@ * drivers/mmc/host/sdhci-msm.c - Qualcomm Technologies, Inc. MSM SDHCI Platform * driver source file * - * Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-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 @@ -3293,6 +3293,11 @@ void sdhci_msm_dump_vendor_regs(struct sdhci_host *host) if (host->cq_host) sdhci_msm_cmdq_dump_debug_ram(host); + MMC_TRACE(host->mmc, "Data cnt: 0x%08x | Fifo cnt: 0x%08x\n", + sdhci_msm_readl_relaxed(host, + msm_host_offset->CORE_MCI_DATA_CNT), + sdhci_msm_readl_relaxed(host, + msm_host_offset->CORE_MCI_FIFO_CNT)); pr_info("Data cnt: 0x%08x | Fifo cnt: 0x%08x | Int sts: 0x%08x\n", sdhci_msm_readl_relaxed(host, msm_host_offset->CORE_MCI_DATA_CNT), diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 08822464d82f..3fd564388720 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -111,6 +111,17 @@ static void sdhci_dump_state(struct sdhci_host *host) static void sdhci_dumpregs(struct sdhci_host *host) { + MMC_TRACE(host->mmc, + "%s: 0x04=0x%08x 0x06=0x%08x 0x0E=0x%08x 0x30=0x%08x 0x34=0x%08x 0x38=0x%08x\n", + __func__, + sdhci_readw(host, SDHCI_BLOCK_SIZE), + sdhci_readw(host, SDHCI_BLOCK_COUNT), + sdhci_readw(host, SDHCI_COMMAND), + sdhci_readl(host, SDHCI_INT_STATUS), + sdhci_readl(host, SDHCI_INT_ENABLE), + sdhci_readl(host, SDHCI_SIGNAL_ENABLE)); + mmc_stop_tracing(host->mmc); + pr_info(DRIVER_NAME ": =========== REGISTER DUMP (%s)===========\n", mmc_hostname(host->mmc)); @@ -1013,6 +1024,11 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd) /* Set the DMA boundary value and block size */ sdhci_set_blk_size_reg(host, data->blksz, SDHCI_DEFAULT_BOUNDARY_ARG); sdhci_writew(host, data->blocks, SDHCI_BLOCK_COUNT); + MMC_TRACE(host->mmc, + "%s: 0x28=0x%08x 0x3E=0x%08x 0x06=0x%08x\n", __func__, + sdhci_readb(host, SDHCI_HOST_CONTROL), + sdhci_readw(host, SDHCI_HOST_CONTROL2), + sdhci_readw(host, SDHCI_BLOCK_COUNT)); } static void sdhci_set_transfer_mode(struct sdhci_host *host, @@ -1071,6 +1087,9 @@ static void sdhci_set_transfer_mode(struct sdhci_host *host, mode |= SDHCI_TRNS_DMA; sdhci_writew(host, mode, SDHCI_TRANSFER_MODE); + MMC_TRACE(host->mmc, "%s: 0x00=0x%08x 0x0C=0x%08x\n", __func__, + sdhci_readw(host, SDHCI_ARGUMENT2), + sdhci_readw(host, SDHCI_TRANSFER_MODE)); } static void sdhci_finish_data(struct sdhci_host *host) @@ -1082,6 +1101,8 @@ static void sdhci_finish_data(struct sdhci_host *host) data = host->data; host->data = NULL; + MMC_TRACE(host->mmc, "%s: 0x24=0x%08x\n", __func__, + sdhci_readl(host, SDHCI_PRESENT_STATE)); if (host->flags & SDHCI_REQ_USE_DMA) { if (host->flags & SDHCI_USE_ADMA) sdhci_adma_table_post(host, data); @@ -1210,6 +1231,11 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) if (cmd->data) host->data_start_time = ktime_get(); trace_mmc_cmd_rw_start(cmd->opcode, cmd->arg, cmd->flags); + MMC_TRACE(host->mmc, + "%s: updated 0x8=0x%08x 0xC=0x%08x 0xE=0x%08x\n", __func__, + sdhci_readl(host, SDHCI_ARGUMENT), + sdhci_readw(host, SDHCI_TRANSFER_MODE), + sdhci_readw(host, SDHCI_COMMAND)); sdhci_writew(host, SDHCI_MAKE_CMD(cmd->opcode, flags), SDHCI_COMMAND); } EXPORT_SYMBOL_GPL(sdhci_send_command); @@ -1231,8 +1257,14 @@ static void sdhci_finish_command(struct sdhci_host *host) sdhci_readb(host, SDHCI_RESPONSE + (3-i)*4-1); } + MMC_TRACE(host->mmc, + "%s: resp 0: 0x%08x resp 1: 0x%08x resp 2: 0x%08x resp 3: 0x%08x\n", + __func__, host->cmd->resp[0], host->cmd->resp[1], + host->cmd->resp[2], host->cmd->resp[3]); } else { host->cmd->resp[0] = sdhci_readl(host, SDHCI_RESPONSE); + MMC_TRACE(host->mmc, "%s: resp 0: 0x%08x\n", + __func__, host->cmd->resp[0]); } } @@ -3169,6 +3201,9 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) goto out; } + MMC_TRACE(host->mmc, + "%s: intmask: 0x%x\n", __func__, intmask); + if (intmask & SDHCI_INT_AUTO_CMD_ERR) host->auto_cmd_err_sts = sdhci_readw(host, SDHCI_AUTO_CMD_ERR); diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c index e7205546fa6b..080a26d744ee 100644 --- a/drivers/net/wireless/ath/ath10k/ce.c +++ b/drivers/net/wireless/ath/ath10k/ce.c @@ -16,7 +16,6 @@ */ #include "hif.h" -#include "pci.h" #include "ce.h" #include "debug.h" @@ -63,56 +62,56 @@ static inline void ath10k_ce_dest_ring_write_index_set(struct ath10k *ar, u32 ce_ctrl_addr, unsigned int n) { - ath10k_pci_write32(ar, ce_ctrl_addr + DST_WR_INDEX_ADDRESS, n); + ar->bus_write32(ar, ce_ctrl_addr + DST_WR_INDEX_ADDRESS, n); } static inline u32 ath10k_ce_dest_ring_write_index_get(struct ath10k *ar, u32 ce_ctrl_addr) { - return ath10k_pci_read32(ar, ce_ctrl_addr + DST_WR_INDEX_ADDRESS); + return ar->bus_read32(ar, ce_ctrl_addr + DST_WR_INDEX_ADDRESS); } static inline void ath10k_ce_src_ring_write_index_set(struct ath10k *ar, u32 ce_ctrl_addr, unsigned int n) { - ath10k_pci_write32(ar, ce_ctrl_addr + SR_WR_INDEX_ADDRESS, n); + ar->bus_write32(ar, ce_ctrl_addr + SR_WR_INDEX_ADDRESS, n); } static inline u32 ath10k_ce_src_ring_write_index_get(struct ath10k *ar, u32 ce_ctrl_addr) { - return ath10k_pci_read32(ar, ce_ctrl_addr + SR_WR_INDEX_ADDRESS); + return ar->bus_read32(ar, ce_ctrl_addr + SR_WR_INDEX_ADDRESS); } static inline u32 ath10k_ce_src_ring_read_index_get(struct ath10k *ar, u32 ce_ctrl_addr) { - return ath10k_pci_read32(ar, ce_ctrl_addr + CURRENT_SRRI_ADDRESS); + return ar->bus_read32(ar, ce_ctrl_addr + CURRENT_SRRI_ADDRESS); } static inline void ath10k_ce_src_ring_base_addr_set(struct ath10k *ar, u32 ce_ctrl_addr, unsigned int addr) { - ath10k_pci_write32(ar, ce_ctrl_addr + SR_BA_ADDRESS, addr); + ar->bus_write32(ar, ce_ctrl_addr + SR_BA_ADDRESS, addr); } static inline void ath10k_ce_src_ring_size_set(struct ath10k *ar, u32 ce_ctrl_addr, unsigned int n) { - ath10k_pci_write32(ar, ce_ctrl_addr + SR_SIZE_ADDRESS, n); + ar->bus_write32(ar, ce_ctrl_addr + SR_SIZE_ADDRESS, n); } static inline void ath10k_ce_src_ring_dmax_set(struct ath10k *ar, u32 ce_ctrl_addr, unsigned int n) { - u32 ctrl1_addr = ath10k_pci_read32((ar), + u32 ctrl1_addr = ar->bus_read32((ar), (ce_ctrl_addr) + CE_CTRL1_ADDRESS); - ath10k_pci_write32(ar, ce_ctrl_addr + CE_CTRL1_ADDRESS, + ar->bus_write32(ar, ce_ctrl_addr + CE_CTRL1_ADDRESS, (ctrl1_addr & ~CE_CTRL1_DMAX_LENGTH_MASK) | CE_CTRL1_DMAX_LENGTH_SET(n)); } @@ -121,9 +120,9 @@ static inline void ath10k_ce_src_ring_byte_swap_set(struct ath10k *ar, u32 ce_ctrl_addr, unsigned int n) { - u32 ctrl1_addr = ath10k_pci_read32(ar, ce_ctrl_addr + CE_CTRL1_ADDRESS); + u32 ctrl1_addr = ar->bus_read32(ar, ce_ctrl_addr + CE_CTRL1_ADDRESS); - ath10k_pci_write32(ar, ce_ctrl_addr + CE_CTRL1_ADDRESS, + ar->bus_write32(ar, ce_ctrl_addr + CE_CTRL1_ADDRESS, (ctrl1_addr & ~CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MASK) | CE_CTRL1_SRC_RING_BYTE_SWAP_EN_SET(n)); } @@ -132,9 +131,9 @@ static inline void ath10k_ce_dest_ring_byte_swap_set(struct ath10k *ar, u32 ce_ctrl_addr, unsigned int n) { - u32 ctrl1_addr = ath10k_pci_read32(ar, ce_ctrl_addr + CE_CTRL1_ADDRESS); + u32 ctrl1_addr = ar->bus_read32(ar, ce_ctrl_addr + CE_CTRL1_ADDRESS); - ath10k_pci_write32(ar, ce_ctrl_addr + CE_CTRL1_ADDRESS, + ar->bus_write32(ar, ce_ctrl_addr + CE_CTRL1_ADDRESS, (ctrl1_addr & ~CE_CTRL1_DST_RING_BYTE_SWAP_EN_MASK) | CE_CTRL1_DST_RING_BYTE_SWAP_EN_SET(n)); } @@ -142,30 +141,30 @@ static inline void ath10k_ce_dest_ring_byte_swap_set(struct ath10k *ar, static inline u32 ath10k_ce_dest_ring_read_index_get(struct ath10k *ar, u32 ce_ctrl_addr) { - return ath10k_pci_read32(ar, ce_ctrl_addr + CURRENT_DRRI_ADDRESS); + return ar->bus_read32(ar, ce_ctrl_addr + CURRENT_DRRI_ADDRESS); } static inline void ath10k_ce_dest_ring_base_addr_set(struct ath10k *ar, u32 ce_ctrl_addr, u32 addr) { - ath10k_pci_write32(ar, ce_ctrl_addr + DR_BA_ADDRESS, addr); + ar->bus_write32(ar, ce_ctrl_addr + DR_BA_ADDRESS, addr); } static inline void ath10k_ce_dest_ring_size_set(struct ath10k *ar, u32 ce_ctrl_addr, unsigned int n) { - ath10k_pci_write32(ar, ce_ctrl_addr + DR_SIZE_ADDRESS, n); + ar->bus_write32(ar, ce_ctrl_addr + DR_SIZE_ADDRESS, n); } static inline void ath10k_ce_src_ring_highmark_set(struct ath10k *ar, u32 ce_ctrl_addr, unsigned int n) { - u32 addr = ath10k_pci_read32(ar, ce_ctrl_addr + SRC_WATERMARK_ADDRESS); + u32 addr = ar->bus_read32(ar, ce_ctrl_addr + SRC_WATERMARK_ADDRESS); - ath10k_pci_write32(ar, ce_ctrl_addr + SRC_WATERMARK_ADDRESS, + ar->bus_write32(ar, ce_ctrl_addr + SRC_WATERMARK_ADDRESS, (addr & ~SRC_WATERMARK_HIGH_MASK) | SRC_WATERMARK_HIGH_SET(n)); } @@ -174,9 +173,9 @@ static inline void ath10k_ce_src_ring_lowmark_set(struct ath10k *ar, u32 ce_ctrl_addr, unsigned int n) { - u32 addr = ath10k_pci_read32(ar, ce_ctrl_addr + SRC_WATERMARK_ADDRESS); + u32 addr = ar->bus_read32(ar, ce_ctrl_addr + SRC_WATERMARK_ADDRESS); - ath10k_pci_write32(ar, ce_ctrl_addr + SRC_WATERMARK_ADDRESS, + ar->bus_write32(ar, ce_ctrl_addr + SRC_WATERMARK_ADDRESS, (addr & ~SRC_WATERMARK_LOW_MASK) | SRC_WATERMARK_LOW_SET(n)); } @@ -185,9 +184,9 @@ static inline void ath10k_ce_dest_ring_highmark_set(struct ath10k *ar, u32 ce_ctrl_addr, unsigned int n) { - u32 addr = ath10k_pci_read32(ar, ce_ctrl_addr + DST_WATERMARK_ADDRESS); + u32 addr = ar->bus_read32(ar, ce_ctrl_addr + DST_WATERMARK_ADDRESS); - ath10k_pci_write32(ar, ce_ctrl_addr + DST_WATERMARK_ADDRESS, + ar->bus_write32(ar, ce_ctrl_addr + DST_WATERMARK_ADDRESS, (addr & ~DST_WATERMARK_HIGH_MASK) | DST_WATERMARK_HIGH_SET(n)); } @@ -196,9 +195,9 @@ static inline void ath10k_ce_dest_ring_lowmark_set(struct ath10k *ar, u32 ce_ctrl_addr, unsigned int n) { - u32 addr = ath10k_pci_read32(ar, ce_ctrl_addr + DST_WATERMARK_ADDRESS); + u32 addr = ar->bus_read32(ar, ce_ctrl_addr + DST_WATERMARK_ADDRESS); - ath10k_pci_write32(ar, ce_ctrl_addr + DST_WATERMARK_ADDRESS, + ar->bus_write32(ar, ce_ctrl_addr + DST_WATERMARK_ADDRESS, (addr & ~DST_WATERMARK_LOW_MASK) | DST_WATERMARK_LOW_SET(n)); } @@ -206,50 +205,50 @@ static inline void ath10k_ce_dest_ring_lowmark_set(struct ath10k *ar, static inline void ath10k_ce_copy_complete_inter_enable(struct ath10k *ar, u32 ce_ctrl_addr) { - u32 host_ie_addr = ath10k_pci_read32(ar, + u32 host_ie_addr = ar->bus_read32(ar, ce_ctrl_addr + HOST_IE_ADDRESS); - ath10k_pci_write32(ar, ce_ctrl_addr + HOST_IE_ADDRESS, + ar->bus_write32(ar, ce_ctrl_addr + HOST_IE_ADDRESS, host_ie_addr | HOST_IE_COPY_COMPLETE_MASK); } static inline void ath10k_ce_copy_complete_intr_disable(struct ath10k *ar, u32 ce_ctrl_addr) { - u32 host_ie_addr = ath10k_pci_read32(ar, + u32 host_ie_addr = ar->bus_read32(ar, ce_ctrl_addr + HOST_IE_ADDRESS); - ath10k_pci_write32(ar, ce_ctrl_addr + HOST_IE_ADDRESS, + ar->bus_write32(ar, ce_ctrl_addr + HOST_IE_ADDRESS, host_ie_addr & ~HOST_IE_COPY_COMPLETE_MASK); } static inline void ath10k_ce_watermark_intr_disable(struct ath10k *ar, u32 ce_ctrl_addr) { - u32 host_ie_addr = ath10k_pci_read32(ar, + u32 host_ie_addr = ar->bus_read32(ar, ce_ctrl_addr + HOST_IE_ADDRESS); - ath10k_pci_write32(ar, ce_ctrl_addr + HOST_IE_ADDRESS, + ar->bus_write32(ar, ce_ctrl_addr + HOST_IE_ADDRESS, host_ie_addr & ~CE_WATERMARK_MASK); } static inline void ath10k_ce_error_intr_enable(struct ath10k *ar, u32 ce_ctrl_addr) { - u32 misc_ie_addr = ath10k_pci_read32(ar, + u32 misc_ie_addr = ar->bus_read32(ar, ce_ctrl_addr + MISC_IE_ADDRESS); - ath10k_pci_write32(ar, ce_ctrl_addr + MISC_IE_ADDRESS, + ar->bus_write32(ar, ce_ctrl_addr + MISC_IE_ADDRESS, misc_ie_addr | CE_ERROR_MASK); } static inline void ath10k_ce_error_intr_disable(struct ath10k *ar, u32 ce_ctrl_addr) { - u32 misc_ie_addr = ath10k_pci_read32(ar, + u32 misc_ie_addr = ar->bus_read32(ar, ce_ctrl_addr + MISC_IE_ADDRESS); - ath10k_pci_write32(ar, ce_ctrl_addr + MISC_IE_ADDRESS, + ar->bus_write32(ar, ce_ctrl_addr + MISC_IE_ADDRESS, misc_ie_addr & ~CE_ERROR_MASK); } @@ -257,7 +256,7 @@ static inline void ath10k_ce_engine_int_status_clear(struct ath10k *ar, u32 ce_ctrl_addr, unsigned int mask) { - ath10k_pci_write32(ar, ce_ctrl_addr + HOST_IS_ADDRESS, mask); + ar->bus_write32(ar, ce_ctrl_addr + HOST_IS_ADDRESS, mask); } /* @@ -325,11 +324,10 @@ exit: void __ath10k_ce_send_revert(struct ath10k_ce_pipe *pipe) { struct ath10k *ar = pipe->ar; - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); struct ath10k_ce_ring *src_ring = pipe->src_ring; u32 ctrl_addr = pipe->ctrl_addr; - lockdep_assert_held(&ar_pci->ce_lock); + lockdep_assert_held(&ar->ce_lock); /* * This function must be called only if there is an incomplete @@ -357,13 +355,12 @@ int ath10k_ce_send(struct ath10k_ce_pipe *ce_state, unsigned int flags) { struct ath10k *ar = ce_state->ar; - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); int ret; - spin_lock_bh(&ar_pci->ce_lock); + spin_lock_bh(&ar->ce_lock); ret = ath10k_ce_send_nolock(ce_state, per_transfer_context, buffer, nbytes, transfer_id, flags); - spin_unlock_bh(&ar_pci->ce_lock); + spin_unlock_bh(&ar->ce_lock); return ret; } @@ -371,14 +368,13 @@ int ath10k_ce_send(struct ath10k_ce_pipe *ce_state, int ath10k_ce_num_free_src_entries(struct ath10k_ce_pipe *pipe) { struct ath10k *ar = pipe->ar; - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); int delta; - spin_lock_bh(&ar_pci->ce_lock); + spin_lock_bh(&ar->ce_lock); delta = CE_RING_DELTA(pipe->src_ring->nentries_mask, pipe->src_ring->write_index, pipe->src_ring->sw_index - 1); - spin_unlock_bh(&ar_pci->ce_lock); + spin_unlock_bh(&ar->ce_lock); return delta; } @@ -386,13 +382,12 @@ int ath10k_ce_num_free_src_entries(struct ath10k_ce_pipe *pipe) int __ath10k_ce_rx_num_free_bufs(struct ath10k_ce_pipe *pipe) { struct ath10k *ar = pipe->ar; - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); struct ath10k_ce_ring *dest_ring = pipe->dest_ring; unsigned int nentries_mask = dest_ring->nentries_mask; unsigned int write_index = dest_ring->write_index; unsigned int sw_index = dest_ring->sw_index; - lockdep_assert_held(&ar_pci->ce_lock); + lockdep_assert_held(&ar->ce_lock); return CE_RING_DELTA(nentries_mask, write_index, sw_index - 1); } @@ -400,7 +395,6 @@ int __ath10k_ce_rx_num_free_bufs(struct ath10k_ce_pipe *pipe) int __ath10k_ce_rx_post_buf(struct ath10k_ce_pipe *pipe, void *ctx, u32 paddr) { struct ath10k *ar = pipe->ar; - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); struct ath10k_ce_ring *dest_ring = pipe->dest_ring; unsigned int nentries_mask = dest_ring->nentries_mask; unsigned int write_index = dest_ring->write_index; @@ -409,7 +403,7 @@ int __ath10k_ce_rx_post_buf(struct ath10k_ce_pipe *pipe, void *ctx, u32 paddr) struct ce_desc *desc = CE_DEST_RING_TO_DESC(base, write_index); u32 ctrl_addr = pipe->ctrl_addr; - lockdep_assert_held(&ar_pci->ce_lock); + lockdep_assert_held(&ar->ce_lock); if ((pipe->id != 5) && CE_RING_DELTA(nentries_mask, write_index, sw_index - 1) == 0) @@ -442,12 +436,11 @@ void ath10k_ce_rx_update_write_idx(struct ath10k_ce_pipe *pipe, u32 nentries) int ath10k_ce_rx_post_buf(struct ath10k_ce_pipe *pipe, void *ctx, u32 paddr) { struct ath10k *ar = pipe->ar; - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); int ret; - spin_lock_bh(&ar_pci->ce_lock); + spin_lock_bh(&ar->ce_lock); ret = __ath10k_ce_rx_post_buf(pipe, ctx, paddr); - spin_unlock_bh(&ar_pci->ce_lock); + spin_unlock_bh(&ar->ce_lock); return ret; } @@ -510,14 +503,13 @@ int ath10k_ce_completed_recv_next(struct ath10k_ce_pipe *ce_state, unsigned int *nbytesp) { struct ath10k *ar = ce_state->ar; - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); int ret; - spin_lock_bh(&ar_pci->ce_lock); + spin_lock_bh(&ar->ce_lock); ret = ath10k_ce_completed_recv_next_nolock(ce_state, per_transfer_contextp, nbytesp); - spin_unlock_bh(&ar_pci->ce_lock); + spin_unlock_bh(&ar->ce_lock); return ret; } @@ -532,7 +524,6 @@ int ath10k_ce_revoke_recv_next(struct ath10k_ce_pipe *ce_state, unsigned int write_index; int ret; struct ath10k *ar; - struct ath10k_pci *ar_pci; dest_ring = ce_state->dest_ring; @@ -540,9 +531,8 @@ int ath10k_ce_revoke_recv_next(struct ath10k_ce_pipe *ce_state, return -EIO; ar = ce_state->ar; - ar_pci = ath10k_pci_priv(ar); - spin_lock_bh(&ar_pci->ce_lock); + spin_lock_bh(&ar->ce_lock); nentries_mask = dest_ring->nentries_mask; sw_index = dest_ring->sw_index; @@ -570,7 +560,7 @@ int ath10k_ce_revoke_recv_next(struct ath10k_ce_pipe *ce_state, ret = -EIO; } - spin_unlock_bh(&ar_pci->ce_lock); + spin_unlock_bh(&ar->ce_lock); return ret; } @@ -638,7 +628,6 @@ int ath10k_ce_cancel_send_next(struct ath10k_ce_pipe *ce_state, unsigned int write_index; int ret; struct ath10k *ar; - struct ath10k_pci *ar_pci; src_ring = ce_state->src_ring; @@ -646,9 +635,8 @@ int ath10k_ce_cancel_send_next(struct ath10k_ce_pipe *ce_state, return -EIO; ar = ce_state->ar; - ar_pci = ath10k_pci_priv(ar); - spin_lock_bh(&ar_pci->ce_lock); + spin_lock_bh(&ar->ce_lock); nentries_mask = src_ring->nentries_mask; sw_index = src_ring->sw_index; @@ -679,7 +667,7 @@ int ath10k_ce_cancel_send_next(struct ath10k_ce_pipe *ce_state, ret = -EIO; } - spin_unlock_bh(&ar_pci->ce_lock); + spin_unlock_bh(&ar->ce_lock); return ret; } @@ -688,13 +676,12 @@ int ath10k_ce_completed_send_next(struct ath10k_ce_pipe *ce_state, void **per_transfer_contextp) { struct ath10k *ar = ce_state->ar; - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); int ret; - spin_lock_bh(&ar_pci->ce_lock); + spin_lock_bh(&ar->ce_lock); ret = ath10k_ce_completed_send_next_nolock(ce_state, per_transfer_contextp); - spin_unlock_bh(&ar_pci->ce_lock); + spin_unlock_bh(&ar->ce_lock); return ret; } @@ -707,17 +694,17 @@ int ath10k_ce_completed_send_next(struct ath10k_ce_pipe *ce_state, */ void ath10k_ce_per_engine_service(struct ath10k *ar, unsigned int ce_id) { - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); - struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id]; + struct ath10k_ce_pipe *ce_state = + ((struct ath10k_ce_pipe *)ar->ce_states + ce_id); u32 ctrl_addr = ce_state->ctrl_addr; - spin_lock_bh(&ar_pci->ce_lock); + spin_lock_bh(&ar->ce_lock); /* Clear the copy-complete interrupts that will be handled here. */ ath10k_ce_engine_int_status_clear(ar, ctrl_addr, HOST_IS_COPY_COMPLETE_MASK); - spin_unlock_bh(&ar_pci->ce_lock); + spin_unlock_bh(&ar->ce_lock); if (ce_state->recv_cb) ce_state->recv_cb(ce_state); @@ -725,7 +712,7 @@ void ath10k_ce_per_engine_service(struct ath10k *ar, unsigned int ce_id) if (ce_state->send_cb) ce_state->send_cb(ce_state); - spin_lock_bh(&ar_pci->ce_lock); + spin_lock_bh(&ar->ce_lock); /* * Misc CE interrupts are not being handled, but still need @@ -733,7 +720,7 @@ void ath10k_ce_per_engine_service(struct ath10k *ar, unsigned int ce_id) */ ath10k_ce_engine_int_status_clear(ar, ctrl_addr, CE_WATERMARK_MASK); - spin_unlock_bh(&ar_pci->ce_lock); + spin_unlock_bh(&ar->ce_lock); } /* @@ -799,22 +786,22 @@ int ath10k_ce_disable_interrupts(struct ath10k *ar) void ath10k_ce_enable_interrupts(struct ath10k *ar) { - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); int ce_id; /* Skip the last copy engine, CE7 the diagnostic window, as that * uses polling and isn't initialized for interrupts. */ for (ce_id = 0; ce_id < CE_COUNT - 1; ce_id++) - ath10k_ce_per_engine_handler_adjust(&ar_pci->ce_states[ce_id]); + ath10k_ce_per_engine_handler_adjust( + ((struct ath10k_ce_pipe *)ar->ce_states + ce_id)); } static int ath10k_ce_init_src_ring(struct ath10k *ar, unsigned int ce_id, const struct ce_attr *attr) { - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); - struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id]; + struct ath10k_ce_pipe *ce_state = + ((struct ath10k_ce_pipe *)ar->ce_states + ce_id); struct ath10k_ce_ring *src_ring = ce_state->src_ring; u32 nentries, ctrl_addr = ath10k_ce_base_address(ar, ce_id); @@ -850,8 +837,8 @@ static int ath10k_ce_init_dest_ring(struct ath10k *ar, unsigned int ce_id, const struct ce_attr *attr) { - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); - struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id]; + struct ath10k_ce_pipe *ce_state = + ((struct ath10k_ce_pipe *)ar->ce_states + ce_id); struct ath10k_ce_ring *dest_ring = ce_state->dest_ring; u32 nentries, ctrl_addr = ath10k_ce_base_address(ar, ce_id); @@ -1040,8 +1027,8 @@ void ath10k_ce_deinit_pipe(struct ath10k *ar, unsigned int ce_id) int ath10k_ce_alloc_pipe(struct ath10k *ar, int ce_id, const struct ce_attr *attr) { - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); - struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id]; + struct ath10k_ce_pipe *ce_state = + ((struct ath10k_ce_pipe *)ar->ce_states + ce_id); int ret; /* @@ -1097,8 +1084,8 @@ int ath10k_ce_alloc_pipe(struct ath10k *ar, int ce_id, void ath10k_ce_free_pipe(struct ath10k *ar, int ce_id) { - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); - struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id]; + struct ath10k_ce_pipe *ce_state = + ((struct ath10k_ce_pipe *)ar->ce_states + ce_id); if (ce_state->src_ring) { dma_free_coherent(ar->dev, diff --git a/drivers/net/wireless/ath/ath10k/ce.h b/drivers/net/wireless/ath/ath10k/ce.h index dfc098606bee..0e1ab73b0e11 100644 --- a/drivers/net/wireless/ath/ath10k/ce.h +++ b/drivers/net/wireless/ath/ath10k/ce.h @@ -425,7 +425,7 @@ static inline u32 ath10k_ce_base_address(struct ath10k *ar, unsigned int ce_id) #define CE_INTERRUPT_SUMMARY(ar) \ CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_GET( \ - ath10k_pci_read32((ar), CE_WRAPPER_BASE_ADDRESS + \ + ar->bus_read32((ar), CE_WRAPPER_BASE_ADDRESS + \ CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS)) #endif /* _CE_H_ */ diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 521f1c55c19e..bea1a0bd865b 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -74,6 +74,7 @@ struct ath10k; enum ath10k_bus { ATH10K_BUS_PCI, ATH10K_BUS_AHB, + ATH10K_BUS_SNOC, }; static inline const char *ath10k_bus_str(enum ath10k_bus bus) @@ -83,6 +84,8 @@ static inline const char *ath10k_bus_str(enum ath10k_bus bus) return "pci"; case ATH10K_BUS_AHB: return "ahb"; + case ATH10K_BUS_SNOC: + return "snoc"; } return "unknown"; @@ -912,6 +915,10 @@ struct ath10k { struct net_device napi_dev; struct napi_struct napi; + void (*bus_write32)(void *ar, u32 offset, u32 value); + u32 (*bus_read32)(void *ar, u32 offset); + spinlock_t ce_lock; /* lock for CE access */ + void *ce_states; /* must be last */ u8 drv_priv[0] __aligned(sizeof(void *)); }; diff --git a/drivers/net/wireless/ath/ath10k/debug.h b/drivers/net/wireless/ath/ath10k/debug.h index c458fa96a6d4..b1db01a167ac 100644 --- a/drivers/net/wireless/ath/ath10k/debug.h +++ b/drivers/net/wireless/ath/ath10k/debug.h @@ -38,6 +38,7 @@ enum ath10k_debug_mask { ATH10K_DBG_WMI_PRINT = 0x00002000, ATH10K_DBG_PCI_PS = 0x00004000, ATH10K_DBG_AHB = 0x00008000, + ATH10K_DBG_SNOC = 0x00009000, ATH10K_DBG_ANY = 0xffffffff, }; diff --git a/drivers/net/wireless/ath/ath10k/hif.h b/drivers/net/wireless/ath/ath10k/hif.h index b2566b06e1e1..9e79d52e18cf 100644 --- a/drivers/net/wireless/ath/ath10k/hif.h +++ b/drivers/net/wireless/ath/ath10k/hif.h @@ -74,9 +74,9 @@ struct ath10k_hif_ops { u16 (*get_free_queue_number)(struct ath10k *ar, u8 pipe_id); - u32 (*read32)(struct ath10k *ar, u32 address); + u32 (*read32)(void *ar, u32 address); - void (*write32)(struct ath10k *ar, u32 address, u32 value); + void (*write32)(void *ar, u32 address, u32 value); /* Power up the device and enter BMI transfer mode for FW download */ int (*power_up)(struct ath10k *ar); diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 6038b7486f1d..7e12291852d2 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -224,6 +224,7 @@ enum ath10k_hw_rev { ATH10K_HW_QCA9377, ATH10K_HW_QCA4019, ATH10K_HW_QCA9887, + ATH10K_HW_WCN3990, }; struct ath10k_hw_regs { diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 9fbeb7e5ab2d..0c250f8d45ce 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -669,14 +669,14 @@ static u32 ath10k_bus_pci_read32(struct ath10k *ar, u32 offset) return val; } -inline void ath10k_pci_write32(struct ath10k *ar, u32 offset, u32 value) +inline void ath10k_pci_write32(void *ar, u32 offset, u32 value) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); ar_pci->bus_ops->write32(ar, offset, value); } -inline u32 ath10k_pci_read32(struct ath10k *ar, u32 offset) +inline u32 ath10k_pci_read32(void *ar, u32 offset) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); @@ -3246,6 +3246,16 @@ static int ath10k_pci_probe(struct pci_dev *pdev, ar->id.subsystem_vendor = pdev->subsystem_vendor; ar->id.subsystem_device = pdev->subsystem_device; + spin_lock_init(&ar_pci->ce_lock); + spin_lock_init(&ar_pci->ps_lock); + + ar->bus_write32 = ath10k_pci_write32; + ar->bus_read32 = ath10k_pci_read32; + ar->ce_lock = ar_pci->ce_lock; + ar->ce_states = ar_pci->ce_states; + + setup_timer(&ar_pci->rx_post_retry, ath10k_pci_rx_replenish_retry, + (unsigned long)ar); setup_timer(&ar_pci->ps_timer, ath10k_pci_ps_timer, (unsigned long)ar); diff --git a/drivers/net/wireless/ath/ath10k/pci.h b/drivers/net/wireless/ath/ath10k/pci.h index 9854ad56b2de..06d0bd3993d3 100644 --- a/drivers/net/wireless/ath/ath10k/pci.h +++ b/drivers/net/wireless/ath/ath10k/pci.h @@ -263,11 +263,11 @@ static inline struct ath10k_pci *ath10k_pci_priv(struct ath10k *ar) /* Wait up to this many Ms for a Diagnostic Access CE operation to complete */ #define DIAG_ACCESS_CE_TIMEOUT_MS 10 -void ath10k_pci_write32(struct ath10k *ar, u32 offset, u32 value); +void ath10k_pci_write32(void *ar, u32 offset, u32 value); void ath10k_pci_soc_write32(struct ath10k *ar, u32 addr, u32 val); void ath10k_pci_reg_write32(struct ath10k *ar, u32 addr, u32 val); -u32 ath10k_pci_read32(struct ath10k *ar, u32 offset); +u32 ath10k_pci_read32(void *ar, u32 offset); u32 ath10k_pci_soc_read32(struct ath10k *ar, u32 addr); u32 ath10k_pci_reg_read32(struct ath10k *ar, u32 addr); diff --git a/drivers/platform/msm/gsi/gsi.c b/drivers/platform/msm/gsi/gsi.c index a617c9e8e11f..f32d3d9646c1 100644 --- a/drivers/platform/msm/gsi/gsi.c +++ b/drivers/platform/msm/gsi/gsi.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 @@ -362,8 +362,13 @@ static void gsi_process_chan(struct gsi_xfer_compl_evt *evt, notify->chan_user_data = ch_ctx->props.chan_user_data; notify->evt_id = evt->code; notify->bytes_xfered = evt->len; - if (callback) + if (callback) { + if (atomic_read(&ch_ctx->poll_mode)) { + GSIERR("Calling client callback in polling mode\n"); + WARN_ON(1); + } ch_ctx->props.xfer_cb(notify); + } } static void gsi_process_evt_re(struct gsi_evt_ctx *ctx, @@ -459,12 +464,12 @@ check_again: ctx->ring.rp = rp; while (ctx->ring.rp_local != rp) { ++cntr; - gsi_process_evt_re(ctx, ¬ify, true); if (ctx->props.exclusive && atomic_read(&ctx->chan->poll_mode)) { cntr = 0; break; } + gsi_process_evt_re(ctx, ¬ify, true); } gsi_ring_evt_doorbell(ctx); if (cntr != 0) diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c index d3f7e43ea10e..62d8ae0c5f36 100644 --- a/drivers/power/supply/qcom/smb-lib.c +++ b/drivers/power/supply/qcom/smb-lib.c @@ -1216,11 +1216,9 @@ static int _smblib_vbus_regulator_disable(struct regulator_dev *rdev) if (!chg->external_vconn) { rc = smblib_read(chg, RID_CC_CONTROL_7_0_REG, &stat); - if (rc < 0) { + if (rc < 0) smblib_err(chg, "Couldn't read RID_CC_CONTROL_7_0 rc=%d\n", rc); - return rc; - } /* check if VCONN is enabled on either CC pin */ if (stat & VCONN_EN_CC_MASK) { @@ -1229,7 +1227,6 @@ static int _smblib_vbus_regulator_disable(struct regulator_dev *rdev) if (rc < 0) smblib_err(chg, "Couldn't disable VCONN rc=%d\n", rc); - return rc; } } diff --git a/drivers/power/supply/qcom/smb138x-charger.c b/drivers/power/supply/qcom/smb138x-charger.c index 70d935e9d1df..ed76a585ed03 100644 --- a/drivers/power/supply/qcom/smb138x-charger.c +++ b/drivers/power/supply/qcom/smb138x-charger.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 @@ -410,6 +410,7 @@ static enum power_supply_property smb138x_parallel_props[] = { POWER_SUPPLY_PROP_CURRENT_NOW, POWER_SUPPLY_PROP_CHARGER_TEMP, POWER_SUPPLY_PROP_CHARGER_TEMP_MAX, + POWER_SUPPLY_PROP_MODEL_NAME, }; static int smb138x_parallel_get_prop(struct power_supply *psy, @@ -456,6 +457,9 @@ static int smb138x_parallel_get_prop(struct power_supply *psy, 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 = "smb138x"; + break; default: pr_err("parallel power supply get prop %d not supported\n", prop); diff --git a/drivers/scsi/ufs/ufs-qcom-ice.c b/drivers/scsi/ufs/ufs-qcom-ice.c index 070d27df6b49..85f82b2251c1 100644 --- a/drivers/scsi/ufs/ufs-qcom-ice.c +++ b/drivers/scsi/ufs/ufs-qcom-ice.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 @@ -14,6 +14,7 @@ #include <linux/io.h> #include <linux/of.h> #include <linux/blkdev.h> +#include <linux/spinlock.h> #include <crypto/ice.h> #include "ufs-qcom-ice.h" @@ -168,6 +169,7 @@ out: static void ufs_qcom_ice_cfg_work(struct work_struct *work) { + unsigned long flags; struct ice_data_setting ice_set; struct ufs_qcom_host *qcom_host = container_of(work, struct ufs_qcom_host, ice_cfg_work); @@ -185,12 +187,17 @@ static void ufs_qcom_ice_cfg_work(struct work_struct *work) qcom_host->ice.vops->config_start(qcom_host->ice.pdev, qcom_host->req_pending, &ice_set, false); + spin_lock_irqsave(&qcom_host->ice_work_lock, flags); + qcom_host->req_pending = NULL; + spin_unlock_irqrestore(&qcom_host->ice_work_lock, flags); + /* * Resume with requests processing. We assume config_start has been * successful, but even if it wasn't we still must resume in order to * allow for the request to be retried. */ ufshcd_scsi_unblock_requests(qcom_host->hba); + } /** @@ -246,6 +253,7 @@ int ufs_qcom_ice_req_setup(struct ufs_qcom_host *qcom_host, struct ice_data_setting ice_set; char cmd_op = cmd->cmnd[0]; int err; + unsigned long flags; if (!qcom_host->ice.pdev || !qcom_host->ice.vops) { dev_dbg(qcom_host->hba->dev, "%s: ice device is not enabled\n", @@ -272,14 +280,36 @@ int ufs_qcom_ice_req_setup(struct ufs_qcom_host *qcom_host, dev_dbg(qcom_host->hba->dev, "%s: scheduling task for ice setup\n", __func__); - qcom_host->req_pending = cmd->request; - if (schedule_work(&qcom_host->ice_cfg_work)) + + spin_lock_irqsave( + &qcom_host->ice_work_lock, flags); + + if (!qcom_host->req_pending) { ufshcd_scsi_block_requests( qcom_host->hba); + qcom_host->req_pending = cmd->request; + if (!schedule_work( + &qcom_host->ice_cfg_work)) { + qcom_host->req_pending = NULL; + + spin_unlock_irqrestore( + &qcom_host->ice_work_lock, + flags); + + ufshcd_scsi_unblock_requests( + qcom_host->hba); + return err; + } + } + + spin_unlock_irqrestore( + &qcom_host->ice_work_lock, flags); + } else { - dev_err(qcom_host->hba->dev, - "%s: error in ice_vops->config %d\n", - __func__, err); + if (err != -EBUSY) + dev_err(qcom_host->hba->dev, + "%s: error in ice_vops->config %d\n", + __func__, err); } return err; @@ -320,6 +350,7 @@ int ufs_qcom_ice_cfg_start(struct ufs_qcom_host *qcom_host, unsigned int bypass = 0; struct request *req; char cmd_op; + unsigned long flags; if (!qcom_host->ice.pdev || !qcom_host->ice.vops) { dev_dbg(dev, "%s: ice device is not enabled\n", __func__); @@ -365,12 +396,43 @@ int ufs_qcom_ice_cfg_start(struct ufs_qcom_host *qcom_host, * request processing. */ if (err == -EAGAIN) { - qcom_host->req_pending = req; - if (schedule_work(&qcom_host->ice_cfg_work)) + + dev_dbg(qcom_host->hba->dev, + "%s: scheduling task for ice setup\n", + __func__); + + spin_lock_irqsave( + &qcom_host->ice_work_lock, flags); + + if (!qcom_host->req_pending) { ufshcd_scsi_block_requests( + qcom_host->hba); + qcom_host->req_pending = cmd->request; + if (!schedule_work( + &qcom_host->ice_cfg_work)) { + qcom_host->req_pending = NULL; + + spin_unlock_irqrestore( + &qcom_host->ice_work_lock, + flags); + + ufshcd_scsi_unblock_requests( qcom_host->hba); + return err; + } + } + + spin_unlock_irqrestore( + &qcom_host->ice_work_lock, flags); + + } else { + if (err != -EBUSY) + dev_err(qcom_host->hba->dev, + "%s: error in ice_vops->config %d\n", + __func__, err); } - goto out; + + return err; } } diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c index 2b0731b8358c..03b222d8be93 100644 --- a/drivers/scsi/ufs/ufs-qcom.c +++ b/drivers/scsi/ufs/ufs-qcom.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2016, Linux Foundation. All rights reserved. + * Copyright (c) 2013-2017, 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 @@ -1981,6 +1981,8 @@ static int ufs_qcom_init(struct ufs_hba *hba) /* Make a two way bind between the qcom host and the hba */ host->hba = hba; + spin_lock_init(&host->ice_work_lock); + ufshcd_set_variant(hba, host); err = ufs_qcom_ice_get_dev(host); diff --git a/drivers/scsi/ufs/ufs-qcom.h b/drivers/scsi/ufs/ufs-qcom.h index 394de8302fd2..74d8a7a30ad6 100644 --- a/drivers/scsi/ufs/ufs-qcom.h +++ b/drivers/scsi/ufs/ufs-qcom.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 @@ -370,6 +370,7 @@ struct ufs_qcom_host { u32 dbg_print_en; struct ufs_qcom_testbus testbus; + spinlock_t ice_work_lock; struct work_struct ice_cfg_work; struct request *req_pending; }; diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 1e6db2a76fa5..d4acc3c911f5 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -48,6 +48,7 @@ #include "ufshci.h" #include "ufs_quirks.h" #include "ufs-debugfs.h" +#include "ufs-qcom.h" #define CREATE_TRACE_POINTS #include <trace/events/ufs.h> @@ -2884,11 +2885,11 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) "%s: failed to compose upiu %d\n", __func__, err); - lrbp->cmd = NULL; - clear_bit_unlock(tag, &hba->lrb_in_use); - ufshcd_release_all(hba); - ufshcd_vops_pm_qos_req_end(hba, cmd->request, true); - goto out; + lrbp->cmd = NULL; + clear_bit_unlock(tag, &hba->lrb_in_use); + ufshcd_release_all(hba); + ufshcd_vops_pm_qos_req_end(hba, cmd->request, true); + goto out; } err = ufshcd_map_sg(lrbp); diff --git a/drivers/soc/qcom/msm_smem.c b/drivers/soc/qcom/msm_smem.c index 9c4d89ac704d..d3f44ab75f67 100644 --- a/drivers/soc/qcom/msm_smem.c +++ b/drivers/soc/qcom/msm_smem.c @@ -1222,12 +1222,18 @@ static void smem_init_security_partition(struct smem_toc_entry *entry, LOG_ERR("Smem partition %d cached heap exceeds size\n", num); BUG(); } - if (hdr->host0 == SMEM_COMM_HOST && hdr->host1 == SMEM_COMM_HOST) { - comm_partition.partition_num = num; - comm_partition.offset = entry->offset; - comm_partition.size_cacheline = entry->size_cacheline; - SMEM_INFO("Common Partition %d offset:%x\n", num, - entry->offset); + if (is_comm_partition) { + if (hdr->host0 == SMEM_COMM_HOST + && hdr->host1 == SMEM_COMM_HOST) { + comm_partition.partition_num = num; + comm_partition.offset = entry->offset; + comm_partition.size_cacheline = entry->size_cacheline; + SMEM_INFO("Common Partition %d offset:%x\n", num, + entry->offset); + } else { + LOG_ERR("Smem Comm partition hosts don't match TOC\n"); + WARN_ON(1); + } return; } if (hdr->host0 != SMEM_APPS && hdr->host1 != SMEM_APPS) { diff --git a/drivers/soc/qcom/service-notifier.c b/drivers/soc/qcom/service-notifier.c index e7307c46a895..8a501d4d0615 100644 --- a/drivers/soc/qcom/service-notifier.c +++ b/drivers/soc/qcom/service-notifier.c @@ -215,7 +215,7 @@ static void send_ind_ack(struct work_struct *work) if (QMI_RESP_BIT_SHIFT(resp.resp.result) != QMI_RESULT_SUCCESS_V01) pr_err("QMI request failed 0x%x\n", QMI_RESP_BIT_SHIFT(resp.resp.error)); - pr_debug("Indication ACKed for transid %d, service %s, instance %d!\n", + pr_info("Indication ACKed for transid %d, service %s, instance %d!\n", data->ind_msg.transaction_id, data->ind_msg.service_path, data->instance_id); } @@ -240,7 +240,7 @@ static void root_service_service_ind_cb(struct qmi_handle *handle, return; } - pr_debug("Indication received from %s, state: 0x%x, trans-id: %d\n", + pr_info("Indication received from %s, state: 0x%x, trans-id: %d\n", ind_msg.service_name, ind_msg.curr_state, ind_msg.transaction_id); diff --git a/drivers/spi/spi_qsd.c b/drivers/spi/spi_qsd.c index 7aa04a4fa156..b81348ceb469 100644 --- a/drivers/spi/spi_qsd.c +++ b/drivers/spi/spi_qsd.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2008-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 @@ -45,8 +45,6 @@ #include <linux/msm-bus-board.h> #include "spi_qsd.h" -#define SPI_MAX_BYTES_PER_WORD (4) - static int msm_spi_pm_resume_runtime(struct device *device); static int msm_spi_pm_suspend_runtime(struct device *device); static inline void msm_spi_dma_unmap_buffers(struct msm_spi *dd); @@ -440,12 +438,10 @@ static void msm_spi_read_word_from_fifo(struct msm_spi *dd) u32 data_in; int i; int shift; - int read_bytes = (dd->pack_words ? - SPI_MAX_BYTES_PER_WORD : dd->bytes_per_word); data_in = readl_relaxed(dd->base + SPI_INPUT_FIFO); if (dd->read_buf) { - for (i = 0; (i < read_bytes) && + for (i = 0; (i < dd->bytes_per_word) && dd->rx_bytes_remaining; i++) { /* The data format depends on bytes_per_word: 4 bytes: 0x12345678 @@ -458,8 +454,8 @@ static void msm_spi_read_word_from_fifo(struct msm_spi *dd) dd->rx_bytes_remaining--; } } else { - if (dd->rx_bytes_remaining >= read_bytes) - dd->rx_bytes_remaining -= read_bytes; + if (dd->rx_bytes_remaining >= dd->bytes_per_word) + dd->rx_bytes_remaining -= dd->bytes_per_word; else dd->rx_bytes_remaining = 0; } @@ -556,7 +552,7 @@ msm_spi_set_bpw_and_no_io_flags(struct msm_spi *dd, u32 *config, int n) if (n != (*config & SPI_CFG_N)) *config = (*config & ~SPI_CFG_N) | n; - if (dd->tx_mode == SPI_BAM_MODE) { + if (dd->mode == SPI_BAM_MODE) { if (dd->read_buf == NULL) *config |= SPI_NO_INPUT; if (dd->write_buf == NULL) @@ -621,34 +617,25 @@ static void msm_spi_set_spi_config(struct msm_spi *dd, int bpw) static void msm_spi_set_mx_counts(struct msm_spi *dd, u32 n_words) { /* - * For FIFO mode: - * - Set the MX_OUTPUT_COUNT/MX_INPUT_COUNT registers to 0 - * - Set the READ/WRITE_COUNT registers to 0 (infinite mode) - * or num bytes (finite mode) if less than fifo worth of data. - * For Block mode: - * - Set the MX_OUTPUT/MX_INPUT_COUNT registers to num xfer bytes. - * - Set the READ/WRITE_COUNT registers to 0. + * n_words cannot exceed fifo_size, and only one READ COUNT + * interrupt is generated per transaction, so for transactions + * larger than fifo size READ COUNT must be disabled. + * For those transactions we usually move to Data Mover mode. */ - if (dd->tx_mode != SPI_BAM_MODE) { - if (dd->tx_mode == SPI_FIFO_MODE) { - if (n_words <= dd->input_fifo_size) - msm_spi_set_write_count(dd, n_words); - else - msm_spi_set_write_count(dd, 0); - writel_relaxed(0, dd->base + SPI_MX_OUTPUT_COUNT); - } else - writel_relaxed(n_words, dd->base + SPI_MX_OUTPUT_COUNT); - - if (dd->rx_mode == SPI_FIFO_MODE) { - if (n_words <= dd->input_fifo_size) - writel_relaxed(n_words, - dd->base + SPI_MX_READ_COUNT); - else - writel_relaxed(0, - dd->base + SPI_MX_READ_COUNT); + if (dd->mode == SPI_FIFO_MODE) { + if (n_words <= dd->input_fifo_size) { + writel_relaxed(n_words, + dd->base + SPI_MX_READ_COUNT); + msm_spi_set_write_count(dd, n_words); + } else { + writel_relaxed(0, dd->base + SPI_MX_READ_COUNT); + msm_spi_set_write_count(dd, 0); + } + if (dd->qup_ver == SPI_QUP_VERSION_BFAM) { + /* must be zero for FIFO */ writel_relaxed(0, dd->base + SPI_MX_INPUT_COUNT); - } else - writel_relaxed(n_words, dd->base + SPI_MX_INPUT_COUNT); + writel_relaxed(0, dd->base + SPI_MX_OUTPUT_COUNT); + } } else { /* must be zero for BAM and DMOV */ writel_relaxed(0, dd->base + SPI_MX_READ_COUNT); @@ -895,7 +882,7 @@ xfr_err: static int msm_spi_bam_next_transfer(struct msm_spi *dd) { - if (dd->tx_mode != SPI_BAM_MODE) + if (dd->mode != SPI_BAM_MODE) return 0; if (dd->tx_bytes_remaining > 0) { @@ -914,7 +901,7 @@ msm_spi_bam_next_transfer(struct msm_spi *dd) static int msm_spi_dma_send_next(struct msm_spi *dd) { int ret = 0; - if (dd->tx_mode == SPI_BAM_MODE) + if (dd->mode == SPI_BAM_MODE) ret = msm_spi_bam_next_transfer(dd); return ret; } @@ -945,38 +932,32 @@ static inline irqreturn_t msm_spi_qup_irq(int irq, void *dev_id) } op = readl_relaxed(dd->base + SPI_OPERATIONAL); - writel_relaxed(op, dd->base + SPI_OPERATIONAL); - /* - * Ensure service flag was cleared before further - * processing of interrupt. - */ - mb(); if (op & SPI_OP_INPUT_SERVICE_FLAG) { + writel_relaxed(SPI_OP_INPUT_SERVICE_FLAG, + dd->base + SPI_OPERATIONAL); + /* + * Ensure service flag was cleared before further + * processing of interrupt. + */ + mb(); ret |= msm_spi_input_irq(irq, dev_id); } if (op & SPI_OP_OUTPUT_SERVICE_FLAG) { + writel_relaxed(SPI_OP_OUTPUT_SERVICE_FLAG, + dd->base + SPI_OPERATIONAL); + /* + * Ensure service flag was cleared before further + * processing of interrupt. + */ + mb(); ret |= msm_spi_output_irq(irq, dev_id); } - if (dd->tx_mode != SPI_BAM_MODE) { - if (!dd->rx_done) { - if (dd->rx_bytes_remaining == 0) - dd->rx_done = true; - } - if (!dd->tx_done) { - if (!dd->tx_bytes_remaining && - (op & SPI_OP_IP_FIFO_NOT_EMPTY)) { - dd->tx_done = true; - } - } - } - if (dd->tx_done && dd->rx_done) { - msm_spi_set_state(dd, SPI_OP_STATE_RESET); - dd->tx_done = false; - dd->rx_done = false; + if (dd->done) { complete(&dd->rx_transfer_complete); complete(&dd->tx_transfer_complete); + dd->done = 0; } return ret; } @@ -987,23 +968,17 @@ static irqreturn_t msm_spi_input_irq(int irq, void *dev_id) dd->stat_rx++; - if (dd->rx_mode == SPI_MODE_NONE) + if (dd->mode == SPI_MODE_NONE) return IRQ_HANDLED; - if (dd->rx_mode == SPI_FIFO_MODE) { + if (dd->mode == SPI_FIFO_MODE) { while ((readl_relaxed(dd->base + SPI_OPERATIONAL) & SPI_OP_IP_FIFO_NOT_EMPTY) && (dd->rx_bytes_remaining > 0)) { msm_spi_read_word_from_fifo(dd); } - } else if (dd->rx_mode == SPI_BLOCK_MODE) { - int count = 0; - - while (dd->rx_bytes_remaining && - (count < dd->input_block_size)) { - msm_spi_read_word_from_fifo(dd); - count += SPI_MAX_BYTES_PER_WORD; - } + if (dd->rx_bytes_remaining == 0) + msm_spi_complete(dd); } return IRQ_HANDLED; @@ -1014,20 +989,18 @@ static void msm_spi_write_word_to_fifo(struct msm_spi *dd) u32 word; u8 byte; int i; - int write_bytes = - (dd->pack_words ? SPI_MAX_BYTES_PER_WORD : dd->bytes_per_word); word = 0; if (dd->write_buf) { - for (i = 0; (i < write_bytes) && + for (i = 0; (i < dd->bytes_per_word) && dd->tx_bytes_remaining; i++) { dd->tx_bytes_remaining--; byte = *dd->write_buf++; word |= (byte << (BITS_PER_BYTE * i)); } } else - if (dd->tx_bytes_remaining > write_bytes) - dd->tx_bytes_remaining -= write_bytes; + if (dd->tx_bytes_remaining > dd->bytes_per_word) + dd->tx_bytes_remaining -= dd->bytes_per_word; else dd->tx_bytes_remaining = 0; dd->write_xfr_cnt++; @@ -1039,22 +1012,11 @@ static inline void msm_spi_write_rmn_to_fifo(struct msm_spi *dd) { int count = 0; - if (dd->tx_mode == SPI_FIFO_MODE) { - while ((dd->tx_bytes_remaining > 0) && - (count < dd->input_fifo_size) && - !(readl_relaxed(dd->base + SPI_OPERATIONAL) - & SPI_OP_OUTPUT_FIFO_FULL)) { - msm_spi_write_word_to_fifo(dd); - count++; - } - } - - if (dd->tx_mode == SPI_BLOCK_MODE) { - while (dd->tx_bytes_remaining && - (count < dd->output_block_size)) { - msm_spi_write_word_to_fifo(dd); - count += SPI_MAX_BYTES_PER_WORD; - } + while ((dd->tx_bytes_remaining > 0) && (count < dd->input_fifo_size) && + !(readl_relaxed(dd->base + SPI_OPERATIONAL) & + SPI_OP_OUTPUT_FIFO_FULL)) { + msm_spi_write_word_to_fifo(dd); + count++; } } @@ -1064,11 +1026,11 @@ static irqreturn_t msm_spi_output_irq(int irq, void *dev_id) dd->stat_tx++; - if (dd->tx_mode == SPI_MODE_NONE) + if (dd->mode == SPI_MODE_NONE) return IRQ_HANDLED; /* Output FIFO is empty. Transmit any outstanding write data. */ - if ((dd->tx_mode == SPI_FIFO_MODE) || (dd->tx_mode == SPI_BLOCK_MODE)) + if (dd->mode == SPI_FIFO_MODE) msm_spi_write_rmn_to_fifo(dd); return IRQ_HANDLED; @@ -1144,7 +1106,7 @@ error: static int msm_spi_dma_map_buffers(struct msm_spi *dd) { int ret = 0; - if (dd->tx_mode == SPI_BAM_MODE) + if (dd->mode == SPI_BAM_MODE) ret = msm_spi_bam_map_buffers(dd); return ret; } @@ -1173,7 +1135,7 @@ static void msm_spi_bam_unmap_buffers(struct msm_spi *dd) static inline void msm_spi_dma_unmap_buffers(struct msm_spi *dd) { - if (dd->tx_mode == SPI_BAM_MODE) + if (dd->mode == SPI_BAM_MODE) msm_spi_bam_unmap_buffers(dd); } @@ -1235,11 +1197,9 @@ static void msm_spi_set_transfer_mode(struct msm_spi *dd, u8 bpw, u32 read_count) { if (msm_spi_use_dma(dd, dd->cur_transfer, bpw)) { - dd->tx_mode = SPI_BAM_MODE; - dd->rx_mode = SPI_BAM_MODE; + dd->mode = SPI_BAM_MODE; } else { - dd->rx_mode = SPI_FIFO_MODE; - dd->tx_mode = SPI_FIFO_MODE; + dd->mode = SPI_FIFO_MODE; dd->read_len = dd->cur_transfer->len; dd->write_len = dd->cur_transfer->len; } @@ -1255,19 +1215,14 @@ static void msm_spi_set_qup_io_modes(struct msm_spi *dd) spi_iom = readl_relaxed(dd->base + SPI_IO_MODES); /* Set input and output transfer mode: FIFO, DMOV, or BAM */ spi_iom &= ~(SPI_IO_M_INPUT_MODE | SPI_IO_M_OUTPUT_MODE); - spi_iom = (spi_iom | (dd->tx_mode << OUTPUT_MODE_SHIFT)); - spi_iom = (spi_iom | (dd->rx_mode << INPUT_MODE_SHIFT)); - /* Always enable packing for all % 8 bits_per_word */ - if (dd->cur_transfer->bits_per_word && - ((dd->cur_transfer->bits_per_word == 8) || - (dd->cur_transfer->bits_per_word == 16) || - (dd->cur_transfer->bits_per_word == 32))) { + spi_iom = (spi_iom | (dd->mode << OUTPUT_MODE_SHIFT)); + spi_iom = (spi_iom | (dd->mode << INPUT_MODE_SHIFT)); + /* Turn on packing for data mover */ + if (dd->mode == SPI_BAM_MODE) spi_iom |= SPI_IO_M_PACK_EN | SPI_IO_M_UNPACK_EN; - dd->pack_words = true; - } else { + else { spi_iom &= ~(SPI_IO_M_PACK_EN | SPI_IO_M_UNPACK_EN); spi_iom |= SPI_IO_M_OUTPUT_BIT_SHIFT_EN; - dd->pack_words = false; } /*if (dd->mode == SPI_BAM_MODE) { @@ -1325,7 +1280,7 @@ static void msm_spi_set_qup_op_mask(struct msm_spi *dd) { /* mask INPUT and OUTPUT service flags in to prevent IRQs on FIFO status * change in BAM mode */ - u32 mask = (dd->tx_mode == SPI_BAM_MODE) ? + u32 mask = (dd->mode == SPI_BAM_MODE) ? QUP_OP_MASK_OUTPUT_SERVICE_FLAG | QUP_OP_MASK_INPUT_SERVICE_FLAG : 0; writel_relaxed(mask, dd->base + QUP_OPERATIONAL_MASK); @@ -1366,8 +1321,6 @@ static int msm_spi_process_transfer(struct msm_spi *dd) dd->rx_bytes_remaining = dd->cur_msg_len; dd->read_buf = dd->cur_transfer->rx_buf; dd->write_buf = dd->cur_transfer->tx_buf; - dd->tx_done = false; - dd->rx_done = false; init_completion(&dd->tx_transfer_complete); init_completion(&dd->rx_transfer_complete); if (dd->cur_transfer->bits_per_word) @@ -1398,12 +1351,10 @@ static int msm_spi_process_transfer(struct msm_spi *dd) msm_spi_set_transfer_mode(dd, bpw, read_count); msm_spi_set_mx_counts(dd, read_count); - if (dd->tx_mode == SPI_BAM_MODE) { + if (dd->mode == SPI_BAM_MODE) { ret = msm_spi_dma_map_buffers(dd); if (ret < 0) { pr_err("Mapping DMA buffers\n"); - dd->tx_mode = SPI_MODE_NONE; - dd->rx_mode = SPI_MODE_NONE; return ret; } } @@ -1417,11 +1368,11 @@ static int msm_spi_process_transfer(struct msm_spi *dd) the first. Restricting this to one write avoids contention issues and race conditions between this thread and the int handler */ - if (dd->tx_mode != SPI_BAM_MODE) { + if (dd->mode == SPI_FIFO_MODE) { if (msm_spi_prepare_for_write(dd)) goto transfer_end; msm_spi_start_write(dd, read_count); - } else { + } else if (dd->mode == SPI_BAM_MODE) { if ((msm_spi_bam_begin_transfer(dd)) < 0) { dev_err(dd->dev, "%s: BAM transfer setup failed\n", __func__); @@ -1437,11 +1388,11 @@ static int msm_spi_process_transfer(struct msm_spi *dd) * might fire before the first word is written resulting in a * possible race condition. */ - if (dd->tx_mode != SPI_BAM_MODE) + if (dd->mode != SPI_BAM_MODE) if (msm_spi_set_state(dd, SPI_OP_STATE_RUN)) { dev_warn(dd->dev, "%s: Failed to set QUP to run-state. Mode:%d", - __func__, dd->tx_mode); + __func__, dd->mode); goto transfer_end; } @@ -1471,11 +1422,10 @@ static int msm_spi_process_transfer(struct msm_spi *dd) msm_spi_udelay(dd->xfrs_delay_usec); transfer_end: - if ((dd->tx_mode == SPI_BAM_MODE) && status) + if ((dd->mode == SPI_BAM_MODE) && status) msm_spi_bam_flush(dd); msm_spi_dma_unmap_buffers(dd); - dd->tx_mode = SPI_MODE_NONE; - dd->rx_mode = SPI_MODE_NONE; + dd->mode = SPI_MODE_NONE; msm_spi_set_state(dd, SPI_OP_STATE_RESET); if (!dd->cur_transfer->cs_change) @@ -2403,8 +2353,7 @@ static int init_resources(struct platform_device *pdev) pclk_enabled = 0; dd->transfer_pending = 0; - dd->tx_mode = SPI_MODE_NONE; - dd->rx_mode = SPI_MODE_NONE; + dd->mode = SPI_MODE_NONE; rc = msm_spi_request_irq(dd, pdev, master); if (rc) diff --git a/drivers/spi/spi_qsd.h b/drivers/spi/spi_qsd.h index e8e6cdce1a02..53ec1e600594 100644 --- a/drivers/spi/spi_qsd.h +++ b/drivers/spi/spi_qsd.h @@ -1,4 +1,4 @@ -/* 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 @@ -113,8 +113,6 @@ #define INPUT_MODE_SHIFT QSD_REG(10) QUP_REG(12) /* SPI_OPERATIONAL fields */ -#define SPI_OP_IN_BLK_RD_REQ_FLAG 0x00002000 -#define SPI_OP_OUT_BLK_WR_REQ_FLAG 0x00001000 #define SPI_OP_MAX_INPUT_DONE_FLAG 0x00000800 #define SPI_OP_MAX_OUTPUT_DONE_FLAG 0x00000400 #define SPI_OP_INPUT_SERVICE_FLAG 0x00000200 @@ -316,8 +314,7 @@ struct msm_spi { bool transfer_pending; wait_queue_head_t continue_suspend; /* DMA data */ - enum msm_spi_mode tx_mode; - enum msm_spi_mode rx_mode; + enum msm_spi_mode mode; bool use_dma; int tx_dma_chan; int tx_dma_crci; @@ -349,8 +346,7 @@ struct msm_spi { #endif struct msm_spi_platform_data *pdata; /* Platform data */ /* When set indicates multiple transfers in a single message */ - bool rx_done; - bool tx_done; + bool done; u32 cur_msg_len; /* Used in FIFO mode to keep track of the transfer being processed */ struct spi_transfer *cur_tx_transfer; @@ -368,7 +364,6 @@ struct msm_spi { struct pinctrl_state *pins_active; struct pinctrl_state *pins_sleep; bool is_init_complete; - bool pack_words; }; /* Forward declaration */ @@ -522,8 +517,7 @@ static inline void msm_spi_set_write_count(struct msm_spi *dd, int val) static inline void msm_spi_complete(struct msm_spi *dd) { - dd->tx_done = true; - dd->rx_done = true; + dd->done = 1; } static inline void msm_spi_enable_error_flags(struct msm_spi *dd) diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c index f3715d85aedc..7cafd0dd59f5 100644 --- a/drivers/usb/gadget/function/f_mass_storage.c +++ b/drivers/usb/gadget/function/f_mass_storage.c @@ -454,13 +454,23 @@ static void bulk_in_complete(struct usb_ep *ep, struct usb_request *req) struct fsg_buffhd *bh = req->context; if (req->status || req->actual != req->length) - DBG(common, "%s --> %d, %u/%u\n", __func__, + pr_debug("%s --> %d, %u/%u\n", __func__, req->status, req->actual, req->length); if (req->status == -ECONNRESET) /* Request was cancelled */ usb_ep_fifo_flush(ep); /* Hold the lock while we update the request and buffer states */ smp_wmb(); + /* + * Disconnect and completion might race each other and driver data + * is set to NULL during ep disable. So, add a check if that is case. + */ + if (!common) { + bh->inreq_busy = 0; + bh->state = BUF_STATE_EMPTY; + return; + } + spin_lock(&common->lock); bh->inreq_busy = 0; bh->state = BUF_STATE_EMPTY; @@ -473,15 +483,24 @@ static void bulk_out_complete(struct usb_ep *ep, struct usb_request *req) struct fsg_common *common = ep->driver_data; struct fsg_buffhd *bh = req->context; - dump_msg(common, "bulk-out", req->buf, req->actual); if (req->status || req->actual != bh->bulk_out_intended_length) - DBG(common, "%s --> %d, %u/%u\n", __func__, + pr_debug("%s --> %d, %u/%u\n", __func__, req->status, req->actual, bh->bulk_out_intended_length); if (req->status == -ECONNRESET) /* Request was cancelled */ usb_ep_fifo_flush(ep); /* Hold the lock while we update the request and buffer states */ smp_wmb(); + /* + * Disconnect and completion might race each other and driver data + * is set to NULL during ep disable. So, add a check if that is case. + */ + if (!common) { + bh->outreq_busy = 0; + return; + } + + dump_msg(common, "bulk-out", req->buf, req->actual); spin_lock(&common->lock); bh->outreq_busy = 0; bh->state = BUF_STATE_FULL; diff --git a/drivers/usb/gadget/function/f_qc_rndis.c b/drivers/usb/gadget/function/f_qc_rndis.c index 11c73f584594..061095b78c37 100644 --- a/drivers/usb/gadget/function/f_qc_rndis.c +++ b/drivers/usb/gadget/function/f_qc_rndis.c @@ -683,6 +683,7 @@ static int rndis_qc_set_alt(struct usb_function *f, unsigned intf, unsigned alt) /* we know alt == 0 */ + opts = container_of(f->fi, struct f_rndis_qc_opts, func_inst); if (intf == rndis->ctrl_id) { if (rndis->notify->driver_data) { VDBG(cdev, "reset rndis control %d\n", intf); diff --git a/drivers/usb/gadget/function/u_ctrl_qti.c b/drivers/usb/gadget/function/u_ctrl_qti.c index 8ef223370827..013c54da0d0a 100644 --- a/drivers/usb/gadget/function/u_ctrl_qti.c +++ b/drivers/usb/gadget/function/u_ctrl_qti.c @@ -485,7 +485,7 @@ qti_ctrl_write(struct file *fp, const char __user *buf, size_t count, port->copied_from_modem++; spin_lock_irqsave(&port->lock, flags); - if (port && port->port_usb) { + if (port->port_usb) { if (port->port_type == QTI_PORT_RMNET) { g_rmnet = (struct grmnet *)port->port_usb; } else { diff --git a/drivers/usb/gadget/function/u_data_ipa.c b/drivers/usb/gadget/function/u_data_ipa.c index bf9e0fa9950b..6c18a04f6c1c 100644 --- a/drivers/usb/gadget/function/u_data_ipa.c +++ b/drivers/usb/gadget/function/u_data_ipa.c @@ -1107,18 +1107,18 @@ static void bam2bam_data_resume_work(struct work_struct *w) unsigned long flags; int ret; - if (!port->port_usb->cdev) { - pr_err("!port->port_usb->cdev is NULL"); + spin_lock_irqsave(&port->port_lock, flags); + if (!port->port_usb || !port->port_usb->cdev) { + pr_err("port->port_usb or cdev is NULL"); goto exit; } if (!port->port_usb->cdev->gadget) { - pr_err("!port->port_usb->cdev->gadget is NULL"); + pr_err("port->port_usb->cdev->gadget is NULL"); goto exit; } pr_debug("%s: resume started\n", __func__); - spin_lock_irqsave(&port->port_lock, flags); gadget = port->port_usb->cdev->gadget; if (!gadget) { spin_unlock_irqrestore(&port->port_lock, flags); diff --git a/drivers/usb/phy/phy-msm-usb.c b/drivers/usb/phy/phy-msm-usb.c index f3e17b84efff..f1360f20ffe4 100644 --- a/drivers/usb/phy/phy-msm-usb.c +++ b/drivers/usb/phy/phy-msm-usb.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2009-2017, Code Aurora Forum. All rights reserved. +/* Copyright (c) 2009-2011, 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 diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 5071d1039c26..025f11b9cffa 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -928,6 +928,8 @@ static int fuse_readpages_fill(void *_data, struct page *page) lock_page(newpage); put_page(newpage); + lru_cache_add_file(newpage); + /* finally release the old page and swap pointers */ unlock_page(oldpage); page_cache_release(oldpage); diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h index da8ca5a7da58..6d73a04d0150 100644 --- a/include/linux/blk_types.h +++ b/include/linux/blk_types.h @@ -39,6 +39,15 @@ struct bvec_iter { current bvec */ }; +#ifdef CONFIG_BLOCK_PERF_FRAMEWORK +/* Double declaration from ktime.h so as to not break the include dependency + * chain. Should be kept up to date. + */ +union blk_ktime { + s64 tv64; +}; +#endif + /* * main unit of I/O for the block layer and lower layers (ie drivers and * stacking drivers) @@ -54,6 +63,10 @@ struct bio { struct bvec_iter bi_iter; +#ifdef CONFIG_BLOCK_PERF_FRAMEWORK + union blk_ktime submit_time; + unsigned int blk_sector_count; +#endif /* Number of segments in this BIO after * physical address coalescing is performed. */ diff --git a/include/linux/cpumask.h b/include/linux/cpumask.h index 0eab4811ee92..d81d6a2db342 100644 --- a/include/linux/cpumask.h +++ b/include/linux/cpumask.h @@ -113,7 +113,7 @@ extern const struct cpumask *const cpu_isolated_mask; #define cpu_possible(cpu) ((cpu) == 0) #define cpu_present(cpu) ((cpu) == 0) #define cpu_active(cpu) ((cpu) == 0) -#define cpu_isolated(cpu) ((cpu) == 0) +#define cpu_isolated(cpu) ((cpu) != 0) #endif /* verify cpu argument to cpumask_* operators */ diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 276dbf19805b..804d89a825fc 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -22,6 +22,7 @@ #include <linux/mmc/core.h> #include <linux/mmc/card.h> #include <linux/mmc/pm.h> +#include <linux/mmc/ring_buffer.h> #define MMC_AUTOSUSPEND_DELAY_MS 3000 @@ -571,6 +572,7 @@ struct mmc_host { } perf; bool perf_enable; #endif + struct mmc_trace_buffer trace_buf; enum dev_state dev_status; bool wakeup_on_idle; struct mmc_cmdq_context_info cmdq_ctx; diff --git a/include/linux/mmc/ring_buffer.h b/include/linux/mmc/ring_buffer.h new file mode 100644 index 000000000000..e6bf163ffcfe --- /dev/null +++ b/include/linux/mmc/ring_buffer.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 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. + * + */ + +#ifndef __MMC_RING_BUFFER__ +#define __MMC_RING_BUFFER__ + +#include <linux/mmc/card.h> +#include <linux/smp.h> + +#include "core.h" + +#define MMC_TRACE_RBUF_SZ_ORDER 2 /* 2^2 pages */ +#define MMC_TRACE_RBUF_SZ (PAGE_SIZE * (1 << MMC_TRACE_RBUF_SZ_ORDER)) +#define MMC_TRACE_EVENT_SZ 256 +#define MMC_TRACE_RBUF_NUM_EVENTS (MMC_TRACE_RBUF_SZ / MMC_TRACE_EVENT_SZ) + +struct mmc_host; +struct mmc_trace_buffer { + int wr_idx; + bool stop_tracing; + spinlock_t trace_lock; + char *data; +}; + +#ifdef CONFIG_MMC_RING_BUFFER +void mmc_stop_tracing(struct mmc_host *mmc); +void mmc_trace_write(struct mmc_host *mmc, const char *fmt, ...); +void mmc_trace_init(struct mmc_host *mmc); +void mmc_trace_free(struct mmc_host *mmc); +void mmc_dump_trace_buffer(struct mmc_host *mmc, struct seq_file *s); +#else +static inline void mmc_stop_tracing(struct mmc_host *mmc) {} +static inline void mmc_trace_write(struct mmc_host *mmc, + const char *fmt, ...) {} +static inline void mmc_trace_init(struct mmc_host *mmc) {} +static inline void mmc_trace_free(struct mmc_host *mmc) {} +static inline void mmc_dump_trace_buffer(struct mmc_host *mmc, + struct seq_file *s) {} +#endif + +#define MMC_TRACE(mmc, fmt, ...) \ + mmc_trace_write(mmc, fmt, ##__VA_ARGS__) + +#endif /* __MMC_RING_BUFFER__ */ diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h index bc5637ab01df..4cde40dac778 100644 --- a/include/linux/usb/composite.h +++ b/include/linux/usb/composite.h @@ -55,7 +55,7 @@ #define USB_GADGET_DELAYED_STATUS 0x7fff /* Impossibly large value */ /* big enough to hold our biggest descriptor */ -#define USB_COMP_EP0_BUFSIZ 1024 +#define USB_COMP_EP0_BUFSIZ 4096 #define USB_MS_TO_HS_INTERVAL(x) (ilog2((x * 1000 / 125)) + 1) struct usb_configuration; diff --git a/kernel/sched/hmp.c b/kernel/sched/hmp.c index 40df4f8f1de0..95125c5518e2 100644 --- a/kernel/sched/hmp.c +++ b/kernel/sched/hmp.c @@ -590,6 +590,7 @@ void update_cluster_topology(void) * cluster_head visible. */ move_list(&cluster_head, &new_head, false); + update_all_clusters_stats(); } void init_clusters(void) diff --git a/security/pfe/pfk_kc.c b/security/pfe/pfk_kc.c index 0869a862f521..cd3f08b3959d 100644 --- a/security/pfe/pfk_kc.c +++ b/security/pfe/pfk_kc.c @@ -1,5 +1,5 @@ /* - * 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 @@ -100,6 +100,9 @@ struct kc_entry { struct task_struct *thread_pending; enum pfk_kc_entry_state state; + + /* ref count for the number of requests in the HW queue for this key */ + int loaded_ref_cnt; int scm_error; }; @@ -520,6 +523,10 @@ int pfk_kc_load_key_start(const unsigned char *key, size_t key_size, if (entry_exists) { kc_update_timestamp(entry); entry->state = ACTIVE_ICE_LOADED; + + if (async) + entry->loaded_ref_cnt++; + break; } case (FREE): @@ -529,8 +536,17 @@ int pfk_kc_load_key_start(const unsigned char *key, size_t key_size, entry->scm_error = ret; pr_err("%s: key load error (%d)\n", __func__, ret); } else { - entry->state = ACTIVE_ICE_LOADED; kc_update_timestamp(entry); + entry->state = ACTIVE_ICE_LOADED; + + /* + * only increase ref cnt for async calls, + * sync calls from within work thread do not pass + * requests further to HW + */ + if (async) + entry->loaded_ref_cnt++; + } break; case (ACTIVE_ICE_PRELOAD): @@ -539,6 +555,10 @@ int pfk_kc_load_key_start(const unsigned char *key, size_t key_size, break; case (ACTIVE_ICE_LOADED): kc_update_timestamp(entry); + + if (async) + entry->loaded_ref_cnt++; + break; case(SCM_ERROR): ret = entry->scm_error; @@ -572,6 +592,8 @@ void pfk_kc_load_key_end(const unsigned char *key, size_t key_size, const unsigned char *salt, size_t salt_size) { struct kc_entry *entry = NULL; + struct task_struct *tmp_pending = NULL; + int ref_cnt = 0; if (!kc_is_ready()) return; @@ -591,14 +613,28 @@ void pfk_kc_load_key_end(const unsigned char *key, size_t key_size, if (!entry) { kc_spin_unlock(); pr_err("internal error, there should an entry to unlock\n"); + return; } - entry->state = INACTIVE; + ref_cnt = --entry->loaded_ref_cnt; + + if (ref_cnt < 0) + pr_err("internal error, ref count should never be negative\n"); - /* wake-up invalidation if it's waiting for the entry to be released */ - if (entry->thread_pending) { - wake_up_process(entry->thread_pending); - entry->thread_pending = NULL; + if (!ref_cnt) { + entry->state = INACTIVE; + /* + * wake-up invalidation if it's waiting + * for the entry to be released + */ + if (entry->thread_pending) { + tmp_pending = entry->thread_pending; + entry->thread_pending = NULL; + + kc_spin_unlock(); + wake_up_process(tmp_pending); + return; + } } kc_spin_unlock(); |
