diff options
111 files changed, 3053 insertions, 1055 deletions
diff --git a/Documentation/devicetree/bindings/cnss/icnss.txt b/Documentation/devicetree/bindings/cnss/icnss.txt index 4b70e670798d..c801e8486f87 100644 --- a/Documentation/devicetree/bindings/cnss/icnss.txt +++ b/Documentation/devicetree/bindings/cnss/icnss.txt @@ -17,14 +17,14 @@ Required properties: - iommus: SMMUs and corresponding Stream IDs needed by WLAN - qcom,wlan-smmu-iova-address: I/O virtual address range as <start length> format to be used for allocations associated between WLAN and SMMU - - <supply-name>-supply: phandle to the regulator device tree node - Required "supply-name" is "vdd-0.8-cx-mx". - - qcom,<supply>-config: Specifies voltage levels for supply. Should be - specified in pairs (min, max), units uV. There can - be optional load in uA and Regulator settle delay in - uS. Optional properties: + - <supply-name>-supply: phandle to the regulator device tree node + optional "supply-name" is "vdd-0.8-cx-mx". + - qcom,<supply>-config: Specifies voltage levels for supply. Should be + specified in pairs (min, max), units uV. There can + be optional load in uA and Regulator settle delay in + uS. - qcom,icnss-vadc: VADC handle for vph_pwr read APIs. - qcom,icnss-adc_tm: VADC handle for vph_pwr notification APIs. - qcom,smmu-s1-bypass: Boolean context flag to set SMMU to S1 bypass diff --git a/Documentation/devicetree/bindings/fb/mdss-pll.txt b/Documentation/devicetree/bindings/fb/mdss-pll.txt index c3a1567340a8..2e9d2dae51a2 100644 --- a/Documentation/devicetree/bindings/fb/mdss-pll.txt +++ b/Documentation/devicetree/bindings/fb/mdss-pll.txt @@ -16,7 +16,8 @@ Required properties: "qcom,mdss_hdmi_pll_8996_v3", "qcom,mdss_hdmi_pll_8996_v3_1p8", "qcom,mdss_dsi_pll_8998", "qcom,mdss_dp_pll_8998", "qcom,mdss_hdmi_pll_8998", "qcom,mdss_dsi_pll_sdm660", - "qcom,mdss_dp_pll_sdm660", "qcom,mdss_dsi_pll_sdm630" + "qcom,mdss_dp_pll_sdm660", "qcom,mdss_dsi_pll_sdm630", + "qcom,mdss_dp_pll_sdm630" - cell-index: Specifies the controller used - reg: offset and length of the register set for the device. - reg-names : names to refer to register sets related to this device diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp-wled.txt b/Documentation/devicetree/bindings/leds/leds-qpnp-wled.txt index a77a291a99da..1e6aac56c44e 100644 --- a/Documentation/devicetree/bindings/leds/leds-qpnp-wled.txt +++ b/Documentation/devicetree/bindings/leds/leds-qpnp-wled.txt @@ -75,6 +75,9 @@ Optional properties for WLED: - qcom,lcd-auto-pfm-thresh : Specify the auto-pfm threshold, if the headroom voltage level falls below this threshold and auto PFM is enabled, boost controller will enter into PFM mode automatically. +- qcom,lcd-psm-ctrl : A boolean property to specify if PSM needs to be + controlled dynamically when WLED module is enabled + or disabled. Optional properties if 'qcom,disp-type-amoled' is mentioned in DT: - qcom,loop-comp-res-kohm : control to select the compensation resistor in kohm. default is 320. diff --git a/Documentation/devicetree/bindings/platform/msm/msm_rmnet_mhi.txt b/Documentation/devicetree/bindings/platform/msm/msm_rmnet_mhi.txt new file mode 100644 index 000000000000..5ec2fb51833e --- /dev/null +++ b/Documentation/devicetree/bindings/platform/msm/msm_rmnet_mhi.txt @@ -0,0 +1,25 @@ +MSM MHI RMNET interface device + +MHI RMNET provides a network interface over PCIe +to transfer IP packets between modem and apps. + +Required properties: +- compatible : "qcom,mhi-rmnet" +- At least one of MHI channel + - qcom,mhi-rx-channel : MHI channel number for incoming data + - qcom,mhi-tx-channel : MHI channel number for outgoing data +- Default MRU for interface + - qcom,mhi-mru +- Alias id to identify interface instance + +Example: + aliases { + mhi_rmnet0 = &mhi_rmnet_0; + }; + mhi_rmnet_0: qcom,mhi-rmnet@0 { + compatible = "qcom,mhi-rmnet"; + qcom,mhi-rx-channel = <101>; + qcom,mhi-tx-channel = <100>; + qcom,mhi-mru = <8000>; + status = "okay"; + }; diff --git a/arch/arm/boot/dts/qcom/apq8998-v2.1-mediabox.dts b/arch/arm/boot/dts/qcom/apq8998-v2.1-mediabox.dts index 00e3d0e42427..2f4037497764 100644 --- a/arch/arm/boot/dts/qcom/apq8998-v2.1-mediabox.dts +++ b/arch/arm/boot/dts/qcom/apq8998-v2.1-mediabox.dts @@ -21,6 +21,10 @@ qcom,board-id = <8 1>; }; +&spi_10 { + status = "disabled"; +}; + &msm_ath10k_wlan { status = "ok"; }; diff --git a/arch/arm/boot/dts/qcom/msm-audio-lpass.dtsi b/arch/arm/boot/dts/qcom/msm-audio-lpass.dtsi index 067f2c35eecd..97a134b46713 100644 --- a/arch/arm/boot/dts/qcom/msm-audio-lpass.dtsi +++ b/arch/arm/boot/dts/qcom/msm-audio-lpass.dtsi @@ -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 @@ -187,11 +187,6 @@ qcom,msm-dai-q6-dev-id = <16393>; }; - sb_4_tx_vi: qcom,msm-dai-q6-sb-4-tx-vi { - compatible = "qcom,msm-dai-q6-dev"; - qcom,msm-dai-q6-dev-id = <20233>; - }; - sb_5_tx: qcom,msm-dai-q6-sb-5-tx { compatible = "qcom,msm-dai-q6-dev"; qcom,msm-dai-q6-dev-id = <16395>; diff --git a/arch/arm/boot/dts/qcom/msm-pm660l.dtsi b/arch/arm/boot/dts/qcom/msm-pm660l.dtsi index f39cc96ea9a6..bcdbc4ed7c55 100644 --- a/arch/arm/boot/dts/qcom/msm-pm660l.dtsi +++ b/arch/arm/boot/dts/qcom/msm-pm660l.dtsi @@ -250,8 +250,8 @@ <0xd900 0x100>; reg-names = "qpnp-wled-ctrl-base", "qpnp-wled-sink-base"; - interrupts = <0x3 0xd8 0x1 IRQ_TYPE_EDGE_BOTH>, - <0x3 0xd8 0x2 IRQ_TYPE_EDGE_BOTH>; + interrupts = <0x3 0xd8 0x1 IRQ_TYPE_EDGE_RISING>, + <0x3 0xd8 0x2 IRQ_TYPE_EDGE_RISING>; interrupt-names = "ovp-irq", "sc-irq"; linux,name = "wled"; linux,default-trigger = "bkl-trigger"; @@ -394,6 +394,9 @@ #address-cells = <1>; #size-cells = <1>; reg = <0xec00 0x100>; + interrupts = <0x3 0xec 0x1 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "sc-irq"; + qcom,force-module-reenable; lcdb_ldo_vreg: ldo { diff --git a/arch/arm/boot/dts/qcom/msm-pmi8998.dtsi b/arch/arm/boot/dts/qcom/msm-pmi8998.dtsi index c21c136907d4..fba0aed42146 100644 --- a/arch/arm/boot/dts/qcom/msm-pmi8998.dtsi +++ b/arch/arm/boot/dts/qcom/msm-pmi8998.dtsi @@ -600,8 +600,8 @@ <0xd900 0x100>; reg-names = "qpnp-wled-ctrl-base", "qpnp-wled-sink-base"; - interrupts = <0x3 0xd8 0x1 IRQ_TYPE_EDGE_BOTH>, - <0x3 0xd8 0x2 IRQ_TYPE_EDGE_BOTH>; + interrupts = <0x3 0xd8 0x1 IRQ_TYPE_EDGE_RISING>, + <0x3 0xd8 0x2 IRQ_TYPE_EDGE_RISING>; interrupt-names = "ovp-irq", "sc-irq"; linux,name = "wled"; linux,default-trigger = "bkl-trigger"; diff --git a/arch/arm/boot/dts/qcom/msm8998-audio.dtsi b/arch/arm/boot/dts/qcom/msm8998-audio.dtsi index ac1e37fa1d63..c4e6393997ec 100644 --- a/arch/arm/boot/dts/qcom/msm8998-audio.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-audio.dtsi @@ -105,8 +105,7 @@ <&dai_tert_auxpcm>, <&dai_quat_auxpcm>, <&sb_0_rx>, <&sb_0_tx>, <&sb_1_rx>, <&sb_1_tx>, <&sb_2_rx>, <&sb_2_tx>, <&sb_3_rx>, <&sb_3_tx>, - <&sb_4_rx>, <&sb_4_tx>, <&sb_4_tx_vi>, - <&sb_5_tx>, + <&sb_4_rx>, <&sb_4_tx>, <&sb_5_tx>, <&afe_pcm_rx>, <&afe_pcm_tx>, <&afe_proxy_rx>, <&afe_proxy_tx>, <&incall_record_rx>, <&incall_record_tx>, <&incall_music_rx>, @@ -127,7 +126,6 @@ "msm-dai-q6-dev.16388", "msm-dai-q6-dev.16389", "msm-dai-q6-dev.16390", "msm-dai-q6-dev.16391", "msm-dai-q6-dev.16392", "msm-dai-q6-dev.16393", - "msm-dai-q6-dev.20233", "msm-dai-q6-dev.16395", "msm-dai-q6-dev.224", "msm-dai-q6-dev.225", "msm-dai-q6-dev.241", "msm-dai-q6-dev.240", "msm-dai-q6-dev.32771", @@ -164,7 +162,7 @@ }; }; - sound-tavil { + snd_934x: sound-tavil { compatible = "qcom,msm8998-asoc-snd-tavil"; qcom,model = "msm8998-tavil-snd-card"; qcom,ext-disp-audio-rx; @@ -239,8 +237,7 @@ <&dai_tert_auxpcm>, <&dai_quat_auxpcm>, <&sb_0_rx>, <&sb_0_tx>, <&sb_1_rx>, <&sb_1_tx>, <&sb_2_rx>, <&sb_2_tx>, <&sb_3_rx>, <&sb_3_tx>, - <&sb_4_rx>, <&sb_4_tx>, <&sb_4_tx_vi>, - <&sb_5_tx>, + <&sb_4_rx>, <&sb_4_tx>, <&sb_5_tx>, <&afe_pcm_rx>, <&afe_pcm_tx>, <&afe_proxy_rx>, <&afe_proxy_tx>, <&incall_record_rx>, <&incall_record_tx>, <&incall_music_rx>, @@ -261,7 +258,6 @@ "msm-dai-q6-dev.16388", "msm-dai-q6-dev.16389", "msm-dai-q6-dev.16390", "msm-dai-q6-dev.16391", "msm-dai-q6-dev.16392", "msm-dai-q6-dev.16393", - "msm-dai-q6-dev.20233", "msm-dai-q6-dev.16395", "msm-dai-q6-dev.224", "msm-dai-q6-dev.225", "msm-dai-q6-dev.241", "msm-dai-q6-dev.240", "msm-dai-q6-dev.32771", diff --git a/arch/arm/boot/dts/qcom/msm8998-cdp.dtsi b/arch/arm/boot/dts/qcom/msm8998-cdp.dtsi index 48415eb81406..2b925250c5c0 100644 --- a/arch/arm/boot/dts/qcom/msm8998-cdp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-cdp.dtsi @@ -516,6 +516,10 @@ qcom,mbhc-audio-jack-type = "6-pole-jack"; }; +&snd_934x { + qcom,mbhc-audio-jack-type = "6-pole-jack"; +}; + &soc { gpio_keys { compatible = "gpio-keys"; diff --git a/arch/arm/boot/dts/qcom/msm8998-pm.dtsi b/arch/arm/boot/dts/qcom/msm8998-pm.dtsi index 8fd75c369c53..bb478794e832 100644 --- a/arch/arm/boot/dts/qcom/msm8998-pm.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-pm.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 @@ -302,7 +302,7 @@ qcom,rpm-master-stats@778150 { compatible = "qcom,rpm-master-stats"; reg = <0x778150 0x5000>; - qcom,masters = "APSS", "MPSS", "ADSP", "SLPI"; + qcom,masters = "APSS", "MPSS", "ADSP", "SLPI", "TZ", "SPSS"; qcom,master-stats-version = <2>; qcom,master-offset = <4096>; }; @@ -322,7 +322,7 @@ compatible = "qcom,system-stats"; qcom,rpm-msg-ram = <&rpm_msg_ram>; qcom,rpm-code-ram = <&rpm_code_ram>; - qcom,masters = "APSS", "MPSS", "ADSP", "SLPI"; + qcom,masters = "APSS", "MPSS", "ADSP", "SLPI", "TZ", "SPSS"; }; qcom,mpm@7781b8 { diff --git a/arch/arm/boot/dts/qcom/sdm630-cdp.dtsi b/arch/arm/boot/dts/qcom/sdm630-cdp.dtsi index a5e33514976f..55e6943bf327 100644 --- a/arch/arm/boot/dts/qcom/sdm630-cdp.dtsi +++ b/arch/arm/boot/dts/qcom/sdm630-cdp.dtsi @@ -154,6 +154,15 @@ qcom,platform-te-gpio = <&tlmm 59 0>; }; +&mdss_dp_ctrl { + pinctrl-names = "mdss_dp_active", "mdss_dp_sleep"; + pinctrl-0 = <&mdss_dp_aux_active &mdss_dp_usbplug_cc_active>; + pinctrl-1 = <&mdss_dp_aux_suspend &mdss_dp_usbplug_cc_suspend>; + qcom,aux-en-gpio = <&tlmm 55 0>; + qcom,aux-sel-gpio = <&tlmm 56 0>; + qcom,usbplug-cc-gpio = <&tlmm 58 0>; +}; + &pm660l_wled { qcom,led-strings-list = [01 02]; }; diff --git a/arch/arm/boot/dts/qcom/sdm630-mdss-pll.dtsi b/arch/arm/boot/dts/qcom/sdm630-mdss-pll.dtsi index 82acdec92431..42eac0ab223a 100644 --- a/arch/arm/boot/dts/qcom/sdm630-mdss-pll.dtsi +++ b/arch/arm/boot/dts/qcom/sdm630-mdss-pll.dtsi @@ -44,4 +44,39 @@ }; }; }; + + mdss_dp_pll: qcom,mdss_dp_pll@c011000 { + compatible = "qcom,mdss_dp_pll_sdm630"; + status = "ok"; + label = "MDSS DP PLL"; + cell-index = <0>; + #clock-cells = <1>; + + reg = <0xc011c00 0x190>, + <0xc011000 0x910>, + <0x0c8c2300 0x8>; + reg-names = "pll_base", "phy_base", "gdsc_base"; + + gdsc-supply = <&gdsc_mdss>; + + clocks = <&clock_mmss MMSS_MDSS_AHB_CLK>, + <&clock_rpmcc RPM_LN_BB_CLK1>, + <&clock_gcc GCC_USB3_CLKREF_CLK>; + clock-names = "iface_clk", "ref_clk_src", "ref_clk"; + clock-rate = <0>; + + qcom,platform-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,platform-supply-entry@0 { + reg = <0>; + qcom,supply-name = "gdsc"; + qcom,supply-min-voltage = <0>; + qcom,supply-max-voltage = <0>; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + }; + }; + }; }; diff --git a/arch/arm/boot/dts/qcom/sdm630-mdss.dtsi b/arch/arm/boot/dts/qcom/sdm630-mdss.dtsi index 3fb6993d71d6..1fdfba6ddf2c 100644 --- a/arch/arm/boot/dts/qcom/sdm630-mdss.dtsi +++ b/arch/arm/boot/dts/qcom/sdm630-mdss.dtsi @@ -382,7 +382,7 @@ }; msm_ext_disp: qcom,msm_ext_disp { - status = "disabled"; + status = "ok"; compatible = "qcom,msm-ext-disp"; ext_disp_audio_codec: qcom,msm-ext-disp-audio-codec-rx { @@ -392,13 +392,13 @@ }; mdss_dp_ctrl: qcom,dp_ctrl@c990000 { - status = "disabled"; + status = "ok"; cell-index = <0>; compatible = "qcom,mdss-dp"; qcom,mdss-fb-map = <&mdss_fb2>; gdsc-supply = <&gdsc_mdss>; - vdda-1p2-supply = <&pm660_l1>; + vdda-1p8-supply = <&pm660_l10>; vdda-0p9-supply = <&pm660l_l1>; reg = <0xc990000 0xa84>, @@ -410,8 +410,37 @@ reg-names = "dp_ctrl", "dp_phy", "tcsr_regs", "dp_mmss_cc", "qfprom_physical","hdcp_physical"; + clocks = <&clock_mmss MMSS_MNOC_AHB_CLK>, + <&clock_mmss MMSS_MDSS_AHB_CLK>, + <&clock_mmss MMSS_MDSS_AXI_CLK>, + <&clock_mmss MMSS_MDSS_MDP_CLK>, + <&clock_mmss MMSS_MDSS_HDMI_DP_AHB_CLK>, + <&clock_mmss MMSS_MDSS_DP_AUX_CLK>, + <&clock_rpmcc RPM_LN_BB_CLK1>, + <&clock_gcc GCC_USB3_CLKREF_CLK>, + <&clock_gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>, + <&clock_mmss MMSS_MDSS_DP_LINK_CLK>, + <&clock_mmss MMSS_MDSS_DP_LINK_INTF_CLK>, + <&clock_mmss MMSS_MDSS_DP_CRYPTO_CLK>, + <&clock_mmss MMSS_MDSS_DP_PIXEL_CLK>, + <&clock_mmss DP_PIXEL_CLK_SRC>, + <&mdss_dp_pll DP_VCO_DIVIDED_CLK_SRC_MUX>; + clock-names = "core_mnoc_clk", "core_iface_clk", "core_bus_clk", + "core_mdp_core_clk", "core_alt_iface_clk", + "core_aux_clk", "core_ref_clk_src", "core_ref_clk", + "core_ahb_phy_clk", "ctrl_link_clk", + "ctrl_link_iface_clk", "ctrl_crypto_clk", + "ctrl_pixel_clk", "pixel_clk_rcg", "pixel_parent"; + + qcom,dp-usbpd-detection = <&pm660_pdphy>; + qcom,msm_ext_disp = <&msm_ext_disp>; + qcom,aux-cfg-settings = [00 13 00 00 0a 28 0a 03 b7 03]; + qcom,logical2physical-lane-map = [00 01 02 03]; + qcom,phy-register-offset = <0x4>; + qcom,max-pclk-frequency-khz = <150000>; + qcom,core-supply-entries { #address-cells = <1>; #size-cells = <0>; @@ -432,9 +461,9 @@ qcom,ctrl-supply-entry@0 { reg = <0>; - qcom,supply-name = "vdda-1p2"; - qcom,supply-min-voltage = <1200000>; - qcom,supply-max-voltage = <1250000>; + qcom,supply-name = "vdda-1p8"; + qcom,supply-min-voltage = <1780000>; + qcom,supply-max-voltage = <1950000>; qcom,supply-enable-load = <12560>; qcom,supply-disable-load = <4>; }; diff --git a/arch/arm/boot/dts/qcom/sdm630-mtp.dtsi b/arch/arm/boot/dts/qcom/sdm630-mtp.dtsi index be36f1b8a6cb..0619d62526b1 100644 --- a/arch/arm/boot/dts/qcom/sdm630-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/sdm630-mtp.dtsi @@ -164,6 +164,15 @@ qcom,platform-te-gpio = <&tlmm 59 0>; }; +&mdss_dp_ctrl { + pinctrl-names = "mdss_dp_active", "mdss_dp_sleep"; + pinctrl-0 = <&mdss_dp_aux_active &mdss_dp_usbplug_cc_active>; + pinctrl-1 = <&mdss_dp_aux_suspend &mdss_dp_usbplug_cc_suspend>; + qcom,aux-en-gpio = <&tlmm 55 0>; + qcom,aux-sel-gpio = <&tlmm 56 0>; + qcom,usbplug-cc-gpio = <&tlmm 58 0>; +}; + &pm660l_wled { qcom,led-strings-list = [01 02]; }; diff --git a/arch/arm/boot/dts/qcom/sdm630-qrd.dtsi b/arch/arm/boot/dts/qcom/sdm630-qrd.dtsi index 8763f57f5ae8..f21707db590a 100644 --- a/arch/arm/boot/dts/qcom/sdm630-qrd.dtsi +++ b/arch/arm/boot/dts/qcom/sdm630-qrd.dtsi @@ -285,6 +285,38 @@ }; }; +&tlmm { + pmx_ts_rst_active { + ts_rst_active: ts_rst_active { + mux { + pins = "gpio66"; + function = "gpio"; + }; + + config { + pins = "gpio66"; + drive-strength = <16>; + bias-pull-up; + }; + }; + }; + + pmx_ts_rst_suspend { + ts_rst_suspend: ts_rst_suspend { + mux { + pins = "gpio66"; + function = "gpio"; + }; + + config { + pins = "gpio66"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; +}; + &soc { gpio_keys { compatible = "gpio-keys"; @@ -310,4 +342,22 @@ }; }; + + hbtp { + compatible = "qcom,hbtp-input"; + pinctrl-names = "pmx_ts_active", "pmx_ts_suspend"; + pinctrl-0 = <&ts_rst_active>; + pinctrl-1 = <&ts_rst_suspend>; + vcc_ana-supply = <&pm660l_l3>; + vcc_dig-supply = <&pm660_l13>; + qcom,afe-load = <20000>; + qcom,afe-vtg-min = <3008000>; + qcom,afe-vtg-max = <3008000>; + qcom,dig-load = <40000>; + qcom,dig-vtg-min = <1808000>; + qcom,dig-vtg-max = <1808000>; + qcom,fb-resume-delay-us = <10000>; + qcom,afe-power-on-delay-us = <1000>; + qcom,afe-power-off-delay-us = <6>; + }; }; diff --git a/arch/arm/boot/dts/qcom/sdm630.dtsi b/arch/arm/boot/dts/qcom/sdm630.dtsi index cd895a067f65..ce088c372eea 100644 --- a/arch/arm/boot/dts/qcom/sdm630.dtsi +++ b/arch/arm/boot/dts/qcom/sdm630.dtsi @@ -322,6 +322,18 @@ reg = <0x0 0x92a00000 0x0 0x1e00000>; }; + pil_mba_mem: pil_mba_region@94800000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x94800000 0x0 0x200000>; + }; + + buffer_mem: buffer_region@94a00000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x94a00000 0x0 0x100000>; + }; + venus_fw_mem: venus_fw_region { compatible = "shared-dma-pool"; alloc-ranges = <0x0 0x80000000 0x0 0x20000000>; @@ -335,7 +347,7 @@ alloc-ranges = <0x0 0x00000000 0x0 0xffffffff>; reusable; alignment = <0x0 0x400000>; - size = <0x0 0xa00000>; + size = <0x0 0x800000>; }; qseecom_mem: qseecom_region { @@ -1742,6 +1754,10 @@ /* GPIO output to mss */ qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_1_out 0 0>; status = "ok"; + qcom,mba-mem@0 { + compatible = "qcom,pil-mba-mem"; + memory-region = <&pil_mba_mem>; + }; }; qcom,msm-rtb { @@ -2216,4 +2232,9 @@ debounce-interval = <15>; }; }; + + devfreq_spdm_cpu { + qcom,bw-dwnstep = <6750>; + qcom,max-vote = <6750>; + }; }; diff --git a/arch/arm/boot/dts/qcom/sdm658.dtsi b/arch/arm/boot/dts/qcom/sdm658.dtsi index 3eca3dc30e50..3387482dbc18 100644 --- a/arch/arm/boot/dts/qcom/sdm658.dtsi +++ b/arch/arm/boot/dts/qcom/sdm658.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 @@ -16,4 +16,67 @@ model = "Qualcomm Technologies, Inc. SDM 658"; compatible = "qcom,sdm658"; qcom,msm-id = <325 0x0>; + + cpus { + /delete-node/ cpu@102; + /delete-node/ cpu@103; + + cpu-map { + cluster1 { + /delete-node/ core2; + /delete-node/ core3; + }; + }; + }; +}; + +&soc { + /delete-node/ jtagmm@7e40000; + /delete-node/ jtagmm@7f40000; + /delete-node/ etm@7e40000; + /delete-node/ etm@7f40000; + /delete-node/ cti@7e20000; + /delete-node/ cti@7f20000; + + devfreq_memlat_4: qcom,arm-memlat-mon-4 { + qcom,cpulist = <&CPU4 &CPU5>; + }; + + cpuss_dump { + /delete-node/ qcom,l1_i_cache102; + /delete-node/ qcom,l1_i_cache103; + /delete-node/ qcom,l1_d_cache102; + /delete-node/ qcom,l1_d_cache103; + /delete-node/ qcom,l1_tlb_dump102; + /delete-node/ qcom,l1_tlb_dump103; + }; + + funnel@7b60000 { + ports { + /delete-node/ port@7; + /delete-node/ port@8; + }; + }; + + qcom,msm-thermal { + qcom,synchronous-cluster-map = <0 4 &CPU0 &CPU1 &CPU2 &CPU3>, + <1 2 &CPU4 &CPU5>; + }; + + qcom,bcl { + qcom,bcl-hotplug-list = <&CPU4 &CPU5>; + qcom,bcl-soc-hotplug-list = <&CPU4 &CPU5>; + }; + + qcom,spm@178120000 { + qcom,cpu-vctl-list = <&CPU4 &CPU5>; + }; + + qcom,lpm-levels { + qcom,pm-cluster@0 { + qcom,pm-cluster@1 { + qcom,cpu = <&CPU4 &CPU5>; + }; + }; + }; }; diff --git a/arch/arm/boot/dts/qcom/sdm660-bus.dtsi b/arch/arm/boot/dts/qcom/sdm660-bus.dtsi index 68ff96829d4f..0524935b9a30 100644 --- a/arch/arm/boot/dts/qcom/sdm660-bus.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-bus.dtsi @@ -1248,4 +1248,46 @@ qcom,slv-rpm-id = <ICBID_SLAVE_SERVICE_SNOC>; }; }; + + devfreq_spdm_cpu { + compatible = "qcom,devfreq_spdm"; + qcom,msm-bus,name = "devfreq_spdm"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <1 512 0 0>, + <1 512 0 0>; + qcom,msm-bus,active-only; + qcom,spdm-client = <0>; + + qcom,bw-upstep = <450>; + qcom,bw-dwnstep = <8200>; + qcom,max-vote = <8200>; + qcom,up-step-multp = <2>; + qcom,spdm-interval = <30>; + + qcom,ports = <24>; + qcom,alpha-up = <8>; + qcom,alpha-down = <15>; + qcom,bucket-size = <8>; + + /*max pl1 freq, max pl2 freq*/ + qcom,pl-freqs = <210000 610000>; + + /* pl1 low, pl1 high, pl2 low, pl2 high, pl3 low, pl3 high */ + qcom,reject-rate = <5000 5000 5000 5000 5000 5000>; + /* pl1 low, pl1 high, pl2 low, pl2 high, pl3 low, pl3 high */ + qcom,response-time-us = <5000 5000 5000 5000 5000 5000>; + + /* pl1 low, pl1 high, pl2 low, pl2 high, pl3 low, pl3 high */ + qcom,cci-response-time-us = <10000 10000 10000 + 10000 10000 10000>; + qcom,max-cci-freq = <1036800>; + }; + + devfreq_spdm_gov { + compatible = "qcom,gov_spdm_hyp"; + interrupt-names = "spdm-irq"; + interrupts = <0 192 IRQ_TYPE_EDGE_RISING>; + }; }; diff --git a/arch/arm/boot/dts/qcom/sdm660-camera.dtsi b/arch/arm/boot/dts/qcom/sdm660-camera.dtsi index 10afca1c56ed..e6bd0c06e444 100644 --- a/arch/arm/boot/dts/qcom/sdm660-camera.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-camera.dtsi @@ -396,6 +396,7 @@ reset-names = "micro_iface_reset"; qcom,src-clock-rates = <120000000 256000000 384000000 480000000 540000000 576000000>; + qcom,micro-reset; qcom,cpp-fw-payload-info { qcom,stripe-base = <790>; qcom,plane-base = <715>; diff --git a/arch/arm/boot/dts/qcom/sdm660-common.dtsi b/arch/arm/boot/dts/qcom/sdm660-common.dtsi index a9de658a064d..ad30af3376c7 100644 --- a/arch/arm/boot/dts/qcom/sdm660-common.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-common.dtsi @@ -467,10 +467,10 @@ qcom,devfreq,freq-table = <50000000 200000000>; qcom,pm-qos-irq-type = "affine_irq"; - qcom,pm-qos-irq-latency = <43 377>; + qcom,pm-qos-irq-latency = <43 518>; qcom,pm-qos-cpu-groups = <0x0f 0xf0>; - qcom,pm-qos-cmdq-latency-us = <43 377>, <40 325>; - qcom,pm-qos-legacy-latency-us = <43 377>, <40 325>; + qcom,pm-qos-cmdq-latency-us = <43 518>, <40 518>; + qcom,pm-qos-legacy-latency-us = <43 518>, <40 518>; qcom,msm-bus,name = "sdhc1"; qcom,msm-bus,num-cases = <9>; @@ -565,9 +565,9 @@ qcom,devfreq,freq-table = <50000000 200000000>; qcom,pm-qos-irq-type = "affine_irq"; - qcom,pm-qos-irq-latency = <43 377>; + qcom,pm-qos-irq-latency = <43 518>; qcom,pm-qos-cpu-groups = <0x0f 0xf0>; - qcom,pm-qos-legacy-latency-us = <43 377>, <40 325>; + qcom,pm-qos-legacy-latency-us = <43 518>, <40 518>; clocks = <&clock_gcc GCC_SDCC2_AHB_CLK>, <&clock_gcc GCC_SDCC2_APPS_CLK>; diff --git a/arch/arm/boot/dts/qcom/sdm660-coresight.dtsi b/arch/arm/boot/dts/qcom/sdm660-coresight.dtsi index dce86a7ceec3..51903c8b028d 100644 --- a/arch/arm/boot/dts/qcom/sdm660-coresight.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-coresight.dtsi @@ -942,30 +942,6 @@ clock-names = "core_clk", "core_a_clk"; }; - cti_lpass0: cti@7060000 { - compatible = "arm,coresight-cti"; - reg = <0x7060000 0x1000>; - reg-names = "cti-base"; - - coresight-name = "coresight-cti-lpass0"; - - clocks = <&clock_rpmcc RPM_QDSS_CLK>, - <&clock_rpmcc RPM_QDSS_A_CLK>; - clock-names = "core_clk", "core_a_clk"; - }; - - cti_lpass1: cti@7061000 { - compatible = "arm,coresight-cti"; - reg = <0x7061000 0x1000>; - reg-names = "cti-base"; - - coresight-name = "coresight-cti-lpass1"; - - clocks = <&clock_rpmcc RPM_QDSS_CLK>, - <&clock_rpmcc RPM_QDSS_A_CLK>; - clock-names = "core_clk", "core_a_clk"; - }; - cti_turing: cti@7068000 { compatible = "arm,coresight-cti"; reg = <0x7068000 0x1000>; diff --git a/arch/arm/boot/dts/qcom/sdm660-pinctrl.dtsi b/arch/arm/boot/dts/qcom/sdm660-pinctrl.dtsi index 57565134788c..37a88ea0dcec 100644 --- a/arch/arm/boot/dts/qcom/sdm660-pinctrl.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-pinctrl.dtsi @@ -52,12 +52,12 @@ trigout_a: trigout_a { mux { pins = "gpio49"; - function = "qdss_cti_trig_out_a"; + function = "qdss_cti0_a"; }; config { pins = "gpio49"; - drive-strength = <2>; + drive-strength = <16>; bias-disable; output-low; }; diff --git a/arch/arm/boot/dts/qcom/sdm660-qrd.dtsi b/arch/arm/boot/dts/qcom/sdm660-qrd.dtsi index 65741e0df3ba..77e8505408d0 100644 --- a/arch/arm/boot/dts/qcom/sdm660-qrd.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-qrd.dtsi @@ -52,6 +52,13 @@ status = "ok"; }; +&sdc2_cd_on { + config { + /delete-property/ bias-pull-up; + bias-disable; + }; +}; + &sdhc_2 { /* device core power supply */ vdd-supply = <&pm660l_l5>; @@ -245,10 +252,13 @@ qcom,parallel-charger; qcom,float-voltage-mv = <4400>; qcom,recharge-mv = <100>; - qcom,parallel-en-pin-polarity = <0>; + qcom,parallel-en-pin-polarity = <1>; }; }; +/delete-node/ &tasha_hph_en0; +/delete-node/ &tasha_hph_en1; + &tasha_snd { qcom,model = "sdm660-tasha-skus-snd-card"; qcom,audio-routing = diff --git a/arch/arm/boot/dts/qcom/sdm660-regulator.dtsi b/arch/arm/boot/dts/qcom/sdm660-regulator.dtsi index 47db57b3dc0a..462a76ef8bfe 100644 --- a/arch/arm/boot/dts/qcom/sdm660-regulator.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-regulator.dtsi @@ -695,8 +695,8 @@ qcom,cpr-corner-fmax-map = <2 3 4 5 8>; qcom,cpr-voltage-ceiling = - <724000 724000 724000 788000 868000 - 924000 988000 1068000>; + < 724000 724000 724000 788000 868000 + 1068000 1068000 1068000>; qcom,cpr-voltage-floor = <588000 588000 596000 652000 712000 @@ -729,13 +729,14 @@ 4370 4780>; qcom,cpr-open-loop-voltage-fuse-adjustment = - <13000 31000 27000 37000 21000>; + < (-4000) 4000 7000 19000 (-8000)>; qcom,cpr-closed-loop-voltage-fuse-adjustment = - <0 0 0 0 8000>; + <(-32000) (-30000) (-29000) (-23000) + (-21000)>; qcom,cpr-floor-to-ceiling-max-range = - <32000 32000 32000 40000 40000 + <32000 32000 32000 40000 44000 40000 40000 40000>; }; }; @@ -801,7 +802,7 @@ qcom,cpr-voltage-ceiling = <724000 724000 788000 868000 - 924000 988000 1068000>; + 988000 988000 1068000>; qcom,cpr-voltage-floor = <588000 596000 652000 712000 @@ -840,14 +841,15 @@ 2620 2280>; qcom,cpr-open-loop-voltage-fuse-adjustment = - <31000 39000 53000 40000 29000>; + <16000 27000 39000 39000 20000>; qcom,cpr-closed-loop-voltage-fuse-adjustment = - <0 3000 19000 23000 28000>; + <(-22000) (-9000) (-7000) (-2000) + 11000>; qcom,cpr-floor-to-ceiling-max-range = <40000 40000 40000 40000 - 40000 40000 40000>; + 66000 66000 40000>; }; }; }; diff --git a/arch/arm/boot/dts/qcom/sdm660.dtsi b/arch/arm/boot/dts/qcom/sdm660.dtsi index c14449289594..1767e811a826 100644 --- a/arch/arm/boot/dts/qcom/sdm660.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660.dtsi @@ -345,7 +345,7 @@ alloc-ranges = <0x0 0x00000000 0x0 0xffffffff>; reusable; alignment = <0x0 0x400000>; - size = <0x0 0xa00000>; + size = <0x0 0x800000>; }; qseecom_mem: qseecom_region { @@ -2050,6 +2050,11 @@ reg = <0x6b0 32>; }; + kaslr_offset@6d0 { + compatible = "qcom,msm-imem-kaslr_offset"; + reg = <0x6d0 12>; + }; + pil@94c { compatible = "qcom,msm-imem-pil"; reg = <0x94c 200>; diff --git a/arch/arm/configs/sdm660-perf_defconfig b/arch/arm/configs/sdm660-perf_defconfig index 309d7a802d07..62b3c87338c7 100644 --- a/arch/arm/configs/sdm660-perf_defconfig +++ b/arch/arm/configs/sdm660-perf_defconfig @@ -560,6 +560,7 @@ CONFIG_MSM_RPM_LOG=y CONFIG_MSM_RPM_STATS_LOG=y # CONFIG_WCD_DSP_GLINK is not set CONFIG_QCOM_SMCINVOKE=y +CONFIG_QCOM_CX_IPEAK=y CONFIG_MEM_SHARE_QMI_SERVICE=y CONFIG_QCOM_BIMC_BWMON=y CONFIG_ARM_MEMLAT_MON=y diff --git a/arch/arm/configs/sdm660_defconfig b/arch/arm/configs/sdm660_defconfig index ba22d7864d1c..f12addecaf02 100644 --- a/arch/arm/configs/sdm660_defconfig +++ b/arch/arm/configs/sdm660_defconfig @@ -565,6 +565,7 @@ CONFIG_MSM_RPM_STATS_LOG=y # CONFIG_WCD_DSP_GLINK is not set CONFIG_QCOM_SMCINVOKE=y CONFIG_QCOM_EARLY_RANDOM=y +CONFIG_QCOM_CX_IPEAK=y CONFIG_MEM_SHARE_QMI_SERVICE=y CONFIG_QCOM_BIMC_BWMON=y CONFIG_ARM_MEMLAT_MON=y diff --git a/arch/arm64/configs/msmcortex_defconfig b/arch/arm64/configs/msmcortex_defconfig index d5f30e9a8b16..c2038317857d 100644 --- a/arch/arm64/configs/msmcortex_defconfig +++ b/arch/arm64/configs/msmcortex_defconfig @@ -643,6 +643,8 @@ CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y CONFIG_DEBUG_STACK_USAGE=y CONFIG_DEBUG_MEMORY_INIT=y CONFIG_LOCKUP_DETECTOR=y +CONFIG_BOOTPARAM_HARDLOCKUP_PANIC=y +CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y CONFIG_WQ_WATCHDOG=y CONFIG_PANIC_TIMEOUT=5 CONFIG_PANIC_ON_SCHED_BUG=y diff --git a/arch/arm64/configs/msmcortex_mediabox_defconfig b/arch/arm64/configs/msmcortex_mediabox_defconfig index 7e762a4d207b..9ebe740c7d91 100644 --- a/arch/arm64/configs/msmcortex_mediabox_defconfig +++ b/arch/arm64/configs/msmcortex_mediabox_defconfig @@ -298,7 +298,6 @@ CONFIG_INPUT_KEYCHORD=y CONFIG_INPUT_UINPUT=y CONFIG_INPUT_GPIO=y # CONFIG_SERIO_SERPORT is not set -# CONFIG_VT is not set # CONFIG_LEGACY_PTYS is not set CONFIG_SERIAL_MSM=y CONFIG_SERIAL_MSM_CONSOLE=y diff --git a/arch/arm64/configs/sdm660-perf_defconfig b/arch/arm64/configs/sdm660-perf_defconfig index b0bdabf58d62..29ddd002830c 100644 --- a/arch/arm64/configs/sdm660-perf_defconfig +++ b/arch/arm64/configs/sdm660-perf_defconfig @@ -67,6 +67,7 @@ CONFIG_ARMV8_DEPRECATED=y CONFIG_SWP_EMULATION=y CONFIG_CP15_BARRIER_EMULATION=y CONFIG_SETEND_EMULATION=y +CONFIG_RANDOMIZE_BASE=y # CONFIG_EFI is not set CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set @@ -575,6 +576,7 @@ CONFIG_MSM_RPM_STATS_LOG=y CONFIG_QSEE_IPC_IRQ_BRIDGE=y CONFIG_QCOM_SMCINVOKE=y CONFIG_QCOM_EARLY_RANDOM=y +CONFIG_QCOM_CX_IPEAK=y CONFIG_MEM_SHARE_QMI_SERVICE=y CONFIG_QCOM_BIMC_BWMON=y CONFIG_ARM_MEMLAT_MON=y diff --git a/arch/arm64/configs/sdm660_defconfig b/arch/arm64/configs/sdm660_defconfig index 7b21409c3266..034ce548556e 100644 --- a/arch/arm64/configs/sdm660_defconfig +++ b/arch/arm64/configs/sdm660_defconfig @@ -67,6 +67,7 @@ CONFIG_ARMV8_DEPRECATED=y CONFIG_SWP_EMULATION=y CONFIG_CP15_BARRIER_EMULATION=y CONFIG_SETEND_EMULATION=y +CONFIG_RANDOMIZE_BASE=y CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set CONFIG_COMPAT=y @@ -596,6 +597,7 @@ CONFIG_MSM_RPM_STATS_LOG=y CONFIG_QSEE_IPC_IRQ_BRIDGE=y CONFIG_QCOM_SMCINVOKE=y CONFIG_QCOM_EARLY_RANDOM=y +CONFIG_QCOM_CX_IPEAK=y CONFIG_MEM_SHARE_QMI_SERVICE=y CONFIG_QCOM_BIMC_BWMON=y CONFIG_ARM_MEMLAT_MON=y diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c index c3efb77d1229..a2b67feb623b 100644 --- a/arch/arm64/mm/fault.c +++ b/arch/arm64/mm/fault.c @@ -334,10 +334,6 @@ static int __kprobes do_page_fault(unsigned long addr, unsigned int esr, } if (addr < USER_DS && is_permission_fault(esr, regs)) { - /* regs->orig_addr_limit may be 0 if we entered from EL0 */ - if (regs->orig_addr_limit == KERNEL_DS) - die("Accessing user space memory with fs=KERNEL_DS", regs, esr); - if (is_el1_instruction_abort(esr)) die("Attempting to execute userspace memory", regs, esr); diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c index 9ca46ae54ce3..070297785452 100644 --- a/drivers/char/adsprpc.c +++ b/drivers/char/adsprpc.c @@ -217,6 +217,7 @@ struct fastrpc_channel_ctx { int ssrcount; void *handle; int prevssrcount; + int issubsystemup; int vmid; int ramdumpenabled; void *remoteheap_ramdump_dev; @@ -230,6 +231,7 @@ struct fastrpc_apps { struct mutex smd_mutex; struct smq_phy_page range; struct hlist_head maps; + uint32_t staticpd_flags; dev_t dev_no; int compat; struct hlist_head drivers; @@ -1518,10 +1520,15 @@ static int fastrpc_init_process(struct fastrpc_file *fl, struct fastrpc_ioctl_init_attrs *uproc) { int err = 0; + struct fastrpc_apps *me = &gfa; struct fastrpc_ioctl_invoke_attrs ioctl; struct fastrpc_ioctl_init *init = &uproc->init; struct smq_phy_page pages[1]; struct fastrpc_mmap *file = 0, *mem = 0; + int srcVM[1] = {VMID_HLOS}; + int destVM[1] = {VMID_ADSP_Q6}; + int destVMperm[1] = {PERM_READ | PERM_WRITE | PERM_EXEC}; + int hlosVMperm[1] = {PERM_READ | PERM_WRITE | PERM_EXEC}; VERIFY(err, !fastrpc_channel_open(fl)); if (err) @@ -1609,12 +1616,9 @@ static int fastrpc_init_process(struct fastrpc_file *fl, if (err) goto bail; } else if (init->flags == FASTRPC_INIT_CREATE_STATIC) { - int srcVM[1] = {VMID_HLOS}; - int destVM[1] = {VMID_ADSP_Q6}; - int destVMperm[1] = {PERM_READ | PERM_WRITE | PERM_EXEC}; remote_arg_t ra[3]; uint64_t phys = 0; - ssize_t size; + ssize_t size = 0; int fds[3]; char *proc_name = (unsigned char *)init->file; struct { @@ -1624,15 +1628,27 @@ static int fastrpc_init_process(struct fastrpc_file *fl, } inbuf; inbuf.pgid = current->tgid; inbuf.namelen = strlen(proc_name)+1; - inbuf.pageslen = 1; - VERIFY(err, !fastrpc_mmap_create(fl, -1, 0, init->mem, - init->memlen, ADSP_MMAP_HEAP_ADDR, &mem)); - phys = mem->phys; - size = mem->size; - VERIFY(err, !hyp_assign_phys(phys, (uint64_t)size, - srcVM, 1, destVM, destVMperm, 1)); - if (err) - goto bail; + inbuf.pageslen = 0; + if (!me->staticpd_flags) { + inbuf.pageslen = 1; + VERIFY(err, !fastrpc_mmap_create(fl, -1, 0, init->mem, + init->memlen, ADSP_MMAP_REMOTE_HEAP_ADDR, + &mem)); + if (err) + goto bail; + phys = mem->phys; + size = mem->size; + VERIFY(err, !hyp_assign_phys(phys, (uint64_t)size, + srcVM, 1, destVM, destVMperm, 1)); + if (err) { + pr_err("ADSPRPC: hyp_assign_phys fail err %d", + err); + pr_err("map->phys %llx, map->size %d\n", + phys, (int)size); + goto bail; + } + me->staticpd_flags = 1; + } ra[0].buf.pv = (void *)&inbuf; ra[0].buf.len = sizeof(inbuf); @@ -1662,8 +1678,14 @@ static int fastrpc_init_process(struct fastrpc_file *fl, err = -ENOTTY; } bail: - if (mem && err) + if (err && (init->flags == FASTRPC_INIT_CREATE_STATIC)) + me->staticpd_flags = 0; + if (mem && err) { + if (mem->flags == ADSP_MMAP_REMOTE_HEAP_ADDR) + hyp_assign_phys(mem->phys, (uint64_t)mem->size, + destVM, 1, srcVM, hlosVMperm, 1); fastrpc_mmap_free(mem); + } if (file) fastrpc_mmap_free(file); return err; @@ -1790,6 +1812,8 @@ static int fastrpc_munmap_on_dsp_rh(struct fastrpc_file *fl, ioctl.inv.pra = ra; ioctl.fds = 0; ioctl.attrs = 0; + if (fl == NULL) + goto bail; VERIFY(err, 0 == (err = fastrpc_internal_invoke(fl, FASTRPC_MODE_PARALLEL, 1, &ioctl))); @@ -1824,12 +1848,6 @@ static int fastrpc_munmap_on_dsp(struct fastrpc_file *fl, uintptr_t vaddrout; ssize_t size; } inargs; - if (map->flags == ADSP_MMAP_HEAP_ADDR || - map->flags == ADSP_MMAP_REMOTE_HEAP_ADDR) { - VERIFY(err, !fastrpc_munmap_on_dsp_rh(fl, map)); - if (err) - goto bail; - } inargs.pid = current->tgid; inargs.size = map->size; @@ -1847,6 +1865,14 @@ static int fastrpc_munmap_on_dsp(struct fastrpc_file *fl, ioctl.attrs = 0; VERIFY(err, 0 == (err = fastrpc_internal_invoke(fl, FASTRPC_MODE_PARALLEL, 1, &ioctl))); + if (err) + goto bail; + if (map->flags == ADSP_MMAP_HEAP_ADDR || + map->flags == ADSP_MMAP_REMOTE_HEAP_ADDR) { + VERIFY(err, !fastrpc_munmap_on_dsp_rh(fl, map)); + if (err) + goto bail; + } bail: return err; } @@ -1858,35 +1884,38 @@ static int fastrpc_mmap_remove_ssr(struct fastrpc_file *fl) int err = 0, ret = 0; struct fastrpc_apps *me = &gfa; struct ramdump_segment *ramdump_segments_rh = NULL; - - spin_lock(&me->hlock); - hlist_for_each_entry_safe(map, n, &me->maps, hn) { + do { + match = 0; + spin_lock(&me->hlock); + hlist_for_each_entry_safe(map, n, &me->maps, hn) { match = map; hlist_del_init(&map->hn); break; - } - spin_unlock(&me->hlock); + } + spin_unlock(&me->hlock); - if (match) { - VERIFY(err, !fastrpc_munmap_on_dsp_rh(fl, match)); - if (err) - goto bail; - if (me->channel[0].ramdumpenabled) { - ramdump_segments_rh = kcalloc(1, + if (match) { + VERIFY(err, !fastrpc_munmap_on_dsp_rh(fl, match)); + if (err) + goto bail; + if (me->channel[0].ramdumpenabled) { + ramdump_segments_rh = kcalloc(1, sizeof(struct ramdump_segment), GFP_KERNEL); - if (ramdump_segments_rh) { - ramdump_segments_rh->address = match->phys; - ramdump_segments_rh->size = match->size; - ret = do_elf_ramdump( - me->channel[0].remoteheap_ramdump_dev, - ramdump_segments_rh, 1); - if (ret < 0) - pr_err("ADSPRPC: unable to dump heap"); - kfree(ramdump_segments_rh); + if (ramdump_segments_rh) { + ramdump_segments_rh->address = + match->phys; + ramdump_segments_rh->size = match->size; + ret = do_elf_ramdump( + me->channel[0].remoteheap_ramdump_dev, + ramdump_segments_rh, 1); + if (ret < 0) + pr_err("ADSPRPC: unable to dump heap"); + kfree(ramdump_segments_rh); + } } + fastrpc_mmap_free(match); } - fastrpc_mmap_free(match); - } + } while (match); bail: if (err && match) fastrpc_mmap_add(match); @@ -2349,6 +2378,14 @@ static int fastrpc_channel_open(struct fastrpc_file *fl) if (err) goto bail; cid = fl->cid; + if (me->channel[cid].ssrcount != + me->channel[cid].prevssrcount) { + if (!me->channel[cid].issubsystemup) { + VERIFY(err, 0); + if (err) + goto bail; + } + } VERIFY(err, cid >= 0 && cid < NUM_CHANNELS); if (err) goto bail; @@ -2578,6 +2615,7 @@ static int fastrpc_restart_notifier_cb(struct notifier_block *nb, if (code == SUBSYS_BEFORE_SHUTDOWN) { mutex_lock(&me->smd_mutex); ctx->ssrcount++; + ctx->issubsystemup = 0; if (ctx->chan) { fastrpc_glink_close(ctx->chan, cid); ctx->chan = 0; @@ -2585,12 +2623,16 @@ static int fastrpc_restart_notifier_cb(struct notifier_block *nb, gcinfo[cid].name, MAJOR(me->dev_no), cid); } mutex_unlock(&me->smd_mutex); + if (cid == 0) + me->staticpd_flags = 0; fastrpc_notify_drivers(me, cid); } else if (code == SUBSYS_RAMDUMP_NOTIFICATION) { if (me->channel[0].remoteheap_ramdump_dev && notifdata->enable_ramdump) { me->channel[0].ramdumpenabled = 1; } + } else if (code == SUBSYS_AFTER_POWERUP) { + ctx->issubsystemup = 1; } return NOTIFY_DONE; @@ -2882,6 +2924,7 @@ static int __init fastrpc_device_init(void) me->channel[i].dev = dev; me->channel[i].ssrcount = 0; me->channel[i].prevssrcount = 0; + me->channel[i].issubsystemup = 1; me->channel[i].ramdumpenabled = 0; me->channel[i].remoteheap_ramdump_dev = 0; me->channel[i].nb.notifier_call = fastrpc_restart_notifier_cb; diff --git a/drivers/char/diag/diag_masks.c b/drivers/char/diag/diag_masks.c index a1721a3b80cc..44e71a704e6a 100644 --- a/drivers/char/diag/diag_masks.c +++ b/drivers/char/diag/diag_masks.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 @@ -112,10 +112,12 @@ static void diag_send_log_mask_update(uint8_t peripheral, int equip_id) else mask_info = &log_mask; - if (!mask_info) + if (!mask_info || !mask_info->ptr || !mask_info->update_buf) return; mask = (struct diag_log_mask_t *)mask_info->ptr; + if (!mask->ptr) + return; buf = mask_info->update_buf; switch (mask_info->status) { @@ -224,7 +226,7 @@ static void diag_send_event_mask_update(uint8_t peripheral) else mask_info = &event_mask; - if (!mask_info) + if (!mask_info || !mask_info->ptr || !mask_info->update_buf) return; buf = mask_info->update_buf; @@ -305,10 +307,12 @@ static void diag_send_msg_mask_update(uint8_t peripheral, int first, int last) else mask_info = &msg_mask; - if (!mask_info) + if (!mask_info || !mask_info->ptr || !mask_info->update_buf) return; mask = (struct diag_msg_mask_t *)mask_info->ptr; + if (!mask->ptr) + return; buf = mask_info->update_buf; mutex_lock(&mask_info->lock); switch (mask_info->status) { diff --git a/drivers/clk/qcom/clk-smd-rpm.c b/drivers/clk/qcom/clk-smd-rpm.c index 0d76b6b28985..5345e9086627 100644 --- a/drivers/clk/qcom/clk-smd-rpm.c +++ b/drivers/clk/qcom/clk-smd-rpm.c @@ -570,6 +570,10 @@ static DEFINE_CLK_VOTER(pnoc_msmbus_clk, pnoc_clk, LONG_MAX); static DEFINE_CLK_VOTER(pnoc_msmbus_a_clk, pnoc_a_clk, LONG_MAX); static DEFINE_CLK_VOTER(pnoc_pm_clk, pnoc_clk, LONG_MAX); static DEFINE_CLK_VOTER(pnoc_sps_clk, pnoc_clk, 0); +static DEFINE_CLK_VOTER(aggre2_noc_msmbus_clk, aggre2_noc_clk, LONG_MAX); +static DEFINE_CLK_VOTER(aggre2_noc_msmbus_a_clk, aggre2_noc_a_clk, LONG_MAX); +static DEFINE_CLK_VOTER(aggre2_noc_usb_clk, aggre2_noc_clk, 19200000); +static DEFINE_CLK_VOTER(aggre2_noc_smmu_clk, aggre2_noc_clk, 1000); /* Voter Branch clocks */ static DEFINE_CLK_BRANCH_VOTER(cxo_dwc3_clk, cxo); @@ -738,6 +742,10 @@ static struct clk_hw *sdm660_clks[] = { [CXO_PIL_LPASS_CLK] = &cxo_pil_lpass_clk.hw, [CXO_PIL_CDSP_CLK] = &cxo_pil_cdsp_clk.hw, [CNOC_PERIPH_KEEPALIVE_A_CLK] = &cnoc_periph_keepalive_a_clk.hw, + [AGGR2_NOC_MSMBUS_CLK] = &aggre2_noc_msmbus_clk.hw, + [AGGR2_NOC_MSMBUS_A_CLK] = &aggre2_noc_msmbus_a_clk.hw, + [AGGR2_NOC_SMMU_CLK] = &aggre2_noc_smmu_clk.hw, + [AGGR2_NOC_USB_CLK] = &aggre2_noc_usb_clk.hw, }; static const struct rpm_smd_clk_desc rpm_clk_sdm660 = { diff --git a/drivers/clk/qcom/mdss/mdss-pll.c b/drivers/clk/qcom/mdss/mdss-pll.c index 833bb4a17b6a..9b7f014e1cec 100644 --- a/drivers/clk/qcom/mdss/mdss-pll.c +++ b/drivers/clk/qcom/mdss/mdss-pll.c @@ -149,6 +149,9 @@ static int mdss_pll_resource_parse(struct platform_device *pdev, } else if (!strcmp(compatible_stream, "qcom,mdss_dp_pll_sdm660")) { pll_res->target_id = MDSS_PLL_TARGET_SDM660; pll_res->pll_interface_type = MDSS_DP_PLL_SDM660; + } else if (!strcmp(compatible_stream, "qcom,mdss_dp_pll_sdm630")) { + pll_res->target_id = MDSS_PLL_TARGET_SDM630; + pll_res->pll_interface_type = MDSS_DP_PLL_SDM630; } else if (!strcmp(compatible_stream, "qcom,mdss_hdmi_pll_8996")) { pll_res->pll_interface_type = MDSS_HDMI_PLL_8996; } else if (!strcmp(compatible_stream, "qcom,mdss_hdmi_pll_8996_v2")) { @@ -189,6 +192,9 @@ static int mdss_pll_clock_register(struct platform_device *pdev, case MDSS_DP_PLL_SDM660: rc = dp_pll_clock_register_14nm(pdev, pll_res); break; + case MDSS_DP_PLL_SDM630: + rc = dp_pll_clock_register_14nm(pdev, pll_res); + break; case MDSS_UNKNOWN_PLL: default: rc = -EINVAL; @@ -396,6 +402,7 @@ static const struct of_device_id mdss_pll_dt_match[] = { {.compatible = "qcom,mdss_dsi_pll_sdm660"}, {.compatible = "qcom,mdss_dp_pll_sdm660"}, {.compatible = "qcom,mdss_dsi_pll_sdm630"}, + {.compatible = "qcom,mdss_dp_pll_sdm630"}, {} }; diff --git a/drivers/clk/qcom/mdss/mdss-pll.h b/drivers/clk/qcom/mdss/mdss-pll.h index cb6918127041..369c36407ff7 100644 --- a/drivers/clk/qcom/mdss/mdss-pll.h +++ b/drivers/clk/qcom/mdss/mdss-pll.h @@ -42,6 +42,7 @@ enum { MDSS_DSI_PLL_8998, MDSS_DP_PLL_8998, MDSS_DP_PLL_SDM660, + MDSS_DP_PLL_SDM630, MDSS_HDMI_PLL_8996, MDSS_HDMI_PLL_8996_V2, MDSS_HDMI_PLL_8996_V3, diff --git a/drivers/clk/qcom/mmcc-sdm660.c b/drivers/clk/qcom/mmcc-sdm660.c index 87e6f8c6be0a..0bf7ef05ed06 100644 --- a/drivers/clk/qcom/mmcc-sdm660.c +++ b/drivers/clk/qcom/mmcc-sdm660.c @@ -1041,7 +1041,7 @@ static const struct freq_tbl ftbl_mclk0_clk_src[] = { F(9600000, P_CXO, 2, 0, 0), F(16666667, P_GPLL0_OUT_MAIN_DIV, 2, 1, 9), F(19200000, P_CXO, 1, 0, 0), - F(24000000, P_GPLL0_OUT_MAIN_DIV, 1, 2, 25), + F(24000000, P_MMPLL10_PLL_OUT_MAIN, 1, 1, 24), F(33333333, P_GPLL0_OUT_MAIN_DIV, 1, 1, 9), F(48000000, P_GPLL0_OUT_MAIN, 1, 2, 25), F(66666667, P_GPLL0_OUT_MAIN, 1, 1, 9), diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index 900d37ca0d7c..5dc26d29e4a4 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -687,6 +687,7 @@ static void __init arch_timer_common_init(void) arch_timer_banner(arch_timers_present); arch_counter_register(arch_timers_present); arch_timer_arch_init(); + clocksource_select_force(); } static void __init arch_timer_init(void) diff --git a/drivers/cpuidle/lpm-levels.c b/drivers/cpuidle/lpm-levels.c index d8e571981c35..64c4bf8f58a8 100644 --- a/drivers/cpuidle/lpm-levels.c +++ b/drivers/cpuidle/lpm-levels.c @@ -1542,11 +1542,14 @@ static int lpm_cpuidle_enter(struct cpuidle_device *dev, struct cpuidle_driver *drv, int idx) { struct lpm_cluster *cluster = per_cpu(cpu_cluster, dev->cpu); - bool success = true; + bool success = false; const struct cpumask *cpumask = get_cpu_mask(dev->cpu); int64_t start_time = ktime_to_ns(ktime_get()), end_time; struct power_params *pwr_params; + if (idx < 0) + return -EINVAL; + pwr_params = &cluster->cpu->levels[idx].pwr; sched_set_cpu_cstate(smp_processor_id(), idx + 1, pwr_params->energy_overhead, pwr_params->latency_us); @@ -1559,7 +1562,7 @@ static int lpm_cpuidle_enter(struct cpuidle_device *dev, trace_cpu_idle_enter(idx); lpm_stats_cpu_enter(idx, start_time); - if (need_resched() || (idx < 0)) + if (need_resched()) goto exit; BUG_ON(!use_psci); diff --git a/drivers/gpu/drm/msm/sde/sde_formats.c b/drivers/gpu/drm/msm/sde/sde_formats.c index dc7827872276..23ffa9b554dd 100644 --- a/drivers/gpu/drm/msm/sde/sde_formats.c +++ b/drivers/gpu/drm/msm/sde/sde_formats.c @@ -384,19 +384,19 @@ static const struct sde_format sde_format_map[] = { * the data will be passed by user-space. */ static const struct sde_format sde_format_map_ubwc[] = { - INTERLEAVED_RGB_FMT(BGR565, + INTERLEAVED_RGB_FMT(RGB565, 0, COLOR_5BIT, COLOR_6BIT, COLOR_5BIT, C2_R_Cr, C0_G_Y, C1_B_Cb, 0, 3, false, 2, 0, SDE_FETCH_UBWC, 2), - INTERLEAVED_RGB_FMT(ABGR8888, + INTERLEAVED_RGB_FMT(RGBA8888, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, true, 4, 0, SDE_FETCH_UBWC, 2), - INTERLEAVED_RGB_FMT(XBGR8888, + INTERLEAVED_RGB_FMT(RGBX8888, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, false, 4, 0, diff --git a/drivers/leds/leds-qpnp-wled.c b/drivers/leds/leds-qpnp-wled.c index 1e24c79c3f0a..950244f1e4e8 100644 --- a/drivers/leds/leds-qpnp-wled.c +++ b/drivers/leds/leds-qpnp-wled.c @@ -33,6 +33,7 @@ /* ctrl registers */ #define QPNP_WLED_FAULT_STATUS(b) (b + 0x08) +#define QPNP_WLED_INT_RT_STS(b) (b + 0x10) #define QPNP_WLED_EN_REG(b) (b + 0x46) #define QPNP_WLED_FDBK_OP_REG(b) (b + 0x48) #define QPNP_WLED_VREF_REG(b) (b + 0x49) @@ -44,6 +45,7 @@ #define QPNP_WLED_SOFTSTART_RAMP_DLY(b) (b + 0x53) #define QPNP_WLED_VLOOP_COMP_RES_REG(b) (b + 0x55) #define QPNP_WLED_VLOOP_COMP_GM_REG(b) (b + 0x56) +#define QPNP_WLED_EN_PSM_REG(b) (b + 0x5A) #define QPNP_WLED_PSM_CTRL_REG(b) (b + 0x5B) #define QPNP_WLED_LCD_AUTO_PFM_REG(b) (b + 0x5C) #define QPNP_WLED_SC_PRO_REG(b) (b + 0x5E) @@ -82,12 +84,13 @@ #define QPNP_WLED_VREF_PSM_MIN_MV 400 #define QPNP_WLED_VREF_PSM_MAX_MV 750 #define QPNP_WLED_VREF_PSM_DFLT_AMOLED_MV 450 -#define QPNP_WLED_PSM_CTRL_OVERWRITE 0x80 +#define QPNP_WLED_PSM_OVERWRITE_BIT BIT(7) #define QPNP_WLED_LCD_AUTO_PFM_DFLT_THRESH 1 #define QPNP_WLED_LCD_AUTO_PFM_THRESH_MAX 0xF #define QPNP_WLED_LCD_AUTO_PFM_EN_SHIFT 7 #define QPNP_WLED_LCD_AUTO_PFM_EN_BIT BIT(7) #define QPNP_WLED_LCD_AUTO_PFM_THRESH_MASK GENMASK(3, 0) +#define QPNP_WLED_EN_PSM_BIT BIT(7) #define QPNP_WLED_ILIM_MASK GENMASK(2, 0) #define QPNP_WLED_ILIM_OVERWRITE BIT(7) @@ -117,6 +120,9 @@ QPNP_WLED_TEST4_EN_CLAMP_BIT | \ QPNP_WLED_TEST4_EN_SOFT_START_BIT) #define QPNP_WLED_TEST4_EN_IIND_UP 0x1 +#define QPNP_WLED_ILIM_FAULT_BIT BIT(0) +#define QPNP_WLED_OVP_FAULT_BIT BIT(1) +#define QPNP_WLED_SC_FAULT_BIT BIT(2) /* sink registers */ #define QPNP_WLED_CURR_SINK_REG(b) (b + 0x46) @@ -335,6 +341,7 @@ static struct wled_vref_setting vref_setting_pmi8998 = { * @ lcd_auto_pfm_thresh - the threshold for lcd auto pfm mode * @ loop_auto_gm_en - select if auto gm is enabled * @ lcd_auto_pfm_en - select if auto pfm is enabled in lcd mode + * @ lcd_psm_ctrl - select if psm needs to be controlled in lcd mode * @ avdd_mode_spmi - enable avdd programming via spmi * @ en_9b_dim_res - enable or disable 9bit dimming * @ en_phase_stag - enable or disable phase staggering @@ -380,6 +387,7 @@ struct qpnp_wled { u8 lcd_auto_pfm_thresh; bool loop_auto_gm_en; bool lcd_auto_pfm_en; + bool lcd_psm_ctrl; bool avdd_mode_spmi; bool en_9b_dim_res; bool en_phase_stag; @@ -549,6 +557,30 @@ static int qpnp_wled_set_level(struct qpnp_wled *wled, int level) return 0; } +static int qpnp_wled_psm_config(struct qpnp_wled *wled, bool enable) +{ + int rc; + + if (!wled->lcd_psm_ctrl) + return 0; + + rc = qpnp_wled_masked_write_reg(wled, + QPNP_WLED_EN_PSM_REG(wled->ctrl_base), + QPNP_WLED_EN_PSM_BIT, + enable ? QPNP_WLED_EN_PSM_BIT : 0); + if (rc < 0) + return rc; + + rc = qpnp_wled_masked_write_reg(wled, + QPNP_WLED_PSM_CTRL_REG(wled->ctrl_base), + QPNP_WLED_PSM_OVERWRITE_BIT, + enable ? QPNP_WLED_PSM_OVERWRITE_BIT : 0); + if (rc < 0) + return rc; + + return 0; +} + static int qpnp_wled_module_en(struct qpnp_wled *wled, u16 base_addr, bool state) { @@ -561,21 +593,31 @@ static int qpnp_wled_module_en(struct qpnp_wled *wled, if (rc < 0) return rc; - if (wled->ovp_irq > 0) { - if (state && wled->ovp_irq_disabled) { - /* - * Wait for at least 10ms before enabling OVP fault - * interrupt after enabling the module so that soft - * start is completed. Keep OVP interrupt disabled - * when the module is disabled. - */ - usleep_range(10000, 11000); + /* + * Wait for at least 10ms before enabling OVP fault interrupt after + * enabling the module so that soft start is completed. Also, this + * delay can be used to control PSM during enable when required. Keep + * OVP interrupt disabled when the module is disabled. + */ + if (state) { + usleep_range(10000, 11000); + rc = qpnp_wled_psm_config(wled, false); + if (rc < 0) + return rc; + + if (wled->ovp_irq > 0 && wled->ovp_irq_disabled) { enable_irq(wled->ovp_irq); wled->ovp_irq_disabled = false; - } else if (!state && !wled->ovp_irq_disabled) { + } + } else { + if (wled->ovp_irq > 0 && !wled->ovp_irq_disabled) { disable_irq(wled->ovp_irq); wled->ovp_irq_disabled = true; } + + rc = qpnp_wled_psm_config(wled, true); + if (rc < 0) + return rc; } return 0; @@ -990,7 +1032,7 @@ static int qpnp_wled_set_disp(struct qpnp_wled *wled, u16 base_addr) reg &= QPNP_WLED_VREF_PSM_MASK; reg |= ((wled->vref_psm_mv - QPNP_WLED_VREF_PSM_MIN_MV)/ QPNP_WLED_VREF_PSM_STEP_MV); - reg |= QPNP_WLED_PSM_CTRL_OVERWRITE; + reg |= QPNP_WLED_PSM_OVERWRITE_BIT; rc = qpnp_wled_write_reg(wled, QPNP_WLED_PSM_CTRL_REG(wled->ctrl_base), reg); if (rc) @@ -1053,16 +1095,25 @@ static irqreturn_t qpnp_wled_ovp_irq_handler(int irq, void *_wled) { struct qpnp_wled *wled = _wled; int rc; - u8 val; + u8 fault_sts, int_sts; rc = qpnp_wled_read_reg(wled, - QPNP_WLED_FAULT_STATUS(wled->ctrl_base), &val); + QPNP_WLED_INT_RT_STS(wled->ctrl_base), &int_sts); + if (rc < 0) { + pr_err("Error in reading WLED_INT_RT_STS rc=%d\n", rc); + return IRQ_HANDLED; + } + + rc = qpnp_wled_read_reg(wled, + QPNP_WLED_FAULT_STATUS(wled->ctrl_base), &fault_sts); if (rc < 0) { pr_err("Error in reading WLED_FAULT_STATUS rc=%d\n", rc); return IRQ_HANDLED; } - pr_err("WLED OVP fault detected, fault_status= %x\n", val); + if (fault_sts & (QPNP_WLED_OVP_FAULT_BIT | QPNP_WLED_ILIM_FAULT_BIT)) + pr_err("WLED OVP fault detected, int_sts=%x fault_sts= %x\n", + int_sts, fault_sts); return IRQ_HANDLED; } @@ -1677,6 +1728,8 @@ static int qpnp_wled_config(struct qpnp_wled *wled) wled->ovp_irq, rc); return rc; } + disable_irq(wled->ovp_irq); + wled->ovp_irq_disabled = true; } if (wled->sc_irq >= 0) { @@ -2063,6 +2116,8 @@ static int qpnp_wled_parse_dt(struct qpnp_wled *wled) wled->en_ext_pfet_sc_pro = of_property_read_bool(pdev->dev.of_node, "qcom,en-ext-pfet-sc-pro"); + wled->lcd_psm_ctrl = of_property_read_bool(pdev->dev.of_node, + "qcom,lcd-psm-ctrl"); return 0; } diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h index aca8e99650ba..e54342e3935a 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h @@ -795,6 +795,7 @@ struct vfe_device { struct msm_vfe_error_info error_info; struct msm_vfe_fetch_engine_info fetch_engine_info; enum msm_vfe_hvx_streaming_cmd hvx_cmd; + uint8_t cur_hvx_state; /* State variables */ uint32_t vfe_hw_version; diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c index 57373c1fc74c..d829aefe6c98 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c @@ -1495,6 +1495,10 @@ void msm_vfe47_configure_hvx(struct vfe_device *vfe_dev, uint32_t val; int rc = 0; + if (is_stream_on == vfe_dev->cur_hvx_state) { + ISP_DBG("already in same hvx state\n"); + return; + } if (vfe_dev->buf_mgr->secure_enable == SECURE_MODE) { pr_err("%s: Cannot configure hvx, secure_mode: %d\n", __func__, @@ -1528,6 +1532,7 @@ void msm_vfe47_configure_hvx(struct vfe_device *vfe_dev, val &= 0xFFFFFFF7; msm_camera_io_w_mb(val, vfe_dev->vfe_base + 0x50); } + vfe_dev->cur_hvx_state = is_stream_on; } void msm_vfe47_update_camif_state(struct vfe_device *vfe_dev, diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c index 1ddf51407884..4e74851dc67d 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c @@ -39,13 +39,13 @@ static int msm_isp_axi_create_stream(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd, struct msm_vfe_axi_stream *stream_info) { - uint32_t i; + uint32_t i = 0; int rc = 0; if (stream_info->state != AVAILABLE) { - pr_err("%s:%d invalid state %d expected %d for src %d\n", + pr_err("%s:%d invalid state %d expected %d\n", __func__, __LINE__, stream_info->state, - AVAILABLE, i); + AVAILABLE); return -EINVAL; } diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c index df9691be0c28..86b500973538 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c @@ -26,6 +26,7 @@ #define MAX_ISP_V4l2_EVENTS 100 +#define MAX_ISP_REG_LIST 100 static DEFINE_MUTEX(bandwidth_mgr_mutex); static struct msm_isp_bandwidth_mgr isp_bandwidth_mgr; @@ -630,6 +631,13 @@ static int msm_isp_set_dual_HW_master_slave_mode( } ISP_DBG("%s: vfe %d num_src %d\n", __func__, vfe_dev->pdev->id, dual_hw_ms_cmd->num_src); + if (dual_hw_ms_cmd->num_src > VFE_SRC_MAX) { + pr_err("%s: Error! Invalid num_src %d\n", __func__, + dual_hw_ms_cmd->num_src); + spin_unlock_irqrestore(&vfe_dev->common_data-> + common_dev_data_lock, flags); + return -EINVAL; + } /* This for loop is for non-primary intf to be marked with Master/Slave * in order for frame id sync. But their timestamp is not saved. * So no sof_info resource is allocated */ @@ -662,6 +670,7 @@ static int msm_isp_set_dual_HW_master_slave_mode( static int msm_isp_proc_cmd_list_unlocked(struct vfe_device *vfe_dev, void *arg) { int rc = 0; + uint32_t count = 0; struct msm_vfe_cfg_cmd_list *proc_cmd = (struct msm_vfe_cfg_cmd_list *)arg; struct msm_vfe_cfg_cmd_list cmd, cmd_next; @@ -685,6 +694,12 @@ static int msm_isp_proc_cmd_list_unlocked(struct vfe_device *vfe_dev, void *arg) sizeof(struct msm_vfe_cfg_cmd_list)); break; } + if (++count >= MAX_ISP_REG_LIST) { + pr_err("%s:%d Error exceeding the max register count:%u\n", + __func__, __LINE__, count); + rc = -EINVAL; + break; + } if (copy_from_user(&cmd_next, (void __user *)cmd.next, sizeof(struct msm_vfe_cfg_cmd_list))) { rc = -EFAULT; @@ -731,6 +746,7 @@ static void msm_isp_compat_to_proc_cmd(struct msm_vfe_cfg_cmd2 *proc_cmd, static int msm_isp_proc_cmd_list_compat(struct vfe_device *vfe_dev, void *arg) { int rc = 0; + uint32_t count = 0; struct msm_vfe_cfg_cmd_list_32 *proc_cmd = (struct msm_vfe_cfg_cmd_list_32 *)arg; struct msm_vfe_cfg_cmd_list_32 cmd, cmd_next; @@ -755,6 +771,12 @@ static int msm_isp_proc_cmd_list_compat(struct vfe_device *vfe_dev, void *arg) sizeof(struct msm_vfe_cfg_cmd_list)); break; } + if (++count >= MAX_ISP_REG_LIST) { + pr_err("%s:%d Error exceeding the max register count:%u\n", + __func__, __LINE__, count); + rc = -EINVAL; + break; + } if (copy_from_user(&cmd_next, compat_ptr(cmd.next), sizeof(struct msm_vfe_cfg_cmd_list_32))) { rc = -EFAULT; diff --git a/drivers/media/platform/msm/camera_v2/msm.c b/drivers/media/platform/msm/camera_v2/msm.c index 5cf5582b55ab..c2b42a854d35 100644 --- a/drivers/media/platform/msm/camera_v2/msm.c +++ b/drivers/media/platform/msm/camera_v2/msm.c @@ -1119,17 +1119,21 @@ long msm_copy_camera_private_ioctl_args(unsigned long arg, struct msm_camera_private_ioctl_arg *k_ioctl, void __user **tmp_compat_ioctl_ptr) { - struct msm_camera_private_ioctl_arg *up_ioctl_ptr = - (struct msm_camera_private_ioctl_arg *)arg; + struct msm_camera_private_ioctl_arg up_ioctl; if (WARN_ON(!arg || !k_ioctl || !tmp_compat_ioctl_ptr)) return -EIO; - k_ioctl->id = up_ioctl_ptr->id; - k_ioctl->size = up_ioctl_ptr->size; - k_ioctl->result = up_ioctl_ptr->result; - k_ioctl->reserved = up_ioctl_ptr->reserved; - *tmp_compat_ioctl_ptr = compat_ptr(up_ioctl_ptr->ioctl_ptr); + if (copy_from_user(&up_ioctl, + (struct msm_camera_private_ioctl_arg *)arg, + sizeof(struct msm_camera_private_ioctl_arg))) + return -EFAULT; + + k_ioctl->id = up_ioctl.id; + k_ioctl->size = up_ioctl.size; + k_ioctl->result = up_ioctl.result; + k_ioctl->reserved = up_ioctl.reserved; + *tmp_compat_ioctl_ptr = compat_ptr(up_ioctl.ioctl_ptr); return 0; } diff --git a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c index 12d5d7eeb368..48872334cd83 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c +++ b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c @@ -1,4 +1,4 @@ -/* 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 @@ -1284,6 +1284,10 @@ static int32_t msm_cci_init(struct v4l2_subdev *sd, CDBG("%s:%d master %d\n", __func__, __LINE__, master); if (master < MASTER_MAX && master >= 0) { mutex_lock(&cci_dev->cci_master_info[master].mutex); + mutex_lock(&cci_dev->cci_master_info[master]. + mutex_q[PRIORITY_QUEUE]); + mutex_lock(&cci_dev->cci_master_info[master]. + mutex_q[SYNC_QUEUE]); flush_workqueue(cci_dev->write_wq[master]); /* Re-initialize the completion */ reinit_completion(&cci_dev-> @@ -1308,6 +1312,10 @@ static int32_t msm_cci_init(struct v4l2_subdev *sd, if (rc <= 0) pr_err("%s:%d wait failed %d\n", __func__, __LINE__, rc); + mutex_unlock(&cci_dev->cci_master_info[master]. + mutex_q[SYNC_QUEUE]); + mutex_unlock(&cci_dev->cci_master_info[master]. + mutex_q[PRIORITY_QUEUE]); mutex_unlock(&cci_dev->cci_master_info[master].mutex); } return 0; diff --git a/drivers/media/platform/msm/camera_v2/sensor/ois/msm_ois.c b/drivers/media/platform/msm/camera_v2/sensor/ois/msm_ois.c index 5a891592b44f..c94ee509631f 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/ois/msm_ois.c +++ b/drivers/media/platform/msm/camera_v2/sensor/ois/msm_ois.c @@ -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 @@ -452,7 +452,8 @@ static int32_t msm_ois_config(struct msm_ois_ctrl_t *o_ctrl, break; } - if (!conf_array.size) { + if (!conf_array.size || + conf_array.size > I2C_SEQ_REG_DATA_MAX) { pr_err("%s:%d failed\n", __func__, __LINE__); rc = -EFAULT; break; diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index fb5ffde61e8b..ce0ecd1e9b7a 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -3544,7 +3544,7 @@ void mmc_blk_cmdq_complete_rq(struct request *rq) else if (mrq->data && mrq->data->error) err = mrq->data->error; - if (err || cmdq_req->resp_err) { + if ((err || cmdq_req->resp_err) && !cmdq_req->skip_err_handling) { pr_err("%s: %s: txfr error(%d)/resp_err(%d)\n", mmc_hostname(mrq->host), __func__, err, cmdq_req->resp_err); @@ -3581,6 +3581,17 @@ void mmc_blk_cmdq_complete_rq(struct request *rq) blk_end_request_all(rq, err); goto out; } + /* + * In case of error, cmdq_req->data.bytes_xfered is set to 0. + * If we call blk_end_request() with nr_bytes as 0 then the request + * never gets completed. So in case of error, to complete a request + * with error we should use blk_end_request_all(). + */ + if (err && cmdq_req->skip_err_handling) { + cmdq_req->skip_err_handling = false; + blk_end_request_all(rq, err); + goto out; + } blk_end_request(rq, err, cmdq_req->data.bytes_xfered); diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index f79e8377a2ee..5396e1d00178 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -2114,6 +2114,38 @@ int __mmc_claim_host(struct mmc_host *host, atomic_t *abort) EXPORT_SYMBOL(__mmc_claim_host); /** + * mmc_try_claim_host - try exclusively to claim a host + * and keep trying for given time, with a gap of 10ms + * @host: mmc host to claim + * @dealy_ms: delay in ms + * + * Returns %1 if the host is claimed, %0 otherwise. + */ +int mmc_try_claim_host(struct mmc_host *host, unsigned int delay_ms) +{ + int claimed_host = 0; + unsigned long flags; + int retry_cnt = delay_ms/10; + + do { + spin_lock_irqsave(&host->lock, flags); + if (!host->claimed || host->claimer == current) { + host->claimed = 1; + host->claimer = current; + host->claim_cnt += 1; + claimed_host = 1; + } + spin_unlock_irqrestore(&host->lock, flags); + if (!claimed_host) + mmc_delay(10); + } while (!claimed_host && retry_cnt--); + if (host->ops->enable && claimed_host && host->claim_cnt == 1) + host->ops->enable(host); + return claimed_host; +} +EXPORT_SYMBOL(mmc_try_claim_host); + +/** * mmc_release_host - release a host * @host: mmc host to release * diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c index a0d31ded04db..594fba08e623 100644 --- a/drivers/mmc/core/debugfs.c +++ b/drivers/mmc/core/debugfs.c @@ -348,6 +348,33 @@ static int mmc_force_err_set(void *data, u64 val) DEFINE_SIMPLE_ATTRIBUTE(mmc_force_err_fops, NULL, mmc_force_err_set, "%llu\n"); +static int mmc_err_state_get(void *data, u64 *val) +{ + struct mmc_host *host = data; + + if (!host) + return -EINVAL; + + *val = host->err_occurred ? 1 : 0; + + return 0; +} + +static int mmc_err_state_clear(void *data, u64 val) +{ + struct mmc_host *host = data; + + if (!host) + return -EINVAL; + + host->err_occurred = false; + + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(mmc_err_state, mmc_err_state_get, + mmc_err_state_clear, "%llu\n"); + void mmc_add_host_debugfs(struct mmc_host *host) { struct dentry *root; @@ -393,6 +420,10 @@ void mmc_add_host_debugfs(struct mmc_host *host) root, host, &mmc_ring_buffer_fops)) goto err_node; #endif + if (!debugfs_create_file("err_state", S_IRUSR | S_IWUSR, root, host, + &mmc_err_state)) + goto err_node; + #ifdef CONFIG_MMC_CLKGATE if (!debugfs_create_u32("clk_delay", (S_IRUSR | S_IWUSR), root, &host->clk_delay)) diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index 7e7d7eb4da2a..ec5ce79e84e7 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -1147,7 +1147,17 @@ static void mmc_sd_detect(struct mmc_host *host) BUG_ON(!host); BUG_ON(!host->card); - mmc_get_card(host->card); + /* + * Try to acquire claim host. If failed to get the lock in 2 sec, + * just return; This is to ensure that when this call is invoked + * due to pm_suspend, not to block suspend for longer duration. + */ + pm_runtime_get_sync(&host->card->dev); + if (!mmc_try_claim_host(host, 2000)) { + pm_runtime_mark_last_busy(&host->card->dev); + pm_runtime_put_autosuspend(&host->card->dev); + return; + } /* * Just check if our card has been removed. diff --git a/drivers/mmc/host/cmdq_hci.c b/drivers/mmc/host/cmdq_hci.c index 96d4fbf1a823..1ad5fd0e0a78 100644 --- a/drivers/mmc/host/cmdq_hci.c +++ b/drivers/mmc/host/cmdq_hci.c @@ -145,6 +145,29 @@ static void cmdq_clear_set_irqs(struct cmdq_host *cq_host, u32 clear, u32 set) mb(); } +static int cmdq_clear_task_poll(struct cmdq_host *cq_host, unsigned int tag) +{ + int retries = 100; + + cmdq_clear_set_irqs(cq_host, CQIS_TCL, 0); + cmdq_writel(cq_host, 1<<tag, CQTCLR); + while (retries) { + /* + * Task Clear register and doorbell, + * both should indicate that task is cleared + */ + if ((cmdq_readl(cq_host, CQTCLR) & 1<<tag) || + (cmdq_readl(cq_host, CQTDBR) & 1<<tag)) { + udelay(5); + retries--; + continue; + } else + break; + } + + cmdq_clear_set_irqs(cq_host, 0, CQIS_TCL); + return retries ? 0 : -ETIMEDOUT; +} #define DRV_NAME "cmdq-host" @@ -857,6 +880,8 @@ irqreturn_t cmdq_irq(struct mmc_host *mmc, int err) struct mmc_request *mrq; int ret; u32 dbr_set = 0; + u32 dev_pend_set = 0; + int stat_err = 0; status = cmdq_readl(cq_host, CQIS); @@ -865,7 +890,9 @@ irqreturn_t cmdq_irq(struct mmc_host *mmc, int err) MMC_TRACE(mmc, "%s: CQIS: 0x%x err: %d\n", __func__, status, err); - if (err || (status & CQIS_RED)) { + stat_err = status & (CQIS_RED | CQIS_GCE | CQIS_ICCE); + + if (err || stat_err) { err_info = cmdq_readl(cq_host, CQTERRI); pr_err("%s: err: %d status: 0x%08x task-err-info (0x%08lx)\n", mmc_hostname(mmc), err, status, err_info); @@ -968,7 +995,7 @@ skip_cqterri: * CQE detected a reponse error from device * In most cases, this would require a reset. */ - if (status & CQIS_RED) { + if (stat_err & CQIS_RED) { /* * will check if the RED error is due to a bkops * exception once the queue is empty @@ -987,6 +1014,62 @@ skip_cqterri: mrq->cmdq_req->resp_arg = cmdq_readl(cq_host, CQCRA); } + /* + * Generic Crypto error detected by CQE. + * Its a fatal, would require cmdq reset. + */ + if (stat_err & CQIS_GCE) { + if (mrq->data) + mrq->data->error = -EIO; + pr_err("%s: Crypto generic error while processing task %lu!", + mmc_hostname(mmc), tag); + MMC_TRACE(mmc, "%s: GCE error detected with tag %lu\n", + __func__, tag); + } + /* + * Invalid crypto config error detected by CQE, clear the task. + * Task can be cleared only when CQE is halt state. + */ + if (stat_err & CQIS_ICCE) { + /* + * Invalid Crypto Config Error is detected at the + * beginning of the transfer before the actual execution + * started. So just clear the task in CQE. No need to + * clear in device. Only the task which caused ICCE has + * to be cleared. Other tasks can be continue processing + * The first task which is about to be prepared would + * cause ICCE Error. + */ + dbr_set = cmdq_readl(cq_host, CQTDBR); + dev_pend_set = cmdq_readl(cq_host, CQDPT); + if (dbr_set ^ dev_pend_set) + tag = ffs(dbr_set ^ dev_pend_set) - 1; + mrq = get_req_by_tag(cq_host, tag); + pr_err("%s: Crypto config error while processing task %lu!", + mmc_hostname(mmc), tag); + MMC_TRACE(mmc, "%s: ICCE error with tag %lu\n", + __func__, tag); + if (mrq->data) + mrq->data->error = -EIO; + else if (mrq->cmd) + mrq->cmd->error = -EIO; + /* + * If CQE is halted and tag is valid then clear the task + * then un-halt CQE and set flag to skip error recovery. + * If any of the condtions is not met thene it will + * enter into default error recovery path. + */ + if (!ret && (dbr_set ^ dev_pend_set)) { + ret = cmdq_clear_task_poll(cq_host, tag); + if (ret) { + pr_err("%s: %s: task[%lu] clear failed ret=%d\n", + mmc_hostname(mmc), + __func__, tag, ret); + } else if (!cmdq_halt_poll(mmc, false)) { + mrq->cmdq_req->skip_err_handling = true; + } + } + } cmdq_finish_data(mmc, tag); } else { cmdq_writel(cq_host, status, CQIS); @@ -1052,6 +1135,7 @@ static int cmdq_halt_poll(struct mmc_host *mmc, bool halt) cq_host->ops->clear_set_irqs(mmc, true); cmdq_writel(cq_host, cmdq_readl(cq_host, CQCTL) & ~HALT, CQCTL); + mmc_host_clr_halt(mmc); return 0; } diff --git a/drivers/mmc/host/cmdq_hci.h b/drivers/mmc/host/cmdq_hci.h index 6c10ab3859d1..db0cd956ae90 100644 --- a/drivers/mmc/host/cmdq_hci.h +++ b/drivers/mmc/host/cmdq_hci.h @@ -37,6 +37,8 @@ #define CQIS_TCC (1 << 1) #define CQIS_RED (1 << 2) #define CQIS_TCL (1 << 3) +#define CQIS_GCE (1 << 4) +#define CQIS_ICCE (1 << 5) /* interrupt status enable */ #define CQISTE 0x14 @@ -112,7 +114,7 @@ /* command response argument */ #define CQCRA 0x5C -#define CQ_INT_ALL 0xF +#define CQ_INT_ALL 0x3F #define CQIC_DEFAULT_ICCTH 31 #define CQIC_DEFAULT_ICTOVAL 1 diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 21d2a4b8f7ae..1fdc23365c8f 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -179,6 +179,8 @@ static void sdhci_dumpregs(struct sdhci_host *host) readl(host->ioaddr + SDHCI_ADMA_ADDRESS)); } + host->mmc->err_occurred = true; + if (host->ops->dump_vendor_regs) host->ops->dump_vendor_regs(host); sdhci_dump_state(host); diff --git a/drivers/net/ethernet/msm/msm_rmnet_mhi.c b/drivers/net/ethernet/msm/msm_rmnet_mhi.c index 4285a8d8a65f..9117ea7d08c0 100644 --- a/drivers/net/ethernet/msm/msm_rmnet_mhi.c +++ b/drivers/net/ethernet/msm/msm_rmnet_mhi.c @@ -26,18 +26,16 @@ #include <linux/ipc_logging.h> #include <linux/device.h> #include <linux/errno.h> +#include <linux/of_device.h> #define RMNET_MHI_DRIVER_NAME "rmnet_mhi" #define RMNET_MHI_DEV_NAME "rmnet_mhi%d" #define MHI_DEFAULT_MTU 8000 -#define MHI_DEFAULT_MRU 8000 #define MHI_MAX_MRU 0xFFFF #define MHI_NAPI_WEIGHT_VALUE 12 #define MHI_RX_HEADROOM 64 #define WATCHDOG_TIMEOUT (30 * HZ) -#define MHI_RMNET_DEVICE_COUNT 1 #define RMNET_IPC_LOG_PAGES (100) -#define IS_INBOUND(_chan) (((u32)(_chan)) % 2) enum DBG_LVL { MSG_VERBOSE = 0x1, @@ -49,88 +47,38 @@ enum DBG_LVL { MSG_reserved = 0x80000000 }; +struct debug_params { + enum DBG_LVL rmnet_msg_lvl; + enum DBG_LVL rmnet_ipc_log_lvl; + u64 tx_interrupts_count; + u64 rx_interrupts_count; + u64 tx_ring_full_count; + u64 tx_queued_packets_count; + u64 rx_interrupts_in_masked_irq; + u64 rx_napi_skb_burst_min; + u64 rx_napi_skb_burst_max; + u64 tx_cb_skb_free_burst_min; + u64 tx_cb_skb_free_burst_max; + u64 rx_napi_budget_overflow; + u64 rx_fragmentation; +}; + struct __packed mhi_skb_priv { dma_addr_t dma_addr; size_t dma_size; }; -enum DBG_LVL rmnet_msg_lvl = MSG_CRITICAL; - -#ifdef CONFIG_MSM_MHI_DEBUG -enum DBG_LVL rmnet_ipc_log_lvl = MSG_VERBOSE; -#else -enum DBG_LVL rmnet_ipc_log_lvl = MSG_ERROR; -#endif - -module_param(rmnet_msg_lvl , uint, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(rmnet_msg_lvl, "dbg lvl"); -module_param(rmnet_ipc_log_lvl, uint, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(rmnet_ipc_log_lvl, "dbg lvl"); - -unsigned int mru = MHI_DEFAULT_MRU; -module_param(mru, uint, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(mru, "MRU interface setting"); - -void *rmnet_ipc_log; - -#define rmnet_log(_msg_lvl, _msg, ...) do { \ - if ((_msg_lvl) >= rmnet_msg_lvl) \ +#define rmnet_log(rmnet_mhi_ptr, _msg_lvl, _msg, ...) do { \ + if ((_msg_lvl) >= rmnet_mhi_ptr->debug.rmnet_msg_lvl) \ pr_alert("[%s] " _msg, __func__, ##__VA_ARGS__);\ - if (rmnet_ipc_log && ((_msg_lvl) >= rmnet_ipc_log_lvl)) \ - ipc_log_string(rmnet_ipc_log, \ + if (rmnet_mhi_ptr->rmnet_ipc_log && \ + ((_msg_lvl) >= rmnet_mhi_ptr->debug.rmnet_ipc_log_lvl)) \ + ipc_log_string(rmnet_mhi_ptr->rmnet_ipc_log, \ "[%s] " _msg, __func__, ##__VA_ARGS__); \ } while (0) -unsigned long tx_interrupts_count[MHI_RMNET_DEVICE_COUNT]; -module_param_array(tx_interrupts_count, ulong, 0, S_IRUGO); -MODULE_PARM_DESC(tx_interrupts_count, "Tx interrupts"); - -unsigned long rx_interrupts_count[MHI_RMNET_DEVICE_COUNT]; -module_param_array(rx_interrupts_count, ulong, 0, S_IRUGO); -MODULE_PARM_DESC(rx_interrupts_count, "RX interrupts"); - -unsigned long tx_ring_full_count[MHI_RMNET_DEVICE_COUNT]; -module_param_array(tx_ring_full_count, ulong, 0, S_IRUGO); -MODULE_PARM_DESC(tx_ring_full_count, "RING FULL errors from MHI Core"); - - -unsigned long tx_queued_packets_count[MHI_RMNET_DEVICE_COUNT]; -module_param_array(tx_queued_packets_count, ulong, 0, S_IRUGO); -MODULE_PARM_DESC(tx_queued_packets_count, "TX packets queued in MHI core"); - -unsigned long rx_interrupts_in_masked_irq[MHI_RMNET_DEVICE_COUNT]; -module_param_array(rx_interrupts_in_masked_irq, ulong, 0, S_IRUGO); -MODULE_PARM_DESC(rx_interrupts_in_masked_irq, - "RX interrupts while IRQs are masked"); - -unsigned long rx_napi_skb_burst_min[MHI_RMNET_DEVICE_COUNT]; -module_param_array(rx_napi_skb_burst_min, ulong, 0, S_IRUGO); -MODULE_PARM_DESC(rx_napi_skb_burst_min, "MIN SKBs sent to NS during NAPI"); - -unsigned long rx_napi_skb_burst_max[MHI_RMNET_DEVICE_COUNT]; -module_param_array(rx_napi_skb_burst_max, ulong, 0, S_IRUGO); -MODULE_PARM_DESC(rx_napi_skb_burst_max, "MAX SKBs sent to NS during NAPI"); - -unsigned long tx_cb_skb_free_burst_min[MHI_RMNET_DEVICE_COUNT]; -module_param_array(tx_cb_skb_free_burst_min, ulong, 0, S_IRUGO); -MODULE_PARM_DESC(tx_cb_skb_free_burst_min, "MIN SKBs freed during TX CB"); - -unsigned long tx_cb_skb_free_burst_max[MHI_RMNET_DEVICE_COUNT]; -module_param_array(tx_cb_skb_free_burst_max, ulong, 0, S_IRUGO); -MODULE_PARM_DESC(tx_cb_skb_free_burst_max, "MAX SKBs freed during TX CB"); - -unsigned long rx_napi_budget_overflow[MHI_RMNET_DEVICE_COUNT]; -module_param_array(rx_napi_budget_overflow, ulong, 0, S_IRUGO); -MODULE_PARM_DESC(rx_napi_budget_overflow, - "Budget hit with more items to read counter"); - -unsigned long rx_fragmentation[MHI_RMNET_DEVICE_COUNT]; -module_param_array(rx_fragmentation, ulong, 0, S_IRUGO); -MODULE_PARM_DESC(rx_fragmentation, - "Number of fragmented packets received"); - struct rmnet_mhi_private { - int dev_index; + struct list_head node; struct mhi_client_handle *tx_client_handle; struct mhi_client_handle *rx_client_handle; enum MHI_CLIENT_CHANNEL tx_channel; @@ -138,7 +86,7 @@ struct rmnet_mhi_private { struct sk_buff_head tx_buffers; struct sk_buff_head rx_buffers; atomic_t rx_pool_len; - uint32_t mru; + u32 mru; struct napi_struct napi; gfp_t allocation_flags; uint32_t tx_buffers_max; @@ -147,6 +95,7 @@ struct rmnet_mhi_private { u32 tx_enabled; u32 rx_enabled; u32 mhi_enabled; + struct platform_device *pdev; struct net_device *dev; atomic_t irq_masked_cntr; spinlock_t out_chan_full_lock; /* tx queue lock */ @@ -155,9 +104,12 @@ struct rmnet_mhi_private { struct work_struct alloc_work; /* lock to queue hardware and internal queue */ spinlock_t alloc_lock; + void *rmnet_ipc_log; + struct debug_params debug; + struct dentry *dentry; }; -static struct rmnet_mhi_private rmnet_mhi_ctxt_list[MHI_RMNET_DEVICE_COUNT]; +static LIST_HEAD(rmnet_mhi_ctxt_list); static int rmnet_mhi_process_fragment(struct rmnet_mhi_private *rmnet_mhi_ptr, struct sk_buff *skb, int frag) @@ -189,7 +141,7 @@ static int rmnet_mhi_process_fragment(struct rmnet_mhi_private *rmnet_mhi_ptr, if (frag) { /* This is the first fragment */ rmnet_mhi_ptr->frag_skb = skb; - rx_fragmentation[rmnet_mhi_ptr->dev_index]++; + rmnet_mhi_ptr->debug.rx_fragmentation++; } else { netif_receive_skb(skb); } @@ -201,8 +153,10 @@ static void rmnet_mhi_internal_clean_unmap_buffers(struct net_device *dev, enum dma_data_direction dir) { struct mhi_skb_priv *skb_priv; + struct rmnet_mhi_private *rmnet_mhi_ptr = + *(struct rmnet_mhi_private **)netdev_priv(dev); - rmnet_log(MSG_INFO, "Entered\n"); + rmnet_log(rmnet_mhi_ptr, MSG_INFO, "Entered\n"); while (!skb_queue_empty(queue)) { struct sk_buff *skb = skb_dequeue(queue); skb_priv = (struct mhi_skb_priv *)(skb->cb); @@ -210,7 +164,7 @@ static void rmnet_mhi_internal_clean_unmap_buffers(struct net_device *dev, kfree_skb(skb); } } - rmnet_log(MSG_INFO, "Exited\n"); + rmnet_log(rmnet_mhi_ptr, MSG_INFO, "Exited\n"); } static __be16 rmnet_mhi_ip_type_trans(struct sk_buff *skb) @@ -246,7 +200,8 @@ static int rmnet_alloc_rx(struct rmnet_mhi_private *rmnet_mhi_ptr, rmnet_mhi_ptr->rx_buffers_max) { skb = alloc_skb(cur_mru, alloc_flags); if (!skb) { - rmnet_log(MSG_INFO, + rmnet_log(rmnet_mhi_ptr, + MSG_INFO, "SKB Alloc failed with flags:0x%x\n", alloc_flags); return -ENOMEM; @@ -278,7 +233,8 @@ static int rmnet_alloc_rx(struct rmnet_mhi_private *rmnet_mhi_ptr, skb_priv->dma_size, MHI_EOT); if (unlikely(ret != 0)) { - rmnet_log(MSG_CRITICAL, + rmnet_log(rmnet_mhi_ptr, + MSG_CRITICAL, "mhi_queue_xfer failed, error %d", ret); spin_unlock_irqrestore(&rmnet_mhi_ptr->alloc_lock, flags); @@ -300,11 +256,12 @@ static void rmnet_mhi_alloc_work(struct work_struct *work) alloc_work); int ret; - rmnet_log(MSG_INFO, "Entered\n"); + rmnet_log(rmnet_mhi_ptr, MSG_INFO, "Entered\n"); ret = rmnet_alloc_rx(rmnet_mhi_ptr, rmnet_mhi_ptr->allocation_flags); + WARN_ON(ret == -ENOMEM); - rmnet_log(MSG_INFO, "Exit\n"); + rmnet_log(rmnet_mhi_ptr, MSG_INFO, "Exit\n"); } static int rmnet_mhi_poll(struct napi_struct *napi, int budget) @@ -319,18 +276,20 @@ static int rmnet_mhi_poll(struct napi_struct *napi, int budget) struct mhi_skb_priv *skb_priv; int r; - rmnet_log(MSG_VERBOSE, "Entered\n"); - rmnet_mhi_ptr->mru = mru; + rmnet_log(rmnet_mhi_ptr, MSG_VERBOSE, "Entered\n"); + while (received_packets < budget) { struct mhi_result *result = mhi_poll(rmnet_mhi_ptr->rx_client_handle); if (result->transaction_status == -ENOTCONN) { - rmnet_log(MSG_INFO, + rmnet_log(rmnet_mhi_ptr, + MSG_INFO, "Transaction status not ready, continuing\n"); break; } else if (result->transaction_status != 0 && result->transaction_status != -EOVERFLOW) { - rmnet_log(MSG_CRITICAL, + rmnet_log(rmnet_mhi_ptr, + MSG_CRITICAL, "mhi_poll failed, error %d\n", result->transaction_status); break; @@ -345,7 +304,8 @@ static int rmnet_mhi_poll(struct napi_struct *napi, int budget) atomic_dec(&rmnet_mhi_ptr->rx_pool_len); skb = skb_dequeue(&(rmnet_mhi_ptr->rx_buffers)); if (unlikely(!skb)) { - rmnet_log(MSG_CRITICAL, + rmnet_log(rmnet_mhi_ptr, + MSG_CRITICAL, "No RX buffers to match"); break; } @@ -363,7 +323,7 @@ static int rmnet_mhi_poll(struct napi_struct *napi, int budget) else r = rmnet_mhi_process_fragment(rmnet_mhi_ptr, skb, 0); if (r) { - rmnet_log(MSG_CRITICAL, + rmnet_log(rmnet_mhi_ptr, MSG_CRITICAL, "Failed to process fragmented packet ret %d", r); BUG(); @@ -379,7 +339,9 @@ static int rmnet_mhi_poll(struct napi_struct *napi, int budget) /* Queue new buffers */ res = rmnet_alloc_rx(rmnet_mhi_ptr, GFP_ATOMIC); if (res == -ENOMEM) { - rmnet_log(MSG_INFO, "out of mem, queuing bg worker\n"); + rmnet_log(rmnet_mhi_ptr, + MSG_INFO, + "out of mem, queuing bg worker\n"); rmnet_mhi_ptr->alloc_fail++; schedule_work(&rmnet_mhi_ptr->alloc_work); } @@ -391,22 +353,24 @@ static int rmnet_mhi_poll(struct napi_struct *napi, int budget) if (atomic_read(&rmnet_mhi_ptr->irq_masked_cntr)) { atomic_dec(&rmnet_mhi_ptr->irq_masked_cntr); mhi_unmask_irq(rmnet_mhi_ptr->rx_client_handle); + mhi_set_lpm(rmnet_mhi_ptr->rx_client_handle, true); } } else { if (received_packets == budget) - rx_napi_budget_overflow[rmnet_mhi_ptr->dev_index]++; + rmnet_mhi_ptr->debug.rx_napi_budget_overflow++; napi_reschedule(napi); } - rx_napi_skb_burst_min[rmnet_mhi_ptr->dev_index] = - min((unsigned long)received_packets, - rx_napi_skb_burst_min[rmnet_mhi_ptr->dev_index]); + rmnet_mhi_ptr->debug.rx_napi_skb_burst_min = + min((u64)received_packets, + rmnet_mhi_ptr->debug.rx_napi_skb_burst_min); - rx_napi_skb_burst_max[rmnet_mhi_ptr->dev_index] = - max((unsigned long)received_packets, - rx_napi_skb_burst_max[rmnet_mhi_ptr->dev_index]); + rmnet_mhi_ptr->debug.rx_napi_skb_burst_max = + max((u64)received_packets, + rmnet_mhi_ptr->debug.rx_napi_skb_burst_max); - rmnet_log(MSG_VERBOSE, "Exited, polled %d pkts\n", received_packets); + rmnet_log(rmnet_mhi_ptr, MSG_VERBOSE, + "Exited, polled %d pkts\n", received_packets); return received_packets; } @@ -414,7 +378,8 @@ void rmnet_mhi_clean_buffers(struct net_device *dev) { struct rmnet_mhi_private *rmnet_mhi_ptr = *(struct rmnet_mhi_private **)netdev_priv(dev); - rmnet_log(MSG_INFO, "Entered\n"); + + rmnet_log(rmnet_mhi_ptr, MSG_INFO, "Entered\n"); /* Clean TX buffers */ rmnet_mhi_internal_clean_unmap_buffers(dev, &rmnet_mhi_ptr->tx_buffers, @@ -424,16 +389,16 @@ void rmnet_mhi_clean_buffers(struct net_device *dev) rmnet_mhi_internal_clean_unmap_buffers(dev, &rmnet_mhi_ptr->rx_buffers, DMA_FROM_DEVICE); - rmnet_log(MSG_INFO, "Exited\n"); + rmnet_log(rmnet_mhi_ptr, MSG_INFO, "Exited\n"); } static int rmnet_mhi_disable_channels(struct rmnet_mhi_private *rmnet_mhi_ptr) { - rmnet_log(MSG_INFO, "Closing MHI TX channel\n"); + rmnet_log(rmnet_mhi_ptr, MSG_INFO, "Closing MHI TX channel\n"); mhi_close_channel(rmnet_mhi_ptr->tx_client_handle); - rmnet_log(MSG_INFO, "Closing MHI RX channel\n"); + rmnet_log(rmnet_mhi_ptr, MSG_INFO, "Closing MHI RX channel\n"); mhi_close_channel(rmnet_mhi_ptr->rx_client_handle); - rmnet_log(MSG_INFO, "Clearing Pending TX buffers.\n"); + rmnet_log(rmnet_mhi_ptr, MSG_INFO, "Clearing Pending TX buffers.\n"); rmnet_mhi_clean_buffers(rmnet_mhi_ptr->dev); rmnet_mhi_ptr->tx_client_handle = NULL; rmnet_mhi_ptr->rx_client_handle = NULL; @@ -445,7 +410,7 @@ static int rmnet_mhi_init_inbound(struct rmnet_mhi_private *rmnet_mhi_ptr) { int res; - rmnet_log(MSG_INFO, "Entered\n"); + rmnet_log(rmnet_mhi_ptr, MSG_INFO, "Entered\n"); rmnet_mhi_ptr->tx_buffers_max = mhi_get_max_desc( rmnet_mhi_ptr->tx_client_handle); rmnet_mhi_ptr->rx_buffers_max = mhi_get_max_desc( @@ -454,7 +419,7 @@ static int rmnet_mhi_init_inbound(struct rmnet_mhi_private *rmnet_mhi_ptr) res = rmnet_alloc_rx(rmnet_mhi_ptr, rmnet_mhi_ptr->allocation_flags); - rmnet_log(MSG_INFO, "Exited with %d\n", res); + rmnet_log(rmnet_mhi_ptr, MSG_INFO, "Exited with %d\n", res); return res; } @@ -467,9 +432,9 @@ static void rmnet_mhi_tx_cb(struct mhi_result *result) rmnet_mhi_ptr = result->user_data; dev = rmnet_mhi_ptr->dev; - tx_interrupts_count[rmnet_mhi_ptr->dev_index]++; + rmnet_mhi_ptr->debug.tx_interrupts_count++; - rmnet_log(MSG_VERBOSE, "Entered\n"); + rmnet_log(rmnet_mhi_ptr, MSG_VERBOSE, "Entered\n"); if (!result->buf_addr || !result->bytes_xferd) return; /* Free the buffers which are TX'd up to the provided address */ @@ -477,7 +442,8 @@ static void rmnet_mhi_tx_cb(struct mhi_result *result) struct sk_buff *skb = skb_dequeue(&(rmnet_mhi_ptr->tx_buffers)); if (!skb) { - rmnet_log(MSG_CRITICAL, + rmnet_log(rmnet_mhi_ptr, + MSG_CRITICAL, "NULL buffer returned, error"); break; } else { @@ -498,20 +464,21 @@ static void rmnet_mhi_tx_cb(struct mhi_result *result) */ } } /* While TX queue is not empty */ - tx_cb_skb_free_burst_min[rmnet_mhi_ptr->dev_index] = - min(burst_counter, - tx_cb_skb_free_burst_min[rmnet_mhi_ptr->dev_index]); - tx_cb_skb_free_burst_max[rmnet_mhi_ptr->dev_index] = - max(burst_counter, - tx_cb_skb_free_burst_max[rmnet_mhi_ptr->dev_index]); + rmnet_mhi_ptr->debug.tx_cb_skb_free_burst_min = + min((u64)burst_counter, + rmnet_mhi_ptr->debug.tx_cb_skb_free_burst_min); + + rmnet_mhi_ptr->debug.tx_cb_skb_free_burst_max = + max((u64)burst_counter, + rmnet_mhi_ptr->debug.tx_cb_skb_free_burst_max); /* In case we couldn't write again, now we can! */ spin_lock_irqsave(&rmnet_mhi_ptr->out_chan_full_lock, flags); - rmnet_log(MSG_VERBOSE, "Waking up queue\n"); + rmnet_log(rmnet_mhi_ptr, MSG_VERBOSE, "Waking up queue\n"); netif_wake_queue(dev); spin_unlock_irqrestore(&rmnet_mhi_ptr->out_chan_full_lock, flags); - rmnet_log(MSG_VERBOSE, "Exited\n"); + rmnet_log(rmnet_mhi_ptr, MSG_VERBOSE, "Exited\n"); } static void rmnet_mhi_rx_cb(struct mhi_result *result) @@ -521,17 +488,18 @@ static void rmnet_mhi_rx_cb(struct mhi_result *result) rmnet_mhi_ptr = result->user_data; dev = rmnet_mhi_ptr->dev; - rmnet_log(MSG_VERBOSE, "Entered\n"); - rx_interrupts_count[rmnet_mhi_ptr->dev_index]++; + rmnet_log(rmnet_mhi_ptr, MSG_VERBOSE, "Entered\n"); + rmnet_mhi_ptr->debug.rx_interrupts_count++; if (napi_schedule_prep(&(rmnet_mhi_ptr->napi))) { mhi_mask_irq(rmnet_mhi_ptr->rx_client_handle); atomic_inc(&rmnet_mhi_ptr->irq_masked_cntr); + mhi_set_lpm(rmnet_mhi_ptr->rx_client_handle, false); __napi_schedule(&(rmnet_mhi_ptr->napi)); } else { - rx_interrupts_in_masked_irq[rmnet_mhi_ptr->dev_index]++; + rmnet_mhi_ptr->debug.rx_interrupts_in_masked_irq++; } - rmnet_log(MSG_VERBOSE, "Exited\n"); + rmnet_log(rmnet_mhi_ptr, MSG_VERBOSE, "Exited\n"); } static int rmnet_mhi_open(struct net_device *dev) @@ -539,11 +507,19 @@ static int rmnet_mhi_open(struct net_device *dev) struct rmnet_mhi_private *rmnet_mhi_ptr = *(struct rmnet_mhi_private **)netdev_priv(dev); - rmnet_log(MSG_INFO, - "Opened net dev interface for MHI chans %d and %d\n", - rmnet_mhi_ptr->tx_channel, - rmnet_mhi_ptr->rx_channel); - netif_start_queue(dev); + rmnet_log(rmnet_mhi_ptr, + MSG_INFO, + "Opened net dev interface for MHI chans %d and %d\n", + rmnet_mhi_ptr->tx_channel, + rmnet_mhi_ptr->rx_channel); + + /* tx queue may not necessarily be stopped already + * so stop the queue if tx path is not enabled + */ + if (!rmnet_mhi_ptr->tx_client_handle) + netif_stop_queue(dev); + else + netif_start_queue(dev); /* Poll to check if any buffers are accumulated in the * transport buffers @@ -551,9 +527,10 @@ static int rmnet_mhi_open(struct net_device *dev) if (napi_schedule_prep(&(rmnet_mhi_ptr->napi))) { mhi_mask_irq(rmnet_mhi_ptr->rx_client_handle); atomic_inc(&rmnet_mhi_ptr->irq_masked_cntr); + mhi_set_lpm(rmnet_mhi_ptr->rx_client_handle, false); __napi_schedule(&(rmnet_mhi_ptr->napi)); } else { - rx_interrupts_in_masked_irq[rmnet_mhi_ptr->dev_index]++; + rmnet_mhi_ptr->debug.rx_interrupts_in_masked_irq++; } return 0; @@ -591,14 +568,17 @@ static int rmnet_mhi_stop(struct net_device *dev) { struct rmnet_mhi_private *rmnet_mhi_ptr = *(struct rmnet_mhi_private **)netdev_priv(dev); + netif_stop_queue(dev); - rmnet_log(MSG_VERBOSE, "Entered\n"); + rmnet_log(rmnet_mhi_ptr, MSG_VERBOSE, "Entered\n"); if (atomic_read(&rmnet_mhi_ptr->irq_masked_cntr)) { mhi_unmask_irq(rmnet_mhi_ptr->rx_client_handle); atomic_dec(&rmnet_mhi_ptr->irq_masked_cntr); - rmnet_log(MSG_ERROR, "IRQ was masked, unmasking...\n"); + rmnet_log(rmnet_mhi_ptr, + MSG_ERROR, + "IRQ was masked, unmasking...\n"); } - rmnet_log(MSG_VERBOSE, "Exited\n"); + rmnet_log(rmnet_mhi_ptr, MSG_VERBOSE, "Exited\n"); return 0; } @@ -619,17 +599,22 @@ static int rmnet_mhi_xmit(struct sk_buff *skb, struct net_device *dev) unsigned long flags; struct mhi_skb_priv *tx_priv; - rmnet_log(MSG_VERBOSE, "Entered chan %d\n", rmnet_mhi_ptr->tx_channel); + rmnet_log(rmnet_mhi_ptr, + MSG_VERBOSE, + "Entered chan %d\n", + rmnet_mhi_ptr->tx_channel); tx_priv = (struct mhi_skb_priv *)(skb->cb); tx_priv->dma_size = skb->len; tx_priv->dma_addr = 0; if (mhi_get_free_desc(rmnet_mhi_ptr->tx_client_handle) <= 0) { - rmnet_log(MSG_VERBOSE, "Stopping Queue\n"); + rmnet_log(rmnet_mhi_ptr, + MSG_VERBOSE, + "Stopping Queue\n"); spin_lock_irqsave(&rmnet_mhi_ptr->out_chan_full_lock, flags); - tx_ring_full_count[rmnet_mhi_ptr->dev_index]++; + rmnet_mhi_ptr->debug.tx_ring_full_count++; netif_stop_queue(dev); spin_unlock_irqrestore(&rmnet_mhi_ptr->out_chan_full_lock, flags); @@ -641,7 +626,9 @@ static int rmnet_mhi_xmit(struct sk_buff *skb, struct net_device *dev) MHI_EOT); if (res != 0) { - rmnet_log(MSG_CRITICAL, "Failed to queue with reason:%d\n", + rmnet_log(rmnet_mhi_ptr, + MSG_CRITICAL, + "Failed to queue with reason:%d\n", res); spin_lock_irqsave(&rmnet_mhi_ptr->out_chan_full_lock, flags); @@ -652,12 +639,10 @@ static int rmnet_mhi_xmit(struct sk_buff *skb, struct net_device *dev) } skb_queue_tail(&(rmnet_mhi_ptr->tx_buffers), skb); - dev->trans_start = jiffies; + rmnet_mhi_ptr->debug.tx_queued_packets_count++; - tx_queued_packets_count[rmnet_mhi_ptr->dev_index]++; - rmnet_log(MSG_VERBOSE, "Exited\n"); - + rmnet_log(rmnet_mhi_ptr, MSG_VERBOSE, "Exited\n"); return NETDEV_TX_OK; } @@ -673,24 +658,27 @@ static int rmnet_mhi_ioctl_extended(struct net_device *dev, struct ifreq *ifr) sizeof(struct rmnet_ioctl_extended_s)); if (rc) { - rmnet_log(MSG_CRITICAL, - "copy_from_user failed ,error %d", rc); + rmnet_log(rmnet_mhi_ptr, + MSG_CRITICAL, + "copy_from_user failed ,error %d", + rc); return rc; } switch (ext_cmd.extended_ioctl) { case RMNET_IOCTL_SET_MRU: - if ((0 > ext_cmd.u.data) || (ext_cmd.u.data > MHI_MAX_MRU)) { - rmnet_log(MSG_CRITICAL, - "Can't set MRU, value %u is invalid\n", - ext_cmd.u.data); + if (!ext_cmd.u.data || ext_cmd.u.data > MHI_MAX_MRU) { + rmnet_log(rmnet_mhi_ptr, + MSG_CRITICAL, + "Can't set MRU, value %u is invalid\n", + ext_cmd.u.data); return -EINVAL; } - rmnet_log(MSG_INFO, - "MRU change request to 0x%x\n", - ext_cmd.u.data); - mru = ext_cmd.u.data; - rmnet_mhi_ptr->mru = mru; + rmnet_log(rmnet_mhi_ptr, + MSG_INFO, + "MRU change request to 0x%x\n", + ext_cmd.u.data); + rmnet_mhi_ptr->mru = ext_cmd.u.data; break; case RMNET_IOCTL_GET_EPID: ext_cmd.u.data = @@ -709,7 +697,8 @@ static int rmnet_mhi_ioctl_extended(struct net_device *dev, struct ifreq *ifr) mhi_set_lpm(rmnet_mhi_ptr->tx_client_handle, ext_cmd.u.data); } else { - rmnet_log(MSG_ERROR, + rmnet_log(rmnet_mhi_ptr, + MSG_ERROR, "Cannot set LPM value, MHI is not up.\n"); return -ENODEV; } @@ -723,9 +712,10 @@ static int rmnet_mhi_ioctl_extended(struct net_device *dev, struct ifreq *ifr) sizeof(struct rmnet_ioctl_extended_s)); if (rc) - rmnet_log(MSG_CRITICAL, - "copy_to_user failed, error %d\n", - rc); + rmnet_log(rmnet_mhi_ptr, + MSG_CRITICAL, + "copy_to_user failed, error %d\n", + rc); return rc; } @@ -804,50 +794,49 @@ static int rmnet_mhi_enable_iface(struct rmnet_mhi_private *rmnet_mhi_ptr) struct rmnet_mhi_private **rmnet_mhi_ctxt = NULL; int r = 0; - memset(tx_interrupts_count, 0, sizeof(tx_interrupts_count)); - memset(rx_interrupts_count, 0, sizeof(rx_interrupts_count)); - memset(rx_interrupts_in_masked_irq, 0, - sizeof(rx_interrupts_in_masked_irq)); - memset(rx_napi_skb_burst_min, 0, sizeof(rx_napi_skb_burst_min)); - memset(rx_napi_skb_burst_max, 0, sizeof(rx_napi_skb_burst_max)); - memset(tx_cb_skb_free_burst_min, 0, sizeof(tx_cb_skb_free_burst_min)); - memset(tx_cb_skb_free_burst_max, 0, sizeof(tx_cb_skb_free_burst_max)); - memset(tx_ring_full_count, 0, sizeof(tx_ring_full_count)); - memset(tx_queued_packets_count, 0, sizeof(tx_queued_packets_count)); - memset(rx_napi_budget_overflow, 0, sizeof(rx_napi_budget_overflow)); - - rmnet_log(MSG_INFO, "Entered.\n"); - - if (rmnet_mhi_ptr == NULL) { - rmnet_log(MSG_CRITICAL, "Bad input args.\n"); - return -EINVAL; - } - - rx_napi_skb_burst_min[rmnet_mhi_ptr->dev_index] = UINT_MAX; - tx_cb_skb_free_burst_min[rmnet_mhi_ptr->dev_index] = UINT_MAX; + rmnet_log(rmnet_mhi_ptr, MSG_INFO, "Entered.\n"); + + rmnet_mhi_ptr->debug.tx_interrupts_count = 0; + rmnet_mhi_ptr->debug.rx_interrupts_count = 0; + rmnet_mhi_ptr->debug.rx_interrupts_in_masked_irq = 0; + rmnet_mhi_ptr->debug.rx_napi_skb_burst_min = 0; + rmnet_mhi_ptr->debug.rx_napi_skb_burst_max = 0; + rmnet_mhi_ptr->debug.tx_cb_skb_free_burst_min = 0; + rmnet_mhi_ptr->debug.tx_cb_skb_free_burst_max = 0; + rmnet_mhi_ptr->debug.tx_ring_full_count = 0; + rmnet_mhi_ptr->debug.tx_queued_packets_count = 0; + rmnet_mhi_ptr->debug.rx_napi_budget_overflow = 0; + rmnet_mhi_ptr->debug.rx_napi_skb_burst_min = UINT_MAX; + rmnet_mhi_ptr->debug.tx_cb_skb_free_burst_min = UINT_MAX; skb_queue_head_init(&(rmnet_mhi_ptr->tx_buffers)); skb_queue_head_init(&(rmnet_mhi_ptr->rx_buffers)); if (rmnet_mhi_ptr->tx_client_handle != NULL) { - rmnet_log(MSG_INFO, - "Opening TX channel\n"); + rmnet_log(rmnet_mhi_ptr, + MSG_INFO, + "Opening TX channel\n"); r = mhi_open_channel(rmnet_mhi_ptr->tx_client_handle); if (r != 0) { - rmnet_log(MSG_CRITICAL, - "Failed to start TX chan ret %d\n", r); + rmnet_log(rmnet_mhi_ptr, + MSG_CRITICAL, + "Failed to start TX chan ret %d\n", + r); goto mhi_tx_chan_start_fail; } else { rmnet_mhi_ptr->tx_enabled = 1; } } if (rmnet_mhi_ptr->rx_client_handle != NULL) { - rmnet_log(MSG_INFO, - "Opening RX channel\n"); + rmnet_log(rmnet_mhi_ptr, + MSG_INFO, + "Opening RX channel\n"); r = mhi_open_channel(rmnet_mhi_ptr->rx_client_handle); if (r != 0) { - rmnet_log(MSG_CRITICAL, - "Failed to start RX chan ret %d\n", r); + rmnet_log(rmnet_mhi_ptr, + MSG_CRITICAL, + "Failed to start RX chan ret %d\n", + r); goto mhi_rx_chan_start_fail; } else { rmnet_mhi_ptr->rx_enabled = 1; @@ -858,11 +847,13 @@ static int rmnet_mhi_enable_iface(struct rmnet_mhi_private *rmnet_mhi_ptr) RMNET_MHI_DEV_NAME, NET_NAME_PREDICTABLE, rmnet_mhi_setup); if (!rmnet_mhi_ptr->dev) { - rmnet_log(MSG_CRITICAL, "Network device allocation failed\n"); + rmnet_log(rmnet_mhi_ptr, + MSG_CRITICAL, + "Network device allocation failed\n"); ret = -ENOMEM; goto net_dev_alloc_fail; } - + SET_NETDEV_DEV(rmnet_mhi_ptr->dev, &rmnet_mhi_ptr->pdev->dev); rmnet_mhi_ctxt = netdev_priv(rmnet_mhi_ptr->dev); *rmnet_mhi_ctxt = rmnet_mhi_ptr; @@ -875,8 +866,10 @@ static int rmnet_mhi_enable_iface(struct rmnet_mhi_private *rmnet_mhi_ptr) r = rmnet_mhi_init_inbound(rmnet_mhi_ptr); if (r) { - rmnet_log(MSG_CRITICAL, - "Failed to init inbound ret %d\n", r); + rmnet_log(rmnet_mhi_ptr, + MSG_CRITICAL, + "Failed to init inbound ret %d\n", + r); } netif_napi_add(rmnet_mhi_ptr->dev, &(rmnet_mhi_ptr->napi), @@ -885,13 +878,14 @@ static int rmnet_mhi_enable_iface(struct rmnet_mhi_private *rmnet_mhi_ptr) rmnet_mhi_ptr->mhi_enabled = 1; ret = register_netdev(rmnet_mhi_ptr->dev); if (ret) { - rmnet_log(MSG_CRITICAL, + rmnet_log(rmnet_mhi_ptr, + MSG_CRITICAL, "Network device registration failed\n"); goto net_dev_reg_fail; } napi_enable(&(rmnet_mhi_ptr->napi)); - rmnet_log(MSG_INFO, "Exited.\n"); + rmnet_log(rmnet_mhi_ptr, MSG_INFO, "Exited.\n"); return 0; @@ -904,7 +898,7 @@ net_dev_alloc_fail: mhi_rx_chan_start_fail: mhi_close_channel(rmnet_mhi_ptr->tx_client_handle); mhi_tx_chan_start_fail: - rmnet_log(MSG_INFO, "Exited ret %d.\n", ret); + rmnet_log(rmnet_mhi_ptr, MSG_INFO, "Exited ret %d.\n", ret); return ret; } @@ -914,52 +908,60 @@ static void rmnet_mhi_cb(struct mhi_cb_info *cb_info) struct mhi_result *result; int r = 0; - if (NULL != cb_info && NULL != cb_info->result) { - result = cb_info->result; - rmnet_mhi_ptr = result->user_data; - } else { - rmnet_log(MSG_CRITICAL, - "Invalid data in MHI callback, quitting\n"); + if (!cb_info || !cb_info->result) { + pr_err("%s: Invalid data in MHI callback\n", __func__); return; } + result = cb_info->result; + rmnet_mhi_ptr = result->user_data; + switch (cb_info->cb_reason) { case MHI_CB_MHI_DISABLED: - rmnet_log(MSG_CRITICAL, - "Got MHI_DISABLED notification. Stopping stack\n"); + rmnet_log(rmnet_mhi_ptr, + MSG_CRITICAL, + "Got MHI_DISABLED notification. Stopping stack\n"); if (rmnet_mhi_ptr->mhi_enabled) { rmnet_mhi_ptr->mhi_enabled = 0; /* Ensure MHI is disabled before other mem ops */ wmb(); while (atomic_read(&rmnet_mhi_ptr->pending_data)) { - rmnet_log(MSG_CRITICAL, - "Waiting for channels to stop.\n"); + rmnet_log(rmnet_mhi_ptr, + MSG_CRITICAL, + "Waiting for channels to stop.\n"); msleep(25); } rmnet_mhi_disable(rmnet_mhi_ptr); } break; case MHI_CB_MHI_ENABLED: - rmnet_log(MSG_CRITICAL, - "Got MHI_ENABLED notification. Starting stack\n"); - if (IS_INBOUND(cb_info->chan)) + rmnet_log(rmnet_mhi_ptr, + MSG_CRITICAL, + "Got MHI_ENABLED notification. Starting stack\n"); + if (cb_info->chan == rmnet_mhi_ptr->rx_channel) rmnet_mhi_ptr->rx_enabled = 1; else rmnet_mhi_ptr->tx_enabled = 1; - if (rmnet_mhi_ptr->tx_enabled && - rmnet_mhi_ptr->rx_enabled) { - rmnet_log(MSG_INFO, - "Both RX/TX are enabled, enabling iface.\n"); + if ((rmnet_mhi_ptr->tx_enabled && rmnet_mhi_ptr->rx_enabled) || + (rmnet_mhi_ptr->tx_enabled && + !rmnet_mhi_ptr->rx_client_handle) || + (rmnet_mhi_ptr->rx_enabled && + !rmnet_mhi_ptr->tx_client_handle)) { + rmnet_log(rmnet_mhi_ptr, + MSG_INFO, + "enabling iface.\n"); r = rmnet_mhi_enable_iface(rmnet_mhi_ptr); if (r) - rmnet_log(MSG_CRITICAL, - "Failed to enable iface for chan %d\n", - cb_info->chan); + rmnet_log(rmnet_mhi_ptr, + MSG_CRITICAL, + "Failed to enable iface for chan %d\n", + cb_info->chan); else - rmnet_log(MSG_INFO, - "Enabled iface for chan %d\n", - cb_info->chan); + rmnet_log(rmnet_mhi_ptr, + MSG_INFO, + "Enabled iface for chan %d\n", + cb_info->chan); } break; case MHI_CB_XFER: @@ -967,7 +969,7 @@ static void rmnet_mhi_cb(struct mhi_cb_info *cb_info) /* Flush pending data is set before any other mem operations */ wmb(); if (rmnet_mhi_ptr->mhi_enabled) { - if (IS_INBOUND(cb_info->chan)) + if (cb_info->chan == rmnet_mhi_ptr->rx_channel) rmnet_mhi_rx_cb(cb_info->result); else rmnet_mhi_tx_cb(cb_info->result); @@ -981,67 +983,261 @@ static void rmnet_mhi_cb(struct mhi_cb_info *cb_info) static struct mhi_client_info_t rmnet_mhi_info = {rmnet_mhi_cb}; -static int __init rmnet_mhi_init(void) +#ifdef CONFIG_DEBUG_FS +struct dentry *dentry; + +static void rmnet_mhi_create_debugfs(struct rmnet_mhi_private *rmnet_mhi_ptr) { + char node_name[15]; int i; - int res = 0; - struct rmnet_mhi_private *rmnet_mhi_ptr = 0; - rmnet_ipc_log = ipc_log_context_create(RMNET_IPC_LOG_PAGES, - "mhi_rmnet", 0); - - for (i = 0; i < MHI_RMNET_DEVICE_COUNT; i++) { - rmnet_mhi_ptr = &rmnet_mhi_ctxt_list[i]; - - rmnet_mhi_ptr->tx_channel = MHI_CLIENT_IP_HW_0_OUT + - (enum MHI_CLIENT_CHANNEL)(i * 2); - rmnet_mhi_ptr->rx_channel = MHI_CLIENT_IP_HW_0_IN + - (enum MHI_CLIENT_CHANNEL)((i * 2)); - - rmnet_mhi_ptr->tx_client_handle = 0; - rmnet_mhi_ptr->rx_client_handle = 0; - spin_lock_init(&rmnet_mhi_ptr->out_chan_full_lock); - - rmnet_mhi_ptr->mru = MHI_DEFAULT_MRU; - rmnet_mhi_ptr->dev_index = i; - - res = mhi_register_channel( - &(rmnet_mhi_ptr->tx_client_handle), - rmnet_mhi_ptr->tx_channel, 0, - &rmnet_mhi_info, rmnet_mhi_ptr); - - if (0 != res) { - rmnet_mhi_ptr->tx_client_handle = 0; - rmnet_log(MSG_CRITICAL, - "mhi_register_channel failed chan %d ret %d\n", - rmnet_mhi_ptr->tx_channel, res); + const umode_t mode = (S_IRUSR | S_IWUSR); + struct dentry *file; + + const struct { + char *name; + u64 *ptr; + } debugfs_table[] = { + { + "tx_interrupts_count", + &rmnet_mhi_ptr->debug.tx_interrupts_count + }, + { + "rx_interrupts_count", + &rmnet_mhi_ptr->debug.rx_interrupts_count + }, + { + "tx_ring_full_count", + &rmnet_mhi_ptr->debug.tx_ring_full_count + }, + { + "tx_queued_packets_count", + &rmnet_mhi_ptr->debug.tx_queued_packets_count + }, + { + "rx_interrupts_in_masked_irq", + &rmnet_mhi_ptr-> + debug.rx_interrupts_in_masked_irq + }, + { + "rx_napi_skb_burst_min", + &rmnet_mhi_ptr->debug.rx_napi_skb_burst_min + }, + { + "rx_napi_skb_burst_max", + &rmnet_mhi_ptr->debug.rx_napi_skb_burst_max + }, + { + "tx_cb_skb_free_burst_min", + &rmnet_mhi_ptr->debug.tx_cb_skb_free_burst_min + }, + { + "tx_cb_skb_free_burst_max", + &rmnet_mhi_ptr->debug.tx_cb_skb_free_burst_max + }, + { + "rx_napi_budget_overflow", + &rmnet_mhi_ptr->debug.rx_napi_budget_overflow + }, + { + "rx_fragmentation", + &rmnet_mhi_ptr->debug.rx_fragmentation + }, + { + NULL, NULL + }, + }; + + snprintf(node_name, sizeof(node_name), "%s%d", + RMNET_MHI_DRIVER_NAME, rmnet_mhi_ptr->pdev->id); + + if (IS_ERR_OR_NULL(dentry)) + return; + + rmnet_mhi_ptr->dentry = debugfs_create_dir(node_name, dentry); + if (IS_ERR_OR_NULL(rmnet_mhi_ptr->dentry)) + return; + + file = debugfs_create_u32("msg_lvl", + mode, + rmnet_mhi_ptr->dentry, + (u32 *)&rmnet_mhi_ptr->debug.rmnet_msg_lvl); + if (IS_ERR_OR_NULL(file)) + return; + + file = debugfs_create_u32("ipc_log_lvl", + mode, + rmnet_mhi_ptr->dentry, + (u32 *)&rmnet_mhi_ptr-> + debug.rmnet_ipc_log_lvl); + if (IS_ERR_OR_NULL(file)) + return; + + file = debugfs_create_u32("mru", + mode, + rmnet_mhi_ptr->dentry, + &rmnet_mhi_ptr->mru); + if (IS_ERR_OR_NULL(file)) + return; + + /* Add debug stats table */ + for (i = 0; debugfs_table[i].name; i++) { + file = debugfs_create_u64(debugfs_table[i].name, + mode, + rmnet_mhi_ptr->dentry, + debugfs_table[i].ptr); + if (IS_ERR_OR_NULL(file)) + return; + } +} + +static void rmnet_mhi_create_debugfs_dir(void) +{ + dentry = debugfs_create_dir(RMNET_MHI_DRIVER_NAME, 0); +} +#else +static void rmnet_mhi_create_debugfs(struct rmnet_mhi_private *rmnet_mhi_ptr) +{ +} + +static void rmnet_mhi_create_debugfs_dir(void) +{ +} +#endif + +static int rmnet_mhi_probe(struct platform_device *pdev) +{ + int rc; + u32 channel; + struct rmnet_mhi_private *rmnet_mhi_ptr; + char node_name[15]; + + if (unlikely(!pdev->dev.of_node)) + return -ENODEV; + + pdev->id = of_alias_get_id(pdev->dev.of_node, "mhi_rmnet"); + if (unlikely(pdev->id < 0)) + return -ENODEV; + + rmnet_mhi_ptr = kzalloc(sizeof(*rmnet_mhi_ptr), GFP_KERNEL); + if (unlikely(!rmnet_mhi_ptr)) + return -ENOMEM; + rmnet_mhi_ptr->pdev = pdev; + spin_lock_init(&rmnet_mhi_ptr->out_chan_full_lock); + + rc = of_property_read_u32(pdev->dev.of_node, + "qcom,mhi-mru", + &rmnet_mhi_ptr->mru); + if (unlikely(rc)) { + rmnet_log(rmnet_mhi_ptr, + MSG_CRITICAL, + "failed to get valid mru\n"); + goto probe_fail; + } + + rc = of_property_read_u32(pdev->dev.of_node, + "qcom,mhi-tx-channel", + &channel); + if (rc == 0) { + rmnet_mhi_ptr->tx_channel = channel; + rc = mhi_register_channel(&rmnet_mhi_ptr->tx_client_handle, + rmnet_mhi_ptr->tx_channel, + 0, + &rmnet_mhi_info, + rmnet_mhi_ptr); + if (unlikely(rc)) { + rmnet_log(rmnet_mhi_ptr, + MSG_CRITICAL, + "mhi_register_channel failed chan %d ret %d\n", + rmnet_mhi_ptr->tx_channel, + rc); + goto probe_fail; } - res = mhi_register_channel( - &(rmnet_mhi_ptr->rx_client_handle), - rmnet_mhi_ptr->rx_channel, 0, - &rmnet_mhi_info, rmnet_mhi_ptr); - - if (0 != res) { - rmnet_mhi_ptr->rx_client_handle = 0; - rmnet_log(MSG_CRITICAL, - "mhi_register_channel failed chan %d, ret %d\n", - rmnet_mhi_ptr->rx_channel, res); + } + + rc = of_property_read_u32(pdev->dev.of_node, + "qcom,mhi-rx-channel", + &channel); + if (rc == 0) { + rmnet_mhi_ptr->rx_channel = channel; + rc = mhi_register_channel(&rmnet_mhi_ptr->rx_client_handle, + rmnet_mhi_ptr->rx_channel, + 0, + &rmnet_mhi_info, + rmnet_mhi_ptr); + if (unlikely(rc)) { + rmnet_log(rmnet_mhi_ptr, + MSG_CRITICAL, + "mhi_register_channel failed chan %d ret %d\n", + rmnet_mhi_ptr->rx_channel, + rc); + goto probe_fail; } INIT_WORK(&rmnet_mhi_ptr->alloc_work, rmnet_mhi_alloc_work); spin_lock_init(&rmnet_mhi_ptr->alloc_lock); } + + /* We must've have @ least one valid channel */ + if (!rmnet_mhi_ptr->rx_client_handle && + !rmnet_mhi_ptr->tx_client_handle) { + rmnet_log(rmnet_mhi_ptr, MSG_CRITICAL, + "No registered channels\n"); + rc = -ENODEV; + goto probe_fail; + } + + snprintf(node_name, sizeof(node_name), "%s%d", + RMNET_MHI_DRIVER_NAME, pdev->id); + rmnet_mhi_ptr->rmnet_ipc_log = + ipc_log_context_create(RMNET_IPC_LOG_PAGES, + node_name, 0); + rmnet_mhi_ptr->debug.rmnet_msg_lvl = MSG_CRITICAL; + +#ifdef CONFIG_MSM_MHI_DEBUG + rmnet_mhi_ptr->debug.rmnet_ipc_log_lvl = MSG_VERBOSE; +#else + rmnet_mhi_ptr->debug.rmnet_ipc_log_lvl = MSG_ERROR; +#endif + + rmnet_mhi_create_debugfs(rmnet_mhi_ptr); + list_add_tail(&rmnet_mhi_ptr->node, &rmnet_mhi_ctxt_list); return 0; + +probe_fail: + kfree(rmnet_mhi_ptr); + return rc; +} + +static const struct of_device_id msm_mhi_match_table[] = { + {.compatible = "qcom,mhi-rmnet"}, + {}, +}; + +static struct platform_driver rmnet_mhi_driver = { + .probe = rmnet_mhi_probe, + .driver = { + .name = RMNET_MHI_DRIVER_NAME, + .owner = THIS_MODULE, + .of_match_table = msm_mhi_match_table, + }, +}; + +static int __init rmnet_mhi_init(void) +{ + rmnet_mhi_create_debugfs_dir(); + + return platform_driver_register(&rmnet_mhi_driver); } static void __exit rmnet_mhi_exit(void) { struct rmnet_mhi_private *rmnet_mhi_ptr = 0; - int index = 0; - for (index = 0; index < MHI_RMNET_DEVICE_COUNT; index++) { - rmnet_mhi_ptr = &rmnet_mhi_ctxt_list[index]; - mhi_deregister_channel(rmnet_mhi_ptr->tx_client_handle); - mhi_deregister_channel(rmnet_mhi_ptr->rx_client_handle); + list_for_each_entry(rmnet_mhi_ptr, &rmnet_mhi_ctxt_list, node) { + if (rmnet_mhi_ptr->tx_client_handle) + mhi_deregister_channel(rmnet_mhi_ptr->tx_client_handle); + if (rmnet_mhi_ptr->rx_client_handle) + mhi_deregister_channel(rmnet_mhi_ptr->rx_client_handle); } } diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c index b8ef3780c2ac..b8a3a1ecabaa 100644 --- a/drivers/net/wireless/ath/ath10k/ce.c +++ b/drivers/net/wireless/ath/ath10k/ce.c @@ -64,7 +64,8 @@ static inline void ath10k_ce_dest_ring_write_index_set(struct ath10k *ar, { struct bus_opaque *ar_opaque = ath10k_bus_priv(ar); - ar_opaque->bus_ops->write32(ar, ce_ctrl_addr + DST_WR_INDEX_ADDRESS, n); + ar_opaque->bus_ops->write32(ar, + ce_ctrl_addr + ar->hw_ce_regs->dst_wr_index_addr, n); } static inline u32 ath10k_ce_dest_ring_write_index_get(struct ath10k *ar, @@ -72,8 +73,8 @@ static inline u32 ath10k_ce_dest_ring_write_index_get(struct ath10k *ar, { struct bus_opaque *ar_opaque = ath10k_bus_priv(ar); - return ar_opaque->bus_ops->read32(ar, ce_ctrl_addr + - DST_WR_INDEX_ADDRESS); + return ar_opaque->bus_ops->read32(ar, + ce_ctrl_addr + ar->hw_ce_regs->dst_wr_index_addr); } static inline void ath10k_ce_src_ring_write_index_set(struct ath10k *ar, @@ -82,7 +83,8 @@ static inline void ath10k_ce_src_ring_write_index_set(struct ath10k *ar, { struct bus_opaque *ar_opaque = ath10k_bus_priv(ar); - ar_opaque->bus_ops->write32(ar, ce_ctrl_addr + SR_WR_INDEX_ADDRESS, n); + ar_opaque->bus_ops->write32(ar, + ce_ctrl_addr + ar->hw_ce_regs->sr_wr_index_addr, n); } static inline u32 ath10k_ce_src_ring_write_index_get(struct ath10k *ar, @@ -90,8 +92,8 @@ static inline u32 ath10k_ce_src_ring_write_index_get(struct ath10k *ar, { struct bus_opaque *ar_opaque = ath10k_bus_priv(ar); - return ar_opaque->bus_ops->read32(ar, ce_ctrl_addr + - SR_WR_INDEX_ADDRESS); + return ar_opaque->bus_ops->read32(ar, + ce_ctrl_addr + ar->hw_ce_regs->sr_wr_index_addr); } static inline u32 ath10k_ce_src_ring_read_index_get(struct ath10k *ar, @@ -99,8 +101,8 @@ static inline u32 ath10k_ce_src_ring_read_index_get(struct ath10k *ar, { struct bus_opaque *ar_opaque = ath10k_bus_priv(ar); - return ar_opaque->bus_ops->read32(ar, ce_ctrl_addr + - CURRENT_SRRI_ADDRESS); + return ar_opaque->bus_ops->read32(ar, + ce_ctrl_addr + ar->hw_ce_regs->current_srri_addr); } static inline void ath10k_ce_shadow_src_ring_write_index_set(struct ath10k *ar, @@ -130,7 +132,8 @@ static inline void ath10k_ce_src_ring_base_addr_set(struct ath10k *ar, { struct bus_opaque *ar_opaque = ath10k_bus_priv(ar); - ar_opaque->bus_ops->write32(ar, ce_ctrl_addr + SR_BA_ADDRESS, addr); + ar_opaque->bus_ops->write32(ar, + ce_ctrl_addr + ar->hw_ce_regs->sr_base_addr, addr); } static inline void ath10k_ce_src_ring_size_set(struct ath10k *ar, @@ -139,7 +142,8 @@ static inline void ath10k_ce_src_ring_size_set(struct ath10k *ar, { struct bus_opaque *ar_opaque = ath10k_bus_priv(ar); - ar_opaque->bus_ops->write32(ar, ce_ctrl_addr + SR_SIZE_ADDRESS, n); + ar_opaque->bus_ops->write32(ar, + ce_ctrl_addr + ar->hw_ce_regs->sr_size_addr, n); } static inline void ath10k_ce_src_ring_dmax_set(struct ath10k *ar, @@ -147,12 +151,14 @@ static inline void ath10k_ce_src_ring_dmax_set(struct ath10k *ar, unsigned int n) { struct bus_opaque *ar_opaque = ath10k_bus_priv(ar); + struct ath10k_hw_ce_ctrl1 *ctrl_regs = ar->hw_ce_regs->ctrl1_regs; + u32 ctrl1_addr = ar_opaque->bus_ops->read32((ar), - (ce_ctrl_addr) + CE_CTRL1_ADDRESS); + (ce_ctrl_addr) + ctrl_regs->addr); - ar_opaque->bus_ops->write32(ar, ce_ctrl_addr + CE_CTRL1_ADDRESS, - (ctrl1_addr & ~CE_CTRL1_DMAX_LENGTH_MASK) | - CE_CTRL1_DMAX_LENGTH_SET(n)); + ar_opaque->bus_ops->write32(ar, ce_ctrl_addr + ctrl_regs->addr, + (ctrl1_addr & ~(ctrl_regs->dmax->mask)) | + ctrl_regs->dmax->set(n, ctrl_regs->dmax)); } static inline void ath10k_ce_src_ring_byte_swap_set(struct ath10k *ar, @@ -160,12 +166,14 @@ static inline void ath10k_ce_src_ring_byte_swap_set(struct ath10k *ar, unsigned int n) { struct bus_opaque *ar_opaque = ath10k_bus_priv(ar); + struct ath10k_hw_ce_ctrl1 *ctrl_regs = ar->hw_ce_regs->ctrl1_regs; + u32 ctrl1_addr = ar_opaque->bus_ops->read32(ar, ce_ctrl_addr + - CE_CTRL1_ADDRESS); + ctrl_regs->addr); - ar_opaque->bus_ops->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)); + ar_opaque->bus_ops->write32(ar, ce_ctrl_addr + ctrl_regs->addr, + (ctrl1_addr & ~(ctrl_regs->src_ring->mask)) | + ctrl_regs->src_ring->set(n, ctrl_regs->src_ring)); } static inline void ath10k_ce_dest_ring_byte_swap_set(struct ath10k *ar, @@ -173,12 +181,14 @@ static inline void ath10k_ce_dest_ring_byte_swap_set(struct ath10k *ar, unsigned int n) { struct bus_opaque *ar_opaque = ath10k_bus_priv(ar); + struct ath10k_hw_ce_ctrl1 *ctrl_regs = ar->hw_ce_regs->ctrl1_regs; + u32 ctrl1_addr = ar_opaque->bus_ops->read32(ar, ce_ctrl_addr + - CE_CTRL1_ADDRESS); + ctrl_regs->addr); - ar_opaque->bus_ops->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)); + ar_opaque->bus_ops->write32(ar, ce_ctrl_addr + ctrl_regs->addr, + (ctrl1_addr & ~(ctrl_regs->dst_ring->mask)) | + ctrl_regs->dst_ring->set(n, ctrl_regs->dst_ring)); } static inline u32 ath10k_ce_dest_ring_read_index_get(struct ath10k *ar, @@ -186,8 +196,8 @@ static inline u32 ath10k_ce_dest_ring_read_index_get(struct ath10k *ar, { struct bus_opaque *ar_opaque = ath10k_bus_priv(ar); - return ar_opaque->bus_ops->read32(ar, ce_ctrl_addr + - CURRENT_DRRI_ADDRESS); + return ar_opaque->bus_ops->read32(ar, + ce_ctrl_addr + ar->hw_ce_regs->current_drri_addr); } static inline void ath10k_ce_dest_ring_base_addr_set(struct ath10k *ar, @@ -196,7 +206,8 @@ static inline void ath10k_ce_dest_ring_base_addr_set(struct ath10k *ar, { struct bus_opaque *ar_opaque = ath10k_bus_priv(ar); - ar_opaque->bus_ops->write32(ar, ce_ctrl_addr + DR_BA_ADDRESS, addr); + ar_opaque->bus_ops->write32(ar, + ce_ctrl_addr + ar->hw_ce_regs->dr_base_addr, addr); } static inline void ath10k_ce_dest_ring_size_set(struct ath10k *ar, @@ -205,7 +216,8 @@ static inline void ath10k_ce_dest_ring_size_set(struct ath10k *ar, { struct bus_opaque *ar_opaque = ath10k_bus_priv(ar); - ar_opaque->bus_ops->write32(ar, ce_ctrl_addr + DR_SIZE_ADDRESS, n); + ar_opaque->bus_ops->write32(ar, + ce_ctrl_addr + ar->hw_ce_regs->dr_size_addr, n); } static inline void ath10k_ce_src_ring_highmark_set(struct ath10k *ar, @@ -213,13 +225,12 @@ static inline void ath10k_ce_src_ring_highmark_set(struct ath10k *ar, unsigned int n) { struct bus_opaque *ar_opaque = ath10k_bus_priv(ar); + struct ath10k_hw_ce_dst_src_wm_regs *srcr_wm = ar->hw_ce_regs->wm_srcr; + u32 addr = ar_opaque->bus_ops->read32(ar, ce_ctrl_addr + srcr_wm->addr); - u32 addr = ar_opaque->bus_ops->read32(ar, ce_ctrl_addr + - SRC_WATERMARK_ADDRESS); - - ar_opaque->bus_ops->write32(ar, ce_ctrl_addr + SRC_WATERMARK_ADDRESS, - (addr & ~SRC_WATERMARK_HIGH_MASK) | - SRC_WATERMARK_HIGH_SET(n)); + ar_opaque->bus_ops->write32(ar, ce_ctrl_addr + srcr_wm->addr, + (addr & ~(srcr_wm->wm_high->mask)) | + (srcr_wm->wm_high->set(n, srcr_wm->wm_high))); } static inline void ath10k_ce_src_ring_lowmark_set(struct ath10k *ar, @@ -227,12 +238,12 @@ static inline void ath10k_ce_src_ring_lowmark_set(struct ath10k *ar, unsigned int n) { struct bus_opaque *ar_opaque = ath10k_bus_priv(ar); - u32 addr = ar_opaque->bus_ops->read32(ar, ce_ctrl_addr + - SRC_WATERMARK_ADDRESS); + struct ath10k_hw_ce_dst_src_wm_regs *srcr_wm = ar->hw_ce_regs->wm_srcr; + u32 addr = ar_opaque->bus_ops->read32(ar, ce_ctrl_addr + srcr_wm->addr); - ar_opaque->bus_ops->write32(ar, ce_ctrl_addr + SRC_WATERMARK_ADDRESS, - (addr & ~SRC_WATERMARK_LOW_MASK) | - SRC_WATERMARK_LOW_SET(n)); + ar_opaque->bus_ops->write32(ar, ce_ctrl_addr + srcr_wm->addr, + (addr & ~(srcr_wm->wm_low->mask)) | + (srcr_wm->wm_low->set(n, srcr_wm->wm_low))); } static inline void ath10k_ce_dest_ring_highmark_set(struct ath10k *ar, @@ -240,12 +251,12 @@ static inline void ath10k_ce_dest_ring_highmark_set(struct ath10k *ar, unsigned int n) { struct bus_opaque *ar_opaque = ath10k_bus_priv(ar); - u32 addr = ar_opaque->bus_ops->read32(ar, ce_ctrl_addr + - DST_WATERMARK_ADDRESS); + struct ath10k_hw_ce_dst_src_wm_regs *dstr_wm = ar->hw_ce_regs->wm_dstr; + u32 addr = ar_opaque->bus_ops->read32(ar, ce_ctrl_addr + dstr_wm->addr); - ar_opaque->bus_ops->write32(ar, ce_ctrl_addr + DST_WATERMARK_ADDRESS, - (addr & ~DST_WATERMARK_HIGH_MASK) | - DST_WATERMARK_HIGH_SET(n)); + ar_opaque->bus_ops->write32(ar, ce_ctrl_addr + dstr_wm->addr, + (addr & ~(dstr_wm->wm_high->mask)) | + (dstr_wm->wm_high->set(n, dstr_wm->wm_high))); } static inline void ath10k_ce_dest_ring_lowmark_set(struct ath10k *ar, @@ -253,67 +264,82 @@ static inline void ath10k_ce_dest_ring_lowmark_set(struct ath10k *ar, unsigned int n) { struct bus_opaque *ar_opaque = ath10k_bus_priv(ar); - u32 addr = ar_opaque->bus_ops->read32(ar, ce_ctrl_addr + - DST_WATERMARK_ADDRESS); + struct ath10k_hw_ce_dst_src_wm_regs *dstr_wm = ar->hw_ce_regs->wm_dstr; + u32 addr = ar_opaque->bus_ops->read32(ar, ce_ctrl_addr + dstr_wm->addr); - ar_opaque->bus_ops->write32(ar, ce_ctrl_addr + DST_WATERMARK_ADDRESS, - (addr & ~DST_WATERMARK_LOW_MASK) | - DST_WATERMARK_LOW_SET(n)); + ar_opaque->bus_ops->write32(ar, ce_ctrl_addr + dstr_wm->addr, + (addr & ~(dstr_wm->wm_low->mask)) | + (dstr_wm->wm_low->set(n, dstr_wm->wm_low))); } static inline void ath10k_ce_copy_complete_inter_enable(struct ath10k *ar, u32 ce_ctrl_addr) { struct bus_opaque *ar_opaque = ath10k_bus_priv(ar); + struct ath10k_hw_ce_host_ie *host_ie = ar->hw_ce_regs->host_ie; + u32 host_ie_addr = ar_opaque->bus_ops->read32(ar, - ce_ctrl_addr + HOST_IE_ADDRESS); + ce_ctrl_addr + ar->hw_ce_regs->host_ie_addr); - ar_opaque->bus_ops->write32(ar, ce_ctrl_addr + HOST_IE_ADDRESS, - host_ie_addr | HOST_IE_COPY_COMPLETE_MASK); + ar_opaque->bus_ops->write32(ar, + ce_ctrl_addr + ar->hw_ce_regs->host_ie_addr, + host_ie_addr | host_ie->copy_complete->mask); } static inline void ath10k_ce_copy_complete_intr_disable(struct ath10k *ar, u32 ce_ctrl_addr) { struct bus_opaque *ar_opaque = ath10k_bus_priv(ar); + struct ath10k_hw_ce_host_ie *host_ie = ar->hw_ce_regs->host_ie; + u32 host_ie_addr = ar_opaque->bus_ops->read32(ar, - ce_ctrl_addr + HOST_IE_ADDRESS); + ce_ctrl_addr + ar->hw_ce_regs->host_ie_addr); - ar_opaque->bus_ops->write32(ar, ce_ctrl_addr + HOST_IE_ADDRESS, - host_ie_addr & ~HOST_IE_COPY_COMPLETE_MASK); + ar_opaque->bus_ops->write32(ar, + ce_ctrl_addr + ar->hw_ce_regs->host_ie_addr, + host_ie_addr & ~(host_ie->copy_complete->mask)); } static inline void ath10k_ce_watermark_intr_disable(struct ath10k *ar, u32 ce_ctrl_addr) { struct bus_opaque *ar_opaque = ath10k_bus_priv(ar); + struct ath10k_hw_ce_host_wm_regs *wm_regs = ar->hw_ce_regs->wm_regs; + u32 host_ie_addr = ar_opaque->bus_ops->read32(ar, - ce_ctrl_addr + HOST_IE_ADDRESS); + ce_ctrl_addr + ar->hw_ce_regs->host_ie_addr); - ar_opaque->bus_ops->write32(ar, ce_ctrl_addr + HOST_IE_ADDRESS, - host_ie_addr & ~CE_WATERMARK_MASK); + ar_opaque->bus_ops->write32(ar, + ce_ctrl_addr + ar->hw_ce_regs->host_ie_addr, + host_ie_addr & ~(wm_regs->wm_mask)); } static inline void ath10k_ce_error_intr_enable(struct ath10k *ar, u32 ce_ctrl_addr) { struct bus_opaque *ar_opaque = ath10k_bus_priv(ar); + struct ath10k_hw_ce_misc_regs *misc_regs = ar->hw_ce_regs->misc_regs; + u32 misc_ie_addr = ar_opaque->bus_ops->read32(ar, - ce_ctrl_addr + MISC_IE_ADDRESS); + ce_ctrl_addr + ar->hw_ce_regs->misc_ie_addr); - ar_opaque->bus_ops->write32(ar, ce_ctrl_addr + MISC_IE_ADDRESS, - misc_ie_addr | CE_ERROR_MASK); + ar_opaque->bus_ops->write32(ar, + ce_ctrl_addr + ar->hw_ce_regs->misc_ie_addr, + misc_ie_addr | misc_regs->err_mask); } static inline void ath10k_ce_error_intr_disable(struct ath10k *ar, u32 ce_ctrl_addr) { struct bus_opaque *ar_opaque = ath10k_bus_priv(ar); + struct ath10k_hw_ce_misc_regs *misc_regs = ar->hw_ce_regs->misc_regs; + u32 misc_ie_addr = ar_opaque->bus_ops->read32(ar, - ce_ctrl_addr + MISC_IE_ADDRESS); + ce_ctrl_addr + ar->hw_ce_regs->misc_ie_addr); - ar_opaque->bus_ops->write32(ar, ce_ctrl_addr + MISC_IE_ADDRESS, - misc_ie_addr & ~CE_ERROR_MASK); + ar_opaque->bus_ops->write32(ar, + ce_ctrl_addr + ar->hw_ce_regs->misc_ie_addr, + misc_ie_addr & ~(misc_regs->err_mask)); } static inline void ath10k_ce_engine_int_status_clear(struct ath10k *ar, @@ -321,8 +347,9 @@ static inline void ath10k_ce_engine_int_status_clear(struct ath10k *ar, unsigned int mask) { struct bus_opaque *ar_opaque = ath10k_bus_priv(ar); + struct ath10k_hw_ce_host_wm_regs *wm_regs = ar->hw_ce_regs->wm_regs; - ar_opaque->bus_ops->write32(ar, ce_ctrl_addr + HOST_IS_ADDRESS, mask); + ar_opaque->bus_ops->write32(ar, ce_ctrl_addr + wm_regs->addr, mask); } u32 shadow_sr_wr_ind_addr(struct ath10k *ar, u32 ctrl_addr) @@ -391,6 +418,21 @@ u32 shadow_dst_wr_ind_addr(struct ath10k *ar, u32 ctrl_addr) return addr; } +static inline void ath10k_ce_snoc_addr_config(struct ce_desc *sdesc, + dma_addr_t buffer, + unsigned int flags) +{ + __le32 *addr = (__le32 *)&sdesc->addr; + + flags |= upper_32_bits(buffer) & CE_DESC_FLAGS_GET_MASK; + addr[0] = __cpu_to_le32(buffer); + addr[1] = flags; + if (flags & CE_SEND_FLAG_GATHER) + addr[1] |= CE_WCN3990_DESC_FLAGS_GATHER; + else + addr[1] &= ~CE_WCN3990_DESC_FLAGS_GATHER; +} + /* * Guts of ath10k_ce_send, used by both ath10k_ce_send and * ath10k_ce_sendlist_send. @@ -434,17 +476,10 @@ int ath10k_ce_send_nolock(struct ath10k_ce_pipe *ce_state, if (flags & CE_SEND_FLAG_BYTE_SWAP) desc_flags |= CE_DESC_FLAGS_BYTE_SWAP; - if (QCA_REV_WCN3990(ar)) { - flags |= upper_32_bits(buffer) & CE_DESC_FLAGS_GET_MASK; - sdesc.addr_lo = __cpu_to_le32(buffer); - sdesc.addr_hi = flags; - if (flags & CE_SEND_FLAG_GATHER) - sdesc.addr_hi |= CE_WCN3990_DESC_FLAGS_GATHER; - else - sdesc.addr_hi &= ~CE_WCN3990_DESC_FLAGS_GATHER; - } else { + if (QCA_REV_WCN3990(ar)) + ath10k_ce_snoc_addr_config(&sdesc, buffer, flags); + else sdesc.addr = __cpu_to_le32(buffer); - } sdesc.nbytes = __cpu_to_le16(nbytes); sdesc.flags = __cpu_to_le16(desc_flags); @@ -866,13 +901,14 @@ void ath10k_ce_per_engine_service(struct ath10k *ar, unsigned int ce_id) { struct bus_opaque *ar_opaque = ath10k_bus_priv(ar); struct ath10k_ce_pipe *ce_state = &ar_opaque->ce_states[ce_id]; + struct ath10k_hw_ce_host_wm_regs *wm_regs = ar->hw_ce_regs->wm_regs; u32 ctrl_addr = ce_state->ctrl_addr; spin_lock_bh(&ar_opaque->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); + wm_regs->cc_mask); spin_unlock_bh(&ar_opaque->ce_lock); @@ -888,7 +924,7 @@ void ath10k_ce_per_engine_service(struct ath10k *ar, unsigned int ce_id) * Misc CE interrupts are not being handled, but still need * to be cleared. */ - ath10k_ce_engine_int_status_clear(ar, ctrl_addr, CE_WATERMARK_MASK); + ath10k_ce_engine_int_status_clear(ar, ctrl_addr, wm_regs->wm_mask); spin_unlock_bh(&ar_opaque->ce_lock); } @@ -983,7 +1019,7 @@ void ath10k_ce_enable_per_ce_interrupts(struct ath10k *ar, unsigned int ce_id) u32 ctrl_addr = ath10k_ce_base_address(ar, ce_id); struct bus_opaque *ar_opaque = ath10k_bus_priv(ar); - offset = HOST_IE_ADDRESS + ctrl_addr; + offset = ar->hw_ce_regs->host_ie_addr + ctrl_addr; ar_opaque->bus_ops->write32(ar, offset, 1); ar_opaque->bus_ops->read32(ar, offset); } @@ -994,7 +1030,7 @@ void ath10k_ce_disable_per_ce_interrupts(struct ath10k *ar, unsigned int ce_id) u32 ctrl_addr = ath10k_ce_base_address(ar, ce_id); struct bus_opaque *ar_opaque = ath10k_bus_priv(ar); - offset = HOST_IE_ADDRESS + ctrl_addr; + offset = ar->hw_ce_regs->host_ie_addr + ctrl_addr; ar_opaque->bus_ops->write32(ar, offset, 0); ar_opaque->bus_ops->read32(ar, offset); } diff --git a/drivers/net/wireless/ath/ath10k/ce.h b/drivers/net/wireless/ath/ath10k/ce.h index f4fa86b93082..936f0698c0f0 100644 --- a/drivers/net/wireless/ath/ath10k/ce.h +++ b/drivers/net/wireless/ath/ath10k/ce.h @@ -58,13 +58,7 @@ struct ce_desc { }; #else struct ce_desc { - union { - __le64 addr; - struct { - __le32 addr_lo; - __le32 addr_hi; - }; - }; + __le64 addr; u16 nbytes; /* length in register map */ u16 flags; /* fw_metadata_high */ u32 toeplitz_hash_result; @@ -362,311 +356,6 @@ struct ce_attr { void (*recv_cb)(struct ath10k_ce_pipe *); }; -#ifndef CONFIG_ATH10K_SNOC -#define SR_BA_ADDRESS 0x0000 -#define SR_SIZE_ADDRESS 0x0004 -#define DR_BA_ADDRESS 0x0008 -#define DR_SIZE_ADDRESS 0x000c -#define CE_CMD_ADDRESS 0x0018 - -#define CE_CTRL1_DST_RING_BYTE_SWAP_EN_MSB 17 -#define CE_CTRL1_DST_RING_BYTE_SWAP_EN_LSB 17 -#define CE_CTRL1_DST_RING_BYTE_SWAP_EN_MASK 0x00020000 -#define CE_CTRL1_DST_RING_BYTE_SWAP_EN_SET(x) \ - (((0 | (x)) << CE_CTRL1_DST_RING_BYTE_SWAP_EN_LSB) & \ - CE_CTRL1_DST_RING_BYTE_SWAP_EN_MASK) - -#define CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MSB 16 -#define CE_CTRL1_SRC_RING_BYTE_SWAP_EN_LSB 16 -#define CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MASK 0x00010000 -#define CE_CTRL1_SRC_RING_BYTE_SWAP_EN_GET(x) \ - (((x) & CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MASK) >> \ - CE_CTRL1_SRC_RING_BYTE_SWAP_EN_LSB) -#define CE_CTRL1_SRC_RING_BYTE_SWAP_EN_SET(x) \ - (((0 | (x)) << CE_CTRL1_SRC_RING_BYTE_SWAP_EN_LSB) & \ - CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MASK) - -#define CE_CTRL1_DMAX_LENGTH_MSB 15 -#define CE_CTRL1_DMAX_LENGTH_LSB 0 -#define CE_CTRL1_DMAX_LENGTH_MASK 0x0000ffff -#define CE_CTRL1_DMAX_LENGTH_GET(x) \ - (((x) & CE_CTRL1_DMAX_LENGTH_MASK) >> CE_CTRL1_DMAX_LENGTH_LSB) -#define CE_CTRL1_DMAX_LENGTH_SET(x) \ - (((0 | (x)) << CE_CTRL1_DMAX_LENGTH_LSB) & CE_CTRL1_DMAX_LENGTH_MASK) - -#define CE_CTRL1_ADDRESS 0x0010 -#define CE_CTRL1_HW_MASK 0x0007ffff -#define CE_CTRL1_SW_MASK 0x0007ffff -#define CE_CTRL1_HW_WRITE_MASK 0x00000000 -#define CE_CTRL1_SW_WRITE_MASK 0x0007ffff -#define CE_CTRL1_RSTMASK 0xffffffff -#define CE_CTRL1_RESET 0x00000080 - -#define CE_CMD_HALT_STATUS_MSB 3 -#define CE_CMD_HALT_STATUS_LSB 3 -#define CE_CMD_HALT_STATUS_MASK 0x00000008 -#define CE_CMD_HALT_STATUS_GET(x) \ - (((x) & CE_CMD_HALT_STATUS_MASK) >> CE_CMD_HALT_STATUS_LSB) -#define CE_CMD_HALT_STATUS_SET(x) \ - (((0 | (x)) << CE_CMD_HALT_STATUS_LSB) & CE_CMD_HALT_STATUS_MASK) -#define CE_CMD_HALT_STATUS_RESET 0 -#define CE_CMD_HALT_MSB 0 -#define CE_CMD_HALT_MASK 0x00000001 - -#define HOST_IE_COPY_COMPLETE_MSB 0 -#define HOST_IE_COPY_COMPLETE_LSB 0 -#define HOST_IE_COPY_COMPLETE_MASK 0x00000001 -#define HOST_IE_COPY_COMPLETE_GET(x) \ - (((x) & HOST_IE_COPY_COMPLETE_MASK) >> HOST_IE_COPY_COMPLETE_LSB) -#define HOST_IE_COPY_COMPLETE_SET(x) \ - (((0 | (x)) << HOST_IE_COPY_COMPLETE_LSB) & HOST_IE_COPY_COMPLETE_MASK) -#define HOST_IE_COPY_COMPLETE_RESET 0 -#define HOST_IE_ADDRESS 0x002c - -#define HOST_IS_DST_RING_LOW_WATERMARK_MASK 0x00000010 -#define HOST_IS_DST_RING_HIGH_WATERMARK_MASK 0x00000008 -#define HOST_IS_SRC_RING_LOW_WATERMARK_MASK 0x00000004 -#define HOST_IS_SRC_RING_HIGH_WATERMARK_MASK 0x00000002 -#define HOST_IS_COPY_COMPLETE_MASK 0x00000001 -#define HOST_IS_ADDRESS 0x0030 - -#define MISC_IE_ADDRESS 0x0034 - -#define MISC_IS_AXI_ERR_MASK 0x00000400 - -#define MISC_IS_DST_ADDR_ERR_MASK 0x00000200 -#define MISC_IS_SRC_LEN_ERR_MASK 0x00000100 -#define MISC_IS_DST_MAX_LEN_VIO_MASK 0x00000080 -#define MISC_IS_DST_RING_OVERFLOW_MASK 0x00000040 -#define MISC_IS_SRC_RING_OVERFLOW_MASK 0x00000020 - -#define MISC_IS_ADDRESS 0x0038 - -#define SR_WR_INDEX_ADDRESS 0x003c - -#define DST_WR_INDEX_ADDRESS 0x0040 - -#define CURRENT_SRRI_ADDRESS 0x0044 - -#define CURRENT_DRRI_ADDRESS 0x0048 - -#define SRC_WATERMARK_LOW_MSB 31 -#define SRC_WATERMARK_LOW_LSB 16 -#define SRC_WATERMARK_LOW_MASK 0xffff0000 -#define SRC_WATERMARK_LOW_GET(x) \ - (((x) & SRC_WATERMARK_LOW_MASK) >> SRC_WATERMARK_LOW_LSB) -#define SRC_WATERMARK_LOW_SET(x) \ - (((0 | (x)) << SRC_WATERMARK_LOW_LSB) & SRC_WATERMARK_LOW_MASK) -#define SRC_WATERMARK_LOW_RESET 0 -#define SRC_WATERMARK_HIGH_MSB 15 -#define SRC_WATERMARK_HIGH_LSB 0 -#define SRC_WATERMARK_HIGH_MASK 0x0000ffff -#define SRC_WATERMARK_HIGH_GET(x) \ - (((x) & SRC_WATERMARK_HIGH_MASK) >> SRC_WATERMARK_HIGH_LSB) -#define SRC_WATERMARK_HIGH_SET(x) \ - (((0 | (x)) << SRC_WATERMARK_HIGH_LSB) & SRC_WATERMARK_HIGH_MASK) -#define SRC_WATERMARK_HIGH_RESET 0 -#define SRC_WATERMARK_ADDRESS 0x004c - -#define DST_WATERMARK_LOW_LSB 16 -#define DST_WATERMARK_LOW_MASK 0xffff0000 -#define DST_WATERMARK_LOW_SET(x) \ - (((0 | (x)) << DST_WATERMARK_LOW_LSB) & DST_WATERMARK_LOW_MASK) -#define DST_WATERMARK_LOW_RESET 0 -#define DST_WATERMARK_HIGH_MSB 15 -#define DST_WATERMARK_HIGH_LSB 0 -#define DST_WATERMARK_HIGH_MASK 0x0000ffff -#define DST_WATERMARK_HIGH_GET(x) \ - (((x) & DST_WATERMARK_HIGH_MASK) >> DST_WATERMARK_HIGH_LSB) -#define DST_WATERMARK_HIGH_SET(x) \ - (((0 | (x)) << DST_WATERMARK_HIGH_LSB) & DST_WATERMARK_HIGH_MASK) -#define DST_WATERMARK_HIGH_RESET 0 -#define DST_WATERMARK_ADDRESS 0x0050 - -#else -#define WCN3990_CE0_SR_BA_LOW (0x00240000) -#define WCN3990_CE1_SR_BA_LOW (0x00241000) -#define WCN3990_CE2_SR_BA_LOW (0x00242000) -#define WCN3990_CE3_SR_BA_LOW (0x00243000) -#define WCN3990_CE4_SR_BA_LOW (0x00244000) -#define WCN3990_CE5_SR_BA_LOW (0x00245000) -#define WCN3990_CE6_SR_BA_LOW (0x00246000) -#define WCN3990_CE7_SR_BA_LOW (0x00247000) -#define WCN3990_CE8_SR_BA_LOW (0x00248000) -#define WCN3990_CE9_SR_BA_LOW (0x00249000) -#define WCN3990_CE10_SR_BA_LOW (0x0024A000) -#define WCN3990_CE11_SR_BA_LOW (0x0024B000) -#define WCN3990_CE0_DR_BA_LOW (0x0024000C) -#define WNC3990_CE0_DR_SIZE (0x00240014) -#define WCN3990_CE0_CE_CTRL1 (0x00240018) -#define WCN3990_CE0_HOST_IE (0x0024002C) -#define WCN3990_CE0_HOST_IS (0x00240030) -#define WCN3990_CE0_MISC_IE (0x00240034) -#define WCN3990_CE0_MISC_IS (0x00240038) -#define WCN3990_CE0_SRC_WR_INDEX (0x0024003C) -#define WCN3990_CE0_CURRENT_SRRI (0x00240044) -#define WCN3990_CE0_CURRENT_DRRI (0x00240048) -#define WCN3990_CE0_SRC_WATERMARK (0x0024004C) -#define WCN3990_CE0_DST_WATERMARK (0x00240050) -#define WCN3990_CE0_SR_SIZE (0x00240008) -#define HOST_IE_COPY_COMPLETE_MASK (0x00000001) -#define WCN3990_CE_WRAPPER_HOST_INTERRUPT_SUMMARY 0x0024C000 -#define WCN3990_CE_WRAPPER_INDEX_BASE_LOW 0x0024C004 -#define WCN3990_CE_WRAPPER_INDEX_BASE_HIGH 0x0024C008 -#define CE_CTRL1_IDX_UPD_EN 0x00080000 - -#define WCN3990_CE_WRAPPER_BASE_ADDRESS \ - WCN3990_CE_WRAPPER_HOST_INTERRUPT_SUMMARY -#define WCN3990_CE0_BASE_ADDRESS \ - WCN3990_CE0_SR_BA_LOW -#define WCN3990_CE1_BASE_ADDRESS \ - WCN3990_CE1_SR_BA_LOW -#define WCN3990_CE2_BASE_ADDRESS \ - WCN3990_CE2_SR_BA_LOW -#define WCN3990_CE3_BASE_ADDRESS \ - WCN3990_CE3_SR_BA_LOW -#define WCN3990_CE4_BASE_ADDRESS \ - WCN3990_CE4_SR_BA_LOW -#define WCN3990_CE5_BASE_ADDRESS \ - WCN3990_CE5_SR_BA_LOW -#define WCN3990_CE6_BASE_ADDRESS \ - WCN3990_CE6_SR_BA_LOW -#define WCN3990_CE7_BASE_ADDRESS \ - WCN3990_CE7_SR_BA_LOW -#define WCN3990_CE8_BASE_ADDRESS \ - WCN3990_CE8_SR_BA_LOW -#define WCN3990_CE9_BASE_ADDRESS \ - WCN3990_CE9_SR_BA_LOW -#define WCN3990_CE10_BASE_ADDRESS \ - WCN3990_CE10_SR_BA_LOW -#define WCN3990_CE11_BASE_ADDRESS \ - WCN3990_CE11_SR_BA_LOW - -#define SR_BA_ADDRESS (WCN3990_CE0_SR_BA_LOW\ - - WCN3990_CE0_BASE_ADDRESS) -#define SR_SIZE_ADDRESS (WCN3990_CE0_SR_SIZE \ - - WCN3990_CE0_BASE_ADDRESS) -#define DR_BA_ADDRESS (WCN3990_CE0_DR_BA_LOW\ - - WCN3990_CE0_BASE_ADDRESS) -#define DR_SIZE_ADDRESS (WNC3990_CE0_DR_SIZE\ - - WCN3990_CE0_BASE_ADDRESS) -#define WCN3990_CE_DDR_ADDRESS_FOR_RRI_LOW \ - (WCN3990_CE_WRAPPER_INDEX_BASE_LOW - WCN3990_CE_WRAPPER_BASE_ADDRESS) - -#define WCN3990_CE_DDR_ADDRESS_FOR_RRI_HIGH \ - (WCN3990_CE_WRAPPER_INDEX_BASE_HIGH - WCN3990_CE_WRAPPER_BASE_ADDRESS) - -#define CE_RRI_LOW (WCN3990_CE_WRAPPER_BASE_ADDRESS \ - + WCN3990_CE_DDR_ADDRESS_FOR_RRI_LOW) - -#define CE_RRI_HIGH (WCN3990_CE_WRAPPER_BASE_ADDRESS \ - + WCN3990_CE_DDR_ADDRESS_FOR_RRI_HIGH) - -#define CE_CTRL1_DST_RING_BYTE_SWAP_EN_MSB 18 -#define CE_CTRL1_DST_RING_BYTE_SWAP_EN_LSB 18 - -#define CE_CTRL1_DST_RING_BYTE_SWAP_EN_MASK 0x00040000 -#define CE_CTRL1_DST_RING_BYTE_SWAP_EN_SET(x) \ - (((0 | (x)) << CE_CTRL1_DST_RING_BYTE_SWAP_EN_LSB) & \ - CE_CTRL1_DST_RING_BYTE_SWAP_EN_MASK) - -#define CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MSB 16 -#define CE_CTRL1_SRC_RING_BYTE_SWAP_EN_LSB 16 - -#define CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MASK 0x00020000 -#define CE_CTRL1_SRC_RING_BYTE_SWAP_EN_GET(x) \ - (((x) & CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MASK) >> \ - CE_CTRL1_SRC_RING_BYTE_SWAP_EN_LSB) -#define CE_CTRL1_SRC_RING_BYTE_SWAP_EN_SET(x) \ - (((0 | (x)) << CE_CTRL1_SRC_RING_BYTE_SWAP_EN_LSB) & \ - CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MASK) - -#define CE_CTRL1_DMAX_LENGTH_MSB 0 -#define CE_CTRL1_DMAX_LENGTH_LSB 0 - -#define CE_CTRL1_DMAX_LENGTH_MASK 0x0000FFFF -#define CE_CTRL1_DMAX_LENGTH_GET(x) \ - (((x) & CE_CTRL1_DMAX_LENGTH_MASK) >> CE_CTRL1_DMAX_LENGTH_LSB) -#define CE_CTRL1_DMAX_LENGTH_SET(x) \ - (((0 | (x)) << CE_CTRL1_DMAX_LENGTH_LSB) & CE_CTRL1_DMAX_LENGTH_MASK) - -#define CE_CTRL1_ADDRESS (WCN3990_CE0_CE_CTRL1 \ - - WCN3990_CE0_BASE_ADDRESS) - -#define HOST_IE_ADDRESS (WCN3990_CE0_HOST_IE\ - - WCN3990_CE0_BASE_ADDRESS) - -#define HOST_IS_DST_RING_LOW_WATERMARK_MASK 0x00000010 -#define HOST_IS_DST_RING_HIGH_WATERMARK_MASK 0x00000008 -#define HOST_IS_SRC_RING_LOW_WATERMARK_MASK 0x00000004 -#define HOST_IS_SRC_RING_HIGH_WATERMARK_MASK 0x00000002 -#define HOST_IS_COPY_COMPLETE_MASK 0x00000001 -#define HOST_IS_ADDRESS (WCN3990_CE0_HOST_IS \ - - WCN3990_CE0_BASE_ADDRESS) -#define MISC_IE_ADDRESS (WCN3990_CE0_MISC_IE \ - - WCN3990_CE0_BASE_ADDRESS) - -#define MISC_IS_AXI_ERR_MASK 0x00000100 -#define MISC_IS_DST_ADDR_ERR_MASK 0x00000200 -#define MISC_IS_SRC_LEN_ERR_MASK 0x00000100 -#define MISC_IS_DST_MAX_LEN_VIO_MASK 0x00000080 -#define MISC_IS_DST_RING_OVERFLOW_MASK 0x00000040 -#define MISC_IS_SRC_RING_OVERFLOW_MASK 0x00000020 -#define MISC_IS_ADDRESS (WCN3990_CE0_MISC_IS \ - - WCN3990_CE0_BASE_ADDRESS) - -#define SR_WR_INDEX_ADDRESS 0x3C -#define DST_WR_INDEX_ADDRESS 0x40 - -#define CURRENT_SRRI_ADDRESS (WCN3990_CE0_CURRENT_SRRI\ - - WCN3990_CE0_BASE_ADDRESS) -#define CURRENT_DRRI_ADDRESS (WCN3990_CE0_CURRENT_DRRI\ - - WCN3990_CE0_BASE_ADDRESS) - -#define SRC_WATERMARK_LOW_MSB 0 -#define SRC_WATERMARK_LOW_LSB 16 - -#define SRC_WATERMARK_LOW_MASK 0xffff0000 -#define SRC_WATERMARK_LOW_GET(x) \ - (((x) & SRC_WATERMARK_LOW_MASK) >> SRC_WATERMARK_LOW_LSB) -#define SRC_WATERMARK_LOW_SET(x) \ - (((0 | (x)) << SRC_WATERMARK_LOW_LSB) & SRC_WATERMARK_LOW_MASK) - -#define SRC_WATERMARK_LOW_RESET 0 -#define SRC_WATERMARK_HIGH_MSB 15 -#define SRC_WATERMARK_HIGH_LSB 0 -#define SRC_WATERMARK_HIGH_MASK 0x0000ffff -#define SRC_WATERMARK_HIGH_GET(x) \ - (((x) & SRC_WATERMARK_HIGH_MASK) >> SRC_WATERMARK_HIGH_LSB) -#define SRC_WATERMARK_HIGH_SET(x) \ - (((0 | (x)) << SRC_WATERMARK_HIGH_LSB) & SRC_WATERMARK_HIGH_MASK) - -#define SRC_WATERMARK_HIGH_RESET 0 -#define SRC_WATERMARK_ADDRESS (WCN3990_CE0_SRC_WATERMARK\ - - WCN3990_CE0_BASE_ADDRESS) - -#define DST_WATERMARK_LOW_LSB 16 -#define DST_WATERMARK_LOW_MASK 0xffff0000 -#define DST_WATERMARK_LOW_SET(x) \ - (((0 | (x)) << DST_WATERMARK_LOW_LSB) & DST_WATERMARK_LOW_MASK) -#define DST_WATERMARK_LOW_RESET 0 -#define DST_WATERMARK_HIGH_MSB 15 -#define DST_WATERMARK_HIGH_LSB 0 -#define DST_WATERMARK_HIGH_MASK 0x0000ffff -#define DST_WATERMARK_HIGH_GET(x) \ - (((x) & DST_WATERMARK_HIGH_MASK) >> DST_WATERMARK_HIGH_LSB) -#define DST_WATERMARK_HIGH_SET(x) \ - (((0 | (x)) << DST_WATERMARK_HIGH_LSB) & DST_WATERMARK_HIGH_MASK) -#define DST_WATERMARK_HIGH_RESET 0 -#define DST_WATERMARK_ADDRESS (WCN3990_CE0_DST_WATERMARK \ - - WCN3990_CE0_BASE_ADDRESS) - -#define BITS0_TO_31(val) ((uint32_t)((uint64_t)(val)\ - & (uint64_t)(0xFFFFFFFF))) -#define BITS32_TO_35(val) ((uint32_t)(((uint64_t)(val)\ - & (uint64_t)(0xF00000000)) >> 32)) -#endif - #define COPY_ENGINE_ID(COPY_ENGINE_BASE_ADDRESS) ((COPY_ENGINE_BASE_ADDRESS \ - CE0_BASE_ADDRESS) / (CE1_BASE_ADDRESS - CE0_BASE_ADDRESS)) @@ -675,18 +364,6 @@ static inline u32 ath10k_ce_base_address(struct ath10k *ar, unsigned int ce_id) return CE0_BASE_ADDRESS + (CE1_BASE_ADDRESS - CE0_BASE_ADDRESS) * ce_id; } -#define CE_WATERMARK_MASK (HOST_IS_SRC_RING_LOW_WATERMARK_MASK | \ - HOST_IS_SRC_RING_HIGH_WATERMARK_MASK | \ - HOST_IS_DST_RING_LOW_WATERMARK_MASK | \ - HOST_IS_DST_RING_HIGH_WATERMARK_MASK) - -#define CE_ERROR_MASK (MISC_IS_AXI_ERR_MASK | \ - MISC_IS_DST_ADDR_ERR_MASK | \ - MISC_IS_SRC_LEN_ERR_MASK | \ - MISC_IS_DST_MAX_LEN_VIO_MASK | \ - MISC_IS_DST_RING_OVERFLOW_MASK | \ - MISC_IS_SRC_RING_OVERFLOW_MASK) - #define CE_SRC_RING_TO_DESC(baddr, idx) \ (&(((struct ce_desc *)baddr)[idx])) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 052ebd7dd26b..d37ed66d767b 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -2324,28 +2324,34 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev, case ATH10K_HW_QCA988X: case ATH10K_HW_QCA9887: ar->regs = &qca988x_regs; + ar->hw_ce_regs = &qcax_ce_regs; ar->hw_values = &qca988x_values; break; case ATH10K_HW_QCA6174: case ATH10K_HW_QCA9377: ar->regs = &qca6174_regs; + ar->hw_ce_regs = &qcax_ce_regs; ar->hw_values = &qca6174_values; break; case ATH10K_HW_QCA99X0: case ATH10K_HW_QCA9984: ar->regs = &qca99x0_regs; + ar->hw_ce_regs = &qcax_ce_regs; ar->hw_values = &qca99x0_values; break; case ATH10K_HW_QCA9888: ar->regs = &qca99x0_regs; + ar->hw_ce_regs = &qcax_ce_regs; ar->hw_values = &qca9888_values; break; case ATH10K_HW_QCA4019: ar->regs = &qca4019_regs; + ar->hw_ce_regs = &qcax_ce_regs; ar->hw_values = &qca4019_values; break; case ATH10K_HW_WCN3990: ar->regs = &wcn3990_regs; + ar->hw_ce_regs = &wcn3990_ce_regs; ar->hw_values = &wcn3990_values; /* WCN3990 chip set is non bmi based */ ar->is_bmi = false; diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index dc4cefb1177f..21c63d5d3ead 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -740,6 +740,7 @@ struct ath10k { struct completion target_suspend; const struct ath10k_hw_regs *regs; + const struct ath10k_hw_ce_regs *hw_ce_regs; const struct ath10k_hw_values *hw_values; struct ath10k_shadow_reg_value *shadow_reg_value; struct ath10k_shadow_reg_address *shadow_reg_address; diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index 82a4c67f3672..c36c2481856b 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -1909,7 +1909,7 @@ int ath10k_debug_start(struct ath10k *ar) ath10k_warn(ar, "failed to disable pktlog: %d\n", ret); } - if (ar->debug.nf_cal_period) { + if (ar->debug.nf_cal_period && !QCA_REV_WCN3990(ar)) { ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->cal_period, ar->debug.nf_cal_period); @@ -1926,7 +1926,8 @@ void ath10k_debug_stop(struct ath10k *ar) { lockdep_assert_held(&ar->conf_mutex); - ath10k_debug_cal_data_fetch(ar); + if (!QCA_REV_WCN3990(ar)) + ath10k_debug_cal_data_fetch(ar); /* Must not use _sync to avoid deadlock, we do that in * ath10k_debug_destroy(). The check for htt_stats_mask is to avoid @@ -2419,15 +2420,18 @@ int ath10k_debug_register(struct ath10k *ar) debugfs_create_file("fw_dbglog", S_IRUSR | S_IWUSR, ar->debug.debugfs_phy, ar, &fops_fw_dbglog); - debugfs_create_file("cal_data", S_IRUSR, ar->debug.debugfs_phy, - ar, &fops_cal_data); + if (!QCA_REV_WCN3990(ar)) { + debugfs_create_file("cal_data", S_IRUSR, ar->debug.debugfs_phy, + ar, &fops_cal_data); + + debugfs_create_file("nf_cal_period", S_IRUSR | S_IWUSR, + ar->debug.debugfs_phy, ar, + &fops_nf_cal_period); + } debugfs_create_file("ani_enable", S_IRUSR | S_IWUSR, ar->debug.debugfs_phy, ar, &fops_ani_enable); - debugfs_create_file("nf_cal_period", S_IRUSR | S_IWUSR, - ar->debug.debugfs_phy, ar, &fops_nf_cal_period); - if (IS_ENABLED(CONFIG_ATH10K_DFS_CERTIFIED)) { debugfs_create_file("dfs_simulate_radar", S_IWUSR, ar->debug.debugfs_phy, ar, diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h index b2678984f2de..6dd396430f19 100644 --- a/drivers/net/wireless/ath/ath10k/htt.h +++ b/drivers/net/wireless/ath/ath10k/htt.h @@ -541,6 +541,7 @@ struct htt_rx_indication_hdr { #define HTT_RX_INDICATION_INFO2_SERVICE_LSB 24 #define HTT_WCN3990_PADDR_MASK 0x1F +#define HTT_WCN3990_ARCH_PADDR_MASK 0x1FFFFFFFFF enum htt_rx_legacy_rate { HTT_RX_OFDM_48 = 0, @@ -865,8 +866,7 @@ struct htt_rx_offload_ind { struct htt_rx_in_ord_msdu_desc { #ifdef CONFIG_ATH10K_SNOC - __le32 msdu_paddr_lo; - __le32 msdu_paddr_hi; + __le64 msdu_paddr; #else __le32 msdu_paddr; #endif diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index cbb61267eb10..ddf097e3a143 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -429,9 +429,8 @@ static int ath10k_htt_rx_pop_paddr_list(struct ath10k_htt *htt, while (msdu_count--) { #ifdef CONFIG_ATH10K_SNOC - paddr = __le32_to_cpu(msdu_desc->msdu_paddr_lo); - paddr |= ((u64)(msdu_desc->msdu_paddr_hi & - HTT_WCN3990_PADDR_MASK) << 32); + paddr = __le64_to_cpu(msdu_desc->msdu_paddr); + paddr &= HTT_WCN3990_ARCH_PADDR_MASK; #else paddr = __le32_to_cpu(msdu_desc->msdu_paddr); #endif diff --git a/drivers/net/wireless/ath/ath10k/hw.c b/drivers/net/wireless/ath/ath10k/hw.c index 1a8f3a388ce2..1d37b2c8426b 100644 --- a/drivers/net/wireless/ath/ath10k/hw.c +++ b/drivers/net/wireless/ath/ath10k/hw.c @@ -164,6 +164,301 @@ const struct ath10k_hw_regs wcn3990_regs = { .pcie_intr_fw_mask = 0x00100000, }; +static unsigned int +ath10k_set_ring_byte(unsigned int offset, + struct ath10k_hw_ce_regs_addr_map *addr_map) +{ + return (((0 | (offset)) << addr_map->lsb) & addr_map->mask); +} + +static unsigned int +ath10k_get_ring_byte(unsigned int offset, + struct ath10k_hw_ce_regs_addr_map *addr_map) +{ + return (((offset) & addr_map->mask) >> (addr_map->lsb)); +} + +struct ath10k_hw_ce_regs_addr_map wcn3990_src_ring = { + .msb = 0x00000010, + .lsb = 0x00000010, + .mask = 0x00020000, + .set = &ath10k_set_ring_byte, + .get = &ath10k_get_ring_byte, +}; + +struct ath10k_hw_ce_regs_addr_map wcn3990_dst_ring = { + .msb = 0x00000012, + .lsb = 0x00000012, + .mask = 0x00040000, + .set = &ath10k_set_ring_byte, + .get = &ath10k_get_ring_byte, +}; + +struct ath10k_hw_ce_regs_addr_map wcn3990_dmax = { + .msb = 0x00000000, + .lsb = 0x00000000, + .mask = 0x0000ffff, + .set = &ath10k_set_ring_byte, + .get = &ath10k_get_ring_byte, +}; + +struct ath10k_hw_ce_ctrl1 wcn3990_ctrl1 = { + .addr = 0x00000018, + .src_ring = &wcn3990_src_ring, + .dst_ring = &wcn3990_dst_ring, + .dmax = &wcn3990_dmax, +}; + +struct ath10k_hw_ce_regs_addr_map wcn3990_host_ie_cc = { + .mask = 0x00000001, +}; + +struct ath10k_hw_ce_host_ie wcn3990_host_ie = { + .copy_complete = &wcn3990_host_ie_cc, +}; + +struct ath10k_hw_ce_host_wm_regs wcn3990_wm_reg = { + .dstr_lmask = 0x00000010, + .dstr_hmask = 0x00000008, + .srcr_lmask = 0x00000004, + .srcr_hmask = 0x00000002, + .cc_mask = 0x00000001, + .wm_mask = 0x0000001E, + .addr = 0x00000030, +}; + +struct ath10k_hw_ce_misc_regs wcn3990_misc_reg = { + .axi_err = 0x00000100, + .dstr_add_err = 0x00000200, + .srcr_len_err = 0x00000100, + .dstr_mlen_vio = 0x00000080, + .dstr_overflow = 0x00000040, + .srcr_overflow = 0x00000020, + .err_mask = 0x000003E0, + .addr = 0x00000038, +}; + +struct ath10k_hw_ce_regs_addr_map wcn3990_src_wm_low = { + .msb = 0x00000000, + .lsb = 0x00000010, + .mask = 0xffff0000, + .set = &ath10k_set_ring_byte, + .get = &ath10k_get_ring_byte, +}; + +struct ath10k_hw_ce_regs_addr_map wcn3990_src_wm_high = { + .msb = 0x0000000f, + .lsb = 0x00000000, + .mask = 0x0000ffff, + .set = &ath10k_set_ring_byte, + .get = &ath10k_get_ring_byte, +}; + +struct ath10k_hw_ce_dst_src_wm_regs wcn3990_wm_src_ring = { + .addr = 0x0000004c, + .low_rst = 0x00000000, + .high_rst = 0x00000000, + .wm_low = &wcn3990_src_wm_low, + .wm_high = &wcn3990_src_wm_high, +}; + +struct ath10k_hw_ce_regs_addr_map wcn3990_dst_wm_low = { + .lsb = 0x00000010, + .mask = 0xffff0000, + .set = &ath10k_set_ring_byte, +}; + +struct ath10k_hw_ce_regs_addr_map wcn3990_dst_wm_high = { + .msb = 0x0000000f, + .lsb = 0x00000000, + .mask = 0x0000ffff, + .set = &ath10k_set_ring_byte, + .get = &ath10k_get_ring_byte, +}; + +struct ath10k_hw_ce_dst_src_wm_regs wcn3990_wm_dst_ring = { + .addr = 0x00000050, + .low_rst = 0x00000000, + .high_rst = 0x00000000, + .wm_low = &wcn3990_dst_wm_low, + .wm_high = &wcn3990_dst_wm_high, +}; + +struct ath10k_hw_ce_regs wcn3990_ce_regs = { + .sr_base_addr = 0x00000000, + .sr_size_addr = 0x00000008, + .dr_base_addr = 0x0000000c, + .dr_size_addr = 0x00000014, + .misc_ie_addr = 0x00000034, + .sr_wr_index_addr = 0x0000003c, + .dst_wr_index_addr = 0x00000040, + .current_srri_addr = 0x00000044, + .current_drri_addr = 0x00000048, + .ddr_addr_for_rri_low = 0x00000004, + .ddr_addr_for_rri_high = 0x00000008, + .ce_rri_low = 0x0024C004, + .ce_rri_high = 0x0024C008, + .host_ie_addr = 0x0000002c, + .ctrl1_regs = &wcn3990_ctrl1, + .host_ie = &wcn3990_host_ie, + .wm_regs = &wcn3990_wm_reg, + .misc_regs = &wcn3990_misc_reg, + .wm_srcr = &wcn3990_wm_src_ring, + .wm_dstr = &wcn3990_wm_dst_ring, +}; + +struct ath10k_hw_ce_regs_addr_map qcax_src_ring = { + .msb = 0x00000010, + .lsb = 0x00000010, + .mask = 0x00010000, + .set = &ath10k_set_ring_byte, +}; + +struct ath10k_hw_ce_regs_addr_map qcax_dst_ring = { + .msb = 0x00000011, + .lsb = 0x00000011, + .mask = 0x00020000, + .set = &ath10k_set_ring_byte, + .get = &ath10k_get_ring_byte, +}; + +struct ath10k_hw_ce_regs_addr_map qcax_dmax = { + .msb = 0x0000000f, + .lsb = 0x00000000, + .mask = 0x0000ffff, + .set = &ath10k_set_ring_byte, + .get = &ath10k_get_ring_byte, +}; + +struct ath10k_hw_ce_ctrl1 qcax_ctrl1 = { + .addr = 0x00000010, + .hw_mask = 0x0007ffff, + .sw_mask = 0x0007ffff, + .hw_wr_mask = 0x00000000, + .sw_wr_mask = 0x0007ffff, + .reset_mask = 0xffffffff, + .reset = 0x00000080, + .src_ring = &qcax_src_ring, + .dst_ring = &qcax_dst_ring, + .dmax = &qcax_dmax, +}; + +struct ath10k_hw_ce_regs_addr_map qcax_cmd_halt_status = { + .msb = 0x00000003, + .lsb = 0x00000003, + .mask = 0x00000008, + .set = &ath10k_set_ring_byte, + .get = &ath10k_get_ring_byte, +}; + +struct ath10k_hw_ce_cmd_halt qcax_cmd_halt = { + .msb = 0x00000000, + .mask = 0x00000001, + .status_reset = 0x00000000, + .status = &qcax_cmd_halt_status, +}; + +struct ath10k_hw_ce_regs_addr_map qcax_host_ie_cc = { + .msb = 0x00000000, + .lsb = 0x00000000, + .mask = 0x00000001, + .set = &ath10k_set_ring_byte, + .get = &ath10k_get_ring_byte, +}; + +struct ath10k_hw_ce_host_ie qcax_host_ie = { + .copy_complete_reset = 0x00000000, + .copy_complete = &qcax_host_ie_cc, +}; + +struct ath10k_hw_ce_host_wm_regs qcax_wm_reg = { + .dstr_lmask = 0x00000010, + .dstr_hmask = 0x00000008, + .srcr_lmask = 0x00000004, + .srcr_hmask = 0x00000002, + .cc_mask = 0x00000001, + .wm_mask = 0x0000001E, + .addr = 0x00000030, +}; + +struct ath10k_hw_ce_misc_regs qcax_misc_reg = { + .axi_err = 0x00000400, + .dstr_add_err = 0x00000200, + .srcr_len_err = 0x00000100, + .dstr_mlen_vio = 0x00000080, + .dstr_overflow = 0x00000040, + .srcr_overflow = 0x00000020, + .err_mask = 0x000007E0, + .addr = 0x00000038, +}; + +struct ath10k_hw_ce_regs_addr_map qcax_src_wm_low = { + .msb = 0x0000001f, + .lsb = 0x00000010, + .mask = 0xffff0000, + .set = &ath10k_set_ring_byte, + .get = &ath10k_get_ring_byte, +}; + +struct ath10k_hw_ce_regs_addr_map qcax_src_wm_high = { + .msb = 0x0000000f, + .lsb = 0x00000000, + .mask = 0x0000ffff, + .set = &ath10k_set_ring_byte, + .get = &ath10k_get_ring_byte, +}; + +struct ath10k_hw_ce_dst_src_wm_regs qcax_wm_src_ring = { + .addr = 0x0000004c, + .low_rst = 0x00000000, + .high_rst = 0x00000000, + .wm_low = &qcax_src_wm_low, + .wm_high = &qcax_src_wm_high, +}; + +struct ath10k_hw_ce_regs_addr_map qcax_dst_wm_low = { + .lsb = 0x00000010, + .mask = 0xffff0000, + .set = &ath10k_set_ring_byte, +}; + +struct ath10k_hw_ce_regs_addr_map qcax_dst_wm_high = { + .msb = 0x0000000f, + .lsb = 0x00000000, + .mask = 0x0000ffff, + .set = &ath10k_set_ring_byte, + .get = &ath10k_get_ring_byte, +}; + +struct ath10k_hw_ce_dst_src_wm_regs qcax_wm_dst_ring = { + .addr = 0x00000050, + .low_rst = 0x00000000, + .high_rst = 0x00000000, + .wm_low = &qcax_dst_wm_low, + .wm_high = &qcax_dst_wm_high, +}; + +struct ath10k_hw_ce_regs qcax_ce_regs = { + .sr_base_addr = 0x00000000, + .sr_size_addr = 0x00000004, + .dr_base_addr = 0x00000008, + .dr_size_addr = 0x0000000c, + .ce_cmd_addr = 0x00000018, + .misc_ie_addr = 0x00000034, + .sr_wr_index_addr = 0x0000003c, + .dst_wr_index_addr = 0x00000040, + .current_srri_addr = 0x00000044, + .current_drri_addr = 0x00000048, + .host_ie_addr = 0x0000002c, + .ctrl1_regs = &qcax_ctrl1, + .cmd_halt = &qcax_cmd_halt, + .host_ie = &qcax_host_ie, + .wm_regs = &qcax_wm_reg, + .misc_regs = &qcax_misc_reg, + .wm_srcr = &qcax_wm_src_ring, + .wm_dstr = &qcax_wm_dst_ring, +}; + const struct ath10k_hw_values qca988x_values = { .rtc_state_val_on = 3, .ce_count = 8, diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index ce87f8112928..0f2422480c4e 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -268,6 +268,98 @@ extern const struct ath10k_hw_regs qca99x0_regs; extern const struct ath10k_hw_regs qca4019_regs; extern const struct ath10k_hw_regs wcn3990_regs; +struct ath10k_hw_ce_regs_addr_map { + u32 msb; + u32 lsb; + u32 mask; + unsigned int (*set)(unsigned int offset, + struct ath10k_hw_ce_regs_addr_map *addr_map); + unsigned int (*get)(unsigned int offset, + struct ath10k_hw_ce_regs_addr_map *addr_map); +}; + +struct ath10k_hw_ce_ctrl1 { + u32 addr; + u32 hw_mask; + u32 sw_mask; + u32 hw_wr_mask; + u32 sw_wr_mask; + u32 reset_mask; + u32 reset; + struct ath10k_hw_ce_regs_addr_map *src_ring; + struct ath10k_hw_ce_regs_addr_map *dst_ring; + struct ath10k_hw_ce_regs_addr_map *dmax; +}; + +struct ath10k_hw_ce_cmd_halt { + u32 status_reset; + u32 msb; + u32 mask; + struct ath10k_hw_ce_regs_addr_map *status; +}; + +struct ath10k_hw_ce_host_ie { + u32 copy_complete_reset; + struct ath10k_hw_ce_regs_addr_map *copy_complete; +}; + +struct ath10k_hw_ce_host_wm_regs { + u32 dstr_lmask; + u32 dstr_hmask; + u32 srcr_lmask; + u32 srcr_hmask; + u32 cc_mask; + u32 wm_mask; + u32 addr; +}; + +struct ath10k_hw_ce_misc_regs { + u32 axi_err; + u32 dstr_add_err; + u32 srcr_len_err; + u32 dstr_mlen_vio; + u32 dstr_overflow; + u32 srcr_overflow; + u32 err_mask; + u32 addr; +}; + +struct ath10k_hw_ce_dst_src_wm_regs { + u32 addr; + u32 low_rst; + u32 high_rst; + struct ath10k_hw_ce_regs_addr_map *wm_low; + struct ath10k_hw_ce_regs_addr_map *wm_high; +}; + +struct ath10k_hw_ce_regs { + u32 sr_base_addr; + u32 sr_size_addr; + u32 dr_base_addr; + u32 dr_size_addr; + u32 ce_cmd_addr; + u32 misc_ie_addr; + u32 sr_wr_index_addr; + u32 dst_wr_index_addr; + u32 current_srri_addr; + u32 current_drri_addr; + u32 ddr_addr_for_rri_low; + u32 ddr_addr_for_rri_high; + u32 ce_rri_low; + u32 ce_rri_high; + u32 host_ie_addr; + struct ath10k_hw_ce_host_wm_regs *wm_regs; + struct ath10k_hw_ce_misc_regs *misc_regs; + struct ath10k_hw_ce_ctrl1 *ctrl1_regs; + struct ath10k_hw_ce_cmd_halt *cmd_halt; + struct ath10k_hw_ce_host_ie *host_ie; + struct ath10k_hw_ce_dst_src_wm_regs *wm_srcr; + struct ath10k_hw_ce_dst_src_wm_regs *wm_dstr; +}; + +extern struct ath10k_hw_ce_regs wcn3990_ce_regs; +extern struct ath10k_hw_ce_regs qcax_ce_regs; + extern struct fw_flag wcn3990_fw_flags; struct ath10k_hw_values { diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 210ea654c83f..acd5347f2cae 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -15,6 +15,7 @@ */ #include <linux/etherdevice.h> +#include <linux/moduleparam.h> #include "wil6210.h" #include "wmi.h" #include "ftm.h" diff --git a/drivers/pci/host/pci-msm.c b/drivers/pci/host/pci-msm.c index cd105a0bf5d1..584ad96c703f 100644 --- a/drivers/pci/host/pci-msm.c +++ b/drivers/pci/host/pci-msm.c @@ -2534,13 +2534,14 @@ static ssize_t msm_pcie_cmd_debug(struct file *file, char str[MAX_MSG_LEN]; unsigned int testcase = 0; int i; + u32 size = sizeof(str) < count ? sizeof(str) : count; - memset(str, 0, sizeof(str)); - ret = copy_from_user(str, buf, sizeof(str)); + memset(str, 0, size); + ret = copy_from_user(str, buf, size); if (ret) return -EFAULT; - for (i = 0; i < sizeof(str) && (str[i] >= '0') && (str[i] <= '9'); ++i) + for (i = 0; i < size && (str[i] >= '0') && (str[i] <= '9'); ++i) testcase = (testcase * 10) + (str[i] - '0'); if (!rc_sel) @@ -2569,13 +2570,14 @@ static ssize_t msm_pcie_set_rc_sel(struct file *file, char str[MAX_MSG_LEN]; int i; u32 new_rc_sel = 0; + u32 size = sizeof(str) < count ? sizeof(str) : count; - memset(str, 0, sizeof(str)); - ret = copy_from_user(str, buf, sizeof(str)); + memset(str, 0, size); + ret = copy_from_user(str, buf, size); if (ret) return -EFAULT; - for (i = 0; i < sizeof(str) && (str[i] >= '0') && (str[i] <= '9'); ++i) + for (i = 0; i < size && (str[i] >= '0') && (str[i] <= '9'); ++i) new_rc_sel = (new_rc_sel * 10) + (str[i] - '0'); if ((!new_rc_sel) || (new_rc_sel > rc_sel_max)) { @@ -2612,13 +2614,14 @@ static ssize_t msm_pcie_set_base_sel(struct file *file, int i; u32 new_base_sel = 0; char *base_sel_name; + u32 size = sizeof(str) < count ? sizeof(str) : count; - memset(str, 0, sizeof(str)); - ret = copy_from_user(str, buf, sizeof(str)); + memset(str, 0, size); + ret = copy_from_user(str, buf, size); if (ret) return -EFAULT; - for (i = 0; i < sizeof(str) && (str[i] >= '0') && (str[i] <= '9'); ++i) + for (i = 0; i < size && (str[i] >= '0') && (str[i] <= '9'); ++i) new_base_sel = (new_base_sel * 10) + (str[i] - '0'); if (!new_base_sel || new_base_sel > 5) { @@ -2713,14 +2716,15 @@ static ssize_t msm_pcie_set_wr_offset(struct file *file, unsigned long ret; char str[MAX_MSG_LEN]; int i; + u32 size = sizeof(str) < count ? sizeof(str) : count; - memset(str, 0, sizeof(str)); - ret = copy_from_user(str, buf, sizeof(str)); + memset(str, 0, size); + ret = copy_from_user(str, buf, size); if (ret) return -EFAULT; wr_offset = 0; - for (i = 0; i < sizeof(str) && (str[i] >= '0') && (str[i] <= '9'); ++i) + for (i = 0; i < size && (str[i] >= '0') && (str[i] <= '9'); ++i) wr_offset = (wr_offset * 10) + (str[i] - '0'); pr_alert("PCIe: wr_offset is now 0x%x\n", wr_offset); @@ -2739,14 +2743,15 @@ static ssize_t msm_pcie_set_wr_mask(struct file *file, unsigned long ret; char str[MAX_MSG_LEN]; int i; + u32 size = sizeof(str) < count ? sizeof(str) : count; - memset(str, 0, sizeof(str)); - ret = copy_from_user(str, buf, sizeof(str)); + memset(str, 0, size); + ret = copy_from_user(str, buf, size); if (ret) return -EFAULT; wr_mask = 0; - for (i = 0; i < sizeof(str) && (str[i] >= '0') && (str[i] <= '9'); ++i) + for (i = 0; i < size && (str[i] >= '0') && (str[i] <= '9'); ++i) wr_mask = (wr_mask * 10) + (str[i] - '0'); pr_alert("PCIe: wr_mask is now 0x%x\n", wr_mask); @@ -2764,14 +2769,15 @@ static ssize_t msm_pcie_set_wr_value(struct file *file, unsigned long ret; char str[MAX_MSG_LEN]; int i; + u32 size = sizeof(str) < count ? sizeof(str) : count; - memset(str, 0, sizeof(str)); - ret = copy_from_user(str, buf, sizeof(str)); + memset(str, 0, size); + ret = copy_from_user(str, buf, size); if (ret) return -EFAULT; wr_value = 0; - for (i = 0; i < sizeof(str) && (str[i] >= '0') && (str[i] <= '9'); ++i) + for (i = 0; i < size && (str[i] >= '0') && (str[i] <= '9'); ++i) wr_value = (wr_value * 10) + (str[i] - '0'); pr_alert("PCIe: wr_value is now 0x%x\n", wr_value); @@ -2890,14 +2896,15 @@ static ssize_t msm_pcie_set_corr_counter_limit(struct file *file, unsigned long ret; char str[MAX_MSG_LEN]; int i; + u32 size = sizeof(str) < count ? sizeof(str) : count; - memset(str, 0, sizeof(str)); - ret = copy_from_user(str, buf, sizeof(str)); + memset(str, 0, size); + ret = copy_from_user(str, buf, size); if (ret) return -EFAULT; corr_counter_limit = 0; - for (i = 0; i < sizeof(str) && (str[i] >= '0') && (str[i] <= '9'); ++i) + for (i = 0; i < size && (str[i] >= '0') && (str[i] <= '9'); ++i) corr_counter_limit = (corr_counter_limit * 10) + (str[i] - '0'); pr_info("PCIe: corr_counter_limit is now %lu\n", corr_counter_limit); diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v2/ipa_dp.c index 7b48991cba65..a2665c9e9688 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_dp.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_dp.c @@ -1,4 +1,4 @@ -/* 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 @@ -3147,6 +3147,8 @@ static int ipa_assign_policy_v2(struct ipa_sys_connect_params *in, IPA_GENERIC_AGGR_TIME_LIMIT; if (in->client == IPA_CLIENT_APPS_LAN_CONS) { sys->pyld_hdlr = ipa_lan_rx_pyld_hdlr; + sys->rx_pool_sz = + ipa_ctx->lan_rx_ring_size; if (nr_cpu_ids > 1) { sys->repl_hdlr = ipa_fast_replenish_rx_cache; @@ -3156,8 +3158,6 @@ static int ipa_assign_policy_v2(struct ipa_sys_connect_params *in, sys->repl_hdlr = ipa_replenish_rx_cache; } - sys->rx_pool_sz = - ipa_ctx->lan_rx_ring_size; in->ipa_ep_cfg.aggr.aggr_byte_limit = IPA_GENERIC_AGGR_BYTE_LIMIT; in->ipa_ep_cfg.aggr.aggr_pkt_limit = diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c index 9cab7e010c3a..d53121292c03 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c @@ -5161,7 +5161,8 @@ int ipa2_bind_api_controller(enum ipa_hw_type ipa_hw_type, */ u32 ipa_get_sys_yellow_wm(struct ipa_sys_context *sys) { - if (ipa_ctx->ipa_hw_type == IPA_HW_v2_6L) { + if (ipa_ctx->ipa_hw_type == IPA_HW_v2_6L && + ipa_ctx->ipa_uc_monitor_holb) { return ipa_read_reg(ipa_ctx->mmio, IPA_YELLOW_MARKER_SYS_CFG_OFST); } else { diff --git a/drivers/power/supply/qcom/Makefile b/drivers/power/supply/qcom/Makefile index dfa83f2304b2..de6c86984e3f 100644 --- a/drivers/power/supply/qcom/Makefile +++ b/drivers/power/supply/qcom/Makefile @@ -1,9 +1,9 @@ obj-$(CONFIG_QPNP_FG_GEN3) += qpnp-fg-gen3.o fg-memif.o fg-util.o obj-$(CONFIG_SMB135X_CHARGER) += smb135x-charger.o pmic-voter.o -obj-$(CONFIG_SMB1351_USB_CHARGER) += smb1351-charger.o pmic-voter.o battery.o +obj-$(CONFIG_SMB1351_USB_CHARGER) += battery.o smb1351-charger.o pmic-voter.o obj-$(CONFIG_MSM_BCL_CTL) += msm_bcl.o obj-$(CONFIG_MSM_BCL_PERIPHERAL_CTL) += bcl_peripheral.o obj-$(CONFIG_BATTERY_BCL) += battery_current_limit.o -obj-$(CONFIG_QPNP_SMB2) += qpnp-smb2.o smb-lib.o pmic-voter.o storm-watch.o battery.o -obj-$(CONFIG_SMB138X_CHARGER) += smb138x-charger.o smb-lib.o pmic-voter.o storm-watch.o battery.o -obj-$(CONFIG_QPNP_QNOVO) += qpnp-qnovo.o battery.o +obj-$(CONFIG_QPNP_SMB2) += battery.o qpnp-smb2.o smb-lib.o pmic-voter.o storm-watch.o +obj-$(CONFIG_SMB138X_CHARGER) += battery.o smb138x-charger.o smb-lib.o pmic-voter.o storm-watch.o +obj-$(CONFIG_QPNP_QNOVO) += battery.o qpnp-qnovo.o diff --git a/drivers/power/supply/qcom/qpnp-smb2.c b/drivers/power/supply/qcom/qpnp-smb2.c index 64f4d46df9a0..bf7aa7a36784 100644 --- a/drivers/power/supply/qcom/qpnp-smb2.c +++ b/drivers/power/supply/qcom/qpnp-smb2.c @@ -239,7 +239,6 @@ static struct smb_params pm660_params = { struct smb_dt_props { int fcc_ua; int usb_icl_ua; - int otg_cl_ua; int dc_icl_ua; int boost_threshold_ua; int fv_uv; @@ -323,9 +322,9 @@ static int smb2_parse_dt(struct smb2 *chip) chip->dt.usb_icl_ua = -EINVAL; rc = of_property_read_u32(node, - "qcom,otg-cl-ua", &chip->dt.otg_cl_ua); + "qcom,otg-cl-ua", &chg->otg_cl_ua); if (rc < 0) - chip->dt.otg_cl_ua = MICRO_1P5A; + chg->otg_cl_ua = MICRO_1P5A; rc = of_property_read_u32(node, "qcom,dc-icl-ua", &chip->dt.dc_icl_ua); @@ -1386,7 +1385,8 @@ static int smb2_init_hw(struct smb2 *chip) /* set OTG current limit */ rc = smblib_set_charge_param(chg, &chg->param.otg_cl, - chip->dt.otg_cl_ua); + (chg->wa_flags & OTG_WA) ? + chg->param.otg_cl.min_u : chg->otg_cl_ua); if (rc < 0) { pr_err("Couldn't set otg current limit rc=%d\n", rc); return rc; @@ -1649,7 +1649,7 @@ static int smb2_chg_config_init(struct smb2 *chip) break; case PM660_SUBTYPE: chip->chg.smb_version = PM660_SUBTYPE; - chip->chg.wa_flags |= BOOST_BACK_WA; + chip->chg.wa_flags |= BOOST_BACK_WA | OTG_WA; chg->param.freq_buck = pm660_params.freq_buck; chg->param.freq_boost = pm660_params.freq_boost; chg->chg_freq.freq_5V = 600; diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c index a8427c5e3107..4090bea62044 100644 --- a/drivers/power/supply/qcom/smb-lib.c +++ b/drivers/power/supply/qcom/smb-lib.c @@ -548,6 +548,26 @@ static int smblib_set_usb_pd_allowed_voltage(struct smb_charger *chg, * HELPER FUNCTIONS * ********************/ +static void smblib_rerun_apsd(struct smb_charger *chg) +{ + int rc; + + smblib_dbg(chg, PR_MISC, "re-running APSD\n"); + if (chg->wa_flags & QC_AUTH_INTERRUPT_WA_BIT) { + rc = smblib_masked_write(chg, + USBIN_SOURCE_CHANGE_INTRPT_ENB_REG, + AUTH_IRQ_EN_CFG_BIT, AUTH_IRQ_EN_CFG_BIT); + if (rc < 0) + smblib_err(chg, "Couldn't enable HVDCP auth IRQ rc=%d\n", + rc); + } + + rc = smblib_masked_write(chg, CMD_APSD_REG, + APSD_RERUN_BIT, APSD_RERUN_BIT); + if (rc < 0) + smblib_err(chg, "Couldn't re-run APSD rc=%d\n", rc); +} + static int try_rerun_apsd_for_hvdcp(struct smb_charger *chg) { const struct apsd_result *apsd_result; @@ -565,11 +585,7 @@ static int try_rerun_apsd_for_hvdcp(struct smb_charger *chg) chg->hvdcp_disable_votable_indirect)) { apsd_result = smblib_get_apsd_result(chg); if (apsd_result->bit & (QC_2P0_BIT | QC_3P0_BIT)) { - /* rerun APSD */ - smblib_dbg(chg, PR_MISC, "rerun APSD\n"); - smblib_masked_write(chg, CMD_APSD_REG, - APSD_RERUN_BIT, - APSD_RERUN_BIT); + smblib_rerun_apsd(chg); } } } @@ -581,12 +597,13 @@ static const struct apsd_result *smblib_update_usb_type(struct smb_charger *chg) const struct apsd_result *apsd_result = smblib_get_apsd_result(chg); /* if PD is active, APSD is disabled so won't have a valid result */ - if (chg->pd_active) { + if (chg->pd_active) chg->usb_psy_desc.type = POWER_SUPPLY_TYPE_USB_PD; - return apsd_result; - } + else + chg->usb_psy_desc.type = apsd_result->pst; - chg->usb_psy_desc.type = apsd_result->pst; + smblib_dbg(chg, PR_MISC, "APSD=%s PD=%d\n", + apsd_result->name, chg->pd_active); return apsd_result; } @@ -764,16 +781,7 @@ int smblib_rerun_apsd_if_required(struct smb_charger *chg) apsd_result = smblib_get_apsd_result(chg); if ((apsd_result->pst == POWER_SUPPLY_TYPE_UNKNOWN) || (apsd_result->pst == POWER_SUPPLY_TYPE_USB)) { - /* rerun APSD */ - pr_info("Reruning APSD type = %s at bootup\n", - apsd_result->name); - rc = smblib_masked_write(chg, CMD_APSD_REG, - APSD_RERUN_BIT, - APSD_RERUN_BIT); - if (rc < 0) { - smblib_err(chg, "Couldn't rerun APSD rc = %d\n", rc); - return rc; - } + smblib_rerun_apsd(chg); } return 0; @@ -1282,11 +1290,14 @@ int smblib_vconn_regulator_is_enabled(struct regulator_dev *rdev) /***************** * OTG REGULATOR * *****************/ - +#define MAX_RETRY 15 +#define MIN_DELAY_US 2000 +#define MAX_DELAY_US 9000 static int _smblib_vbus_regulator_enable(struct regulator_dev *rdev) { struct smb_charger *chg = rdev_get_drvdata(rdev); - int rc; + int rc, retry_count = 0, min_delay = MIN_DELAY_US; + u8 stat; smblib_dbg(chg, PR_OTG, "halt 1 in 8 mode\n"); rc = smblib_masked_write(chg, OTG_ENG_OTG_CFG_REG, @@ -1305,6 +1316,42 @@ static int _smblib_vbus_regulator_enable(struct regulator_dev *rdev) return rc; } + if (chg->wa_flags & OTG_WA) { + /* check for softstart */ + do { + usleep_range(min_delay, min_delay + 100); + rc = smblib_read(chg, OTG_STATUS_REG, &stat); + if (rc < 0) { + smblib_err(chg, + "Couldn't read OTG status rc=%d\n", + rc); + goto out; + } + + if (stat & BOOST_SOFTSTART_DONE_BIT) { + rc = smblib_set_charge_param(chg, + &chg->param.otg_cl, chg->otg_cl_ua); + if (rc < 0) + smblib_err(chg, + "Couldn't set otg limit\n"); + break; + } + + /* increase the delay for following iterations */ + if (retry_count > 5) + min_delay = MAX_DELAY_US; + } while (retry_count++ < MAX_RETRY); + + if (retry_count >= MAX_RETRY) { + smblib_dbg(chg, PR_OTG, "Boost Softstart not done\n"); + goto out; + } + } + + return 0; +out: + /* disable OTG if softstart failed */ + smblib_write(chg, CMD_OTG_REG, 0); return rc; } @@ -1338,6 +1385,17 @@ static int _smblib_vbus_regulator_disable(struct regulator_dev *rdev) smblib_err(chg, "Couldn't disable VCONN rc=%d\n", rc); } + if (chg->wa_flags & OTG_WA) { + /* set OTG current limit to minimum value */ + rc = smblib_set_charge_param(chg, &chg->param.otg_cl, + chg->param.otg_cl.min_u); + if (rc < 0) { + smblib_err(chg, + "Couldn't set otg current limit rc=%d\n", rc); + return rc; + } + } + smblib_dbg(chg, PR_OTG, "disabling OTG\n"); rc = smblib_write(chg, CMD_OTG_REG, 0); if (rc < 0) { @@ -1346,7 +1404,6 @@ static int _smblib_vbus_regulator_disable(struct regulator_dev *rdev) } smblib_dbg(chg, PR_OTG, "start 1 in 8 mode\n"); - rc = smblib_write(chg, CMD_OTG_REG, 0); rc = smblib_masked_write(chg, OTG_ENG_OTG_CFG_REG, ENG_BUCKBOOST_HALT1_8_MODE_BIT, 0); if (rc < 0) { @@ -2947,6 +3004,14 @@ irqreturn_t smblib_handle_otg_overcurrent(int irq, void *data) return IRQ_HANDLED; } + if (chg->wa_flags & OTG_WA) { + if (stat & OTG_OC_DIS_SW_STS_RT_STS_BIT) + smblib_err(chg, "OTG disabled by hw\n"); + + /* not handling software based hiccups for PM660 */ + return IRQ_HANDLED; + } + if (stat & OTG_OVERCURRENT_RT_STS_BIT) schedule_work(&chg->otg_oc_work); @@ -3162,6 +3227,7 @@ irqreturn_t smblib_handle_icl_change(int irq, void *data) || (stat & AICL_DONE_BIT)) delay = 0; + cancel_delayed_work_sync(&chg->icl_change_work); schedule_delayed_work(&chg->icl_change_work, msecs_to_jiffies(delay)); } @@ -3271,11 +3337,22 @@ static void smblib_handle_hvdcp_3p0_auth_done(struct smb_charger *chg, if (chg->mode == PARALLEL_MASTER) vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, true, 0); + /* the APSD done handler will set the USB supply type */ + apsd_result = smblib_get_apsd_result(chg); + if (get_effective_result(chg->hvdcp_hw_inov_dis_votable)) { + if (apsd_result->pst == POWER_SUPPLY_TYPE_USB_HVDCP) { + /* force HVDCP2 to 9V if INOV is disabled */ + rc = smblib_masked_write(chg, CMD_HVDCP_2_REG, + FORCE_9V_BIT, FORCE_9V_BIT); + if (rc < 0) + smblib_err(chg, + "Couldn't force 9V HVDCP rc=%d\n", rc); + } + } + /* QC authentication done, parallel charger can be enabled now */ vote(chg->pl_disable_votable, PL_DELAY_HVDCP_VOTER, false, 0); - /* the APSD done handler will set the USB supply type */ - apsd_result = smblib_get_apsd_result(chg); smblib_dbg(chg, PR_INTERRUPT, "IRQ: hvdcp-3p0-auth-done rising; %s detected\n", apsd_result->name); } diff --git a/drivers/power/supply/qcom/smb-lib.h b/drivers/power/supply/qcom/smb-lib.h index 21ccd3ce57c7..d6afca010502 100644 --- a/drivers/power/supply/qcom/smb-lib.h +++ b/drivers/power/supply/qcom/smb-lib.h @@ -80,6 +80,7 @@ enum { BOOST_BACK_WA = BIT(1), TYPEC_CC2_REMOVAL_WA_BIT = BIT(2), QC_AUTH_INTERRUPT_WA_BIT = BIT(3), + OTG_WA = BIT(4), }; enum smb_irq_index { @@ -305,6 +306,7 @@ struct smb_charger { int otg_attempts; int vconn_attempts; int default_icl_ua; + int otg_cl_ua; /* workaround flag */ u32 wa_flags; diff --git a/drivers/regulator/qpnp-lcdb-regulator.c b/drivers/regulator/qpnp-lcdb-regulator.c index 19b1d319ef45..aef28dbeb931 100644 --- a/drivers/regulator/qpnp-lcdb-regulator.c +++ b/drivers/regulator/qpnp-lcdb-regulator.c @@ -16,6 +16,7 @@ #include <linux/delay.h> #include <linux/device.h> #include <linux/interrupt.h> +#include <linux/ktime.h> #include <linux/module.h> #include <linux/of_irq.h> #include <linux/platform_device.h> @@ -31,6 +32,13 @@ #define INT_RT_STATUS_REG 0x10 #define VREG_OK_RT_STS_BIT BIT(0) +#define SC_ERROR_RT_STS_BIT BIT(1) + +#define LCDB_STS3_REG 0x0A +#define LDO_VREG_OK_BIT BIT(7) + +#define LCDB_STS4_REG 0x0B +#define NCP_VREG_OK_BIT BIT(7) #define LCDB_AUTO_TOUCH_WAKE_CTL_REG 0x40 #define EN_AUTO_TOUCH_WAKE_BIT BIT(7) @@ -185,6 +193,7 @@ struct qpnp_lcdb { struct platform_device *pdev; struct regmap *regmap; u32 base; + int sc_irq; /* TTW params */ bool ttw_enable; @@ -196,6 +205,9 @@ struct qpnp_lcdb { /* status parameters */ bool lcdb_enabled; bool settings_saved; + bool lcdb_sc_disable; + int sc_count; + ktime_t sc_module_enable_time; struct mutex lcdb_mutex; struct mutex read_write_mutex; @@ -572,8 +584,11 @@ static int qpnp_lcdb_enable(struct qpnp_lcdb *lcdb) int rc = 0, timeout, delay; u8 val = 0; - if (lcdb->lcdb_enabled) + if (lcdb->lcdb_enabled || lcdb->lcdb_sc_disable) { + pr_debug("lcdb_enabled=%d lcdb_sc_disable=%d\n", + lcdb->lcdb_enabled, lcdb->lcdb_sc_disable); return 0; + } if (lcdb->ttw_enable) { rc = qpnp_lcdb_ttw_exit(lcdb); @@ -676,6 +691,111 @@ static int qpnp_lcdb_disable(struct qpnp_lcdb *lcdb) return rc; } +#define LCDB_SC_RESET_CNT_DLY_US 1000000 +#define LCDB_SC_CNT_MAX 10 +static int qpnp_lcdb_handle_sc_event(struct qpnp_lcdb *lcdb) +{ + int rc = 0; + s64 elapsed_time_us; + + mutex_lock(&lcdb->lcdb_mutex); + rc = qpnp_lcdb_disable(lcdb); + if (rc < 0) { + pr_err("Failed to disable lcdb rc=%d\n", rc); + goto unlock_mutex; + } + + /* Check if the SC re-occurred immediately */ + elapsed_time_us = ktime_us_delta(ktime_get(), + lcdb->sc_module_enable_time); + if (elapsed_time_us > LCDB_SC_RESET_CNT_DLY_US) { + lcdb->sc_count = 0; + } else if (lcdb->sc_count > LCDB_SC_CNT_MAX) { + pr_err("SC trigged %d times, disabling LCDB forever!\n", + lcdb->sc_count); + lcdb->lcdb_sc_disable = true; + goto unlock_mutex; + } + lcdb->sc_count++; + lcdb->sc_module_enable_time = ktime_get(); + + /* delay for SC to clear */ + usleep_range(10000, 10100); + + rc = qpnp_lcdb_enable(lcdb); + if (rc < 0) + pr_err("Failed to enable lcdb rc=%d\n", rc); + +unlock_mutex: + mutex_unlock(&lcdb->lcdb_mutex); + return rc; +} + +static irqreturn_t qpnp_lcdb_sc_irq_handler(int irq, void *data) +{ + struct qpnp_lcdb *lcdb = data; + int rc; + u8 val, val2[2] = {0}; + + rc = qpnp_lcdb_read(lcdb, lcdb->base + INT_RT_STATUS_REG, &val, 1); + if (rc < 0) + goto irq_handled; + + if (val & SC_ERROR_RT_STS_BIT) { + rc = qpnp_lcdb_read(lcdb, + lcdb->base + LCDB_MISC_CTL_REG, &val, 1); + if (rc < 0) + goto irq_handled; + + if (val & EN_TOUCH_WAKE_BIT) { + /* blanking time */ + usleep_range(300, 310); + /* + * The status registers need to written with any value + * before reading + */ + rc = qpnp_lcdb_write(lcdb, + lcdb->base + LCDB_STS3_REG, val2, 2); + if (rc < 0) + goto irq_handled; + + rc = qpnp_lcdb_read(lcdb, + lcdb->base + LCDB_STS3_REG, val2, 2); + if (rc < 0) + goto irq_handled; + + if (!(val2[0] & LDO_VREG_OK_BIT) || + !(val2[1] & NCP_VREG_OK_BIT)) { + rc = qpnp_lcdb_handle_sc_event(lcdb); + if (rc < 0) { + pr_err("Failed to handle SC rc=%d\n", + rc); + goto irq_handled; + } + } + } else { + /* blanking time */ + usleep_range(2000, 2100); + /* Read the SC status again to confirm true SC */ + rc = qpnp_lcdb_read(lcdb, + lcdb->base + INT_RT_STATUS_REG, &val, 1); + if (rc < 0) + goto irq_handled; + + if (val & SC_ERROR_RT_STS_BIT) { + rc = qpnp_lcdb_handle_sc_event(lcdb); + if (rc < 0) { + pr_err("Failed to handle SC rc=%d\n", + rc); + goto irq_handled; + } + } + } + } +irq_handled: + return IRQ_HANDLED; +} + #define MIN_BST_VOLTAGE_MV 4700 #define MAX_BST_VOLTAGE_MV 6250 #define MIN_VOLTAGE_MV 4000 @@ -1554,6 +1674,18 @@ static int qpnp_lcdb_hw_init(struct qpnp_lcdb *lcdb) return rc; } + if (lcdb->sc_irq >= 0) { + lcdb->sc_count = 0; + rc = devm_request_threaded_irq(lcdb->dev, lcdb->sc_irq, + NULL, qpnp_lcdb_sc_irq_handler, IRQF_ONESHOT, + "qpnp_lcdb_sc_irq", lcdb); + if (rc < 0) { + pr_err("Unable to request sc(%d) irq rc=%d\n", + lcdb->sc_irq, rc); + return rc; + } + } + if (!is_lcdb_enabled(lcdb)) { rc = qpnp_lcdb_read(lcdb, lcdb->base + LCDB_MODULE_RDY_REG, &val, 1); @@ -1622,6 +1754,10 @@ static int qpnp_lcdb_parse_dt(struct qpnp_lcdb *lcdb) lcdb->ttw_enable = true; } + lcdb->sc_irq = platform_get_irq_byname(lcdb->pdev, "sc-irq"); + if (lcdb->sc_irq < 0) + pr_debug("sc irq is not defined\n"); + return rc; } diff --git a/drivers/soc/qcom/glink.c b/drivers/soc/qcom/glink.c index 09c50a81a943..cc809cbdd839 100644 --- a/drivers/soc/qcom/glink.c +++ b/drivers/soc/qcom/glink.c @@ -4187,7 +4187,6 @@ static void glink_core_channel_cleanup(struct glink_core_xprt_ctx *xprt_ptr) if (ctx->local_open_state == GLINK_CHANNEL_OPENED || ctx->local_open_state == GLINK_CHANNEL_OPENING) { ctx->transport_ptr = dummy_xprt_ctx; - rwref_write_put(&ctx->ch_state_lhb2); glink_core_move_ch_node(xprt_ptr, dummy_xprt_ctx, ctx); } else { /* local state is in either CLOSED or CLOSING */ @@ -4197,9 +4196,9 @@ static void glink_core_channel_cleanup(struct glink_core_xprt_ctx *xprt_ptr) /* Channel should be fully closed now. Delete here */ if (ch_is_fully_closed(ctx)) glink_delete_ch_from_list(ctx, false); - rwref_write_put(&ctx->ch_state_lhb2); } rwref_put(&ctx->ch_state_lhb2); + rwref_write_put(&ctx->ch_state_lhb2); ctx = get_first_ch_ctx(xprt_ptr); } spin_lock_irqsave(&xprt_ptr->xprt_ctx_lock_lhb1, flags); diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c index 4e541773c805..0a68eaf79e60 100644 --- a/drivers/soc/qcom/icnss.c +++ b/drivers/soc/qcom/icnss.c @@ -213,7 +213,7 @@ struct icnss_clk_info { }; static struct icnss_vreg_info icnss_vreg_info[] = { - {NULL, "vdd-0.8-cx-mx", 800000, 800000, 0, 0, true}, + {NULL, "vdd-0.8-cx-mx", 800000, 800000, 0, 0, false}, {NULL, "vdd-1.8-xo", 1800000, 1800000, 0, 0, false}, {NULL, "vdd-1.3-rfa", 1304000, 1304000, 0, 0, false}, {NULL, "vdd-3.3-ch0", 3312000, 3312000, 0, 0, false}, diff --git a/drivers/soc/qcom/qdsp6v2/voice_svc.c b/drivers/soc/qcom/qdsp6v2/voice_svc.c index 10f71b85a15b..fe5458974406 100644 --- a/drivers/soc/qcom/qdsp6v2/voice_svc.c +++ b/drivers/soc/qcom/qdsp6v2/voice_svc.c @@ -368,6 +368,9 @@ static ssize_t voice_svc_write(struct file *file, const char __user *buf, struct voice_svc_prvt *prtd; struct voice_svc_write_msg *data = NULL; uint32_t cmd; + struct voice_svc_register *register_data = NULL; + struct voice_svc_cmd_request *request_data = NULL; + uint32_t request_payload_size; pr_debug("%s\n", __func__); @@ -416,12 +419,19 @@ static ssize_t voice_svc_write(struct file *file, const char __user *buf, */ if (count == (sizeof(struct voice_svc_write_msg) + sizeof(struct voice_svc_register))) { - ret = process_reg_cmd( - (struct voice_svc_register *)data->payload, prtd); + register_data = + (struct voice_svc_register *)data->payload; + if (register_data == NULL) { + pr_err("%s: register data is NULL", __func__); + ret = -EINVAL; + goto done; + } + ret = process_reg_cmd(register_data, prtd); if (!ret) ret = count; } else { - pr_err("%s: invalid payload size\n", __func__); + pr_err("%s: invalid data payload size for register command\n", + __func__); ret = -EINVAL; goto done; } @@ -430,19 +440,40 @@ static ssize_t voice_svc_write(struct file *file, const char __user *buf, /* * Check that count reflects the expected size to ensure * sufficient memory was allocated. Since voice_svc_cmd_request - * has a variable size, check the minimum value count must be. + * has a variable size, check the minimum value count must be to + * parse the message request then check the minimum size to hold + * the payload of the message request. */ if (count >= (sizeof(struct voice_svc_write_msg) + sizeof(struct voice_svc_cmd_request))) { - ret = voice_svc_send_req( - (struct voice_svc_cmd_request *)data->payload, prtd); - if (!ret) - ret = count; - } else { - pr_err("%s: invalid payload size\n", __func__); - ret = -EINVAL; - goto done; - } + request_data = + (struct voice_svc_cmd_request *)data->payload; + if (request_data == NULL) { + pr_err("%s: request data is NULL", __func__); + ret = -EINVAL; + goto done; + } + + request_payload_size = request_data->payload_size; + + if (count >= (sizeof(struct voice_svc_write_msg) + + sizeof(struct voice_svc_cmd_request) + + request_payload_size)) { + ret = voice_svc_send_req(request_data, prtd); + if (!ret) + ret = count; + } else { + pr_err("%s: invalid request payload size\n", + __func__); + ret = -EINVAL; + goto done; + } + } else { + pr_err("%s: invalid data payload size for request command\n", + __func__); + ret = -EINVAL; + goto done; + } break; default: pr_debug("%s: Invalid command: %u\n", __func__, cmd); diff --git a/drivers/soc/qcom/service-notifier.c b/drivers/soc/qcom/service-notifier.c index c1c65cd25558..ebea5b7726e4 100644 --- a/drivers/soc/qcom/service-notifier.c +++ b/drivers/soc/qcom/service-notifier.c @@ -99,6 +99,7 @@ struct ind_req_resp { */ struct qmi_client_info { int instance_id; + int subsys_state; struct work_struct svc_arrive; struct work_struct svc_exit; struct work_struct svc_rcv_msg; @@ -436,7 +437,7 @@ static void root_service_exit_work(struct work_struct *work) { struct qmi_client_info *data = container_of(work, struct qmi_client_info, svc_exit); - root_service_service_exit(data, ROOT_PD_DOWN); + root_service_service_exit(data, data->subsys_state); } static int service_event_notify(struct notifier_block *this, @@ -453,6 +454,7 @@ static int service_event_notify(struct notifier_block *this, break; case QMI_SERVER_EXIT: pr_debug("Root PD service DOWN\n"); + data->subsys_state = ROOT_PD_DOWN; queue_work(data->svc_event_wq, &data->svc_exit); break; default: @@ -468,7 +470,6 @@ static int ssr_event_notify(struct notifier_block *this, struct qmi_client_info *info = container_of(this, struct qmi_client_info, ssr_notifier); struct notif_data *notif = data; - enum pd_subsys_state state; switch (code) { case SUBSYS_BEFORE_SHUTDOWN: @@ -476,16 +477,16 @@ static int ssr_event_notify(struct notifier_block *this, notif->crashed); switch (notif->crashed) { case CRASH_STATUS_ERR_FATAL: - state = ROOT_PD_ERR_FATAL; + info->subsys_state = ROOT_PD_ERR_FATAL; break; case CRASH_STATUS_WDOG_BITE: - state = ROOT_PD_WDOG_BITE; + info->subsys_state = ROOT_PD_WDOG_BITE; break; default: - state = ROOT_PD_SHUTDOWN; + info->subsys_state = ROOT_PD_SHUTDOWN; break; } - root_service_service_exit(info, state); + queue_work(info->svc_event_wq, &info->svc_exit); break; default: break; diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 018f539054fe..9d795489c285 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -1942,7 +1942,9 @@ unknown: if (value < 0) { DBG(cdev, "ep_queue --> %d\n", value); req->status = 0; - composite_setup_complete(gadget->ep0, req); + if (value != -ESHUTDOWN) + composite_setup_complete(gadget->ep0, + req); } return value; } @@ -2031,7 +2033,8 @@ try_fun_setup: if (value < 0) { DBG(cdev, "ep_queue --> %d\n", value); req->status = 0; - composite_setup_complete(gadget->ep0, req); + if (value != -ESHUTDOWN) + composite_setup_complete(gadget->ep0, req); } } else if (value == USB_GADGET_DELAYED_STATUS && w_length != 0) { WARN(cdev, @@ -2467,6 +2470,7 @@ void usb_composite_setup_continue(struct usb_composite_dev *cdev) } spin_unlock_irqrestore(&cdev->lock, flags); WARN(cdev, "%s: Unexpected call\n", __func__); + return; } else if (--cdev->delayed_status == 0) { DBG(cdev, "%s: Completing delayed status\n", __func__); diff --git a/drivers/usb/gadget/function/f_midi.c b/drivers/usb/gadget/function/f_midi.c index 8919cc26b98e..5bcff5d2cd8d 100644 --- a/drivers/usb/gadget/function/f_midi.c +++ b/drivers/usb/gadget/function/f_midi.c @@ -1160,7 +1160,7 @@ static void f_midi_unbind(struct usb_configuration *c, struct usb_function *f) card = midi->card; midi->card = NULL; if (card) - snd_card_free(card); + snd_card_free_when_closed(card); usb_free_all_descriptors(f); } diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 098df6ced1c3..8e5ab373dce9 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -1476,6 +1476,8 @@ int xhci_endpoint_init(struct xhci_hcd *xhci, } break; case USB_SPEED_FULL: + if (usb_endpoint_xfer_bulk(&ep->desc) && max_packet < 8) + max_packet = 8; case USB_SPEED_LOW: break; default: diff --git a/drivers/video/fbdev/msm/mdss_dsi_host.c b/drivers/video/fbdev/msm/mdss_dsi_host.c index d57558a1b52d..734d3bee8fd0 100644 --- a/drivers/video/fbdev/msm/mdss_dsi_host.c +++ b/drivers/video/fbdev/msm/mdss_dsi_host.c @@ -41,6 +41,8 @@ #define LANE_SWAP_CTRL 0x0B0 #define LOGICAL_LANE_SWAP_CTRL 0x310 +#define CEIL(x, y) (((x) + ((y)-1)) / (y)) + struct mdss_dsi_ctrl_pdata *ctrl_list[DSI_CTRL_MAX]; struct mdss_hw mdss_dsi0_hw = { @@ -1423,6 +1425,35 @@ void mdss_dsi_ctrl_setup(struct mdss_dsi_ctrl_pdata *ctrl) mdss_dsi_op_mode_config(pdata->panel_info.mipi.mode, pdata); } +static int mdss_dsi_wait4video_eng_busy(struct mdss_dsi_ctrl_pdata *ctrl) +{ + int ret = 0; + u32 v_total = 0, v_blank = 0, sleep_ms = 0, fps = 0; + struct mdss_panel_info *pinfo = &ctrl->panel_data.panel_info; + + if (ctrl->panel_mode == DSI_CMD_MODE) + return ret; + + if (ctrl->ctrl_state & CTRL_STATE_MDP_ACTIVE) { + mdss_dsi_wait4video_done(ctrl); + v_total = mdss_panel_get_vtotal(pinfo); + v_blank = pinfo->lcdc.v_back_porch + pinfo->lcdc.v_front_porch + + pinfo->lcdc.v_pulse_width; + if (pinfo->dynamic_fps && pinfo->current_fps) + fps = pinfo->current_fps; + else + fps = pinfo->mipi.frame_rate; + + sleep_ms = CEIL((v_blank * 1000), (v_total * fps)) + 1; + /* delay sleep_ms to skip BLLP */ + if (sleep_ms) + udelay(sleep_ms * 1000); + ret = 1; + } + + return ret; +} + /** * mdss_dsi_bta_status_check() - Check dsi panel status through bta check * @ctrl_pdata: pointer to the dsi controller structure @@ -1463,6 +1494,7 @@ int mdss_dsi_bta_status_check(struct mdss_dsi_ctrl_pdata *ctrl_pdata) reinit_completion(&ctrl_pdata->bta_comp); mdss_dsi_enable_irq(ctrl_pdata, DSI_BTA_TERM); spin_unlock_irqrestore(&ctrl_pdata->mdp_lock, flag); + mdss_dsi_wait4video_eng_busy(ctrl_pdata); /* mask out overflow errors */ if (ignore_underflow) mdss_dsi_set_reg(ctrl_pdata, 0x10c, 0x0f0000, 0x0f0000); @@ -2348,15 +2380,20 @@ void mdss_dsi_wait4video_done(struct mdss_dsi_ctrl_pdata *ctrl) /* DSI_INTL_CTRL */ data = MIPI_INP((ctrl->ctrl_base) + 0x0110); data &= DSI_INTR_TOTAL_MASK; - data |= DSI_INTR_VIDEO_DONE_MASK; - MIPI_OUTP((ctrl->ctrl_base) + 0x0110, data); + /* clear previous VIDEO_DONE interrupt */ + MIPI_OUTP((ctrl->ctrl_base) + 0x0110, (data | DSI_INTR_VIDEO_DONE)); + wmb(); /* ensure interrupt is cleared */ spin_lock_irqsave(&ctrl->mdp_lock, flag); reinit_completion(&ctrl->video_comp); mdss_dsi_enable_irq(ctrl, DSI_VIDEO_TERM); spin_unlock_irqrestore(&ctrl->mdp_lock, flag); + data |= DSI_INTR_VIDEO_DONE_MASK; + MIPI_OUTP((ctrl->ctrl_base) + 0x0110, data); + wmb(); /* ensure interrupt is enabled */ + wait_for_completion_timeout(&ctrl->video_comp, msecs_to_jiffies(VSYNC_PERIOD * 4)); @@ -2366,23 +2403,6 @@ void mdss_dsi_wait4video_done(struct mdss_dsi_ctrl_pdata *ctrl) MIPI_OUTP((ctrl->ctrl_base) + 0x0110, data); } -static int mdss_dsi_wait4video_eng_busy(struct mdss_dsi_ctrl_pdata *ctrl) -{ - int ret = 0; - - if (ctrl->panel_mode == DSI_CMD_MODE) - return ret; - - if (ctrl->ctrl_state & CTRL_STATE_MDP_ACTIVE) { - mdss_dsi_wait4video_done(ctrl); - /* delay 4 ms to skip BLLP */ - usleep_range(4000, 4000); - ret = 1; - } - - return ret; -} - void mdss_dsi_cmd_mdp_start(struct mdss_dsi_ctrl_pdata *ctrl) { unsigned long flag; diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_video.c b/drivers/video/fbdev/msm/mdss_mdp_intf_video.c index 5173567a3420..97be2fd728c8 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_intf_video.c +++ b/drivers/video/fbdev/msm/mdss_mdp_intf_video.c @@ -449,7 +449,7 @@ static void mdss_mdp_video_avr_vtotal_setup(struct mdss_mdp_ctl *ctl, if (sctl) sctx = (struct mdss_mdp_video_ctx *) sctl->intf_ctx[MASTER_CTX]; - mdss_mdp_video_timegen_flush(ctl, ctx); + mdss_mdp_video_timegen_flush(ctl, sctx); MDSS_XLOG(pinfo->min_fps, pinfo->default_fps, avr_vtotal); } @@ -1671,7 +1671,7 @@ int mdss_mdp_video_reconfigure_splash_done(struct mdss_mdp_ctl *ctl, struct mdss_panel_data *pdata; int i, ret = 0, off; u32 data, flush; - struct mdss_mdp_video_ctx *ctx; + struct mdss_mdp_video_ctx *ctx, *sctx = NULL; struct mdss_mdp_ctl *sctl; if (!ctl) { @@ -1695,10 +1695,13 @@ int mdss_mdp_video_reconfigure_splash_done(struct mdss_mdp_ctl *ctl, pdata->panel_info.cont_splash_enabled = 0; sctl = mdss_mdp_get_split_ctl(ctl); - if (sctl) + if (sctl) { sctl->panel_data->panel_info.cont_splash_enabled = 0; - else if (ctl->panel_data->next && is_pingpong_split(ctl->mfd)) + sctx = (struct mdss_mdp_video_ctx *) sctl->intf_ctx[MASTER_CTX]; + } else if (ctl->panel_data->next && is_pingpong_split(ctl->mfd)) { ctl->panel_data->next->panel_info.cont_splash_enabled = 0; + sctx = (struct mdss_mdp_video_ctx *) ctl->intf_ctx[SLAVE_CTX]; + } if (!handoff) { ret = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_CONT_SPLASH_BEGIN, @@ -1724,6 +1727,8 @@ int mdss_mdp_video_reconfigure_splash_done(struct mdss_mdp_ctl *ctl, mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_FLUSH, flush); mdp_video_write(ctx, MDSS_MDP_REG_INTF_TIMING_ENGINE_EN, 0); + mdss_mdp_video_timegen_flush(ctl, sctx); + /* wait for 1 VSYNC for the pipe to be unstaged */ msleep(20); diff --git a/drivers/video/fbdev/msm/mdss_mdp_overlay.c b/drivers/video/fbdev/msm/mdss_mdp_overlay.c index 5d80c80ebcef..9e295815da77 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_overlay.c +++ b/drivers/video/fbdev/msm/mdss_mdp_overlay.c @@ -519,6 +519,102 @@ static int __mdss_mdp_validate_pxl_extn(struct mdss_mdp_pipe *pipe) return 0; } +static int __mdss_mdp_validate_qseed3_cfg(struct mdss_mdp_pipe *pipe) +{ + int plane; + + for (plane = 0; plane < MAX_PLANES; plane++) { + u32 hor_req_pixels, hor_fetch_pixels; + u32 hor_ov_fetch, vert_ov_fetch; + u32 vert_req_pixels, vert_fetch_pixels; + u32 src_w = DECIMATED_DIMENSION(pipe->src.w, pipe->horz_deci); + u32 src_h = DECIMATED_DIMENSION(pipe->src.h, pipe->vert_deci); + + /* + * plane 1 and 2 are for chroma and are same. While configuring + * HW, programming only one of the chroma components is + * sufficient. + */ + if (plane == 2) + continue; + + /* + * For chroma plane, width is half for the following sub sampled + * formats. Except in case of decimation, where hardware avoids + * 1 line of decimation instead of downsampling. + */ + if (plane == 1 && !pipe->horz_deci && + ((pipe->src_fmt->chroma_sample == MDSS_MDP_CHROMA_420) || + (pipe->src_fmt->chroma_sample == MDSS_MDP_CHROMA_H2V1))) { + src_w >>= 1; + } + + if (plane == 1 && !pipe->vert_deci && + ((pipe->src_fmt->chroma_sample == MDSS_MDP_CHROMA_420) || + (pipe->src_fmt->chroma_sample == MDSS_MDP_CHROMA_H1V2))) + src_h >>= 1; + + hor_req_pixels = pipe->scaler.num_ext_pxls_left[plane]; + + hor_fetch_pixels = src_w + + (pipe->scaler.left_ftch[plane] >> pipe->horz_deci) + + pipe->scaler.left_rpt[plane] + + (pipe->scaler.right_ftch[plane] >> pipe->horz_deci) + + pipe->scaler.right_rpt[plane]; + + hor_ov_fetch = src_w + + (pipe->scaler.left_ftch[plane] >> pipe->horz_deci) + + (pipe->scaler.right_ftch[plane] >> pipe->horz_deci); + + vert_req_pixels = pipe->scaler.num_ext_pxls_top[plane]; + + vert_fetch_pixels = src_h + + (pipe->scaler.top_ftch[plane] >> pipe->vert_deci) + + pipe->scaler.top_rpt[plane] + + (pipe->scaler.btm_ftch[plane] >> pipe->vert_deci) + + pipe->scaler.btm_rpt[plane]; + + vert_ov_fetch = src_h + + (pipe->scaler.top_ftch[plane] >> pipe->vert_deci) + + (pipe->scaler.btm_ftch[plane] >> pipe->vert_deci); + + if ((hor_req_pixels != hor_fetch_pixels) || + (hor_ov_fetch > pipe->img_width) || + (vert_req_pixels != vert_fetch_pixels) || + (vert_ov_fetch > pipe->img_height)) { + pr_err("err: plane=%d h_req:%d h_fetch:%d v_req:%d v_fetch:%d src_img[%d %d] ov_fetch[%d %d]\n", + + plane, + hor_req_pixels, hor_fetch_pixels, + vert_req_pixels, vert_fetch_pixels, + pipe->img_width, pipe->img_height, + hor_ov_fetch, vert_ov_fetch); + pipe->scaler.enable = 0; + return -EINVAL; + } + /* + * alpha plane can only be scaled using bilinear or pixel + * repeat/drop, src_width and src_height are only specified + * for Y and UV plane + */ + if (plane != 3) { + if ((hor_req_pixels != + pipe->scaler.src_width[plane]) || + (vert_req_pixels != + pipe->scaler.src_height[plane])) { + pr_err("roi_w[%d]=%d, scaler:[%d, %d], src_img:[%d, %d]\n", + plane, pipe->scaler.roi_w[plane], + pipe->scaler.src_width[plane], + pipe->scaler.src_height[plane], + pipe->img_width, pipe->img_height); + pipe->scaler.enable = 0; + return -EINVAL; + } + } + } + + return 0; +} int mdss_mdp_overlay_setup_scaling(struct mdss_mdp_pipe *pipe) { @@ -528,8 +624,11 @@ int mdss_mdp_overlay_setup_scaling(struct mdss_mdp_pipe *pipe) mdata = mdss_mdp_get_mdata(); if (pipe->scaler.enable) { - if (!test_bit(MDSS_CAPS_QSEED3, mdata->mdss_caps_map)) + if (test_bit(MDSS_CAPS_QSEED3, mdata->mdss_caps_map)) + rc = __mdss_mdp_validate_qseed3_cfg(pipe); + else rc = __mdss_mdp_validate_pxl_extn(pipe); + return rc; } diff --git a/include/dt-bindings/clock/qcom,rpmcc.h b/include/dt-bindings/clock/qcom,rpmcc.h index 0f0c6300642c..cb5329bc9ba8 100644 --- a/include/dt-bindings/clock/qcom,rpmcc.h +++ b/include/dt-bindings/clock/qcom,rpmcc.h @@ -1,6 +1,6 @@ /* * Copyright 2015 Linaro Limited - * Copyright (c) 2016, The Linux Foundation. All rights reserved. + * Copyright (c) 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 @@ -129,5 +129,9 @@ #define CXO_PIL_CDSP_CLK 84 #define CNOC_PERIPH_KEEPALIVE_A_CLK 85 #define MMSSNOC_A_CLK_CPU_VOTE 86 +#define AGGR2_NOC_MSMBUS_CLK 87 +#define AGGR2_NOC_MSMBUS_A_CLK 88 +#define AGGR2_NOC_SMMU_CLK 89 +#define AGGR2_NOC_USB_CLK 90 #endif diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h index 7784b597e959..39c7de8c3048 100644 --- a/include/linux/clocksource.h +++ b/include/linux/clocksource.h @@ -186,6 +186,7 @@ extern void clocksource_suspend(void); extern void clocksource_resume(void); extern struct clocksource * __init clocksource_default_clock(void); extern void clocksource_mark_unstable(struct clocksource *cs); +extern void clocksource_select_force(void); extern u64 clocks_calc_max_nsecs(u32 mult, u32 shift, u32 maxadj, u64 mask, u64 *max_cycles); diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h index 55a30d685226..1068953943d8 100644 --- a/include/linux/mmc/core.h +++ b/include/linux/mmc/core.h @@ -203,6 +203,7 @@ extern unsigned int mmc_align_data_size(struct mmc_card *, unsigned int); extern int __mmc_claim_host(struct mmc_host *host, atomic_t *abort); extern void mmc_release_host(struct mmc_host *host); +extern int mmc_try_claim_host(struct mmc_host *host, unsigned int delay); extern void mmc_get_card(struct mmc_card *card); extern void mmc_put_card(struct mmc_card *card); diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 804d89a825fc..055b879dfa6b 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -208,6 +208,7 @@ struct mmc_cmdq_req { unsigned int resp_arg; unsigned int dev_pend_tasks; bool resp_err; + bool skip_err_handling; int tag; /* used for command queuing */ u8 ctx_id; }; @@ -533,6 +534,8 @@ struct mmc_host { struct dentry *debugfs_root; + bool err_occurred; + struct mmc_async_req *areq; /* active async req */ struct mmc_context_info context_info; /* async synchronization info */ diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h index ddc21d0c1bbb..06c273252484 100644 --- a/include/sound/apr_audio-v2.h +++ b/include/sound/apr_audio-v2.h @@ -933,7 +933,6 @@ struct adm_cmd_connect_afe_port_v5 { #define SLIMBUS_3_TX 0x4007 #define SLIMBUS_4_RX 0x4008 #define SLIMBUS_4_TX 0x4009 -#define SLIMBUS_TX_VI 0x4f09 #define SLIMBUS_5_RX 0x400a #define SLIMBUS_5_TX 0x400b #define SLIMBUS_6_RX 0x400c @@ -10224,12 +10223,108 @@ struct asm_session_cmd_set_mtmx_strstr_params_v2 { */ }; +/* Parameter used by #ASM_SESSION_MTMX_STRTR_MODULE_ID_AVSYNC which allows the + * audio client choose the rendering decision that the audio DSP should use. + */ +#define ASM_SESSION_MTMX_STRTR_PARAM_RENDER_MODE_CMD 0x00012F0D + +/* Indicates that rendering decision will be based on default rate + * (session clock based rendering, device driven). + * 1. The default session clock based rendering is inherently driven + * by the timing of the device. + * 2. After the initial decision is made (first buffer after a run + * command), subsequent data rendering decisions are made with + * respect to the rate at which the device is rendering, thus deriving + * its timing from the device. + * 3. While this decision making is simple, it has some inherent limitations + * (mentioned in the next section). + * 4. If this API is not set, the session clock based rendering will be assumed + * and this will ensure that the DSP is backward compatible. + */ +#define ASM_SESSION_MTMX_STRTR_PARAM_RENDER_DEFAULT 0 + +/* Indicates that rendering decision will be based on local clock rate. + * 1. In the DSP loopback/client loopback use cases (frame based + * inputs), the incoming data into audio DSP is time-stamped at the + * local clock rate (STC). + * 2. This TS rate may match the incoming data rate or maybe different + * from the incoming data rate. + * 3. Regardless, the data will be time-stamped with local STC and + * therefore, the client is recommended to set this mode for these + * use cases. This method is inherently more robust to sequencing + * (AFE Start/Stop) and device switches, among other benefits. + * 4. This API will inform the DSP to compare every incoming buffer TS + * against local STC. + * 5. DSP will continue to honor render windows APIs, as before. + */ +#define ASM_SESSION_MTMX_STRTR_PARAM_RENDER_LOCAL_STC 1 + +/* Structure for rendering decision parameter */ +struct asm_session_mtmx_strtr_param_render_mode_t { + /* Specifies the type of rendering decision the audio DSP should use. + * + * @values + * - #ASM_SESSION_MTMX_STRTR_PARAM_RENDER_DEFAULT + * - #ASM_SESSION_MTMX_STRTR_PARAM_RENDER_LOCAL_STC + */ + u32 flags; +} __packed; + +/* Parameter used by #ASM_SESSION_MTMX_STRTR_MODULE_ID_AVSYNC which allows the + * audio client to specify the clock recovery mechanism that the audio DSP + * should use. + */ + +#define ASM_SESSION_MTMX_STRTR_PARAM_CLK_REC_CMD 0x00012F0E + +/* Indicates that default clock recovery will be used (no clock recovery). + * If the client wishes that no clock recovery be done, the client can + * choose this. This means that no attempt will made by the DSP to try and + * match the rates of the input and output audio. + */ +#define ASM_SESSION_MTMX_STRTR_PARAM_CLK_REC_NONE 0 + +/* Indicates that independent clock recovery needs to be used. + * 1. In the DSP loopback/client loopback use cases (frame based inputs), + * the client should choose the independent clock recovery option. + * 2. This basically de-couples the audio and video from knowing each others + * clock sources and lets the audio DSP independently rate match the input + * and output rates. + * 3. After drift detection, the drift correction is achieved by either pulling + * the PLLs (if applicable) or by stream to device rate matching + * (for PCM use cases) by comparing drift with respect to STC. + * 4. For passthrough use cases, since the PLL pulling is the only option, + * a best effort will be made. + * If PLL pulling is not possible / available, the rendering will be + * done without rate matching. + */ +#define ASM_SESSION_MTMX_STRTR_PARAM_CLK_REC_AUTO 1 + +/* Payload of the #ASM_SESSION_MTMX_STRTR_PARAM_CLK_REC parameter. + */ +struct asm_session_mtmx_strtr_param_clk_rec_t { + /* Specifies the type of clock recovery that the audio DSP should + * use for rate matching. + */ + + /* @values + * #ASM_SESSION_MTMX_STRTR_PARAM_CLK_REC_DEFAULT + * #ASM_SESSION_MTMX_STRTR_PARAM_CLK_REC_INDEPENDENT + */ + u32 flags; +} __packed; + +union asm_session_mtmx_strtr_param_config { + struct asm_session_mtmx_strtr_param_window_v2_t window_param; + struct asm_session_mtmx_strtr_param_render_mode_t render_param; + struct asm_session_mtmx_strtr_param_clk_rec_t clk_rec_param; +} __packed; + struct asm_mtmx_strtr_params { struct apr_hdr hdr; struct asm_session_cmd_set_mtmx_strstr_params_v2 param; struct asm_stream_param_data_v2 data; - u32 window_lsw; - u32 window_msw; + union asm_session_mtmx_strtr_param_config config; } __packed; #define ASM_SESSION_CMD_GET_MTMX_STRTR_PARAMS_V2 0x00010DCF diff --git a/include/sound/q6asm-v2.h b/include/sound/q6asm-v2.h index 76bb795119c2..4947c30287a3 100644 --- a/include/sound/q6asm-v2.h +++ b/include/sound/q6asm-v2.h @@ -642,6 +642,14 @@ int q6asm_send_mtmx_strtr_window(struct audio_client *ac, struct asm_session_mtmx_strtr_param_window_v2_t *window_param, uint32_t param_id); +/* Configure DSP render mode */ +int q6asm_send_mtmx_strtr_render_mode(struct audio_client *ac, + uint32_t render_mode); + +/* Configure DSP clock recovery mode */ +int q6asm_send_mtmx_strtr_clk_rec_mode(struct audio_client *ac, + uint32_t clk_rec_mode); + /* Retrieve the current DSP path delay */ int q6asm_get_path_delay(struct audio_client *ac); diff --git a/include/uapi/sound/compress_offload.h b/include/uapi/sound/compress_offload.h index e050bc758b3b..30481056cce1 100644 --- a/include/uapi/sound/compress_offload.h +++ b/include/uapi/sound/compress_offload.h @@ -132,20 +132,42 @@ struct snd_compr_audio_info { __u32 reserved[15]; } __attribute__((packed, aligned(4))); +#define SNDRV_COMPRESS_RENDER_MODE_AUDIO_MASTER 0 +#define SNDRV_COMPRESS_RENDER_MODE_STC_MASTER 1 + +#define SNDRV_COMPRESS_CLK_REC_MODE_NONE 0 +#define SNDRV_COMPRESS_CLK_REC_MODE_AUTO 1 + /** * enum sndrv_compress_encoder * @SNDRV_COMPRESS_ENCODER_PADDING: no of samples appended by the encoder at the * end of the track * @SNDRV_COMPRESS_ENCODER_DELAY: no of samples inserted by the encoder at the * beginning of the track + * @SNDRV_COMPRESS_PATH_DELAY: dsp path delay in microseconds + * @SNDRV_COMPRESS_RENDER_MODE: dsp render mode (audio master or stc) + * @SNDRV_COMPRESS_CLK_REC_MODE: clock recovery mode ( none or auto) + * @SNDRV_COMPRESS_RENDER_WINDOW: render window + * @SNDRV_COMPRESS_START_DELAY: start delay */ enum sndrv_compress_encoder { SNDRV_COMPRESS_ENCODER_PADDING = 1, SNDRV_COMPRESS_ENCODER_DELAY = 2, SNDRV_COMPRESS_MIN_BLK_SIZE = 3, SNDRV_COMPRESS_MAX_BLK_SIZE = 4, + SNDRV_COMPRESS_PATH_DELAY = 5, + SNDRV_COMPRESS_RENDER_MODE = 6, + SNDRV_COMPRESS_CLK_REC_MODE = 7, + SNDRV_COMPRESS_RENDER_WINDOW = 8, + SNDRV_COMPRESS_START_DELAY = 9, }; +#define SNDRV_COMPRESS_PATH_DELAY SNDRV_COMPRESS_PATH_DELAY +#define SNDRV_COMPRESS_RENDER_MODE SNDRV_COMPRESS_RENDER_MODE +#define SNDRV_COMPRESS_CLK_REC_MODE SNDRV_COMPRESS_CLK_REC_MODE +#define SNDRV_COMPRESS_RENDER_WINDOW SNDRV_COMPRESS_RENDER_WINDOW +#define SNDRV_COMPRESS_START_DELAY SNDRV_COMPRESS_START_DELAY + /** * struct snd_compr_metadata - compressed stream metadata * @key: key id diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c index b98810d2f3b4..89cc82a38e4d 100644 --- a/kernel/time/clocksource.c +++ b/kernel/time/clocksource.c @@ -108,7 +108,7 @@ static int finished_booting; #ifdef CONFIG_CLOCKSOURCE_WATCHDOG static void clocksource_watchdog_work(struct work_struct *work); -static void clocksource_select(void); +static void clocksource_select(bool force); static LIST_HEAD(watchdog_list); static struct clocksource *watchdog; @@ -415,7 +415,7 @@ static int clocksource_watchdog_kthread(void *data) { mutex_lock(&clocksource_mutex); if (__clocksource_watchdog_kthread()) - clocksource_select(); + clocksource_select(false); mutex_unlock(&clocksource_mutex); return 0; } @@ -555,11 +555,12 @@ static inline void clocksource_update_max_deferment(struct clocksource *cs) #ifndef CONFIG_ARCH_USES_GETTIMEOFFSET -static struct clocksource *clocksource_find_best(bool oneshot, bool skipcur) +static struct clocksource *clocksource_find_best(bool oneshot, bool skipcur, + bool force) { struct clocksource *cs; - if (!finished_booting || list_empty(&clocksource_list)) + if ((!finished_booting && !force) || list_empty(&clocksource_list)) return NULL; /* @@ -577,13 +578,13 @@ static struct clocksource *clocksource_find_best(bool oneshot, bool skipcur) return NULL; } -static void __clocksource_select(bool skipcur) +static void __clocksource_select(bool skipcur, bool force) { bool oneshot = tick_oneshot_mode_active(); struct clocksource *best, *cs; /* Find the best suitable clocksource */ - best = clocksource_find_best(oneshot, skipcur); + best = clocksource_find_best(oneshot, skipcur, force); if (!best) return; @@ -623,22 +624,40 @@ static void __clocksource_select(bool skipcur) * Select the clocksource with the best rating, or the clocksource, * which is selected by userspace override. */ -static void clocksource_select(void) +static void clocksource_select(bool force) { - __clocksource_select(false); + return __clocksource_select(false, force); } static void clocksource_select_fallback(void) { - __clocksource_select(true); + __clocksource_select(true, false); } #else /* !CONFIG_ARCH_USES_GETTIMEOFFSET */ -static inline void clocksource_select(void) { } + +static inline void clocksource_select(bool force) { } static inline void clocksource_select_fallback(void) { } #endif +/** + * clocksource_select_force - Force re-selection of the best clocksource + * among registered clocksources + * + * clocksource_select() can't select the best clocksource before + * calling clocksource_done_booting() and since clocksource_select() + * should be called with clocksource_mutex held, provide a new API + * can be called from other files to select best clockrouce irrespective + * of finished_booting flag. + */ +void clocksource_select_force(void) +{ + mutex_lock(&clocksource_mutex); + clocksource_select(true); + mutex_unlock(&clocksource_mutex); +} + /* * clocksource_done_booting - Called near the end of core bootup * @@ -655,7 +674,7 @@ static int __init clocksource_done_booting(void) * Run the watchdog first to eliminate unstable clock sources */ __clocksource_watchdog_kthread(); - clocksource_select(); + clocksource_select(false); mutex_unlock(&clocksource_mutex); return 0; } @@ -744,6 +763,7 @@ void __clocksource_update_freq_scale(struct clocksource *cs, u32 scale, u32 freq } EXPORT_SYMBOL_GPL(__clocksource_update_freq_scale); + /** * __clocksource_register_scale - Used to install new clocksources * @cs: clocksource to be registered @@ -765,7 +785,7 @@ int __clocksource_register_scale(struct clocksource *cs, u32 scale, u32 freq) mutex_lock(&clocksource_mutex); clocksource_enqueue(cs); clocksource_enqueue_watchdog(cs); - clocksource_select(); + clocksource_select(false); clocksource_select_watchdog(false); mutex_unlock(&clocksource_mutex); return 0; @@ -788,7 +808,7 @@ void clocksource_change_rating(struct clocksource *cs, int rating) { mutex_lock(&clocksource_mutex); __clocksource_change_rating(cs, rating); - clocksource_select(); + clocksource_select(false); clocksource_select_watchdog(false); mutex_unlock(&clocksource_mutex); } @@ -892,7 +912,7 @@ static ssize_t sysfs_override_clocksource(struct device *dev, ret = sysfs_get_uname(buf, override_name, count); if (ret >= 0) - clocksource_select(); + clocksource_select(false); mutex_unlock(&clocksource_mutex); diff --git a/kernel/watchdog.c b/kernel/watchdog.c index f2813e137b23..91fa701b4a24 100644 --- a/kernel/watchdog.c +++ b/kernel/watchdog.c @@ -27,6 +27,7 @@ #include <linux/kvm_para.h> #include <linux/perf_event.h> #include <linux/kthread.h> +#include <soc/qcom/watchdog.h> /* * The run state of the lockup detectors is controlled by the content of the @@ -366,8 +367,11 @@ static void watchdog_check_hardlockup_other_cpu(void) if (per_cpu(hard_watchdog_warn, next_cpu) == true) return; - if (hardlockup_panic) - panic("Watchdog detected hard LOCKUP on cpu %u", next_cpu); + if (hardlockup_panic) { + pr_err("Watchdog detected hard LOCKUP on cpu %u", + next_cpu); + msm_trigger_wdog_bite(); + } else WARN(1, "Watchdog detected hard LOCKUP on cpu %u", next_cpu); @@ -430,6 +434,9 @@ static void watchdog_overflow_callback(struct perf_event *event, return; pr_emerg("Watchdog detected hard LOCKUP on cpu %d", this_cpu); + if (hardlockup_panic) + msm_trigger_wdog_bite(); + print_modules(); print_irqtrace_events(current); if (regs) @@ -552,6 +559,9 @@ static enum hrtimer_restart watchdog_timer_fn(struct hrtimer *hrtimer) pr_emerg("BUG: soft lockup - CPU#%d stuck for %us! [%s:%d]\n", smp_processor_id(), duration, current->comm, task_pid_nr(current)); + + if (softlockup_panic) + msm_trigger_wdog_bite(); __this_cpu_write(softlockup_task_ptr_saved, current); print_modules(); print_irqtrace_events(current); diff --git a/sound/soc/codecs/msm_hdmi_codec_rx.c b/sound/soc/codecs/msm_hdmi_codec_rx.c index 8ae789a90f33..e75e1939df33 100644 --- a/sound/soc/codecs/msm_hdmi_codec_rx.c +++ b/sound/soc/codecs/msm_hdmi_codec_rx.c @@ -20,10 +20,17 @@ #include <linux/msm_ext_display.h> #define MSM_EXT_DISP_PCM_RATES SNDRV_PCM_RATE_48000 +#define AUD_EXT_DISP_ACK_DISCONNECT (AUDIO_ACK_CONNECT ^ AUDIO_ACK_CONNECT) +#define AUD_EXT_DISP_ACK_CONNECT (AUDIO_ACK_CONNECT) +#define AUD_EXT_DISP_ACK_ENABLE (AUDIO_ACK_SET_ENABLE | AUDIO_ACK_ENABLE) static const char *const ext_disp_audio_type_text[] = {"None", "HDMI", "DP"}; +static const char *const ext_disp_audio_ack_text[] = {"Disconnect", "Connect", + "Ack_Enable"}; static SOC_ENUM_SINGLE_EXT_DECL(ext_disp_audio_type, ext_disp_audio_type_text); +static SOC_ENUM_SINGLE_EXT_DECL(ext_disp_audio_ack_state, + ext_disp_audio_ack_text); struct msm_ext_disp_audio_codec_rx_data { struct platform_device *ext_disp_core_pdev; @@ -176,6 +183,55 @@ done: return rc; } +static int msm_ext_disp_audio_ack_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct msm_ext_disp_audio_codec_rx_data *codec_data; + u32 ack_state = 0; + int rc; + + codec_data = snd_soc_codec_get_drvdata(codec); + if (!codec_data || + !codec_data->ext_disp_ops.acknowledge) { + dev_err(codec->dev, + "%s: codec_data or ops acknowledge() is NULL\n", + __func__); + rc = -EINVAL; + goto done; + } + + switch (ucontrol->value.enumerated.item[0]) { + case 0: + ack_state = AUD_EXT_DISP_ACK_DISCONNECT; + break; + case 1: + ack_state = AUD_EXT_DISP_ACK_CONNECT; + break; + case 2: + ack_state = AUD_EXT_DISP_ACK_ENABLE; + break; + default: + rc = -EINVAL; + dev_err(codec->dev, + "%s: invalid value %d for mixer ctl\n", + __func__, ucontrol->value.enumerated.item[0]); + goto done; + } + dev_dbg(codec->dev, "%s: control %d, ack set value 0x%x\n", + __func__, ucontrol->value.enumerated.item[0], ack_state); + + rc = codec_data->ext_disp_ops.acknowledge( + codec_data->ext_disp_core_pdev, ack_state); + if (rc < 0) { + dev_err(codec->dev, "%s: error from acknowledge(), err:%d\n", + __func__, rc); + } + +done: + return rc; +} + static const struct snd_kcontrol_new msm_ext_disp_codec_rx_controls[] = { { .access = SNDRV_CTL_ELEM_ACCESS_READ | @@ -195,6 +251,8 @@ static const struct snd_kcontrol_new msm_ext_disp_codec_rx_controls[] = { }, SOC_ENUM_EXT("External Display Type", ext_disp_audio_type, msm_ext_disp_audio_type_get, NULL), + SOC_ENUM_EXT("External Display Audio Ack", ext_disp_audio_ack_state, + NULL, msm_ext_disp_audio_ack_set), }; static int msm_ext_disp_audio_codec_rx_dai_startup( diff --git a/sound/soc/codecs/wcd934x/wcd934x.c b/sound/soc/codecs/wcd934x/wcd934x.c index 4fe9e2d50f7a..192d9291a8f3 100644 --- a/sound/soc/codecs/wcd934x/wcd934x.c +++ b/sound/soc/codecs/wcd934x/wcd934x.c @@ -9319,6 +9319,7 @@ static int tavil_soc_codec_probe(struct snd_soc_codec *codec) snd_soc_dapm_ignore_suspend(dapm, "AIF3 Playback"); snd_soc_dapm_ignore_suspend(dapm, "AIF3 Capture"); snd_soc_dapm_ignore_suspend(dapm, "AIF4 Playback"); + snd_soc_dapm_ignore_suspend(dapm, "AIF4 MAD TX"); snd_soc_dapm_ignore_suspend(dapm, "VIfeed"); snd_soc_dapm_sync(dapm); diff --git a/sound/soc/msm/msm8998.c b/sound/soc/msm/msm8998.c index 6324e81759de..041a91e28988 100644 --- a/sound/soc/msm/msm8998.c +++ b/sound/soc/msm/msm8998.c @@ -2906,7 +2906,6 @@ static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, break; case MSM_BACKEND_DAI_SLIMBUS_4_TX: - case MSM_BACKEND_DAI_SLIMBUS_TX_VI: param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, SNDRV_PCM_FORMAT_S32_LE); rate->min = rate->max = SAMPLING_RATE_8KHZ; @@ -3699,8 +3698,7 @@ static int msm_snd_hw_params(struct snd_pcm_substream *substream, /* For <codec>_tx3 case */ else if (dai_link->be_id == MSM_BACKEND_DAI_SLIMBUS_1_TX) user_set_tx_ch = slim_tx_cfg[1].channels; - else if (dai_link->be_id == MSM_BACKEND_DAI_SLIMBUS_4_TX || - dai_link->be_id == MSM_BACKEND_DAI_SLIMBUS_TX_VI) + else if (dai_link->be_id == MSM_BACKEND_DAI_SLIMBUS_4_TX) user_set_tx_ch = msm_vi_feed_tx_ch; else user_set_tx_ch = tx_ch_cnt; @@ -5728,12 +5726,12 @@ static struct snd_soc_dai_link msm_tasha_be_dai_links[] = { /* Slimbus VI Recording */ { .name = LPASS_BE_SLIMBUS_TX_VI, - .stream_name = "Slimbus VI Capture", - .cpu_dai_name = "msm-dai-q6-dev.20233", + .stream_name = "Slimbus4 Capture", + .cpu_dai_name = "msm-dai-q6-dev.16393", .platform_name = "msm-pcm-routing", .codec_name = "tasha_codec", .codec_dai_name = "tasha_vifeedback", - .be_id = MSM_BACKEND_DAI_SLIMBUS_TX_VI, + .be_id = MSM_BACKEND_DAI_SLIMBUS_4_TX, .be_hw_params_fixup = msm_be_hw_params_fixup, .ops = &msm_be_ops, .ignore_suspend = 1, @@ -5913,16 +5911,15 @@ static struct snd_soc_dai_link msm_tavil_be_dai_links[] = { .ignore_pmdown_time = 1, .ignore_suspend = 1, }, - /* Slimbus VI Recording */ { .name = LPASS_BE_SLIMBUS_TX_VI, - .stream_name = "Slimbus VI Capture", - .cpu_dai_name = "msm-dai-q6-dev.20233", + .stream_name = "Slimbus4 Capture", + .cpu_dai_name = "msm-dai-q6-dev.16393", .platform_name = "msm-pcm-routing", .codec_name = "tavil_codec", .codec_dai_name = "tavil_vifeedback", - .be_id = MSM_BACKEND_DAI_SLIMBUS_TX_VI, + .be_id = MSM_BACKEND_DAI_SLIMBUS_4_TX, .be_hw_params_fixup = msm_be_hw_params_fixup, .ops = &msm_be_ops, .ignore_suspend = 1, diff --git a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c index 7f032dcceabd..4fa80c679b46 100644 --- a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c @@ -160,6 +160,10 @@ struct msm_compr_audio { uint32_t stream_available; uint32_t next_stream; + uint32_t run_mode; + uint32_t start_delay_lsw; + uint32_t start_delay_msw; + uint64_t marker_timestamp; struct msm_compr_gapless_state gapless_state; @@ -215,6 +219,99 @@ static int msm_compr_send_dec_params(struct snd_compr_stream *cstream, struct msm_compr_dec_params *dec_params, int stream_id); +static int msm_compr_set_render_mode(struct msm_compr_audio *prtd, + uint32_t render_mode) { + int ret = -EINVAL; + struct audio_client *ac = prtd->audio_client; + + pr_debug("%s, got render mode %u\n", __func__, render_mode); + + if (render_mode == SNDRV_COMPRESS_RENDER_MODE_AUDIO_MASTER) { + render_mode = ASM_SESSION_MTMX_STRTR_PARAM_RENDER_DEFAULT; + } else if (render_mode == SNDRV_COMPRESS_RENDER_MODE_STC_MASTER) { + render_mode = ASM_SESSION_MTMX_STRTR_PARAM_RENDER_LOCAL_STC; + prtd->run_mode = ASM_SESSION_CMD_RUN_STARTIME_RUN_WITH_DELAY; + } else { + pr_err("%s, Invalid render mode %u\n", __func__, + render_mode); + ret = -EINVAL; + goto exit; + } + + ret = q6asm_send_mtmx_strtr_render_mode(ac, render_mode); + if (ret) { + pr_err("%s, Render mode can't be set error %d\n", __func__, + ret); + } +exit: + return ret; +} + +static int msm_compr_set_clk_rec_mode(struct audio_client *ac, + uint32_t clk_rec_mode) { + int ret = -EINVAL; + + pr_debug("%s, got clk rec mode %u\n", __func__, clk_rec_mode); + + if (clk_rec_mode == SNDRV_COMPRESS_CLK_REC_MODE_NONE) { + clk_rec_mode = ASM_SESSION_MTMX_STRTR_PARAM_CLK_REC_NONE; + } else if (clk_rec_mode == SNDRV_COMPRESS_CLK_REC_MODE_AUTO) { + clk_rec_mode = ASM_SESSION_MTMX_STRTR_PARAM_CLK_REC_AUTO; + } else { + pr_err("%s, Invalid clk rec_mode mode %u\n", __func__, + clk_rec_mode); + ret = -EINVAL; + goto exit; + } + + ret = q6asm_send_mtmx_strtr_clk_rec_mode(ac, clk_rec_mode); + if (ret) { + pr_err("%s, clk rec mode can't be set, error %d\n", __func__, + ret); + } + +exit: + return ret; +} + +static int msm_compr_set_render_window(struct audio_client *ac, + uint32_t ws_lsw, uint32_t ws_msw, + uint32_t we_lsw, uint32_t we_msw) +{ + int ret = -EINVAL; + struct asm_session_mtmx_strtr_param_window_v2_t asm_mtmx_strtr_window; + uint32_t param_id; + + pr_debug("%s, ws_lsw 0x%x ws_msw 0x%x we_lsw 0x%x we_ms 0x%x\n", + __func__, ws_lsw, ws_msw, we_lsw, we_msw); + + memset(&asm_mtmx_strtr_window, 0, + sizeof(struct asm_session_mtmx_strtr_param_window_v2_t)); + asm_mtmx_strtr_window.window_lsw = ws_lsw; + asm_mtmx_strtr_window.window_msw = ws_msw; + param_id = ASM_SESSION_MTMX_STRTR_PARAM_RENDER_WINDOW_START_V2; + ret = q6asm_send_mtmx_strtr_window(ac, &asm_mtmx_strtr_window, + param_id); + if (ret) { + pr_err("%s, start window can't be set error %d\n", __func__, + ret); + goto exit; + } + + asm_mtmx_strtr_window.window_lsw = we_lsw; + asm_mtmx_strtr_window.window_msw = we_msw; + param_id = ASM_SESSION_MTMX_STRTR_PARAM_RENDER_WINDOW_END_V2; + ret = q6asm_send_mtmx_strtr_window(ac, &asm_mtmx_strtr_window, + param_id); + if (ret) { + pr_err("%s, end window can't be set error %d\n", __func__, + ret); + } + +exit: + return ret; +} + static int msm_compr_set_volume(struct snd_compr_stream *cstream, uint32_t volume_l, uint32_t volume_r) { @@ -1586,6 +1683,7 @@ static int msm_compr_playback_free(struct snd_compr_stream *cstream) kfree(pdata->dec_params[soc_prtd->dai_link->be_id]); pdata->dec_params[soc_prtd->dai_link->be_id] = NULL; kfree(prtd); + runtime->private_data = NULL; return 0; } @@ -1645,6 +1743,7 @@ static int msm_compr_capture_free(struct snd_compr_stream *cstream) q6asm_audio_client_free(ac); kfree(prtd); + runtime->private_data = NULL; return 0; } @@ -1963,7 +2062,8 @@ static int msm_compr_trigger(struct snd_compr_stream *cstream, int cmd) msm_compr_read_buffer(prtd); } /* issue RUN command for the stream */ - q6asm_run_nowait(prtd->audio_client, 0, 0, 0); + q6asm_run_nowait(prtd->audio_client, prtd->run_mode, + prtd->start_delay_msw, prtd->start_delay_lsw); break; case SNDRV_PCM_TRIGGER_STOP: spin_lock_irqsave(&prtd->lock, flags); @@ -2047,7 +2147,8 @@ static int msm_compr_trigger(struct snd_compr_stream *cstream, int cmd) prtd->gapless_state.gapless_transition); if (!prtd->gapless_state.gapless_transition) { atomic_set(&prtd->start, 1); - q6asm_run_nowait(prtd->audio_client, 0, 0, 0); + q6asm_run_nowait(prtd->audio_client, prtd->run_mode, + 0, 0); } break; case SND_COMPR_TRIGGER_PARTIAL_DRAIN: @@ -2717,11 +2818,14 @@ static int msm_compr_set_metadata(struct snd_compr_stream *cstream, return -EINVAL; } - if (prtd->compr_passthr != LEGACY_PCM) { + if (((metadata->key == SNDRV_COMPRESS_ENCODER_PADDING) || + (metadata->key == SNDRV_COMPRESS_ENCODER_DELAY)) && + (prtd->compr_passthr != LEGACY_PCM)) { pr_debug("%s: No trailing silence for compress_type[%d]\n", __func__, prtd->compr_passthr); return 0; } + ac = prtd->audio_client; if (metadata->key == SNDRV_COMPRESS_ENCODER_PADDING) { pr_debug("%s, got encoder padding %u", __func__, metadata->value[0]); @@ -2729,11 +2833,63 @@ static int msm_compr_set_metadata(struct snd_compr_stream *cstream, } else if (metadata->key == SNDRV_COMPRESS_ENCODER_DELAY) { pr_debug("%s, got encoder delay %u", __func__, metadata->value[0]); prtd->gapless_state.initial_samples_drop = metadata->value[0]; + } else if (metadata->key == SNDRV_COMPRESS_RENDER_MODE) { + return msm_compr_set_render_mode(prtd, metadata->value[0]); + } else if (metadata->key == SNDRV_COMPRESS_CLK_REC_MODE) { + return msm_compr_set_clk_rec_mode(ac, metadata->value[0]); + } else if (metadata->key == SNDRV_COMPRESS_RENDER_WINDOW) { + return msm_compr_set_render_window( + ac, + metadata->value[0], + metadata->value[1], + metadata->value[2], + metadata->value[3]); + } else if (metadata->key == SNDRV_COMPRESS_START_DELAY) { + prtd->start_delay_lsw = metadata->value[0]; + prtd->start_delay_msw = metadata->value[1]; } return 0; } +static int msm_compr_get_metadata(struct snd_compr_stream *cstream, + struct snd_compr_metadata *metadata) +{ + struct msm_compr_audio *prtd; + struct audio_client *ac; + int ret = -EINVAL; + + pr_debug("%s\n", __func__); + + if (!metadata || !cstream || !cstream->runtime) + return ret; + + if (metadata->key != SNDRV_COMPRESS_PATH_DELAY) { + pr_err("%s, unsupported key %d\n", __func__, metadata->key); + return ret; + } + + prtd = cstream->runtime->private_data; + if (!prtd || !prtd->audio_client) { + pr_err("%s: prtd or audio client is NULL\n", __func__); + return ret; + } + + ac = prtd->audio_client; + ret = q6asm_get_path_delay(prtd->audio_client); + if (ret) { + pr_err("%s: get_path_delay failed, ret=%d\n", __func__, ret); + return ret; + } + + pr_debug("%s, path delay(in us) %u\n", __func__, ac->path_delay); + + metadata->value[0] = ac->path_delay; + + return ret; +} + + static int msm_compr_set_next_track_param(struct snd_compr_stream *cstream, union snd_codec_options *codec_options) { @@ -3889,6 +4045,7 @@ static struct snd_compr_ops msm_compr_ops = { .pointer = msm_compr_pointer, .set_params = msm_compr_set_params, .set_metadata = msm_compr_set_metadata, + .get_metadata = msm_compr_get_metadata, .set_next_track_param = msm_compr_set_next_track_param, .ack = msm_compr_ack, .copy = msm_compr_copy, diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c index 19e2fad2920d..d7efefdb3a04 100644 --- a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c @@ -1773,7 +1773,6 @@ static int msm_dai_q6_hw_params(struct snd_pcm_substream *substream, case SLIMBUS_2_TX: case SLIMBUS_3_TX: case SLIMBUS_4_TX: - case SLIMBUS_TX_VI: case SLIMBUS_5_TX: case SLIMBUS_6_TX: case SLIMBUS_7_TX: @@ -1928,7 +1927,6 @@ static int msm_dai_q6_set_channel_map(struct snd_soc_dai *dai, case SLIMBUS_2_TX: case SLIMBUS_3_TX: case SLIMBUS_4_TX: - case SLIMBUS_TX_VI: case SLIMBUS_5_TX: case SLIMBUS_6_TX: case SLIMBUS_7_TX: @@ -2348,9 +2346,6 @@ static const struct snd_kcontrol_new sb_config_controls[] = { msm_dai_q6_cal_info_put), SOC_ENUM_EXT("SLIM_2_RX Format", sb_config_enum[0], msm_dai_q6_sb_format_get, - msm_dai_q6_sb_format_put), - SOC_ENUM_EXT("SLIM_TX_VI Format", sb_config_enum[0], - msm_dai_q6_sb_format_get, msm_dai_q6_sb_format_put) }; @@ -2409,11 +2404,6 @@ static int msm_dai_q6_dai_probe(struct snd_soc_dai *dai) snd_ctl_new1(&sb_config_controls[0], dai_data)); break; - case SLIMBUS_TX_VI: - rc = snd_ctl_add(dai->component->card->snd_card, - snd_ctl_new1(&sb_config_controls[3], - dai_data)); - break; case SLIMBUS_2_RX: rc = snd_ctl_add(dai->component->card->snd_card, snd_ctl_new1(&sb_config_controls[1], @@ -3302,25 +3292,6 @@ static struct snd_soc_dai_driver msm_dai_q6_slimbus_tx_dai[] = { }, { .capture = { - .stream_name = "Slimbus VI Capture", - .aif_name = "SLIMBUS_TX_VI", - .rates = SNDRV_PCM_RATE_8000_96000 | - SNDRV_PCM_RATE_192000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_S24_LE | - SNDRV_PCM_FMTBIT_S32_LE, - .channels_min = 1, - .channels_max = 4, - .rate_min = 8000, - .rate_max = 192000, - }, - .ops = &msm_dai_q6_ops, - .id = SLIMBUS_TX_VI, - .probe = msm_dai_q6_dai_probe, - .remove = msm_dai_q6_dai_remove, - }, - { - .capture = { .stream_name = "Slimbus5 Capture", .aif_name = "SLIMBUS_5_TX", .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 | @@ -4677,9 +4648,6 @@ register_slim_playback: case SLIMBUS_4_TX: strlcpy(stream_name, "Slimbus4 Capture", 80); goto register_slim_capture; - case SLIMBUS_TX_VI: - strlcpy(stream_name, "Slimbus VI Capture", 80); - goto register_slim_capture; case SLIMBUS_5_TX: strlcpy(stream_name, "Slimbus5 Capture", 80); goto register_slim_capture; diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c index d65108e04e0b..b1a1ea54a73e 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c @@ -1,4 +1,4 @@ -/* 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 @@ -684,6 +684,7 @@ done: mutex_unlock(&prtd->lock); prtd->prepared--; kfree(prtd); + runtime->private_data = NULL; return 0; } static int msm_afe_prepare(struct snd_pcm_substream *substream) diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-noirq.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-noirq.c index 33c5b6486cca..c0ca9b24f544 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-noirq.c +++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-noirq.c @@ -570,6 +570,8 @@ static int msm_pcm_close(struct snd_pcm_substream *substream) SNDRV_PCM_STREAM_PLAYBACK : SNDRV_PCM_STREAM_CAPTURE); kfree(prtd); + runtime->private_data = NULL; + return 0; } @@ -834,6 +836,182 @@ static int msm_pcm_add_fe_topology_control(struct snd_soc_pcm_runtime *rtd) return ret; } +static int msm_pcm_playback_app_type_cfg_ctl_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + u64 fe_id = kcontrol->private_value; + int session_type = SESSION_TYPE_RX; + int be_id = ucontrol->value.integer.value[3]; + int ret = 0; + int app_type; + int acdb_dev_id; + int sample_rate = 48000; + + app_type = ucontrol->value.integer.value[0]; + acdb_dev_id = ucontrol->value.integer.value[1]; + if (ucontrol->value.integer.value[2] != 0) + sample_rate = ucontrol->value.integer.value[2]; + + ret = msm_pcm_routing_reg_stream_app_type_cfg(fe_id, session_type, + be_id, app_type, + acdb_dev_id, sample_rate); + if (ret < 0) + pr_err("%s: msm_pcm_playback_app_type_cfg_ctl_put failed, err %d\n", + __func__, ret); + + pr_debug("%s: fe_id- %llu session_type- %d be_id- %d app_type- %d acdb_dev_id- %d sample_rate- %d\n", + __func__, fe_id, session_type, be_id, + app_type, acdb_dev_id, sample_rate); + return ret; +} + +static int msm_pcm_playback_app_type_cfg_ctl_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + u64 fe_id = kcontrol->private_value; + int session_type = SESSION_TYPE_RX; + int be_id = ucontrol->value.integer.value[3]; + int ret = 0; + int app_type; + int acdb_dev_id; + int sample_rate; + + ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, session_type, + be_id, &app_type, + &acdb_dev_id, + &sample_rate); + if (ret < 0) { + pr_err("%s: msm_pcm_playback_app_type_cfg_ctl_get failed, err: %d\n", + __func__, ret); + goto done; + } + + ucontrol->value.integer.value[0] = app_type; + ucontrol->value.integer.value[1] = acdb_dev_id; + ucontrol->value.integer.value[2] = sample_rate; + + pr_debug("%s: fedai_id %llu, session_type %d, be_id %d, app_type %d, acdb_dev_id %d, sample_rate %d\n", + __func__, fe_id, session_type, be_id, + app_type, acdb_dev_id, sample_rate); +done: + return ret; +} + +static int msm_pcm_capture_app_type_cfg_ctl_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + u64 fe_id = kcontrol->private_value; + int session_type = SESSION_TYPE_TX; + int be_id = ucontrol->value.integer.value[3]; + int ret = 0; + int app_type; + int acdb_dev_id; + int sample_rate = 48000; + + app_type = ucontrol->value.integer.value[0]; + acdb_dev_id = ucontrol->value.integer.value[1]; + if (ucontrol->value.integer.value[2] != 0) + sample_rate = ucontrol->value.integer.value[2]; + + ret = msm_pcm_routing_reg_stream_app_type_cfg(fe_id, session_type, + be_id, app_type, + acdb_dev_id, sample_rate); + if (ret < 0) + pr_err("%s: msm_pcm_capture_app_type_cfg_ctl_put failed, err: %d\n", + __func__, ret); + + pr_debug("%s: fe_id- %llu session_type- %d be_id- %d app_type- %d acdb_dev_id- %d sample_rate- %d\n", + __func__, fe_id, session_type, be_id, + app_type, acdb_dev_id, sample_rate); + + return ret; +} + +static int msm_pcm_capture_app_type_cfg_ctl_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + u64 fe_id = kcontrol->private_value; + int session_type = SESSION_TYPE_TX; + int be_id = ucontrol->value.integer.value[3]; + int ret = 0; + int app_type; + int acdb_dev_id; + int sample_rate; + + ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, session_type, + be_id, &app_type, + &acdb_dev_id, + &sample_rate); + if (ret < 0) { + pr_err("%s: msm_pcm_capture_app_type_cfg_ctl_get failed, err: %d\n", + __func__, ret); + goto done; + } + + ucontrol->value.integer.value[0] = app_type; + ucontrol->value.integer.value[1] = acdb_dev_id; + ucontrol->value.integer.value[2] = sample_rate; + pr_debug("%s: fedai_id %llu, session_type %d, be_id %d, app_type %d, acdb_dev_id %d, sample_rate %d\n", + __func__, fe_id, session_type, be_id, + app_type, acdb_dev_id, sample_rate); +done: + return ret; +} + +static int msm_pcm_add_app_type_controls(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_pcm *pcm = rtd->pcm; + struct snd_pcm_usr *app_type_info; + struct snd_kcontrol *kctl; + const char *playback_mixer_ctl_name = "Audio Stream"; + const char *capture_mixer_ctl_name = "Audio Stream Capture"; + const char *deviceNo = "NN"; + const char *suffix = "App Type Cfg"; + int ctl_len, ret = 0; + + if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) { + ctl_len = strlen(playback_mixer_ctl_name) + 1 + + strlen(deviceNo) + 1 + + strlen(suffix) + 1; + pr_debug("%s: Playback app type cntrl add\n", __func__); + ret = snd_pcm_add_usr_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, + NULL, 1, ctl_len, rtd->dai_link->be_id, + &app_type_info); + if (ret < 0) { + pr_err("%s: playback app type cntrl add failed, err: %d\n", + __func__, ret); + return ret; + } + kctl = app_type_info->kctl; + snprintf(kctl->id.name, ctl_len, "%s %d %s", + playback_mixer_ctl_name, rtd->pcm->device, suffix); + kctl->put = msm_pcm_playback_app_type_cfg_ctl_put; + kctl->get = msm_pcm_playback_app_type_cfg_ctl_get; + } + + if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) { + ctl_len = strlen(capture_mixer_ctl_name) + 1 + + strlen(deviceNo) + 1 + strlen(suffix) + 1; + pr_debug("%s: Capture app type cntrl add\n", __func__); + ret = snd_pcm_add_usr_ctls(pcm, SNDRV_PCM_STREAM_CAPTURE, + NULL, 1, ctl_len, rtd->dai_link->be_id, + &app_type_info); + if (ret < 0) { + pr_err("%s: capture app type cntrl add failed, err: %d\n", + __func__, ret); + return ret; + } + kctl = app_type_info->kctl; + snprintf(kctl->id.name, ctl_len, "%s %d %s", + capture_mixer_ctl_name, rtd->pcm->device, suffix); + kctl->put = msm_pcm_capture_app_type_cfg_ctl_put; + kctl->get = msm_pcm_capture_app_type_cfg_ctl_get; + } + + return 0; +} + + static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd) { struct snd_card *card = rtd->card->snd_card; @@ -860,6 +1038,13 @@ static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd) pr_err("%s: Could not add pcm topology control %d\n", __func__, ret); } + + ret = msm_pcm_add_app_type_controls(rtd); + if (ret) { + pr_err("%s: Could not add app type controls failed %d\n", + __func__, ret); + } + pcm->nonatomic = true; exit: return ret; diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c index e14f410bd310..7928c3791f96 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c @@ -804,6 +804,8 @@ static int msm_pcm_playback_close(struct snd_pcm_substream *substream) msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->be_id, SNDRV_PCM_STREAM_PLAYBACK); kfree(prtd); + runtime->private_data = NULL; + return 0; } @@ -909,6 +911,7 @@ static int msm_pcm_capture_close(struct snd_pcm_substream *substream) msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->be_id, SNDRV_PCM_STREAM_CAPTURE); kfree(prtd); + runtime->private_data = NULL; return 0; } diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c index 3677a06c65ae..c3db926be5d9 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c @@ -96,7 +96,6 @@ enum { #define SLIMBUS_2_TX_TEXT "SLIMBUS_2_TX" #define SLIMBUS_3_TX_TEXT "SLIMBUS_3_TX" #define SLIMBUS_4_TX_TEXT "SLIMBUS_4_TX" -#define SLIMBUS_TX_VI_TEXT "SLIMBUS_TX_VI" #define SLIMBUS_5_TX_TEXT "SLIMBUS_5_TX" #define TERT_MI2S_TX_TEXT "TERT_MI2S_TX" #define QUAT_MI2S_TX_TEXT "QUAT_MI2S_TX" @@ -109,7 +108,7 @@ static const char * const lsm_port_text[] = { SLIMBUS_0_TX_TEXT, SLIMBUS_1_TX_TEXT, SLIMBUS_2_TX_TEXT, SLIMBUS_3_TX_TEXT, SLIMBUS_4_TX_TEXT, SLIMBUS_5_TX_TEXT, TERT_MI2S_TX_TEXT, QUAT_MI2S_TX_TEXT, ADM_LSM_TX_TEXT, - INT3_MI2S_TX_TEXT, SLIMBUS_TX_VI_TEXT + INT3_MI2S_TX_TEXT }; struct msm_pcm_route_bdai_pp_params { @@ -538,7 +537,6 @@ struct msm_pcm_routing_bdai_data msm_bedais[MSM_BACKEND_DAI_MAX] = { LPASS_BE_INT6_MI2S_RX}, { AFE_PORT_ID_INT6_MI2S_TX, 0, {0}, {0}, 0, 0, 0, 0, 0, LPASS_BE_INT6_MI2S_TX}, - { SLIMBUS_TX_VI, 0, {0}, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_TX_VI}, }; /* Track ASM playback & capture sessions of DAI @@ -5681,9 +5679,6 @@ static const struct snd_kcontrol_new mmul1_mixer_controls[] = { SOC_SINGLE_EXT("SLIM_4_TX", MSM_BACKEND_DAI_SLIMBUS_4_TX, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SLIM_TX_VI", MSM_BACKEND_DAI_SLIMBUS_TX_VI, - MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), SOC_SINGLE_EXT("SLIM_6_TX", MSM_BACKEND_DAI_SLIMBUS_6_TX, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), @@ -10994,8 +10989,6 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = { 0, 0, 0, 0), SND_SOC_DAPM_AIF_IN("SLIMBUS_4_TX", "Slimbus4 Capture", 0, 0, 0, 0), - SND_SOC_DAPM_AIF_IN("SLIMBUS_TX_VI", "Slimbus VI Capture", - 0, 0, 0, 0), SND_SOC_DAPM_AIF_IN("SENARY_TX", "Senary_mi2s Capture", 0, 0, 0, 0), SND_SOC_DAPM_AIF_IN("INT5_MI2S_TX", "INT5 MI2S Capture", @@ -11759,7 +11752,6 @@ static const struct snd_soc_dapm_route intercon[] = { {"MultiMedia4 Mixer", "VOC_REC_DL", "INCALL_RECORD_RX"}, {"MultiMedia8 Mixer", "VOC_REC_DL", "INCALL_RECORD_RX"}, {"MultiMedia1 Mixer", "SLIM_4_TX", "SLIMBUS_4_TX"}, - {"MultiMedia1 Mixer", "SLIM_TX_VI", "SLIMBUS_TX_VI"}, {"MultiMedia1 Mixer", "SLIM_6_TX", "SLIMBUS_6_TX"}, {"MultiMedia1 Mixer", "SLIM_7_TX", "SLIMBUS_7_TX"}, {"MultiMedia1 Mixer", "SLIM_8_TX", "SLIMBUS_8_TX"}, @@ -13921,7 +13913,6 @@ static const struct snd_soc_dapm_route intercon[] = { {"SLIMBUS_1_TX", NULL, "BE_IN" }, {"SLIMBUS_3_TX", NULL, "BE_IN" }, {"SLIMBUS_4_TX", NULL, "BE_IN" }, - {"SLIMBUS_TX_VI", NULL, "BE_IN" }, {"SLIMBUS_5_TX", NULL, "BE_IN" }, {"SLIMBUS_6_TX", NULL, "BE_IN" }, {"SLIMBUS_7_TX", NULL, "BE_IN" }, diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h index 94c79f00afec..fcd155e71317 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h +++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h @@ -70,8 +70,8 @@ #define LPASS_BE_SLIMBUS_3_TX "SLIMBUS_3_TX" #define LPASS_BE_SLIMBUS_4_RX "SLIMBUS_4_RX" #define LPASS_BE_SLIMBUS_4_TX "SLIMBUS_4_TX" -#define LPASS_BE_SLIMBUS_5_RX "SLIMBUS_5_RX" #define LPASS_BE_SLIMBUS_TX_VI "SLIMBUS_TX_VI" +#define LPASS_BE_SLIMBUS_5_RX "SLIMBUS_5_RX" #define LPASS_BE_SLIMBUS_5_TX "SLIMBUS_5_TX" #define LPASS_BE_SLIMBUS_6_RX "SLIMBUS_6_RX" #define LPASS_BE_SLIMBUS_6_TX "SLIMBUS_6_TX" @@ -362,7 +362,6 @@ enum { MSM_BACKEND_DAI_INT5_MI2S_TX, MSM_BACKEND_DAI_INT6_MI2S_RX, MSM_BACKEND_DAI_INT6_MI2S_TX, - MSM_BACKEND_DAI_SLIMBUS_TX_VI, MSM_BACKEND_DAI_MAX, }; diff --git a/sound/soc/msm/qdsp6v2/q6adm.c b/sound/soc/msm/qdsp6v2/q6adm.c index 4a4f02c7b9b6..2da7e6dc11e7 100644 --- a/sound/soc/msm/qdsp6v2/q6adm.c +++ b/sound/soc/msm/qdsp6v2/q6adm.c @@ -2463,6 +2463,7 @@ int adm_open(int port_id, int path, int rate, int channel_mode, int topology, pr_err("%s: DTS_EAGLE mmap did not work!", __func__); } + memset(&open, 0, sizeof(struct adm_cmd_device_open_v5)); open.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER); @@ -2506,6 +2507,8 @@ int adm_open(int port_id, int path, int rate, int channel_mode, int topology, if ((this_adm.num_ec_ref_rx_chans != 0) && (path != 1) && (open.endpoint_id_2 != 0xFFFF)) { + memset(&open_v6, 0, + sizeof(struct adm_cmd_device_open_v6)); memcpy(&open_v6, &open, sizeof(struct adm_cmd_device_open_v5)); open_v6.hdr.opcode = ADM_CMD_DEVICE_OPEN_V6; diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c index fcff383b9c3b..80729b3052b7 100644 --- a/sound/soc/msm/qdsp6v2/q6afe.c +++ b/sound/soc/msm/qdsp6v2/q6afe.c @@ -547,7 +547,6 @@ int afe_get_port_type(u16 port_id) case SLIMBUS_2_TX: case SLIMBUS_3_TX: case SLIMBUS_4_TX: - case SLIMBUS_TX_VI: case SLIMBUS_5_TX: case SLIMBUS_6_TX: case SLIMBUS_7_TX: @@ -652,7 +651,6 @@ int afe_sizeof_cfg_cmd(u16 port_id) case SLIMBUS_3_TX: case SLIMBUS_4_RX: case SLIMBUS_4_TX: - case SLIMBUS_TX_VI: case SLIMBUS_5_RX: case SLIMBUS_5_TX: case SLIMBUS_6_RX: @@ -2939,13 +2937,6 @@ static int __afe_port_start(u16 port_id, union afe_port_config *afe_config, return ret; } - /* - * Virtual SLIMBUS_TX_VI shares afe port with SLIMBUS_4_TX. - * port_id changes to physical port of SLIMBUS_4_TX. - */ - if (port_id == SLIMBUS_TX_VI) - port_id = SLIMBUS_4_TX; - if ((port_id == RT_PROXY_DAI_001_RX) || (port_id == RT_PROXY_DAI_002_TX)) { pr_debug("%s: before incrementing pcm_afe_instance %d"\ @@ -3132,7 +3123,6 @@ static int __afe_port_start(u16 port_id, union afe_port_config *afe_config, case SLIMBUS_3_TX: case SLIMBUS_4_RX: case SLIMBUS_4_TX: - case SLIMBUS_TX_VI: case SLIMBUS_5_RX: case SLIMBUS_5_TX: case SLIMBUS_6_RX: @@ -3325,7 +3315,6 @@ int afe_get_port_index(u16 port_id) case RT_PROXY_PORT_001_TX: return IDX_RT_PROXY_PORT_001_TX; case SLIMBUS_4_RX: return IDX_SLIMBUS_4_RX; case SLIMBUS_4_TX: return IDX_SLIMBUS_4_TX; - case SLIMBUS_TX_VI: return IDX_SLIMBUS_4_TX; case SLIMBUS_5_RX: return IDX_SLIMBUS_5_RX; case SLIMBUS_5_TX: return IDX_SLIMBUS_5_TX; case SLIMBUS_6_RX: return IDX_SLIMBUS_6_RX; @@ -5494,14 +5483,6 @@ int afe_close(int port_id) goto fail_cmd; } pr_debug("%s: port_id = 0x%x\n", __func__, port_id); - - /* - * Virtual SLIMBUS_TX_VI shares afe port with SLIMBUS_4_TX. - * port_id changes to physical port of SLIMBUS_4_TX. - */ - if (port_id == SLIMBUS_TX_VI) - port_id = SLIMBUS_4_TX; - if ((port_id == RT_PROXY_DAI_001_RX) || (port_id == RT_PROXY_DAI_002_TX)) { pr_debug("%s: before decrementing pcm_afe_instance %d\n", diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c index d55c28fab652..c3a4719542ef 100644 --- a/sound/soc/msm/qdsp6v2/q6asm.c +++ b/sound/soc/msm/qdsp6v2/q6asm.c @@ -7934,16 +7934,18 @@ int q6asm_send_mtmx_strtr_window(struct audio_client *ac, matrix.param.data_payload_addr_lsw = 0; matrix.param.data_payload_addr_msw = 0; matrix.param.mem_map_handle = 0; - matrix.param.data_payload_size = sizeof(matrix) - - sizeof(matrix.hdr) - sizeof(matrix.param); + matrix.param.data_payload_size = + sizeof(struct asm_stream_param_data_v2) + + sizeof(struct asm_session_mtmx_strtr_param_window_v2_t); matrix.param.direction = 0; /* RX */ matrix.data.module_id = ASM_SESSION_MTMX_STRTR_MODULE_ID_AVSYNC; matrix.data.param_id = param_id; - matrix.data.param_size = matrix.param.data_payload_size - - sizeof(matrix.data); + matrix.data.param_size = + sizeof(struct asm_session_mtmx_strtr_param_window_v2_t); matrix.data.reserved = 0; - matrix.window_lsw = window_param->window_lsw; - matrix.window_msw = window_param->window_msw; + memcpy(&(matrix.config.window_param), + window_param, + sizeof(struct asm_session_mtmx_strtr_param_window_v2_t)); rc = apr_send_pkt(ac->apr, (uint32_t *) &matrix); if (rc < 0) { @@ -7973,7 +7975,177 @@ int q6asm_send_mtmx_strtr_window(struct audio_client *ac, rc = 0; fail_cmd: return rc; -}; +} + +int q6asm_send_mtmx_strtr_render_mode(struct audio_client *ac, + uint32_t render_mode) +{ + struct asm_mtmx_strtr_params matrix; + struct asm_session_mtmx_strtr_param_render_mode_t render_param; + int sz = 0; + int rc = 0; + + pr_debug("%s: render mode is %d\n", __func__, render_mode); + + if (!ac) { + pr_err("%s: audio client handle is NULL\n", __func__); + rc = -EINVAL; + goto exit; + } + + if (ac->apr == NULL) { + pr_err("%s: ac->apr is NULL\n", __func__); + rc = -EINVAL; + goto exit; + } + + if ((render_mode != ASM_SESSION_MTMX_STRTR_PARAM_RENDER_DEFAULT) && + (render_mode != ASM_SESSION_MTMX_STRTR_PARAM_RENDER_LOCAL_STC)) { + pr_err("%s: Invalid render mode %d\n", __func__, render_mode); + rc = -EINVAL; + goto exit; + } + + memset(&render_param, 0, + sizeof(struct asm_session_mtmx_strtr_param_render_mode_t)); + render_param.flags = render_mode; + + memset(&matrix, 0, sizeof(struct asm_mtmx_strtr_params)); + sz = sizeof(struct asm_mtmx_strtr_params); + q6asm_add_hdr(ac, &matrix.hdr, sz, TRUE); + atomic_set(&ac->cmd_state, -1); + matrix.hdr.opcode = ASM_SESSION_CMD_SET_MTMX_STRTR_PARAMS_V2; + + matrix.param.data_payload_addr_lsw = 0; + matrix.param.data_payload_addr_msw = 0; + matrix.param.mem_map_handle = 0; + matrix.param.data_payload_size = + sizeof(struct asm_stream_param_data_v2) + + sizeof(struct asm_session_mtmx_strtr_param_render_mode_t); + matrix.param.direction = 0; /* RX */ + matrix.data.module_id = ASM_SESSION_MTMX_STRTR_MODULE_ID_AVSYNC; + matrix.data.param_id = ASM_SESSION_MTMX_STRTR_PARAM_RENDER_MODE_CMD; + matrix.data.param_size = + sizeof(struct asm_session_mtmx_strtr_param_render_mode_t); + matrix.data.reserved = 0; + memcpy(&(matrix.config.render_param), + &render_param, + sizeof(struct asm_session_mtmx_strtr_param_render_mode_t)); + + rc = apr_send_pkt(ac->apr, (uint32_t *) &matrix); + if (rc < 0) { + pr_err("%s: Render mode send failed paramid [0x%x]\n", + __func__, matrix.data.param_id); + rc = -EINVAL; + goto exit; + } + + rc = wait_event_timeout(ac->cmd_wait, + (atomic_read(&ac->cmd_state) >= 0), 5*HZ); + if (!rc) { + pr_err("%s: timeout, Render mode send paramid [0x%x]\n", + __func__, matrix.data.param_id); + rc = -ETIMEDOUT; + goto exit; + } + + if (atomic_read(&ac->cmd_state) > 0) { + pr_err("%s: DSP returned error[%s]\n", + __func__, adsp_err_get_err_str( + atomic_read(&ac->cmd_state))); + rc = adsp_err_get_lnx_err_code( + atomic_read(&ac->cmd_state)); + goto exit; + } + rc = 0; +exit: + return rc; +} + +int q6asm_send_mtmx_strtr_clk_rec_mode(struct audio_client *ac, + uint32_t clk_rec_mode) +{ + struct asm_mtmx_strtr_params matrix; + struct asm_session_mtmx_strtr_param_clk_rec_t clk_rec_param; + int sz = 0; + int rc = 0; + + pr_debug("%s: clk rec mode is %d\n", __func__, clk_rec_mode); + + if (!ac) { + pr_err("%s: audio client handle is NULL\n", __func__); + rc = -EINVAL; + goto exit; + } + + if (ac->apr == NULL) { + pr_err("%s: ac->apr is NULL\n", __func__); + rc = -EINVAL; + goto exit; + } + + if ((clk_rec_mode != ASM_SESSION_MTMX_STRTR_PARAM_CLK_REC_NONE) && + (clk_rec_mode != ASM_SESSION_MTMX_STRTR_PARAM_CLK_REC_AUTO)) { + pr_err("%s: Invalid clk rec mode %d\n", __func__, clk_rec_mode); + rc = -EINVAL; + goto exit; + } + + memset(&clk_rec_param, 0, + sizeof(struct asm_session_mtmx_strtr_param_clk_rec_t)); + clk_rec_param.flags = clk_rec_mode; + + memset(&matrix, 0, sizeof(struct asm_mtmx_strtr_params)); + sz = sizeof(struct asm_mtmx_strtr_params); + q6asm_add_hdr(ac, &matrix.hdr, sz, TRUE); + atomic_set(&ac->cmd_state, -1); + matrix.hdr.opcode = ASM_SESSION_CMD_SET_MTMX_STRTR_PARAMS_V2; + + matrix.param.data_payload_addr_lsw = 0; + matrix.param.data_payload_addr_msw = 0; + matrix.param.mem_map_handle = 0; + matrix.param.data_payload_size = + sizeof(struct asm_stream_param_data_v2) + + sizeof(struct asm_session_mtmx_strtr_param_clk_rec_t); + matrix.param.direction = 0; /* RX */ + matrix.data.module_id = ASM_SESSION_MTMX_STRTR_MODULE_ID_AVSYNC; + matrix.data.param_id = ASM_SESSION_MTMX_STRTR_PARAM_CLK_REC_CMD; + matrix.data.param_size = + sizeof(struct asm_session_mtmx_strtr_param_clk_rec_t); + matrix.data.reserved = 0; + memcpy(&(matrix.config.clk_rec_param), + &clk_rec_param, + sizeof(struct asm_session_mtmx_strtr_param_clk_rec_t)); + + rc = apr_send_pkt(ac->apr, (uint32_t *) &matrix); + if (rc < 0) { + pr_err("%s: clk rec mode send failed paramid [0x%x]\n", + __func__, matrix.data.param_id); + rc = -EINVAL; + goto exit; + } + + rc = wait_event_timeout(ac->cmd_wait, + (atomic_read(&ac->cmd_state) >= 0), 5*HZ); + if (!rc) { + pr_err("%s: timeout, clk rec mode send paramid [0x%x]\n", + __func__, matrix.data.param_id); + rc = -ETIMEDOUT; + goto exit; + } + + if (atomic_read(&ac->cmd_state) > 0) { + pr_err("%s: DSP returned error[%s]\n", + __func__, adsp_err_get_err_str( + atomic_read(&ac->cmd_state))); + rc = adsp_err_get_lnx_err_code( + atomic_read(&ac->cmd_state)); + goto exit; + } + rc = 0; +exit: + return rc; +} static int __q6asm_cmd(struct audio_client *ac, int cmd, uint32_t stream_id) { diff --git a/sound/soc/msm/qdsp6v2/q6audio-v2.c b/sound/soc/msm/qdsp6v2/q6audio-v2.c index a4951dc77378..3b745c24f90e 100644 --- a/sound/soc/msm/qdsp6v2/q6audio-v2.c +++ b/sound/soc/msm/qdsp6v2/q6audio-v2.c @@ -1,4 +1,4 @@ -/* 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 @@ -64,7 +64,6 @@ int q6audio_get_port_index(u16 port_id) case SLIMBUS_3_TX: return IDX_SLIMBUS_3_TX; case SLIMBUS_4_RX: return IDX_SLIMBUS_4_RX; case SLIMBUS_4_TX: return IDX_SLIMBUS_4_TX; - case SLIMBUS_TX_VI: return IDX_SLIMBUS_4_TX; case SLIMBUS_5_RX: return IDX_SLIMBUS_5_RX; case SLIMBUS_5_TX: return IDX_SLIMBUS_5_TX; case SLIMBUS_6_RX: return IDX_SLIMBUS_6_RX; @@ -312,7 +311,6 @@ int q6audio_get_port_id(u16 port_id) case SLIMBUS_3_TX: return AFE_PORT_ID_SLIMBUS_MULTI_CHAN_3_TX; case SLIMBUS_4_RX: return AFE_PORT_ID_SLIMBUS_MULTI_CHAN_4_RX; case SLIMBUS_4_TX: return AFE_PORT_ID_SLIMBUS_MULTI_CHAN_4_TX; - case SLIMBUS_TX_VI: return AFE_PORT_ID_SLIMBUS_MULTI_CHAN_4_TX; case SLIMBUS_5_RX: return AFE_PORT_ID_SLIMBUS_MULTI_CHAN_5_RX; case SLIMBUS_5_TX: return AFE_PORT_ID_SLIMBUS_MULTI_CHAN_5_TX; case SLIMBUS_6_RX: return AFE_PORT_ID_SLIMBUS_MULTI_CHAN_6_RX; @@ -690,7 +688,6 @@ int q6audio_validate_port(u16 port_id) case SLIMBUS_3_TX: case SLIMBUS_4_RX: case SLIMBUS_4_TX: - case SLIMBUS_TX_VI: case SLIMBUS_5_RX: case SLIMBUS_5_TX: case SLIMBUS_6_RX: diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index eb894d073c07..736b9c45e59a 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -527,6 +527,11 @@ static int soc_compr_set_params_fe(struct snd_compr_stream *cstream, cstream, &async_domain); } else { be_list[j++] = be; + if (j == DPCM_MAX_BE_USERS) { + dev_dbg(fe->dev, + "ASoC: MAX backend users!\n"); + break; + } } } for (i = 0; i < j; i++) { diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 13649f96b370..0ba9dfb854b3 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -2403,6 +2403,10 @@ void dpcm_be_dai_prepare_async(struct snd_soc_pcm_runtime *fe, int stream, dpcm, domain); } else { dpcm_async[i++] = dpcm; + if (i == DPCM_MAX_BE_USERS) { + dev_dbg(fe->dev, "ASoC: MAX backend users!\n"); + break; + } } } |
