diff options
67 files changed, 1916 insertions, 2455 deletions
diff --git a/Documentation/devicetree/bindings/arm/msm/wil6210.txt b/Documentation/devicetree/bindings/arm/msm/wil6210.txt index c4673279953d..54bbf2535340 100644 --- a/Documentation/devicetree/bindings/arm/msm/wil6210.txt +++ b/Documentation/devicetree/bindings/arm/msm/wil6210.txt @@ -32,6 +32,8 @@ Optional properties: - clocks : List of phandle and clock specifier pairs - clock-names : List of clock input name strings sorted in the same order as the clocks property. +- qcom,keep_radio_on_during_sleep: Boolean flag to indicate if to suspend to d3hot + instead of turning off the device Example: wil6210: qcom,wil6210 { @@ -56,5 +58,6 @@ Example: clocks = <&clock_gcc clk_rf_clk3>, <&clock_gcc clk_rf_clk3_pin>; clock-names = "rf_clk3_clk", "rf_clk3_pin_clk"; + qcom,keep_radio_on_during_sleep; }; diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt index acf12239c813..dec5442b33d6 100644 --- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt +++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt @@ -1245,12 +1245,9 @@ Required properties: When clock rate is set to zero, then external clock is assumed. - [Second Level Nodes] - -Required properties: - - - compatible : "qcom,msm-dai-q6-tdm" - - qcom,msm-dai-q6-mi2s-dev-id: TDM port ID. + - qcom,msm-cpudai-tdm-clk-internal: Clock Source. + 0 - EBIT clock from clk tree + 1 - IBIT clock from clk tree - qcom,msm-cpudai-tdm-sync-mode: Synchronization setting. 0 - Short sync bit mode @@ -1275,6 +1272,13 @@ Required properties: 1 - 1 bit clock cycle 2 - 2 bit clock cycle + [Second Level Nodes] + +Required properties: + + - compatible : "qcom,msm-dai-q6-tdm" + - qcom,msm-dai-q6-mi2s-dev-id: TDM port ID. + - qcom,msm-cpudai-tdm-data-align: Indicate how data is packed within the slot. For example, 32 slot width in case of sample bit width is 24. @@ -1309,17 +1313,18 @@ Example: qcom,msm-cpudai-tdm-group-num-ports = <1>; qcom,msm-cpudai-tdm-group-port-id = <36912>; qcom,msm-cpudai-tdm-clk-rate = <12288000>; + qcom,msm-cpudai-tdm-clk-internal = <1>; + qcom,msm-cpudai-tdm-sync-mode = <0>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <0>; + qcom,msm-cpudai-tdm-data-delay = <0>; pinctrl-names = "default", "sleep"; pinctrl-0 = <&quat_tdm_active &quat_tdm_dout_active>; pinctrl-1 = <&quat_tdm_sleep &quat_tdm_dout_sleep>; dai_quat_tdm_rx_0: qcom,msm-dai-q6-tdm-quat-rx-0 { compatible = "qcom,msm-dai-q6-tdm"; qcom,msm-cpudai-tdm-dev-id = <36912>; - qcom,msm-cpudai-tdm-sync-mode = <0>; - qcom,msm-cpudai-tdm-sync-src = <1>; - qcom,msm-cpudai-tdm-data-out = <0>; - qcom,msm-cpudai-tdm-invert-sync = <0>; - qcom,msm-cpudai-tdm-data-delay = <0>; qcom,msm-cpudai-tdm-data-align = <0>; qcom,msm-cpudai-tdm-header-start-offset = <0>; qcom,msm-cpudai-tdm-header-width = <2>; diff --git a/arch/arm/boot/dts/qcom/apq8096-auto-dragonboard.dtsi b/arch/arm/boot/dts/qcom/apq8096-auto-dragonboard.dtsi index 549bb9c169ce..ea8fc87c9b67 100644 --- a/arch/arm/boot/dts/qcom/apq8096-auto-dragonboard.dtsi +++ b/arch/arm/boot/dts/qcom/apq8096-auto-dragonboard.dtsi @@ -705,22 +705,9 @@ }; qcom,msm-dai-tdm-tert-rx { - qcom,msm-cpudai-tdm-group-num-ports = <5>; - qcom,msm-cpudai-tdm-group-port-id = <36896 36898 36900 - 36902 36904>; pinctrl-names = "default", "sleep"; pinctrl-0 = <&tert_tdm_dout_active>; pinctrl-1 = <&tert_tdm_dout_sleep>; - dai_tert_tdm_rx_4: qcom,msm-dai-q6-tdm-tert-rx-4 { - compatible = "qcom,msm-dai-q6-tdm"; - qcom,msm-cpudai-tdm-dev-id = <36904>; - qcom,msm-cpudai-tdm-sync-mode = <1>; - qcom,msm-cpudai-tdm-sync-src = <0>; - qcom,msm-cpudai-tdm-data-out = <0>; - qcom,msm-cpudai-tdm-invert-sync = <0>; - qcom,msm-cpudai-tdm-data-delay = <0>; - qcom,msm-cpudai-tdm-data-align = <0>; - }; }; qcom,msm-dai-tdm-quat-rx { diff --git a/arch/arm/boot/dts/qcom/apq8098-v2.1-mediabox.dts b/arch/arm/boot/dts/qcom/apq8098-v2.1-mediabox.dts index 03e1e05a3739..822757ae1ec4 100644 --- a/arch/arm/boot/dts/qcom/apq8098-v2.1-mediabox.dts +++ b/arch/arm/boot/dts/qcom/apq8098-v2.1-mediabox.dts @@ -31,7 +31,6 @@ }; &mdss_mdp { - status = "disabled"; qcom,mdss-pref-prim-intf = "hdmi"; }; diff --git a/arch/arm/boot/dts/qcom/msm-audio-lpass.dtsi b/arch/arm/boot/dts/qcom/msm-audio-lpass.dtsi index 97a134b46713..d4962df321ed 100644 --- a/arch/arm/boot/dts/qcom/msm-audio-lpass.dtsi +++ b/arch/arm/boot/dts/qcom/msm-audio-lpass.dtsi @@ -377,14 +377,15 @@ qcom,msm-cpudai-tdm-group-num-ports = <1>; qcom,msm-cpudai-tdm-group-port-id = <36864>; qcom,msm-cpudai-tdm-clk-rate = <1536000>; + qcom,msm-cpudai-tdm-clk-internal = <1>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <1>; + qcom,msm-cpudai-tdm-data-delay = <1>; dai_pri_tdm_rx_0: qcom,msm-dai-q6-tdm-pri-rx-0 { compatible = "qcom,msm-dai-q6-tdm"; qcom,msm-cpudai-tdm-dev-id = <36864>; - qcom,msm-cpudai-tdm-sync-mode = <1>; - qcom,msm-cpudai-tdm-sync-src = <1>; - qcom,msm-cpudai-tdm-data-out = <0>; - qcom,msm-cpudai-tdm-invert-sync = <1>; - qcom,msm-cpudai-tdm-data-delay = <1>; qcom,msm-cpudai-tdm-data-align = <0>; }; }; @@ -395,14 +396,15 @@ qcom,msm-cpudai-tdm-group-num-ports = <1>; qcom,msm-cpudai-tdm-group-port-id = <36865>; qcom,msm-cpudai-tdm-clk-rate = <1536000>; + qcom,msm-cpudai-tdm-clk-internal = <1>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <1>; + qcom,msm-cpudai-tdm-data-delay = <1>; dai_pri_tdm_tx_0: qcom,msm-dai-q6-tdm-pri-tx-0 { compatible = "qcom,msm-dai-q6-tdm"; qcom,msm-cpudai-tdm-dev-id = <36865>; - qcom,msm-cpudai-tdm-sync-mode = <1>; - qcom,msm-cpudai-tdm-sync-src = <1>; - qcom,msm-cpudai-tdm-data-out = <0>; - qcom,msm-cpudai-tdm-invert-sync = <1>; - qcom,msm-cpudai-tdm-data-delay = <1>; qcom,msm-cpudai-tdm-data-align = <0>; }; }; @@ -413,14 +415,15 @@ qcom,msm-cpudai-tdm-group-num-ports = <1>; qcom,msm-cpudai-tdm-group-port-id = <36880>; qcom,msm-cpudai-tdm-clk-rate = <1536000>; + qcom,msm-cpudai-tdm-clk-internal = <1>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <1>; + qcom,msm-cpudai-tdm-data-delay = <1>; dai_sec_tdm_rx_0: qcom,msm-dai-q6-tdm-sec-rx-0 { compatible = "qcom,msm-dai-q6-tdm"; qcom,msm-cpudai-tdm-dev-id = <36880>; - qcom,msm-cpudai-tdm-sync-mode = <1>; - qcom,msm-cpudai-tdm-sync-src = <1>; - qcom,msm-cpudai-tdm-data-out = <0>; - qcom,msm-cpudai-tdm-invert-sync = <1>; - qcom,msm-cpudai-tdm-data-delay = <1>; qcom,msm-cpudai-tdm-data-align = <0>; }; }; @@ -431,14 +434,15 @@ qcom,msm-cpudai-tdm-group-num-ports = <1>; qcom,msm-cpudai-tdm-group-port-id = <36881>; qcom,msm-cpudai-tdm-clk-rate = <1536000>; + qcom,msm-cpudai-tdm-clk-internal = <1>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <1>; + qcom,msm-cpudai-tdm-data-delay = <1>; dai_sec_tdm_tx_0: qcom,msm-dai-q6-tdm-sec-tx-0 { compatible = "qcom,msm-dai-q6-tdm"; qcom,msm-cpudai-tdm-dev-id = <36881>; - qcom,msm-cpudai-tdm-sync-mode = <1>; - qcom,msm-cpudai-tdm-sync-src = <1>; - qcom,msm-cpudai-tdm-data-out = <0>; - qcom,msm-cpudai-tdm-invert-sync = <1>; - qcom,msm-cpudai-tdm-data-delay = <1>; qcom,msm-cpudai-tdm-data-align = <0>; }; }; @@ -449,14 +453,15 @@ qcom,msm-cpudai-tdm-group-num-ports = <1>; qcom,msm-cpudai-tdm-group-port-id = <36896>; qcom,msm-cpudai-tdm-clk-rate = <1536000>; + qcom,msm-cpudai-tdm-clk-internal = <1>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <1>; + qcom,msm-cpudai-tdm-data-delay = <1>; dai_tert_tdm_rx_0: qcom,msm-dai-q6-tdm-tert-rx-0 { compatible = "qcom,msm-dai-q6-tdm"; qcom,msm-cpudai-tdm-dev-id = <36896>; - qcom,msm-cpudai-tdm-sync-mode = <1>; - qcom,msm-cpudai-tdm-sync-src = <1>; - qcom,msm-cpudai-tdm-data-out = <0>; - qcom,msm-cpudai-tdm-invert-sync = <1>; - qcom,msm-cpudai-tdm-data-delay = <1>; qcom,msm-cpudai-tdm-data-align = <0>; }; }; @@ -467,14 +472,15 @@ qcom,msm-cpudai-tdm-group-num-ports = <1>; qcom,msm-cpudai-tdm-group-port-id = <36897 >; qcom,msm-cpudai-tdm-clk-rate = <1536000>; + qcom,msm-cpudai-tdm-clk-internal = <1>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <1>; + qcom,msm-cpudai-tdm-data-delay = <1>; dai_tert_tdm_tx_0: qcom,msm-dai-q6-tdm-tert-tx-0 { compatible = "qcom,msm-dai-q6-tdm"; qcom,msm-cpudai-tdm-dev-id = <36897 >; - qcom,msm-cpudai-tdm-sync-mode = <1>; - qcom,msm-cpudai-tdm-sync-src = <1>; - qcom,msm-cpudai-tdm-data-out = <0>; - qcom,msm-cpudai-tdm-invert-sync = <1>; - qcom,msm-cpudai-tdm-data-delay = <1>; qcom,msm-cpudai-tdm-data-align = <0>; }; }; @@ -485,14 +491,15 @@ qcom,msm-cpudai-tdm-group-num-ports = <1>; qcom,msm-cpudai-tdm-group-port-id = <36912>; qcom,msm-cpudai-tdm-clk-rate = <1536000>; + qcom,msm-cpudai-tdm-clk-internal = <1>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <1>; + qcom,msm-cpudai-tdm-data-delay = <1>; dai_quat_tdm_rx_0: qcom,msm-dai-q6-tdm-quat-rx-0 { compatible = "qcom,msm-dai-q6-tdm"; qcom,msm-cpudai-tdm-dev-id = <36912>; - qcom,msm-cpudai-tdm-sync-mode = <1>; - qcom,msm-cpudai-tdm-sync-src = <1>; - qcom,msm-cpudai-tdm-data-out = <0>; - qcom,msm-cpudai-tdm-invert-sync = <1>; - qcom,msm-cpudai-tdm-data-delay = <1>; qcom,msm-cpudai-tdm-data-align = <0>; }; }; @@ -503,14 +510,15 @@ qcom,msm-cpudai-tdm-group-num-ports = <1>; qcom,msm-cpudai-tdm-group-port-id = <36913 >; qcom,msm-cpudai-tdm-clk-rate = <1536000>; + qcom,msm-cpudai-tdm-clk-internal = <1>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <1>; + qcom,msm-cpudai-tdm-data-delay = <1>; dai_quat_tdm_tx_0: qcom,msm-dai-q6-tdm-quat-tx-0 { compatible = "qcom,msm-dai-q6-tdm"; qcom,msm-cpudai-tdm-dev-id = <36913 >; - qcom,msm-cpudai-tdm-sync-mode = <1>; - qcom,msm-cpudai-tdm-sync-src = <1>; - qcom,msm-cpudai-tdm-data-out = <0>; - qcom,msm-cpudai-tdm-invert-sync = <1>; - qcom,msm-cpudai-tdm-data-delay = <1>; qcom,msm-cpudai-tdm-data-align = <0>; }; }; diff --git a/arch/arm/boot/dts/qcom/msm-audio.dtsi b/arch/arm/boot/dts/qcom/msm-audio.dtsi index d450f43f8c22..3a7514397139 100644 --- a/arch/arm/boot/dts/qcom/msm-audio.dtsi +++ b/arch/arm/boot/dts/qcom/msm-audio.dtsi @@ -445,14 +445,15 @@ qcom,msm-cpudai-tdm-group-num-ports = <1>; qcom,msm-cpudai-tdm-group-port-id = <36864>; qcom,msm-cpudai-tdm-clk-rate = <1536000>; + qcom,msm-cpudai-tdm-clk-internal = <1>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <1>; + qcom,msm-cpudai-tdm-data-delay = <1>; dai_pri_tdm_rx_0: qcom,msm-dai-q6-tdm-pri-rx-0 { compatible = "qcom,msm-dai-q6-tdm"; qcom,msm-cpudai-tdm-dev-id = <36864>; - qcom,msm-cpudai-tdm-sync-mode = <1>; - qcom,msm-cpudai-tdm-sync-src = <1>; - qcom,msm-cpudai-tdm-data-out = <0>; - qcom,msm-cpudai-tdm-invert-sync = <1>; - qcom,msm-cpudai-tdm-data-delay = <1>; qcom,msm-cpudai-tdm-data-align = <0>; }; }; @@ -463,14 +464,15 @@ qcom,msm-cpudai-tdm-group-num-ports = <1>; qcom,msm-cpudai-tdm-group-port-id = <36865>; qcom,msm-cpudai-tdm-clk-rate = <1536000>; + qcom,msm-cpudai-tdm-clk-internal = <1>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <1>; + qcom,msm-cpudai-tdm-data-delay = <1>; dai_pri_tdm_tx_0: qcom,msm-dai-q6-tdm-pri-tx-0 { compatible = "qcom,msm-dai-q6-tdm"; qcom,msm-cpudai-tdm-dev-id = <36865>; - qcom,msm-cpudai-tdm-sync-mode = <1>; - qcom,msm-cpudai-tdm-sync-src = <1>; - qcom,msm-cpudai-tdm-data-out = <0>; - qcom,msm-cpudai-tdm-invert-sync = <1>; - qcom,msm-cpudai-tdm-data-delay = <1>; qcom,msm-cpudai-tdm-data-align = <0>; }; }; @@ -481,14 +483,15 @@ qcom,msm-cpudai-tdm-group-num-ports = <1>; qcom,msm-cpudai-tdm-group-port-id = <36880>; qcom,msm-cpudai-tdm-clk-rate = <1536000>; + qcom,msm-cpudai-tdm-clk-internal = <1>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <1>; + qcom,msm-cpudai-tdm-data-delay = <1>; dai_sec_tdm_rx_0: qcom,msm-dai-q6-tdm-sec-rx-0 { compatible = "qcom,msm-dai-q6-tdm"; qcom,msm-cpudai-tdm-dev-id = <36880>; - qcom,msm-cpudai-tdm-sync-mode = <1>; - qcom,msm-cpudai-tdm-sync-src = <1>; - qcom,msm-cpudai-tdm-data-out = <0>; - qcom,msm-cpudai-tdm-invert-sync = <1>; - qcom,msm-cpudai-tdm-data-delay = <1>; qcom,msm-cpudai-tdm-data-align = <0>; }; }; @@ -499,14 +502,15 @@ qcom,msm-cpudai-tdm-group-num-ports = <1>; qcom,msm-cpudai-tdm-group-port-id = <36881>; qcom,msm-cpudai-tdm-clk-rate = <1536000>; + qcom,msm-cpudai-tdm-clk-internal = <1>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <1>; + qcom,msm-cpudai-tdm-data-delay = <1>; dai_sec_tdm_tx_0: qcom,msm-dai-q6-tdm-sec-tx-0 { compatible = "qcom,msm-dai-q6-tdm"; qcom,msm-cpudai-tdm-dev-id = <36881>; - qcom,msm-cpudai-tdm-sync-mode = <1>; - qcom,msm-cpudai-tdm-sync-src = <1>; - qcom,msm-cpudai-tdm-data-out = <0>; - qcom,msm-cpudai-tdm-invert-sync = <1>; - qcom,msm-cpudai-tdm-data-delay = <1>; qcom,msm-cpudai-tdm-data-align = <0>; }; }; @@ -517,14 +521,15 @@ qcom,msm-cpudai-tdm-group-num-ports = <1>; qcom,msm-cpudai-tdm-group-port-id = <36896>; qcom,msm-cpudai-tdm-clk-rate = <1536000>; + qcom,msm-cpudai-tdm-clk-internal = <1>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <1>; + qcom,msm-cpudai-tdm-data-delay = <1>; dai_tert_tdm_rx_0: qcom,msm-dai-q6-tdm-tert-rx-0 { compatible = "qcom,msm-dai-q6-tdm"; qcom,msm-cpudai-tdm-dev-id = <36896>; - qcom,msm-cpudai-tdm-sync-mode = <1>; - qcom,msm-cpudai-tdm-sync-src = <1>; - qcom,msm-cpudai-tdm-data-out = <0>; - qcom,msm-cpudai-tdm-invert-sync = <1>; - qcom,msm-cpudai-tdm-data-delay = <1>; qcom,msm-cpudai-tdm-data-align = <0>; }; }; @@ -535,14 +540,15 @@ qcom,msm-cpudai-tdm-group-num-ports = <1>; qcom,msm-cpudai-tdm-group-port-id = <36897 >; qcom,msm-cpudai-tdm-clk-rate = <1536000>; + qcom,msm-cpudai-tdm-clk-internal = <1>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <1>; + qcom,msm-cpudai-tdm-data-delay = <1>; dai_tert_tdm_tx_0: qcom,msm-dai-q6-tdm-tert-tx-0 { compatible = "qcom,msm-dai-q6-tdm"; qcom,msm-cpudai-tdm-dev-id = <36897 >; - qcom,msm-cpudai-tdm-sync-mode = <1>; - qcom,msm-cpudai-tdm-sync-src = <1>; - qcom,msm-cpudai-tdm-data-out = <0>; - qcom,msm-cpudai-tdm-invert-sync = <1>; - qcom,msm-cpudai-tdm-data-delay = <1>; qcom,msm-cpudai-tdm-data-align = <0>; }; }; @@ -553,14 +559,15 @@ qcom,msm-cpudai-tdm-group-num-ports = <1>; qcom,msm-cpudai-tdm-group-port-id = <36912>; qcom,msm-cpudai-tdm-clk-rate = <1536000>; + qcom,msm-cpudai-tdm-clk-internal = <1>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <1>; + qcom,msm-cpudai-tdm-data-delay = <1>; dai_quat_tdm_rx_0: qcom,msm-dai-q6-tdm-quat-rx-0 { compatible = "qcom,msm-dai-q6-tdm"; qcom,msm-cpudai-tdm-dev-id = <36912>; - qcom,msm-cpudai-tdm-sync-mode = <1>; - qcom,msm-cpudai-tdm-sync-src = <1>; - qcom,msm-cpudai-tdm-data-out = <0>; - qcom,msm-cpudai-tdm-invert-sync = <1>; - qcom,msm-cpudai-tdm-data-delay = <1>; qcom,msm-cpudai-tdm-data-align = <0>; }; }; @@ -571,14 +578,15 @@ qcom,msm-cpudai-tdm-group-num-ports = <1>; qcom,msm-cpudai-tdm-group-port-id = <36913 >; qcom,msm-cpudai-tdm-clk-rate = <1536000>; + qcom,msm-cpudai-tdm-clk-internal = <1>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <1>; + qcom,msm-cpudai-tdm-data-delay = <1>; dai_quat_tdm_tx_0: qcom,msm-dai-q6-tdm-quat-tx-0 { compatible = "qcom,msm-dai-q6-tdm"; qcom,msm-cpudai-tdm-dev-id = <36913 >; - qcom,msm-cpudai-tdm-sync-mode = <1>; - qcom,msm-cpudai-tdm-sync-src = <1>; - qcom,msm-cpudai-tdm-data-out = <0>; - qcom,msm-cpudai-tdm-invert-sync = <1>; - qcom,msm-cpudai-tdm-data-delay = <1>; qcom,msm-cpudai-tdm-data-align = <0>; }; }; diff --git a/arch/arm/boot/dts/qcom/msm8996-agave-adp.dtsi b/arch/arm/boot/dts/qcom/msm8996-agave-adp.dtsi index fc26c16f6bf5..eae8c29fe21e 100644 --- a/arch/arm/boot/dts/qcom/msm8996-agave-adp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996-agave-adp.dtsi @@ -1010,22 +1010,9 @@ }; qcom,msm-dai-tdm-tert-rx { - qcom,msm-cpudai-tdm-group-num-ports = <5>; - qcom,msm-cpudai-tdm-group-port-id = <36896 36898 36900 - 36902 36904>; pinctrl-names = "default", "sleep"; pinctrl-0 = <&tert_tdm_dout_active>; pinctrl-1 = <&tert_tdm_dout_sleep>; - dai_tert_tdm_rx_4: qcom,msm-dai-q6-tdm-tert-rx-4 { - compatible = "qcom,msm-dai-q6-tdm"; - qcom,msm-cpudai-tdm-dev-id = <36904>; - qcom,msm-cpudai-tdm-sync-mode = <1>; - qcom,msm-cpudai-tdm-sync-src = <0>; - qcom,msm-cpudai-tdm-data-out = <0>; - qcom,msm-cpudai-tdm-invert-sync = <0>; - qcom,msm-cpudai-tdm-data-delay = <0>; - qcom,msm-cpudai-tdm-data-align = <0>; - }; }; qcom,msm-dai-tdm-quat-rx { diff --git a/arch/arm/boot/dts/qcom/msm8996-auto-cdp.dtsi b/arch/arm/boot/dts/qcom/msm8996-auto-cdp.dtsi index 01f67b041b76..3e28f21eaac1 100644 --- a/arch/arm/boot/dts/qcom/msm8996-auto-cdp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996-auto-cdp.dtsi @@ -725,22 +725,9 @@ }; qcom,msm-dai-tdm-tert-rx { - qcom,msm-cpudai-tdm-group-num-ports = <5>; - qcom,msm-cpudai-tdm-group-port-id = <36896 36898 36900 - 36902 36904>; pinctrl-names = "default", "sleep"; pinctrl-0 = <&tert_tdm_dout_active>; pinctrl-1 = <&tert_tdm_dout_sleep>; - dai_tert_tdm_rx_4: qcom,msm-dai-q6-tdm-tert-rx-4 { - compatible = "qcom,msm-dai-q6-tdm"; - qcom,msm-cpudai-tdm-dev-id = <36904>; - qcom,msm-cpudai-tdm-sync-mode = <1>; - qcom,msm-cpudai-tdm-sync-src = <0>; - qcom,msm-cpudai-tdm-data-out = <0>; - qcom,msm-cpudai-tdm-invert-sync = <0>; - qcom,msm-cpudai-tdm-data-delay = <0>; - qcom,msm-cpudai-tdm-data-align = <0>; - }; }; qcom,msm-dai-tdm-quat-rx { diff --git a/arch/arm/boot/dts/qcom/msm8996-mmxf-adp.dtsi b/arch/arm/boot/dts/qcom/msm8996-mmxf-adp.dtsi index c5b6e7d0a3dc..53c3c7e727bc 100644 --- a/arch/arm/boot/dts/qcom/msm8996-mmxf-adp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996-mmxf-adp.dtsi @@ -595,22 +595,9 @@ }; qcom,msm-dai-tdm-tert-rx { - qcom,msm-cpudai-tdm-group-num-ports = <5>; - qcom,msm-cpudai-tdm-group-port-id = <36896 36898 36900 - 36902 36904>; pinctrl-names = "default", "sleep"; pinctrl-0 = <&tert_tdm_dout_active>; pinctrl-1 = <&tert_tdm_dout_sleep>; - dai_tert_tdm_rx_4: qcom,msm-dai-q6-tdm-tert-rx-4 { - compatible = "qcom,msm-dai-q6-tdm"; - qcom,msm-cpudai-tdm-dev-id = <36904>; - qcom,msm-cpudai-tdm-sync-mode = <1>; - qcom,msm-cpudai-tdm-sync-src = <0>; - qcom,msm-cpudai-tdm-data-out = <0>; - qcom,msm-cpudai-tdm-invert-sync = <0>; - qcom,msm-cpudai-tdm-data-delay = <0>; - qcom,msm-cpudai-tdm-data-align = <0>; - }; }; qcom,msm-dai-tdm-quat-rx { diff --git a/arch/arm/boot/dts/qcom/msm8996.dtsi b/arch/arm/boot/dts/qcom/msm8996.dtsi index 1752256029e7..ee069f5d8bdf 100644 --- a/arch/arm/boot/dts/qcom/msm8996.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996.dtsi @@ -3356,48 +3356,34 @@ qcom,msm-cpudai-tdm-group-id = <37137>; qcom,msm-cpudai-tdm-group-num-ports = <4>; qcom,msm-cpudai-tdm-group-port-id = <36881 36883 36885 36887>; - qcom,msm-cpudai-tdm-clk-rate = <0>; + qcom,msm-cpudai-tdm-clk-rate = <12288000>; + qcom,msm-cpudai-tdm-clk-internal = <0>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <0>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <0>; + qcom,msm-cpudai-tdm-data-delay = <0>; dai_sec_tdm_tx_0: qcom,msm-dai-q6-tdm-sec-tx-0 { compatible = "qcom,msm-dai-q6-tdm"; qcom,msm-cpudai-tdm-dev-id = <36881>; - qcom,msm-cpudai-tdm-sync-mode = <1>; - qcom,msm-cpudai-tdm-sync-src = <0>; - qcom,msm-cpudai-tdm-data-out = <0>; - qcom,msm-cpudai-tdm-invert-sync = <0>; - qcom,msm-cpudai-tdm-data-delay = <0>; qcom,msm-cpudai-tdm-data-align = <0>; }; dai_sec_tdm_tx_1: qcom,msm-dai-q6-tdm-sec-tx-1 { compatible = "qcom,msm-dai-q6-tdm"; qcom,msm-cpudai-tdm-dev-id = <36883>; - qcom,msm-cpudai-tdm-sync-mode = <1>; - qcom,msm-cpudai-tdm-sync-src = <0>; - qcom,msm-cpudai-tdm-data-out = <0>; - qcom,msm-cpudai-tdm-invert-sync = <0>; - qcom,msm-cpudai-tdm-data-delay = <0>; qcom,msm-cpudai-tdm-data-align = <0>; }; dai_sec_tdm_tx_2: qcom,msm-dai-q6-tdm-sec-tx-2 { compatible = "qcom,msm-dai-q6-tdm"; qcom,msm-cpudai-tdm-dev-id = <36885>; - qcom,msm-cpudai-tdm-sync-mode = <1>; - qcom,msm-cpudai-tdm-sync-src = <0>; - qcom,msm-cpudai-tdm-data-out = <0>; - qcom,msm-cpudai-tdm-invert-sync = <0>; - qcom,msm-cpudai-tdm-data-delay = <0>; qcom,msm-cpudai-tdm-data-align = <0>; }; dai_sec_tdm_tx_3: qcom,msm-dai-q6-tdm-sec-tx-3 { compatible = "qcom,msm-dai-q6-tdm"; qcom,msm-cpudai-tdm-dev-id = <36887>; - qcom,msm-cpudai-tdm-sync-mode = <1>; - qcom,msm-cpudai-tdm-sync-src = <0>; - qcom,msm-cpudai-tdm-data-out = <0>; - qcom,msm-cpudai-tdm-invert-sync = <0>; - qcom,msm-cpudai-tdm-data-delay = <0>; qcom,msm-cpudai-tdm-data-align = <0>; }; }; @@ -3405,50 +3391,43 @@ qcom,msm-dai-tdm-tert-rx { compatible = "qcom,msm-dai-tdm"; qcom,msm-cpudai-tdm-group-id = <37152>; - qcom,msm-cpudai-tdm-group-num-ports = <4>; - qcom,msm-cpudai-tdm-group-port-id = <36896 36898 36900 36902>; - qcom,msm-cpudai-tdm-clk-rate = <0>; + qcom,msm-cpudai-tdm-group-num-ports = <5>; + qcom,msm-cpudai-tdm-group-port-id = <36896 36898 36900 + 36902 36904>; + qcom,msm-cpudai-tdm-clk-rate = <12288000>; + qcom,msm-cpudai-tdm-clk-internal = <0>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <0>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <0>; + qcom,msm-cpudai-tdm-data-delay = <0>; dai_tert_tdm_rx_0: qcom,msm-dai-q6-tdm-tert-rx-0 { compatible = "qcom,msm-dai-q6-tdm"; qcom,msm-cpudai-tdm-dev-id = <36896>; - qcom,msm-cpudai-tdm-sync-mode = <1>; - qcom,msm-cpudai-tdm-sync-src = <0>; - qcom,msm-cpudai-tdm-data-out = <0>; - qcom,msm-cpudai-tdm-invert-sync = <0>; - qcom,msm-cpudai-tdm-data-delay = <0>; qcom,msm-cpudai-tdm-data-align = <0>; }; dai_tert_tdm_rx_1: qcom,msm-dai-q6-tdm-tert-rx-1 { compatible = "qcom,msm-dai-q6-tdm"; qcom,msm-cpudai-tdm-dev-id = <36898>; - qcom,msm-cpudai-tdm-sync-mode = <1>; - qcom,msm-cpudai-tdm-sync-src = <0>; - qcom,msm-cpudai-tdm-data-out = <0>; - qcom,msm-cpudai-tdm-invert-sync = <0>; - qcom,msm-cpudai-tdm-data-delay = <0>; qcom,msm-cpudai-tdm-data-align = <0>; }; dai_tert_tdm_rx_2: qcom,msm-dai-q6-tdm-tert-rx-2 { compatible = "qcom,msm-dai-q6-tdm"; qcom,msm-cpudai-tdm-dev-id = <36900>; - qcom,msm-cpudai-tdm-sync-mode = <1>; - qcom,msm-cpudai-tdm-sync-src = <0>; - qcom,msm-cpudai-tdm-data-out = <0>; - qcom,msm-cpudai-tdm-invert-sync = <0>; - qcom,msm-cpudai-tdm-data-delay = <0>; qcom,msm-cpudai-tdm-data-align = <0>; }; dai_tert_tdm_rx_3: qcom,msm-dai-q6-tdm-tert-rx-3 { compatible = "qcom,msm-dai-q6-tdm"; qcom,msm-cpudai-tdm-dev-id = <36902>; - qcom,msm-cpudai-tdm-sync-mode = <1>; - qcom,msm-cpudai-tdm-sync-src = <0>; - qcom,msm-cpudai-tdm-data-out = <0>; - qcom,msm-cpudai-tdm-invert-sync = <0>; - qcom,msm-cpudai-tdm-data-delay = <0>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + + dai_tert_tdm_rx_4: qcom,msm-dai-q6-tdm-tert-rx-4 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36904>; qcom,msm-cpudai-tdm-data-align = <0>; }; }; @@ -3458,48 +3437,34 @@ qcom,msm-cpudai-tdm-group-id = <37153>; qcom,msm-cpudai-tdm-group-num-ports = <4>; qcom,msm-cpudai-tdm-group-port-id = <36897 36899 36901 36903>; - qcom,msm-cpudai-tdm-clk-rate = <0>; + qcom,msm-cpudai-tdm-clk-rate = <12288000>; + qcom,msm-cpudai-tdm-clk-internal = <0>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <0>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <0>; + qcom,msm-cpudai-tdm-data-delay = <0>; dai_tert_tdm_tx_0: qcom,msm-dai-q6-tdm-tert-tx-0 { compatible = "qcom,msm-dai-q6-tdm"; qcom,msm-cpudai-tdm-dev-id = <36897>; - qcom,msm-cpudai-tdm-sync-mode = <1>; - qcom,msm-cpudai-tdm-sync-src = <0>; - qcom,msm-cpudai-tdm-data-out = <0>; - qcom,msm-cpudai-tdm-invert-sync = <0>; - qcom,msm-cpudai-tdm-data-delay = <0>; qcom,msm-cpudai-tdm-data-align = <0>; }; dai_tert_tdm_tx_1: qcom,msm-dai-q6-tdm-tert-tx-1 { compatible = "qcom,msm-dai-q6-tdm"; qcom,msm-cpudai-tdm-dev-id = <36899>; - qcom,msm-cpudai-tdm-sync-mode = <1>; - qcom,msm-cpudai-tdm-sync-src = <0>; - qcom,msm-cpudai-tdm-data-out = <0>; - qcom,msm-cpudai-tdm-invert-sync = <0>; - qcom,msm-cpudai-tdm-data-delay = <0>; qcom,msm-cpudai-tdm-data-align = <0>; }; dai_tert_tdm_tx_2: qcom,msm-dai-q6-tdm-tert-tx-2 { compatible = "qcom,msm-dai-q6-tdm"; qcom,msm-cpudai-tdm-dev-id = <36901>; - qcom,msm-cpudai-tdm-sync-mode = <1>; - qcom,msm-cpudai-tdm-sync-src = <0>; - qcom,msm-cpudai-tdm-data-out = <0>; - qcom,msm-cpudai-tdm-invert-sync = <0>; - qcom,msm-cpudai-tdm-data-delay = <0>; qcom,msm-cpudai-tdm-data-align = <0>; }; dai_tert_tdm_tx_3: qcom,msm-dai-q6-tdm-tert-tx-3 { compatible = "qcom,msm-dai-q6-tdm"; qcom,msm-cpudai-tdm-dev-id = <36903>; - qcom,msm-cpudai-tdm-sync-mode = <1>; - qcom,msm-cpudai-tdm-sync-src = <0>; - qcom,msm-cpudai-tdm-data-out = <0>; - qcom,msm-cpudai-tdm-invert-sync = <0>; - qcom,msm-cpudai-tdm-data-delay = <0>; qcom,msm-cpudai-tdm-data-align = <0>; }; }; @@ -3509,48 +3474,34 @@ qcom,msm-cpudai-tdm-group-id = <37168>; qcom,msm-cpudai-tdm-group-num-ports = <4>; qcom,msm-cpudai-tdm-group-port-id = <36912 36914 36916 36918>; - qcom,msm-cpudai-tdm-clk-rate = <0>; + qcom,msm-cpudai-tdm-clk-rate = <12288000>; + qcom,msm-cpudai-tdm-clk-internal = <0>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <0>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <0>; + qcom,msm-cpudai-tdm-data-delay = <0>; dai_quat_tdm_rx_0: qcom,msm-dai-q6-tdm-quat-rx-0 { compatible = "qcom,msm-dai-q6-tdm"; qcom,msm-cpudai-tdm-dev-id = <36912>; - qcom,msm-cpudai-tdm-sync-mode = <1>; - qcom,msm-cpudai-tdm-sync-src = <0>; - qcom,msm-cpudai-tdm-data-out = <0>; - qcom,msm-cpudai-tdm-invert-sync = <0>; - qcom,msm-cpudai-tdm-data-delay = <0>; qcom,msm-cpudai-tdm-data-align = <0>; }; dai_quat_tdm_rx_1: qcom,msm-dai-q6-tdm-quat-rx-1 { compatible = "qcom,msm-dai-q6-tdm"; qcom,msm-cpudai-tdm-dev-id = <36914>; - qcom,msm-cpudai-tdm-sync-mode = <1>; - qcom,msm-cpudai-tdm-sync-src = <0>; - qcom,msm-cpudai-tdm-data-out = <0>; - qcom,msm-cpudai-tdm-invert-sync = <0>; - qcom,msm-cpudai-tdm-data-delay = <0>; qcom,msm-cpudai-tdm-data-align = <0>; }; dai_quat_tdm_rx_2: qcom,msm-dai-q6-tdm-quat-rx-2 { compatible = "qcom,msm-dai-q6-tdm"; qcom,msm-cpudai-tdm-dev-id = <36916>; - qcom,msm-cpudai-tdm-sync-mode = <1>; - qcom,msm-cpudai-tdm-sync-src = <0>; - qcom,msm-cpudai-tdm-data-out = <0>; - qcom,msm-cpudai-tdm-invert-sync = <0>; - qcom,msm-cpudai-tdm-data-delay = <0>; qcom,msm-cpudai-tdm-data-align = <0>; }; dai_quat_tdm_rx_3: qcom,msm-dai-q6-tdm-quat-rx-3 { compatible = "qcom,msm-dai-q6-tdm"; qcom,msm-cpudai-tdm-dev-id = <36918>; - qcom,msm-cpudai-tdm-sync-mode = <1>; - qcom,msm-cpudai-tdm-sync-src = <0>; - qcom,msm-cpudai-tdm-data-out = <0>; - qcom,msm-cpudai-tdm-invert-sync = <0>; - qcom,msm-cpudai-tdm-data-delay = <0>; qcom,msm-cpudai-tdm-data-align = <0>; }; }; @@ -3560,48 +3511,34 @@ qcom,msm-cpudai-tdm-group-id = <37169>; qcom,msm-cpudai-tdm-group-num-ports = <4>; qcom,msm-cpudai-tdm-group-port-id = <36913 36915 36917 36919>; - qcom,msm-cpudai-tdm-clk-rate = <0>; + qcom,msm-cpudai-tdm-clk-rate = <12288000>; + qcom,msm-cpudai-tdm-clk-internal = <0>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <0>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <0>; + qcom,msm-cpudai-tdm-data-delay = <0>; dai_quat_tdm_tx_0: qcom,msm-dai-q6-tdm-quat-tx-0 { compatible = "qcom,msm-dai-q6-tdm"; qcom,msm-cpudai-tdm-dev-id = <36913>; - qcom,msm-cpudai-tdm-sync-mode = <1>; - qcom,msm-cpudai-tdm-sync-src = <0>; - qcom,msm-cpudai-tdm-data-out = <0>; - qcom,msm-cpudai-tdm-invert-sync = <0>; - qcom,msm-cpudai-tdm-data-delay = <0>; qcom,msm-cpudai-tdm-data-align = <0>; }; dai_quat_tdm_tx_1: qcom,msm-dai-q6-tdm-quat-tx-1 { compatible = "qcom,msm-dai-q6-tdm"; qcom,msm-cpudai-tdm-dev-id = <36915>; - qcom,msm-cpudai-tdm-sync-mode = <1>; - qcom,msm-cpudai-tdm-sync-src = <0>; - qcom,msm-cpudai-tdm-data-out = <0>; - qcom,msm-cpudai-tdm-invert-sync = <0>; - qcom,msm-cpudai-tdm-data-delay = <0>; qcom,msm-cpudai-tdm-data-align = <0>; }; dai_quat_tdm_tx_2: qcom,msm-dai-q6-tdm-quat-tx-2 { compatible = "qcom,msm-dai-q6-tdm"; qcom,msm-cpudai-tdm-dev-id = <36917>; - qcom,msm-cpudai-tdm-sync-mode = <1>; - qcom,msm-cpudai-tdm-sync-src = <0>; - qcom,msm-cpudai-tdm-data-out = <0>; - qcom,msm-cpudai-tdm-invert-sync = <0>; - qcom,msm-cpudai-tdm-data-delay = <0>; qcom,msm-cpudai-tdm-data-align = <0>; }; dai_quat_tdm_tx_3: qcom,msm-dai-q6-tdm-quat-tx-3 { compatible = "qcom,msm-dai-q6-tdm"; qcom,msm-cpudai-tdm-dev-id = <36919>; - qcom,msm-cpudai-tdm-sync-mode = <1>; - qcom,msm-cpudai-tdm-sync-src = <0>; - qcom,msm-cpudai-tdm-data-out = <0>; - qcom,msm-cpudai-tdm-invert-sync = <0>; - qcom,msm-cpudai-tdm-data-delay = <0>; qcom,msm-cpudai-tdm-data-align = <0>; }; }; diff --git a/arch/arm/boot/dts/qcom/sdm630-qrd.dtsi b/arch/arm/boot/dts/qcom/sdm630-qrd.dtsi index 5fac5ce2abe2..c24a41656f3a 100644 --- a/arch/arm/boot/dts/qcom/sdm630-qrd.dtsi +++ b/arch/arm/boot/dts/qcom/sdm630-qrd.dtsi @@ -396,3 +396,16 @@ qcom,afe-power-off-delay-us = <6>; }; }; + +&qusb_phy0 { + qcom,qusb-phy-init-seq = <0xf8 0x80 + 0x80 0x84 + 0x83 0x88 + 0xc7 0x8c + 0x30 0x08 + 0x79 0x0c + 0x21 0x10 + 0x14 0x9c + 0x9f 0x1c + 0x00 0x18>; +}; diff --git a/arch/arm/boot/dts/qcom/sdm660-qrd.dtsi b/arch/arm/boot/dts/qcom/sdm660-qrd.dtsi index ce895447f7f9..e78c2474df4d 100644 --- a/arch/arm/boot/dts/qcom/sdm660-qrd.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-qrd.dtsi @@ -119,6 +119,19 @@ }; }; +&qusb_phy0 { + qcom,qusb-phy-init-seq = <0xf8 0x80 + 0x80 0x84 + 0x83 0x88 + 0xc7 0x8c + 0x30 0x08 + 0x79 0x0c + 0x21 0x10 + 0x14 0x9c + 0x9f 0x1c + 0x00 0x18>; +}; + &pm660_gpios { /* GPIO 4 (NFC_CLK_REQ) */ gpio@c300 { diff --git a/arch/arm64/Kconfig.debug b/arch/arm64/Kconfig.debug index 2b9a966791d8..441005f88761 100644 --- a/arch/arm64/Kconfig.debug +++ b/arch/arm64/Kconfig.debug @@ -87,7 +87,6 @@ config DEBUG_ALIGN_RODATA config FORCE_PAGES bool "Force lowmem to be mapped with 4K pages" - depends on !DEBUG_RODATA help There are some advanced debug features that can only be done when memory is mapped with pages instead of sections. Enable this option @@ -112,6 +111,7 @@ config FREE_PAGES_RDONLY config KERNEL_TEXT_RDONLY bool "Set kernel text section pages as read only" depends on FREE_PAGES_RDONLY + depends on !DEBUG_RODATA help The kernel text pages are always mapped in the kernel. This means that anyone can write to the page if they have diff --git a/arch/arm64/configs/msm-auto_defconfig b/arch/arm64/configs/msm-auto_defconfig index e3fbb5166478..1981b97309a2 100644 --- a/arch/arm64/configs/msm-auto_defconfig +++ b/arch/arm64/configs/msm-auto_defconfig @@ -638,7 +638,6 @@ CONFIG_PANIC_ON_DATA_CORRUPTION=y CONFIG_ARM64_PTDUMP=y CONFIG_DEBUG_SET_MODULE_RONX=y CONFIG_FREE_PAGES_RDONLY=y -CONFIG_KERNEL_TEXT_RDONLY=y CONFIG_CORESIGHT=y CONFIG_CORESIGHT_EVENT=y CONFIG_CORESIGHT_LINK_AND_SINK_TMC=y diff --git a/arch/arm64/configs/msm_defconfig b/arch/arm64/configs/msm_defconfig index 80e737e5726c..5c4b307b1887 100644 --- a/arch/arm64/configs/msm_defconfig +++ b/arch/arm64/configs/msm_defconfig @@ -622,7 +622,6 @@ CONFIG_PANIC_ON_DATA_CORRUPTION=y CONFIG_ARM64_PTDUMP=y CONFIG_DEBUG_SET_MODULE_RONX=y CONFIG_FREE_PAGES_RDONLY=y -CONFIG_KERNEL_TEXT_RDONLY=y CONFIG_PFK=y CONFIG_SECURITY=y CONFIG_SECURITY_SELINUX=y diff --git a/arch/arm64/configs/msmcortex_defconfig b/arch/arm64/configs/msmcortex_defconfig index 5c88fd4985e1..743f76c8ac3f 100644 --- a/arch/arm64/configs/msmcortex_defconfig +++ b/arch/arm64/configs/msmcortex_defconfig @@ -263,6 +263,7 @@ CONFIG_SCSI_UFSHCD=y CONFIG_SCSI_UFSHCD_PLATFORM=y CONFIG_SCSI_UFS_QCOM=y CONFIG_SCSI_UFS_QCOM_ICE=y +CONFIG_SCSI_UFSHCD_CMD_LOGGING=y CONFIG_MD=y CONFIG_BLK_DEV_MD=y CONFIG_MD_LINEAR=y diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c index b1432ccf5358..38da42906994 100644 --- a/drivers/char/adsprpc.c +++ b/drivers/char/adsprpc.c @@ -1488,14 +1488,15 @@ static int fastrpc_internal_invoke(struct fastrpc_file *fl, uint32_t mode, int err = 0; struct timespec invoket; + if (fl->profile) + getnstimeofday(&invoket); + VERIFY(err, fl->sctx); if (err) goto bail; VERIFY(err, fl->cid >= 0 && fl->cid < NUM_CHANNELS); if (err) goto bail; - if (fl->profile) - getnstimeofday(&invoket); if (!kernel) { VERIFY(err, 0 == context_restore_interrupted(fl, inv, &ctx)); @@ -2440,6 +2441,9 @@ static int fastrpc_channel_open(struct fastrpc_file *fl) if (err) goto bail; cid = fl->cid; + VERIFY(err, cid >= 0 && cid < NUM_CHANNELS); + if (err) + goto bail; if (me->channel[cid].ssrcount != me->channel[cid].prevssrcount) { if (!me->channel[cid].issubsystemup) { @@ -2448,9 +2452,6 @@ static int fastrpc_channel_open(struct fastrpc_file *fl) goto bail; } } - VERIFY(err, cid >= 0 && cid < NUM_CHANNELS); - if (err) - goto bail; fl->ssrcount = me->channel[cid].ssrcount; if ((kref_get_unless_zero(&me->channel[cid].kref) == 0) || (me->channel[cid].chan == 0)) { diff --git a/drivers/char/diag/diag_masks.c b/drivers/char/diag/diag_masks.c index 3c10462c2274..382717bad828 100644 --- a/drivers/char/diag/diag_masks.c +++ b/drivers/char/diag/diag_masks.c @@ -309,10 +309,12 @@ static void diag_send_msg_mask_update(uint8_t peripheral, int first, int last) if (!mask_info || !mask_info->ptr || !mask_info->update_buf) return; - + mutex_lock(&driver->msg_mask_lock); mask = (struct diag_msg_mask_t *)mask_info->ptr; - if (!mask->ptr) + if (!mask->ptr) { + mutex_unlock(&driver->msg_mask_lock); return; + } buf = mask_info->update_buf; mutex_lock(&mask_info->lock); switch (mask_info->status) { @@ -385,6 +387,7 @@ proceed: } err: mutex_unlock(&mask_info->lock); + mutex_unlock(&driver->msg_mask_lock); } static void diag_send_time_sync_update(uint8_t peripheral) @@ -506,7 +509,7 @@ static int diag_cmd_get_ssid_range(unsigned char *src_buf, int src_len, if (!diag_apps_responds()) return 0; - + mutex_lock(&driver->msg_mask_lock); rsp.cmd_code = DIAG_CMD_MSG_CONFIG; rsp.sub_cmd = DIAG_CMD_OP_GET_SSID_RANGE; rsp.status = MSG_STATUS_SUCCESS; @@ -514,7 +517,6 @@ static int diag_cmd_get_ssid_range(unsigned char *src_buf, int src_len, rsp.count = driver->msg_mask_tbl_count; memcpy(dest_buf, &rsp, sizeof(rsp)); write_len += sizeof(rsp); - mask_ptr = (struct diag_msg_mask_t *)mask_info->ptr; for (i = 0; i < driver->msg_mask_tbl_count; i++, mask_ptr++) { if (write_len + sizeof(ssid_range) > dest_len) { @@ -527,7 +529,7 @@ static int diag_cmd_get_ssid_range(unsigned char *src_buf, int src_len, memcpy(dest_buf + write_len, &ssid_range, sizeof(ssid_range)); write_len += sizeof(ssid_range); } - + mutex_unlock(&driver->msg_mask_lock); return write_len; } @@ -551,7 +553,7 @@ static int diag_cmd_get_build_mask(unsigned char *src_buf, int src_len, if (!diag_apps_responds()) return 0; - + mutex_lock(&driver->msg_mask_lock); req = (struct diag_build_mask_req_t *)src_buf; rsp.cmd_code = DIAG_CMD_MSG_CONFIG; rsp.sub_cmd = DIAG_CMD_OP_GET_BUILD_MASK; @@ -559,9 +561,8 @@ static int diag_cmd_get_build_mask(unsigned char *src_buf, int src_len, rsp.ssid_last = req->ssid_last; rsp.status = MSG_STATUS_FAIL; rsp.padding = 0; - build_mask = (struct diag_msg_mask_t *)msg_bt_mask.ptr; - for (i = 0; i < driver->msg_mask_tbl_count; i++, build_mask++) { + for (i = 0; i < driver->bt_msg_mask_tbl_count; i++, build_mask++) { if (build_mask->ssid_first != req->ssid_first) continue; num_entries = req->ssid_last - req->ssid_first + 1; @@ -582,7 +583,7 @@ static int diag_cmd_get_build_mask(unsigned char *src_buf, int src_len, } memcpy(dest_buf, &rsp, sizeof(rsp)); write_len += sizeof(rsp); - + mutex_unlock(&driver->msg_mask_lock); return write_len; } @@ -610,6 +611,7 @@ static int diag_cmd_get_msg_mask(unsigned char *src_buf, int src_len, if (!diag_apps_responds()) return 0; + mutex_lock(&driver->msg_mask_lock); req = (struct diag_build_mask_req_t *)src_buf; rsp.cmd_code = DIAG_CMD_MSG_CONFIG; rsp.sub_cmd = DIAG_CMD_OP_GET_MSG_MASK; @@ -617,7 +619,6 @@ static int diag_cmd_get_msg_mask(unsigned char *src_buf, int src_len, rsp.ssid_last = req->ssid_last; rsp.status = MSG_STATUS_FAIL; rsp.padding = 0; - mask = (struct diag_msg_mask_t *)mask_info->ptr; for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) { if ((req->ssid_first < mask->ssid_first) || @@ -635,7 +636,7 @@ static int diag_cmd_get_msg_mask(unsigned char *src_buf, int src_len, } memcpy(dest_buf, &rsp, sizeof(rsp)); write_len += sizeof(rsp); - + mutex_unlock(&driver->msg_mask_lock); return write_len; } @@ -666,7 +667,7 @@ static int diag_cmd_set_msg_mask(unsigned char *src_buf, int src_len, } req = (struct diag_msg_build_mask_t *)src_buf; - + mutex_lock(&driver->msg_mask_lock); mutex_lock(&mask_info->lock); mask = (struct diag_msg_mask_t *)mask_info->ptr; for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) { @@ -726,7 +727,7 @@ static int diag_cmd_set_msg_mask(unsigned char *src_buf, int src_len, break; } mutex_unlock(&mask_info->lock); - + mutex_unlock(&driver->msg_mask_lock); if (diag_check_update(APPS_DATA)) diag_update_userspace_clients(MSG_MASKS_TYPE); @@ -779,7 +780,7 @@ static int diag_cmd_set_all_msg_mask(unsigned char *src_buf, int src_len, } req = (struct diag_msg_config_rsp_t *)src_buf; - + mutex_lock(&driver->msg_mask_lock); mask = (struct diag_msg_mask_t *)mask_info->ptr; mutex_lock(&mask_info->lock); mask_info->status = (req->rt_mask) ? DIAG_CTRL_MASK_ALL_ENABLED : @@ -791,6 +792,7 @@ static int diag_cmd_set_all_msg_mask(unsigned char *src_buf, int src_len, mutex_unlock(&mask->lock); } mutex_unlock(&mask_info->lock); + mutex_unlock(&driver->msg_mask_lock); if (diag_check_update(APPS_DATA)) diag_update_userspace_clients(MSG_MASKS_TYPE); @@ -1294,6 +1296,7 @@ static int diag_create_msg_mask_table(void) struct diag_msg_mask_t *mask = (struct diag_msg_mask_t *)msg_mask.ptr; struct diag_ssid_range_t range; + mutex_lock(&driver->msg_mask_lock); mutex_lock(&msg_mask.lock); driver->msg_mask_tbl_count = MSG_MASK_TBL_CNT; for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) { @@ -1304,6 +1307,7 @@ static int diag_create_msg_mask_table(void) break; } mutex_unlock(&msg_mask.lock); + mutex_unlock(&driver->msg_mask_lock); return err; } @@ -1316,9 +1320,11 @@ static int diag_create_build_time_mask(void) struct diag_msg_mask_t *build_mask = NULL; struct diag_ssid_range_t range; + mutex_lock(&driver->msg_mask_lock); mutex_lock(&msg_bt_mask.lock); + driver->bt_msg_mask_tbl_count = MSG_MASK_TBL_CNT; build_mask = (struct diag_msg_mask_t *)msg_bt_mask.ptr; - for (i = 0; i < driver->msg_mask_tbl_count; i++, build_mask++) { + for (i = 0; i < driver->bt_msg_mask_tbl_count; i++, build_mask++) { range.ssid_first = msg_mask_tbl[i].ssid_first; range.ssid_last = msg_mask_tbl[i].ssid_last; err = diag_create_msg_mask_table_entry(build_mask, &range); @@ -1429,6 +1435,7 @@ static int diag_create_build_time_mask(void) memcpy(build_mask->ptr, tbl, tbl_size); } mutex_unlock(&msg_bt_mask.lock); + mutex_unlock(&driver->msg_mask_lock); return err; } @@ -1576,10 +1583,11 @@ static int diag_msg_mask_init(void) pr_err("diag: Unable to create msg masks, err: %d\n", err); return err; } + mutex_lock(&driver->msg_mask_lock); driver->msg_mask = &msg_mask; - for (i = 0; i < NUM_PERIPHERALS; i++) driver->max_ssid_count[i] = 0; + mutex_unlock(&driver->msg_mask_lock); return 0; } @@ -1598,7 +1606,7 @@ int diag_msg_mask_copy(struct diag_mask_info *dest, struct diag_mask_info *src) err = __diag_mask_init(dest, MSG_MASK_SIZE, APPS_BUF_SIZE); if (err) return err; - + mutex_lock(&driver->msg_mask_lock); mutex_lock(&dest->lock); src_mask = (struct diag_msg_mask_t *)src->ptr; dest_mask = (struct diag_msg_mask_t *)dest->ptr; @@ -1617,6 +1625,7 @@ int diag_msg_mask_copy(struct diag_mask_info *dest, struct diag_mask_info *src) dest_mask++; } mutex_unlock(&dest->lock); + mutex_unlock(&driver->msg_mask_lock); return err; } @@ -1628,7 +1637,7 @@ void diag_msg_mask_free(struct diag_mask_info *mask_info) if (!mask_info) return; - + mutex_lock(&driver->msg_mask_lock); mutex_lock(&mask_info->lock); mask = (struct diag_msg_mask_t *)mask_info->ptr; for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) { @@ -1636,7 +1645,7 @@ void diag_msg_mask_free(struct diag_mask_info *mask_info) mask->ptr = NULL; } mutex_unlock(&mask_info->lock); - + mutex_unlock(&driver->msg_mask_lock); __diag_mask_exit(mask_info); } @@ -1644,15 +1653,17 @@ static void diag_msg_mask_exit(void) { int i; struct diag_msg_mask_t *mask = NULL; - + mutex_lock(&driver->msg_mask_lock); mask = (struct diag_msg_mask_t *)(msg_mask.ptr); if (mask) { for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) kfree(mask->ptr); kfree(msg_mask.ptr); + msg_mask.ptr = NULL; } - kfree(msg_mask.update_buf); + msg_mask.update_buf = NULL; + mutex_unlock(&driver->msg_mask_lock); } static int diag_build_time_mask_init(void) @@ -1677,13 +1688,15 @@ static void diag_build_time_mask_exit(void) { int i; struct diag_msg_mask_t *mask = NULL; - + mutex_lock(&driver->msg_mask_lock); mask = (struct diag_msg_mask_t *)(msg_bt_mask.ptr); if (mask) { - for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) + for (i = 0; i < driver->bt_msg_mask_tbl_count; i++, mask++) kfree(mask->ptr); - kfree(msg_mask.ptr); + kfree(msg_bt_mask.ptr); + msg_bt_mask.ptr = NULL; } + mutex_unlock(&driver->msg_mask_lock); } static int diag_log_mask_init(void) @@ -1801,7 +1814,7 @@ int diag_copy_to_user_msg_mask(char __user *buf, size_t count, return -EIO; } mutex_unlock(&driver->diag_maskclear_mutex); - + mutex_lock(&driver->msg_mask_lock); mutex_lock(&mask_info->lock); mask = (struct diag_msg_mask_t *)(mask_info->ptr); for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) { @@ -1840,7 +1853,7 @@ int diag_copy_to_user_msg_mask(char __user *buf, size_t count, total_len += len; } mutex_unlock(&mask_info->lock); - + mutex_unlock(&driver->msg_mask_lock); return err ? err : total_len; } diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h index b17538a10ea9..4047a2c42bb7 100644 --- a/drivers/char/diag/diagchar.h +++ b/drivers/char/diag/diagchar.h @@ -627,8 +627,10 @@ struct diagchar_dev { struct diag_mask_info *event_mask; struct diag_mask_info *build_time_mask; uint8_t msg_mask_tbl_count; + uint8_t bt_msg_mask_tbl_count; uint16_t event_mask_size; uint16_t last_event_id; + struct mutex msg_mask_lock; /* Variables for Mask Centralization */ uint16_t num_event_id[NUM_PERIPHERALS]; uint32_t num_equip_id[NUM_PERIPHERALS]; diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c index dc2d9fc4282c..60bfb2af49d0 100644 --- a/drivers/char/diag/diagchar_core.c +++ b/drivers/char/diag/diagchar_core.c @@ -3570,6 +3570,7 @@ static int __init diagchar_init(void) mutex_init(&driver->diag_file_mutex); mutex_init(&driver->delayed_rsp_mutex); mutex_init(&apps_data_mutex); + mutex_init(&driver->msg_mask_lock); for (i = 0; i < NUM_PERIPHERALS; i++) mutex_init(&driver->diagfwd_channel_mutex[i]); mutex_init(&driver->diagfwd_untag_mutex); diff --git a/drivers/char/diag/diagfwd_cntl.c b/drivers/char/diag/diagfwd_cntl.c index 82a67f1f6f47..729fbf4fc145 100644 --- a/drivers/char/diag/diagfwd_cntl.c +++ b/drivers/char/diag/diagfwd_cntl.c @@ -548,6 +548,7 @@ static void process_ssid_range_report(uint8_t *buf, uint32_t len, /* Don't account for pkt_id and length */ read_len += header_len - (2 * sizeof(uint32_t)); + mutex_lock(&driver->msg_mask_lock); driver->max_ssid_count[peripheral] = header->count; for (i = 0; i < header->count && read_len < len; i++) { ssid_range = (struct diag_ssid_range_t *)ptr; @@ -591,6 +592,7 @@ static void process_ssid_range_report(uint8_t *buf, uint32_t len, } driver->msg_mask_tbl_count += 1; } + mutex_unlock(&driver->msg_mask_lock); } static void diag_build_time_mask_update(uint8_t *buf, @@ -615,11 +617,11 @@ static void diag_build_time_mask_update(uint8_t *buf, __func__, range->ssid_first, range->ssid_last); return; } - + mutex_lock(&driver->msg_mask_lock); build_mask = (struct diag_msg_mask_t *)(driver->build_time_mask->ptr); num_items = range->ssid_last - range->ssid_first + 1; - for (i = 0; i < driver->msg_mask_tbl_count; i++, build_mask++) { + for (i = 0; i < driver->bt_msg_mask_tbl_count; i++, build_mask++) { if (build_mask->ssid_first != range->ssid_first) continue; found = 1; @@ -638,7 +640,7 @@ static void diag_build_time_mask_update(uint8_t *buf, if (found) goto end; - new_size = (driver->msg_mask_tbl_count + 1) * + new_size = (driver->bt_msg_mask_tbl_count + 1) * sizeof(struct diag_msg_mask_t); temp = krealloc(driver->build_time_mask->ptr, new_size, GFP_KERNEL); if (!temp) { @@ -653,8 +655,9 @@ static void diag_build_time_mask_update(uint8_t *buf, __func__, err); goto end; } - driver->msg_mask_tbl_count += 1; + driver->bt_msg_mask_tbl_count += 1; end: + mutex_unlock(&driver->msg_mask_lock); return; } diff --git a/drivers/devfreq/governor_bw_hwmon.c b/drivers/devfreq/governor_bw_hwmon.c index b997e79e3d73..972de02ca549 100644 --- a/drivers/devfreq/governor_bw_hwmon.c +++ b/drivers/devfreq/governor_bw_hwmon.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -86,6 +86,8 @@ static DEFINE_SPINLOCK(irq_lock); static LIST_HEAD(hwmon_list); static DEFINE_MUTEX(list_lock); +static DEFINE_MUTEX(sync_lock); + static int use_cnt; static DEFINE_MUTEX(state_lock); @@ -846,6 +848,7 @@ static int devfreq_bw_hwmon_ev_handler(struct devfreq *df, break; case DEVFREQ_GOV_INTERVAL: + mutex_lock(&sync_lock); sample_ms = *(unsigned int *)data; sample_ms = max(MIN_MS, sample_ms); sample_ms = min(MAX_MS, sample_ms); @@ -865,6 +868,7 @@ static int devfreq_bw_hwmon_ev_handler(struct devfreq *df, "Unable to resume HW monitor (%d)\n", ret); return ret; } + mutex_unlock(&sync_lock); break; case DEVFREQ_GOV_SUSPEND: diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c index dbd4fb8b2212..ac6c47bd33ae 100644 --- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c @@ -103,7 +103,7 @@ static void a5xx_set_pagetable(struct msm_gpu *gpu, struct msm_ringbuffer *ring, OUT_RING(ring, 1); } -static int a5xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit) +static void a5xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit) { struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu); @@ -273,8 +273,6 @@ static int a5xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit) /* Check to see if we need to start preemption */ a5xx_preempt_trigger(gpu); - - return 0; } static const struct { diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c index 0929dc1ce78e..a66c7e80d2af 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c @@ -172,7 +172,7 @@ void adreno_recover(struct msm_gpu *gpu) enable_irq(gpu->irq); } -int adreno_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit) +void adreno_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit) { struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); struct msm_ringbuffer *ring = gpu->rb[submit->ring]; @@ -248,8 +248,6 @@ int adreno_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit) #endif gpu->funcs->flush(gpu, ring); - - return 0; } void adreno_flush(struct msm_gpu *gpu, struct msm_ringbuffer *ring) diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.h b/drivers/gpu/drm/msm/adreno/adreno_gpu.h index 3f9bc655c383..9e622fa06ce4 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.h +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.h @@ -244,7 +244,7 @@ uint32_t adreno_last_fence(struct msm_gpu *gpu, struct msm_ringbuffer *ring); uint32_t adreno_submitted_fence(struct msm_gpu *gpu, struct msm_ringbuffer *ring); void adreno_recover(struct msm_gpu *gpu); -int adreno_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit); +void adreno_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit); void adreno_flush(struct msm_gpu *gpu, struct msm_ringbuffer *ring); bool adreno_idle(struct msm_gpu *gpu, struct msm_ringbuffer *ring); #ifdef CONFIG_DEBUG_FS diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 22addb797db3..665f8db0e04f 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -251,17 +251,12 @@ static int msm_unload(struct drm_device *dev) } #define KMS_MDP4 0 -#define KMS_MDP5 1 -#define KMS_SDE 2 +#define KMS_SDE 1 static int get_mdp_ver(struct platform_device *pdev) { #ifdef CONFIG_OF static const struct of_device_id match_types[] = { { - .compatible = "qcom,mdss_mdp", - .data = (void *)KMS_MDP5, - }, - { .compatible = "qcom,sde-kms", .data = (void *)KMS_SDE, /* end node */ @@ -432,9 +427,6 @@ static int msm_load(struct drm_device *dev, unsigned long flags) case KMS_MDP4: kms = mdp4_kms_init(dev); break; - case KMS_MDP5: - kms = mdp5_kms_init(dev); - break; case KMS_SDE: kms = sde_kms_init(dev); break; @@ -1948,7 +1940,6 @@ static const struct platform_device_id msm_id[] = { static const struct of_device_id dt_match[] = { { .compatible = "qcom,mdp" }, /* mdp4 */ - { .compatible = "qcom,mdss_mdp" }, /* mdp5 */ { .compatible = "qcom,sde-kms" }, /* sde */ {} }; diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c index 47fa02e8d1fc..bef6e81de82a 100644 --- a/drivers/gpu/drm/msm/msm_gpu.c +++ b/drivers/gpu/drm/msm/msm_gpu.c @@ -547,7 +547,7 @@ int msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit) struct drm_device *dev = gpu->dev; struct msm_drm_private *priv = dev->dev_private; struct msm_ringbuffer *ring = gpu->rb[submit->ring]; - int i, ret; + int i; WARN_ON(!mutex_is_locked(&dev->struct_mutex)); @@ -590,11 +590,11 @@ int msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit) msm_gem_move_to_active(&msm_obj->base, gpu, true, submit->fence); } - ret = gpu->funcs->submit(gpu, submit); + gpu->funcs->submit(gpu, submit); hangcheck_timer_reset(gpu); - return ret; + return 0; } struct msm_context_counter { diff --git a/drivers/gpu/drm/msm/msm_gpu.h b/drivers/gpu/drm/msm/msm_gpu.h index d273ea30151e..a47eae68dd9b 100644 --- a/drivers/gpu/drm/msm/msm_gpu.h +++ b/drivers/gpu/drm/msm/msm_gpu.h @@ -61,7 +61,7 @@ struct msm_gpu_funcs { int (*hw_init)(struct msm_gpu *gpu); int (*pm_suspend)(struct msm_gpu *gpu); int (*pm_resume)(struct msm_gpu *gpu); - int (*submit)(struct msm_gpu *gpu, struct msm_gem_submit *submit); + void (*submit)(struct msm_gpu *gpu, struct msm_gem_submit *submit); void (*flush)(struct msm_gpu *gpu, struct msm_ringbuffer *ring); irqreturn_t (*irq)(struct msm_gpu *irq); uint32_t (*last_fence)(struct msm_gpu *gpu, diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index 986026aa1b66..50f55abd6db8 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -255,6 +255,13 @@ static void _deferred_put(struct work_struct *work) kgsl_mem_entry_put(entry); } +static inline void +kgsl_mem_entry_put_deferred(struct kgsl_mem_entry *entry) +{ + if (entry) + queue_work(kgsl_driver.mem_workqueue, &entry->work); +} + static inline struct kgsl_mem_entry * kgsl_mem_entry_create(void) { @@ -265,6 +272,7 @@ kgsl_mem_entry_create(void) /* put this ref in the caller functions after init */ kref_get(&entry->refcount); + INIT_WORK(&entry->work, _deferred_put); } return entry; } @@ -1860,7 +1868,7 @@ long kgsl_ioctl_sharedmem_free(struct kgsl_device_private *dev_priv, return -EINVAL; ret = gpumem_free_entry(entry); - kgsl_mem_entry_put(entry); + kgsl_mem_entry_put_deferred(entry); return ret; } @@ -1878,7 +1886,7 @@ long kgsl_ioctl_gpumem_free_id(struct kgsl_device_private *dev_priv, return -EINVAL; ret = gpumem_free_entry(entry); - kgsl_mem_entry_put(entry); + kgsl_mem_entry_put_deferred(entry); return ret; } @@ -1915,8 +1923,7 @@ static void gpuobj_free_fence_func(void *priv) { struct kgsl_mem_entry *entry = priv; - INIT_WORK(&entry->work, _deferred_put); - queue_work(kgsl_driver.mem_workqueue, &entry->work); + kgsl_mem_entry_put_deferred(entry); } static long gpuobj_free_on_fence(struct kgsl_device_private *dev_priv, @@ -1980,7 +1987,7 @@ long kgsl_ioctl_gpuobj_free(struct kgsl_device_private *dev_priv, else ret = -EINVAL; - kgsl_mem_entry_put(entry); + kgsl_mem_entry_put_deferred(entry); return ret; } @@ -3355,7 +3362,13 @@ long kgsl_ioctl_sparse_phys_free(struct kgsl_device_private *dev_priv, if (entry == NULL) return -EINVAL; + if (!kgsl_mem_entry_set_pend(entry)) { + kgsl_mem_entry_put(entry); + return -EBUSY; + } + if (entry->memdesc.cur_bindings != 0) { + kgsl_mem_entry_unset_pend(entry); kgsl_mem_entry_put(entry); return -EINVAL; } @@ -3364,7 +3377,7 @@ long kgsl_ioctl_sparse_phys_free(struct kgsl_device_private *dev_priv, /* One put for find_id(), one put for the kgsl_mem_entry_create() */ kgsl_mem_entry_put(entry); - kgsl_mem_entry_put(entry); + kgsl_mem_entry_put_deferred(entry); return 0; } @@ -3424,7 +3437,13 @@ long kgsl_ioctl_sparse_virt_free(struct kgsl_device_private *dev_priv, if (entry == NULL) return -EINVAL; + if (!kgsl_mem_entry_set_pend(entry)) { + kgsl_mem_entry_put(entry); + return -EBUSY; + } + if (entry->bind_tree.rb_node != NULL) { + kgsl_mem_entry_unset_pend(entry); kgsl_mem_entry_put(entry); return -EINVAL; } @@ -3433,7 +3452,7 @@ long kgsl_ioctl_sparse_virt_free(struct kgsl_device_private *dev_priv, /* One put for find_id(), one put for the kgsl_mem_entry_create() */ kgsl_mem_entry_put(entry); - kgsl_mem_entry_put(entry); + kgsl_mem_entry_put_deferred(entry); return 0; } @@ -4906,7 +4925,7 @@ static int __init kgsl_core_init(void) WQ_UNBOUND | WQ_MEM_RECLAIM | WQ_SYSFS, 0); kgsl_driver.mem_workqueue = alloc_workqueue("kgsl-mementry", - WQ_UNBOUND | WQ_MEM_RECLAIM, 0); + WQ_MEM_RECLAIM, 0); kgsl_events_init(); diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c index 3e59b288b8a8..57d2f89350d2 100644 --- a/drivers/media/usb/uvc/uvc_ctrl.c +++ b/drivers/media/usb/uvc/uvc_ctrl.c @@ -1991,6 +1991,9 @@ int uvc_ctrl_add_mapping(struct uvc_video_chain *chain, if (!found) return -ENOENT; + if (ctrl->info.size < mapping->size) + return -EINVAL; + if (mutex_lock_interruptible(&chain->ctrl_mutex)) return -ERESTARTSYS; diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c index ee5bafc1515e..1c7cc917faa6 100644 --- a/drivers/misc/qseecom.c +++ b/drivers/misc/qseecom.c @@ -6843,6 +6843,60 @@ static void __qseecom_clean_data_sglistinfo(struct qseecom_dev_handle *data) } } + +static int __qseecom_bus_scaling_enable(struct qseecom_dev_handle *data, + bool *perf_enabled) +{ + int ret = 0; + + if (qseecom.support_bus_scaling) { + if (!data->mode) { + mutex_lock(&qsee_bw_mutex); + __qseecom_register_bus_bandwidth_needs( + data, HIGH); + mutex_unlock(&qsee_bw_mutex); + } + ret = qseecom_scale_bus_bandwidth_timer(INACTIVE); + if (ret) { + pr_err("Failed to set bw\n"); + ret = -EINVAL; + goto exit; + } + } + /* + * On targets where crypto clock is handled by HLOS, + * if clk_access_cnt is zero and perf_enabled is false, + * then the crypto clock was not enabled before sending cmd + * to tz, qseecom will enable the clock to avoid service failure. + */ + if (!qseecom.no_clock_support && + !qseecom.qsee.clk_access_cnt && !data->perf_enabled) { + pr_debug("ce clock is not enabled\n"); + ret = qseecom_perf_enable(data); + if (ret) { + pr_err("Failed to vote for clock with err %d\n", + ret); + ret = -EINVAL; + goto exit; + } + *perf_enabled = true; + } +exit: + return ret; +} + +static void __qseecom_bus_scaling_disable(struct qseecom_dev_handle *data, + bool perf_enabled) +{ + if (qseecom.support_bus_scaling) + __qseecom_add_bw_scale_down_timer( + QSEECOM_SEND_CMD_CRYPTO_TIMEOUT); + if (perf_enabled) { + qsee_disable_clock_vote(data, CLK_DFAB); + qsee_disable_clock_vote(data, CLK_SFPB); + } +} + long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg) { int ret = 0; @@ -6909,50 +6963,14 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg) } /* Only one client allowed here at a time */ mutex_lock(&app_access_lock); - if (qseecom.support_bus_scaling) { - /* register bus bw in case the client doesn't do it */ - if (!data->mode) { - mutex_lock(&qsee_bw_mutex); - __qseecom_register_bus_bandwidth_needs( - data, HIGH); - mutex_unlock(&qsee_bw_mutex); - } - ret = qseecom_scale_bus_bandwidth_timer(INACTIVE); - if (ret) { - pr_err("Failed to set bw.\n"); - ret = -EINVAL; - mutex_unlock(&app_access_lock); - break; - } - } - /* - * On targets where crypto clock is handled by HLOS, - * if clk_access_cnt is zero and perf_enabled is false, - * then the crypto clock was not enabled before sending cmd - * to tz, qseecom will enable the clock to avoid service failure. - */ - if (!qseecom.no_clock_support && - !qseecom.qsee.clk_access_cnt && !data->perf_enabled) { - pr_debug("ce clock is not enabled!\n"); - ret = qseecom_perf_enable(data); - if (ret) { - pr_err("Failed to vote for clock with err %d\n", - ret); - mutex_unlock(&app_access_lock); - ret = -EINVAL; - break; - } - perf_enabled = true; + ret = __qseecom_bus_scaling_enable(data, &perf_enabled); + if (ret) { + mutex_unlock(&app_access_lock); + break; } atomic_inc(&data->ioctl_count); ret = qseecom_send_cmd(data, argp); - if (qseecom.support_bus_scaling) - __qseecom_add_bw_scale_down_timer( - QSEECOM_SEND_CMD_CRYPTO_TIMEOUT); - if (perf_enabled) { - qsee_disable_clock_vote(data, CLK_DFAB); - qsee_disable_clock_vote(data, CLK_SFPB); - } + __qseecom_bus_scaling_disable(data, perf_enabled); atomic_dec(&data->ioctl_count); wake_up_all(&data->abort_wq); mutex_unlock(&app_access_lock); @@ -6971,52 +6989,17 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg) } /* Only one client allowed here at a time */ mutex_lock(&app_access_lock); - if (qseecom.support_bus_scaling) { - if (!data->mode) { - mutex_lock(&qsee_bw_mutex); - __qseecom_register_bus_bandwidth_needs( - data, HIGH); - mutex_unlock(&qsee_bw_mutex); - } - ret = qseecom_scale_bus_bandwidth_timer(INACTIVE); - if (ret) { - pr_err("Failed to set bw.\n"); - mutex_unlock(&app_access_lock); - ret = -EINVAL; - break; - } - } - /* - * On targets where crypto clock is handled by HLOS, - * if clk_access_cnt is zero and perf_enabled is false, - * then the crypto clock was not enabled before sending cmd - * to tz, qseecom will enable the clock to avoid service failure. - */ - if (!qseecom.no_clock_support && - !qseecom.qsee.clk_access_cnt && !data->perf_enabled) { - pr_debug("ce clock is not enabled!\n"); - ret = qseecom_perf_enable(data); - if (ret) { - pr_err("Failed to vote for clock with err %d\n", - ret); - mutex_unlock(&app_access_lock); - ret = -EINVAL; - break; - } - perf_enabled = true; + ret = __qseecom_bus_scaling_enable(data, &perf_enabled); + if (ret) { + mutex_unlock(&app_access_lock); + break; } atomic_inc(&data->ioctl_count); if (cmd == QSEECOM_IOCTL_SEND_MODFD_CMD_REQ) ret = qseecom_send_modfd_cmd(data, argp); else ret = qseecom_send_modfd_cmd_64(data, argp); - if (qseecom.support_bus_scaling) - __qseecom_add_bw_scale_down_timer( - QSEECOM_SEND_CMD_CRYPTO_TIMEOUT); - if (perf_enabled) { - qsee_disable_clock_vote(data, CLK_DFAB); - qsee_disable_clock_vote(data, CLK_SFPB); - } + __qseecom_bus_scaling_disable(data, perf_enabled); atomic_dec(&data->ioctl_count); wake_up_all(&data->abort_wq); mutex_unlock(&app_access_lock); @@ -7418,8 +7401,14 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg) } /* Only one client allowed here at a time */ mutex_lock(&app_access_lock); + ret = __qseecom_bus_scaling_enable(data, &perf_enabled); + if (ret) { + mutex_unlock(&app_access_lock); + break; + } atomic_inc(&data->ioctl_count); ret = qseecom_qteec_open_session(data, argp); + __qseecom_bus_scaling_disable(data, perf_enabled); atomic_dec(&data->ioctl_count); wake_up_all(&data->abort_wq); mutex_unlock(&app_access_lock); @@ -7467,8 +7456,14 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg) } /* Only one client allowed here at a time */ mutex_lock(&app_access_lock); + ret = __qseecom_bus_scaling_enable(data, &perf_enabled); + if (ret) { + mutex_unlock(&app_access_lock); + break; + } atomic_inc(&data->ioctl_count); ret = qseecom_qteec_invoke_modfd_cmd(data, argp); + __qseecom_bus_scaling_disable(data, perf_enabled); atomic_dec(&data->ioctl_count); wake_up_all(&data->abort_wq); mutex_unlock(&app_access_lock); diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c index 0cc98e45b65c..9406b6f71a6b 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.c +++ b/drivers/net/wireless/ath/ath10k/snoc.c @@ -969,7 +969,7 @@ int ath10k_snoc_get_ce_id(struct ath10k *ar, int irq) struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); for (i = 0; i < CE_COUNT_MAX; i++) { - if (ar_snoc->ce_irqs[i] == irq) + if (ar_snoc->ce_irqs[i].irq_line == irq) return i; } ath10k_err(ar, "No matching CE id for irq %d\n", irq); @@ -1002,15 +1002,17 @@ static int ath10k_snoc_request_irq(struct ath10k *ar) int irqflags = IRQF_TRIGGER_RISING; for (id = 0; id < CE_COUNT_MAX; id++) { - ret = request_irq(ar_snoc->ce_irqs[id], + ret = request_irq(ar_snoc->ce_irqs[id].irq_line, ath10k_snoc_per_engine_handler, irqflags, ce_name[id], ar); if (ret) { ath10k_err(ar, "%s: cannot register CE %d irq handler, ret = %d", __func__, id, ret); - free_irq(ar_snoc->ce_irqs[id], ar); + atomic_set(&ar_snoc->ce_irqs[id].irq_req_stat, 0); return ret; + } else { + atomic_set(&ar_snoc->ce_irqs[id].irq_req_stat, 1); } } @@ -1022,11 +1024,14 @@ static void ath10k_snoc_free_irq(struct ath10k *ar) int id; struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); - for (id = 0; id < CE_COUNT_MAX; id++) - free_irq(ar_snoc->ce_irqs[id], ar); + for (id = 0; id < CE_COUNT_MAX; id++) { + if (atomic_read(&ar_snoc->ce_irqs[id].irq_req_stat)) { + free_irq(ar_snoc->ce_irqs[id].irq_line, ar); + atomic_set(&ar_snoc->ce_irqs[id].irq_req_stat, 0); + } + } } - static int ath10k_snoc_get_soc_info(struct ath10k *ar) { struct resource *res; @@ -1198,7 +1203,7 @@ static int ath10k_snoc_resource_init(struct ath10k *ar) ret = -ENODEV; goto out; } else { - ar_snoc->ce_irqs[i] = res->start; + ar_snoc->ce_irqs[i].irq_line = res->start; } } diff --git a/drivers/net/wireless/ath/ath10k/snoc.h b/drivers/net/wireless/ath/ath10k/snoc.h index 99ae157885bb..7a223b1d3ded 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.h +++ b/drivers/net/wireless/ath/ath10k/snoc.h @@ -103,6 +103,15 @@ struct ath10k_service_notifier_context { char name[QMI_SERVREG_LOC_NAME_LENGTH_V01 + 1]; }; +/* struct ath10k_snoc_ce_irq: copy engine irq struct + * @irq_req_stat: irq request status + * @irq_line: irq line + */ +struct ath10k_snoc_ce_irq { + atomic_t irq_req_stat; + u32 irq_line; +}; + /* struct ath10k_snoc: SNOC info struct * @dev: device structure * @ar:ath10k base structure @@ -111,6 +120,7 @@ struct ath10k_service_notifier_context { * @target_info: snoc target info * @mem_len: mempry map length * @pipe_info: pipe info struct + * @ce_irqs: copy engine irq list * @ce_lock: protect ce structures * @ce_states: maps ce id to ce state * @rx_post_retry: rx buffer post processing timer @@ -134,7 +144,7 @@ struct ath10k_snoc { size_t mem_len; struct ath10k_snoc_pipe pipe_info[CE_COUNT_MAX]; struct timer_list rx_post_retry; - u32 ce_irqs[CE_COUNT_MAX]; + struct ath10k_snoc_ce_irq ce_irqs[CE_COUNT_MAX]; u32 *vaddr_rri_on_ddr; bool is_driver_probed; struct notifier_block modem_ssr_nb; diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index d68d6c926029..69214fb2586c 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -1666,6 +1666,42 @@ static int wil_cfg80211_set_power_mgmt(struct wiphy *wiphy, return wil_ps_update(wil, ps_profile); } +static int wil_cfg80211_suspend(struct wiphy *wiphy, + struct cfg80211_wowlan *wow) +{ + struct wil6210_priv *wil = wiphy_to_wil(wiphy); + int rc; + + /* Setting the wakeup trigger based on wow is TBD */ + + if (test_bit(wil_status_suspended, wil->status)) { + wil_dbg_pm(wil, "trying to suspend while suspended\n"); + return 0; + } + + rc = wil_can_suspend(wil, false); + if (rc) + goto out; + + wil_dbg_pm(wil, "suspending\n"); + + wil_p2p_stop_discovery(wil); + + wil_abort_scan(wil, true); + +out: + return rc; +} + +static int wil_cfg80211_resume(struct wiphy *wiphy) +{ + struct wil6210_priv *wil = wiphy_to_wil(wiphy); + + wil_dbg_pm(wil, "resuming\n"); + + return 0; +} + static struct cfg80211_ops wil_cfg80211_ops = { .add_virtual_intf = wil_cfg80211_add_iface, .del_virtual_intf = wil_cfg80211_del_iface, @@ -1697,6 +1733,8 @@ static struct cfg80211_ops wil_cfg80211_ops = { .start_p2p_device = wil_cfg80211_start_p2p_device, .stop_p2p_device = wil_cfg80211_stop_p2p_device, .set_power_mgmt = wil_cfg80211_set_power_mgmt, + .suspend = wil_cfg80211_suspend, + .resume = wil_cfg80211_resume, }; static void wil_wiphy_init(struct wiphy *wiphy) diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 4a299f238c54..d3691c64d47a 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -509,6 +509,10 @@ static ssize_t wil_read_file_ioblob(struct file *file, char __user *user_buf, void *buf; size_t ret; + if (test_bit(wil_status_suspending, wil_blob->wil->status) || + test_bit(wil_status_suspended, wil_blob->wil->status)) + return 0; + if (pos < 0) return -EINVAL; @@ -1610,6 +1614,49 @@ static const struct file_operations fops_fw_version = { .llseek = seq_lseek, }; +/*---------suspend_stats---------*/ +static ssize_t wil_write_suspend_stats(struct file *file, + const char __user *buf, + size_t len, loff_t *ppos) +{ + struct wil6210_priv *wil = file->private_data; + + memset(&wil->suspend_stats, 0, sizeof(wil->suspend_stats)); + + return len; +} + +static ssize_t wil_read_suspend_stats(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct wil6210_priv *wil = file->private_data; + static char text[400]; + int n; + + n = snprintf(text, sizeof(text), + "Suspend statistics:\n" + "successful suspends:%ld failed suspends:%ld\n" + "successful resumes:%ld failed resumes:%ld\n" + "rejected by host:%ld rejected by device:%ld\n", + wil->suspend_stats.successful_suspends, + wil->suspend_stats.failed_suspends, + wil->suspend_stats.successful_resumes, + wil->suspend_stats.failed_resumes, + wil->suspend_stats.rejected_by_host, + wil->suspend_stats.rejected_by_device); + + n = min_t(int, n, sizeof(text)); + + return simple_read_from_buffer(user_buf, count, ppos, text, n); +} + +static const struct file_operations fops_suspend_stats = { + .read = wil_read_suspend_stats, + .write = wil_write_suspend_stats, + .open = simple_open, +}; + /*----------------*/ static void wil6210_debugfs_init_blobs(struct wil6210_priv *wil, struct dentry *dbg) @@ -1662,6 +1709,7 @@ static const struct { {"led_blink_time", 0644, &fops_led_blink_time}, {"fw_capabilities", 0444, &fops_fw_capabilities}, {"fw_version", 0444, &fops_fw_version}, + {"suspend_stats", 0644, &fops_suspend_stats}, }; static void wil6210_debugfs_init_files(struct wil6210_priv *wil, @@ -1708,6 +1756,7 @@ static const struct dbg_off dbg_wil_off[] = { WIL_FIELD(discovery_mode, 0644, doff_u8), WIL_FIELD(chip_revision, 0444, doff_u8), WIL_FIELD(abft_len, 0644, doff_u8), + WIL_FIELD(wakeup_trigger, 0644, doff_u8), {}, }; diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c index cab1e5c0e374..cad8a95c4e4e 100644 --- a/drivers/net/wireless/ath/wil6210/interrupt.c +++ b/drivers/net/wireless/ath/wil6210/interrupt.c @@ -467,6 +467,12 @@ static irqreturn_t wil6210_thread_irq(int irq, void *cookie) wil6210_unmask_irq_pseudo(wil); + if (wil->suspend_resp_rcvd) { + wil_dbg_irq(wil, "set suspend_resp_comp to true\n"); + wil->suspend_resp_comp = true; + wake_up_interruptible(&wil->wq); + } + return IRQ_HANDLED; } diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 45a5fb6d23a0..78091b7910c7 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -579,6 +579,9 @@ int wil_priv_init(struct wil6210_priv *wil) wil->ps_profile = WMI_PS_PROFILE_TYPE_DEFAULT; + wil->wakeup_trigger = WMI_WAKEUP_TRIGGER_UCAST | + WMI_WAKEUP_TRIGGER_BCAST; + return 0; out_wmi_wq: @@ -589,8 +592,10 @@ out_wmi_wq: void wil6210_bus_request(struct wil6210_priv *wil, u32 kbps) { - if (wil->platform_ops.bus_request) + if (wil->platform_ops.bus_request) { + wil->bus_request_kbps = kbps; wil->platform_ops.bus_request(wil->platform_handle, kbps); + } } /** diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c index 2a515e848820..8d3d25333ba5 100644 --- a/drivers/net/wireless/ath/wil6210/pcie_bus.c +++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c @@ -112,8 +112,6 @@ static int wil_if_pcie_enable(struct wil6210_priv *wil) wil_dbg_misc(wil, "if_pcie_enable, wmi_only %d\n", wmi_only); - pdev->msi_enabled = 0; - pci_set_master(pdev); wil_dbg_misc(wil, "Setup %s interrupt\n", use_msi ? "MSI" : "INTx"); @@ -249,7 +247,7 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) } rc = pci_enable_device(pdev); - if (rc) { + if (rc && pdev->msi_enabled == 0) { wil_err(wil, "pci_enable_device failed, retry with MSI only\n"); /* Work around for platforms that can't allocate IRQ: @@ -264,6 +262,7 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto err_plat; } /* rollback to err_disable_pdev */ + pci_set_power_state(pdev, PCI_D0); rc = pci_request_region(pdev, 0, WIL_NAME); if (rc) { @@ -284,6 +283,15 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) wil_set_capabilities(wil); wil6210_clear_irq(wil); + wil->keep_radio_on_during_sleep = + wil->platform_ops.keep_radio_on_during_sleep && + wil->platform_ops.keep_radio_on_during_sleep( + wil->platform_handle) && + test_bit(WMI_FW_CAPABILITY_D3_SUSPEND, wil->fw_capabilities); + + wil_info(wil, "keep_radio_on_during_sleep (%d)\n", + wil->keep_radio_on_during_sleep); + /* FW should raise IRQ when ready */ rc = wil_if_pcie_enable(wil); if (rc) { @@ -383,15 +391,16 @@ static int wil6210_suspend(struct device *dev, bool is_runtime) goto out; rc = wil_suspend(wil, is_runtime); - if (rc) - goto out; - - /* TODO: how do I bring card in low power state? */ - - /* disable bus mastering */ - pci_clear_master(pdev); - /* PCI will call pci_save_state(pdev) and pci_prepare_to_sleep(pdev) */ + if (!rc) { + wil->suspend_stats.successful_suspends++; + /* If platform device supports keep_radio_on_during_sleep + * it will control PCIe master + */ + if (!wil->keep_radio_on_during_sleep) + /* disable bus mastering */ + pci_clear_master(pdev); + } out: return rc; } @@ -404,12 +413,21 @@ static int wil6210_resume(struct device *dev, bool is_runtime) wil_dbg_pm(wil, "resume: %s\n", is_runtime ? "runtime" : "system"); - /* allow master */ - pci_set_master(pdev); - + /* If platform device supports keep_radio_on_during_sleep it will + * control PCIe master + */ + if (!wil->keep_radio_on_during_sleep) + /* allow master */ + pci_set_master(pdev); rc = wil_resume(wil, is_runtime); - if (rc) - pci_clear_master(pdev); + if (rc) { + wil_err(wil, "device failed to resume (%d)\n", rc); + wil->suspend_stats.failed_resumes++; + if (!wil->keep_radio_on_during_sleep) + pci_clear_master(pdev); + } else { + wil->suspend_stats.successful_resumes++; + } return rc; } diff --git a/drivers/net/wireless/ath/wil6210/pm.c b/drivers/net/wireless/ath/wil6210/pm.c index 2ae4fe85cc8c..015dc3c1493f 100644 --- a/drivers/net/wireless/ath/wil6210/pm.c +++ b/drivers/net/wireless/ath/wil6210/pm.c @@ -15,6 +15,7 @@ */ #include "wil6210.h" +#include <linux/jiffies.h> int wil_can_suspend(struct wil6210_priv *wil, bool is_runtime) { @@ -61,21 +62,165 @@ out: wil_dbg_pm(wil, "can_suspend: %s => %s (%d)\n", is_runtime ? "runtime" : "system", rc ? "No" : "Yes", rc); + if (rc) + wil->suspend_stats.rejected_by_host++; + return rc; } -int wil_suspend(struct wil6210_priv *wil, bool is_runtime) +static int wil_resume_keep_radio_on(struct wil6210_priv *wil) { int rc = 0; - struct net_device *ndev = wil_to_ndev(wil); - wil_dbg_pm(wil, "suspend: %s\n", is_runtime ? "runtime" : "system"); + /* wil_status_resuming will be cleared when getting + * WMI_TRAFFIC_RESUME_EVENTID + */ + set_bit(wil_status_resuming, wil->status); + clear_bit(wil_status_suspended, wil->status); + wil_c(wil, RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD); + wil_unmask_irq(wil); - if (test_bit(wil_status_suspended, wil->status)) { - wil_dbg_pm(wil, "trying to suspend while suspended\n"); - return 0; + /* Send WMI resume request to the device */ + rc = wmi_resume(wil); + if (rc) { + wil_err(wil, "device failed to resume (%d), resetting\n", rc); + rc = wil_down(wil); + if (rc) { + wil_err(wil, "wil_down failed (%d)\n", rc); + goto out; + } + rc = wil_up(wil); + if (rc) { + wil_err(wil, "wil_up failed (%d)\n", rc); + goto out; + } + } + + wil6210_bus_request(wil, wil->bus_request_kbps_pre_suspend); + +out: + if (rc) + set_bit(wil_status_suspended, wil->status); + return rc; +} + +static int wil_suspend_keep_radio_on(struct wil6210_priv *wil) +{ + int rc = 0; + unsigned long start, data_comp_to; + + wil_dbg_pm(wil, "suspend keep radio on\n"); + + /* Prevent handling of new tx and wmi commands */ + set_bit(wil_status_suspending, wil->status); + + if (!wil_is_tx_idle(wil)) { + wil_dbg_pm(wil, "Pending TX data, reject suspend\n"); + wil->suspend_stats.rejected_by_host++; + goto reject_suspend; } + if (!wil_is_rx_idle(wil)) { + wil_dbg_pm(wil, "Pending RX data, reject suspend\n"); + wil->suspend_stats.rejected_by_host++; + goto reject_suspend; + } + + if (!wil_is_wmi_idle(wil)) { + wil_dbg_pm(wil, "Pending WMI events, reject suspend\n"); + wil->suspend_stats.rejected_by_host++; + goto reject_suspend; + } + + /* Send WMI suspend request to the device */ + rc = wmi_suspend(wil); + if (rc) { + wil_dbg_pm(wil, "wmi_suspend failed, reject suspend (%d)\n", + rc); + goto reject_suspend; + } + + /* Wait for completion of the pending RX packets */ + start = jiffies; + data_comp_to = jiffies + msecs_to_jiffies(WIL_DATA_COMPLETION_TO_MS); + if (test_bit(wil_status_napi_en, wil->status)) { + while (!wil_is_rx_idle(wil)) { + if (time_after(jiffies, data_comp_to)) { + if (wil_is_rx_idle(wil)) + break; + wil_err(wil, + "TO waiting for idle RX, suspend failed\n"); + wil->suspend_stats.failed_suspends++; + goto resume_after_fail; + } + wil_dbg_ratelimited(wil, "rx vring is not empty -> NAPI\n"); + napi_synchronize(&wil->napi_rx); + msleep(20); + } + } + + /* In case of pending WMI events, reject the suspend + * and resume the device. + * This can happen if the device sent the WMI events before + * approving the suspend. + */ + if (!wil_is_wmi_idle(wil)) { + wil_err(wil, "suspend failed due to pending WMI events\n"); + wil->suspend_stats.failed_suspends++; + goto resume_after_fail; + } + + wil_mask_irq(wil); + + /* Disable device reset on PERST */ + wil_s(wil, RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD); + + /* Save the current bus request to return to the same in resume */ + wil->bus_request_kbps_pre_suspend = wil->bus_request_kbps; + wil6210_bus_request(wil, 0); + + if (wil->platform_ops.suspend) { + rc = wil->platform_ops.suspend(wil->platform_handle, true); + if (rc) { + wil_err(wil, "platform device failed to suspend (%d)\n", + rc); + wil->suspend_stats.failed_suspends++; + clear_bit(wil_status_suspending, wil->status); + rc = wil_resume_keep_radio_on(wil); + /* if resume succeeded, reject the suspend */ + if (!rc) + rc = -EBUSY; + goto out; + } + } + + set_bit(wil_status_suspended, wil->status); + clear_bit(wil_status_suspending, wil->status); + + return rc; + +resume_after_fail: + clear_bit(wil_status_suspending, wil->status); + rc = wmi_resume(wil); + /* if resume succeeded, reject the suspend */ + if (!rc) + rc = -EBUSY; + +out: + return rc; + +reject_suspend: + clear_bit(wil_status_suspending, wil->status); + return -EBUSY; +} + +static int wil_suspend_radio_off(struct wil6210_priv *wil) +{ + int rc = 0; + struct net_device *ndev = wil_to_ndev(wil); + + wil_dbg_pm(wil, "suspend radio off\n"); + /* if netif up, hardware is alive, shut it down */ if (ndev->flags & IFF_UP) { rc = wil_down(wil); @@ -90,7 +235,7 @@ int wil_suspend(struct wil6210_priv *wil, bool is_runtime) wil_disable_irq(wil); if (wil->platform_ops.suspend) { - rc = wil->platform_ops.suspend(wil->platform_handle); + rc = wil->platform_ops.suspend(wil->platform_handle, false); if (rc) { wil_enable_irq(wil); goto out; @@ -100,6 +245,50 @@ int wil_suspend(struct wil6210_priv *wil, bool is_runtime) set_bit(wil_status_suspended, wil->status); out: + wil_dbg_pm(wil, "suspend radio off: %d\n", rc); + + return rc; +} + +static int wil_resume_radio_off(struct wil6210_priv *wil) +{ + int rc = 0; + struct net_device *ndev = wil_to_ndev(wil); + + wil_dbg_pm(wil, "Enabling PCIe IRQ\n"); + wil_enable_irq(wil); + /* if netif up, bring hardware up + * During open(), IFF_UP set after actual device method + * invocation. This prevent recursive call to wil_up() + * wil_status_suspended will be cleared in wil_reset + */ + if (ndev->flags & IFF_UP) + rc = wil_up(wil); + else + clear_bit(wil_status_suspended, wil->status); + + return rc; +} + +int wil_suspend(struct wil6210_priv *wil, bool is_runtime) +{ + int rc = 0; + struct net_device *ndev = wil_to_ndev(wil); + bool keep_radio_on = ndev->flags & IFF_UP && + wil->keep_radio_on_during_sleep; + + wil_dbg_pm(wil, "suspend: %s\n", is_runtime ? "runtime" : "system"); + + if (test_bit(wil_status_suspended, wil->status)) { + wil_dbg_pm(wil, "trying to suspend while suspended\n"); + return 0; + } + + if (!keep_radio_on) + rc = wil_suspend_radio_off(wil); + else + rc = wil_suspend_keep_radio_on(wil); + wil_dbg_pm(wil, "suspend: %s => %d\n", is_runtime ? "runtime" : "system", rc); @@ -110,29 +299,24 @@ int wil_resume(struct wil6210_priv *wil, bool is_runtime) { int rc = 0; struct net_device *ndev = wil_to_ndev(wil); + bool keep_radio_on = ndev->flags & IFF_UP && + wil->keep_radio_on_during_sleep; wil_dbg_pm(wil, "resume: %s\n", is_runtime ? "runtime" : "system"); if (wil->platform_ops.resume) { - rc = wil->platform_ops.resume(wil->platform_handle); + rc = wil->platform_ops.resume(wil->platform_handle, + keep_radio_on); if (rc) { wil_err(wil, "platform_ops.resume : %d\n", rc); goto out; } } - wil_dbg_pm(wil, "Enabling PCIe IRQ\n"); - wil_enable_irq(wil); - - /* if netif up, bring hardware up - * During open(), IFF_UP set after actual device method - * invocation. This prevent recursive call to wil_up(). - * wil_status_suspended will be cleared in wil_reset - */ - if (ndev->flags & IFF_UP) - rc = wil_up(wil); + if (keep_radio_on) + rc = wil_resume_keep_radio_on(wil); else - clear_bit(wil_status_suspended, wil->status); + rc = wil_resume_radio_off(wil); out: wil_dbg_pm(wil, "resume: %s => %d\n", diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 35bbf3a91f3e..439fe30936b6 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -104,6 +104,51 @@ static inline int wil_vring_avail_high(struct vring *vring) return wil_vring_avail_tx(vring) > wil_vring_wmark_high(vring); } +/* returns true when all tx vrings are empty */ +bool wil_is_tx_idle(struct wil6210_priv *wil) +{ + int i; + unsigned long data_comp_to; + + for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) { + struct vring *vring = &wil->vring_tx[i]; + int vring_index = vring - wil->vring_tx; + struct vring_tx_data *txdata = &wil->vring_tx_data[vring_index]; + + spin_lock(&txdata->lock); + + if (!vring->va || !txdata->enabled) { + spin_unlock(&txdata->lock); + continue; + } + + data_comp_to = jiffies + msecs_to_jiffies( + WIL_DATA_COMPLETION_TO_MS); + if (test_bit(wil_status_napi_en, wil->status)) { + while (!wil_vring_is_empty(vring)) { + if (time_after(jiffies, data_comp_to)) { + wil_dbg_pm(wil, + "TO waiting for idle tx\n"); + spin_unlock(&txdata->lock); + return false; + } + wil_dbg_ratelimited(wil, + "tx vring is not empty -> NAPI\n"); + spin_unlock(&txdata->lock); + napi_synchronize(&wil->napi_tx); + msleep(20); + spin_lock(&txdata->lock); + if (!vring->va || !txdata->enabled) + break; + } + } + + spin_unlock(&txdata->lock); + } + + return true; +} + /* wil_val_in_range - check if value in [min,max) */ static inline bool wil_val_in_range(int val, int min, int max) { @@ -406,6 +451,18 @@ static inline int wil_is_back_req(u8 fc) (IEEE80211_FTYPE_CTL | IEEE80211_STYPE_BACK_REQ); } +bool wil_is_rx_idle(struct wil6210_priv *wil) +{ + struct vring_rx_desc *_d; + struct vring *vring = &wil->vring_rx; + + _d = (struct vring_rx_desc *)&vring->va[vring->swhead].rx; + if (_d->dma.status & RX_DMA_STATUS_DU) + return false; + + return true; +} + /** * reap 1 frame from @swhead * @@ -1812,6 +1869,15 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, spin_lock(&txdata->lock); + if (test_bit(wil_status_suspending, wil->status) || + test_bit(wil_status_suspended, wil->status) || + test_bit(wil_status_resuming, wil->status)) { + wil_dbg_txrx(wil, + "suspend/resume in progress. drop packet\n"); + spin_unlock(&txdata->lock); + return -EINVAL; + } + rc = (skb_is_gso(skb) ? __wil_tx_vring_tso : __wil_tx_vring) (wil, vring, skb); diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index eee528127e97..e76ec6ed9995 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -83,6 +83,15 @@ static inline u32 WIL_GET_BITS(u32 x, int b0, int b1) */ #define WIL_MAX_MPDU_OVERHEAD (62) +struct wil_suspend_stats { + unsigned long successful_suspends; + unsigned long failed_suspends; + unsigned long successful_resumes; + unsigned long failed_resumes; + unsigned long rejected_by_device; + unsigned long rejected_by_host; +}; + /* Calculate MAC buffer size for the firmware. It includes all overhead, * as it will go over the air, and need to be 8 byte aligned */ @@ -296,6 +305,8 @@ enum { #define ISR_MISC_MBOX_EVT BIT_DMA_EP_MISC_ICR_FW_INT(1) #define ISR_MISC_FW_ERROR BIT_DMA_EP_MISC_ICR_FW_INT(3) +#define WIL_DATA_COMPLETION_TO_MS 200 + /* Hardware definitions end */ struct fw_map { u32 from; /* linker address - from, inclusive */ @@ -424,7 +435,9 @@ enum { /* for wil6210_priv.status */ wil_status_irqen, /* FIXME: interrupts enabled - for debug */ wil_status_napi_en, /* NAPI enabled protected by wil->mutex */ wil_status_resetting, /* reset in progress */ + wil_status_suspending, /* suspend in progress */ wil_status_suspended, /* suspend completed, device is suspended */ + wil_status_resuming, /* resume in progress */ wil_status_last /* keep last */ }; @@ -689,9 +702,12 @@ struct wil6210_priv { struct wil_blob_wrapper blobs[ARRAY_SIZE(fw_mapping)]; u8 discovery_mode; u8 abft_len; + u8 wakeup_trigger; + struct wil_suspend_stats suspend_stats; void *platform_handle; struct wil_platform_ops platform_ops; + bool keep_radio_on_during_sleep; struct pmc_ctx pmc; @@ -718,6 +734,11 @@ struct wil6210_priv { struct notifier_block pm_notify; #endif /* CONFIG_PM_SLEEP */ #endif /* CONFIG_PM */ + + bool suspend_resp_rcvd; + bool suspend_resp_comp; + u32 bus_request_kbps; + u32 bus_request_kbps_pre_suspend; }; #define wil_to_wiphy(i) (i->wdev->wiphy) @@ -980,6 +1001,11 @@ bool wil_fw_verify_file_exists(struct wil6210_priv *wil, const char *name); int wil_can_suspend(struct wil6210_priv *wil, bool is_runtime); int wil_suspend(struct wil6210_priv *wil, bool is_runtime); int wil_resume(struct wil6210_priv *wil, bool is_runtime); +bool wil_is_wmi_idle(struct wil6210_priv *wil); +int wmi_resume(struct wil6210_priv *wil); +int wmi_suspend(struct wil6210_priv *wil); +bool wil_is_tx_idle(struct wil6210_priv *wil); +bool wil_is_rx_idle(struct wil6210_priv *wil); int wil_fw_copy_crash_dump(struct wil6210_priv *wil, void *dest, u32 size); void wil_fw_core_dump(struct wil6210_priv *wil); diff --git a/drivers/net/wireless/ath/wil6210/wil_platform.h b/drivers/net/wireless/ath/wil6210/wil_platform.h index f8c41172a3f4..621005b0c5ca 100644 --- a/drivers/net/wireless/ath/wil6210/wil_platform.h +++ b/drivers/net/wireless/ath/wil6210/wil_platform.h @@ -33,10 +33,11 @@ enum wil_platform_event { */ struct wil_platform_ops { int (*bus_request)(void *handle, uint32_t kbps /* KBytes/Sec */); - int (*suspend)(void *handle); - int (*resume)(void *handle); + int (*suspend)(void *handle, bool keep_device_power); + int (*resume)(void *handle, bool device_powered_on); void (*uninit)(void *handle); int (*notify)(void *handle, enum wil_platform_event evt); + bool (*keep_radio_on_during_sleep)(void *handle); }; /** diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 97e22281314c..24878ecf7e93 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -38,6 +38,8 @@ module_param(led_id, byte, 0444); MODULE_PARM_DESC(led_id, " 60G device led enablement. Set the led ID (0-2) to enable"); +#define WIL_WAIT_FOR_SUSPEND_RESUME_COMP 200 + /** * WMI event receiving - theory of operations * @@ -234,6 +236,16 @@ static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len) return -EAGAIN; } + /* Allow sending only suspend / resume commands during susepnd flow */ + if ((test_bit(wil_status_suspending, wil->status) || + test_bit(wil_status_suspended, wil->status) || + test_bit(wil_status_resuming, wil->status)) && + ((cmdid != WMI_TRAFFIC_SUSPEND_CMDID) && + (cmdid != WMI_TRAFFIC_RESUME_CMDID))) { + wil_err(wil, "WMI: reject send_command during suspend\n"); + return -EINVAL; + } + if (!head) { wil_err(wil, "WMI head is garbage: 0x%08x\n", r->head); return -EINVAL; @@ -893,6 +905,11 @@ void wmi_recv_cmd(struct wil6210_priv *wil) return; } + if (test_bit(wil_status_suspended, wil->status)) { + wil_err(wil, "suspended. cannot handle WMI event\n"); + return; + } + for (n = 0;; n++) { u16 len; bool q; @@ -945,6 +962,15 @@ void wmi_recv_cmd(struct wil6210_priv *wil) struct wmi_cmd_hdr *wmi = &evt->event.wmi; u16 id = le16_to_cpu(wmi->command_id); u32 tstamp = le32_to_cpu(wmi->fw_timestamp); + if (test_bit(wil_status_resuming, wil->status)) { + if (id == WMI_TRAFFIC_RESUME_EVENTID) + clear_bit(wil_status_resuming, + wil->status); + else + wil_err(wil, + "WMI evt %d while resuming\n", + id); + } spin_lock_irqsave(&wil->wmi_ev_lock, flags); if (wil->reply_id && wil->reply_id == id) { if (wil->reply_buf) { @@ -952,6 +978,11 @@ void wmi_recv_cmd(struct wil6210_priv *wil) min(len, wil->reply_size)); immed_reply = true; } + if (id == WMI_TRAFFIC_SUSPEND_EVENTID) { + wil_dbg_wmi(wil, + "set suspend_resp_rcvd\n"); + wil->suspend_resp_rcvd = true; + } } spin_unlock_irqrestore(&wil->wmi_ev_lock, flags); @@ -1909,6 +1940,85 @@ int wmi_link_maintain_cfg_write(struct wil6210_priv *wil, return rc; } +int wmi_suspend(struct wil6210_priv *wil) +{ + int rc; + struct wmi_traffic_suspend_cmd cmd = { + .wakeup_trigger = wil->wakeup_trigger, + }; + struct { + struct wmi_cmd_hdr wmi; + struct wmi_traffic_suspend_event evt; + } __packed reply; + u32 suspend_to = WIL_WAIT_FOR_SUSPEND_RESUME_COMP; + + wil->suspend_resp_rcvd = false; + wil->suspend_resp_comp = false; + + reply.evt.status = WMI_TRAFFIC_SUSPEND_REJECTED; + + rc = wmi_call(wil, WMI_TRAFFIC_SUSPEND_CMDID, &cmd, sizeof(cmd), + WMI_TRAFFIC_SUSPEND_EVENTID, &reply, sizeof(reply), + suspend_to); + if (rc) { + wil_err(wil, "wmi_call for suspend req failed, rc=%d\n", rc); + if (rc == -ETIME) + /* wmi_call TO */ + wil->suspend_stats.rejected_by_device++; + else + wil->suspend_stats.rejected_by_host++; + goto out; + } + + wil_dbg_wmi(wil, "waiting for suspend_response_completed\n"); + + rc = wait_event_interruptible_timeout(wil->wq, + wil->suspend_resp_comp, + msecs_to_jiffies(suspend_to)); + if (rc == 0) { + wil_err(wil, "TO waiting for suspend_response_completed\n"); + if (wil->suspend_resp_rcvd) + /* Device responded but we TO due to another reason */ + wil->suspend_stats.rejected_by_host++; + else + wil->suspend_stats.rejected_by_device++; + rc = -EBUSY; + goto out; + } + + wil_dbg_wmi(wil, "suspend_response_completed rcvd\n"); + if (reply.evt.status == WMI_TRAFFIC_SUSPEND_REJECTED) { + wil_dbg_pm(wil, "device rejected the suspend\n"); + wil->suspend_stats.rejected_by_device++; + } + rc = reply.evt.status; + +out: + wil->suspend_resp_rcvd = false; + wil->suspend_resp_comp = false; + + return rc; +} + +int wmi_resume(struct wil6210_priv *wil) +{ + int rc; + struct { + struct wmi_cmd_hdr wmi; + struct wmi_traffic_resume_event evt; + } __packed reply; + + reply.evt.status = WMI_TRAFFIC_RESUME_FAILED; + + rc = wmi_call(wil, WMI_TRAFFIC_RESUME_CMDID, NULL, 0, + WMI_TRAFFIC_RESUME_EVENTID, &reply, sizeof(reply), + WIL_WAIT_FOR_SUSPEND_RESUME_COMP); + if (rc) + return rc; + + return reply.evt.status; +} + static bool wmi_evt_call_handler(struct wil6210_priv *wil, int id, void *d, int len) { @@ -1998,3 +2108,36 @@ void wmi_event_worker(struct work_struct *work) } wil_dbg_wmi(wil, "event_worker: Finished\n"); } + +bool wil_is_wmi_idle(struct wil6210_priv *wil) +{ + ulong flags; + struct wil6210_mbox_ring *r = &wil->mbox_ctl.rx; + bool rc = false; + + spin_lock_irqsave(&wil->wmi_ev_lock, flags); + + /* Check if there are pending WMI events in the events queue */ + if (!list_empty(&wil->pending_wmi_ev)) { + wil_dbg_pm(wil, "Pending WMI events in queue\n"); + goto out; + } + + /* Check if there is a pending WMI call */ + if (wil->reply_id) { + wil_dbg_pm(wil, "Pending WMI call\n"); + goto out; + } + + /* Check if there are pending RX events in mbox */ + r->head = wil_r(wil, RGF_MBOX + + offsetof(struct wil6210_mbox_ctl, rx.head)); + if (r->tail != r->head) + wil_dbg_pm(wil, "Pending WMI mbox events\n"); + else + rc = true; + +out: + spin_unlock_irqrestore(&wil->wmi_ev_lock, flags); + return rc; +} diff --git a/drivers/net/wireless/ath/wil6210/wmi.h b/drivers/net/wireless/ath/wil6210/wmi.h index f7f5f4f801e3..256f63c57da0 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.h +++ b/drivers/net/wireless/ath/wil6210/wmi.h @@ -59,6 +59,7 @@ enum wmi_fw_capability { WMI_FW_CAPABILITY_DISABLE_AP_SME = 4, WMI_FW_CAPABILITY_WMI_ONLY = 5, WMI_FW_CAPABILITY_THERMAL_THROTTLING = 7, + WMI_FW_CAPABILITY_D3_SUSPEND = 8, WMI_FW_CAPABILITY_MAX, }; @@ -157,7 +158,7 @@ enum wmi_command_id { WMI_FLASH_READ_CMDID = 0x902, WMI_FLASH_WRITE_CMDID = 0x903, /* Power management */ - WMI_TRAFFIC_DEFERRAL_CMDID = 0x904, + WMI_TRAFFIC_SUSPEND_CMDID = 0x904, WMI_TRAFFIC_RESUME_CMDID = 0x905, /* P2P */ WMI_P2P_CFG_CMDID = 0x910, @@ -500,8 +501,14 @@ struct wmi_port_delete_cmd { u8 reserved[3]; } __packed; -/* WMI_TRAFFIC_DEFERRAL_CMDID */ -struct wmi_traffic_deferral_cmd { +/* WMI_TRAFFIC_SUSPEND_CMD wakeup trigger bit mask values */ +enum wmi_wakeup_trigger { + WMI_WAKEUP_TRIGGER_UCAST = 0x01, + WMI_WAKEUP_TRIGGER_BCAST = 0x02, +}; + +/* WMI_TRAFFIC_SUSPEND_CMDID */ +struct wmi_traffic_suspend_cmd { /* Bit vector: bit[0] - wake on Unicast, bit[1] - wake on Broadcast */ u8 wakeup_trigger; } __packed; @@ -1084,7 +1091,7 @@ enum wmi_event_id { WMI_FLASH_READ_DONE_EVENTID = 0x1902, WMI_FLASH_WRITE_DONE_EVENTID = 0x1903, /* Power management */ - WMI_TRAFFIC_DEFERRAL_EVENTID = 0x1904, + WMI_TRAFFIC_SUSPEND_EVENTID = 0x1904, WMI_TRAFFIC_RESUME_EVENTID = 0x1905, /* P2P */ WMI_P2P_CFG_DONE_EVENTID = 0x1910, @@ -1926,14 +1933,14 @@ struct wmi_link_maintain_cfg_read_done_event { struct wmi_link_maintain_cfg lm_cfg; } __packed; -enum wmi_traffic_deferral_status { - WMI_TRAFFIC_DEFERRAL_APPROVED = 0x0, - WMI_TRAFFIC_DEFERRAL_REJECTED = 0x1, +enum wmi_traffic_suspend_status { + WMI_TRAFFIC_SUSPEND_APPROVED = 0x0, + WMI_TRAFFIC_SUSPEND_REJECTED = 0x1, }; -/* WMI_TRAFFIC_DEFERRAL_EVENTID */ -struct wmi_traffic_deferral_event { - /* enum wmi_traffic_deferral_status_e */ +/* WMI_TRAFFIC_SUSPEND_EVENTID */ +struct wmi_traffic_suspend_event { + /* enum wmi_traffic_suspend_status_e */ u8 status; } __packed; diff --git a/drivers/platform/msm/msm_11ad/msm_11ad.c b/drivers/platform/msm/msm_11ad/msm_11ad.c index f1e348969c7b..b1989f8741f5 100644 --- a/drivers/platform/msm/msm_11ad/msm_11ad.c +++ b/drivers/platform/msm/msm_11ad/msm_11ad.c @@ -40,9 +40,6 @@ #define SMMU_SIZE ((SZ_1G * 4ULL) - SMMU_BASE) #define WIGIG_ENABLE_DELAY 50 -#define PM_OPT_SUSPEND (MSM_PCIE_CONFIG_NO_CFG_RESTORE | \ - MSM_PCIE_CONFIG_LINKDOWN) -#define PM_OPT_RESUME MSM_PCIE_CONFIG_NO_CFG_RESTORE #define WIGIG_SUBSYS_NAME "WIGIG" #define WIGIG_RAMDUMP_SIZE 0x200000 /* maximum ramdump size */ @@ -127,6 +124,8 @@ struct msm11ad_ctx { bool use_cpu_boost; bool is_cpu_boosted; struct cpumask boost_cpu; + + bool keep_radio_on_during_sleep; }; static LIST_HEAD(dev_list); @@ -523,30 +522,8 @@ int msm_11ad_ctrl_aspm_l1(struct msm11ad_ctx *ctx, bool enable) return rc; } -static int ops_suspend(void *handle) +static int msm_11ad_turn_device_power_off(struct msm11ad_ctx *ctx) { - int rc; - struct msm11ad_ctx *ctx = handle; - struct pci_dev *pcidev; - - pr_info("%s(%p)\n", __func__, handle); - if (!ctx) { - pr_err("No context\n"); - return -ENODEV; - } - pcidev = ctx->pcidev; - rc = pci_save_state(pcidev); - if (rc) { - dev_err(ctx->dev, "pci_save_state failed :%d\n", rc); - return rc; - } - rc = msm_pcie_pm_control(MSM_PCIE_SUSPEND, pcidev->bus->number, - pcidev, NULL, PM_OPT_SUSPEND); - if (rc) { - dev_err(ctx->dev, "msm_pcie_pm_control(SUSPEND) failed :%d\n", - rc); - return rc; - } if (ctx->gpio_en >= 0) gpio_direction_output(ctx->gpio_en, 0); @@ -557,20 +534,12 @@ static int ops_suspend(void *handle) msm_11ad_disable_vregs(ctx); - return rc; + return 0; } -static int ops_resume(void *handle) +static int msm_11ad_turn_device_power_on(struct msm11ad_ctx *ctx) { int rc; - struct msm11ad_ctx *ctx = handle; - struct pci_dev *pcidev; - - pr_info("%s(%p)\n", __func__, handle); - if (!ctx) { - pr_err("No context\n"); - return -ENODEV; - } rc = msm_11ad_enable_vregs(ctx); if (rc) { @@ -588,26 +557,125 @@ static int ops_resume(void *handle) if (ctx->sleep_clk_en >= 0) gpio_direction_output(ctx->sleep_clk_en, 1); - pcidev = ctx->pcidev; if (ctx->gpio_en >= 0) { gpio_direction_output(ctx->gpio_en, 1); msleep(WIGIG_ENABLE_DELAY); } - rc = msm_pcie_pm_control(MSM_PCIE_RESUME, pcidev->bus->number, - pcidev, NULL, PM_OPT_RESUME); + return 0; + +err_disable_vregs: + msm_11ad_disable_vregs(ctx); + return rc; +} + +static int msm_11ad_suspend_power_off(void *handle) +{ + int rc; + struct msm11ad_ctx *ctx = handle; + struct pci_dev *pcidev; + + pr_debug("%s\n", __func__); + + if (!ctx) { + pr_err("%s: No context\n", __func__); + return -ENODEV; + } + + pcidev = ctx->pcidev; + + msm_pcie_shadow_control(ctx->pcidev, 0); + + rc = pci_save_state(pcidev); if (rc) { - dev_err(ctx->dev, "msm_pcie_pm_control(RESUME) failed :%d\n", + dev_err(ctx->dev, "pci_save_state failed :%d\n", rc); + goto out; + } + ctx->pristine_state = pci_store_saved_state(pcidev); + + rc = msm_pcie_pm_control(MSM_PCIE_SUSPEND, pcidev->bus->number, + pcidev, NULL, 0); + if (rc) { + dev_err(ctx->dev, "msm_pcie_pm_control(SUSPEND) failed :%d\n", rc); - goto err_disable_power; + goto out; + } + + rc = msm_11ad_turn_device_power_off(ctx); + +out: + return rc; +} + +static int ops_suspend(void *handle, bool keep_device_power) +{ + struct msm11ad_ctx *ctx = handle; + struct pci_dev *pcidev; + int rc; + + pr_debug("11ad suspend: %s\n", __func__); + if (!ctx) { + pr_err("11ad suspend: No context\n"); + return -ENODEV; } - rc = msm_pcie_recover_config(pcidev); + + if (!keep_device_power) + return msm_11ad_suspend_power_off(handle); + + pcidev = ctx->pcidev; + + msm_pcie_shadow_control(pcidev, 0); + + dev_dbg(ctx->dev, "disable device and save config\n"); + pci_disable_device(pcidev); + pci_save_state(pcidev); + ctx->pristine_state = pci_store_saved_state(pcidev); + dev_dbg(ctx->dev, "moving to D3\n"); + pci_set_power_state(pcidev, PCI_D3hot); + + rc = msm_pcie_pm_control(MSM_PCIE_SUSPEND, pcidev->bus->number, + pcidev, NULL, 0); + if (rc) + dev_err(ctx->dev, "msm_pcie_pm_control(SUSPEND) failed :%d\n", + rc); + + return rc; +} + +static int msm_11ad_resume_power_on(void *handle) +{ + int rc; + struct msm11ad_ctx *ctx = handle; + struct pci_dev *pcidev; + + pr_debug("%s\n", __func__); + + if (!ctx) { + pr_err("%s: No context\n", __func__); + return -ENODEV; + } + pcidev = ctx->pcidev; + + rc = msm_11ad_turn_device_power_on(ctx); + if (rc) + return rc; + + rc = msm_pcie_pm_control(MSM_PCIE_RESUME, pcidev->bus->number, + pcidev, NULL, 0); if (rc) { - dev_err(ctx->dev, "msm_pcie_recover_config failed :%d\n", + dev_err(ctx->dev, "msm_pcie_pm_control(RESUME) failed :%d\n", rc); - goto err_suspend_rc; + goto err_disable_power; } + pci_set_power_state(pcidev, PCI_D0); + + if (ctx->pristine_state) + pci_load_saved_state(ctx->pcidev, ctx->pristine_state); + pci_restore_state(ctx->pcidev); + + msm_pcie_shadow_control(ctx->pcidev, 1); + /* Disable L1, in case it is enabled */ if (ctx->l1_enabled_in_enum) { rc = msm_11ad_ctrl_aspm_l1(ctx, false); @@ -622,18 +690,54 @@ static int ops_resume(void *handle) err_suspend_rc: msm_pcie_pm_control(MSM_PCIE_SUSPEND, pcidev->bus->number, - pcidev, NULL, PM_OPT_SUSPEND); + pcidev, NULL, 0); err_disable_power: - if (ctx->gpio_en >= 0) - gpio_direction_output(ctx->gpio_en, 0); + msm_11ad_turn_device_power_off(ctx); + return rc; +} - if (ctx->sleep_clk_en >= 0) - gpio_direction_output(ctx->sleep_clk_en, 0); +static int ops_resume(void *handle, bool device_powered_on) +{ + struct msm11ad_ctx *ctx = handle; + struct pci_dev *pcidev; + int rc; - msm_11ad_disable_clocks(ctx); -err_disable_vregs: - msm_11ad_disable_vregs(ctx); + pr_debug("11ad resume: %s\n", __func__); + if (!ctx) { + pr_err("11ad resume: No context\n"); + return -ENODEV; + } + + pcidev = ctx->pcidev; + + if (!device_powered_on) + return msm_11ad_resume_power_on(handle); + + rc = msm_pcie_pm_control(MSM_PCIE_RESUME, pcidev->bus->number, + pcidev, NULL, 0); + if (rc) { + dev_err(ctx->dev, "msm_pcie_pm_control(RESUME) failed :%d\n", + rc); + return rc; + } + pci_set_power_state(pcidev, PCI_D0); + + dev_dbg(ctx->dev, "restore state and enable device\n"); + pci_load_saved_state(pcidev, ctx->pristine_state); + pci_restore_state(pcidev); + + rc = pci_enable_device(pcidev); + if (rc) { + dev_err(ctx->dev, "pci_enable_device failed (%d)\n", rc); + goto out; + } + + msm_pcie_shadow_control(pcidev, 1); + + dev_dbg(ctx->dev, "pci set master\n"); + pci_set_master(pcidev); +out: return rc; } @@ -906,7 +1010,7 @@ out_rc: static void msm_11ad_init_cpu_boost(struct msm11ad_ctx *ctx) { unsigned int minfreq = 0, maxfreq = 0, freq; - int i, boost_cpu; + int i, boost_cpu = 0; for_each_possible_cpu(i) { freq = cpufreq_quick_get_max(i); @@ -993,6 +1097,8 @@ static int msm_11ad_probe(struct platform_device *pdev) return -EINVAL; } ctx->use_smmu = of_property_read_bool(of_node, "qcom,smmu-support"); + ctx->keep_radio_on_during_sleep = of_property_read_bool(of_node, + "qcom,keep_radio_on_during_sleep"); ctx->bus_scale = msm_bus_cl_get_pdata(pdev); ctx->smmu_s1_en = of_property_read_bool(of_node, "qcom,smmu-s1-en"); @@ -1105,13 +1211,6 @@ static int msm_11ad_probe(struct platform_device *pdev) } } - rc = pci_save_state(pcidev); - if (rc) { - dev_err(ctx->dev, "pci_save_state failed :%d\n", rc); - goto out_rc; - } - ctx->pristine_state = pci_store_saved_state(pcidev); - if (ctx->sleep_clk_en >= 0) { rc = gpio_request(ctx->sleep_clk_en, "msm_11ad"); if (rc < 0) { @@ -1147,7 +1246,7 @@ static int msm_11ad_probe(struct platform_device *pdev) device_disable_async_suspend(&pcidev->dev); list_add_tail(&ctx->list, &dev_list); - ops_suspend(ctx); + msm_11ad_suspend_power_off(ctx); return 0; out_rc: @@ -1315,7 +1414,7 @@ static void ops_uninit(void *handle) memset(&ctx->rops, 0, sizeof(ctx->rops)); ctx->wil_handle = NULL; - ops_suspend(ctx); + msm_11ad_suspend_power_off(ctx); } static int msm_11ad_notify_crash(struct msm11ad_ctx *ctx) @@ -1373,6 +1472,16 @@ static int ops_notify(void *handle, enum wil_platform_event evt) return rc; } +bool ops_keep_radio_on_during_sleep(void *handle) +{ + struct msm11ad_ctx *ctx = (struct msm11ad_ctx *)handle; + + pr_debug("%s: keep radio on during sleep is %s\n", __func__, + ctx->keep_radio_on_during_sleep ? "allowed" : "not allowed"); + + return ctx->keep_radio_on_during_sleep; +} + void *msm_11ad_dev_init(struct device *dev, struct wil_platform_ops *ops, const struct wil_platform_rops *rops, void *wil_handle) { @@ -1412,6 +1521,7 @@ void *msm_11ad_dev_init(struct device *dev, struct wil_platform_ops *ops, ops->resume = ops_resume; ops->uninit = ops_uninit; ops->notify = ops_notify; + ops->keep_radio_on_during_sleep = ops_keep_radio_on_during_sleep; return ctx; } @@ -1428,19 +1538,9 @@ int msm_11ad_modinit(void) return -EINVAL; } - if (ctx->pristine_state) { - /* in old kernels, pci_load_saved_state() is not exported; - * so use pci_load_and_free_saved_state() - * and re-allocate ctx->saved_state again - */ - pci_load_and_free_saved_state(ctx->pcidev, - &ctx->pristine_state); - ctx->pristine_state = pci_store_saved_state(ctx->pcidev); - } - ctx->subsys_handle = subsystem_get(ctx->subsysdesc.name); - return ops_resume(ctx); + return msm_11ad_resume_power_on(ctx); } EXPORT_SYMBOL(msm_11ad_modinit); diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c index bc00a7e9572f..aadaef7d1bed 100644 --- a/drivers/scsi/ufs/ufs-qcom.c +++ b/drivers/scsi/ufs/ufs-qcom.c @@ -1497,7 +1497,7 @@ static void ufs_qcom_advertise_quirks(struct ufs_hba *hba) hba->quirks |= UFSHCD_QUIRK_BROKEN_LCC; } - if (host->hw_ver.major >= 0x2) { + if (host->hw_ver.major == 0x2) { hba->quirks |= UFSHCD_QUIRK_BROKEN_UFS_HCI_VERSION; if (!ufs_qcom_cap_qunipro(host)) diff --git a/drivers/soc/qcom/memshare/msm_memshare.c b/drivers/soc/qcom/memshare/msm_memshare.c index c11114528d2a..7406dba44320 100644 --- a/drivers/soc/qcom/memshare/msm_memshare.c +++ b/drivers/soc/qcom/memshare/msm_memshare.c @@ -524,10 +524,6 @@ static int handle_alloc_generic_req(void *req_h, void *req, void *conn_h) return -EINVAL; } - memblock[client_id].free_memory += 1; - pr_debug("memshare: In %s, free memory count for client id: %d = %d", - __func__, memblock[client_id].client_id, - memblock[client_id].free_memory); if (!memblock[client_id].alloted) { if (alloc_req->client_id == 1 && alloc_req->num_bytes > 0) size = alloc_req->num_bytes + MEMSHARE_GUARD_BYTES; @@ -541,11 +537,16 @@ static int handle_alloc_generic_req(void *req_h, void *req, void *conn_h) resp = 1; } if (!resp) { + memblock[client_id].free_memory += 1; memblock[client_id].alloted = 1; memblock[client_id].size = alloc_req->num_bytes; memblock[client_id].peripheral = alloc_req->proc_id; } } + pr_debug("memshare: In %s, free memory count for client id: %d = %d", + __func__, memblock[client_id].client_id, + memblock[client_id].free_memory); + memblock[client_id].sequence_id = alloc_req->sequence_id; fill_alloc_response(alloc_resp, client_id, &resp); diff --git a/drivers/soc/qcom/msm_bus/msm_bus_rules.c b/drivers/soc/qcom/msm_bus/msm_bus_rules.c index 297ba9fc3c35..ea29e303bbde 100644 --- a/drivers/soc/qcom/msm_bus/msm_bus_rules.c +++ b/drivers/soc/qcom/msm_bus/msm_bus_rules.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2015, 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 @@ -410,8 +410,10 @@ void print_all_rules(void) { struct rule_node_info *node_it = NULL; + mutex_lock(&msm_bus_rules_lock); list_for_each_entry(node_it, &node_list, link) print_rules(node_it); + mutex_unlock(&msm_bus_rules_lock); } void print_rules_buf(char *buf, int max_buf) @@ -421,6 +423,7 @@ void print_rules_buf(char *buf, int max_buf) int i; int cnt = 0; + mutex_lock(&msm_bus_rules_lock); list_for_each_entry(node_it, &node_list, link) { cnt += scnprintf(buf + cnt, max_buf - cnt, "\n Now printing rules for Node %d cur_rule %d\n", @@ -452,6 +455,7 @@ void print_rules_buf(char *buf, int max_buf) node_rule->rule_ops.mode); } } + mutex_unlock(&msm_bus_rules_lock); } static int copy_rule(struct bus_rule_type *src, struct rules_def *node_rule, @@ -721,11 +725,12 @@ bool msm_rule_are_rules_registered(void) { bool ret = false; + mutex_lock(&msm_bus_rules_lock); if (list_empty(&node_list)) ret = false; else ret = true; - + mutex_unlock(&msm_bus_rules_lock); return ret; } diff --git a/drivers/soc/qcom/rpm_master_stat.c b/drivers/soc/qcom/rpm_master_stat.c index 14004a2b721e..7bf18ffe6ad2 100644 --- a/drivers/soc/qcom/rpm_master_stat.c +++ b/drivers/soc/qcom/rpm_master_stat.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 @@ -96,6 +96,7 @@ static int msm_rpm_master_copy_stats( int count, j = 0; char *buf; static DEFINE_MUTEX(msm_rpm_master_stats_mutex); + unsigned long active_cores; mutex_lock(&msm_rpm_master_stats_mutex); @@ -247,12 +248,11 @@ static int msm_rpm_master_copy_stats( record.active_cores); } - j = find_first_bit((unsigned long *)&record.active_cores, - BITS_PER_LONG); + active_cores = record.active_cores; + j = find_first_bit(&active_cores, BITS_PER_LONG); while (j < BITS_PER_LONG) { SNPRINTF(buf, count, "\t\tcore%d\n", j); - j = find_next_bit((unsigned long *)&record.active_cores, - BITS_PER_LONG, j + 1); + j = find_next_bit(&active_cores, BITS_PER_LONG, j + 1); } master_cnt++; diff --git a/drivers/soc/qcom/service-locator.c b/drivers/soc/qcom/service-locator.c index 97cd11201262..f19db5fe99b3 100644 --- a/drivers/soc/qcom/service-locator.c +++ b/drivers/soc/qcom/service-locator.c @@ -31,7 +31,6 @@ #define SERVREG_LOC_SERVICE_INSTANCE_ID 1 -#define QMI_RESP_BIT_SHIFT(x) (x << 16) #define QMI_SERVREG_LOC_SERVER_INITIAL_TIMEOUT 2000 #define QMI_SERVREG_LOC_SERVER_TIMEOUT 2000 #define INITIAL_TIMEOUT 100000 @@ -199,9 +198,9 @@ static int servreg_loc_send_msg(struct msg_desc *req_desc, } /* Check the response */ - if (QMI_RESP_BIT_SHIFT(resp->resp.result) != QMI_RESULT_SUCCESS_V01) { + if (resp->resp.result != QMI_RESULT_SUCCESS_V01) { pr_err("QMI request for client %s failed 0x%x\n", - pd->client_name, QMI_RESP_BIT_SHIFT(resp->resp.error)); + pd->client_name, resp->resp.error); return -EREMOTEIO; } return rc; @@ -220,7 +219,7 @@ static int service_locator_send_msg(struct pd_qmi_client_data *pd) return -EAGAIN; } - req = kmalloc(sizeof( + req = kzalloc(sizeof( struct qmi_servreg_loc_get_domain_list_req_msg_v01), GFP_KERNEL); if (!req) { @@ -228,7 +227,7 @@ static int service_locator_send_msg(struct pd_qmi_client_data *pd) rc = -ENOMEM; goto out; } - resp = kmalloc(sizeof( + resp = kzalloc(sizeof( struct qmi_servreg_loc_get_domain_list_resp_msg_v01), GFP_KERNEL); if (!resp) { diff --git a/drivers/soc/qcom/service-notifier.c b/drivers/soc/qcom/service-notifier.c index b5681a5c6817..221ae0c1fefb 100644 --- a/drivers/soc/qcom/service-notifier.c +++ b/drivers/soc/qcom/service-notifier.c @@ -30,7 +30,6 @@ #include <soc/qcom/service-notifier.h> #include "service-notifier-private.h" -#define QMI_RESP_BIT_SHIFT(x) (x << 16) #define SERVREG_NOTIF_NAME_LENGTH QMI_SERVREG_NOTIF_NAME_LENGTH_V01 #define SERVREG_NOTIF_SERVICE_ID SERVREG_NOTIF_SERVICE_ID_V01 #define SERVREG_NOTIF_SERVICE_VERS SERVREG_NOTIF_SERVICE_VERS_V01 @@ -225,9 +224,8 @@ static void send_ind_ack(struct work_struct *work) } /* Check the response */ - if (QMI_RESP_BIT_SHIFT(resp.resp.result) != QMI_RESULT_SUCCESS_V01) - pr_err("QMI request failed 0x%x\n", - QMI_RESP_BIT_SHIFT(resp.resp.error)); + if (resp.resp.result != QMI_RESULT_SUCCESS_V01) + pr_err("QMI request failed 0x%x\n", resp.resp.error); pr_info("Indication ACKed for transid %d, service %s, instance %d!\n", data->ind_msg.transaction_id, data->ind_msg.service_path, data->instance_id); @@ -318,9 +316,8 @@ static int send_notif_listener_msg_req(struct service_notif_info *service_notif, } /* Check the response */ - if (QMI_RESP_BIT_SHIFT(resp.resp.result) != QMI_RESULT_SUCCESS_V01) { - pr_err("QMI request failed 0x%x\n", - QMI_RESP_BIT_SHIFT(resp.resp.error)); + if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { + pr_err("QMI request failed 0x%x\n", resp.resp.error); return -EREMOTEIO; } @@ -645,15 +642,15 @@ static int send_pd_restart_req(const char *service_path, } /* Check response if PDR is disabled */ - if (QMI_RESP_BIT_SHIFT(resp.resp.result) == QMI_ERR_DISABLED_V01) { - pr_err("PD restart is disabled 0x%x\n", - QMI_RESP_BIT_SHIFT(resp.resp.error)); + if (resp.resp.result == QMI_RESULT_FAILURE_V01 && + resp.resp.error == QMI_ERR_DISABLED_V01) { + pr_err("PD restart is disabled 0x%x\n", resp.resp.error); return -EOPNOTSUPP; } /* Check the response for other error case*/ - if (QMI_RESP_BIT_SHIFT(resp.resp.result) != QMI_RESULT_SUCCESS_V01) { + if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { pr_err("QMI request for PD restart failed 0x%x\n", - QMI_RESP_BIT_SHIFT(resp.resp.error)); + resp.resp.error); return -EREMOTEIO; } diff --git a/drivers/soc/qcom/spcom.c b/drivers/soc/qcom/spcom.c index 10eebb0316e8..c2af34926b37 100644 --- a/drivers/soc/qcom/spcom.c +++ b/drivers/soc/qcom/spcom.c @@ -220,9 +220,9 @@ struct spcom_channel { bool tx_abort; /* rx data info */ - int rx_buf_size; /* allocated rx buffer size */ + size_t rx_buf_size; /* allocated rx buffer size */ bool rx_buf_ready; - int actual_rx_size; /* actual data size received */ + size_t actual_rx_size; /* actual data size received */ const void *glink_rx_buf; /* ION lock/unlock support */ @@ -302,6 +302,10 @@ static inline bool spcom_is_channel_open(struct spcom_channel *ch) */ static inline bool spcom_is_channel_connected(struct spcom_channel *ch) { + /* Channel must be open before it gets connected */ + if (!spcom_is_channel_open(ch)) + return false; + return (ch->glink_state == GLINK_CONNECTED); } @@ -359,6 +363,11 @@ static void spcom_link_state_notif_cb(struct glink_link_state_cb_info *cb_info, struct spcom_channel *ch = NULL; const char *ch_name = "sp_kernel"; + if (!cb_info) { + pr_err("invalid NULL cb_info.\n"); + return; + } + if (!spcom_is_ready()) { pr_err("spcom is not ready.\n"); return; @@ -411,13 +420,17 @@ static void spcom_notify_rx(void *handle, struct spcom_channel *ch = (struct spcom_channel *) priv; if (!ch) { - pr_err("invalid ch parameter.\n"); + pr_err("invalid NULL channel param\n"); + return; + } + if (!buf) { + pr_err("invalid NULL buf param\n"); return; } - pr_debug("ch [%s] rx size [%d].\n", ch->name, (int) size); + pr_debug("ch [%s] rx size [%zu]\n", ch->name, size); - ch->actual_rx_size = (int) size; + ch->actual_rx_size = size; ch->glink_rx_buf = (void *) buf; complete_all(&ch->rx_done); @@ -436,7 +449,11 @@ static void spcom_notify_tx_done(void *handle, int *tx_buf = (int *) buf; if (!ch) { - pr_err("invalid ch parameter.\n"); + pr_err("invalid NULL channel param\n"); + return; + } + if (!buf) { + pr_err("invalid NULL buf param\n"); return; } @@ -460,6 +477,11 @@ static void spcom_notify_state(void *handle, const void *priv, unsigned event) int ret; struct spcom_channel *ch = (struct spcom_channel *) priv; + if (!ch) { + pr_err("invalid NULL channel param\n"); + return; + } + switch (event) { case GLINK_CONNECTED: pr_debug("GLINK_CONNECTED, ch name [%s].\n", ch->name); @@ -479,7 +501,7 @@ static void spcom_notify_state(void *handle, const void *priv, unsigned event) if (ret) { pr_err("glink_queue_rx_intent() err [%d]\n", ret); } else { - pr_debug("rx buf is ready, size [%d].\n", + pr_debug("rx buf is ready, size [%zu]\n", ch->rx_buf_size); ch->rx_buf_ready = true; } @@ -536,9 +558,7 @@ static void spcom_notify_state(void *handle, const void *priv, unsigned event) static bool spcom_notify_rx_intent_req(void *handle, const void *priv, size_t req_size) { - struct spcom_channel *ch = (struct spcom_channel *) priv; - - pr_err("Unexpected intent request for ch [%s].\n", ch->name); + pr_err("Unexpected intent request\n"); return false; } @@ -554,6 +574,11 @@ static void spcom_notify_rx_abort(void *handle, const void *priv, { struct spcom_channel *ch = (struct spcom_channel *) priv; + if (!ch) { + pr_err("invalid NULL channel param\n"); + return; + } + pr_debug("ch [%s] pending rx aborted.\n", ch->name); if (spcom_is_channel_open(ch) && (!ch->rx_abort)) { @@ -574,6 +599,11 @@ static void spcom_notify_tx_abort(void *handle, const void *priv, { struct spcom_channel *ch = (struct spcom_channel *) priv; + if (!ch) { + pr_err("invalid NULL channel param\n"); + return; + } + pr_debug("ch [%s] pending tx aborted.\n", ch->name); if (spcom_is_channel_connected(ch) && (!ch->tx_abort)) { @@ -792,6 +822,8 @@ static int spcom_close(struct spcom_channel *ch) * @size: buffer size * * ACK is expected within a very short time (few msec). + * + * Return: 0 on successful operation, negative value otherwise. */ static int spcom_tx(struct spcom_channel *ch, void *buf, @@ -856,13 +888,15 @@ exit_err: * @size: buffer size * * ACK is expected within a very short time (few msec). + * + * Return: size in bytes on success, negative value on failure. */ static int spcom_rx(struct spcom_channel *ch, void *buf, uint32_t size, uint32_t timeout_msec) { - int ret; + int ret = -1; unsigned long jiffies = msecs_to_jiffies(timeout_msec); long timeleft = 1; @@ -870,7 +904,7 @@ static int spcom_rx(struct spcom_channel *ch, /* check for already pending data */ if (ch->actual_rx_size) { - pr_debug("already pending data size [%d].\n", + pr_debug("already pending data size [%zu]\n", ch->actual_rx_size); goto copy_buf; } @@ -893,7 +927,7 @@ static int spcom_rx(struct spcom_channel *ch, mutex_unlock(&ch->lock); return -ERESTART; /* probably SSR */ } else if (ch->actual_rx_size) { - pr_debug("actual_rx_size is [%d].\n", ch->actual_rx_size); + pr_debug("actual_rx_size is [%zu]\n", ch->actual_rx_size); } else { pr_err("actual_rx_size is zero.\n"); goto exit_err; @@ -922,7 +956,7 @@ copy_buf: pr_err("glink_queue_rx_intent() failed, ret [%d]", ret); goto exit_err; } else { - pr_debug("queue rx_buf, size [%d].\n", ch->rx_buf_size); + pr_debug("queue rx_buf, size [%zu]\n", ch->rx_buf_size); } mutex_unlock(&ch->lock); @@ -942,6 +976,8 @@ exit_err: * Server needs the size of the next request to allocate a request buffer. * Initially used intent-request, however this complicated the remote side, * so both sides are not using glink_tx() with INTENT_REQ anymore. + * + * Return: size in bytes on success, negative value on failure. */ static int spcom_get_next_request_size(struct spcom_channel *ch) { @@ -953,7 +989,7 @@ static int spcom_get_next_request_size(struct spcom_channel *ch) /* check if already got it via callback */ if (ch->actual_rx_size) { - pr_debug("next-req-size already ready ch [%s] size [%d].\n", + pr_debug("next-req-size already ready ch [%s] size [%zu]\n", ch->name, ch->actual_rx_size); goto exit_ready; } @@ -968,7 +1004,7 @@ static int spcom_get_next_request_size(struct spcom_channel *ch) } if (ch->actual_rx_size <= 0) { - pr_err("invalid rx size [%d] ch [%s].\n", + pr_err("invalid rx size [%zu] ch [%s]\n", ch->actual_rx_size, ch->name); goto exit_error; } @@ -1101,16 +1137,21 @@ int spcom_unregister_client(struct spcom_client *client) } if (!client) { - pr_err("Invalid parameter.\n"); + pr_err("Invalid client parameter.\n"); return -EINVAL; } - ch = client->ch; - kfree(client); + ch = client->ch; + if (!ch) { + pr_err("Invalid channel.\n"); + return -EINVAL; + } spcom_close(ch); + kfree(client); + return 0; } EXPORT_SYMBOL(spcom_unregister_client); @@ -1127,6 +1168,8 @@ EXPORT_SYMBOL(spcom_unregister_client); * @timeout_msec: timeout waiting for response. * * The timeout depends on the specific request handling time at the remote side. + * + * Return: number of rx bytes on success, negative value on failure. */ int spcom_client_send_message_sync(struct spcom_client *client, void *req_ptr, @@ -1149,6 +1192,10 @@ int spcom_client_send_message_sync(struct spcom_client *client, } ch = client->ch; + if (!ch) { + pr_err("Invalid channel.\n"); + return -EINVAL; + } /* Check if remote side connect */ if (!spcom_is_channel_connected(ch)) { @@ -1183,6 +1230,7 @@ EXPORT_SYMBOL(spcom_client_send_message_sync); bool spcom_client_is_server_connected(struct spcom_client *client) { bool connected; + struct spcom_channel *ch; if (!spcom_is_ready()) { pr_err("spcom is not ready.\n"); @@ -1194,7 +1242,13 @@ bool spcom_client_is_server_connected(struct spcom_client *client) return false; } - connected = spcom_is_channel_connected(client->ch); + ch = client->ch; + if (!ch) { + pr_err("Invalid channel.\n"); + return -EINVAL; + } + + connected = spcom_is_channel_connected(ch); return connected; } @@ -1267,16 +1321,20 @@ int spcom_unregister_service(struct spcom_server *server) } if (!server) { - pr_err("Invalid parameter.\n"); + pr_err("Invalid server parameter.\n"); return -EINVAL; } ch = server->ch; - - kfree(server); + if (!ch) { + pr_err("Invalid channel parameter.\n"); + return -EINVAL; + } spcom_close(ch); + kfree(server); + return 0; } EXPORT_SYMBOL(spcom_unregister_service); @@ -1286,7 +1344,7 @@ EXPORT_SYMBOL(spcom_unregister_service); * * @server: server handle * - * Return: request size in bytes. + * Return: size in bytes on success, negative value on failure. */ int spcom_server_get_next_request_size(struct spcom_server *server) { @@ -1299,6 +1357,10 @@ int spcom_server_get_next_request_size(struct spcom_server *server) } ch = server->ch; + if (!ch) { + pr_err("Invalid channel.\n"); + return -EINVAL; + } /* Check if remote side connect */ if (!spcom_is_channel_connected(ch)) { @@ -1321,7 +1383,7 @@ EXPORT_SYMBOL(spcom_server_get_next_request_size); * @req_ptr: request buffer pointer * @req_size: max request size * - * Return: request size in bytes. + * Return: size in bytes on success, negative value on failure. */ int spcom_server_wait_for_request(struct spcom_server *server, void *req_ptr, @@ -1341,6 +1403,10 @@ int spcom_server_wait_for_request(struct spcom_server *server, } ch = server->ch; + if (!ch) { + pr_err("Invalid channel.\n"); + return -EINVAL; + } /* Check if remote side connect */ if (!spcom_is_channel_connected(ch)) { @@ -1379,6 +1445,10 @@ int spcom_server_send_response(struct spcom_server *server, } ch = server->ch; + if (!ch) { + pr_err("Invalid channel.\n"); + return -EINVAL; + } /* Check if remote side connect */ if (!spcom_is_channel_connected(ch)) { @@ -1845,18 +1915,6 @@ static int spcom_handle_unlock_ion_buf_command(struct spcom_channel *ch, } /** - * spcom_handle_fake_ssr_command() - Handle fake ssr command from user space. - */ -static int spcom_handle_fake_ssr_command(struct spcom_channel *ch, int arg) -{ - pr_debug("Start Fake glink SSR subsystem [%s].\n", spcom_edge); - glink_ssr(spcom_edge); - pr_debug("Fake glink SSR subsystem [%s] done.\n", spcom_edge); - - return 0; -} - -/** * spcom_handle_write() - Handle user space write commands. * * @buf: command buffer. @@ -1900,9 +1958,6 @@ static int spcom_handle_write(struct spcom_channel *ch, case SPCOM_CMD_UNLOCK_ION_BUF: ret = spcom_handle_unlock_ion_buf_command(ch, buf, buf_size); break; - case SPCOM_CMD_FSSR: - ret = spcom_handle_fake_ssr_command(ch, cmd->arg); - break; case SPCOM_CMD_CREATE_CHANNEL: ret = spcom_handle_create_channel_command(buf, buf_size); break; @@ -1921,7 +1976,7 @@ static int spcom_handle_write(struct spcom_channel *ch, * @buf: command buffer. * @size: command buffer size. * - * Return: size in bytes. + * Return: size in bytes on success, negative value on failure. */ static int spcom_handle_get_req_size(struct spcom_channel *ch, void *buf, @@ -1949,7 +2004,7 @@ static int spcom_handle_get_req_size(struct spcom_channel *ch, * @buf: command buffer. * @size: command buffer size. * - * Return: size in bytes. + * Return: size in bytes on success, negative value on failure. */ static int spcom_handle_read_req_resp(struct spcom_channel *ch, void *buf, @@ -2033,7 +2088,7 @@ exit_err: * A special size SPCOM_GET_NEXT_REQUEST_SIZE, which is bigger than the max * response/request tells the kernel that user space only need the size. * - * Return: size in bytes. + * Return: size in bytes on success, negative value on failure. */ static int spcom_handle_read(struct spcom_channel *ch, void *buf, @@ -2115,8 +2170,6 @@ static int spcom_device_open(struct inode *inode, struct file *filp) return -ENODEV; } - filp->private_data = ch; - ret = spcom_open(ch, OPEN_CHANNEL_TIMEOUT_MSEC); if (ret == -ETIMEDOUT) { pr_err("Connection timeout channel [%s].\n", name); @@ -2125,6 +2178,8 @@ static int spcom_device_open(struct inode *inode, struct file *filp) return ret; } + filp->private_data = ch; + pr_debug("finished.\n"); return 0; @@ -2209,8 +2264,8 @@ static ssize_t spcom_device_write(struct file *filp, ch = filp->private_data; if (!ch) { - pr_debug("invalid ch pointer.\n"); - /* Allow some special commands via /dev/spcom and /dev/sp_ssr */ + pr_err("invalid ch pointer, command not allowed.\n"); + return -EINVAL; } else { /* Check if remote side connect */ if (!spcom_is_channel_connected(ch)) { diff --git a/drivers/soc/qcom/wcd-dsp-glink.c b/drivers/soc/qcom/wcd-dsp-glink.c index f601e6646852..3c9d8efd3956 100644 --- a/drivers/soc/qcom/wcd-dsp-glink.c +++ b/drivers/soc/qcom/wcd-dsp-glink.c @@ -21,6 +21,7 @@ #include <linux/list.h> #include <linux/cdev.h> #include <linux/platform_device.h> +#include <linux/vmalloc.h> #include <soc/qcom/glink.h> #include "sound/wcd-dsp-glink.h" @@ -29,6 +30,10 @@ #define WDSP_MAX_READ_SIZE (4 * 1024) #define WDSP_MAX_NO_OF_INTENTS (20) #define WDSP_MAX_NO_OF_CHANNELS (10) +#define WDSP_WRITE_PKT_SIZE (sizeof(struct wdsp_write_pkt)) +#define WDSP_REG_PKT_SIZE (sizeof(struct wdsp_reg_pkt)) +#define WDSP_CMD_PKT_SIZE (sizeof(struct wdsp_cmd_pkt)) +#define WDSP_CH_CFG_SIZE (sizeof(struct wdsp_glink_ch_cfg)) #define MINOR_NUMBER_COUNT 1 #define WDSP_EDGE "wdsp" @@ -183,7 +188,7 @@ static void wdsp_glink_notify_tx_done(void *handle, const void *priv, return; } /* Free tx pkt */ - kfree(pkt_priv); + vfree(pkt_priv); } /* @@ -201,7 +206,7 @@ static void wdsp_glink_notify_tx_abort(void *handle, const void *priv, return; } /* Free tx pkt */ - kfree(pkt_priv); + vfree(pkt_priv); } /* @@ -519,9 +524,10 @@ static void wdsp_glink_link_state_cb(struct glink_link_state_cb_info *cb_info, * and register with glink * wpriv: Wdsp_glink private structure. * pkt: Glink registration packet contains glink channel information. + * pkt_size: Size of the pkt. */ static int wdsp_glink_ch_info_init(struct wdsp_glink_priv *wpriv, - struct wdsp_reg_pkt *pkt) + struct wdsp_reg_pkt *pkt, size_t pkt_size) { int ret = 0, i, j; struct glink_link_info link_info; @@ -530,6 +536,7 @@ static int wdsp_glink_ch_info_init(struct wdsp_glink_priv *wpriv, u8 no_of_channels; u8 *payload; u32 ch_size, ch_cfg_size; + size_t size = WDSP_WRITE_PKT_SIZE + WDSP_REG_PKT_SIZE; mutex_lock(&wpriv->glink_mutex); if (wpriv->ch) { @@ -542,9 +549,10 @@ static int wdsp_glink_ch_info_init(struct wdsp_glink_priv *wpriv, no_of_channels = pkt->no_of_channels; if (no_of_channels > WDSP_MAX_NO_OF_CHANNELS) { - dev_info(wpriv->dev, "%s: no_of_channels = %d are limited to %d\n", - __func__, no_of_channels, WDSP_MAX_NO_OF_CHANNELS); - no_of_channels = WDSP_MAX_NO_OF_CHANNELS; + dev_err(wpriv->dev, "%s: no_of_channels: %d but max allowed are %d\n", + __func__, no_of_channels, WDSP_MAX_NO_OF_CHANNELS); + ret = -EINVAL; + goto done; } ch = kcalloc(no_of_channels, sizeof(struct wdsp_glink_ch *), GFP_KERNEL); @@ -558,20 +566,34 @@ static int wdsp_glink_ch_info_init(struct wdsp_glink_priv *wpriv, for (i = 0; i < no_of_channels; i++) { ch_cfg = (struct wdsp_glink_ch_cfg *)payload; + size += WDSP_CH_CFG_SIZE; + if (size > pkt_size) { + dev_err(wpriv->dev, "%s: Invalid size = %zd, pkt_size = %zd\n", + __func__, size, pkt_size); + ret = -EINVAL; + goto err_ch_mem; + } if (ch_cfg->no_of_intents > WDSP_MAX_NO_OF_INTENTS) { dev_err(wpriv->dev, "%s: Invalid no_of_intents = %d\n", __func__, ch_cfg->no_of_intents); ret = -EINVAL; goto err_ch_mem; } + size += (sizeof(u32) * ch_cfg->no_of_intents); + if (size > pkt_size) { + dev_err(wpriv->dev, "%s: Invalid size = %zd, pkt_size = %zd\n", + __func__, size, pkt_size); + ret = -EINVAL; + goto err_ch_mem; + } ch_cfg_size = sizeof(struct wdsp_glink_ch_cfg) + (sizeof(u32) * ch_cfg->no_of_intents); ch_size = sizeof(struct wdsp_glink_ch) + (sizeof(u32) * ch_cfg->no_of_intents); - dev_dbg(wpriv->dev, "%s: channels = %d, ch_cfg_size %d", - __func__, no_of_channels, ch_cfg_size); + dev_dbg(wpriv->dev, "%s: channels: %d ch_cfg_size: %d, size: %zd, pkt_size: %zd", + __func__, no_of_channels, ch_cfg_size, size, pkt_size); ch[i] = kzalloc(ch_size, GFP_KERNEL); if (!ch[i]) { @@ -658,7 +680,7 @@ static void wdsp_glink_tx_buf_work(struct work_struct *work) * there won't be any tx_done notification to * free the buffer. */ - kfree(tx_buf); + vfree(tx_buf); } } else { mutex_unlock(&tx_buf->ch->mutex); @@ -668,7 +690,7 @@ static void wdsp_glink_tx_buf_work(struct work_struct *work) * Free tx_buf here as there won't be any tx_done * notification in this case also. */ - kfree(tx_buf); + vfree(tx_buf); } } @@ -761,6 +783,7 @@ static ssize_t wdsp_glink_write(struct file *file, const char __user *buf, struct wdsp_cmd_pkt *cpkt; struct wdsp_glink_tx_buf *tx_buf; struct wdsp_glink_priv *wpriv; + size_t pkt_max_size; wpriv = (struct wdsp_glink_priv *)file->private_data; if (!wpriv) { @@ -769,7 +792,7 @@ static ssize_t wdsp_glink_write(struct file *file, const char __user *buf, goto done; } - if ((count < sizeof(struct wdsp_write_pkt)) || + if ((count < WDSP_WRITE_PKT_SIZE) || (count > WDSP_MAX_WRITE_SIZE)) { dev_err(wpriv->dev, "%s: Invalid count = %zd\n", __func__, count); @@ -779,8 +802,8 @@ static ssize_t wdsp_glink_write(struct file *file, const char __user *buf, dev_dbg(wpriv->dev, "%s: count = %zd\n", __func__, count); - tx_buf_size = WDSP_MAX_WRITE_SIZE + sizeof(struct wdsp_glink_tx_buf); - tx_buf = kzalloc(tx_buf_size, GFP_KERNEL); + tx_buf_size = count + sizeof(struct wdsp_glink_tx_buf); + tx_buf = vzalloc(tx_buf_size); if (!tx_buf) { ret = -ENOMEM; goto done; @@ -797,19 +820,20 @@ static ssize_t wdsp_glink_write(struct file *file, const char __user *buf, wpkt = (struct wdsp_write_pkt *)tx_buf->buf; switch (wpkt->pkt_type) { case WDSP_REG_PKT: - if (count <= (sizeof(struct wdsp_write_pkt) + - sizeof(struct wdsp_reg_pkt))) { + if (count < (WDSP_WRITE_PKT_SIZE + WDSP_REG_PKT_SIZE + + WDSP_CH_CFG_SIZE)) { dev_err(wpriv->dev, "%s: Invalid reg pkt size = %zd\n", __func__, count); ret = -EINVAL; goto free_buf; } ret = wdsp_glink_ch_info_init(wpriv, - (struct wdsp_reg_pkt *)wpkt->payload); + (struct wdsp_reg_pkt *)wpkt->payload, + count); if (IS_ERR_VALUE(ret)) dev_err(wpriv->dev, "%s: glink register failed, ret = %d\n", __func__, ret); - kfree(tx_buf); + vfree(tx_buf); break; case WDSP_READY_PKT: ret = wait_event_timeout(wpriv->link_state_wait, @@ -823,11 +847,10 @@ static ssize_t wdsp_glink_write(struct file *file, const char __user *buf, goto free_buf; } ret = 0; - kfree(tx_buf); + vfree(tx_buf); break; case WDSP_CMD_PKT: - if (count <= (sizeof(struct wdsp_write_pkt) + - sizeof(struct wdsp_cmd_pkt))) { + if (count <= (WDSP_WRITE_PKT_SIZE + WDSP_CMD_PKT_SIZE)) { dev_err(wpriv->dev, "%s: Invalid cmd pkt size = %zd\n", __func__, count); ret = -EINVAL; @@ -843,10 +866,18 @@ static ssize_t wdsp_glink_write(struct file *file, const char __user *buf, goto free_buf; } mutex_unlock(&wpriv->glink_mutex); - cpkt = (struct wdsp_cmd_pkt *)wpkt->payload; - dev_dbg(wpriv->dev, "%s: requested ch_name: %s\n", __func__, - cpkt->ch_name); + pkt_max_size = sizeof(struct wdsp_write_pkt) + + sizeof(struct wdsp_cmd_pkt) + + cpkt->payload_size; + if (count < pkt_max_size) { + dev_err(wpriv->dev, "%s: Invalid cmd pkt count = %zd, pkt_size = %zd\n", + __func__, count, pkt_max_size); + ret = -EINVAL; + goto free_buf; + } + dev_dbg(wpriv->dev, "%s: requested ch_name: %s, pkt_size: %zd\n", + __func__, cpkt->ch_name, pkt_max_size); for (i = 0; i < wpriv->no_of_channels; i++) { if (wpriv->ch && wpriv->ch[i] && (!strcmp(cpkt->ch_name, @@ -881,13 +912,13 @@ static ssize_t wdsp_glink_write(struct file *file, const char __user *buf, default: dev_err(wpriv->dev, "%s: Invalid packet type\n", __func__); ret = -EINVAL; - kfree(tx_buf); + vfree(tx_buf); break; } goto done; free_buf: - kfree(tx_buf); + vfree(tx_buf); done: return ret; diff --git a/drivers/video/fbdev/msm/mdss_dp.c b/drivers/video/fbdev/msm/mdss_dp.c index 1e878e9a00cb..37346c40d81d 100644 --- a/drivers/video/fbdev/msm/mdss_dp.c +++ b/drivers/video/fbdev/msm/mdss_dp.c @@ -3943,6 +3943,12 @@ static int mdss_dp_process_hpd_irq_high(struct mdss_dp_drv_pdata *dp) { int ret = 0; + /* In case of HPD_IRQ events without DP link being turned on such as + * adb shell stop, skip handling hpd_irq event. + */ + if (!dp->dp_initialized) + goto exit; + pr_debug("start\n"); dp->hpd_irq_on = true; diff --git a/include/soc/qcom/msm_qmi_interface.h b/include/soc/qcom/msm_qmi_interface.h index 5ca808dd1fc2..38f390ee71b7 100644 --- a/include/soc/qcom/msm_qmi_interface.h +++ b/include/soc/qcom/msm_qmi_interface.h @@ -92,7 +92,6 @@ enum qmi_result_type_v01 { QMI_RESULT_TYPE_MIN_ENUM_VAL_V01 = INT_MIN, QMI_RESULT_SUCCESS_V01 = 0, QMI_RESULT_FAILURE_V01 = 1, - QMI_ERR_DISABLED_V01 = 0x45, QMI_RESULT_TYPE_MAX_ENUM_VAL_V01 = INT_MAX, }; @@ -106,6 +105,7 @@ enum qmi_error_type_v01 { QMI_ERR_CLIENT_IDS_EXHAUSTED_V01 = 0x0005, QMI_ERR_INVALID_ID_V01 = 0x0029, QMI_ERR_ENCODING_V01 = 0x003A, + QMI_ERR_DISABLED_V01 = 0x0045, QMI_ERR_INCOMPATIBLE_STATE_V01 = 0x005A, QMI_ERR_NOT_SUPPORTED_V01 = 0x005E, QMI_ERR_TYPE_MAX_ENUM_VAL_V01 = INT_MAX, diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h index 40cd9a752c53..084232a1d06e 100644 --- a/include/sound/apr_audio-v2.h +++ b/include/sound/apr_audio-v2.h @@ -6334,6 +6334,62 @@ struct asm_stream_cmd_get_pp_params_v2 { #define ASM_STREAM_CMD_SET_ENCDEC_PARAM 0x00010C10 +#define ASM_STREAM_CMD_SET_ENCDEC_PARAM_V2 0x00013218 + +struct asm_stream_cmd_set_encdec_param_v2 { + u16 service_id; + /* 0 - ASM_ENCODER_SVC; 1 - ASM_DECODER_SVC */ + + u16 reserved; + + u32 param_id; + /* ID of the parameter. */ + + u32 param_size; + /* + * Data size of this parameter, in bytes. The size is a multiple + * of 4 bytes. + */ +} __packed; + +#define ASM_STREAM_CMD_REGISTER_ENCDEC_EVENTS 0x00013219 + +#define ASM_STREAM_CMD_ENCDEC_EVENTS 0x0001321A + +#define AVS_PARAM_ID_RTIC_SHARED_MEMORY_ADDR 0x00013237 + +struct avs_rtic_shared_mem_addr { + struct apr_hdr hdr; + struct asm_stream_cmd_set_encdec_param_v2 encdec; + u32 shm_buf_addr_lsw; + /* Lower 32 bit of the RTIC shared memory */ + + u32 shm_buf_addr_msw; + /* Upper 32 bit of the RTIC shared memory */ + + u32 buf_size; + /* Size of buffer */ + + u16 shm_buf_mem_pool_id; + /* ADSP_MEMORY_MAP_SHMEM8_4K_POOL */ + + u16 shm_buf_num_regions; + /* number of regions to map */ + + u32 shm_buf_flag; + /* buffer property flag */ + + struct avs_shared_map_region_payload map_region; + /* memory map region*/ +} __packed; + +#define AVS_PARAM_ID_RTIC_EVENT_ACK 0x00013238 + +struct avs_param_rtic_event_ack { + struct apr_hdr hdr; + struct asm_stream_cmd_set_encdec_param_v2 encdec; +} __packed; + #define ASM_PARAM_ID_ENCDEC_BITRATE 0x00010C13 struct asm_bitrate_param { diff --git a/include/sound/q6asm-v2.h b/include/sound/q6asm-v2.h index b2bb8d493839..42dd677610d9 100644 --- a/include/sound/q6asm-v2.h +++ b/include/sound/q6asm-v2.h @@ -619,8 +619,13 @@ int q6asm_get_session_time_legacy(struct audio_client *ac, uint64_t *tstamp); int q6asm_send_audio_effects_params(struct audio_client *ac, char *params, uint32_t params_length); -int q6asm_send_stream_cmd(struct audio_client *ac, uint32_t opcode, - void *param, uint32_t params_length); +int q6asm_send_stream_cmd(struct audio_client *ac, + struct msm_adsp_event_data *data); + +int q6asm_send_ion_fd(struct audio_client *ac, int fd); + +int q6asm_send_rtic_event_ack(struct audio_client *ac, + void *param, uint32_t params_length); /* Client can set the IO mode to either AIO/SIO mode */ int q6asm_set_io_mode(struct audio_client *ac, uint32_t mode); diff --git a/kernel/time/timer.c b/kernel/time/timer.c index 8315d4d72cc3..75ce9cbc313d 100644 --- a/kernel/time/timer.c +++ b/kernel/time/timer.c @@ -151,10 +151,11 @@ static inline struct tvec_base *get_target_base(struct tvec_base *base, static inline void __run_deferrable_timers(void) { - if (time_after_eq(jiffies, tvec_base_deferrable.timer_jiffies)) { - if ((atomic_cmpxchg(&deferrable_pending, 1, 0) && - tick_do_timer_cpu == TICK_DO_TIMER_NONE) || - tick_do_timer_cpu == smp_processor_id()) + if ((atomic_cmpxchg(&deferrable_pending, 1, 0) && + tick_do_timer_cpu == TICK_DO_TIMER_NONE) || + tick_do_timer_cpu == smp_processor_id()) { + if (time_after_eq(jiffies, + tvec_base_deferrable.timer_jiffies)) __run_timers(&tvec_base_deferrable); } } diff --git a/kernel/trace/trace_printk.c b/kernel/trace/trace_printk.c index ad1d6164e946..e82cff5c842c 100644 --- a/kernel/trace/trace_printk.c +++ b/kernel/trace/trace_printk.c @@ -304,7 +304,7 @@ static int t_show(struct seq_file *m, void *v) if (!*fmt) return 0; - seq_printf(m, "0x%lx : \"", *(unsigned long *)fmt); + seq_printf(m, "0x%lx : \"", 0L); /* * Tabs and new lines need to be converted. diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 566bcb04ea51..8f3e787501f1 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -775,7 +775,7 @@ config SND_SOC_WCD_DSP_MGR tristate config SND_SOC_WCD_SPI - depends on CONFIG_SPI + depends on SPI tristate config SND_SOC_WL1273 diff --git a/sound/soc/msm/qdsp6v2/Makefile b/sound/soc/msm/qdsp6v2/Makefile index 24672f4da788..219892a85da2 100644 --- a/sound/soc/msm/qdsp6v2/Makefile +++ b/sound/soc/msm/qdsp6v2/Makefile @@ -1,5 +1,5 @@ snd-soc-qdsp6v2-objs += msm-dai-q6-v2.o msm-pcm-q6-v2.o msm-pcm-routing-v2.o \ - msm-compress-q6-v2.o msm-compr-q6-v2.o \ + msm-compress-q6-v2.o \ msm-pcm-afe-v2.o msm-pcm-voip-v2.o \ msm-pcm-voice-v2.o msm-dai-q6-hdmi-v2.o \ msm-lsm-client.o msm-pcm-host-voice-v2.o \ diff --git a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c deleted file mode 100644 index 58a4de5af145..000000000000 --- a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c +++ /dev/null @@ -1,1694 +0,0 @@ -/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - - -#include <linux/init.h> -#include <linux/err.h> -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/time.h> -#include <linux/wait.h> -#include <linux/platform_device.h> -#include <linux/slab.h> -#include <sound/core.h> -#include <sound/soc.h> -#include <sound/soc-dapm.h> -#include <sound/pcm.h> -#include <sound/initval.h> -#include <sound/control.h> -#include <sound/q6asm-v2.h> -#include <sound/pcm_params.h> -#include <asm/dma.h> -#include <linux/dma-mapping.h> -#include <linux/msm_audio_ion.h> - -#include <sound/timer.h> - -#include "msm-compr-q6-v2.h" -#include "msm-pcm-routing-v2.h" -#include <sound/tlv.h> - -#define COMPRE_CAPTURE_NUM_PERIODS 16 -/* Allocate the worst case frame size for compressed audio */ -#define COMPRE_CAPTURE_HEADER_SIZE (sizeof(struct snd_compr_audio_info)) -/* Changing period size to 4032. 4032 will make sure COMPRE_CAPTURE_PERIOD_SIZE - * is 4096 with meta data size of 64 and MAX_NUM_FRAMES_PER_BUFFER 1 - */ -#define COMPRE_CAPTURE_MAX_FRAME_SIZE (4032) -#define COMPRE_CAPTURE_PERIOD_SIZE ((COMPRE_CAPTURE_MAX_FRAME_SIZE + \ - COMPRE_CAPTURE_HEADER_SIZE) * \ - MAX_NUM_FRAMES_PER_BUFFER) -#define COMPRE_OUTPUT_METADATA_SIZE (sizeof(struct output_meta_data_st)) -#define COMPRESSED_LR_VOL_MAX_STEPS 0x20002000 - -#define MAX_AC3_PARAM_SIZE (18*2*sizeof(int)) -#define AMR_WB_BAND_MODE 8 -#define AMR_WB_DTX_MODE 0 - - -const DECLARE_TLV_DB_LINEAR(compr_rx_vol_gain, 0, - COMPRESSED_LR_VOL_MAX_STEPS); - -static struct audio_locks the_locks; - -static struct snd_pcm_hardware msm_compr_hardware_capture = { - .info = (SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME), - .formats = SNDRV_PCM_FMTBIT_S16_LE, - .rates = SNDRV_PCM_RATE_8000_48000, - .rate_min = 8000, - .rate_max = 48000, - .channels_min = 1, - .channels_max = 8, - .buffer_bytes_max = - COMPRE_CAPTURE_PERIOD_SIZE * COMPRE_CAPTURE_NUM_PERIODS , - .period_bytes_min = COMPRE_CAPTURE_PERIOD_SIZE, - .period_bytes_max = COMPRE_CAPTURE_PERIOD_SIZE, - .periods_min = COMPRE_CAPTURE_NUM_PERIODS, - .periods_max = COMPRE_CAPTURE_NUM_PERIODS, - .fifo_size = 0, -}; - -static struct snd_pcm_hardware msm_compr_hardware_playback = { - .info = (SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME), - .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, - .rates = SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_KNOT, - .rate_min = 8000, - .rate_max = 48000, - .channels_min = 1, - .channels_max = 8, - .buffer_bytes_max = 1024 * 1024, - .period_bytes_min = 128 * 1024, - .period_bytes_max = 256 * 1024, - .periods_min = 4, - .periods_max = 8, - .fifo_size = 0, -}; - -/* Conventional and unconventional sample rate supported */ -static unsigned int supported_sample_rates[] = { - 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000 -}; - -/* Add supported codecs for compress capture path */ -static uint32_t supported_compr_capture_codecs[] = { - SND_AUDIOCODEC_AMRWB -}; - -static struct snd_pcm_hw_constraint_list constraints_sample_rates = { - .count = ARRAY_SIZE(supported_sample_rates), - .list = supported_sample_rates, - .mask = 0, -}; - -static bool msm_compr_capture_codecs(uint32_t req_codec) -{ - int i; - pr_debug("%s req_codec:%d\n", __func__, req_codec); - if (req_codec == 0) - return false; - for (i = 0; i < ARRAY_SIZE(supported_compr_capture_codecs); i++) { - if (req_codec == supported_compr_capture_codecs[i]) - return true; - } - return false; -} - -static void compr_event_handler(uint32_t opcode, - uint32_t token, uint32_t *payload, void *priv) -{ - struct compr_audio *compr = priv; - struct msm_audio *prtd = &compr->prtd; - struct snd_pcm_substream *substream = prtd->substream; - struct snd_pcm_runtime *runtime = substream->runtime; - struct audio_aio_write_param param; - struct audio_aio_read_param read_param; - struct audio_buffer *buf = NULL; - phys_addr_t temp; - struct output_meta_data_st output_meta_data; - uint32_t *ptrmem = (uint32_t *)payload; - int i = 0; - int time_stamp_flag = 0; - int buffer_length = 0; - int stop_playback = 0; - - pr_debug("%s opcode =%08x\n", __func__, opcode); - switch (opcode) { - case ASM_DATA_EVENT_WRITE_DONE_V2: { - uint32_t *ptrmem = (uint32_t *)¶m; - pr_debug("ASM_DATA_EVENT_WRITE_DONE\n"); - pr_debug("Buffer Consumed = 0x%08x\n", *ptrmem); - prtd->pcm_irq_pos += prtd->pcm_count; - if (atomic_read(&prtd->start)) - snd_pcm_period_elapsed(substream); - else - if (substream->timer_running) - snd_timer_interrupt(substream->timer, 1); - atomic_inc(&prtd->out_count); - wake_up(&the_locks.write_wait); - if (!atomic_read(&prtd->start)) { - atomic_set(&prtd->pending_buffer, 1); - break; - } else - atomic_set(&prtd->pending_buffer, 0); - - /* - * check for underrun - */ - snd_pcm_stream_lock_irq(substream); - if (runtime->status->hw_ptr >= runtime->control->appl_ptr) { - runtime->render_flag |= SNDRV_RENDER_STOPPED; - stop_playback = 1; - } - snd_pcm_stream_unlock_irq(substream); - - if (stop_playback) { - pr_err("underrun! render stopped\n"); - break; - } - - buf = prtd->audio_client->port[IN].buf; - pr_debug("%s:writing %d bytes of buffer[%d] to dsp 2\n", - __func__, prtd->pcm_count, prtd->out_head); - temp = buf[0].phys + (prtd->out_head * prtd->pcm_count); - pr_debug("%s:writing buffer[%d] from 0x%pK\n", - __func__, prtd->out_head, &temp); - - if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) - time_stamp_flag = SET_TIMESTAMP; - else - time_stamp_flag = NO_TIMESTAMP; - memcpy(&output_meta_data, (char *)(buf->data + - prtd->out_head * prtd->pcm_count), - COMPRE_OUTPUT_METADATA_SIZE); - - buffer_length = output_meta_data.frame_size; - pr_debug("meta_data_length: %d, frame_length: %d\n", - output_meta_data.meta_data_length, - output_meta_data.frame_size); - pr_debug("timestamp_msw: %d, timestamp_lsw: %d\n", - output_meta_data.timestamp_msw, - output_meta_data.timestamp_lsw); - if (buffer_length == 0) { - pr_debug("Recieved a zero length buffer-break out"); - break; - } - param.paddr = temp + output_meta_data.meta_data_length; - param.len = buffer_length; - param.msw_ts = output_meta_data.timestamp_msw; - param.lsw_ts = output_meta_data.timestamp_lsw; - param.flags = time_stamp_flag; - param.uid = prtd->session_id; - for (i = 0; i < sizeof(struct audio_aio_write_param)/4; - i++, ++ptrmem) - pr_debug("cmd[%d]=0x%08x\n", i, *ptrmem); - if (q6asm_async_write(prtd->audio_client, - ¶m) < 0) - pr_err("%s:q6asm_async_write failed\n", - __func__); - else - prtd->out_head = - (prtd->out_head + 1) & (runtime->periods - 1); - break; - } - case ASM_DATA_EVENT_RENDERED_EOS: - pr_debug("ASM_DATA_CMDRSP_EOS\n"); - if (atomic_read(&prtd->eos)) { - pr_debug("ASM_DATA_CMDRSP_EOS wake up\n"); - prtd->cmd_ack = 1; - wake_up(&the_locks.eos_wait); - atomic_set(&prtd->eos, 0); - } - break; - case ASM_DATA_EVENT_READ_DONE_V2: { - pr_debug("ASM_DATA_EVENT_READ_DONE\n"); - pr_debug("buf = %pK, data = 0x%X, *data = %pK,\n" - "prtd->pcm_irq_pos = %d\n", - prtd->audio_client->port[OUT].buf, - *(uint32_t *)prtd->audio_client->port[OUT].buf->data, - prtd->audio_client->port[OUT].buf->data, - prtd->pcm_irq_pos); - - memcpy(prtd->audio_client->port[OUT].buf->data + - prtd->pcm_irq_pos, (ptrmem + READDONE_IDX_SIZE), - COMPRE_CAPTURE_HEADER_SIZE); - pr_debug("buf = %pK, updated data = 0x%X, *data = %pK\n", - prtd->audio_client->port[OUT].buf, - *(uint32_t *)(prtd->audio_client->port[OUT].buf->data + - prtd->pcm_irq_pos), - prtd->audio_client->port[OUT].buf->data); - if (!atomic_read(&prtd->start)) - break; - pr_debug("frame size=%d, buffer = 0x%X\n", - ptrmem[READDONE_IDX_SIZE], - ptrmem[READDONE_IDX_BUFADD_LSW]); - if (ptrmem[READDONE_IDX_SIZE] > COMPRE_CAPTURE_MAX_FRAME_SIZE) { - pr_err("Frame length exceeded the max length"); - break; - } - buf = prtd->audio_client->port[OUT].buf; - - pr_debug("pcm_irq_pos=%d, buf[0].phys = 0x%pK\n", - prtd->pcm_irq_pos, &buf[0].phys); - read_param.len = prtd->pcm_count - COMPRE_CAPTURE_HEADER_SIZE; - read_param.paddr = buf[0].phys + - prtd->pcm_irq_pos + COMPRE_CAPTURE_HEADER_SIZE; - prtd->pcm_irq_pos += prtd->pcm_count; - - if (atomic_read(&prtd->start)) - snd_pcm_period_elapsed(substream); - - q6asm_async_read(prtd->audio_client, &read_param); - break; - } - case APR_BASIC_RSP_RESULT: { - switch (payload[0]) { - case ASM_SESSION_CMD_RUN_V2: { - if (substream->stream - != SNDRV_PCM_STREAM_PLAYBACK) { - atomic_set(&prtd->start, 1); - break; - } - if (!atomic_read(&prtd->pending_buffer)) - break; - pr_debug("%s: writing %d bytes of buffer[%d] to dsp\n", - __func__, prtd->pcm_count, prtd->out_head); - buf = prtd->audio_client->port[IN].buf; - pr_debug("%s: writing buffer[%d] from 0x%pK head %d count %d\n", - __func__, prtd->out_head, &buf[0].phys, - prtd->pcm_count, prtd->out_head); - if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) - time_stamp_flag = SET_TIMESTAMP; - else - time_stamp_flag = NO_TIMESTAMP; - memcpy(&output_meta_data, (char *)(buf->data + - prtd->out_head * prtd->pcm_count), - COMPRE_OUTPUT_METADATA_SIZE); - buffer_length = output_meta_data.frame_size; - pr_debug("meta_data_length: %d, frame_length: %d\n", - output_meta_data.meta_data_length, - output_meta_data.frame_size); - pr_debug("timestamp_msw: %d, timestamp_lsw: %d\n", - output_meta_data.timestamp_msw, - output_meta_data.timestamp_lsw); - param.paddr = buf[prtd->out_head].phys - + output_meta_data.meta_data_length; - param.len = buffer_length; - param.msw_ts = output_meta_data.timestamp_msw; - param.lsw_ts = output_meta_data.timestamp_lsw; - param.flags = time_stamp_flag; - param.uid = prtd->session_id; - param.metadata_len = COMPRE_OUTPUT_METADATA_SIZE; - if (q6asm_async_write(prtd->audio_client, - ¶m) < 0) - pr_err("%s:q6asm_async_write failed\n", - __func__); - else - prtd->out_head = - (prtd->out_head + 1) - & (runtime->periods - 1); - atomic_set(&prtd->pending_buffer, 0); - } - break; - case ASM_STREAM_CMD_FLUSH: - pr_debug("ASM_STREAM_CMD_FLUSH\n"); - prtd->cmd_ack = 1; - wake_up(&the_locks.flush_wait); - break; - default: - break; - } - break; - } - default: - pr_debug("Not Supported Event opcode[0x%x]\n", opcode); - break; - } -} - -static int msm_compr_send_ddp_cfg(struct audio_client *ac, - struct snd_dec_ddp *ddp) -{ - int i, rc; - pr_debug("%s\n", __func__); - - if (ddp->params_length / 2 > SND_DEC_DDP_MAX_PARAMS) { - pr_err("%s: Invalid number of params %u, max allowed %u\n", - __func__, ddp->params_length / 2, - SND_DEC_DDP_MAX_PARAMS); - return -EINVAL; - } - - for (i = 0; i < ddp->params_length/2; i++) { - rc = q6asm_ds1_set_endp_params(ac, ddp->params_id[i], - ddp->params_value[i]); - if (rc) { - pr_err("sending params_id: %d failed\n", - ddp->params_id[i]); - return rc; - } - } - return 0; -} - -static int msm_compr_playback_prepare(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct compr_audio *compr = runtime->private_data; - struct snd_soc_pcm_runtime *soc_prtd = substream->private_data; - struct msm_audio *prtd = &compr->prtd; - struct snd_pcm_hw_params *params; - struct asm_aac_cfg aac_cfg; - uint16_t bits_per_sample = 16; - int ret; - - struct asm_softpause_params softpause = { - .enable = SOFT_PAUSE_ENABLE, - .period = SOFT_PAUSE_PERIOD, - .step = SOFT_PAUSE_STEP, - .rampingcurve = SOFT_PAUSE_CURVE_LINEAR, - }; - struct asm_softvolume_params softvol = { - .period = SOFT_VOLUME_PERIOD, - .step = SOFT_VOLUME_STEP, - .rampingcurve = SOFT_VOLUME_CURVE_LINEAR, - }; - - pr_debug("%s\n", __func__); - - params = &soc_prtd->dpcm[substream->stream].hw_params; - if (runtime->format == SNDRV_PCM_FORMAT_S24_LE) - bits_per_sample = 24; - - ret = q6asm_open_write_v2(prtd->audio_client, - compr->codec, bits_per_sample); - if (ret < 0) { - pr_err("%s: Session out open failed\n", - __func__); - return -ENOMEM; - } - msm_pcm_routing_reg_phy_stream( - soc_prtd->dai_link->be_id, - prtd->audio_client->perf_mode, - prtd->session_id, - substream->stream); - /* - * the number of channels are required to call volume api - * accoridngly. So, get channels from hw params - */ - if ((params_channels(params) > 0) && - (params_periods(params) <= runtime->hw.channels_max)) - prtd->channel_mode = params_channels(params); - - ret = q6asm_set_softpause(prtd->audio_client, &softpause); - if (ret < 0) - pr_err("%s: Send SoftPause Param failed ret=%d\n", - __func__, ret); - ret = q6asm_set_softvolume(prtd->audio_client, &softvol); - if (ret < 0) - pr_err("%s: Send SoftVolume Param failed ret=%d\n", - __func__, ret); - - ret = q6asm_set_io_mode(prtd->audio_client, - (COMPRESSED_IO | ASYNC_IO_MODE)); - if (ret < 0) { - pr_err("%s: Set IO mode failed\n", __func__); - return -ENOMEM; - } - - prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream); - prtd->pcm_count = snd_pcm_lib_period_bytes(substream); - prtd->pcm_irq_pos = 0; - /* rate and channels are sent to audio driver */ - prtd->samp_rate = runtime->rate; - prtd->channel_mode = runtime->channels; - prtd->out_head = 0; - atomic_set(&prtd->out_count, runtime->periods); - - if (prtd->enabled) - return 0; - - switch (compr->info.codec_param.codec.id) { - case SND_AUDIOCODEC_MP3: - /* No media format block for mp3 */ - break; - case SND_AUDIOCODEC_AAC: - pr_debug("%s: SND_AUDIOCODEC_AAC\n", __func__); - memset(&aac_cfg, 0x0, sizeof(struct asm_aac_cfg)); - aac_cfg.aot = AAC_ENC_MODE_EAAC_P; - aac_cfg.format = 0x03; - aac_cfg.ch_cfg = runtime->channels; - aac_cfg.sample_rate = runtime->rate; - ret = q6asm_media_format_block_aac(prtd->audio_client, - &aac_cfg); - if (ret < 0) - pr_err("%s: CMD Format block failed\n", __func__); - break; - case SND_AUDIOCODEC_AC3: { - struct snd_dec_ddp *ddp = - &compr->info.codec_param.codec.options.ddp; - pr_debug("%s: SND_AUDIOCODEC_AC3\n", __func__); - ret = msm_compr_send_ddp_cfg(prtd->audio_client, ddp); - if (ret < 0) - pr_err("%s: DDP CMD CFG failed\n", __func__); - break; - } - case SND_AUDIOCODEC_EAC3: { - struct snd_dec_ddp *ddp = - &compr->info.codec_param.codec.options.ddp; - pr_debug("%s: SND_AUDIOCODEC_EAC3\n", __func__); - ret = msm_compr_send_ddp_cfg(prtd->audio_client, ddp); - if (ret < 0) - pr_err("%s: DDP CMD CFG failed\n", __func__); - break; - } - default: - return -EINVAL; - } - - prtd->enabled = 1; - prtd->cmd_ack = 0; - prtd->cmd_interrupt = 0; - - return 0; -} - -static int msm_compr_capture_prepare(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct compr_audio *compr = runtime->private_data; - struct msm_audio *prtd = &compr->prtd; - struct audio_buffer *buf = prtd->audio_client->port[OUT].buf; - struct snd_codec *codec = &compr->info.codec_param.codec; - struct snd_soc_pcm_runtime *soc_prtd = substream->private_data; - struct audio_aio_read_param read_param; - uint16_t bits_per_sample = 16; - int ret = 0; - int i; - - prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream); - prtd->pcm_count = snd_pcm_lib_period_bytes(substream); - prtd->pcm_irq_pos = 0; - - if (runtime->format == SNDRV_PCM_FORMAT_S24_LE) - bits_per_sample = 24; - - if (!msm_compr_capture_codecs( - compr->info.codec_param.codec.id)) { - /* - * request codec invalid or not supported, - * use default compress format - */ - compr->info.codec_param.codec.id = - SND_AUDIOCODEC_AMRWB; - } - switch (compr->info.codec_param.codec.id) { - case SND_AUDIOCODEC_AMRWB: - pr_debug("q6asm_open_read(FORMAT_AMRWB)\n"); - ret = q6asm_open_read(prtd->audio_client, - FORMAT_AMRWB); - if (ret < 0) { - pr_err("%s: compressed Session out open failed\n", - __func__); - return -ENOMEM; - } - pr_debug("msm_pcm_routing_reg_phy_stream\n"); - msm_pcm_routing_reg_phy_stream( - soc_prtd->dai_link->be_id, - prtd->audio_client->perf_mode, - prtd->session_id, substream->stream); - break; - default: - pr_debug("q6asm_open_read_compressed(COMPRESSED_META_DATA_MODE)\n"); - /* - ret = q6asm_open_read_compressed(prtd->audio_client, - MAX_NUM_FRAMES_PER_BUFFER, - COMPRESSED_META_DATA_MODE); - */ - ret = -EINVAL; - break; - } - - if (ret < 0) { - pr_err("%s: compressed Session out open failed\n", - __func__); - return -ENOMEM; - } - - ret = q6asm_set_io_mode(prtd->audio_client, - (COMPRESSED_IO | ASYNC_IO_MODE)); - if (ret < 0) { - pr_err("%s: Set IO mode failed\n", __func__); - return -ENOMEM; - } - - if (!msm_compr_capture_codecs(codec->id)) { - /* - * request codec invalid or not supported, - * use default compress format - */ - codec->id = SND_AUDIOCODEC_AMRWB; - } - /* rate and channels are sent to audio driver */ - prtd->samp_rate = runtime->rate; - prtd->channel_mode = runtime->channels; - - if (prtd->enabled) - return ret; - read_param.len = prtd->pcm_count; - - switch (codec->id) { - case SND_AUDIOCODEC_AMRWB: - pr_debug("SND_AUDIOCODEC_AMRWB\n"); - ret = q6asm_enc_cfg_blk_amrwb(prtd->audio_client, - MAX_NUM_FRAMES_PER_BUFFER, - /* - * use fixed band mode and dtx mode - * band mode - 23.85 kbps - */ - AMR_WB_BAND_MODE, - /* dtx mode - disable */ - AMR_WB_DTX_MODE); - if (ret < 0) - pr_err("%s: CMD Format block failed: %d\n", - __func__, ret); - break; - default: - pr_debug("No config for codec %d\n", codec->id); - } - pr_debug("%s: Samp_rate = %d, Channel = %d, pcm_size = %d,\n" - "pcm_count = %d, periods = %d\n", - __func__, prtd->samp_rate, prtd->channel_mode, - prtd->pcm_size, prtd->pcm_count, runtime->periods); - - for (i = 0; i < runtime->periods; i++) { - read_param.uid = i; - switch (codec->id) { - case SND_AUDIOCODEC_AMRWB: - read_param.len = prtd->pcm_count - - COMPRE_CAPTURE_HEADER_SIZE; - read_param.paddr = buf[i].phys - + COMPRE_CAPTURE_HEADER_SIZE; - pr_debug("Push buffer [%d] to DSP, paddr: %pK, vaddr: %pK\n", - i, &read_param.paddr, - buf[i].data); - q6asm_async_read(prtd->audio_client, &read_param); - break; - default: - read_param.paddr = buf[i].phys; - /*q6asm_async_read_compressed(prtd->audio_client, - &read_param);*/ - pr_debug("%s: To add support for read compressed\n", - __func__); - ret = -EINVAL; - break; - } - } - prtd->periods = runtime->periods; - - prtd->enabled = 1; - - return ret; -} - -static int msm_compr_trigger(struct snd_pcm_substream *substream, int cmd) -{ - int ret = 0; - struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_soc_pcm_runtime *soc_prtd = substream->private_data; - struct compr_audio *compr = runtime->private_data; - struct msm_audio *prtd = &compr->prtd; - - pr_debug("%s\n", __func__); - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - prtd->pcm_irq_pos = 0; - - if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { - if (!msm_compr_capture_codecs( - compr->info.codec_param.codec.id)) { - /* - * request codec invalid or not supported, - * use default compress format - */ - compr->info.codec_param.codec.id = - SND_AUDIOCODEC_AMRWB; - } - switch (compr->info.codec_param.codec.id) { - case SND_AUDIOCODEC_AMRWB: - break; - default: - msm_pcm_routing_reg_psthr_stream( - soc_prtd->dai_link->be_id, - prtd->session_id, substream->stream); - break; - } - } - atomic_set(&prtd->pending_buffer, 1); - case SNDRV_PCM_TRIGGER_RESUME: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - pr_debug("%s: Trigger start\n", __func__); - q6asm_run_nowait(prtd->audio_client, 0, 0, 0); - atomic_set(&prtd->start, 1); - break; - case SNDRV_PCM_TRIGGER_STOP: - pr_debug("SNDRV_PCM_TRIGGER_STOP\n"); - if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { - switch (compr->info.codec_param.codec.id) { - case SND_AUDIOCODEC_AMRWB: - break; - default: - msm_pcm_routing_reg_psthr_stream( - soc_prtd->dai_link->be_id, - prtd->session_id, substream->stream); - break; - } - } - atomic_set(&prtd->start, 0); - runtime->render_flag &= ~SNDRV_RENDER_STOPPED; - break; - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - pr_debug("SNDRV_PCM_TRIGGER_PAUSE\n"); - q6asm_cmd_nowait(prtd->audio_client, CMD_PAUSE); - atomic_set(&prtd->start, 0); - runtime->render_flag &= ~SNDRV_RENDER_STOPPED; - break; - default: - ret = -EINVAL; - break; - } - - return ret; -} - -static void populate_codec_list(struct compr_audio *compr, - struct snd_pcm_runtime *runtime) -{ - pr_debug("%s\n", __func__); - /* MP3 Block */ - compr->info.compr_cap.num_codecs = 5; - compr->info.compr_cap.min_fragment_size = runtime->hw.period_bytes_min; - compr->info.compr_cap.max_fragment_size = runtime->hw.period_bytes_max; - compr->info.compr_cap.min_fragments = runtime->hw.periods_min; - compr->info.compr_cap.max_fragments = runtime->hw.periods_max; - compr->info.compr_cap.codecs[0] = SND_AUDIOCODEC_MP3; - compr->info.compr_cap.codecs[1] = SND_AUDIOCODEC_AAC; - compr->info.compr_cap.codecs[2] = SND_AUDIOCODEC_AC3; - compr->info.compr_cap.codecs[3] = SND_AUDIOCODEC_EAC3; - compr->info.compr_cap.codecs[4] = SND_AUDIOCODEC_AMRWB; - /* Add new codecs here */ -} - -static int msm_compr_open(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct compr_audio *compr; - struct msm_audio *prtd; - int ret = 0; - - pr_debug("%s\n", __func__); - compr = kzalloc(sizeof(struct compr_audio), GFP_KERNEL); - if (compr == NULL) { - pr_err("Failed to allocate memory for msm_audio\n"); - return -ENOMEM; - } - prtd = &compr->prtd; - prtd->substream = substream; - runtime->render_flag = SNDRV_DMA_MODE; - prtd->audio_client = q6asm_audio_client_alloc( - (app_cb)compr_event_handler, compr); - if (!prtd->audio_client) { - pr_info("%s: Could not allocate memory\n", __func__); - kfree(prtd); - return -ENOMEM; - } - - prtd->audio_client->perf_mode = false; - pr_info("%s: session ID %d\n", __func__, prtd->audio_client->session); - - prtd->session_id = prtd->audio_client->session; - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - runtime->hw = msm_compr_hardware_playback; - prtd->cmd_ack = 1; - } else { - runtime->hw = msm_compr_hardware_capture; - } - - - ret = snd_pcm_hw_constraint_list(runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, - &constraints_sample_rates); - if (ret < 0) - pr_info("snd_pcm_hw_constraint_list failed\n"); - /* Ensure that buffer size is a multiple of period size */ - ret = snd_pcm_hw_constraint_integer(runtime, - SNDRV_PCM_HW_PARAM_PERIODS); - if (ret < 0) - pr_info("snd_pcm_hw_constraint_integer failed\n"); - - prtd->dsp_cnt = 0; - atomic_set(&prtd->pending_buffer, 1); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - compr->codec = FORMAT_MP3; - populate_codec_list(compr, runtime); - runtime->private_data = compr; - atomic_set(&prtd->eos, 0); - return 0; -} - -static int compressed_set_volume(struct msm_audio *prtd, uint32_t volume) -{ - int rc = 0; - int avg_vol = 0; - int lgain = (volume >> 16) & 0xFFFF; - int rgain = volume & 0xFFFF; - if (prtd && prtd->audio_client) { - pr_debug("%s: channels %d volume 0x%x\n", __func__, - prtd->channel_mode, volume); - if ((prtd->channel_mode == 2) && - (lgain != rgain)) { - pr_debug("%s: call q6asm_set_lrgain\n", __func__); - rc = q6asm_set_lrgain(prtd->audio_client, lgain, rgain); - } else { - avg_vol = (lgain + rgain)/2; - pr_debug("%s: call q6asm_set_volume\n", __func__); - rc = q6asm_set_volume(prtd->audio_client, avg_vol); - } - if (rc < 0) { - pr_err("%s: Send Volume command failed rc=%d\n", - __func__, rc); - } - } - return rc; -} - -static int msm_compr_playback_close(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_soc_pcm_runtime *soc_prtd = substream->private_data; - struct compr_audio *compr = runtime->private_data; - struct msm_audio *prtd = &compr->prtd; - int dir = 0; - - pr_debug("%s\n", __func__); - - dir = IN; - atomic_set(&prtd->pending_buffer, 0); - - prtd->pcm_irq_pos = 0; - q6asm_cmd(prtd->audio_client, CMD_CLOSE); - q6asm_audio_client_buf_free_contiguous(dir, - prtd->audio_client); - msm_pcm_routing_dereg_phy_stream( - soc_prtd->dai_link->be_id, - SNDRV_PCM_STREAM_PLAYBACK); - q6asm_audio_client_free(prtd->audio_client); - kfree(prtd); - return 0; -} - -static int msm_compr_capture_close(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_soc_pcm_runtime *soc_prtd = substream->private_data; - struct compr_audio *compr = runtime->private_data; - struct msm_audio *prtd = &compr->prtd; - int dir = OUT; - - pr_debug("%s\n", __func__); - atomic_set(&prtd->pending_buffer, 0); - q6asm_cmd(prtd->audio_client, CMD_CLOSE); - q6asm_audio_client_buf_free_contiguous(dir, - prtd->audio_client); - msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->be_id, - SNDRV_PCM_STREAM_CAPTURE); - q6asm_audio_client_free(prtd->audio_client); - kfree(prtd); - return 0; -} - -static int msm_compr_close(struct snd_pcm_substream *substream) -{ - int ret = 0; - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - ret = msm_compr_playback_close(substream); - else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) - ret = msm_compr_capture_close(substream); - return ret; -} - -static int msm_compr_prepare(struct snd_pcm_substream *substream) -{ - int ret = 0; - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - ret = msm_compr_playback_prepare(substream); - else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) - ret = msm_compr_capture_prepare(substream); - return ret; -} - -static snd_pcm_uframes_t msm_compr_pointer(struct snd_pcm_substream *substream) -{ - - struct snd_pcm_runtime *runtime = substream->runtime; - struct compr_audio *compr = runtime->private_data; - struct msm_audio *prtd = &compr->prtd; - - if (prtd->pcm_irq_pos >= prtd->pcm_size) - prtd->pcm_irq_pos = 0; - - pr_debug("%s: pcm_irq_pos = %d, pcm_size = %d, sample_bits = %d,\n" - "frame_bits = %d\n", __func__, prtd->pcm_irq_pos, - prtd->pcm_size, runtime->sample_bits, - runtime->frame_bits); - return bytes_to_frames(runtime, (prtd->pcm_irq_pos)); -} - -static int msm_compr_mmap(struct snd_pcm_substream *substream, - struct vm_area_struct *vma) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct msm_audio *prtd = runtime->private_data; - struct audio_client *ac = prtd->audio_client; - struct audio_port_data *apd = ac->port; - struct audio_buffer *ab; - int dir = -1; - - prtd->mmap_flag = 1; - runtime->render_flag = SNDRV_NON_DMA_MODE; - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - dir = IN; - else - dir = OUT; - ab = &(apd[dir].buf[0]); - - return msm_audio_ion_mmap(ab, vma); -} - -static int msm_compr_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct compr_audio *compr = runtime->private_data; - struct msm_audio *prtd = &compr->prtd; - struct snd_dma_buffer *dma_buf = &substream->dma_buffer; - struct audio_buffer *buf; - int dir, ret; - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - dir = IN; - else - dir = OUT; - /* Modifying kernel hardware params based on userspace config */ - if (params_periods(params) > 0 && - (params_periods(params) != runtime->hw.periods_max)) { - runtime->hw.periods_max = params_periods(params); - } - if (params_period_bytes(params) > 0 && - (params_period_bytes(params) != runtime->hw.period_bytes_min)) { - runtime->hw.period_bytes_min = params_period_bytes(params); - } - runtime->hw.buffer_bytes_max = - runtime->hw.period_bytes_min * runtime->hw.periods_max; - pr_debug("allocate %zd buffers each of size %d\n", - runtime->hw.period_bytes_min, - runtime->hw.periods_max); - ret = q6asm_audio_client_buf_alloc_contiguous(dir, - prtd->audio_client, - runtime->hw.period_bytes_min, - runtime->hw.periods_max); - if (ret < 0) { - pr_err("Audio Start: Buffer Allocation failed rc = %d\n", - ret); - return -ENOMEM; - } - buf = prtd->audio_client->port[dir].buf; - - dma_buf->dev.type = SNDRV_DMA_TYPE_DEV; - dma_buf->dev.dev = substream->pcm->card->dev; - dma_buf->private_data = NULL; - dma_buf->area = buf[0].data; - dma_buf->addr = buf[0].phys; - dma_buf->bytes = runtime->hw.buffer_bytes_max; - - pr_debug("%s: buf[%pK]dma_buf->area[%pK]dma_buf->addr[%pK]\n" - "dma_buf->bytes[%zd]\n", __func__, - (void *)buf, (void *)dma_buf->area, - &dma_buf->addr, dma_buf->bytes); - if (!dma_buf->area) - return -ENOMEM; - - snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); - return 0; -} - -static int msm_compr_ioctl_shared(struct snd_pcm_substream *substream, - unsigned int cmd, void *arg) -{ - int rc = 0; - struct snd_pcm_runtime *runtime = substream->runtime; - struct compr_audio *compr = runtime->private_data; - struct msm_audio *prtd = &compr->prtd; - uint64_t timestamp; - uint64_t temp; - - switch (cmd) { - case SNDRV_COMPRESS_TSTAMP: { - struct snd_compr_tstamp *tstamp; - pr_debug("SNDRV_COMPRESS_TSTAMP\n"); - tstamp = arg; - memset(tstamp, 0x0, sizeof(*tstamp)); - rc = q6asm_get_session_time(prtd->audio_client, ×tamp); - if (rc < 0) { - pr_err("%s: Get Session Time return value =%lld\n", - __func__, timestamp); - return -EAGAIN; - } - temp = (timestamp * 2 * runtime->channels); - temp = temp * (runtime->rate/1000); - temp = div_u64(temp, 1000); - tstamp->sampling_rate = runtime->rate; - tstamp->timestamp = timestamp; - pr_debug("%s: bytes_consumed:,timestamp = %lld,\n", - __func__, - tstamp->timestamp); - return 0; - } - case SNDRV_COMPRESS_GET_CAPS: { - struct snd_compr_caps *caps; - caps = arg; - memset(caps, 0, sizeof(*caps)); - pr_debug("SNDRV_COMPRESS_GET_CAPS\n"); - memcpy(caps, &compr->info.compr_cap, sizeof(*caps)); - return 0; - } - case SNDRV_COMPRESS_SET_PARAMS: - pr_debug("SNDRV_COMPRESS_SET_PARAMS:\n"); - memcpy(&compr->info.codec_param, (void *) arg, - sizeof(struct snd_compr_params)); - switch (compr->info.codec_param.codec.id) { - case SND_AUDIOCODEC_MP3: - /* For MP3 we dont need any other parameter */ - pr_debug("SND_AUDIOCODEC_MP3\n"); - compr->codec = FORMAT_MP3; - break; - case SND_AUDIOCODEC_AAC: - pr_debug("SND_AUDIOCODEC_AAC\n"); - compr->codec = FORMAT_MPEG4_AAC; - break; - case SND_AUDIOCODEC_AC3: { - char params_value[MAX_AC3_PARAM_SIZE]; - int *params_value_data = (int *)params_value; - /* 36 is the max param length for ddp */ - int i; - struct snd_dec_ddp *ddp = - &compr->info.codec_param.codec.options.ddp; - uint32_t params_length = 0; - memset(params_value, 0, MAX_AC3_PARAM_SIZE); - /* check integer overflow */ - if (ddp->params_length > UINT_MAX/sizeof(int)) { - pr_err("%s: Integer overflow ddp->params_length %d\n", - __func__, ddp->params_length); - return -EINVAL; - } - params_length = ddp->params_length*sizeof(int); - if (params_length > MAX_AC3_PARAM_SIZE) { - /*MAX is 36*sizeof(int) this should not happen*/ - pr_err("%s: params_length(%d) is greater than %zd\n", - __func__, params_length, MAX_AC3_PARAM_SIZE); - return -EINVAL; - } - pr_debug("SND_AUDIOCODEC_AC3\n"); - compr->codec = FORMAT_AC3; - pr_debug("params_length: %d\n", ddp->params_length); - for (i = 0; i < params_length/sizeof(int); i++) - pr_debug("params_value[%d]: %x\n", i, - params_value_data[i]); - for (i = 0; i < ddp->params_length/2; i++) { - ddp->params_id[i] = params_value_data[2*i]; - ddp->params_value[i] = params_value_data[2*i+1]; - } - if (atomic_read(&prtd->start)) { - rc = msm_compr_send_ddp_cfg(prtd->audio_client, - ddp); - if (rc < 0) - pr_err("%s: DDP CMD CFG failed\n", - __func__); - } - break; - } - case SND_AUDIOCODEC_EAC3: { - char params_value[MAX_AC3_PARAM_SIZE]; - int *params_value_data = (int *)params_value; - /* 36 is the max param length for ddp */ - int i; - struct snd_dec_ddp *ddp = - &compr->info.codec_param.codec.options.ddp; - uint32_t params_length = 0; - memset(params_value, 0, MAX_AC3_PARAM_SIZE); - /* check integer overflow */ - if (ddp->params_length > UINT_MAX/sizeof(int)) { - pr_err("%s: Integer overflow ddp->params_length %d\n", - __func__, ddp->params_length); - return -EINVAL; - } - params_length = ddp->params_length*sizeof(int); - if (params_length > MAX_AC3_PARAM_SIZE) { - /*MAX is 36*sizeof(int) this should not happen*/ - pr_err("%s: params_length(%d) is greater than %zd\n", - __func__, params_length, MAX_AC3_PARAM_SIZE); - return -EINVAL; - } - pr_debug("SND_AUDIOCODEC_EAC3\n"); - compr->codec = FORMAT_EAC3; - pr_debug("params_length: %d\n", ddp->params_length); - for (i = 0; i < ddp->params_length; i++) - pr_debug("params_value[%d]: %x\n", i, - params_value_data[i]); - for (i = 0; i < ddp->params_length/2; i++) { - ddp->params_id[i] = params_value_data[2*i]; - ddp->params_value[i] = params_value_data[2*i+1]; - } - if (atomic_read(&prtd->start)) { - rc = msm_compr_send_ddp_cfg(prtd->audio_client, - ddp); - if (rc < 0) - pr_err("%s: DDP CMD CFG failed\n", - __func__); - } - break; - } - default: - pr_debug("FORMAT_LINEAR_PCM\n"); - compr->codec = FORMAT_LINEAR_PCM; - break; - } - return 0; - case SNDRV_PCM_IOCTL1_RESET: - pr_debug("SNDRV_PCM_IOCTL1_RESET\n"); - /* Flush only when session is started during CAPTURE, - while PLAYBACK has no such restriction. */ - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK || - (substream->stream == SNDRV_PCM_STREAM_CAPTURE && - atomic_read(&prtd->start))) { - if (atomic_read(&prtd->eos)) { - prtd->cmd_interrupt = 1; - wake_up(&the_locks.eos_wait); - atomic_set(&prtd->eos, 0); - } - - /* A unlikely race condition possible with FLUSH - DRAIN if ack is set by flush and reset by drain */ - prtd->cmd_ack = 0; - rc = q6asm_cmd(prtd->audio_client, CMD_FLUSH); - if (rc < 0) { - pr_err("%s: flush cmd failed rc=%d\n", - __func__, rc); - return rc; - } - rc = wait_event_timeout(the_locks.flush_wait, - prtd->cmd_ack, 5 * HZ); - if (!rc) - pr_err("Flush cmd timeout\n"); - prtd->pcm_irq_pos = 0; - } - break; - case SNDRV_COMPRESS_DRAIN: - pr_debug("%s: SNDRV_COMPRESS_DRAIN\n", __func__); - if (atomic_read(&prtd->pending_buffer)) { - pr_debug("%s: no pending writes, drain would block\n", - __func__); - return -EWOULDBLOCK; - } - - atomic_set(&prtd->eos, 1); - atomic_set(&prtd->pending_buffer, 0); - prtd->cmd_ack = 0; - q6asm_cmd_nowait(prtd->audio_client, CMD_EOS); - /* Wait indefinitely for DRAIN. Flush can also signal this*/ - rc = wait_event_interruptible(the_locks.eos_wait, - (prtd->cmd_ack || prtd->cmd_interrupt)); - - if (rc < 0) - pr_err("EOS cmd interrupted\n"); - pr_debug("%s: SNDRV_COMPRESS_DRAIN out of wait\n", __func__); - - if (prtd->cmd_interrupt) - rc = -EINTR; - - prtd->cmd_interrupt = 0; - return rc; - default: - break; - } - return snd_pcm_lib_ioctl(substream, cmd, arg); -} -#ifdef CONFIG_COMPAT -struct snd_enc_wma32 { - u32 super_block_align; /* WMA Type-specific data */ - u32 encodeopt1; - u32 encodeopt2; -}; - -struct snd_enc_vorbis32 { - s32 quality; - u32 managed; - u32 max_bit_rate; - u32 min_bit_rate; - u32 downmix; -}; - -struct snd_enc_real32 { - u32 quant_bits; - u32 start_region; - u32 num_regions; -}; - -struct snd_enc_flac32 { - u32 num; - u32 gain; -}; - -struct snd_enc_generic32 { - u32 bw; /* encoder bandwidth */ - s32 reserved[15]; -}; -struct snd_dec_ddp32 { - u32 params_length; - u32 params_id[18]; - u32 params_value[18]; -}; - -union snd_codec_options32 { - struct snd_enc_wma32 wma; - struct snd_enc_vorbis32 vorbis; - struct snd_enc_real32 real; - struct snd_enc_flac32 flac; - struct snd_enc_generic32 generic; - struct snd_dec_ddp32 ddp; -}; - -struct snd_codec32 { - u32 id; - u32 ch_in; - u32 ch_out; - u32 sample_rate; - u32 bit_rate; - u32 rate_control; - u32 profile; - u32 level; - u32 ch_mode; - u32 format; - u32 align; - union snd_codec_options32 options; - u32 reserved[3]; -}; - -struct snd_compressed_buffer32 { - u32 fragment_size; - u32 fragments; -}; - -struct snd_compr_params32 { - struct snd_compressed_buffer32 buffer; - struct snd_codec32 codec; - u8 no_wake_mode; -}; - -struct snd_compr_caps32 { - u32 num_codecs; - u32 direction; - u32 min_fragment_size; - u32 max_fragment_size; - u32 min_fragments; - u32 max_fragments; - u32 codecs[MAX_NUM_CODECS]; - u32 reserved[11]; -}; -struct snd_compr_tstamp32 { - u32 byte_offset; - u32 copied_total; - compat_ulong_t pcm_frames; - compat_ulong_t pcm_io_frames; - u32 sampling_rate; - compat_u64 timestamp; -}; -enum { - SNDRV_COMPRESS_TSTAMP32 = _IOR('C', 0x20, struct snd_compr_tstamp32), - SNDRV_COMPRESS_GET_CAPS32 = _IOWR('C', 0x10, struct snd_compr_caps32), - SNDRV_COMPRESS_SET_PARAMS32 = - _IOW('C', 0x12, struct snd_compr_params32), -}; -static int msm_compr_compat_ioctl(struct snd_pcm_substream *substream, - unsigned int cmd, void *arg) -{ - int err = 0; - switch (cmd) { - case SNDRV_COMPRESS_TSTAMP32: { - struct snd_compr_tstamp tstamp; - struct snd_compr_tstamp32 tstamp32; - memset(&tstamp, 0, sizeof(tstamp)); - memset(&tstamp32, 0, sizeof(tstamp32)); - cmd = SNDRV_COMPRESS_TSTAMP; - err = msm_compr_ioctl_shared(substream, cmd, &tstamp); - if (err) { - pr_err("%s: COMPRESS_TSTAMP failed rc %d\n", - __func__, err); - goto bail_out; - } - tstamp32.byte_offset = tstamp.byte_offset; - tstamp32.copied_total = tstamp.copied_total; - tstamp32.pcm_frames = tstamp.pcm_frames; - tstamp32.pcm_io_frames = tstamp.pcm_io_frames; - tstamp32.sampling_rate = tstamp.sampling_rate; - tstamp32.timestamp = tstamp.timestamp; - if (copy_to_user(arg, &tstamp32, sizeof(tstamp32))) { - pr_err("%s: copytouser failed COMPRESS_TSTAMP32\n", - __func__); - err = -EFAULT; - } - break; - } - case SNDRV_COMPRESS_GET_CAPS32: { - struct snd_compr_caps caps; - struct snd_compr_caps32 caps32; - u32 i; - memset(&caps, 0, sizeof(caps)); - memset(&caps32, 0, sizeof(caps32)); - cmd = SNDRV_COMPRESS_GET_CAPS; - err = msm_compr_ioctl_shared(substream, cmd, &caps); - if (err) { - pr_err("%s: GET_CAPS failed rc %d\n", - __func__, err); - goto bail_out; - } - pr_debug("SNDRV_COMPRESS_GET_CAPS_32\n"); - if (!err && caps.num_codecs >= MAX_NUM_CODECS) { - pr_err("%s: Invalid number of codecs\n", __func__); - err = -EINVAL; - goto bail_out; - } - caps32.direction = caps.direction; - caps32.max_fragment_size = caps.max_fragment_size; - caps32.max_fragments = caps.max_fragments; - caps32.min_fragment_size = caps.min_fragment_size; - caps32.num_codecs = caps.num_codecs; - for (i = 0; i < caps.num_codecs; i++) - caps32.codecs[i] = caps.codecs[i]; - if (copy_to_user(arg, &caps32, sizeof(caps32))) { - pr_err("%s: copytouser failed COMPRESS_GETCAPS32\n", - __func__); - err = -EFAULT; - } - break; - } - case SNDRV_COMPRESS_SET_PARAMS32: { - struct snd_compr_params32 params32; - struct snd_compr_params params; - memset(¶ms32, 0 , sizeof(params32)); - memset(¶ms, 0 , sizeof(params)); - cmd = SNDRV_COMPRESS_SET_PARAMS; - if (copy_from_user(¶ms32, arg, sizeof(params32))) { - pr_err("%s: copyfromuser failed SET_PARAMS32\n", - __func__); - err = -EFAULT; - goto bail_out; - } - params.no_wake_mode = params32.no_wake_mode; - params.codec.id = params32.codec.id; - params.codec.ch_in = params32.codec.ch_in; - params.codec.ch_out = params32.codec.ch_out; - params.codec.sample_rate = params32.codec.sample_rate; - params.codec.bit_rate = params32.codec.bit_rate; - params.codec.rate_control = params32.codec.rate_control; - params.codec.profile = params32.codec.profile; - params.codec.level = params32.codec.level; - params.codec.ch_mode = params32.codec.ch_mode; - params.codec.format = params32.codec.format; - params.codec.align = params32.codec.align; - - switch (params.codec.id) { - case SND_AUDIOCODEC_WMA: - case SND_AUDIOCODEC_WMA_PRO: - params.codec.options.wma.encodeopt1 = - params32.codec.options.wma.encodeopt1; - params.codec.options.wma.encodeopt2 = - params32.codec.options.wma.encodeopt2; - params.codec.options.wma.super_block_align = - params32.codec.options.wma.super_block_align; - break; - case SND_AUDIOCODEC_VORBIS: - params.codec.options.vorbis.downmix = - params32.codec.options.vorbis.downmix; - params.codec.options.vorbis.managed = - params32.codec.options.vorbis.managed; - params.codec.options.vorbis.max_bit_rate = - params32.codec.options.vorbis.max_bit_rate; - params.codec.options.vorbis.min_bit_rate = - params32.codec.options.vorbis.min_bit_rate; - params.codec.options.vorbis.quality = - params32.codec.options.vorbis.quality; - break; - case SND_AUDIOCODEC_REAL: - params.codec.options.real.num_regions = - params32.codec.options.real.num_regions; - params.codec.options.real.quant_bits = - params32.codec.options.real.quant_bits; - params.codec.options.real.start_region = - params32.codec.options.real.start_region; - break; - case SND_AUDIOCODEC_FLAC: - params.codec.options.flac.gain = - params32.codec.options.flac.gain; - params.codec.options.flac.num = - params32.codec.options.flac.num; - break; - case SND_AUDIOCODEC_DTS: - case SND_AUDIOCODEC_DTS_PASS_THROUGH: - case SND_AUDIOCODEC_DTS_LBR: - case SND_AUDIOCODEC_DTS_LBR_PASS_THROUGH: - case SND_AUDIOCODEC_DTS_TRANSCODE_LOOPBACK: - break; - case SND_AUDIOCODEC_AC3: - case SND_AUDIOCODEC_EAC3: - params.codec.options.ddp.params_length = - params32.codec.options.ddp.params_length; - memcpy(params.codec.options.ddp.params_value, - params32.codec.options.ddp.params_value, - sizeof(params32.codec.options.ddp.params_value)); - memcpy(params.codec.options.ddp.params_id, - params32.codec.options.ddp.params_id, - sizeof(params32.codec.options.ddp.params_id)); - break; - default: - params.codec.options.generic.bw = - params32.codec.options.generic.bw; - break; - } - if (!err) - err = msm_compr_ioctl_shared(substream, cmd, ¶ms); - break; - } - default: - err = msm_compr_ioctl_shared(substream, cmd, arg); - } -bail_out: - return err; - -} -#endif -static int msm_compr_ioctl(struct snd_pcm_substream *substream, - unsigned int cmd, void *arg) -{ - int err = 0; - if (!substream) { - pr_err("%s: Invalid params\n", __func__); - return -EINVAL; - } - pr_debug("%s called with cmd = %d\n", __func__, cmd); - switch (cmd) { - case SNDRV_COMPRESS_TSTAMP: { - struct snd_compr_tstamp tstamp; - if (!arg) { - pr_err("%s: Invalid params Tstamp\n", __func__); - return -EINVAL; - } - err = msm_compr_ioctl_shared(substream, cmd, &tstamp); - if (err) - pr_err("%s: COMPRESS_TSTAMP failed rc %d\n", - __func__, err); - if (!err && copy_to_user(arg, &tstamp, sizeof(tstamp))) { - pr_err("%s: copytouser failed COMPRESS_TSTAMP\n", - __func__); - err = -EFAULT; - } - break; - } - case SNDRV_COMPRESS_GET_CAPS: { - struct snd_compr_caps cap; - if (!arg) { - pr_err("%s: Invalid params getcaps\n", __func__); - return -EINVAL; - } - pr_debug("SNDRV_COMPRESS_GET_CAPS\n"); - err = msm_compr_ioctl_shared(substream, cmd, &cap); - if (err) - pr_err("%s: GET_CAPS failed rc %d\n", - __func__, err); - if (!err && copy_to_user(arg, &cap, sizeof(cap))) { - pr_err("%s: copytouser failed GET_CAPS\n", - __func__); - err = -EFAULT; - } - break; - } - case SNDRV_COMPRESS_SET_PARAMS: { - struct snd_compr_params params; - if (!arg) { - pr_err("%s: Invalid params setparam\n", __func__); - return -EINVAL; - } - if (copy_from_user(¶ms, arg, - sizeof(struct snd_compr_params))) { - pr_err("%s: SET_PARAMS\n", __func__); - return -EFAULT; - } - err = msm_compr_ioctl_shared(substream, cmd, ¶ms); - if (err) - pr_err("%s: SET_PARAMS failed rc %d\n", - __func__, err); - break; - } - default: - err = msm_compr_ioctl_shared(substream, cmd, arg); - } - return err; -} - -static int msm_compr_restart(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct compr_audio *compr = runtime->private_data; - struct msm_audio *prtd = &compr->prtd; - struct audio_aio_write_param param; - struct audio_buffer *buf = NULL; - struct output_meta_data_st output_meta_data; - int time_stamp_flag = 0; - int buffer_length = 0; - - pr_debug("%s, trigger restart\n", __func__); - - if (runtime->render_flag & SNDRV_RENDER_STOPPED) { - buf = prtd->audio_client->port[IN].buf; - pr_debug("%s:writing %d bytes of buffer[%d] to dsp 2\n", - __func__, prtd->pcm_count, prtd->out_head); - pr_debug("%s:writing buffer[%d] from 0x%08x\n", - __func__, prtd->out_head, - ((unsigned int)buf[0].phys - + (prtd->out_head * prtd->pcm_count))); - - if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) - time_stamp_flag = SET_TIMESTAMP; - else - time_stamp_flag = NO_TIMESTAMP; - memcpy(&output_meta_data, (char *)(buf->data + - prtd->out_head * prtd->pcm_count), - COMPRE_OUTPUT_METADATA_SIZE); - - buffer_length = output_meta_data.frame_size; - pr_debug("meta_data_length: %d, frame_length: %d\n", - output_meta_data.meta_data_length, - output_meta_data.frame_size); - pr_debug("timestamp_msw: %d, timestamp_lsw: %d\n", - output_meta_data.timestamp_msw, - output_meta_data.timestamp_lsw); - - param.paddr = (unsigned long)buf[0].phys - + (prtd->out_head * prtd->pcm_count) - + output_meta_data.meta_data_length; - param.len = buffer_length; - param.msw_ts = output_meta_data.timestamp_msw; - param.lsw_ts = output_meta_data.timestamp_lsw; - param.flags = time_stamp_flag; - param.uid = prtd->session_id; - if (q6asm_async_write(prtd->audio_client, - ¶m) < 0) - pr_err("%s:q6asm_async_write failed\n", - __func__); - else - prtd->out_head = - (prtd->out_head + 1) & (runtime->periods - 1); - - runtime->render_flag &= ~SNDRV_RENDER_STOPPED; - return 0; - } - return 0; -} - -static int msm_compr_volume_ctl_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - int rc = 0; - struct snd_pcm_volume *vol = snd_kcontrol_chip(kcontrol); - struct snd_pcm_substream *substream = - vol->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; - struct msm_audio *prtd; - int volume = ucontrol->value.integer.value[0]; - - pr_debug("%s: volume : %x\n", __func__, volume); - if (!substream) - return -ENODEV; - if (!substream->runtime) - return 0; - prtd = substream->runtime->private_data; - if (prtd) - rc = compressed_set_volume(prtd, volume); - - return rc; -} - -static int msm_compr_volume_ctl_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_pcm_volume *vol = snd_kcontrol_chip(kcontrol); - struct snd_pcm_substream *substream = - vol->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; - struct msm_audio *prtd; - - pr_debug("%s\n", __func__); - if (!substream) - return -ENODEV; - if (!substream->runtime) - return 0; - prtd = substream->runtime->private_data; - if (prtd) - ucontrol->value.integer.value[0] = prtd->volume; - return 0; -} - -static int msm_compr_add_controls(struct snd_soc_pcm_runtime *rtd) -{ - int ret = 0; - struct snd_pcm *pcm = rtd->pcm; - struct snd_pcm_volume *volume_info; - struct snd_kcontrol *kctl; - - dev_dbg(rtd->dev, "%s, Volume cntrl add\n", __func__); - ret = snd_pcm_add_volume_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, - NULL, 1, rtd->dai_link->be_id, - &volume_info); - if (ret < 0) - return ret; - kctl = volume_info->kctl; - kctl->put = msm_compr_volume_ctl_put; - kctl->get = msm_compr_volume_ctl_get; - kctl->tlv.p = compr_rx_vol_gain; - return 0; -} - -static struct snd_pcm_ops msm_compr_ops = { - .open = msm_compr_open, - .hw_params = msm_compr_hw_params, - .close = msm_compr_close, - .ioctl = msm_compr_ioctl, - .prepare = msm_compr_prepare, - .trigger = msm_compr_trigger, - .pointer = msm_compr_pointer, - .mmap = msm_compr_mmap, - .restart = msm_compr_restart, -#ifdef CONFIG_COMPAT - .compat_ioctl = msm_compr_compat_ioctl, -#endif -}; - -static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_card *card = rtd->card->snd_card; - int ret = 0; - - if (!card->dev->coherent_dma_mask) - card->dev->coherent_dma_mask = DMA_BIT_MASK(32); - - ret = msm_compr_add_controls(rtd); - if (ret) - pr_err("%s, kctl add failed\n", __func__); - return ret; -} - -static struct snd_soc_platform_driver msm_soc_platform = { - .ops = &msm_compr_ops, - .pcm_new = msm_asoc_pcm_new, -}; - -static int msm_compr_probe(struct platform_device *pdev) -{ - - dev_info(&pdev->dev, "%s: dev name %s\n", - __func__, dev_name(&pdev->dev)); - - return snd_soc_register_platform(&pdev->dev, - &msm_soc_platform); -} - -static int msm_compr_remove(struct platform_device *pdev) -{ - snd_soc_unregister_platform(&pdev->dev); - return 0; -} - -static const struct of_device_id msm_compr_dt_match[] = { - {.compatible = "qcom,msm-compr-dsp"}, - {} -}; -MODULE_DEVICE_TABLE(of, msm_compr_dt_match); - -static struct platform_driver msm_compr_driver = { - .driver = { - .name = "msm-compr-dsp", - .owner = THIS_MODULE, - .of_match_table = msm_compr_dt_match, - }, - .probe = msm_compr_probe, - .remove = msm_compr_remove, -}; - -static int __init msm_soc_platform_init(void) -{ - init_waitqueue_head(&the_locks.enable_wait); - init_waitqueue_head(&the_locks.eos_wait); - init_waitqueue_head(&the_locks.write_wait); - init_waitqueue_head(&the_locks.read_wait); - init_waitqueue_head(&the_locks.flush_wait); - - return platform_driver_register(&msm_compr_driver); -} -module_init(msm_soc_platform_init); - -static void __exit msm_soc_platform_exit(void) -{ - platform_driver_unregister(&msm_compr_driver); -} -module_exit(msm_soc_platform_exit); - -MODULE_DESCRIPTION("PCM module platform driver"); -MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.h b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.h deleted file mode 100644 index d6e3ec6956b1..000000000000 --- a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2012, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef _MSM_COMPR_H -#define _MSM_COMPR_H -#include <sound/apr_audio-v2.h> -#include <sound/q6asm-v2.h> -#include <sound/compress_params.h> -#include <sound/compress_offload.h> -#include <sound/compress_driver.h> - -#include "msm-pcm-q6-v2.h" - -struct compr_info { - struct snd_compr_caps compr_cap; - struct snd_compr_codec_caps codec_caps; - struct snd_compr_params codec_param; -}; - -struct compr_audio { - struct msm_audio prtd; - struct compr_info info; - uint32_t codec; -}; - -#endif /*_MSM_COMPR_H*/ diff --git a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c index 426b4d0b0a35..0a93ee593ed2 100644 --- a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c @@ -32,6 +32,7 @@ #include <asm/dma.h> #include <linux/dma-mapping.h> #include <linux/msm_audio_ion.h> +#include <linux/msm_audio.h> #include <sound/timer.h> #include <sound/tlv.h> @@ -742,7 +743,8 @@ static void compr_event_handler(uint32_t opcode, spin_unlock_irqrestore(&prtd->lock, flags); break; case ASM_STREAM_PP_EVENT: - pr_debug("%s: ASM_STREAM_PP_EVENT\n", __func__); + case ASM_STREAM_CMD_ENCDEC_EVENTS: + pr_debug("%s: ASM_STREAM_EVENT(0x%x)\n", __func__, opcode); rtd = cstream->private_data; if (!rtd) { pr_err("%s: rtd is NULL\n", __func__); @@ -755,7 +757,6 @@ static void compr_event_handler(uint32_t opcode, __func__, ret); return; } - break; case ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY: case ASM_DATA_EVENT_ENC_SR_CM_CHANGE_NOTIFY: { @@ -3588,7 +3589,8 @@ static int msm_compr_adsp_stream_cmd_put(struct snd_kcontrol *kcontrol, snd_soc_component_get_drvdata(comp); struct snd_compr_stream *cstream = NULL; struct msm_compr_audio *prtd; - int ret = 0, param_length = 0; + int ret = 0; + struct msm_adsp_event_data *event_data = NULL; if (fe_id >= MSM_FRONTEND_DAI_MAX) { pr_err("%s Received invalid fe_id %lu\n", @@ -3599,20 +3601,131 @@ static int msm_compr_adsp_stream_cmd_put(struct snd_kcontrol *kcontrol, cstream = pdata->cstream[fe_id]; if (cstream == NULL) { - pr_err("%s cstream is null.\n", __func__); + pr_err("%s cstream is null\n", __func__); ret = -EINVAL; goto done; } prtd = cstream->runtime->private_data; if (!prtd) { - pr_err("%s: prtd is null.\n", __func__); + pr_err("%s: prtd is null\n", __func__); ret = -EINVAL; goto done; } if (prtd->audio_client == NULL) { - pr_err("%s: audio_client is null.\n", __func__); + pr_err("%s: audio_client is null\n", __func__); + ret = -EINVAL; + goto done; + } + + event_data = (struct msm_adsp_event_data *)ucontrol->value.bytes.data; + if ((event_data->event_type < ADSP_STREAM_PP_EVENT) || + (event_data->event_type >= ADSP_STREAM_EVENT_MAX)) { + pr_err("%s: invalid event_type=%d", + __func__, event_data->event_type); + ret = -EINVAL; + goto done; + } + + if ((sizeof(struct msm_adsp_event_data) + event_data->payload_len) >= + sizeof(ucontrol->value.bytes.data)) { + pr_err("%s param length=%d exceeds limit", + __func__, event_data->payload_len); + ret = -EINVAL; + goto done; + } + + ret = q6asm_send_stream_cmd(prtd->audio_client, event_data); + if (ret < 0) + pr_err("%s: failed to send stream event cmd, err = %d\n", + __func__, ret); +done: + return ret; +} + +static int msm_compr_ion_fd_map_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol); + unsigned long fe_id = kcontrol->private_value; + struct msm_compr_pdata *pdata = (struct msm_compr_pdata *) + snd_soc_component_get_drvdata(comp); + struct snd_compr_stream *cstream = NULL; + struct msm_compr_audio *prtd; + int fd; + int ret = 0; + + if (fe_id >= MSM_FRONTEND_DAI_MAX) { + pr_err("%s Received out of bounds invalid fe_id %lu\n", + __func__, fe_id); + ret = -EINVAL; + goto done; + } + + cstream = pdata->cstream[fe_id]; + if (cstream == NULL) { + pr_err("%s cstream is null\n", __func__); + ret = -EINVAL; + goto done; + } + + prtd = cstream->runtime->private_data; + if (!prtd) { + pr_err("%s: prtd is null\n", __func__); + ret = -EINVAL; + goto done; + } + + if (prtd->audio_client == NULL) { + pr_err("%s: audio_client is null\n", __func__); + ret = -EINVAL; + goto done; + } + + memcpy(&fd, ucontrol->value.bytes.data, sizeof(fd)); + ret = q6asm_send_ion_fd(prtd->audio_client, fd); + if (ret < 0) + pr_err("%s: failed to register ion fd\n", __func__); +done: + return ret; +} + +static int msm_compr_rtic_event_ack_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol); + unsigned long fe_id = kcontrol->private_value; + struct msm_compr_pdata *pdata = (struct msm_compr_pdata *) + snd_soc_component_get_drvdata(comp); + struct snd_compr_stream *cstream = NULL; + struct msm_compr_audio *prtd; + int ret = 0; + int param_length = 0; + + if (fe_id >= MSM_FRONTEND_DAI_MAX) { + pr_err("%s Received invalid fe_id %lu\n", + __func__, fe_id); + ret = -EINVAL; + goto done; + } + + cstream = pdata->cstream[fe_id]; + if (cstream == NULL) { + pr_err("%s cstream is null\n", __func__); + ret = -EINVAL; + goto done; + } + + prtd = cstream->runtime->private_data; + if (!prtd) { + pr_err("%s: prtd is null\n", __func__); + ret = -EINVAL; + goto done; + } + + if (prtd->audio_client == NULL) { + pr_err("%s: audio_client is null\n", __func__); ret = -EINVAL; goto done; } @@ -3627,12 +3740,11 @@ static int msm_compr_adsp_stream_cmd_put(struct snd_kcontrol *kcontrol, goto done; } - ret = q6asm_send_stream_cmd(prtd->audio_client, - ASM_STREAM_CMD_REGISTER_PP_EVENTS, + ret = q6asm_send_rtic_event_ack(prtd->audio_client, ucontrol->value.bytes.data + sizeof(param_length), param_length); if (ret < 0) - pr_err("%s: failed to register pp event. err = %d\n", + pr_err("%s: failed to send rtic event ack, err = %d\n", __func__, ret); done: return ret; @@ -4206,6 +4318,96 @@ static int msm_compr_add_channel_map_control(struct snd_soc_pcm_runtime *rtd) return 0; } +static int msm_compr_add_io_fd_cmd_control(struct snd_soc_pcm_runtime *rtd) +{ + const char *mixer_ctl_name = "Playback ION FD"; + const char *deviceNo = "NN"; + char *mixer_str = NULL; + int ctl_len = 0, ret = 0; + struct snd_kcontrol_new fe_ion_fd_config_control[1] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "?", + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = msm_adsp_stream_cmd_info, + .put = msm_compr_ion_fd_map_put, + .private_value = 0, + } + }; + + if (!rtd) { + pr_err("%s NULL rtd\n", __func__); + ret = -EINVAL; + goto done; + } + + ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1; + mixer_str = kzalloc(ctl_len, GFP_KERNEL); + if (!mixer_str) { + ret = -ENOMEM; + goto done; + } + + snprintf(mixer_str, ctl_len, "%s %d", mixer_ctl_name, rtd->pcm->device); + fe_ion_fd_config_control[0].name = mixer_str; + fe_ion_fd_config_control[0].private_value = rtd->dai_link->be_id; + pr_debug("%s: Registering new mixer ctl %s\n", __func__, mixer_str); + ret = snd_soc_add_platform_controls(rtd->platform, + fe_ion_fd_config_control, + ARRAY_SIZE(fe_ion_fd_config_control)); + if (ret < 0) + pr_err("%s: failed to add ctl %s\n", __func__, mixer_str); + + kfree(mixer_str); +done: + return ret; +} + +static int msm_compr_add_event_ack_cmd_control(struct snd_soc_pcm_runtime *rtd) +{ + const char *mixer_ctl_name = "Playback Event Ack"; + const char *deviceNo = "NN"; + char *mixer_str = NULL; + int ctl_len = 0, ret = 0; + struct snd_kcontrol_new fe_event_ack_config_control[1] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "?", + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = msm_adsp_stream_cmd_info, + .put = msm_compr_rtic_event_ack_put, + .private_value = 0, + } + }; + + if (!rtd) { + pr_err("%s NULL rtd\n", __func__); + ret = -EINVAL; + goto done; + } + + ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1; + mixer_str = kzalloc(ctl_len, GFP_KERNEL); + if (!mixer_str) { + ret = -ENOMEM; + goto done; + } + + snprintf(mixer_str, ctl_len, "%s %d", mixer_ctl_name, rtd->pcm->device); + fe_event_ack_config_control[0].name = mixer_str; + fe_event_ack_config_control[0].private_value = rtd->dai_link->be_id; + pr_debug("%s: Registering new mixer ctl %s\n", __func__, mixer_str); + ret = snd_soc_add_platform_controls(rtd->platform, + fe_event_ack_config_control, + ARRAY_SIZE(fe_event_ack_config_control)); + if (ret < 0) + pr_err("%s: failed to add ctl %s\n", __func__, mixer_str); + + kfree(mixer_str); +done: + return ret; +} + static int msm_compr_new(struct snd_soc_pcm_runtime *rtd) { int rc; @@ -4229,6 +4431,16 @@ static int msm_compr_new(struct snd_soc_pcm_runtime *rtd) pr_err("%s: Could not add Compr ADSP Stream Callback Control\n", __func__); + rc = msm_compr_add_io_fd_cmd_control(rtd); + if (rc) + pr_err("%s: Could not add Compr ion fd Control\n", + __func__); + + rc = msm_compr_add_event_ack_cmd_control(rtd); + if (rc) + pr_err("%s: Could not add Compr event ack Control\n", + __func__); + rc = msm_compr_add_query_audio_effect_control(rtd); if (rc) pr_err("%s: Could not add Compr Query Audio Effect Control\n", diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c index 9ed61288a3e4..64b1961794b9 100644 --- a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c @@ -5026,6 +5026,44 @@ static struct platform_driver msm_dai_q6_spdif_driver = { }, }; +static int msm_dai_q6_tdm_set_clk_param(u32 group_id, + struct afe_clk_set *clk_set, u32 mode) +{ + switch (group_id) { + case AFE_GROUP_DEVICE_ID_PRIMARY_TDM_RX: + case AFE_GROUP_DEVICE_ID_PRIMARY_TDM_TX: + if (mode) + clk_set->clk_id = Q6AFE_LPASS_CLK_ID_PRI_TDM_IBIT; + else + clk_set->clk_id = Q6AFE_LPASS_CLK_ID_PRI_TDM_EBIT; + break; + case AFE_GROUP_DEVICE_ID_SECONDARY_TDM_RX: + case AFE_GROUP_DEVICE_ID_SECONDARY_TDM_TX: + if (mode) + clk_set->clk_id = Q6AFE_LPASS_CLK_ID_SEC_TDM_IBIT; + else + clk_set->clk_id = Q6AFE_LPASS_CLK_ID_SEC_TDM_EBIT; + break; + case AFE_GROUP_DEVICE_ID_TERTIARY_TDM_RX: + case AFE_GROUP_DEVICE_ID_TERTIARY_TDM_TX: + if (mode) + clk_set->clk_id = Q6AFE_LPASS_CLK_ID_TER_TDM_IBIT; + else + clk_set->clk_id = Q6AFE_LPASS_CLK_ID_TER_TDM_EBIT; + break; + case AFE_GROUP_DEVICE_ID_QUATERNARY_TDM_RX: + case AFE_GROUP_DEVICE_ID_QUATERNARY_TDM_TX: + if (mode) + clk_set->clk_id = Q6AFE_LPASS_CLK_ID_QUAD_TDM_IBIT; + else + clk_set->clk_id = Q6AFE_LPASS_CLK_ID_QUAD_TDM_EBIT; + break; + default: + return -EINVAL; + } + return 0; +} + static int msm_dai_tdm_q6_probe(struct platform_device *pdev) { int rc = 0; @@ -5033,6 +5071,7 @@ static int msm_dai_tdm_q6_probe(struct platform_device *pdev) uint32_t array_length = 0; int i = 0; int group_idx = 0; + u32 clk_mode = 0; /* extract tdm group info into static */ rc = of_property_read_u32(pdev->dev.of_node, @@ -5105,6 +5144,26 @@ static int msm_dai_tdm_q6_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "%s: Clk Rate from DT file %d\n", __func__, tdm_clk_set.clk_freq_in_hz); + /* extract tdm clk src master/slave info into static */ + rc = of_property_read_u32(pdev->dev.of_node, + "qcom,msm-cpudai-tdm-clk-internal", + &clk_mode); + if (rc) { + dev_err(&pdev->dev, "%s: Clk id from DT file %s\n", + __func__, "qcom,msm-cpudai-tdm-clk-internal"); + goto rtn; + } + dev_dbg(&pdev->dev, "%s: Clk id from DT file %d\n", + __func__, clk_mode); + + rc = msm_dai_q6_tdm_set_clk_param(tdm_group_cfg.group_id, + &tdm_clk_set, clk_mode); + if (rc) { + dev_err(&pdev->dev, "%s: group id not supported 0x%x\n", + __func__, tdm_group_cfg.group_id); + goto rtn; + } + /* other initializations within device group */ group_idx = msm_dai_q6_get_group_idx(tdm_group_cfg.group_id); if (group_idx < 0) { @@ -5900,48 +5959,6 @@ static int msm_dai_q6_tdm_set_clk( { int rc = 0; - switch (dai_data->group_cfg.tdm_cfg.group_id) { - case AFE_GROUP_DEVICE_ID_PRIMARY_TDM_RX: - case AFE_GROUP_DEVICE_ID_PRIMARY_TDM_TX: - if (dai_data->clk_set.clk_freq_in_hz) { - dai_data->clk_set.clk_id = - Q6AFE_LPASS_CLK_ID_PRI_TDM_IBIT; - } else - dai_data->clk_set.clk_id = - Q6AFE_LPASS_CLK_ID_PRI_TDM_EBIT; - break; - case AFE_GROUP_DEVICE_ID_SECONDARY_TDM_RX: - case AFE_GROUP_DEVICE_ID_SECONDARY_TDM_TX: - if (dai_data->clk_set.clk_freq_in_hz) { - dai_data->clk_set.clk_id = - Q6AFE_LPASS_CLK_ID_SEC_TDM_IBIT; - } else - dai_data->clk_set.clk_id = - Q6AFE_LPASS_CLK_ID_SEC_TDM_EBIT; - break; - case AFE_GROUP_DEVICE_ID_TERTIARY_TDM_RX: - case AFE_GROUP_DEVICE_ID_TERTIARY_TDM_TX: - if (dai_data->clk_set.clk_freq_in_hz) { - dai_data->clk_set.clk_id = - Q6AFE_LPASS_CLK_ID_TER_TDM_IBIT; - } else - dai_data->clk_set.clk_id = - Q6AFE_LPASS_CLK_ID_TER_TDM_EBIT; - break; - case AFE_GROUP_DEVICE_ID_QUATERNARY_TDM_RX: - case AFE_GROUP_DEVICE_ID_QUATERNARY_TDM_TX: - if (dai_data->clk_set.clk_freq_in_hz) { - dai_data->clk_set.clk_id = - Q6AFE_LPASS_CLK_ID_QUAD_TDM_IBIT; - } else - dai_data->clk_set.clk_id = - Q6AFE_LPASS_CLK_ID_QUAD_TDM_EBIT; - break; - default: - pr_err("%s: port id 0x%x not supported\n", - __func__, port_id); - return -EINVAL; - } dai_data->clk_set.enable = enable; rc = afe_set_lpass_clock_v2(port_id, @@ -7930,6 +7947,7 @@ static int msm_dai_q6_tdm_dev_probe(struct platform_device *pdev) int rc = 0; u32 tdm_dev_id = 0; int port_idx = 0; + struct device_node *tdm_parent_node = NULL; /* retrieve device/afe id */ rc = of_property_read_u32(pdev->dev.of_node, @@ -7964,7 +7982,8 @@ static int msm_dai_q6_tdm_dev_probe(struct platform_device *pdev) memset(dai_data, 0, sizeof(*dai_data)); /* TDM CFG */ - rc = of_property_read_u32(pdev->dev.of_node, + tdm_parent_node = of_get_parent(pdev->dev.of_node); + rc = of_property_read_u32(tdm_parent_node, "qcom,msm-cpudai-tdm-sync-mode", (u32 *)&dai_data->port_cfg.tdm.sync_mode); if (rc) { @@ -7975,7 +7994,7 @@ static int msm_dai_q6_tdm_dev_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "%s: Sync Mode from DT file 0x%x\n", __func__, dai_data->port_cfg.tdm.sync_mode); - rc = of_property_read_u32(pdev->dev.of_node, + rc = of_property_read_u32(tdm_parent_node, "qcom,msm-cpudai-tdm-sync-src", (u32 *)&dai_data->port_cfg.tdm.sync_src); if (rc) { @@ -7986,7 +8005,7 @@ static int msm_dai_q6_tdm_dev_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "%s: Sync Src from DT file 0x%x\n", __func__, dai_data->port_cfg.tdm.sync_src); - rc = of_property_read_u32(pdev->dev.of_node, + rc = of_property_read_u32(tdm_parent_node, "qcom,msm-cpudai-tdm-data-out", (u32 *)&dai_data->port_cfg.tdm.ctrl_data_out_enable); if (rc) { @@ -7997,7 +8016,7 @@ static int msm_dai_q6_tdm_dev_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "%s: Data Out from DT file 0x%x\n", __func__, dai_data->port_cfg.tdm.ctrl_data_out_enable); - rc = of_property_read_u32(pdev->dev.of_node, + rc = of_property_read_u32(tdm_parent_node, "qcom,msm-cpudai-tdm-invert-sync", (u32 *)&dai_data->port_cfg.tdm.ctrl_invert_sync_pulse); if (rc) { @@ -8008,7 +8027,7 @@ static int msm_dai_q6_tdm_dev_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "%s: Invert Sync from DT file 0x%x\n", __func__, dai_data->port_cfg.tdm.ctrl_invert_sync_pulse); - rc = of_property_read_u32(pdev->dev.of_node, + rc = of_property_read_u32(tdm_parent_node, "qcom,msm-cpudai-tdm-data-delay", (u32 *)&dai_data->port_cfg.tdm.ctrl_sync_data_delay); if (rc) { diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c index 8f43aee3974c..3be6567aefab 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c @@ -30,6 +30,7 @@ #include <asm/dma.h> #include <linux/dma-mapping.h> #include <linux/msm_audio_ion.h> +#include <linux/msm_audio.h> #include <linux/of_device.h> #include <sound/tlv.h> @@ -226,8 +227,9 @@ static void event_handler(uint32_t opcode, } break; } - case ASM_STREAM_PP_EVENT: { - pr_debug("%s: ASM_STREAM_PP_EVENT\n", __func__); + case ASM_STREAM_PP_EVENT: + case ASM_STREAM_CMD_ENCDEC_EVENTS: { + pr_debug("%s: ASM_STREAM_EVENT (0x%x)\n", __func__, opcode); if (!substream) { pr_err("%s: substream is NULL.\n", __func__); return; @@ -1075,7 +1077,8 @@ static int msm_pcm_adsp_stream_cmd_put(struct snd_kcontrol *kcontrol, struct msm_plat_data *pdata = dev_get_drvdata(platform->dev); struct snd_pcm_substream *substream; struct msm_audio *prtd; - int ret = 0, param_length = 0; + int ret = 0; + struct msm_adsp_event_data *event_data = NULL; if (!pdata) { pr_err("%s pdata is NULL\n", __func__); @@ -1103,22 +1106,26 @@ static int msm_pcm_adsp_stream_cmd_put(struct snd_kcontrol *kcontrol, goto done; } - memcpy(¶m_length, ucontrol->value.bytes.data, - sizeof(param_length)); - if ((param_length + sizeof(param_length)) - >= sizeof(ucontrol->value.bytes.data)) { + event_data = (struct msm_adsp_event_data *)ucontrol->value.bytes.data; + if ((event_data->event_type < ADSP_STREAM_PP_EVENT) || + (event_data->event_type >= ADSP_STREAM_EVENT_MAX)) { + pr_err("%s: invalid event_type=%d", + __func__, event_data->event_type); + ret = -EINVAL; + goto done; + } + + if ((sizeof(struct msm_adsp_event_data) + event_data->payload_len) >= + sizeof(ucontrol->value.bytes.data)) { pr_err("%s param length=%d exceeds limit", - __func__, param_length); + __func__, event_data->payload_len); ret = -EINVAL; goto done; } - ret = q6asm_send_stream_cmd(prtd->audio_client, - ASM_STREAM_CMD_REGISTER_PP_EVENTS, - ucontrol->value.bytes.data + sizeof(param_length), - param_length); + ret = q6asm_send_stream_cmd(prtd->audio_client, event_data); if (ret < 0) - pr_err("%s: failed to register pp event. err = %d\n", + pr_err("%s: failed to send stream event cmd, err = %d\n", __func__, ret); done: return ret; diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c index 4aebcb6fa77e..50bad5c2e48c 100644 --- a/sound/soc/msm/qdsp6v2/q6asm.c +++ b/sound/soc/msm/qdsp6v2/q6asm.c @@ -155,6 +155,13 @@ static int out_cold_index; static char *out_buffer; static char *in_buffer; +static uint32_t adsp_reg_event_opcode[] = {ASM_STREAM_CMD_REGISTER_PP_EVENTS, + ASM_STREAM_CMD_REGISTER_ENCDEC_EVENTS}; + +static uint32_t adsp_raise_event_opcode[] = {ASM_STREAM_PP_EVENT, + ASM_STREAM_CMD_ENCDEC_EVENTS}; + + static inline void q6asm_set_flag_in_token(union asm_token_struct *asm_token, int flag, int flag_offset) { @@ -1096,37 +1103,44 @@ fail: return NULL; } -int q6asm_send_stream_cmd(struct audio_client *ac, uint32_t opcode, - void *param, uint32_t params_length) +int q6asm_send_stream_cmd(struct audio_client *ac, + struct msm_adsp_event_data *data) { char *asm_params = NULL; struct apr_hdr hdr; int sz, rc; - if (!param || !ac) { + if (!data || !ac) { pr_err("%s: %s is NULL\n", __func__, - (!param) ? "param" : "ac"); + (!data) ? "data" : "ac"); + rc = -EINVAL; + goto done; + } + + if (data->event_type >= ARRAY_SIZE(adsp_reg_event_opcode)) { + pr_err("%s: event %u out of boundary of array size of (%lu)\n", + __func__, data->event_type, + (long)ARRAY_SIZE(adsp_reg_event_opcode)); rc = -EINVAL; goto done; } - sz = sizeof(struct apr_hdr) + params_length; + sz = sizeof(struct apr_hdr) + data->payload_len; asm_params = kzalloc(sz, GFP_KERNEL); if (!asm_params) { rc = -ENOMEM; goto done; } - q6asm_add_hdr_async(ac, &hdr, sizeof(struct apr_hdr) + - params_length, TRUE); + q6asm_add_hdr_async(ac, &hdr, sz, TRUE); atomic_set(&ac->cmd_state_pp, -1); - hdr.opcode = opcode; + hdr.opcode = adsp_reg_event_opcode[data->event_type]; memcpy(asm_params, &hdr, sizeof(struct apr_hdr)); memcpy(asm_params + sizeof(struct apr_hdr), - param, params_length); + data->payload, data->payload_len); rc = apr_send_pkt(ac->apr, (uint32_t *) asm_params); if (rc < 0) { - pr_err("%s: audio adsp pp register failed\n", __func__); + pr_err("%s: stream event cmd apr pkt failed\n", __func__); rc = -EINVAL; goto fail_send_param; } @@ -1134,13 +1148,13 @@ int q6asm_send_stream_cmd(struct audio_client *ac, uint32_t opcode, rc = wait_event_timeout(ac->cmd_wait, (atomic_read(&ac->cmd_state_pp) >= 0), 1 * HZ); if (!rc) { - pr_err("%s: timeout, adsp pp register\n", __func__); + pr_err("%s: timeout for stream event cmd resp\n", __func__); rc = -ETIMEDOUT; goto fail_send_param; } if (atomic_read(&ac->cmd_state_pp) > 0) { - pr_err("%s: DSP returned error[%s] adsp pp register\n", + pr_err("%s: DSP returned error[%s] for stream event cmd\n", __func__, adsp_err_get_err_str( atomic_read(&ac->cmd_state_pp))); rc = adsp_err_get_lnx_err_code( @@ -1779,6 +1793,8 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) case ASM_STREAM_CMD_OPEN_TRANSCODE_LOOPBACK: case ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2: case ASM_STREAM_CMD_SET_ENCDEC_PARAM: + case ASM_STREAM_CMD_SET_ENCDEC_PARAM_V2: + case ASM_STREAM_CMD_REGISTER_ENCDEC_EVENTS: case ASM_DATA_CMD_REMOVE_INITIAL_SILENCE: case ASM_DATA_CMD_REMOVE_TRAILING_SILENCE: case ASM_SESSION_CMD_REGISTER_FOR_RX_UNDERFLOW_EVENTS: @@ -1793,7 +1809,9 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) __func__, payload[0], payload[1]); if (wakeup_flag) { if (payload[0] == - ASM_STREAM_CMD_SET_PP_PARAMS_V2) + ASM_STREAM_CMD_SET_PP_PARAMS_V2 + || payload[0] == + ASM_STREAM_CMD_REGISTER_ENCDEC_EVENTS) atomic_set(&ac->cmd_state_pp, payload[1]); else @@ -1803,7 +1821,9 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) } return 0; } - if (payload[0] == ASM_STREAM_CMD_SET_PP_PARAMS_V2) { + if (payload[0] == ASM_STREAM_CMD_SET_PP_PARAMS_V2 || + payload[0] == + ASM_STREAM_CMD_REGISTER_ENCDEC_EVENTS) { if (atomic_read(&ac->cmd_state_pp) && wakeup_flag) { atomic_set(&ac->cmd_state_pp, 0); @@ -2043,8 +2063,16 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) q6asm_process_mtmx_get_param_rsp(ac, (void *) payload); break; case ASM_STREAM_PP_EVENT: + case ASM_STREAM_CMD_ENCDEC_EVENTS: pr_debug("%s: ASM_STREAM_PP_EVENT payload[0][0x%x] payload[1][0x%x]", __func__, payload[0], payload[1]); + for (i = 0; i < ARRAY_SIZE(adsp_raise_event_opcode); i++) + if (adsp_raise_event_opcode[i] == data->opcode) + break; + + if (i >= ARRAY_SIZE(adsp_raise_event_opcode)) + return 0; + /* repack payload for asm_stream_pp_event * package is composed of event type + size + actual payload */ @@ -2055,10 +2083,10 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) if (!pp_event_package) return -ENOMEM; - pp_event_package->event_type = ASM_STREAM_PP_EVENT; + pp_event_package->event_type = i; pp_event_package->payload_len = payload_size; memcpy((void *)pp_event_package->payload, - data->payload, payload_size); + data->payload, payload_size); ac->cb(data->opcode, data->token, (void *)pp_event_package, ac->priv); kfree(pp_event_package); @@ -6898,6 +6926,156 @@ fail_cmd: return rc; } +int q6asm_send_ion_fd(struct audio_client *ac, int fd) +{ + struct ion_client *client; + struct ion_handle *handle; + ion_phys_addr_t paddr; + size_t pa_len = 0; + void *vaddr; + int ret; + int sz = 0; + struct avs_rtic_shared_mem_addr shm; + + if (ac == NULL) { + pr_err("%s: APR handle NULL\n", __func__); + ret = -EINVAL; + goto fail_cmd; + } + if (ac->apr == NULL) { + pr_err("%s: AC APR handle NULL\n", __func__); + ret = -EINVAL; + goto fail_cmd; + } + + ret = msm_audio_ion_import("audio_mem_client", + &client, + &handle, + fd, + NULL, + 0, + &paddr, + &pa_len, + &vaddr); + if (ret) { + pr_err("%s: audio ION import failed, rc = %d\n", + __func__, ret); + ret = -ENOMEM; + goto fail_cmd; + } + /* get payload length */ + sz = sizeof(struct avs_rtic_shared_mem_addr); + q6asm_add_hdr_async(ac, &shm.hdr, sz, TRUE); + atomic_set(&ac->cmd_state, -1); + shm.shm_buf_addr_lsw = lower_32_bits(paddr); + shm.shm_buf_addr_msw = msm_audio_populate_upper_32_bits(paddr); + shm.buf_size = pa_len; + shm.shm_buf_num_regions = 1; + shm.shm_buf_mem_pool_id = ADSP_MEMORY_MAP_SHMEM8_4K_POOL; + shm.shm_buf_flag = 0x00; + shm.encdec.param_id = AVS_PARAM_ID_RTIC_SHARED_MEMORY_ADDR; + shm.encdec.param_size = sizeof(struct avs_rtic_shared_mem_addr) - + sizeof(struct apr_hdr) - + sizeof(struct asm_stream_cmd_set_encdec_param_v2); + shm.encdec.service_id = OUT; + shm.encdec.reserved = 0; + shm.map_region.shm_addr_lsw = shm.shm_buf_addr_lsw; + shm.map_region.shm_addr_msw = shm.shm_buf_addr_msw; + shm.map_region.mem_size_bytes = pa_len; + shm.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM_V2; + ret = apr_send_pkt(ac->apr, (uint32_t *) &shm); + if (ret < 0) { + pr_err("%s: set-params send failed paramid[0x%x] rc %d\n", + __func__, shm.encdec.param_id, ret); + ret = -EINVAL; + goto fail_cmd; + } + + ret = wait_event_timeout(ac->cmd_wait, + (atomic_read(&ac->cmd_state) >= 0), 1*HZ); + if (!ret) { + pr_err("%s: timeout, shm.encdec paramid[0x%x]\n", __func__, + shm.encdec.param_id); + ret = -ETIMEDOUT; + goto fail_cmd; + } + if (atomic_read(&ac->cmd_state) > 0) { + pr_err("%s: DSP returned error[%s] shm.encdec paramid[0x%x]\n", + __func__, + adsp_err_get_err_str(atomic_read(&ac->cmd_state)), + shm.encdec.param_id); + ret = adsp_err_get_lnx_err_code(atomic_read(&ac->cmd_state)); + goto fail_cmd; + } + ret = 0; +fail_cmd: + return ret; +} + +int q6asm_send_rtic_event_ack(struct audio_client *ac, + void *param, uint32_t params_length) +{ + char *asm_params = NULL; + int sz, rc; + struct avs_param_rtic_event_ack ack; + + if (!param || !ac) { + pr_err("%s: %s is NULL\n", __func__, + (!param) ? "param" : "ac"); + rc = -EINVAL; + goto done; + } + + sz = sizeof(struct avs_param_rtic_event_ack) + params_length; + asm_params = kzalloc(sz, GFP_KERNEL); + if (!asm_params) { + rc = -ENOMEM; + goto done; + } + + q6asm_add_hdr_async(ac, &ack.hdr, + sizeof(struct avs_param_rtic_event_ack) + + params_length, TRUE); + atomic_set(&ac->cmd_state, -1); + ack.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM_V2; + ack.encdec.param_id = AVS_PARAM_ID_RTIC_EVENT_ACK; + ack.encdec.param_size = params_length; + ack.encdec.reserved = 0; + ack.encdec.service_id = OUT; + memcpy(asm_params, &ack, sizeof(struct avs_param_rtic_event_ack)); + memcpy(asm_params + sizeof(struct avs_param_rtic_event_ack), + param, params_length); + rc = apr_send_pkt(ac->apr, (uint32_t *) asm_params); + if (rc < 0) { + pr_err("%s: apr pkt failed for rtic event ack\n", __func__); + rc = -EINVAL; + goto fail_send_param; + } + + rc = wait_event_timeout(ac->cmd_wait, + (atomic_read(&ac->cmd_state) >= 0), 1 * HZ); + if (!rc) { + pr_err("%s: timeout for rtic event ack cmd\n", __func__); + rc = -ETIMEDOUT; + goto fail_send_param; + } + + if (atomic_read(&ac->cmd_state) > 0) { + pr_err("%s: DSP returned error[%s] for rtic event ack cmd\n", + __func__, adsp_err_get_err_str( + atomic_read(&ac->cmd_state))); + rc = adsp_err_get_lnx_err_code( + atomic_read(&ac->cmd_state)); + goto fail_send_param; + } + rc = 0; + +fail_send_param: + kfree(asm_params); +done: + return rc; +} + int q6asm_set_softpause(struct audio_client *ac, struct asm_softpause_params *pause_param) { |
