diff options
315 files changed, 7738 insertions, 3873 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/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt index 8a47b77abfca..e8c74a6e738b 100644 --- a/Documentation/devicetree/bindings/clock/sunxi.txt +++ b/Documentation/devicetree/bindings/clock/sunxi.txt @@ -18,6 +18,7 @@ Required properties: "allwinner,sun4i-a10-cpu-clk" - for the CPU multiplexer clock "allwinner,sun4i-a10-axi-clk" - for the AXI clock "allwinner,sun8i-a23-axi-clk" - for the AXI clock on A23 + "allwinner,sun4i-a10-gates-clk" - for generic gates on all compatible SoCs "allwinner,sun4i-a10-axi-gates-clk" - for the AXI gates "allwinner,sun4i-a10-ahb-clk" - for the AHB clock "allwinner,sun5i-a13-ahb-clk" - for the AHB clock on A13 @@ -43,6 +44,7 @@ Required properties: "allwinner,sun6i-a31-apb0-gates-clk" - for the APB0 gates on A31 "allwinner,sun7i-a20-apb0-gates-clk" - for the APB0 gates on A20 "allwinner,sun8i-a23-apb0-gates-clk" - for the APB0 gates on A23 + "allwinner,sun8i-h3-apb0-gates-clk" - for the APB0 gates on H3 "allwinner,sun9i-a80-apb0-gates-clk" - for the APB0 gates on A80 "allwinner,sun4i-a10-apb1-clk" - for the APB1 clock "allwinner,sun9i-a80-apb1-clk" - for the APB1 bus clock on A80 diff --git a/Documentation/devicetree/bindings/net/neutrino_avb.txt b/Documentation/devicetree/bindings/net/neutrino_avb.txt index 46c6a5208eba..471d59f2a3c0 100644 --- a/Documentation/devicetree/bindings/net/neutrino_avb.txt +++ b/Documentation/devicetree/bindings/net/neutrino_avb.txt @@ -2,6 +2,11 @@ This driver implements Ethernet driver for Neutrino ethernet controller Required properties: - compatible: Should be "qcom,ntn_avb" + - ntn-rst-delay-msec: delay (msec) required after PCIe reset for stabilization + - ntn-rc-num: PCIe root complex number on which Neutrino is connected + +Optional properties: + - ntn-bus-num: PCIe bus number on which Neutrino is connected - ntn-rst-gpio: Neutrino reset GPIO - vdd-ntn-hsic-supply: neutrino HSIC power supply - vdd-ntn-pci-supply: PCIe core power supply @@ -25,4 +30,5 @@ Example: pinctrl-0 = <&ntn_default>; qcom,ntn-rst-delay-msec = <100>; qcom,ntn-rc-num = <1>; + qcom,ntn-bus-num = <1>; }; diff --git a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb2.txt b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb2.txt index 894c34553a22..b41219d51973 100644 --- a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb2.txt +++ b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb2.txt @@ -181,6 +181,12 @@ Charger specific properties: Definition: Specifies the maximum charger buck/boost switching frequency in KHz. It overrides the max frequency defined for the charger. +- qcom,otg-deglitch-time-ms + Usage: optional + Value type: <u32> + Definition: Specifies the deglitch interval for OTG detection. + If the value is not present, 50 msec is used as default. + ============================================= Second Level Nodes - SMB2 Charger Peripherals ============================================= diff --git a/Documentation/devicetree/bindings/soc/qcom/qpnp-haptic.txt b/Documentation/devicetree/bindings/soc/qcom/qpnp-haptic.txt index 337649824257..aa3363b52a03 100644 --- a/Documentation/devicetree/bindings/soc/qcom/qpnp-haptic.txt +++ b/Documentation/devicetree/bindings/soc/qcom/qpnp-haptic.txt @@ -76,6 +76,10 @@ Optional properties when qcom,actuator-type is "lra" at End of Pattern - qcom,lra-res-cal-period : Auto resonance calibration period. The values range from 4 to 32(default) +- qcom,lra-auto-mode : If this property is specified, haptics mode for LRA + actuators will be automatically configured along with + other required settings runtime based on the duration + of the pattern. - qcom,perform-lra-auto-resonance-search : boolean, define this property if: a) the underlying PMI chip does not have a register in the MISC block to read the error percentage in RC clock 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/Documentation/devicetree/bindings/usb/msm-phy.txt b/Documentation/devicetree/bindings/usb/msm-phy.txt index 032f07535415..88ad24900f28 100644 --- a/Documentation/devicetree/bindings/usb/msm-phy.txt +++ b/Documentation/devicetree/bindings/usb/msm-phy.txt @@ -212,6 +212,8 @@ Optional properties: - qcom,hold-reset: Indicates that hold QUSB PHY into reset state. - qcom,phy-clk-scheme: Should be one of "cml" or "cmos" if ref_clk_addr is provided. - qcom,major-rev: provide major revision number to differentiate power up sequence. default is 2.0 + - qcom,vdda33-voltage-level: A list of three integer values (min, op, max) representing + specific voltages (in microvolts) used for the vdda33 supply. Example: qusb_phy: qusb@f9b39000 { @@ -1,6 +1,6 @@ VERSION = 4 PATCHLEVEL = 4 -SUBLEVEL = 65 +SUBLEVEL = 67 EXTRAVERSION = NAME = Blurry Fish Butt diff --git a/android/configs/android-base.cfg b/android/configs/android-base.cfg index 67842e7007a8..73429a4b25b1 100644 --- a/android/configs/android-base.cfg +++ b/android/configs/android-base.cfg @@ -29,7 +29,6 @@ CONFIG_HIGH_RES_TIMERS=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_INET6_AH=y -CONFIG_INET6_DIAG_DESTROY=y CONFIG_INET6_ESP=y CONFIG_INET6_IPCOMP=y CONFIG_INET=y @@ -72,7 +71,6 @@ CONFIG_MODVERSIONS=y CONFIG_NET=y CONFIG_NETDEVICES=y CONFIG_NETFILTER=y -CONFIG_NETFILTER_TPROXY=y CONFIG_NETFILTER_XT_MATCH_COMMENT=y CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y CONFIG_NETFILTER_XT_MATCH_CONNMARK=y @@ -173,5 +171,4 @@ CONFIG_USB_CONFIGFS_F_MTP=y CONFIG_USB_CONFIGFS_F_PTP=y CONFIG_USB_CONFIGFS_UEVENT=y CONFIG_USB_GADGET=y -CONFIG_USB_OTG_WAKELOCK=y CONFIG_XFRM_USER=y diff --git a/arch/arc/include/asm/entry-arcv2.h b/arch/arc/include/asm/entry-arcv2.h index b5ff87e6f4b7..aee1a77934cf 100644 --- a/arch/arc/include/asm/entry-arcv2.h +++ b/arch/arc/include/asm/entry-arcv2.h @@ -16,6 +16,7 @@ ; ; Now manually save: r12, sp, fp, gp, r25 + PUSH r30 PUSH r12 ; Saving pt_regs->sp correctly requires some extra work due to the way @@ -72,6 +73,7 @@ POPAX AUX_USER_SP 1: POP r12 + POP r30 .endm diff --git a/arch/arc/include/asm/ptrace.h b/arch/arc/include/asm/ptrace.h index 69095da1fcfd..47111d565a95 100644 --- a/arch/arc/include/asm/ptrace.h +++ b/arch/arc/include/asm/ptrace.h @@ -84,7 +84,7 @@ struct pt_regs { unsigned long fp; unsigned long sp; /* user/kernel sp depending on where we came from */ - unsigned long r12; + unsigned long r12, r30; /*------- Below list auto saved by h/w -----------*/ unsigned long r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11; diff --git a/arch/arm/boot/dts/qcom/Makefile b/arch/arm/boot/dts/qcom/Makefile index 8e7f26bc85ae..c938988d6634 100644 --- a/arch/arm/boot/dts/qcom/Makefile +++ b/arch/arm/boot/dts/qcom/Makefile @@ -114,6 +114,8 @@ dtb-$(CONFIG_ARCH_MSM8996) += msm8996-v2-pmi8994-cdp.dtb \ apq8096-v3-pmi8996-mdm9x55-slimbus-mtp.dtb \ apq8096-v3-pmi8996-dragonboard.dtb +dtb-$(CONFIG_MSM_GVM_QUIN) += vplatform-lfv-msm8996.dtb + ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y) dtbo-$(CONFIG_ARCH_MSM8998) += \ msm8998-cdp-overlay.dtbo \ 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/msm-pm660.dtsi b/arch/arm/boot/dts/qcom/msm-pm660.dtsi index 9bdaedd72585..7fde74f3d570 100644 --- a/arch/arm/boot/dts/qcom/msm-pm660.dtsi +++ b/arch/arm/boot/dts/qcom/msm-pm660.dtsi @@ -547,6 +547,7 @@ qcom,rradc-base = <0x4500>; qcom,fg-esr-timer-awake = <96>; qcom,fg-esr-timer-asleep = <256>; + qcom,fg-esr-timer-charging = <96>; qcom,cycle-counter-en; status = "okay"; diff --git a/arch/arm/boot/dts/qcom/msm-pm660l.dtsi b/arch/arm/boot/dts/qcom/msm-pm660l.dtsi index 679149a78833..0f18ba5c94c7 100644 --- a/arch/arm/boot/dts/qcom/msm-pm660l.dtsi +++ b/arch/arm/boot/dts/qcom/msm-pm660l.dtsi @@ -380,9 +380,6 @@ qcom,led-name = "led:switch_1"; qcom,led-mask = <4>; qcom,default-led-trigger = "switch1_trigger"; - pinctrl-names = "led_enable","led_disable"; - pinctrl-0 = <&led_enable>; - pinctrl-1 = <&led_disable>; }; }; diff --git a/arch/arm/boot/dts/qcom/msm-pmi8998.dtsi b/arch/arm/boot/dts/qcom/msm-pmi8998.dtsi index 2d2b628ca815..ad32ab01c5fb 100644 --- a/arch/arm/boot/dts/qcom/msm-pmi8998.dtsi +++ b/arch/arm/boot/dts/qcom/msm-pmi8998.dtsi @@ -762,9 +762,6 @@ qcom,led-name = "led:switch_1"; qcom,led-mask = <4>; qcom,default-led-trigger = "switch1_trigger"; - pinctrl-names = "led_enable","led_disable"; - pinctrl-0 = <&led_enable>; - pinctrl-1 = <&led_disable>; }; }; }; diff --git a/arch/arm/boot/dts/qcom/msm8996-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..a1299027ae18 100644 --- a/arch/arm/boot/dts/qcom/msm8996-auto-cdp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996-auto-cdp.dtsi @@ -454,7 +454,7 @@ }; &soc { - qcom,ntn_avb { + ntn1: ntn_avb@1 { /* Neutrno device on RC1*/ compatible = "qcom,ntn_avb"; ntn-rst-gpio = <&pm8994_gpios 13 0>; @@ -465,6 +465,14 @@ qcom,ntn-rst-delay-msec = <100>; qcom,ntn-rc-num = <1>; + qcom,ntn-bus-num = <1>; + }; + + ntn2: ntn_avb@2 { /*Neutrino device on RC2*/ + compatible = "qcom,ntn_avb"; + qcom,ntn-rst-delay-msec = <100>; + qcom,ntn-rc-num = <2>; + qcom,ntn-bus-num = <1>; }; i2c@75ba000 { @@ -725,22 +733,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-regulator.dtsi b/arch/arm/boot/dts/qcom/msm8996-regulator.dtsi index c70003a0a6dd..b86542a174da 100644 --- a/arch/arm/boot/dts/qcom/msm8996-regulator.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996-regulator.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2016, 2017 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1950,4 +1950,21 @@ regulator-ramp-delay = <500>; status = "disabled"; }; + + ncp6335d_vreg: ncp6335d-regulator@68 { + compatible = "onnn,ncp6335d-regulator"; + reg = <0x68>; + vin-supply = <&hl7509_en_vreg>; + onnn,vsel = <0>; + onnn,slew-ns = <2666>; + onnn,step-size = <6250>; + onnn,min-slew-ns = <333>; + onnn,max-slew-ns = <2666>; + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <1143750>; + onnn,min-setpoint = <600000>; + onnn,discharge-enable; + onnn,restore-reg; + status = "disabled"; + }; }; diff --git a/arch/arm/boot/dts/qcom/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/msm8996pro.dtsi b/arch/arm/boot/dts/qcom/msm8996pro.dtsi index 2f29fabb7d7e..ca89a517df5c 100644 --- a/arch/arm/boot/dts/qcom/msm8996pro.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996pro.dtsi @@ -1505,5 +1505,62 @@ qcom,bus-max = <0>; }; }; + + qcom,gpu-pwrlevels-2 { + #address-cells = <1>; + #size-cells = <0>; + + qcom,speed-bin = <2>; + + qcom,initial-pwrlevel = <3>; + + qcom,gpu-pwrlevel@0 { + reg = <0>; + qcom,gpu-freq = <510000000>; + qcom,bus-freq = <11>; + qcom,bus-min = <11>; + qcom,bus-max = <11>; + }; + + qcom,gpu-pwrlevel@1 { + reg = <1>; + qcom,gpu-freq = <401800000>; + qcom,bus-freq = <8>; + qcom,bus-min = <7>; + qcom,bus-max = <9>; + }; + + qcom,gpu-pwrlevel@2 { + reg = <2>; + qcom,gpu-freq = <315000000>; + qcom,bus-freq = <6>; + qcom,bus-min = <5>; + qcom,bus-max = <7>; + }; + + qcom,gpu-pwrlevel@3 { + reg = <3>; + qcom,gpu-freq = <214000000>; + qcom,bus-freq = <4>; + qcom,bus-min = <3>; + qcom,bus-max = <5>; + }; + + qcom,gpu-pwrlevel@4 { + reg = <4>; + qcom,gpu-freq = <133000000>; + qcom,bus-freq = <3>; + qcom,bus-min = <2>; + qcom,bus-max = <4>; + }; + + qcom,gpu-pwrlevel@5 { + reg = <5>; + qcom,gpu-freq = <27000000>; + qcom,bus-freq = <0>; + qcom,bus-min = <0>; + qcom,bus-max = <0>; + }; + }; }; }; diff --git a/arch/arm/boot/dts/qcom/msm8998-camera-sensor-mtp.dtsi b/arch/arm/boot/dts/qcom/msm8998-camera-sensor-mtp.dtsi index d7372f2bb2e4..2095b4e07069 100644 --- a/arch/arm/boot/dts/qcom/msm8998-camera-sensor-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-camera-sensor-mtp.dtsi @@ -334,19 +334,22 @@ qcom,gpio-no-mux = <0>; pinctrl-names = "cam_default", "cam_suspend"; pinctrl-0 = <&cam_sensor_mclk1_active - &cam_sensor_front_active>; + &cam_sensor_front_active &led_enable>; pinctrl-1 = <&cam_sensor_mclk1_suspend - &cam_sensor_front_suspend>; + &cam_sensor_front_suspend &led_disable>; gpios = <&tlmm 14 0>, <&tlmm 28 0>, - <&pm8998_gpios 9 0>; + <&pm8998_gpios 9 0>, + <&tlmm 21 0>; qcom,gpio-reset = <1>; qcom,gpio-vdig = <2>; - qcom,gpio-req-tbl-num = <0 1 2>; - qcom,gpio-req-tbl-flags = <1 0 0>; + qcom,gpio-flash-en = <3>; + qcom,gpio-req-tbl-num = <0 1 2 3>; + qcom,gpio-req-tbl-flags = <1 0 0 0>; qcom,gpio-req-tbl-label = "CAMIF_MCLK2", "CAM_RESET2", - "CAM_VDIG"; + "CAM_VDIG", + "FLASH_EN"; qcom,sensor-position = <1>; qcom,sensor-mode = <0>; qcom,cci-master = <1>; @@ -356,6 +359,45 @@ clock-names = "cam_src_clk", "cam_clk"; qcom,clock-rates = <24000000 0>; }; + + qcom,camera@3 { + cell-index = <3>; + compatible = "qcom,camera"; + reg = <0x03>; + qcom,csiphy-sd-index = <1>; + qcom,csid-sd-index = <1>; + qcom,mount-angle = <270>; + qcom,led-flash-src = <&led_flash1>; + cam_vio-supply = <&pm8998_lvs1>; + cam_vana-supply = <&pm8998_l22>; + cam_vdig-supply = <&pm8998_s3>; + qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig"; + qcom,cam-vreg-min-voltage = + <0 2864000 1352000>; + qcom,cam-vreg-max-voltage = + <0 2864000 1352000>; + qcom,cam-vreg-op-mode = <0 80000 105000>; + qcom,gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk3_active + &cam_sensor_front_iris_active>; + pinctrl-1 = <&cam_sensor_mclk3_suspend + &cam_sensor_front_iris_suspend>; + gpios = <&tlmm 16 0>, + <&tlmm 23 0>; + qcom,gpio-reset = <1>; + qcom,gpio-req-tbl-num = <0 1>; + qcom,gpio-req-tbl-flags = <1 0>; + qcom,gpio-req-tbl-label = "CAMIF_MCLK3", + "CAM_RESET3"; + qcom,sensor-position = <1>; + qcom,sensor-mode = <0>; + qcom,cci-master = <1>; + clocks = <&clock_mmss clk_mclk3_clk_src>, + <&clock_mmss clk_mmss_camss_mclk3_clk>; + clock-names = "cam_src_clk", "cam_clk"; + qcom,clock-rates = <24000000 0>; + }; }; &pm8998_gpios { gpio@c800 { /* GPIO 9 - CAMERA SENSOR 2 VDIG */ diff --git a/arch/arm/boot/dts/qcom/msm8998-interposer-camera-sensor-mtp.dtsi b/arch/arm/boot/dts/qcom/msm8998-interposer-camera-sensor-mtp.dtsi index 722c18a26388..d00ae0f3730c 100644 --- a/arch/arm/boot/dts/qcom/msm8998-interposer-camera-sensor-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-interposer-camera-sensor-mtp.dtsi @@ -12,6 +12,12 @@ */ &soc { + /delete-node/qcom,camera-flash@0; + /delete-node/qcom,camera-flash@1; + /delete-node/gpio-regulator@0; +}; + +&soc { tlmm: pinctrl@03400000 { cam_sensor_rear_active: cam_sensor_rear_active { /* RESET, STANDBY */ @@ -132,19 +138,17 @@ }; }; -&soc { - /delete-node/gpio-regulator@0; -}; - &cci { /delete-node/qcom,camera@0; /delete-node/qcom,camera@1; /delete-node/qcom,camera@2; + /delete-node/qcom,camera@3; /delete-node/qcom,eeprom@0; /delete-node/qcom,eeprom@1; /delete-node/qcom,eeprom@2; /delete-node/qcom,actuator@0; /delete-node/qcom,actuator@1; + /delete-node/qcom,tof@0; /delete-node/qcom,ois@0; }; diff --git a/arch/arm/boot/dts/qcom/msm8998-interposer-camera-sensor-qrd.dtsi b/arch/arm/boot/dts/qcom/msm8998-interposer-camera-sensor-qrd.dtsi index 8b68ece2239f..42414db3cc48 100644 --- a/arch/arm/boot/dts/qcom/msm8998-interposer-camera-sensor-qrd.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-interposer-camera-sensor-qrd.dtsi @@ -12,6 +12,12 @@ */ &soc { + /delete-node/qcom,camera-flash@0; + /delete-node/qcom,camera-flash@1; + /delete-node/gpio-regulator@0; +}; + +&soc { tlmm: pinctrl@03400000 { cam_sensor_rear_active: cam_sensor_rear_active { /* RESET, STANDBY */ @@ -170,19 +176,17 @@ }; }; -&soc { - /delete-node/gpio-regulator@0; -}; - &cci { /delete-node/qcom,camera@0; /delete-node/qcom,camera@1; /delete-node/qcom,camera@2; + /delete-node/qcom,camera@3; /delete-node/qcom,eeprom@0; /delete-node/qcom,eeprom@1; /delete-node/qcom,eeprom@2; /delete-node/qcom,actuator@0; /delete-node/qcom,actuator@1; + /delete-node/qcom,tof@0; /delete-node/qcom,ois@0; }; diff --git a/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi b/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi index cdf4bede6eb3..318dc5d7c791 100644 --- a/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi @@ -996,7 +996,7 @@ cam_sensor_mclk0_active: cam_sensor_mclk0_active { /* MCLK0 */ mux { - /* CLK, DATA */ + /* CLK */ pins = "gpio13"; function = "cam_mclk"; }; @@ -1011,7 +1011,7 @@ cam_sensor_mclk0_suspend: cam_sensor_mclk0_suspend { /* MCLK0 */ mux { - /* CLK, DATA */ + /* CLK */ pins = "gpio13"; function = "cam_mclk"; }; @@ -1305,7 +1305,7 @@ cam_sensor_mclk1_active: cam_sensor_mclk1_active { /* MCLK1 */ mux { - /* CLK, DATA */ + /* CLK */ pins = "gpio14"; function = "cam_mclk"; }; @@ -1320,7 +1320,7 @@ cam_sensor_mclk1_suspend: cam_sensor_mclk1_suspend { /* MCLK1 */ mux { - /* CLK, DATA */ + /* CLK */ pins = "gpio14"; function = "cam_mclk"; }; @@ -1332,6 +1332,36 @@ }; }; + cam_sensor_mclk3_active: cam_sensor_mclk3_active { + /* MCLK3 */ + mux { + /* CLK */ + pins = "gpio16"; + function = "cam_mclk"; + }; + + config { + pins = "gpio16"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk3_suspend: cam_sensor_mclk3_suspend { + /* MCLK3 */ + mux { + /* CLK */ + pins = "gpio16"; + function = "cam_mclk"; + }; + + config { + pins = "gpio16"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + cam_sensor_rear2_active: cam_sensor_rear2_active { /* RESET, STANDBY */ mux { @@ -1468,7 +1498,7 @@ cam_sensor_mclk2_active: cam_sensor_mclk2_active { /* MCLK1 */ mux { - /* CLK, DATA */ + /* CLK */ pins = "gpio15"; function = "cam_mclk"; }; @@ -1483,7 +1513,7 @@ cam_sensor_mclk2_suspend: cam_sensor_mclk2_suspend { /* MCLK1 */ mux { - /* CLK, DATA */ + /* CLK */ pins = "gpio15"; function = "cam_mclk"; }; @@ -1509,6 +1539,21 @@ }; }; + + cam_sensor_front_iris_active: cam_sensor_front_iris_active { + /* RESET */ + mux { + pins = "gpio23"; + function = "gpio"; + }; + + config { + pins = "gpio23"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + blsp2_uart1_active: blsp2_uart1_active { mux { pins = "gpio53", "gpio54", "gpio55", "gpio56"; @@ -1575,6 +1620,20 @@ }; }; + cam_sensor_front_iris_suspend: cam_sensor_front_iris_suspend { + /* RESET */ + mux { + pins = "gpio23"; + function = "gpio"; + }; + + config { + pins = "gpio23"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + pmx_mdss: pmx_mdss { mdss_dsi_active: mdss_dsi_active { mux { diff --git a/arch/arm/boot/dts/qcom/msm8998.dtsi b/arch/arm/boot/dts/qcom/msm8998.dtsi index c25f3ebcb113..c1d785e42669 100644 --- a/arch/arm/boot/dts/qcom/msm8998.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998.dtsi @@ -3200,6 +3200,10 @@ <&clock_gcc clk_rf_clk3_pin>; clock-names = "rf_clk3_clk", "rf_clk3_pin_clk"; qcom,smmu-support; + qcom,smmu-s1-en; + qcom,smmu-fast-map; + qcom,smmu-coherent; + qcom,smmu-mapping = <0x20000000 0xe0000000>; status = "disabled"; }; diff --git a/arch/arm/boot/dts/qcom/sda660-pm660a-qrd-hdk.dts b/arch/arm/boot/dts/qcom/sda660-pm660a-qrd-hdk.dts index a767853cd829..c2bf2c4a088e 100644 --- a/arch/arm/boot/dts/qcom/sda660-pm660a-qrd-hdk.dts +++ b/arch/arm/boot/dts/qcom/sda660-pm660a-qrd-hdk.dts @@ -17,6 +17,143 @@ #include "sdm660-qrd.dtsi" #include "msm-pm660a.dtsi" +&smb1351_charger { + status = "disabled"; +}; + +&i2c_2 { + smb138x: qcom,smb138x@8 { + compatible = "qcom,i2c-pmic"; + reg = <0x8>; + #address-cells = <1>; + #size-cells = <1>; + interrupt-parent = <&tlmm>; + interrupts = <21 IRQ_TYPE_LEVEL_LOW>; + interrupt_names = "smb138x"; + interrupt-controller; + #interrupt-cells = <3>; + qcom,periph-map = <0x10 0x11 0x12 0x13 0x14 0x16 0x36>; + pinctrl-names = "default"; + pinctrl-0 = <&smb_int_default>; + + smb138x_revid: qcom,revid@100 { + compatible = "qcom,qpnp-revid"; + reg = <0x100 0x100>; + }; + + smb138x_tadc: qcom,tadc@3600 { + compatible = "qcom,tadc"; + reg = <0x3600 0x100>; + #address-cells = <1>; + #size-cells = <0>; + #io-channel-cells = <1>; + interrupt-parent = <&smb138x>; + interrupts = <0x36 0x0 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "eoc"; + + batt_temp@0 { + reg = <0>; + qcom,rbias = <68100>; + qcom,rtherm-at-25degc = <68000>; + qcom,beta-coefficient = <3450>; + }; + + skin_temp@1 { + reg = <1>; + qcom,rbias = <33000>; + qcom,rtherm-at-25degc = <68000>; + qcom,beta-coefficient = <3450>; + }; + + die_temp@2 { + reg = <2>; + qcom,scale = <(-1306)>; + qcom,offset = <397904>; + }; + + batt_i@3 { + reg = <3>; + qcom,channel = <3>; + qcom,scale = <(-20000000)>; + }; + + batt_v@4 { + reg = <4>; + qcom,scale = <5000000>; + }; + + input_i@5 { + reg = <5>; + qcom,scale = <14285714>; + }; + + input_v@6 { + reg = <6>; + qcom,scale = <25000000>; + }; + + otg_i@7 { + reg = <7>; + qcom,scale = <5714286>; + }; + }; + + smb138x_parallel_slave: qcom,smb138x-parallel-slave@1000 { + compatible = "qcom,smb138x-parallel-slave"; + qcom,pmic-revid = <&smb138x_revid>; + reg = <0x1000 0x700>; + #address-cells = <1>; + #size-cells = <1>; + interrupt-parent = <&smb138x>; + io-channels = + <&smb138x_tadc 1>, + <&smb138x_tadc 2>, + <&smb138x_tadc 3>, + <&smb138x_tadc 14>, + <&smb138x_tadc 15>, + <&smb138x_tadc 16>, + <&smb138x_tadc 17>; + io-channel-names = + "connector_temp", + "charger_temp", + "batt_i", + "connector_temp_thr1", + "connector_temp_thr2", + "connector_temp_thr3", + "charger_temp_max"; + + qcom,chgr@1000 { + reg = <0x1000 0x100>; + interrupts = <0x10 0x1 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "chg-state-change"; + }; + + qcom,chgr-misc@1600 { + reg = <0x1600 0x100>; + interrupts = <0x16 0x1 IRQ_TYPE_EDGE_RISING>, + <0x16 0x6 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "wdog-bark", + "temperature-change"; + }; + }; + }; +}; + +&tlmm { + smb_int_default: smb_int_default { + mux { + pins = "gpio21"; + function = "gpio"; + }; + + config { + pins = "gpio21"; + drive-strength = <2>; + bias-pull-up; + }; + }; +}; + / { model = "Qualcomm Technologies, Inc. SDA 660 PM660 + PM660A QRD HDK660"; compatible = "qcom,sda660-qrd", "qcom,sda660", "qcom,qrd"; diff --git a/arch/arm/boot/dts/qcom/sdm630-mdss.dtsi b/arch/arm/boot/dts/qcom/sdm630-mdss.dtsi index d35704224f45..49e4fd7e5ba7 100644 --- a/arch/arm/boot/dts/qcom/sdm630-mdss.dtsi +++ b/arch/arm/boot/dts/qcom/sdm630-mdss.dtsi @@ -112,13 +112,14 @@ clocks = <&clock_mmss MMSS_MNOC_AHB_CLK>, <&clock_mmss MMSS_MDSS_AHB_CLK>, <&clock_mmss MMSS_MDSS_AXI_CLK>, + <&clock_mmss MMSS_THROTTLE_MDSS_AXI_CLK>, <&clock_mmss MDP_CLK_SRC>, <&clock_mmss MMSS_MDSS_MDP_CLK>, <&clock_mmss MMSS_MDSS_VSYNC_CLK>, <&clock_mmss MDP_CLK_SRC>; clock-names = "mnoc_clk", "iface_clk", "bus_clk", - "core_clk_src", "core_clk", "vsync_clk", - "lut_clk"; + "throttle_bus_clk", "core_clk_src", + "core_clk", "vsync_clk", "lut_clk"; qcom,mdp-settings = <0x01190 0x00000000>, <0x012ac 0xc0000ccc>, diff --git a/arch/arm/boot/dts/qcom/sdm630-qrd.dtsi b/arch/arm/boot/dts/qcom/sdm630-qrd.dtsi index c677df529dd7..c24a41656f3a 100644 --- a/arch/arm/boot/dts/qcom/sdm630-qrd.dtsi +++ b/arch/arm/boot/dts/qcom/sdm630-qrd.dtsi @@ -159,6 +159,7 @@ &pm660_fg { qcom,battery-data = <&qrd_batterydata>; qcom,fg-jeita-thresholds = <0 5 55 55>; + qcom,battery-thermal-coefficients = [9d 50 ff]; }; &uartblsp1dm1 { @@ -395,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/sdm630.dtsi b/arch/arm/boot/dts/qcom/sdm630.dtsi index 24a935ffebec..9897900d3fd5 100644 --- a/arch/arm/boot/dts/qcom/sdm630.dtsi +++ b/arch/arm/boot/dts/qcom/sdm630.dtsi @@ -1323,7 +1323,7 @@ < 1670400000 0x04040057 0x08450045 0x2 6 >, < 1881600000 0x04040062 0x094e004e 0x2 7 >, < 2016000000 0x04040069 0x0a540054 0x2 8 >, - < 2150400000 0x04040070 0x0b590059 0x2 8 >, + < 2150400000 0x04040070 0x0b590059 0x2 9 >, < 2208000000 0x04040073 0x0b5c005c 0x3 10 >; qcom,perfcl-speedbin2-v0 = diff --git a/arch/arm/boot/dts/qcom/sdm660-camera-sensor-mtp.dtsi b/arch/arm/boot/dts/qcom/sdm660-camera-sensor-mtp.dtsi index 191beaa4d53b..3d37d169a97c 100644 --- a/arch/arm/boot/dts/qcom/sdm660-camera-sensor-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-camera-sensor-mtp.dtsi @@ -29,6 +29,36 @@ qcom,switch-source = <&pm660l_switch1>; status = "ok"; }; + + cam_avdd_gpio_regulator: cam_avdd_fixed_regulator { + compatible = "regulator-fixed"; + regulator-name = "cam_avdd_gpio_regulator"; + regulator-min-microvolt = <3600000>; + regulator-max-microvolt = <3600000>; + enable-active-high; + gpio = <&tlmm 51 0>; + vin-supply = <&pm660l_bob>; + }; + + cam_dvdd_gpio_regulator: cam_dvdd_fixed_regulator { + compatible = "regulator-fixed"; + regulator-name = "cam_dvdd_gpio_regulator"; + regulator-min-microvolt = <1350000>; + regulator-max-microvolt = <1350000>; + enable-active-high; + gpio = <&pm660l_gpios 3 0>; + vin-supply = <&pm660_s5>; + }; + + cam_rear_dvdd_gpio_regulator: cam_rear_dvdd_fixed_regulator { + compatible = "regulator-fixed"; + regulator-name = "cam_rear_dvdd_gpio_regulator"; + regulator-min-microvolt = <1350000>; + regulator-max-microvolt = <1350000>; + enable-active-high; + gpio = <&pm660l_gpios 4 0>; + vin-supply = <&pm660_s5>; + }; }; &cci { @@ -98,12 +128,12 @@ reg = <0>; compatible = "qcom,eeprom"; cam_vio-supply = <&pm660_l11>; - cam_vana-supply = <&pm660l_bob>; - cam_vdig-supply = <&pm660_s5>; + cam_vana-supply = <&cam_avdd_gpio_regulator>; + cam_vdig-supply = <&cam_rear_dvdd_gpio_regulator>; qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig"; - qcom,cam-vreg-min-voltage = <1780000 3300000 1350000>; - qcom,cam-vreg-max-voltage = <1950000 3600000 1350000>; - qcom,cam-vreg-op-mode = <105000 80000 105000>; + qcom,cam-vreg-min-voltage = <1780000 0 0>; + qcom,cam-vreg-max-voltage = <1950000 0 0>; + qcom,cam-vreg-op-mode = <105000 0 0>; qcom,gpio-no-mux = <0>; pinctrl-names = "cam_default", "cam_suspend"; pinctrl-0 = <&cam_sensor_mclk0_active @@ -114,19 +144,13 @@ &cam_actuator_vaf_suspend>; gpios = <&tlmm 32 0>, <&tlmm 46 0>, - <&pm660l_gpios 4 0>, - <&tlmm 51 0>, <&tlmm 50 0>; qcom,gpio-reset = <1>; - qcom,gpio-vdig = <2>; - qcom,gpio-vana = <3>; - qcom,gpio-vaf = <4>; - qcom,gpio-req-tbl-num = <0 1 2 3 4>; - qcom,gpio-req-tbl-flags = <1 0 0 0 0>; + qcom,gpio-vaf = <2>; + qcom,gpio-req-tbl-num = <0 1 2>; + qcom,gpio-req-tbl-flags = <1 0 0>; qcom,gpio-req-tbl-label = "CAMIF_MCLK0", "CAM_RESET0", - "CAM_VDIG", - "CAM_VANA", "CAM_VAF"; qcom,sensor-position = <0>; qcom,sensor-mode = <0>; @@ -143,12 +167,12 @@ reg = <0x1>; compatible = "qcom,eeprom"; cam_vio-supply = <&pm660_l11>; - cam_vana-supply = <&pm660l_bob>; - cam_vdig-supply = <&pm660_s5>; + cam_vana-supply = <&cam_avdd_gpio_regulator>; + cam_vdig-supply = <&cam_dvdd_gpio_regulator>; qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig"; - qcom,cam-vreg-min-voltage = <1780000 3300000 1350000>; - qcom,cam-vreg-max-voltage = <1950000 3600000 1350000>; - qcom,cam-vreg-op-mode = <105000 80000 105000>; + qcom,cam-vreg-min-voltage = <1780000 0 0>; + qcom,cam-vreg-max-voltage = <1950000 0 0>; + qcom,cam-vreg-op-mode = <105000 0 0>; qcom,gpio-no-mux = <0>; pinctrl-names = "cam_default", "cam_suspend"; pinctrl-0 = <&cam_sensor_mclk2_active @@ -156,18 +180,12 @@ pinctrl-1 = <&cam_sensor_mclk2_suspend &cam_sensor_rear2_suspend>; gpios = <&tlmm 34 0>, - <&tlmm 48 0>, - <&pm660l_gpios 3 0>, - <&tlmm 51 0>; + <&tlmm 48 0>; qcom,gpio-reset = <1>; - qcom,gpio-vdig = <2>; - qcom,gpio-vana = <3>; - qcom,gpio-req-tbl-num = <0 1 2 3>; - qcom,gpio-req-tbl-flags = <1 0 0 0>; + qcom,gpio-req-tbl-num = <0 1>; + qcom,gpio-req-tbl-flags = <1 0>; qcom,gpio-req-tbl-label = "CAMIF_MCLK", - "CAM_RESET", - "CAM_VDIG", - "CAM_VANA"; + "CAM_RESET"; qcom,sensor-position = <0>; qcom,sensor-mode = <0>; qcom,cci-master = <1>; @@ -184,11 +202,11 @@ compatible = "qcom,eeprom"; cam_vio-supply = <&pm660_l11>; cam_vana-supply = <&pm660l_bob>; - cam_vdig-supply = <&pm660_s5>; + cam_vdig-supply = <&cam_dvdd_gpio_regulator>; qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig"; - qcom,cam-vreg-min-voltage = <1780000 3300000 1350000>; - qcom,cam-vreg-max-voltage = <1950000 3600000 1350000>; - qcom,cam-vreg-op-mode = <105000 80000 105000>; + qcom,cam-vreg-min-voltage = <1780000 3300000 0>; + qcom,cam-vreg-max-voltage = <1950000 3600000 0>; + qcom,cam-vreg-op-mode = <105000 80000 0>; qcom,gpio-no-mux = <0>; pinctrl-names = "cam_default", "cam_suspend"; pinctrl-0 = <&cam_sensor_mclk1_active @@ -199,18 +217,15 @@ &cam_actuator_vaf_suspend>; gpios = <&tlmm 33 0>, <&tlmm 47 0>, - <&pm660_gpios 3 0>, <&tlmm 44 0>, <&tlmm 50 0>; qcom,gpio-reset = <1>; - qcom,gpio-vdig = <2>; - qcom,gpio-vana = <3>; - qcom,gpio-vaf = <4>; - qcom,gpio-req-tbl-num = <0 1 2 3 4>; - qcom,gpio-req-tbl-flags = <1 0 0 0 0>; + qcom,gpio-vana = <2>; + qcom,gpio-vaf = <3>; + qcom,gpio-req-tbl-num = <0 1 2 3>; + qcom,gpio-req-tbl-flags = <1 0 0 0>; qcom,gpio-req-tbl-label = "CAMIF_MCLK2", "CAM_RESET2", - "CAM_VDIG", "CAM_VANA", "CAM_VAF"; qcom,sensor-position = <1>; @@ -235,12 +250,12 @@ qcom,ois-src = <&ois0>; qcom,eeprom-src = <&eeprom0>; cam_vio-supply = <&pm660_l11>; - cam_vana-supply = <&pm660l_bob>; - cam_vdig-supply = <&pm660_s5>; + cam_vana-supply = <&cam_avdd_gpio_regulator>; + cam_vdig-supply = <&cam_rear_dvdd_gpio_regulator>; qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig"; - qcom,cam-vreg-min-voltage = <1780000 3300000 1350000>; - qcom,cam-vreg-max-voltage = <1950000 3600000 1350000>; - qcom,cam-vreg-op-mode = <105000 80000 105000>; + qcom,cam-vreg-min-voltage = <1780000 0 0>; + qcom,cam-vreg-max-voltage = <1950000 0 0>; + qcom,cam-vreg-op-mode = <105000 0 0>; qcom,gpio-no-mux = <0>; pinctrl-names = "cam_default", "cam_suspend"; pinctrl-0 = <&cam_sensor_mclk0_active @@ -248,18 +263,12 @@ pinctrl-1 = <&cam_sensor_mclk0_suspend &cam_sensor_rear_suspend>; gpios = <&tlmm 32 0>, - <&tlmm 46 0>, - <&pm660l_gpios 4 0>, - <&tlmm 51 0>; + <&tlmm 46 0>; qcom,gpio-reset = <1>; - qcom,gpio-vdig = <2>; - qcom,gpio-vana = <3>; - qcom,gpio-req-tbl-num = <0 1 2 3>; - qcom,gpio-req-tbl-flags = <1 0 0 0>; + qcom,gpio-req-tbl-num = <0 1>; + qcom,gpio-req-tbl-flags = <1 0>; qcom,gpio-req-tbl-label = "CAMIF_MCLK0", - "CAM_RESET0", - "CAM_VDIG", - "CAM_VANA"; + "CAM_RESET0"; qcom,sensor-position = <0>; qcom,sensor-mode = <0>; qcom,cci-master = <0>; @@ -280,12 +289,12 @@ qcom,actuator-src = <&actuator1>; qcom,eeprom-src = <&eeprom1>; cam_vio-supply = <&pm660_l11>; - cam_vana-supply = <&pm660l_bob>; - cam_vdig-supply = <&pm660_s5>; + cam_vana-supply = <&cam_avdd_gpio_regulator>; + cam_vdig-supply = <&cam_dvdd_gpio_regulator>; qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig"; - qcom,cam-vreg-min-voltage = <1780000 3300000 1350000>; - qcom,cam-vreg-max-voltage = <1950000 3600000 1350000>; - qcom,cam-vreg-op-mode = <105000 80000 105000>; + qcom,cam-vreg-min-voltage = <1780000 0 0>; + qcom,cam-vreg-max-voltage = <1950000 0 0>; + qcom,cam-vreg-op-mode = <105000 0 0>; qcom,gpio-no-mux = <0>; pinctrl-names = "cam_default", "cam_suspend"; pinctrl-0 = <&cam_sensor_mclk2_active @@ -293,18 +302,12 @@ pinctrl-1 = <&cam_sensor_mclk2_suspend &cam_sensor_rear2_suspend>; gpios = <&tlmm 34 0>, - <&tlmm 48 0>, - <&pm660l_gpios 3 0>, - <&tlmm 51 0>; + <&tlmm 48 0>; qcom,gpio-reset = <1>; - qcom,gpio-vdig = <2>; - qcom,gpio-vana = <3>; - qcom,gpio-req-tbl-num = <0 1 2 3>; - qcom,gpio-req-tbl-flags = <1 0 0 0>; + qcom,gpio-req-tbl-num = <0 1>; + qcom,gpio-req-tbl-flags = <1 0>; qcom,gpio-req-tbl-label = "CAMIF_MCLK", - "CAM_RESET", - "CAM_VDIG", - "CAM_VANA"; + "CAM_RESET"; qcom,sensor-position = <0>; qcom,sensor-mode = <0>; qcom,cci-master = <1>; @@ -325,12 +328,12 @@ qcom,actuator-src = <&actuator2>; qcom,eeprom-src = <&eeprom2>; cam_vio-supply = <&pm660_l11>; - cam_vana-supply = <&pm660l_bob>; - cam_vdig-supply = <&pm660_s5>; + cam_vana-supply = <&cam_avdd_gpio_regulator>; + cam_vdig-supply = <&cam_dvdd_gpio_regulator>; qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig"; - qcom,cam-vreg-min-voltage = <1780000 3300000 1350000>; - qcom,cam-vreg-max-voltage = <1950000 3600000 1350000>; - qcom,cam-vreg-op-mode = <105000 80000 105000>; + qcom,cam-vreg-min-voltage = <1780000 0 0>; + qcom,cam-vreg-max-voltage = <1950000 0 0>; + qcom,cam-vreg-op-mode = <105000 0 0>; qcom,gpio-no-mux = <0>; pinctrl-names = "cam_default", "cam_suspend"; pinctrl-0 = <&cam_sensor_mclk1_active @@ -338,18 +341,12 @@ pinctrl-1 = <&cam_sensor_mclk1_suspend &cam_sensor_front_suspend>; gpios = <&tlmm 33 0>, - <&tlmm 47 0>, - <&pm660l_gpios 3 0>, - <&tlmm 51 0>; + <&tlmm 47 0>; qcom,gpio-reset = <1>; - qcom,gpio-vdig = <2>; - qcom,gpio-vana = <3>; - qcom,gpio-req-tbl-num = <0 1 2 3>; - qcom,gpio-req-tbl-flags = <1 0 0 0>; + qcom,gpio-req-tbl-num = <0 1>; + qcom,gpio-req-tbl-flags = <1 0>; qcom,gpio-req-tbl-label = "CAMIF_MCLK2", - "CAM_RESET2", - "CAM_VDIG", - "CAM_VANA"; + "CAM_RESET2"; qcom,sensor-position = <1>; qcom,sensor-mode = <0>; qcom,cci-master = <1>; @@ -359,6 +356,45 @@ clock-names = "cam_src_clk", "cam_clk"; qcom,clock-rates = <24000000 0>; }; + + qcom,camera@3 { + cell-index = <3>; + compatible = "qcom,camera"; + reg = <0x03>; + qcom,csiphy-sd-index = <1>; + qcom,csid-sd-index = <1>; + qcom,mount-angle = <90>; + qcom,led-flash-src = <&led_flash1>; + qcom,actuator-src = <&actuator2>; + qcom,eeprom-src = <&eeprom2>; + cam_vio-supply = <&pm660_l11>; + cam_vana-supply = <&cam_avdd_gpio_regulator>; + cam_vdig-supply = <&cam_dvdd_gpio_regulator>; + qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig"; + qcom,cam-vreg-min-voltage = <1780000 0 0>; + qcom,cam-vreg-max-voltage = <1950000 0 0>; + qcom,cam-vreg-op-mode = <105000 0 0>; + qcom,gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk3_active + &cam_sensor_front_iris_active>; + pinctrl-1 = <&cam_sensor_mclk3_suspend + &cam_sensor_front_iris_suspend>; + gpios = <&tlmm 35 0>, + <&tlmm 52 0>; + qcom,gpio-reset = <1>; + qcom,gpio-req-tbl-num = <0 1>; + qcom,gpio-req-tbl-flags = <1 0>; + qcom,gpio-req-tbl-label = "CAMIF_MCLK3", + "CAM_RESET3"; + qcom,sensor-position = <1>; + qcom,sensor-mode = <0>; + qcom,cci-master = <1>; + clocks = <&clock_mmss MCLK3_CLK_SRC>, + <&clock_mmss MMSS_CAMSS_MCLK3_CLK>; + clock-names = "cam_src_clk", "cam_clk"; + qcom,clock-rates = <24000000 0>; + }; }; &pm660l_gpios { diff --git a/arch/arm/boot/dts/qcom/sdm660-camera.dtsi b/arch/arm/boot/dts/qcom/sdm660-camera.dtsi index f3b81b5df1de..8ad33a5cb68a 100644 --- a/arch/arm/boot/dts/qcom/sdm660-camera.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-camera.dtsi @@ -514,7 +514,8 @@ camss-vdd-supply = <&gdsc_camss_top>; smmu-vdd-supply = <&gdsc_bimc_smmu>; qcom,vdd-names = "vdd", "camss-vdd", "smmu-vdd"; - clocks = <&clock_rpmcc MMSSNOC_AXI_CLK>, + clocks = <&clock_mmss MMSS_THROTTLE_CAMSS_AXI_CLK>, + <&clock_rpmcc MMSSNOC_AXI_CLK>, <&clock_mmss MMSS_MNOC_AHB_CLK>, <&clock_mmss MMSS_BIMC_SMMU_AHB_CLK>, <&clock_mmss MMSS_BIMC_SMMU_AXI_CLK>, @@ -527,16 +528,17 @@ <&clock_mmss MMSS_CAMSS_VFE_VBIF_AHB_CLK>, <&clock_mmss MMSS_CAMSS_VFE_VBIF_AXI_CLK>, <&clock_mmss MMSS_CAMSS_CSI_VFE0_CLK>; - clock-names = "mmssnoc_axi", "mnoc_ahb_clk", - "bimc_smmu_ahb_clk", "bimc_smmu_axi_clk", - "camss_ahb_clk", "camss_top_ahb_clk", "vfe_clk_src", + clock-names = "mmss_throttle_camss_axi_clk", "mmssnoc_axi", + "mnoc_ahb_clk", "bimc_smmu_ahb_clk", + "bimc_smmu_axi_clk", "camss_ahb_clk", + "camss_top_ahb_clk", "vfe_clk_src", "camss_vfe_clk", "camss_vfe_stream_clk", "camss_vfe_ahb_clk", "camss_vfe_vbif_ahb_clk", "camss_vfe_vbif_axi_clk", "camss_csi_vfe_clk"; - qcom,clock-rates = <0 0 0 0 0 0 404000000 0 0 0 0 0 0 - 0 0 0 0 0 0 480000000 0 0 0 0 0 0 - 0 0 0 0 0 0 576000000 0 0 0 0 0 0>; + qcom,clock-rates = <0 0 0 0 0 0 0 404000000 0 0 0 0 0 0 + 0 0 0 0 0 0 0 480000000 0 0 0 0 0 0 + 0 0 0 0 0 0 0 576000000 0 0 0 0 0 0>; status = "ok"; qos-entries = <8>; qos-regs = <0x404 0x408 0x40c 0x410 0x414 0x418 @@ -595,7 +597,8 @@ camss-vdd-supply = <&gdsc_camss_top>; smmu-vdd-supply = <&gdsc_bimc_smmu>; qcom,vdd-names = "vdd", "camss-vdd", "smmu-vdd"; - clocks = <&clock_rpmcc MMSSNOC_AXI_CLK>, + clocks = <&clock_mmss MMSS_THROTTLE_CAMSS_AXI_CLK>, + <&clock_rpmcc MMSSNOC_AXI_CLK>, <&clock_mmss MMSS_MNOC_AHB_CLK>, <&clock_mmss MMSS_BIMC_SMMU_AHB_CLK>, <&clock_mmss MMSS_BIMC_SMMU_AXI_CLK>, @@ -608,16 +611,17 @@ <&clock_mmss MMSS_CAMSS_VFE_VBIF_AHB_CLK>, <&clock_mmss MMSS_CAMSS_VFE_VBIF_AXI_CLK>, <&clock_mmss MMSS_CAMSS_CSI_VFE1_CLK>; - clock-names = "mmssnoc_axi", "mnoc_ahb_clk", - "bimc_smmu_ahb_clk", "bimc_smmu_axi_clk", - "camss_ahb_clk", "camss_top_ahb_clk", "vfe_clk_src", + clock-names = "mmss_throttle_camss_axi_clk", "mmssnoc_axi", + "mnoc_ahb_clk", "bimc_smmu_ahb_clk", + "bimc_smmu_axi_clk", "camss_ahb_clk", + "camss_top_ahb_clk", "vfe_clk_src", "camss_vfe_clk", "camss_vfe_stream_clk", "camss_vfe_ahb_clk", "camss_vfe_vbif_ahb_clk", "camss_vfe_vbif_axi_clk", "camss_csi_vfe_clk"; - qcom,clock-rates = <0 0 0 0 0 0 404000000 0 0 0 0 0 0 - 0 0 0 0 0 0 480000000 0 0 0 0 0 0 - 0 0 0 0 0 0 576000000 0 0 0 0 0 0>; + qcom,clock-rates = <0 0 0 0 0 0 0 404000000 0 0 0 0 0 0 + 0 0 0 0 0 0 0 480000000 0 0 0 0 0 0 + 0 0 0 0 0 0 0 576000000 0 0 0 0 0 0>; status = "ok"; qos-entries = <8>; qos-regs = <0x404 0x408 0x40c 0x410 0x414 0x418 diff --git a/arch/arm/boot/dts/qcom/sdm660-mdss.dtsi b/arch/arm/boot/dts/qcom/sdm660-mdss.dtsi index 787c4f1e2fb6..ab4e71e3cd65 100644 --- a/arch/arm/boot/dts/qcom/sdm660-mdss.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-mdss.dtsi @@ -117,13 +117,14 @@ clocks = <&clock_mmss MMSS_MNOC_AHB_CLK>, <&clock_mmss MMSS_MDSS_AHB_CLK>, <&clock_mmss MMSS_MDSS_AXI_CLK>, + <&clock_mmss MMSS_THROTTLE_MDSS_AXI_CLK>, <&clock_mmss MDP_CLK_SRC>, <&clock_mmss MMSS_MDSS_MDP_CLK>, <&clock_mmss MMSS_MDSS_VSYNC_CLK>, <&clock_mmss MDP_CLK_SRC>; clock-names = "mnoc_clk", "iface_clk", "bus_clk", - "core_clk_src", "core_clk", "vsync_clk", - "lut_clk"; + "throttle_bus_clk", "core_clk_src", + "core_clk", "vsync_clk", "lut_clk"; qcom,mdp-settings = <0x01190 0x00000000>, <0x012ac 0xc0000ccc>, diff --git a/arch/arm/boot/dts/qcom/sdm660-pinctrl.dtsi b/arch/arm/boot/dts/qcom/sdm660-pinctrl.dtsi index efe58563a1f3..d902078b1048 100644 --- a/arch/arm/boot/dts/qcom/sdm660-pinctrl.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-pinctrl.dtsi @@ -1104,7 +1104,7 @@ cam_sensor_mclk0_active: cam_sensor_mclk0_active { /* MCLK0 */ mux { - /* CLK, DATA */ + /* CLK */ pins = "gpio32"; function = "cam_mclk"; }; @@ -1119,7 +1119,7 @@ cam_sensor_mclk0_suspend: cam_sensor_mclk0_suspend { /* MCLK0 */ mux { - /* CLK, DATA */ + /* CLK */ pins = "gpio32"; function = "cam_mclk"; }; @@ -1162,7 +1162,7 @@ cam_sensor_mclk1_active: cam_sensor_mclk1_active { /* MCLK1 */ mux { - /* CLK, DATA */ + /* CLK */ pins = "gpio33"; function = "cam_mclk"; }; @@ -1177,7 +1177,7 @@ cam_sensor_mclk1_suspend: cam_sensor_mclk1_suspend { /* MCLK1 */ mux { - /* CLK, DATA */ + /* CLK */ pins = "gpio33"; function = "cam_mclk"; }; @@ -1219,7 +1219,7 @@ cam_sensor_mclk2_active: cam_sensor_mclk2_active { /* MCLK1 */ mux { - /* CLK, DATA */ + /* CLK */ pins = "gpio34"; function = "cam_mclk"; }; @@ -1234,7 +1234,7 @@ cam_sensor_mclk2_suspend: cam_sensor_mclk2_suspend { /* MCLK1 */ mux { - /* CLK, DATA */ + /* CLK */ pins = "gpio34"; function = "cam_mclk"; }; @@ -1274,6 +1274,64 @@ }; }; + cam_sensor_mclk3_active: cam_sensor_mclk3_active { + /* MCLK3 */ + mux { + /* CLK */ + pins = "gpio35"; + function = "cam_mclk"; + }; + + config { + pins = "gpio35"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk3_suspend: cam_sensor_mclk3_suspend { + /* MCLK3 */ + mux { + /* CLK */ + pins = "gpio35"; + function = "cam_mclk"; + }; + + config { + pins = "gpio35"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_front_iris_active: cam_sensor_front_iris_active { + /* RESET */ + mux { + pins = "gpio52"; + function = "gpio"; + }; + + config { + pins = "gpio52"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_front_iris_suspend: cam_sensor_front_iris_suspend { + /* RESET */ + mux { + pins = "gpio52"; + function = "gpio"; + }; + + config { + pins = "gpio52"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + /* HS UART CONFIGURATION */ blsp1_uart1_active: blsp1_uart1_active { mux { diff --git a/arch/arm/boot/dts/qcom/sdm660-qrd.dtsi b/arch/arm/boot/dts/qcom/sdm660-qrd.dtsi index 3d2cfedc1009..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 { @@ -230,11 +243,12 @@ &pm660_fg { qcom,battery-data = <&qrd_batterydata>; qcom,fg-jeita-thresholds = <0 5 55 55>; + qcom,battery-thermal-coefficients = [9d 50 ff]; }; &i2c_2 { status = "ok"; - smb1351-charger@1d { + smb1351_charger: smb1351-charger@1d { compatible = "qcom,smb1351-charger"; reg = <0x1d>; qcom,parallel-charger; diff --git a/arch/arm/boot/dts/qcom/vplatform-lfv-ion.dtsi b/arch/arm/boot/dts/qcom/vplatform-lfv-ion.dtsi new file mode 100644 index 000000000000..1176b54835b1 --- /dev/null +++ b/arch/arm/boot/dts/qcom/vplatform-lfv-ion.dtsi @@ -0,0 +1,31 @@ +/* Copyright (c) 2017, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +&soc { + qcom,ion { + compatible = "qcom,msm-ion"; + #address-cells = <1>; + #size-cells = <0>; + + system_heap: qcom,ion-heap@25 { + reg = <25>; + memory-region = <&ion_system>; + qcom,ion-heap-type = "CARVEOUT"; + }; + + qcom,ion-heap@28 { /* Audio Heap */ + reg = <28>; + memory-region = <&ion_audio>; + qcom,ion-heap-type = "CARVEOUT"; + }; + }; +}; diff --git a/arch/arm/boot/dts/qcom/vplatform-lfv-msm8996.dts b/arch/arm/boot/dts/qcom/vplatform-lfv-msm8996.dts new file mode 100644 index 000000000000..99f17844e508 --- /dev/null +++ b/arch/arm/boot/dts/qcom/vplatform-lfv-msm8996.dts @@ -0,0 +1,487 @@ +/* Copyright (c) 2017, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; + +#include "skeleton64.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. MSM 8996"; + compatible = "qcom,msm8996"; + qcom,msm-id = <246 0x0>; + + soc: soc { }; + + psci { + compatible = "arm,psci"; + method = "smc"; + cpu_suspend = <0xc4000001>; + cpu_off = <0x84000002>; + cpu_on = <0xc4000003>; + }; + + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + pmem_shared: pmem_shared_region { + reg = <0 0xd0000000 0 0x20000000>; + label = "pmem_shared_mem"; + }; + ion_system: ion_system_region { + reg = <0x1 0x0 0 0x10000000>; + label = "ion_system_mem"; + }; + ion_audio: ion_audio_region { + reg = <0 0xc8000000 0 0x00400000>; + label = "ion_audio_mem"; + }; + }; +}; + +#include "vplatform-lfv-ion.dtsi" + +&soc { + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0 0 0xffffffff>; + compatible = "simple-bus"; + + sound-adp-agave { + compatible = "qcom,apq8096-asoc-snd-adp-agave"; + qcom,model = "apq8096-adp-agave-snd-card"; + + asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>, + <&loopback>, <&compress>, <&hostless>, + <&afe>, <&lsm>, <&routing>, <&compr>, + <&loopback1>; + asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1", + "msm-pcm-dsp.2", "msm-voip-dsp", + "msm-pcm-voice", "msm-pcm-loopback", + "msm-compress-dsp", "msm-pcm-hostless", + "msm-pcm-afe", "msm-lsm-client", + "msm-pcm-routing", "msm-compr-dsp", + "msm-pcm-loopback.1"; + asoc-cpu = <&dai_pri_auxpcm>, <&dai_sec_auxpcm>, <&dai_hdmi>, + <&dai_mi2s_sec>, <&dai_mi2s>, <&dai_mi2s_quat>, + <&afe_pcm_rx>, <&afe_pcm_tx>, + <&afe_proxy_rx>, <&afe_proxy_tx>, + <&incall_record_rx>, <&incall_record_tx>, + <&incall_music_rx>, <&incall_music2_rx>, + <&dai_tert_tdm_rx_0>, <&dai_tert_tdm_rx_1>, + <&dai_tert_tdm_rx_2>, <&dai_tert_tdm_rx_3>, + <&dai_tert_tdm_tx_0>, <&dai_tert_tdm_tx_1>, + <&dai_tert_tdm_tx_2>, <&dai_tert_tdm_tx_3>, + <&dai_quat_tdm_rx_0>, <&dai_quat_tdm_rx_1>, + <&dai_quat_tdm_rx_2>, <&dai_quat_tdm_rx_3>, + <&dai_quat_tdm_tx_0>, <&dai_quat_tdm_tx_1>, + <&dai_quat_tdm_tx_2>, <&dai_quat_tdm_tx_3>; + asoc-cpu-names = "msm-dai-q6-auxpcm.1", "msm-dai-q6-auxpcm.2", + "msm-dai-q6-hdmi.8", "msm-dai-q6-mi2s.1", + "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3", + "msm-dai-q6-dev.224", "msm-dai-q6-dev.225", + "msm-dai-q6-dev.241", "msm-dai-q6-dev.240", + "msm-dai-q6-dev.32771", "msm-dai-q6-dev.32772", + "msm-dai-q6-dev.32773", "msm-dai-q6-dev.32770", + "msm-dai-q6-tdm.36896", "msm-dai-q6-tdm.36898", + "msm-dai-q6-tdm.36900", "msm-dai-q6-tdm.36902", + "msm-dai-q6-tdm.36897", "msm-dai-q6-tdm.36899", + "msm-dai-q6-tdm.36901", "msm-dai-q6-tdm.36903", + "msm-dai-q6-tdm.36912", "msm-dai-q6-tdm.36914", + "msm-dai-q6-tdm.36916", "msm-dai-q6-tdm.36918", + "msm-dai-q6-tdm.36913", "msm-dai-q6-tdm.36915", + "msm-dai-q6-tdm.36917", "msm-dai-q6-tdm.36919"; + asoc-codec = <&stub_codec>; + asoc-codec-names = "msm-stub-codec.1"; + }; + + qcom,msm-audio-ion { + compatible = "qcom,msm-audio-ion"; + qcom,smmu-enabled; + qcom,smmu-sid = <1>; + }; + + pcm0: qcom,msm-pcm { + compatible = "qcom,msm-pcm-dsp"; + qcom,msm-pcm-dsp-id = <0>; + }; + + pcm1: qcom,msm-pcm-low-latency { + compatible = "qcom,msm-pcm-dsp"; + qcom,msm-pcm-dsp-id = <1>; + qcom,msm-pcm-low-latency; + qcom,latency-level = "regular"; + }; + + pcm2: qcom,msm-ultra-low-latency { + compatible = "qcom,msm-pcm-dsp"; + qcom,msm-pcm-dsp-id = <2>; + qcom,msm-pcm-low-latency; + qcom,latency-level = "ultra"; + }; + + routing: qcom,msm-pcm-routing { + compatible = "qcom,msm-pcm-routing"; + }; + + compr: qcom,msm-compr-dsp { + compatible = "qcom,msm-compr-dsp"; + }; + + compress: qcom,msm-compress-dsp { + compatible = "qcom,msm-compress-dsp"; + }; + + voip: qcom,msm-voip-dsp { + compatible = "qcom,msm-voip-dsp"; + }; + + voice: qcom,msm-pcm-voice { + compatible = "qcom,msm-pcm-voice"; + qcom,destroy-cvd; + }; + + stub_codec: qcom,msm-stub-codec { + compatible = "qcom,msm-stub-codec"; + }; + + qcom,msm-dai-fe { + compatible = "qcom,msm-dai-fe"; + }; + + afe: qcom,msm-pcm-afe { + compatible = "qcom,msm-pcm-afe"; + }; + + dai_hdmi: qcom,msm-dai-q6-hdmi { + compatible = "qcom,msm-dai-q6-hdmi"; + qcom,msm-dai-q6-dev-id = <8>; + }; + + lsm: qcom,msm-lsm-client { + compatible = "qcom,msm-lsm-client"; + }; + + loopback: qcom,msm-pcm-loopback { + compatible = "qcom,msm-pcm-loopback"; + }; + + loopback1: qcom,msm-pcm-loopback-low-latency { + compatible = "qcom,msm-pcm-loopback"; + qcom,msm-pcm-loopback-low-latency; + }; + + qcom,msm-dai-q6 { + compatible = "qcom,msm-dai-q6"; + + afe_pcm_rx: qcom,msm-dai-q6-be-afe-pcm-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <224>; + }; + + afe_pcm_tx: qcom,msm-dai-q6-be-afe-pcm-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <225>; + }; + + afe_proxy_rx: com,msm-dai-q6-afe-proxy-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <241>; + }; + + afe_proxy_tx: qcom,msm-dai-q6-afe-proxy-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <240>; + }; + + incall_record_rx: qcom,msm-dai-q6-incall-record-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <32771>; + }; + + incall_record_tx: qcom,msm-dai-q6-incall-record-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <32772>; + }; + + incall_music_rx: qcom,msm-dai-q6-incall-music-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <32773>; + }; + + incall_music2_rx: qcom,msm-dai-q6-incall-music-2-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <32770>; + }; + }; + + dai_pri_auxpcm: qcom,msm-pri-auxpcm { + compatible = "qcom,msm-auxpcm-dev"; + qcom,msm-cpudai-auxpcm-mode = <0>, <0>; + qcom,msm-cpudai-auxpcm-sync = <1>, <1>; + qcom,msm-cpudai-auxpcm-frame = <5>, <4>; + qcom,msm-cpudai-auxpcm-quant = <2>, <2>; + qcom,msm-cpudai-auxpcm-num-slots = <1>, <1>; + qcom,msm-cpudai-auxpcm-slot-mapping = <1>, <1>; + qcom,msm-cpudai-auxpcm-data = <0>, <0>; + qcom,msm-cpudai-auxpcm-pcm-clk-rate = <2048000>, <2048000>; + qcom,msm-auxpcm-interface = "primary"; + qcom,msm-cpudai-afe-clk-ver = <2>; + }; + + dai_sec_auxpcm: qcom,msm-sec-auxpcm { + compatible = "qcom,msm-auxpcm-dev"; + qcom,msm-cpudai-auxpcm-mode = <0>, <0>; + qcom,msm-cpudai-auxpcm-sync = <1>, <1>; + qcom,msm-cpudai-auxpcm-frame = <5>, <4>; + qcom,msm-cpudai-auxpcm-quant = <2>, <2>; + qcom,msm-cpudai-auxpcm-num-slots = <1>, <1>; + qcom,msm-cpudai-auxpcm-slot-mapping = <1>, <1>; + qcom,msm-cpudai-auxpcm-data = <0>, <0>; + qcom,msm-cpudai-auxpcm-pcm-clk-rate = <2048000>, <2048000>; + qcom,msm-auxpcm-interface = "secondary"; + qcom,msm-cpudai-afe-clk-ver = <2>; + }; + + qcom,msm-dai-mi2s { + compatible = "qcom,msm-dai-mi2s"; + dai_mi2s_sec: qcom,msm-dai-q6-mi2s-sec { + compatible = "qcom,msm-dai-q6-mi2s"; + qcom,msm-dai-q6-mi2s-dev-id = <1>; + qcom,msm-mi2s-rx-lines = <2>; + qcom,msm-mi2s-tx-lines = <1>; + }; + + dai_mi2s: qcom,msm-dai-q6-mi2s-tert { + compatible = "qcom,msm-dai-q6-mi2s"; + qcom,msm-dai-q6-mi2s-dev-id = <2>; + qcom,msm-mi2s-rx-lines = <2>; + qcom,msm-mi2s-tx-lines = <1>; + }; + + dai_mi2s_quat: qcom,msm-dai-q6-mi2s-quat { + compatible = "qcom,msm-dai-q6-mi2s"; + qcom,msm-dai-q6-mi2s-dev-id = <3>; + qcom,msm-mi2s-rx-lines = <1>; + qcom,msm-mi2s-tx-lines = <0>; + }; + }; + + 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>; + 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>; + }; + }; + + qcom,msm-dai-tdm-tert-tx { + compatible = "qcom,msm-dai-tdm"; + 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>; + 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>; + }; + }; + + qcom,msm-dai-tdm-quat-rx { + compatible = "qcom,msm-dai-tdm"; + 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>; + 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>; + }; + }; + + qcom,msm-dai-tdm-quat-tx { + compatible = "qcom,msm-dai-tdm"; + 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>; + 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>; + }; + }; + + hostless: qcom,msm-pcm-hostless { + compatible = "qcom,msm-pcm-hostless"; + }; +}; diff --git a/arch/arm/configs/msmcortex_defconfig b/arch/arm/configs/msmcortex_defconfig index 1658cc992ee6..60a7cff4836d 100644 --- a/arch/arm/configs/msmcortex_defconfig +++ b/arch/arm/configs/msmcortex_defconfig @@ -224,7 +224,6 @@ CONFIG_ZRAM=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=8192 -CONFIG_UID_CPUTIME=y CONFIG_MSM_ULTRASOUND=y CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y @@ -294,7 +293,6 @@ CONFIG_PINCTRL_SDM660=y CONFIG_GPIO_SYSFS=y CONFIG_GPIO_QPNP_PIN=y CONFIG_POWER_SUPPLY=y -CONFIG_QPNP_SMBCHARGER=y CONFIG_SMB135X_CHARGER=y CONFIG_SMB1351_USB_CHARGER=y CONFIG_MSM_BCL_CTL=y @@ -526,7 +524,6 @@ CONFIG_PANIC_ON_SCHED_BUG=y CONFIG_PANIC_ON_RT_THROTTLING=y CONFIG_SCHEDSTATS=y CONFIG_SCHED_STACK_END_CHECK=y -CONFIG_TIMER_STATS=y # CONFIG_DEBUG_PREEMPT is not set CONFIG_DEBUG_SPINLOCK=y CONFIG_DEBUG_MUTEXES=y diff --git a/arch/arm/configs/sdm660-perf_defconfig b/arch/arm/configs/sdm660-perf_defconfig index fe6988ebbb53..43b6432118f0 100644 --- a/arch/arm/configs/sdm660-perf_defconfig +++ b/arch/arm/configs/sdm660-perf_defconfig @@ -635,7 +635,6 @@ CONFIG_PANIC_ON_SCHED_BUG=y CONFIG_PANIC_ON_RT_THROTTLING=y CONFIG_SCHEDSTATS=y CONFIG_SCHED_STACK_END_CHECK=y -CONFIG_TIMER_STATS=y # CONFIG_DEBUG_PREEMPT is not set CONFIG_IPC_LOGGING=y CONFIG_FUNCTION_TRACER=y diff --git a/arch/arm/configs/sdm660_defconfig b/arch/arm/configs/sdm660_defconfig index 3942da1a768d..e3aa35da81ce 100644 --- a/arch/arm/configs/sdm660_defconfig +++ b/arch/arm/configs/sdm660_defconfig @@ -655,7 +655,6 @@ CONFIG_PANIC_ON_SCHED_BUG=y CONFIG_PANIC_ON_RT_THROTTLING=y CONFIG_SCHEDSTATS=y CONFIG_SCHED_STACK_END_CHECK=y -CONFIG_TIMER_STATS=y # CONFIG_DEBUG_PREEMPT is not set CONFIG_DEBUG_SPINLOCK=y CONFIG_DEBUG_MUTEXES=y diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c index f86692dbcfd5..83fc403aec3c 100644 --- a/arch/arm/mach-omap2/timer.c +++ b/arch/arm/mach-omap2/timer.c @@ -496,8 +496,7 @@ void __init omap_init_time(void) __omap_sync32k_timer_init(1, "timer_32k_ck", "ti,timer-alwon", 2, "timer_sys_ck", NULL, false); - if (of_have_populated_dt()) - clocksource_probe(); + clocksource_probe(); } #if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_SOC_AM43XX) @@ -505,6 +504,8 @@ void __init omap3_secure_sync32k_timer_init(void) { __omap_sync32k_timer_init(12, "secure_32k_fck", "ti,timer-secure", 2, "timer_sys_ck", NULL, false); + + clocksource_probe(); } #endif /* CONFIG_ARCH_OMAP3 */ @@ -513,6 +514,8 @@ void __init omap3_gptimer_timer_init(void) { __omap_sync32k_timer_init(2, "timer_sys_ck", NULL, 1, "timer_sys_ck", "ti,timer-alwon", true); + + clocksource_probe(); } #endif diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index a25d6b0e22a4..7708d83f16ac 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -672,7 +672,7 @@ static void __free_from_contiguous(struct device *dev, struct page *page, if (PageHighMem(page)) __dma_free_remap(cpu_addr, size, true); else - __dma_remap(page, size, PAGE_KERNEL, false); + __dma_remap(page, size, PAGE_KERNEL, true); dma_release_from_contiguous(dev, page, size >> PAGE_SHIFT); } 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-perf_defconfig b/arch/arm64/configs/msm-auto-perf_defconfig index a42cc936e002..81fa3afa8cca 100644 --- a/arch/arm64/configs/msm-auto-perf_defconfig +++ b/arch/arm64/configs/msm-auto-perf_defconfig @@ -89,7 +89,9 @@ CONFIG_IP_MULTIPLE_TABLES=y CONFIG_IP_ROUTE_VERBOSE=y CONFIG_IP_PNP=y CONFIG_IP_PNP_DHCP=y +CONFIG_INET_AH=y CONFIG_INET_ESP=y +CONFIG_INET_IPCOMP=y # CONFIG_INET_LRO is not set CONFIG_INET_DIAG_DESTROY=y CONFIG_IPV6_ROUTER_PREF=y @@ -217,21 +219,10 @@ CONFIG_SOCKEV_NLMCAST=y CONFIG_CAN=y CONFIG_CAN_RH850=y CONFIG_BT=y -CONFIG_BT_RFCOMM=y -CONFIG_BT_RFCOMM_TTY=y -CONFIG_BT_BNEP=y -CONFIG_BT_BNEP_MC_FILTER=y -CONFIG_BT_BNEP_PROTO_FILTER=y -CONFIG_BT_HIDP=y -# CONFIG_BT_HS is not set -# CONFIG_BT_LE is not set -# CONFIG_BT_DEBUGFS is not set CONFIG_MSM_BT_POWER=y CONFIG_BTFM_SLIM=y CONFIG_BTFM_SLIM_WCN3990=y CONFIG_CFG80211=y -CONFIG_CFG80211_INTERNAL_REGDB=y -# CONFIG_CFG80211_CRDA_SUPPORT is not set CONFIG_RFKILL=y CONFIG_IPC_ROUTER=y CONFIG_IPC_ROUTER_SECURITY=y @@ -273,27 +264,23 @@ CONFIG_RNDIS_IPA=y CONFIG_PPP=y CONFIG_PPP_BSDCOMP=y CONFIG_PPP_DEFLATE=y -CONFIG_PPP_FILTER=y CONFIG_PPP_MPPE=y -CONFIG_PPP_MULTILINK=y -CONFIG_PPPOE=y -CONFIG_PPPOL2TP=y CONFIG_PPPOLAC=y CONFIG_PPPOPNS=y -CONFIG_PPP_ASYNC=y -CONFIG_PPP_SYNC_TTY=y CONFIG_USB_USBNET=y CONFIG_WCNSS_MEM_PRE_ALLOC=y CONFIG_CNSS_CRYPTO=y CONFIG_ATH_CARDS=y CONFIG_WIL6210=m CONFIG_CNSS=y +CONFIG_CNSS_ASYNC=y CONFIG_CLD_LL_CORE=y CONFIG_BUS_AUTO_SUSPEND=y CONFIG_INPUT_EVDEV=y CONFIG_INPUT_KEYRESET=y CONFIG_KEYBOARD_GPIO=y # CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_JOYSTICK=y CONFIG_INPUT_TOUCHSCREEN=y CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_CORE_v21=y CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_v21=y @@ -304,7 +291,6 @@ CONFIG_TOUCHSCREEN_GEN_VKEYS=y CONFIG_INPUT_MISC=y CONFIG_INPUT_HBTP_INPUT=y CONFIG_INPUT_QPNP_POWER_ON=y -CONFIG_INPUT_KEYCHORD=y CONFIG_INPUT_UINPUT=y CONFIG_INPUT_GPIO=y # CONFIG_SERIO_SERPORT is not set @@ -319,7 +305,6 @@ CONFIG_HW_RANDOM=y CONFIG_HW_RANDOM_MSM_LEGACY=y CONFIG_MSM_ADSPRPC=y CONFIG_MSM_RDBG=m -# CONFIG_ACPI_I2C_OPREGION is not set CONFIG_I2C_CHARDEV=y CONFIG_I2C_QUP=y CONFIG_I2C_MSM_V2=y @@ -356,6 +341,7 @@ CONFIG_WCD9335_CODEC=y CONFIG_REGULATOR=y CONFIG_REGULATOR_FIXED_VOLTAGE=y CONFIG_REGULATOR_FAN53555=y +CONFIG_REGULATOR_ONSEMI_NCP6335D=y CONFIG_REGULATOR_RPM_SMD=y CONFIG_REGULATOR_QPNP=y CONFIG_REGULATOR_QPNP_LABIBB=y @@ -428,7 +414,6 @@ CONFIG_HID_MAGICMOUSE=y CONFIG_HID_MICROSOFT=y CONFIG_HID_MULTITOUCH=y CONFIG_USB=y -CONFIG_USB_ANNOUNCE_NEW_DEVICES=y CONFIG_USB_XHCI_HCD=y CONFIG_USB_EHCI_HCD=y CONFIG_USB_EHCI_HCD_PLATFORM=y @@ -437,7 +422,6 @@ CONFIG_USB_OHCI_HCD_PLATFORM=y CONFIG_USB_STORAGE=y CONFIG_USB_DWC3=y CONFIG_USB_ISP1760=y -CONFIG_USB_SERIAL=y CONFIG_USB_QTI_KS_BRIDGE=y CONFIG_NOP_USB_XCEIV=y CONFIG_USB_MSM_SSPHY_QMP=y @@ -445,7 +429,6 @@ CONFIG_MSM_QUSB_PHY=y CONFIG_USB_ULPI=y CONFIG_USB_GADGET=y CONFIG_USB_GADGET_VBUS_DRAW=500 -CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=4 CONFIG_USB_CONFIGFS=y CONFIG_USB_CONFIGFS_SERIAL=y CONFIG_USB_CONFIGFS_NCM=y @@ -470,11 +453,17 @@ CONFIG_MMC_TEST=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_MSM=y +CONFIG_MMC_SPI=y +CONFIG_MMC_DW=y +CONFIG_MMC_DW_EXYNOS=y CONFIG_MMC_CQ_HCI=y CONFIG_LEDS_QPNP=y CONFIG_LEDS_QPNP_FLASH_V2=y CONFIG_LEDS_QPNP_WLED=y +CONFIG_LEDS_SYSCON=y CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_TRIGGER_HEARTBEAT=y +CONFIG_LEDS_TRIGGER_CPU=y CONFIG_SWITCH=y CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_QPNP=y @@ -500,6 +489,10 @@ CONFIG_SPS=y CONFIG_SPS_SUPPORT_NDP_BAM=y CONFIG_IPA=y CONFIG_RMNET_IPA=y +CONFIG_GSI=y +CONFIG_IPA3=y +CONFIG_RMNET_IPA3=y +CONFIG_IPA_UT=y CONFIG_GPIO_USB_DETECT=y CONFIG_MSM_MHI=y CONFIG_MSM_MHI_UCI=y @@ -524,6 +517,7 @@ CONFIG_MSM_SMP2P_TEST=y CONFIG_MSM_QMI_INTERFACE=y CONFIG_MSM_RPM_SMD=y CONFIG_QCOM_BUS_SCALING=y +CONFIG_MSM_SERVICE_LOCATOR=y CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y CONFIG_MSM_SYSMON_GLINK_COMM=y CONFIG_MSM_IPC_ROUTER_MHI_XPRT=y @@ -545,9 +539,12 @@ CONFIG_MSM_PIL=y CONFIG_MSM_PIL_SSR_GENERIC=y CONFIG_MSM_PIL_MSS_QDSP6V5=y CONFIG_TRACER_PKT=y +CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y CONFIG_MSM_MPM_OF=y CONFIG_MSM_EVENT_TIMER=y CONFIG_MSM_AVTIMER=y +CONFIG_QCOM_REMOTEQDSS=y +CONFIG_MSM_SERVICE_NOTIFIER=y CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y CONFIG_MSM_RPM_LOG=y CONFIG_MSM_RPM_STATS_LOG=y @@ -567,6 +564,8 @@ CONFIG_QCOM_DEVFREQ_DEVBW=y CONFIG_EXTCON=y CONFIG_PWM=y CONFIG_PWM_QPNP=y +CONFIG_ARM_GIC_V3_ACL=y +CONFIG_PHY_XGENE=y CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y CONFIG_MSM_TZ_LOG=y @@ -592,7 +591,6 @@ CONFIG_DEBUG_INFO=y CONFIG_MAGIC_SYSRQ=y CONFIG_PANIC_TIMEOUT=5 CONFIG_SCHEDSTATS=y -CONFIG_TIMER_STATS=y # CONFIG_DEBUG_PREEMPT is not set # CONFIG_DEBUG_BUGVERBOSE is not set CONFIG_IPC_LOGGING=y @@ -612,8 +610,8 @@ CONFIG_CORESIGHT_QPDI=y CONFIG_CORESIGHT_SOURCE_DUMMY=y CONFIG_PFK=y CONFIG_SECURITY=y -CONFIG_SECURITY_NETWORK=y CONFIG_SECURITY_SELINUX=y +CONFIG_SECURITY_SMACK=y CONFIG_CRYPTO_ECHAINIV=y CONFIG_CRYPTO_XCBC=y CONFIG_CRYPTO_MD4=y diff --git a/arch/arm64/configs/msm-auto_defconfig b/arch/arm64/configs/msm-auto_defconfig index df5060eadd9c..70674f6043cf 100644 --- a/arch/arm64/configs/msm-auto_defconfig +++ b/arch/arm64/configs/msm-auto_defconfig @@ -274,6 +274,7 @@ CONFIG_CNSS_CRYPTO=y CONFIG_ATH_CARDS=y CONFIG_WIL6210=m CONFIG_CNSS=y +CONFIG_CNSS_ASYNC=y CONFIG_CLD_LL_CORE=y CONFIG_BUS_AUTO_SUSPEND=y CONFIG_INPUT_EVDEV=y @@ -343,6 +344,7 @@ CONFIG_WCD9335_CODEC=y CONFIG_REGULATOR=y CONFIG_REGULATOR_FIXED_VOLTAGE=y CONFIG_REGULATOR_FAN53555=y +CONFIG_REGULATOR_ONSEMI_NCP6335D=y CONFIG_REGULATOR_RPM_SMD=y CONFIG_REGULATOR_QPNP=y CONFIG_REGULATOR_QPNP_LABIBB=y @@ -615,7 +617,6 @@ CONFIG_PANIC_TIMEOUT=5 CONFIG_PANIC_ON_SCHED_BUG=y CONFIG_PANIC_ON_RT_THROTTLING=y CONFIG_SCHEDSTATS=y -CONFIG_TIMER_STATS=y CONFIG_DEBUG_SPINLOCK=y CONFIG_DEBUG_MUTEXES=y CONFIG_DEBUG_ATOMIC_SLEEP=y @@ -636,7 +637,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-perf_defconfig b/arch/arm64/configs/msm-perf_defconfig index 3cd68ecf8634..acde18d2fe31 100644 --- a/arch/arm64/configs/msm-perf_defconfig +++ b/arch/arm64/configs/msm-perf_defconfig @@ -578,7 +578,6 @@ CONFIG_DEBUG_INFO=y CONFIG_MAGIC_SYSRQ=y CONFIG_PANIC_TIMEOUT=5 CONFIG_SCHEDSTATS=y -CONFIG_TIMER_STATS=y # CONFIG_DEBUG_PREEMPT is not set # CONFIG_DEBUG_BUGVERBOSE is not set CONFIG_IPC_LOGGING=y diff --git a/arch/arm64/configs/msm_defconfig b/arch/arm64/configs/msm_defconfig index 80e737e5726c..f510f43427ce 100644 --- a/arch/arm64/configs/msm_defconfig +++ b/arch/arm64/configs/msm_defconfig @@ -601,7 +601,6 @@ CONFIG_PANIC_TIMEOUT=5 CONFIG_PANIC_ON_SCHED_BUG=y CONFIG_PANIC_ON_RT_THROTTLING=y CONFIG_SCHEDSTATS=y -CONFIG_TIMER_STATS=y CONFIG_DEBUG_SPINLOCK=y CONFIG_DEBUG_MUTEXES=y CONFIG_DEBUG_ATOMIC_SLEEP=y @@ -622,7 +621,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-perf_defconfig b/arch/arm64/configs/msmcortex-perf_defconfig index a5c58dc66191..6ee2f4003574 100644 --- a/arch/arm64/configs/msmcortex-perf_defconfig +++ b/arch/arm64/configs/msmcortex-perf_defconfig @@ -65,12 +65,12 @@ CONFIG_CMA=y CONFIG_CMA_DEBUGFS=y CONFIG_ZSMALLOC=y CONFIG_BALANCE_ANON_FILE_RECLAIM=y -CONFIG_FORCE_ALLOC_FROM_DMA_ZONE=y CONFIG_SECCOMP=y CONFIG_ARMV8_DEPRECATED=y CONFIG_SWP_EMULATION=y CONFIG_CP15_BARRIER_EMULATION=y CONFIG_SETEND_EMULATION=y +CONFIG_ARM64_SW_TTBR0_PAN=y CONFIG_RANDOMIZE_BASE=y # CONFIG_RANDOMIZE_MODULE_REGION_FULL is not set # CONFIG_EFI is not set @@ -621,7 +621,6 @@ CONFIG_DEBUG_INFO=y CONFIG_MAGIC_SYSRQ=y CONFIG_PANIC_TIMEOUT=5 CONFIG_SCHEDSTATS=y -CONFIG_TIMER_STATS=y # CONFIG_DEBUG_PREEMPT is not set CONFIG_IPC_LOGGING=y CONFIG_CPU_FREQ_SWITCH_PROFILER=y diff --git a/arch/arm64/configs/msmcortex_defconfig b/arch/arm64/configs/msmcortex_defconfig index 7a82377302fe..bbe23b823b5d 100644 --- a/arch/arm64/configs/msmcortex_defconfig +++ b/arch/arm64/configs/msmcortex_defconfig @@ -71,6 +71,7 @@ CONFIG_ARMV8_DEPRECATED=y CONFIG_SWP_EMULATION=y CONFIG_CP15_BARRIER_EMULATION=y CONFIG_SETEND_EMULATION=y +CONFIG_ARM64_SW_TTBR0_PAN=y CONFIG_RANDOMIZE_BASE=y CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set @@ -262,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 @@ -672,7 +674,6 @@ CONFIG_PANIC_ON_SCHED_BUG=y CONFIG_PANIC_ON_RT_THROTTLING=y CONFIG_SCHEDSTATS=y CONFIG_SCHED_STACK_END_CHECK=y -CONFIG_TIMER_STATS=y # CONFIG_DEBUG_PREEMPT is not set CONFIG_DEBUG_SPINLOCK=y CONFIG_DEBUG_MUTEXES=y diff --git a/arch/arm64/configs/msmcortex_mediabox-perf_defconfig b/arch/arm64/configs/msmcortex_mediabox-perf_defconfig new file mode 100644 index 000000000000..953d700c20cc --- /dev/null +++ b/arch/arm64/configs/msmcortex_mediabox-perf_defconfig @@ -0,0 +1,641 @@ +CONFIG_LOCALVERSION="-perf" +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_AUDIT=y +# CONFIG_AUDITSYSCALL is not set +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_IRQ_TIME_ACCOUNTING=y +CONFIG_RCU_EXPERT=y +CONFIG_RCU_FAST_NO_HZ=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_CPU_MAX_BUF_SHIFT=17 +CONFIG_CGROUP_FREEZER=y +CONFIG_CPUSETS=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_CGROUP_SCHEDTUNE=y +CONFIG_RT_GROUP_SCHED=y +CONFIG_SCHED_HMP=y +CONFIG_SCHED_HMP_CSTATE_AWARE=y +CONFIG_SCHED_CORE_CTL=y +CONFIG_NAMESPACES=y +# CONFIG_UTS_NS is not set +# CONFIG_PID_NS is not set +CONFIG_SCHED_AUTOGROUP=y +CONFIG_SCHED_TUNE=y +CONFIG_BLK_DEV_INITRD=y +# CONFIG_RD_XZ is not set +# CONFIG_RD_LZO is not set +# CONFIG_RD_LZ4 is not set +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_KALLSYMS_ALL=y +# CONFIG_AIO is not set +# CONFIG_MEMBARRIER is not set +CONFIG_EMBEDDED=y +# CONFIG_SLUB_DEBUG is not set +# CONFIG_COMPAT_BRK is not set +CONFIG_PROFILING=y +CONFIG_CC_STACKPROTECTOR_REGULAR=y +CONFIG_ARCH_MMAP_RND_COMPAT_BITS=16 +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_MODVERSIONS=y +CONFIG_MODULE_SIG=y +CONFIG_MODULE_SIG_FORCE=y +CONFIG_MODULE_SIG_SHA512=y +CONFIG_PARTITION_ADVANCED=y +CONFIG_ARCH_QCOM=y +CONFIG_ARCH_MSM8998=y +CONFIG_ARCH_MSMHAMSTER=y +CONFIG_PCI=y +CONFIG_PCI_MSM=y +CONFIG_SCHED_MC=y +CONFIG_NR_CPUS=8 +CONFIG_QCOM_TLB_EL2_HANDLER=y +CONFIG_PREEMPT=y +CONFIG_HZ_100=y +CONFIG_ARM64_REG_REBALANCE_ON_CTX_SW=y +CONFIG_CMA=y +CONFIG_CMA_DEBUGFS=y +CONFIG_ZSMALLOC=y +CONFIG_BALANCE_ANON_FILE_RECLAIM=y +CONFIG_FORCE_ALLOC_FROM_DMA_ZONE=y +CONFIG_SECCOMP=y +CONFIG_ARMV8_DEPRECATED=y +CONFIG_SWP_EMULATION=y +CONFIG_CP15_BARRIER_EMULATION=y +CONFIG_SETEND_EMULATION=y +CONFIG_RANDOMIZE_BASE=y +# CONFIG_RANDOMIZE_MODULE_REGION_FULL is not set +# CONFIG_EFI is not set +CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_COMPAT=y +CONFIG_PM_AUTOSLEEP=y +CONFIG_PM_WAKELOCKS=y +CONFIG_PM_WAKELOCKS_LIMIT=0 +# CONFIG_PM_WAKELOCKS_GC is not set +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_INTERACTIVE=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y +CONFIG_CPU_BOOST=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_XFRM_USER=y +CONFIG_XFRM_STATISTICS=y +CONFIG_NET_KEY=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_INET_AH=y +CONFIG_INET_ESP=y +CONFIG_INET_IPCOMP=y +CONFIG_INET_DIAG_DESTROY=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +CONFIG_INET6_IPCOMP=y +CONFIG_IPV6_MIP6=y +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_IPV6_SUBTREES=y +CONFIG_NETFILTER=y +CONFIG_NF_CONNTRACK=y +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CT_PROTO_DCCP=y +CONFIG_NF_CT_PROTO_SCTP=y +CONFIG_NF_CT_PROTO_UDPLITE=y +CONFIG_NF_CONNTRACK_AMANDA=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_H323=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=y +CONFIG_NF_CONNTRACK_PPTP=y +CONFIG_NF_CONNTRACK_SANE=y +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NF_CT_NETLINK=y +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y +CONFIG_NETFILTER_XT_TARGET_CONNMARK=y +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_HARDIDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_LOG=y +CONFIG_NETFILTER_XT_TARGET_MARK=y +CONFIG_NETFILTER_XT_TARGET_NFLOG=y +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y +CONFIG_NETFILTER_XT_TARGET_NOTRACK=y +CONFIG_NETFILTER_XT_TARGET_TEE=y +CONFIG_NETFILTER_XT_TARGET_TPROXY=y +CONFIG_NETFILTER_XT_TARGET_TRACE=y +CONFIG_NETFILTER_XT_TARGET_SECMARK=y +CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +CONFIG_NETFILTER_XT_MATCH_COMMENT=y +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y +CONFIG_NETFILTER_XT_MATCH_CONNMARK=y +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y +CONFIG_NETFILTER_XT_MATCH_DSCP=y +CONFIG_NETFILTER_XT_MATCH_ESP=y +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y +CONFIG_NETFILTER_XT_MATCH_HELPER=y +CONFIG_NETFILTER_XT_MATCH_IPRANGE=y +# CONFIG_NETFILTER_XT_MATCH_L2TP is not set +CONFIG_NETFILTER_XT_MATCH_LENGTH=y +CONFIG_NETFILTER_XT_MATCH_LIMIT=y +CONFIG_NETFILTER_XT_MATCH_MAC=y +CONFIG_NETFILTER_XT_MATCH_MARK=y +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y +CONFIG_NETFILTER_XT_MATCH_POLICY=y +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_QTAGUID=y +CONFIG_NETFILTER_XT_MATCH_QUOTA=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_SOCKET=y +CONFIG_NETFILTER_XT_MATCH_STATE=y +CONFIG_NETFILTER_XT_MATCH_STATISTIC=y +CONFIG_NETFILTER_XT_MATCH_STRING=y +CONFIG_NETFILTER_XT_MATCH_TIME=y +CONFIG_NETFILTER_XT_MATCH_U32=y +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MATCH_AH=y +CONFIG_IP_NF_MATCH_ECN=y +CONFIG_IP_NF_MATCH_RPFILTER=y +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_NF_NAT=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_IP_NF_MANGLE=y +CONFIG_IP_NF_RAW=y +CONFIG_IP_NF_SECURITY=y +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARP_MANGLE=y +CONFIG_NF_CONNTRACK_IPV6=y +CONFIG_IP6_NF_IPTABLES=y +CONFIG_IP6_NF_MATCH_RPFILTER=y +CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_TARGET_REJECT=y +CONFIG_IP6_NF_MANGLE=y +CONFIG_IP6_NF_RAW=y +CONFIG_BRIDGE_NF_EBTABLES=y +CONFIG_BRIDGE_EBT_BROUTE=y +CONFIG_L2TP=y +CONFIG_L2TP_V3=y +CONFIG_L2TP_IP=y +CONFIG_L2TP_ETH=y +CONFIG_BRIDGE=y +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_HTB=y +CONFIG_NET_SCH_PRIO=y +CONFIG_NET_SCH_MULTIQ=y +CONFIG_NET_SCH_INGRESS=y +CONFIG_NET_CLS_FW=y +CONFIG_NET_CLS_U32=y +CONFIG_CLS_U32_MARK=y +CONFIG_NET_CLS_FLOW=y +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_CMP=y +CONFIG_NET_EMATCH_NBYTE=y +CONFIG_NET_EMATCH_U32=y +CONFIG_NET_EMATCH_META=y +CONFIG_NET_EMATCH_TEXT=y +CONFIG_NET_CLS_ACT=y +CONFIG_NET_ACT_GACT=y +CONFIG_NET_ACT_MIRRED=y +CONFIG_NET_ACT_SKBEDIT=y +CONFIG_RMNET_DATA=y +CONFIG_RMNET_DATA_FC=y +CONFIG_RMNET_DATA_DEBUG_PKT=y +CONFIG_SOCKEV_NLMCAST=y +CONFIG_BT=y +CONFIG_MSM_BT_POWER=y +CONFIG_BTFM_SLIM=y +CONFIG_BTFM_SLIM_WCN3990=y +CONFIG_CFG80211=y +CONFIG_CFG80211_INTERNAL_REGDB=y +CONFIG_CFG80211_WEXT=y +CONFIG_MAC80211=m +CONFIG_MAC80211_MESH=y +CONFIG_MAC80211_LEDS=y +CONFIG_RFKILL=y +CONFIG_NFC_NQ=y +CONFIG_IPC_ROUTER=y +CONFIG_IPC_ROUTER_SECURITY=y +CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y +CONFIG_DMA_CMA=y +# CONFIG_PNP_DEBUG_MESSAGES is not set +CONFIG_ZRAM=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_QSEECOM=y +CONFIG_HDCP_QSEECOM=y +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y +CONFIG_CHR_DEV_SG=y +CONFIG_CHR_DEV_SCH=y +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_UFSHCD=y +CONFIG_SCSI_UFSHCD_PLATFORM=y +CONFIG_SCSI_UFS_QCOM=y +CONFIG_SCSI_UFS_QCOM_ICE=y +CONFIG_MD=y +CONFIG_BLK_DEV_MD=y +CONFIG_MD_LINEAR=y +CONFIG_BLK_DEV_DM=y +CONFIG_DM_CRYPT=y +CONFIG_DM_REQ_CRYPT=y +CONFIG_DM_UEVENT=y +CONFIG_DM_VERITY=y +CONFIG_DM_VERITY_FEC=y +CONFIG_DM_ANDROID_VERITY=y +CONFIG_NETDEVICES=y +CONFIG_BONDING=y +CONFIG_DUMMY=y +CONFIG_TUN=y +CONFIG_SKY2=y +CONFIG_RNDIS_IPA=y +CONFIG_SMSC911X=y +CONFIG_PPP=y +CONFIG_PPP_BSDCOMP=y +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_MPPE=y +CONFIG_PPPOLAC=y +CONFIG_PPPOPNS=y +CONFIG_USB_USBNET=y +CONFIG_WCNSS_MEM_PRE_ALLOC=y +CONFIG_ATH_CARDS=y +CONFIG_WIL6210=m +CONFIG_ATH10K=m +CONFIG_ATH10K_TARGET_SNOC=m +CONFIG_ATH10K_SNOC=y +CONFIG_CLD_LL_CORE=y +CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_KEYRESET=y +CONFIG_KEYBOARD_GPIO=y +# CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_CORE_v21=y +CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_v21=y +CONFIG_SECURE_TOUCH=y +CONFIG_TOUCHSCREEN_ST=y +CONFIG_TOUCHSCREEN_ST_I2C=y +CONFIG_INPUT_MISC=y +CONFIG_INPUT_HBTP_INPUT=y +CONFIG_INPUT_QPNP_POWER_ON=y +CONFIG_INPUT_UINPUT=y +# CONFIG_SERIO_SERPORT is not set +# CONFIG_VT is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_DEVMEM is not set +# CONFIG_DEVKMEM is not set +CONFIG_SERIAL_MSM_HS=y +CONFIG_SERIAL_MSM_SMD=y +CONFIG_DIAG_CHAR=y +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_MSM_LEGACY=y +CONFIG_MSM_ADSPRPC=y +CONFIG_MSM_RDBG=m +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_MSM_V2=y +CONFIG_SLIMBUS_MSM_NGD=y +CONFIG_SOUNDWIRE=y +CONFIG_SPI=y +CONFIG_SPI_QUP=y +CONFIG_SPI_SPIDEV=y +CONFIG_SPMI=y +CONFIG_PINCTRL_MSM8998=y +CONFIG_PINCTRL_SDM660=y +CONFIG_GPIOLIB=y +CONFIG_GPIO_SYSFS=y +CONFIG_GPIO_QPNP_PIN=y +CONFIG_POWER_RESET_QCOM=y +CONFIG_QCOM_DLOAD_MODE=y +CONFIG_POWER_RESET_XGENE=y +CONFIG_POWER_RESET_SYSCON=y +CONFIG_QPNP_FG_GEN3=y +CONFIG_MSM_BCL_CTL=y +CONFIG_MSM_BCL_PERIPHERAL_CTL=y +CONFIG_BATTERY_BCL=y +CONFIG_QPNP_SMB2=y +CONFIG_SMB138X_CHARGER=y +CONFIG_QPNP_QNOVO=y +CONFIG_MSM_PM=y +CONFIG_APSS_CORE_EA=y +CONFIG_MSM_APM=y +CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y +CONFIG_CPU_THERMAL=y +CONFIG_LIMITS_MONITOR=y +CONFIG_LIMITS_LITE_HW=y +CONFIG_THERMAL_MONITOR=y +CONFIG_THERMAL_TSENS8974=y +CONFIG_THERMAL_QPNP=y +CONFIG_THERMAL_QPNP_ADC_TM=y +CONFIG_QCOM_THERMAL_LIMITS_DCVS=y +CONFIG_MFD_SPMI_PMIC=y +CONFIG_MFD_I2C_PMIC=y +CONFIG_WCD9335_CODEC=y +CONFIG_WCD934X_CODEC=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_RPM_SMD=y +CONFIG_REGULATOR_QPNP=y +CONFIG_REGULATOR_QPNP_LABIBB=y +CONFIG_REGULATOR_QPNP_LCDB=y +CONFIG_REGULATOR_SPM=y +CONFIG_REGULATOR_CPR3_HMSS=y +CONFIG_REGULATOR_CPR3_MMSS=y +CONFIG_REGULATOR_CPRH_KBSS=y +CONFIG_REGULATOR_MEM_ACC=y +CONFIG_REGULATOR_PROXY_CONSUMER=y +CONFIG_REGULATOR_STUB=y +CONFIG_MEDIA_SUPPORT=y +CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y +CONFIG_MEDIA_CONTROLLER=y +CONFIG_VIDEO_V4L2_SUBDEV_API=y +CONFIG_VIDEO_ADV_DEBUG=y +CONFIG_VIDEO_FIXED_MINOR_RANGES=y +CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_MSM_CAMERA=y +CONFIG_MSM_CAMERA_DEBUG=y +CONFIG_MSMB_CAMERA=y +CONFIG_MSMB_CAMERA_DEBUG=y +CONFIG_MSM_CAMERA_SENSOR=y +CONFIG_MSM_CPP=y +CONFIG_MSM_CCI=y +CONFIG_MSM_CSI20_HEADER=y +CONFIG_MSM_CSI22_HEADER=y +CONFIG_MSM_CSI30_HEADER=y +CONFIG_MSM_CSI31_HEADER=y +CONFIG_MSM_CSIPHY=y +CONFIG_MSM_CSID=y +CONFIG_MSM_EEPROM=y +CONFIG_MSM_ISPIF=y +CONFIG_IMX134=y +CONFIG_IMX132=y +CONFIG_OV9724=y +CONFIG_OV5648=y +CONFIG_GC0339=y +CONFIG_OV8825=y +CONFIG_OV8865=y +CONFIG_s5k4e1=y +CONFIG_OV12830=y +CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE=y +CONFIG_MSMB_JPEG=y +CONFIG_MSM_FD=y +CONFIG_MSM_JPEGDMA=y +CONFIG_MSM_VIDC_V4L2=y +CONFIG_MSM_VIDC_VMEM=y +CONFIG_MSM_VIDC_GOVERNORS=y +CONFIG_MSM_SDE_ROTATOR=y +CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=y +CONFIG_DVB_MPQ=m +CONFIG_DVB_MPQ_DEMUX=m +CONFIG_DVB_MPQ_MEDIA_BOX_DEMUX=y +CONFIG_TSPP=m +CONFIG_DRM=y +CONFIG_LOGO=y +# CONFIG_LOGO_LINUX_MONO is not set +# CONFIG_LOGO_LINUX_VGA16 is not set +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_SND_USB_AUDIO=y +CONFIG_SND_USB_AUDIO_QMI=y +CONFIG_SND_SOC=y +CONFIG_SND_SOC_MSM8998=y +CONFIG_UHID=y +CONFIG_HID_APPLE=y +CONFIG_HID_ELECOM=y +CONFIG_HID_MAGICMOUSE=y +CONFIG_HID_MICROSOFT=y +CONFIG_HID_MULTITOUCH=y +CONFIG_HID_PLANTRONICS=y +CONFIG_USB=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_HCD_PLATFORM=y +CONFIG_USB_OHCI_HCD=y +CONFIG_USB_OHCI_HCD_PLATFORM=y +CONFIG_USB_STORAGE=y +CONFIG_USB_DWC3=y +CONFIG_USB_ISP1760=y +CONFIG_USB_ISP1760_HOST_ROLE=y +CONFIG_USB_PD_POLICY=y +CONFIG_QPNP_USB_PDPHY=y +CONFIG_USB_EHSET_TEST_FIXTURE=y +CONFIG_USB_OTG_WAKELOCK=y +CONFIG_NOP_USB_XCEIV=y +CONFIG_USB_MSM_SSPHY_QMP=y +CONFIG_MSM_QUSB_PHY=y +CONFIG_DUAL_ROLE_USB_INTF=y +CONFIG_USB_GADGET=y +CONFIG_USB_GADGET_VBUS_DRAW=500 +CONFIG_USB_CONFIGFS=y +CONFIG_USB_CONFIGFS_NCM=y +CONFIG_USB_CONFIGFS_MASS_STORAGE=y +CONFIG_USB_CONFIGFS_F_FS=y +CONFIG_USB_CONFIGFS_F_MTP=y +CONFIG_USB_CONFIGFS_F_PTP=y +CONFIG_USB_CONFIGFS_F_ACC=y +CONFIG_USB_CONFIGFS_UEVENT=y +CONFIG_USB_CONFIGFS_F_MIDI=y +CONFIG_USB_CONFIGFS_F_HID=y +CONFIG_USB_CONFIGFS_F_DIAG=y +CONFIG_USB_CONFIGFS_F_GSI=y +CONFIG_USB_CONFIGFS_F_CDEV=y +CONFIG_USB_CONFIGFS_F_QDSS=y +CONFIG_USB_CONFIGFS_F_CCID=y +CONFIG_MMC=y +CONFIG_MMC_PERF_PROFILING=y +CONFIG_MMC_CLKGATE=y +CONFIG_MMC_BLOCK_MINORS=32 +CONFIG_MMC_TEST=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_MSM=y +CONFIG_LEDS_QPNP=y +CONFIG_LEDS_QPNP_FLASH_V2=y +CONFIG_LEDS_QPNP_WLED=y +CONFIG_LEDS_SYSCON=y +CONFIG_SWITCH=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_QPNP=y +CONFIG_ESOC=y +CONFIG_ESOC_DEV=y +CONFIG_ESOC_CLIENT=y +CONFIG_ESOC_MDM_4x=y +CONFIG_ESOC_MDM_DRV=y +CONFIG_DMADEVICES=y +CONFIG_QCOM_SPS_DMA=y +CONFIG_UIO=y +CONFIG_UIO_MSM_SHAREDMEM=y +CONFIG_STAGING=y +CONFIG_ASHMEM=y +CONFIG_ANDROID_TIMED_GPIO=y +CONFIG_ANDROID_LOW_MEMORY_KILLER=y +CONFIG_ION=y +CONFIG_ION_MSM=y +CONFIG_QPNP_REVID=y +CONFIG_QPNP_COINCELL=y +CONFIG_SPS=y +CONFIG_SPS_SUPPORT_NDP_BAM=y +CONFIG_IPA=y +CONFIG_RMNET_IPA=y +CONFIG_GSI=y +CONFIG_IPA3=y +CONFIG_RMNET_IPA3=y +CONFIG_GPIO_USB_DETECT=y +CONFIG_SEEMP_CORE=y +CONFIG_USB_BAM=y +CONFIG_MSM_MDSS_PLL=y +CONFIG_REMOTE_SPINLOCK_MSM=y +CONFIG_MSM_TIMER_LEAP=y +CONFIG_IOMMU_IO_PGTABLE_FAST=y +CONFIG_ARM_SMMU=y +CONFIG_IOMMU_DEBUG=y +CONFIG_IOMMU_DEBUG_TRACKING=y +CONFIG_IOMMU_TESTS=y +CONFIG_MSM_SMEM=y +CONFIG_QPNP_HAPTIC=y +CONFIG_MSM_SMD=y +CONFIG_MSM_GLINK=y +CONFIG_MSM_GLINK_LOOPBACK_SERVER=y +CONFIG_MSM_GLINK_SMD_XPRT=y +CONFIG_MSM_GLINK_SMEM_NATIVE_XPRT=y +CONFIG_MSM_GLINK_SPI_XPRT=y +CONFIG_MSM_SPCOM=y +CONFIG_MSM_SPSS_UTILS=y +CONFIG_MSM_SMEM_LOGGING=y +CONFIG_MSM_SMP2P=y +CONFIG_MSM_SMP2P_TEST=y +CONFIG_MSM_QMI_INTERFACE=y +CONFIG_MSM_RPM_SMD=y +CONFIG_QCOM_BUS_SCALING=y +CONFIG_MSM_SERVICE_LOCATOR=y +CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y +CONFIG_MSM_SYSMON_GLINK_COMM=y +CONFIG_MSM_IPC_ROUTER_GLINK_XPRT=y +CONFIG_MSM_GLINK_PKT=y +CONFIG_MSM_SPM=y +CONFIG_QCOM_WATCHDOG_V2=y +CONFIG_QCOM_IRQ_HELPER=y +CONFIG_QCOM_MEMORY_DUMP_V2=y +CONFIG_ICNSS=y +CONFIG_MSM_RUN_QUEUE_STATS=y +CONFIG_MSM_BOOT_STATS=y +CONFIG_MSM_ADSP_LOADER=y +CONFIG_MSM_PERFORMANCE=y +CONFIG_MSM_SUBSYSTEM_RESTART=y +CONFIG_MSM_PIL=y +CONFIG_MSM_PIL_SSR_GENERIC=y +CONFIG_MSM_PIL_MSS_QDSP6V5=y +CONFIG_TRACER_PKT=y +CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y +CONFIG_MSM_MPM_OF=y +CONFIG_MSM_EVENT_TIMER=y +CONFIG_MSM_AVTIMER=y +CONFIG_QCOM_REMOTEQDSS=y +CONFIG_MSM_SERVICE_NOTIFIER=y +CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y +CONFIG_MSM_RPM_LOG=y +CONFIG_MSM_RPM_STATS_LOG=y +CONFIG_QSEE_IPC_IRQ_BRIDGE=y +CONFIG_QCOM_SMCINVOKE=y +CONFIG_QCOM_EARLY_RANDOM=y +CONFIG_MEM_SHARE_QMI_SERVICE=y +CONFIG_QCOM_BIMC_BWMON=y +CONFIG_ARM_MEMLAT_MON=y +CONFIG_DEVFREQ_GOV_QCOM_BW_HWMON=y +CONFIG_DEVFREQ_GOV_MEMLAT=y +CONFIG_QCOM_DEVFREQ_DEVBW=y +CONFIG_SPDM_SCM=y +CONFIG_DEVFREQ_SPDM=y +CONFIG_EXTCON=y +CONFIG_IIO=y +CONFIG_QCOM_RRADC=y +CONFIG_QCOM_TADC=y +CONFIG_PWM=y +CONFIG_PWM_QPNP=y +CONFIG_ARM_GIC_V3_ACL=y +CONFIG_ANDROID=y +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_ANDROID_BINDER_DEVICES="binder,hwbinder" +CONFIG_MSM_TZ_LOG=y +CONFIG_SENSORS_SSC=y +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT3_FS=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_EXT4_ENCRYPTION=y +CONFIG_EXT4_FS_ENCRYPTION=y +CONFIG_EXT4_FS_ICE_ENCRYPTION=y +CONFIG_FUSE_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_ECRYPT_FS=y +CONFIG_ECRYPT_FS_MESSAGING=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ISO8859_1=y +CONFIG_PRINTK_TIME=y +CONFIG_DEBUG_INFO=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_PANIC_TIMEOUT=5 +CONFIG_SCHEDSTATS=y +# CONFIG_DEBUG_PREEMPT is not set +CONFIG_IPC_LOGGING=y +CONFIG_CPU_FREQ_SWITCH_PROFILER=y +CONFIG_DEBUG_SET_MODULE_RONX=y +CONFIG_DEBUG_ALIGN_RODATA=y +CONFIG_CORESIGHT=y +CONFIG_CORESIGHT_EVENT=y +CONFIG_CORESIGHT_LINK_AND_SINK_TMC=y +CONFIG_CORESIGHT_QCOM_REPLICATOR=y +CONFIG_CORESIGHT_STM=y +CONFIG_CORESIGHT_HWEVENT=y +CONFIG_CORESIGHT_CTI=y +CONFIG_CORESIGHT_TPDA=y +CONFIG_CORESIGHT_TPDM=y +CONFIG_CORESIGHT_QPDI=y +CONFIG_CORESIGHT_SOURCE_DUMMY=y +CONFIG_PFK=y +CONFIG_SECURITY=y +CONFIG_SECURITY_SELINUX=y +CONFIG_SECURITY_SMACK=y +CONFIG_CRYPTO_ECHAINIV=y +CONFIG_CRYPTO_XCBC=y +CONFIG_CRYPTO_MD4=y +CONFIG_CRYPTO_TWOFISH=y +CONFIG_CRYPTO_ANSI_CPRNG=y +CONFIG_CRYPTO_DEV_QCRYPTO=y +CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y +CONFIG_CRYPTO_DEV_QCEDEV=y +CONFIG_CRYPTO_DEV_OTA_CRYPTO=y +CONFIG_CRYPTO_DEV_QCOM_ICE=y +CONFIG_SYSTEM_TRUSTED_KEYS="verity.x509.pem" +CONFIG_ARM64_CRYPTO=y +CONFIG_CRYPTO_SHA1_ARM64_CE=y +CONFIG_CRYPTO_SHA2_ARM64_CE=y +CONFIG_CRYPTO_GHASH_ARM64_CE=y +CONFIG_CRYPTO_AES_ARM64_CE_CCM=y +CONFIG_CRYPTO_AES_ARM64_CE_BLK=y +CONFIG_CRYPTO_AES_ARM64_NEON_BLK=y +CONFIG_CRYPTO_CRC32_ARM64=y +CONFIG_QMI_ENCDEC=y diff --git a/arch/arm64/configs/msmcortex_mediabox_defconfig b/arch/arm64/configs/msmcortex_mediabox_defconfig index 28d900cf5b18..d81c10d11318 100644 --- a/arch/arm64/configs/msmcortex_mediabox_defconfig +++ b/arch/arm64/configs/msmcortex_mediabox_defconfig @@ -638,7 +638,6 @@ CONFIG_PANIC_ON_SCHED_BUG=y CONFIG_PANIC_ON_RT_THROTTLING=y CONFIG_SCHEDSTATS=y CONFIG_SCHED_STACK_END_CHECK=y -CONFIG_TIMER_STATS=y # CONFIG_DEBUG_PREEMPT is not set CONFIG_DEBUG_SPINLOCK=y CONFIG_DEBUG_MUTEXES=y diff --git a/arch/arm64/configs/sdm660-perf_defconfig b/arch/arm64/configs/sdm660-perf_defconfig index b75b4244aa72..939b34f7d6dd 100644 --- a/arch/arm64/configs/sdm660-perf_defconfig +++ b/arch/arm64/configs/sdm660-perf_defconfig @@ -545,7 +545,6 @@ CONFIG_MSM_QMI_INTERFACE=y CONFIG_MSM_RPM_SMD=y CONFIG_QCOM_BUS_SCALING=y CONFIG_MSM_SERVICE_LOCATOR=y -CONFIG_QCOM_DCC=y CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y CONFIG_MSM_SYSMON_GLINK_COMM=y CONFIG_MSM_IPC_ROUTER_GLINK_XPRT=y @@ -619,7 +618,6 @@ CONFIG_DEBUG_INFO=y CONFIG_MAGIC_SYSRQ=y CONFIG_PANIC_TIMEOUT=5 CONFIG_SCHEDSTATS=y -CONFIG_TIMER_STATS=y # CONFIG_DEBUG_PREEMPT is not set CONFIG_IPC_LOGGING=y CONFIG_CPU_FREQ_SWITCH_PROFILER=y diff --git a/arch/arm64/configs/sdm660_defconfig b/arch/arm64/configs/sdm660_defconfig index 3fe9e2bda6d2..aafde733099b 100644 --- a/arch/arm64/configs/sdm660_defconfig +++ b/arch/arm64/configs/sdm660_defconfig @@ -668,7 +668,6 @@ CONFIG_PANIC_ON_SCHED_BUG=y CONFIG_PANIC_ON_RT_THROTTLING=y CONFIG_SCHEDSTATS=y CONFIG_SCHED_STACK_END_CHECK=y -CONFIG_TIMER_STATS=y # CONFIG_DEBUG_PREEMPT is not set CONFIG_DEBUG_SPINLOCK=y CONFIG_DEBUG_MUTEXES=y diff --git a/arch/arm64/include/asm/exec.h b/arch/arm64/include/asm/exec.h index db0563c23482..f7865dd9d868 100644 --- a/arch/arm64/include/asm/exec.h +++ b/arch/arm64/include/asm/exec.h @@ -18,6 +18,9 @@ #ifndef __ASM_EXEC_H #define __ASM_EXEC_H +#include <linux/sched.h> + extern unsigned long arch_align_stack(unsigned long sp); +void uao_thread_switch(struct task_struct *next); #endif /* __ASM_EXEC_H */ diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c index 5a09efa75722..fc0a7aa2ca82 100644 --- a/arch/arm64/kernel/process.c +++ b/arch/arm64/kernel/process.c @@ -49,6 +49,7 @@ #include <asm/alternative.h> #include <asm/compat.h> #include <asm/cacheflush.h> +#include <asm/exec.h> #include <asm/fpsimd.h> #include <asm/mmu_context.h> #include <asm/processor.h> @@ -383,7 +384,7 @@ static void tls_thread_switch(struct task_struct *next) } /* Restore the UAO state depending on next's addr_limit */ -static void uao_thread_switch(struct task_struct *next) +void uao_thread_switch(struct task_struct *next) { if (IS_ENABLED(CONFIG_ARM64_UAO)) { if (task_thread_info(next)->addr_limit == KERNEL_DS) diff --git a/arch/arm64/kernel/suspend.c b/arch/arm64/kernel/suspend.c index 5a0b1088c17c..0acdb63d19b6 100644 --- a/arch/arm64/kernel/suspend.c +++ b/arch/arm64/kernel/suspend.c @@ -5,6 +5,7 @@ #include <asm/cacheflush.h> #include <asm/cpufeature.h> #include <asm/debug-monitors.h> +#include <asm/exec.h> #include <asm/pgtable.h> #include <asm/memory.h> #include <asm/mmu_context.h> @@ -95,6 +96,7 @@ int cpu_suspend(unsigned long arg, int (*fn)(unsigned long)) */ asm(ALTERNATIVE("nop", SET_PSTATE_PAN(1), ARM64_HAS_PAN, CONFIG_ARM64_PAN)); + uao_thread_switch(current); /* * Restore HW breakpoint registers to sane values diff --git a/arch/mips/kernel/crash.c b/arch/mips/kernel/crash.c index d434d5d5ae6e..610f0f3bdb34 100644 --- a/arch/mips/kernel/crash.c +++ b/arch/mips/kernel/crash.c @@ -14,12 +14,22 @@ static int crashing_cpu = -1; static cpumask_t cpus_in_crash = CPU_MASK_NONE; #ifdef CONFIG_SMP -static void crash_shutdown_secondary(void *ignore) +static void crash_shutdown_secondary(void *passed_regs) { - struct pt_regs *regs; + struct pt_regs *regs = passed_regs; int cpu = smp_processor_id(); - regs = task_pt_regs(current); + /* + * If we are passed registers, use those. Otherwise get the + * regs from the last interrupt, which should be correct, as + * we are in an interrupt. But if the regs are not there, + * pull them from the top of the stack. They are probably + * wrong, but we need something to keep from crashing again. + */ + if (!regs) + regs = get_irq_regs(); + if (!regs) + regs = task_pt_regs(current); if (!cpu_online(cpu)) return; diff --git a/arch/mips/kernel/elf.c b/arch/mips/kernel/elf.c index 4a4d9e067c89..3afffc30ee12 100644 --- a/arch/mips/kernel/elf.c +++ b/arch/mips/kernel/elf.c @@ -206,7 +206,7 @@ int arch_check_elf(void *_ehdr, bool has_interpreter, else if ((prog_req.fr1 && prog_req.frdefault) || (prog_req.single && !prog_req.frdefault)) /* Make sure 64-bit MIPS III/IV/64R1 will not pick FR1 */ - state->overall_fp_mode = ((current_cpu_data.fpu_id & MIPS_FPIR_F64) && + state->overall_fp_mode = ((raw_current_cpu_data.fpu_id & MIPS_FPIR_F64) && cpu_has_mips_r2_r6) ? FP_FR1 : FP_FR0; else if (prog_req.fr1) diff --git a/arch/mips/kernel/kgdb.c b/arch/mips/kernel/kgdb.c index de63d36af895..732d6171ac6a 100644 --- a/arch/mips/kernel/kgdb.c +++ b/arch/mips/kernel/kgdb.c @@ -244,9 +244,6 @@ static int compute_signal(int tt) void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p) { int reg; - struct thread_info *ti = task_thread_info(p); - unsigned long ksp = (unsigned long)ti + THREAD_SIZE - 32; - struct pt_regs *regs = (struct pt_regs *)ksp - 1; #if (KGDB_GDB_REG_SIZE == 32) u32 *ptr = (u32 *)gdb_regs; #else @@ -254,25 +251,46 @@ void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p) #endif for (reg = 0; reg < 16; reg++) - *(ptr++) = regs->regs[reg]; + *(ptr++) = 0; /* S0 - S7 */ - for (reg = 16; reg < 24; reg++) - *(ptr++) = regs->regs[reg]; + *(ptr++) = p->thread.reg16; + *(ptr++) = p->thread.reg17; + *(ptr++) = p->thread.reg18; + *(ptr++) = p->thread.reg19; + *(ptr++) = p->thread.reg20; + *(ptr++) = p->thread.reg21; + *(ptr++) = p->thread.reg22; + *(ptr++) = p->thread.reg23; for (reg = 24; reg < 28; reg++) *(ptr++) = 0; /* GP, SP, FP, RA */ - for (reg = 28; reg < 32; reg++) - *(ptr++) = regs->regs[reg]; - - *(ptr++) = regs->cp0_status; - *(ptr++) = regs->lo; - *(ptr++) = regs->hi; - *(ptr++) = regs->cp0_badvaddr; - *(ptr++) = regs->cp0_cause; - *(ptr++) = regs->cp0_epc; + *(ptr++) = (long)p; + *(ptr++) = p->thread.reg29; + *(ptr++) = p->thread.reg30; + *(ptr++) = p->thread.reg31; + + *(ptr++) = p->thread.cp0_status; + + /* lo, hi */ + *(ptr++) = 0; + *(ptr++) = 0; + + /* + * BadVAddr, Cause + * Ideally these would come from the last exception frame up the stack + * but that requires unwinding, otherwise we can't know much for sure. + */ + *(ptr++) = 0; + *(ptr++) = 0; + + /* + * PC + * use return address (RA), i.e. the moment after return from resume() + */ + *(ptr++) = p->thread.reg31; } void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long pc) diff --git a/arch/sparc/include/asm/pgtable_64.h b/arch/sparc/include/asm/pgtable_64.h index 408b715c95a5..9d81579f3d54 100644 --- a/arch/sparc/include/asm/pgtable_64.h +++ b/arch/sparc/include/asm/pgtable_64.h @@ -668,26 +668,27 @@ static inline unsigned long pmd_pfn(pmd_t pmd) return pte_pfn(pte); } -#ifdef CONFIG_TRANSPARENT_HUGEPAGE -static inline unsigned long pmd_dirty(pmd_t pmd) +#define __HAVE_ARCH_PMD_WRITE +static inline unsigned long pmd_write(pmd_t pmd) { pte_t pte = __pte(pmd_val(pmd)); - return pte_dirty(pte); + return pte_write(pte); } -static inline unsigned long pmd_young(pmd_t pmd) +#ifdef CONFIG_TRANSPARENT_HUGEPAGE +static inline unsigned long pmd_dirty(pmd_t pmd) { pte_t pte = __pte(pmd_val(pmd)); - return pte_young(pte); + return pte_dirty(pte); } -static inline unsigned long pmd_write(pmd_t pmd) +static inline unsigned long pmd_young(pmd_t pmd) { pte_t pte = __pte(pmd_val(pmd)); - return pte_write(pte); + return pte_young(pte); } static inline unsigned long pmd_trans_huge(pmd_t pmd) diff --git a/arch/sparc/mm/init_64.c b/arch/sparc/mm/init_64.c index 3d3414c14792..965655afdbb6 100644 --- a/arch/sparc/mm/init_64.c +++ b/arch/sparc/mm/init_64.c @@ -1493,7 +1493,7 @@ bool kern_addr_valid(unsigned long addr) if ((long)addr < 0L) { unsigned long pa = __pa(addr); - if ((addr >> max_phys_bits) != 0UL) + if ((pa >> max_phys_bits) != 0UL) return false; return pfn_valid(pa >> PAGE_SHIFT); diff --git a/arch/x86/kernel/ftrace.c b/arch/x86/kernel/ftrace.c index eb6bd34582c6..1b96bfe09d42 100644 --- a/arch/x86/kernel/ftrace.c +++ b/arch/x86/kernel/ftrace.c @@ -977,6 +977,18 @@ void prepare_ftrace_return(unsigned long self_addr, unsigned long *parent, unsigned long return_hooker = (unsigned long) &return_to_handler; + /* + * When resuming from suspend-to-ram, this function can be indirectly + * called from early CPU startup code while the CPU is in real mode, + * which would fail miserably. Make sure the stack pointer is a + * virtual address. + * + * This check isn't as accurate as virt_addr_valid(), but it should be + * good enough for this purpose, and it's fast. + */ + if (unlikely((long)__builtin_frame_address(0) >= 0)) + return; + if (unlikely(ftrace_graph_is_dead())) return; diff --git a/arch/x86/xen/time.c b/arch/x86/xen/time.c index f1ba6a092854..8846257d8792 100644 --- a/arch/x86/xen/time.c +++ b/arch/x86/xen/time.c @@ -343,11 +343,11 @@ static int xen_vcpuop_set_next_event(unsigned long delta, WARN_ON(!clockevent_state_oneshot(evt)); single.timeout_abs_ns = get_abs_timeout(delta); - single.flags = VCPU_SSHOTTMR_future; + /* Get an event anyway, even if the timeout is already expired */ + single.flags = 0; ret = HYPERVISOR_vcpu_op(VCPUOP_set_singleshot_timer, cpu, &single); - - BUG_ON(ret != 0 && ret != -ETIME); + BUG_ON(ret != 0); return ret; } diff --git a/crypto/testmgr.c b/crypto/testmgr.c index 8374ca8b6579..6d4da8fd24fd 100644 --- a/crypto/testmgr.c +++ b/crypto/testmgr.c @@ -488,6 +488,8 @@ static int __test_aead(struct crypto_aead *tfm, int enc, aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, tcrypt_complete, &result); + iv_len = crypto_aead_ivsize(tfm); + for (i = 0, j = 0; i < tcount; i++) { if (template[i].np) continue; @@ -508,7 +510,6 @@ static int __test_aead(struct crypto_aead *tfm, int enc, memcpy(input, template[i].input, template[i].ilen); memcpy(assoc, template[i].assoc, template[i].alen); - iv_len = crypto_aead_ivsize(tfm); if (template[i].iv) memcpy(iv, template[i].iv, iv_len); else @@ -617,7 +618,7 @@ static int __test_aead(struct crypto_aead *tfm, int enc, j++; if (template[i].iv) - memcpy(iv, template[i].iv, MAX_IVLEN); + memcpy(iv, template[i].iv, iv_len); else memset(iv, 0, MAX_IVLEN); diff --git a/drivers/block/drbd/drbd_bitmap.c b/drivers/block/drbd/drbd_bitmap.c index 9462d2752850..8bdc34dbaedf 100644 --- a/drivers/block/drbd/drbd_bitmap.c +++ b/drivers/block/drbd/drbd_bitmap.c @@ -479,8 +479,14 @@ void drbd_bm_cleanup(struct drbd_device *device) * this masks out the remaining bits. * Returns the number of bits cleared. */ +#ifndef BITS_PER_PAGE #define BITS_PER_PAGE (1UL << (PAGE_SHIFT + 3)) #define BITS_PER_PAGE_MASK (BITS_PER_PAGE - 1) +#else +# if BITS_PER_PAGE != (1UL << (PAGE_SHIFT + 3)) +# error "ambiguous BITS_PER_PAGE" +# endif +#endif #define BITS_PER_LONG_MASK (BITS_PER_LONG - 1) static int bm_clear_surplus(struct drbd_bitmap *b) { diff --git a/drivers/bluetooth/bluetooth-power.c b/drivers/bluetooth/bluetooth-power.c index b05b999fbbdc..59245ba320f6 100644 --- a/drivers/bluetooth/bluetooth-power.c +++ b/drivers/bluetooth/bluetooth-power.c @@ -704,6 +704,7 @@ static long bt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) } else { BT_PWR_ERR("BT chip state is already :%d no change d\n" , pwr_state); + ret = 0; } break; default: diff --git a/drivers/bluetooth/btfm_slim.h b/drivers/bluetooth/btfm_slim.h index 5d105fba2193..e67c6964ee65 100644 --- a/drivers/bluetooth/btfm_slim.h +++ b/drivers/bluetooth/btfm_slim.h @@ -13,7 +13,7 @@ #define BTFM_SLIM_H #include <linux/slimbus/slimbus.h> -#define BTFMSLIM_DBG(fmt, arg...) pr_debug(fmt "\n", ## arg) +#define BTFMSLIM_DBG(fmt, arg...) pr_debug("%s: " fmt "\n", __func__, ## arg) #define BTFMSLIM_INFO(fmt, arg...) pr_info("%s: " fmt "\n", __func__, ## arg) #define BTFMSLIM_ERR(fmt, arg...) pr_err("%s: " fmt "\n", __func__, ## arg) diff --git a/drivers/bluetooth/btfm_slim_codec.c b/drivers/bluetooth/btfm_slim_codec.c index 1ed366fd3d71..4dd8e6833ccf 100644 --- a/drivers/bluetooth/btfm_slim_codec.c +++ b/drivers/bluetooth/btfm_slim_codec.c @@ -332,6 +332,9 @@ static int btfm_slim_dai_get_channel_map(struct snd_soc_dai *dai, *tx_num = 0; *rx_num = num; break; + default: + BTFMSLIM_ERR("Unsupported DAI %d", dai->id); + return -EINVAL; } do { diff --git a/drivers/bluetooth/btfm_slim_wcn3990.c b/drivers/bluetooth/btfm_slim_wcn3990.c index c93b29281e35..a451ff33103c 100644 --- a/drivers/bluetooth/btfm_slim_wcn3990.c +++ b/drivers/bluetooth/btfm_slim_wcn3990.c @@ -83,19 +83,34 @@ int btfm_slim_chrk_enable_port(struct btfmslim *btfmslim, uint8_t port_num, { int ret = 0; uint8_t reg_val = 0; + uint8_t port_bit = 0; uint16_t reg; BTFMSLIM_DBG("port(%d) enable(%d)", port_num, enable); if (rxport) { + if (enable) { + /* For SCO Rx, A2DP Rx */ + reg_val = 0x1; + port_bit = port_num - 0x10; + reg = CHRK_SB_PGD_RX_PORTn_MULTI_CHNL_0(port_bit); + BTFMSLIM_DBG("writing reg_val (%d) to reg(%x)", + reg_val, reg); + ret = btfm_slim_write(btfmslim, reg, 1, ®_val, IFD); + if (ret) { + BTFMSLIM_ERR("failed to write (%d) reg 0x%x", + ret, reg); + goto error; + } + } /* Port enable */ reg = CHRK_SB_PGD_PORT_RX_CFGN(port_num - 0x10); goto enable_disable_rxport; } - /* txport */ if (!enable) goto enable_disable_txport; - /* Multiple Channel Setting - only for FM Tx */ + /* txport */ + /* Multiple Channel Setting */ if (is_fm_port(port_num)) { reg_val = (0x1 << CHRK_SB_PGD_PORT_TX1_FM) | (0x1 << CHRK_SB_PGD_PORT_TX2_FM); @@ -105,6 +120,18 @@ int btfm_slim_chrk_enable_port(struct btfmslim *btfmslim, uint8_t port_num, BTFMSLIM_ERR("failed to write (%d) reg 0x%x", ret, reg); goto error; } + } else if (port_num == CHRK_SB_PGD_PORT_TX_SCO) { + /* SCO Tx */ + reg_val = 0x1 << CHRK_SB_PGD_PORT_TX_SCO; + reg = CHRK_SB_PGD_TX_PORTn_MULTI_CHNL_0(port_num); + BTFMSLIM_DBG("writing reg_val (%d) to reg(%x)", + reg_val, reg); + ret = btfm_slim_write(btfmslim, reg, 1, ®_val, IFD); + if (ret) { + BTFMSLIM_ERR("failed to write (%d) reg 0x%x", + ret, reg); + goto error; + } } /* Enable Tx port hw auto recovery for underrun or overrun error */ diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c index 7e44b38bbfca..1b76f58809b3 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)); @@ -1584,6 +1585,7 @@ static int fastrpc_init_process(struct fastrpc_file *fl, struct fastrpc_ioctl_init *init = &uproc->init; struct smq_phy_page pages[1]; struct fastrpc_mmap *file = 0, *mem = 0; + char *proc_name = NULL; int srcVM[1] = {VMID_HLOS}; int destVM[1] = {VMID_ADSP_Q6}; int destVMperm[1] = {PERM_READ | PERM_WRITE | PERM_EXEC}; @@ -1679,12 +1681,18 @@ static int fastrpc_init_process(struct fastrpc_file *fl, uint64_t phys = 0; ssize_t size = 0; int fds[3]; - char *proc_name = (unsigned char *)init->file; struct { int pgid; int namelen; int pageslen; } inbuf; + VERIFY(err, proc_name = kzalloc(init->filelen, GFP_KERNEL)); + if (err) + goto bail; + VERIFY(err, 0 == copy_from_user(proc_name, + (unsigned char *)init->file, init->filelen)); + if (err) + goto bail; inbuf.pgid = current->tgid; inbuf.namelen = strlen(proc_name)+1; inbuf.pageslen = 0; @@ -1737,6 +1745,7 @@ static int fastrpc_init_process(struct fastrpc_file *fl, err = -ENOTTY; } bail: + kfree(proc_name); if (err && (init->flags == FASTRPC_INIT_CREATE_STATIC)) me->staticpd_flags = 0; if (mem && err) { @@ -2126,11 +2135,9 @@ void fastrpc_glink_notify_state(void *handle, const void *priv, unsigned event) link->port_state = FASTRPC_LINK_DISCONNECTED; break; case GLINK_REMOTE_DISCONNECTED: - if (me->channel[cid].chan && - link->link_state == FASTRPC_LINK_STATE_UP) { + if (me->channel[cid].chan) { fastrpc_glink_close(me->channel[cid].chan, cid); me->channel[cid].chan = 0; - link->port_state = FASTRPC_LINK_DISCONNECTED; } break; default: @@ -2296,10 +2303,9 @@ static int fastrpc_glink_open(int cid) if (err) goto bail; - if (link->port_state == FASTRPC_LINK_CONNECTED || - link->port_state == FASTRPC_LINK_CONNECTING) { + VERIFY(err, (link->port_state == FASTRPC_LINK_DISCONNECTED)); + if (err) goto bail; - } link->port_state = FASTRPC_LINK_CONNECTING; cfg->priv = (void *)(uintptr_t)cid; @@ -2443,6 +2449,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) { @@ -2451,14 +2460,13 @@ 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)) { if (me->glink) { - fastrpc_glink_register(cid, me); + VERIFY(err, 0 == fastrpc_glink_register(cid, me)); + if (err) + goto bail; VERIFY(err, 0 == fastrpc_glink_open(cid)); } else { VERIFY(err, !smd_named_open_on_edge(FASTRPC_SMD_GUID, diff --git a/drivers/char/diag/diag_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/diag_memorydevice.c b/drivers/char/diag/diag_memorydevice.c index bd34e6cceec0..a5d92c51cc0b 100644 --- a/drivers/char/diag/diag_memorydevice.c +++ b/drivers/char/diag/diag_memorydevice.c @@ -252,6 +252,7 @@ int diag_md_copy_to_user(char __user *buf, int *pret, size_t buf_size, uint8_t drain_again = 0; uint8_t peripheral = 0; struct diag_md_session_t *session_info = NULL; + struct pid *pid_struct = NULL; mutex_lock(&driver->diagfwd_untag_mutex); @@ -278,6 +279,14 @@ int diag_md_copy_to_user(char __user *buf, int *pret, size_t buf_size, if ((info && (info->peripheral_mask & MD_PERIPHERAL_MASK(peripheral)) == 0)) goto drop_data; + pid_struct = find_get_pid(session_info->pid); + if (!pid_struct) { + err = -ESRCH; + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "diag: No such md_session_map[%d] with pid = %d err=%d exists..\n", + peripheral, session_info->pid, err); + goto drop_data; + } /* * If the data is from remote processor, copy the remote * token first @@ -297,27 +306,35 @@ int diag_md_copy_to_user(char __user *buf, int *pret, size_t buf_size, } if (i > 0) { remote_token = diag_get_remote(i); - err = copy_to_user(buf + ret, &remote_token, - sizeof(int)); + if (get_pid_task(pid_struct, PIDTYPE_PID)) { + err = copy_to_user(buf + ret, + &remote_token, + sizeof(int)); + if (err) + goto drop_data; + ret += sizeof(int); + } + } + + /* Copy the length of data being passed */ + if (get_pid_task(pid_struct, PIDTYPE_PID)) { + err = copy_to_user(buf + ret, + (void *)&(entry->len), + sizeof(int)); if (err) goto drop_data; ret += sizeof(int); } - /* Copy the length of data being passed */ - err = copy_to_user(buf + ret, (void *)&(entry->len), - sizeof(int)); - if (err) - goto drop_data; - ret += sizeof(int); - /* Copy the actual data being passed */ - err = copy_to_user(buf + ret, (void *)entry->buf, - entry->len); - if (err) - goto drop_data; - ret += entry->len; - + if (get_pid_task(pid_struct, PIDTYPE_PID)) { + err = copy_to_user(buf + ret, + (void *)entry->buf, + entry->len); + if (err) + goto drop_data; + ret += entry->len; + } /* * The data is now copied to the user space client, * Notify that the write is complete and delete its @@ -339,7 +356,15 @@ drop_data: } *pret = ret; - err = copy_to_user(buf + sizeof(int), (void *)&num_data, sizeof(int)); + if (pid_struct && get_pid_task(pid_struct, PIDTYPE_PID)) { + err = copy_to_user(buf + sizeof(int), + (void *)&num_data, + sizeof(int)); + } else { + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "diag: md_session_map[%d] with pid = %d Exited..\n", + peripheral, driver->md_session_map[peripheral]->pid); + } diag_ws_on_copy_complete(DIAG_WS_MUX); if (drain_again) chk_logging_wakeup(); diff --git a/drivers/char/diag/diag_mux.c b/drivers/char/diag/diag_mux.c index 39f4b08d9b0a..d6f6ea7af8ea 100644 --- a/drivers/char/diag/diag_mux.c +++ b/drivers/char/diag/diag_mux.c @@ -153,8 +153,13 @@ int diag_mux_write(int proc, unsigned char *buf, int len, int ctx) upd = PERIPHERAL_CDSP; break; case UPD_WLAN: + if (!driver->num_pd_session) + upd = PERIPHERAL_MODEM; + break; case UPD_AUDIO: case UPD_SENSORS: + if (!driver->num_pd_session) + upd = PERIPHERAL_LPASS; break; default: pr_err("diag: invalid pd ctxt= %d\n", upd); 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 682c035c5bd4..60bfb2af49d0 100644 --- a/drivers/char/diag/diagchar_core.c +++ b/drivers/char/diag/diagchar_core.c @@ -2341,7 +2341,9 @@ long diagchar_ioctl(struct file *filp, mutex_unlock(&driver->dci_mutex); break; case DIAG_IOCTL_DCI_EVENT_STATUS: + mutex_lock(&driver->dci_mutex); result = diag_ioctl_dci_event_status(ioarg); + mutex_unlock(&driver->dci_mutex); break; case DIAG_IOCTL_DCI_CLEAR_LOGS: mutex_lock(&driver->dci_mutex); @@ -3568,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/clk/clk.c b/drivers/clk/clk.c index 4996f4f312f4..73d65813de8b 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -1751,6 +1751,15 @@ static int clk_change_rate(struct clk_core *core) else if (core->parent) best_parent_rate = core->parent->rate; + trace_clk_set_rate(core, core->new_rate); + + /* Enforce vdd requirements for new frequency. */ + if (core->prepare_count) { + rc = clk_vote_rate_vdd(core, core->new_rate); + if (rc) + goto out; + } + if (core->new_parent && core->new_parent != core->parent) { old_parent = __clk_set_parent_before(core, core->new_parent); trace_clk_set_parent(core, core->new_parent); @@ -1768,15 +1777,6 @@ static int clk_change_rate(struct clk_core *core) __clk_set_parent_after(core, core->new_parent, old_parent); } - trace_clk_set_rate(core, core->new_rate); - - /* Enforce vdd requirements for new frequency. */ - if (core->prepare_count) { - rc = clk_vote_rate_vdd(core, core->new_rate); - if (rc) - goto out; - } - if (!skip_set_rate && core->ops->set_rate) { rc = core->ops->set_rate(core->hw, core->new_rate, best_parent_rate); diff --git a/drivers/clk/sunxi/clk-simple-gates.c b/drivers/clk/sunxi/clk-simple-gates.c index 0214c6548afd..97cb4221de25 100644 --- a/drivers/clk/sunxi/clk-simple-gates.c +++ b/drivers/clk/sunxi/clk-simple-gates.c @@ -98,6 +98,8 @@ static void __init sunxi_simple_gates_init(struct device_node *node) sunxi_simple_gates_setup(node, NULL, 0); } +CLK_OF_DECLARE(sun4i_a10_gates, "allwinner,sun4i-a10-gates-clk", + sunxi_simple_gates_init); CLK_OF_DECLARE(sun4i_a10_apb0, "allwinner,sun4i-a10-apb0-gates-clk", sunxi_simple_gates_init); CLK_OF_DECLARE(sun4i_a10_apb1, "allwinner,sun4i-a10-apb1-gates-clk", diff --git a/drivers/crypto/msm/ota_crypto.c b/drivers/crypto/msm/ota_crypto.c index 674913cb20bf..a568bf46f09f 100644 --- a/drivers/crypto/msm/ota_crypto.c +++ b/drivers/crypto/msm/ota_crypto.c @@ -239,6 +239,9 @@ static void req_done(unsigned long data) if (!list_empty(&podev->ready_commands)) { new_req = container_of(podev->ready_commands.next, struct ota_async_req, rlist); + if (!new_req) + break; + list_del(&new_req->rlist); pqce->active_command = new_req; spin_unlock_irqrestore(&podev->lock, flags); 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/amd/amdgpu/kv_dpm.c b/drivers/gpu/drm/amd/amdgpu/kv_dpm.c index 7e9154c7f1db..d1c9525d81eb 100644 --- a/drivers/gpu/drm/amd/amdgpu/kv_dpm.c +++ b/drivers/gpu/drm/amd/amdgpu/kv_dpm.c @@ -2258,7 +2258,7 @@ static void kv_apply_state_adjust_rules(struct amdgpu_device *adev, if (pi->caps_stable_p_state) { stable_p_state_sclk = (max_limits->sclk * 75) / 100; - for (i = table->count - 1; i >= 0; i++) { + for (i = table->count - 1; i >= 0; i--) { if (stable_p_state_sclk >= table->entries[i].clk) { stable_p_state_sclk = table->entries[i].clk; break; diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c index de2ee1ffb735..ac6c47bd33ae 100644 --- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c @@ -15,6 +15,9 @@ #include "msm_iommu.h" #include "a5xx_gpu.h" +#define SECURE_VA_START 0xc0000000 +#define SECURE_VA_SIZE SZ_256M + static void a5xx_flush(struct msm_gpu *gpu, struct msm_ringbuffer *ring) { struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); @@ -100,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); @@ -133,6 +136,12 @@ static int a5xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit) OUT_PKT7(ring, CP_YIELD_ENABLE, 1); OUT_RING(ring, 0x02); + /* Turn on secure mode if the submission is secure */ + if (submit->secure) { + OUT_PKT7(ring, CP_SET_SECURE_MODE, 1); + OUT_RING(ring, 1); + } + /* Record the always on counter before command execution */ if (submit->profile_buf_iova) { uint64_t gpuaddr = submit->profile_buf_iova + @@ -212,6 +221,11 @@ static int a5xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit) OUT_RING(ring, upper_32_bits(rbmemptr(adreno_gpu, ring->id, fence))); OUT_RING(ring, submit->fence); + if (submit->secure) { + OUT_PKT7(ring, CP_SET_SECURE_MODE, 1); + OUT_RING(ring, 0); + } + /* Yield the floor on command completion */ OUT_PKT7(ring, CP_CONTEXT_SWITCH_YIELD, 4); /* @@ -259,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 { @@ -762,14 +774,10 @@ static int a5xx_hw_init(struct msm_gpu *gpu) ADRENO_PROTECT_RW(0x10000, 0x8000)); gpu_write(gpu, REG_A5XX_RBBM_SECVID_TSB_CNTL, 0); - /* - * Disable the trusted memory range - we don't actually supported secure - * memory rendering at this point in time and we don't want to block off - * part of the virtual memory space. - */ + gpu_write64(gpu, REG_A5XX_RBBM_SECVID_TSB_TRUSTED_BASE_LO, - REG_A5XX_RBBM_SECVID_TSB_TRUSTED_BASE_HI, 0x00000000); - gpu_write(gpu, REG_A5XX_RBBM_SECVID_TSB_TRUSTED_SIZE, 0x00000000); + REG_A5XX_RBBM_SECVID_TSB_TRUSTED_BASE_HI, SECURE_VA_START); + gpu_write(gpu, REG_A5XX_RBBM_SECVID_TSB_TRUSTED_SIZE, SECURE_VA_SIZE); /* Put the GPU into 64 bit by default */ gpu_write(gpu, REG_A5XX_CP_ADDR_MODE_CNTL, 0x1); @@ -1405,6 +1413,9 @@ struct msm_gpu *a5xx_gpu_init(struct drm_device *dev) a5xx_config.va_start = 0x800000000; a5xx_config.va_end = 0x8ffffffff; + a5xx_config.secure_va_start = SECURE_VA_START; + a5xx_config.secure_va_end = SECURE_VA_START + SECURE_VA_SIZE - 1; + ret = adreno_gpu_init(dev, pdev, adreno_gpu, &funcs, &a5xx_config); if (ret) { a5xx_destroy(&(a5xx_gpu->base.base)); diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c index 9952fa8dcda5..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) @@ -563,6 +561,15 @@ int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev, return ret; } + if (gpu->secure_aspace) { + mmu = gpu->secure_aspace->mmu; + if (mmu) { + ret = mmu->funcs->attach(mmu, NULL, 0); + if (ret) + return ret; + } + } + mutex_lock(&drm->struct_mutex); adreno_gpu->memptrs_bo = msm_gem_new(drm, sizeof(*adreno_gpu->memptrs), MSM_BO_UNCACHED); @@ -608,6 +615,12 @@ void adreno_gpu_cleanup(struct adreno_gpu *gpu) aspace->mmu->funcs->detach(aspace->mmu); msm_gem_address_space_put(aspace); } + + if (gpu->base.secure_aspace) { + aspace = gpu->base.secure_aspace; + aspace->mmu->funcs->detach(aspace->mmu); + msm_gem_address_space_put(aspace); + } } static void adreno_snapshot_os(struct msm_gpu *gpu, 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/hdmi-staging/sde_hdmi.c b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c index 1ff3ee2bdca6..c377f3759e67 100644 --- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c +++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c @@ -934,7 +934,6 @@ static void _sde_hdmi_hotplug_work(struct work_struct *work) } else sde_free_edid((void **)&sde_hdmi->edid_ctrl); - sde_hdmi_notify_clients(connector, sde_hdmi->connected); drm_helper_hpd_irq_event(connector->dev); } @@ -964,8 +963,7 @@ static void _sde_hdmi_connector_irq(struct sde_hdmi *sde_hdmi) hpd_int_ctrl |= HDMI_HPD_INT_CTRL_INT_CONNECT; hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL, hpd_int_ctrl); - if (!sde_hdmi->non_pluggable) - queue_work(hdmi->workq, &sde_hdmi->hpd_work); + queue_work(hdmi->workq, &sde_hdmi->hpd_work); } } @@ -1054,6 +1052,25 @@ static int _sde_hdmi_get_cable_status(struct platform_device *pdev, u32 vote) return hdmi->power_on && display->connected; } +static void _sde_hdmi_audio_codec_ready(struct platform_device *pdev) +{ + struct sde_hdmi *display = platform_get_drvdata(pdev); + + if (!display) { + SDE_ERROR("invalid param(s), display %pK\n", display); + return; + } + + mutex_lock(&display->display_lock); + if (!display->codec_ready) { + display->codec_ready = true; + + if (display->client_notify_pending) + sde_hdmi_notify_clients(display, display->connected); + } + mutex_unlock(&display->display_lock); +} + static int _sde_hdmi_ext_disp_init(struct sde_hdmi *display) { int rc = 0; @@ -1073,6 +1090,8 @@ static int _sde_hdmi_ext_disp_init(struct sde_hdmi *display) _sde_hdmi_get_audio_edid_blk; display->ext_audio_data.codec_ops.cable_status = _sde_hdmi_get_cable_status; + display->ext_audio_data.codec_ops.codec_ready = + _sde_hdmi_audio_codec_ready; if (!display->pdev->dev.of_node) { SDE_ERROR("[%s]cannot find sde_hdmi of_node\n", display->name); @@ -1101,17 +1120,14 @@ static int _sde_hdmi_ext_disp_init(struct sde_hdmi *display) return rc; } -void sde_hdmi_notify_clients(struct drm_connector *connector, - bool connected) +void sde_hdmi_notify_clients(struct sde_hdmi *display, bool connected) { - struct sde_connector *c_conn = to_sde_connector(connector); - struct sde_hdmi *display = (struct sde_hdmi *)c_conn->display; int state = connected ? EXT_DISPLAY_CABLE_CONNECT : EXT_DISPLAY_CABLE_DISCONNECT; if (display && display->ext_audio_data.intf_ops.hpd) { struct hdmi *hdmi = display->ctrl.ctrl; - u32 flags = MSM_EXT_DISP_HPD_VIDEO; + u32 flags = MSM_EXT_DISP_HPD_ASYNC_VIDEO; if (hdmi->hdmi_mode) flags |= MSM_EXT_DISP_HPD_AUDIO; @@ -1121,21 +1137,6 @@ void sde_hdmi_notify_clients(struct drm_connector *connector, } } -void sde_hdmi_ack_state(struct drm_connector *connector, - enum drm_connector_status status) -{ - struct sde_connector *c_conn = to_sde_connector(connector); - struct sde_hdmi *display = (struct sde_hdmi *)c_conn->display; - - if (display) { - struct hdmi *hdmi = display->ctrl.ctrl; - - if (hdmi->hdmi_mode && display->ext_audio_data.intf_ops.notify) - display->ext_audio_data.intf_ops.notify( - display->ext_pdev, status); - } -} - void sde_hdmi_set_mode(struct hdmi *hdmi, bool power_on) { uint32_t ctrl = 0; @@ -1427,8 +1428,8 @@ int sde_hdmi_get_info(struct msm_display_info *info, MSM_DISPLAY_CAP_EDID | MSM_DISPLAY_CAP_VID_MODE; } info->is_connected = hdmi_display->connected; - info->max_width = 1920; - info->max_height = 1080; + info->max_width = 4096; + info->max_height = 2160; info->compression = MSM_DISPLAY_COMPRESS_NONE; mutex_unlock(&hdmi_display->display_lock); diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h index ecdace10d0c3..ffa9a27e7dfe 100644 --- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h +++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h @@ -84,6 +84,8 @@ struct sde_hdmi_ctrl { * @connected: If HDMI display is connected. * @is_tpg_enabled: TPG state. * @hpd_work: HPD work structure. + * @codec_ready: If audio codec is ready. + * @client_notify_pending: If there is client notification pending. * @root: Debug fs root entry. */ struct sde_hdmi { @@ -109,6 +111,8 @@ struct sde_hdmi { bool is_tpg_enabled; struct work_struct hpd_work; + bool codec_ready; + bool client_notify_pending; /* DEBUG FS */ struct dentry *root; @@ -379,13 +383,12 @@ int sde_hdmi_config_avmute(struct hdmi *hdmi, bool set); /** * sde_hdmi_notify_clients() - notify hdmi clients of the connection status. - * @connector: Handle to the drm_connector. + * @display: Handle to sde_hdmi. * @connected: connection status. * * Return: void. */ -void sde_hdmi_notify_clients(struct drm_connector *connector, - bool connected); +void sde_hdmi_notify_clients(struct sde_hdmi *display, bool connected); /** * sde_hdmi_ack_state() - acknowledge the connection status. diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c index 6c82c3d4826d..34268aaedfc0 100644 --- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c +++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c @@ -372,6 +372,8 @@ static void _sde_hdmi_bridge_pre_enable(struct drm_bridge *bridge) struct sde_hdmi_bridge *sde_hdmi_bridge = to_hdmi_bridge(bridge); struct hdmi *hdmi = sde_hdmi_bridge->hdmi; struct hdmi_phy *phy = hdmi->phy; + struct sde_connector *c_conn = to_sde_connector(hdmi->connector); + struct sde_hdmi *display = (struct sde_hdmi *)c_conn->display; DRM_DEBUG("power up"); @@ -388,41 +390,20 @@ static void _sde_hdmi_bridge_pre_enable(struct drm_bridge *bridge) if (hdmi->hdcp_ctrl && hdmi->is_hdcp_supported) hdmi_hdcp_ctrl_on(hdmi->hdcp_ctrl); - sde_hdmi_ack_state(hdmi->connector, EXT_DISPLAY_CABLE_CONNECT); -} - -static void sde_hdmi_force_update_audio(struct drm_connector *connector, - enum drm_connector_status status) -{ - struct sde_connector *c_conn = to_sde_connector(connector); - struct sde_hdmi *display = (struct sde_hdmi *)c_conn->display; - - if (display && display->non_pluggable) { - display->ext_audio_data.intf_ops.hpd(display->ext_pdev, - display->ext_audio_data.type, - status, - MSM_EXT_DISP_HPD_AUDIO); - } + mutex_lock(&display->display_lock); + if (display->codec_ready) + sde_hdmi_notify_clients(display, display->connected); + else + display->client_notify_pending = true; + mutex_unlock(&display->display_lock); } static void _sde_hdmi_bridge_enable(struct drm_bridge *bridge) { - struct sde_hdmi_bridge *sde_hdmi_bridge = to_hdmi_bridge(bridge); - struct hdmi *hdmi = sde_hdmi_bridge->hdmi; - - /* force update audio ops when there's no HPD event */ - sde_hdmi_force_update_audio(hdmi->connector, - EXT_DISPLAY_CABLE_CONNECT); } static void _sde_hdmi_bridge_disable(struct drm_bridge *bridge) { - struct sde_hdmi_bridge *sde_hdmi_bridge = to_hdmi_bridge(bridge); - struct hdmi *hdmi = sde_hdmi_bridge->hdmi; - - /* force update audio ops when there's no HPD event */ - sde_hdmi_force_update_audio(hdmi->connector, - EXT_DISPLAY_CABLE_DISCONNECT); } static void _sde_hdmi_bridge_post_disable(struct drm_bridge *bridge) @@ -430,6 +411,10 @@ static void _sde_hdmi_bridge_post_disable(struct drm_bridge *bridge) struct sde_hdmi_bridge *sde_hdmi_bridge = to_hdmi_bridge(bridge); struct hdmi *hdmi = sde_hdmi_bridge->hdmi; struct hdmi_phy *phy = hdmi->phy; + struct sde_connector *c_conn = to_sde_connector(hdmi->connector); + struct sde_hdmi *display = (struct sde_hdmi *)c_conn->display; + + sde_hdmi_notify_clients(display, display->connected); if (hdmi->hdcp_ctrl && hdmi->is_hdcp_supported) hdmi_hdcp_ctrl_off(hdmi->hdcp_ctrl); @@ -446,8 +431,6 @@ static void _sde_hdmi_bridge_post_disable(struct drm_bridge *bridge) _sde_hdmi_bridge_power_off(bridge); hdmi->power_on = false; } - - sde_hdmi_ack_state(hdmi->connector, EXT_DISPLAY_CABLE_DISCONNECT); } static void _sde_hdmi_bridge_set_avi_infoframe(struct hdmi *hdmi, diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 7d378f7ebaa4..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; @@ -1208,23 +1200,34 @@ static int msm_ioctl_gem_info(struct drm_device *dev, void *data, if (args->flags & ~MSM_INFO_FLAGS) return -EINVAL; - if (!ctx || !ctx->aspace) - return -EINVAL; - obj = drm_gem_object_lookup(dev, file, args->handle); if (!obj) return -ENOENT; if (args->flags & MSM_INFO_IOVA) { + struct msm_gem_address_space *aspace = NULL; + struct msm_drm_private *priv = dev->dev_private; + struct msm_gem_object *msm_obj = to_msm_bo(obj); uint64_t iova; - ret = msm_gem_get_iova(obj, ctx->aspace, &iova); + if (msm_obj->flags & MSM_BO_SECURE && priv->gpu) + aspace = priv->gpu->secure_aspace; + else if (ctx) + aspace = ctx->aspace; + + if (!aspace) { + ret = -EINVAL; + goto out; + } + + ret = msm_gem_get_iova(obj, aspace, &iova); if (!ret) args->offset = iova; } else { args->offset = msm_gem_mmap_offset(obj); } +out: drm_gem_object_unreference_unlocked(obj); return ret; @@ -1937,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_drv.h b/drivers/gpu/drm/msm/msm_drv.h index bd75a1ba1f8b..94f429cb83a7 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -469,7 +469,7 @@ int msm_gem_new_handle(struct drm_device *dev, struct drm_file *file, struct drm_gem_object *msm_gem_new(struct drm_device *dev, uint32_t size, uint32_t flags); struct drm_gem_object *msm_gem_import(struct drm_device *dev, - uint32_t size, struct sg_table *sgt); + uint32_t size, struct sg_table *sgt, u32 flags); void msm_gem_sync(struct drm_gem_object *obj, u32 op); int msm_framebuffer_prepare(struct drm_framebuffer *fb, diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c index d35d03c2935d..4bee797da746 100644 --- a/drivers/gpu/drm/msm/msm_gem.c +++ b/drivers/gpu/drm/msm/msm_gem.c @@ -18,12 +18,31 @@ #include <linux/spinlock.h> #include <linux/shmem_fs.h> #include <linux/dma-buf.h> +#include <soc/qcom/secure_buffer.h> #include "msm_drv.h" #include "msm_gem.h" #include "msm_gpu.h" #include "msm_mmu.h" +static int protect_pages(struct msm_gem_object *msm_obj) +{ + int perm = PERM_READ | PERM_WRITE; + int src = VMID_HLOS; + int dst = VMID_CP_PIXEL; + + return hyp_assign_table(msm_obj->sgt, &src, 1, &dst, &perm, 1); +} + +static int unprotect_pages(struct msm_gem_object *msm_obj) +{ + int perm = PERM_READ | PERM_WRITE | PERM_EXEC; + int src = VMID_CP_PIXEL; + int dst = VMID_HLOS; + + return hyp_assign_table(msm_obj->sgt, &src, 1, &dst, &perm, 1); +} + static void *get_dmabuf_ptr(struct drm_gem_object *obj) { return (obj && obj->import_attach) ? obj->import_attach->dmabuf : NULL; @@ -109,6 +128,20 @@ static struct page **get_pages(struct drm_gem_object *obj) if (msm_obj->flags & (MSM_BO_WC|MSM_BO_UNCACHED)) dma_sync_sg_for_device(dev->dev, msm_obj->sgt->sgl, msm_obj->sgt->nents, DMA_BIDIRECTIONAL); + + /* Secure the pages if we need to */ + if (use_pages(obj) && msm_obj->flags & MSM_BO_SECURE) { + int ret = protect_pages(msm_obj); + + if (ret) + return ERR_PTR(ret); + + /* + * Set a flag to indicate the pages are locked by us and + * need to be unlocked when the pages get freed + */ + msm_obj->flags |= MSM_BO_LOCKED; + } } return msm_obj->pages; @@ -119,12 +152,17 @@ static void put_pages(struct drm_gem_object *obj) struct msm_gem_object *msm_obj = to_msm_bo(obj); if (msm_obj->pages) { + if (msm_obj->flags & MSM_BO_LOCKED) { + unprotect_pages(msm_obj); + msm_obj->flags &= ~MSM_BO_LOCKED; + } + sg_free_table(msm_obj->sgt); kfree(msm_obj->sgt); - if (use_pages(obj)) + if (use_pages(obj)) { drm_gem_put_pages(obj, msm_obj->pages, true, false); - else { + } else { drm_mm_remove_node(msm_obj->vram_node); drm_free_large(msm_obj->pages); } @@ -153,6 +191,12 @@ int msm_gem_mmap_obj(struct drm_gem_object *obj, { struct msm_gem_object *msm_obj = to_msm_bo(obj); + /* We can't mmap secure objects */ + if (msm_obj->flags & MSM_BO_SECURE) { + drm_gem_vm_close(vma); + return -EACCES; + } + vma->vm_flags &= ~VM_PFNMAP; vma->vm_flags |= VM_MIXEDMAP; @@ -734,6 +778,13 @@ struct drm_gem_object *msm_gem_new(struct drm_device *dev, size = PAGE_ALIGN(size); + /* + * Disallow zero sized objects as they make the underlying + * infrastructure grumpy + */ + if (!size) + return ERR_PTR(-EINVAL); + ret = msm_gem_new_impl(dev, size, flags, &obj); if (ret) goto fail; @@ -756,7 +807,7 @@ fail: } struct drm_gem_object *msm_gem_import(struct drm_device *dev, - uint32_t size, struct sg_table *sgt) + uint32_t size, struct sg_table *sgt, u32 flags) { struct msm_gem_object *msm_obj; struct drm_gem_object *obj; @@ -789,6 +840,9 @@ struct drm_gem_object *msm_gem_import(struct drm_device *dev, goto fail; } + /* OR the passed in flags */ + msm_obj->flags |= flags; + ret = drm_prime_sg_to_page_addr_arrays(sgt, msm_obj->pages, NULL, npages); if (ret) goto fail; diff --git a/drivers/gpu/drm/msm/msm_gem.h b/drivers/gpu/drm/msm/msm_gem.h index 0b19d11bc666..d5204221d902 100644 --- a/drivers/gpu/drm/msm/msm_gem.h +++ b/drivers/gpu/drm/msm/msm_gem.h @@ -24,6 +24,7 @@ /* Additional internal-use only BO flags: */ #define MSM_BO_STOLEN 0x10000000 /* try to use stolen/splash memory */ +#define MSM_BO_LOCKED 0x20000000 /* Pages have been securely locked */ struct msm_gem_address_space { const char *name; @@ -118,6 +119,7 @@ struct msm_gem_submit { bool valid; uint64_t profile_buf_iova; void *profile_buf_vaddr; + bool secure; unsigned int nr_cmds; unsigned int nr_bos; struct { diff --git a/drivers/gpu/drm/msm/msm_gem_prime.c b/drivers/gpu/drm/msm/msm_gem_prime.c index 121975b07cd4..678018804f3a 100644 --- a/drivers/gpu/drm/msm/msm_gem_prime.c +++ b/drivers/gpu/drm/msm/msm_gem_prime.c @@ -19,6 +19,7 @@ #include "msm_gem.h" #include <linux/dma-buf.h> +#include <linux/ion.h> struct sg_table *msm_gem_prime_get_sg_table(struct drm_gem_object *obj) { @@ -55,7 +56,16 @@ int msm_gem_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma) struct drm_gem_object *msm_gem_prime_import_sg_table(struct drm_device *dev, struct dma_buf_attachment *attach, struct sg_table *sg) { - return msm_gem_import(dev, attach->dmabuf->size, sg); + u32 flags = 0; + + /* + * Check to see if this is a secure buffer by way of Ion and set the + * appropriate flag if so. + */ + if (ion_dma_buf_is_secure(attach->dmabuf)) + flags |= MSM_BO_SECURE; + + return msm_gem_import(dev, attach->dmabuf->size, sg, flags); } int msm_gem_prime_pin(struct drm_gem_object *obj) diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c index 8e0f15c416fd..ea7b4441fe99 100644 --- a/drivers/gpu/drm/msm/msm_gem_submit.c +++ b/drivers/gpu/drm/msm/msm_gem_submit.c @@ -50,6 +50,7 @@ static struct msm_gem_submit *submit_create(struct drm_device *dev, submit->profile_buf_vaddr = NULL; submit->profile_buf_iova = 0; + submit->secure = false; INIT_LIST_HEAD(&submit->bo_list); ww_acquire_init(&submit->ticket, &reservation_ww_class); @@ -66,7 +67,8 @@ copy_from_user_inatomic(void *to, const void __user *from, unsigned long n) return -EFAULT; } -static int submit_lookup_objects(struct msm_gem_submit *submit, +static int submit_lookup_objects(struct msm_gpu *gpu, + struct msm_gem_submit *submit, struct drm_msm_gem_submit *args, struct drm_file *file) { unsigned i; @@ -119,6 +121,20 @@ static int submit_lookup_objects(struct msm_gem_submit *submit, msm_obj = to_msm_bo(obj); + /* + * If the buffer is marked as secure make sure that we can + * handle secure buffers and then mark the submission as secure + */ + if (msm_obj->flags & MSM_BO_SECURE) { + if (!gpu->secure_aspace) { + DRM_ERROR("Cannot handle secure buffers\n"); + ret = -EINVAL; + goto out_unlock; + } + + submit->secure = true; + } + if (!list_empty(&msm_obj->submit_entry)) { DRM_ERROR("handle %u at index %u already on submit list\n", submit_bo.handle, i); @@ -143,12 +159,17 @@ out: return ret; } -static void submit_unlock_unpin_bo(struct msm_gem_submit *submit, int i) +static void submit_unlock_unpin_bo(struct msm_gpu *gpu, + struct msm_gem_submit *submit, int i) { struct msm_gem_object *msm_obj = submit->bos[i].obj; + struct msm_gem_address_space *aspace; + + aspace = (msm_obj->flags & MSM_BO_SECURE) ? + gpu->secure_aspace : submit->aspace; if (submit->bos[i].flags & BO_PINNED) - msm_gem_put_iova(&msm_obj->base, submit->aspace); + msm_gem_put_iova(&msm_obj->base, aspace); if (submit->bos[i].flags & BO_LOCKED) ww_mutex_unlock(&msm_obj->resv->lock); @@ -160,7 +181,8 @@ static void submit_unlock_unpin_bo(struct msm_gem_submit *submit, int i) } /* This is where we make sure all the bo's are reserved and pin'd: */ -static int submit_validate_objects(struct msm_gem_submit *submit) +static int submit_validate_objects(struct msm_gpu *gpu, + struct msm_gem_submit *submit) { int contended, slow_locked = -1, i, ret = 0; @@ -169,8 +191,12 @@ retry: for (i = 0; i < submit->nr_bos; i++) { struct msm_gem_object *msm_obj = submit->bos[i].obj; + struct msm_gem_address_space *aspace; uint64_t iova; + aspace = (msm_obj->flags & MSM_BO_SECURE) ? + gpu->secure_aspace : submit->aspace; + if (slow_locked == i) slow_locked = -1; @@ -186,8 +212,7 @@ retry: /* if locking succeeded, pin bo: */ - ret = msm_gem_get_iova_locked(&msm_obj->base, - submit->aspace, &iova); + ret = msm_gem_get_iova_locked(&msm_obj->base, aspace, &iova); /* this would break the logic in the fail path.. there is no * reason for this to happen, but just to be on the safe side @@ -215,10 +240,10 @@ retry: fail: for (; i >= 0; i--) - submit_unlock_unpin_bo(submit, i); + submit_unlock_unpin_bo(gpu, submit, i); if (slow_locked > 0) - submit_unlock_unpin_bo(submit, slow_locked); + submit_unlock_unpin_bo(gpu, submit, slow_locked); if (ret == -EDEADLK) { struct msm_gem_object *msm_obj = submit->bos[contended].obj; @@ -267,6 +292,11 @@ static int submit_reloc(struct msm_gem_submit *submit, struct msm_gem_object *ob return -EINVAL; } + if (obj->flags & MSM_BO_SECURE) { + DRM_ERROR("cannot do relocs on a secure buffer\n"); + return -EINVAL; + } + /* For now, just map the entire thing. Eventually we probably * to do it page-by-page, w/ kmap() if not vmap()d.. */ @@ -327,13 +357,14 @@ static int submit_reloc(struct msm_gem_submit *submit, struct msm_gem_object *ob return 0; } -static void submit_cleanup(struct msm_gem_submit *submit, bool fail) +static void submit_cleanup(struct msm_gpu *gpu, struct msm_gem_submit *submit, + bool fail) { unsigned i; for (i = 0; i < submit->nr_bos; i++) { struct msm_gem_object *msm_obj = submit->bos[i].obj; - submit_unlock_unpin_bo(submit, i); + submit_unlock_unpin_bo(gpu, submit, i); list_del_init(&msm_obj->submit_entry); drm_gem_object_unreference(&msm_obj->base); } @@ -373,11 +404,11 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data, goto out; } - ret = submit_lookup_objects(submit, args, file); + ret = submit_lookup_objects(gpu, submit, args, file); if (ret) goto out; - ret = submit_validate_objects(submit); + ret = submit_validate_objects(gpu, submit); if (ret) goto out; @@ -460,7 +491,7 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data, out: if (submit) - submit_cleanup(submit, !!ret); + submit_cleanup(gpu, submit, !!ret); mutex_unlock(&dev->struct_mutex); return ret; } diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c index 2f01db8b08c3..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)); @@ -572,12 +572,16 @@ int msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit) WARN_ON(is_active(msm_obj) && (msm_obj->gpu != gpu)); if (!is_active(msm_obj)) { + struct msm_gem_address_space *aspace; uint64_t iova; + aspace = (msm_obj->flags & MSM_BO_SECURE) ? + gpu->secure_aspace : submit->aspace; + /* ring takes a reference to the bo and iova: */ drm_gem_object_reference(&msm_obj->base); msm_gem_get_iova_locked(&msm_obj->base, - submit->aspace, &iova); + aspace, &iova); } if (submit->bos[i].flags & MSM_SUBMIT_BO_READ) @@ -586,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 { @@ -757,11 +761,49 @@ static int get_clocks(struct platform_device *pdev, struct msm_gpu *gpu) return 0; } +static struct msm_gem_address_space * +msm_gpu_create_address_space(struct msm_gpu *gpu, struct device *dev, + int type, u64 start, u64 end, const char *name) +{ + struct msm_gem_address_space *aspace; + struct iommu_domain *iommu; + + /* + * If start == end then assume we don't want an address space; this is + * mainly for targets to opt out of secure + */ + if (start == end) + return NULL; + + iommu = iommu_domain_alloc(&platform_bus_type); + if (!iommu) { + dev_info(gpu->dev->dev, + "%s: no IOMMU, fallback to VRAM carveout!\n", + gpu->name); + return NULL; + } + + iommu->geometry.aperture_start = start; + iommu->geometry.aperture_end = end; + + dev_info(gpu->dev->dev, "%s: using IOMMU '%s'\n", gpu->name, name); + + aspace = msm_gem_address_space_create(dev, iommu, type, name); + if (IS_ERR(aspace)) { + dev_err(gpu->dev->dev, "%s: failed to init IOMMU '%s': %ld\n", + gpu->name, name, PTR_ERR(aspace)); + + iommu_domain_free(iommu); + aspace = NULL; + } + + return aspace; +} + int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev, struct msm_gpu *gpu, const struct msm_gpu_funcs *funcs, const char *name, struct msm_gpu_config *config) { - struct iommu_domain *iommu; int i, ret, nr_rings; if (WARN_ON(gpu->num_perfcntrs > ARRAY_SIZE(gpu->last_cntrs))) @@ -831,30 +873,13 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev, if (IS_ERR(gpu->gpu_cx)) gpu->gpu_cx = NULL; - /* Setup IOMMU.. eventually we will (I think) do this once per context - * and have separate page tables per context. For now, to keep things - * simple and to get something working, just use a single address space: - */ - iommu = iommu_domain_alloc(&platform_bus_type); - if (iommu) { - /* TODO 32b vs 64b address space.. */ - iommu->geometry.aperture_start = config->va_start; - iommu->geometry.aperture_end = config->va_end; - - dev_info(drm->dev, "%s: using IOMMU\n", name); - gpu->aspace = msm_gem_address_space_create(&pdev->dev, - iommu, MSM_IOMMU_DOMAIN_USER, "gpu"); - if (IS_ERR(gpu->aspace)) { - ret = PTR_ERR(gpu->aspace); - dev_err(drm->dev, "failed to init iommu: %d\n", ret); - gpu->aspace = NULL; - iommu_domain_free(iommu); - goto fail; - } + gpu->aspace = msm_gpu_create_address_space(gpu, &pdev->dev, + MSM_IOMMU_DOMAIN_USER, config->va_start, config->va_end, + "gpu"); - } else { - dev_info(drm->dev, "%s: no IOMMU, fallback to VRAM carveout!\n", name); - } + gpu->secure_aspace = msm_gpu_create_address_space(gpu, &pdev->dev, + MSM_IOMMU_DOMAIN_SECURE, config->secure_va_start, + config->secure_va_end, "gpu_secure"); nr_rings = config->nr_rings; diff --git a/drivers/gpu/drm/msm/msm_gpu.h b/drivers/gpu/drm/msm/msm_gpu.h index 29e2e59b580b..a47eae68dd9b 100644 --- a/drivers/gpu/drm/msm/msm_gpu.h +++ b/drivers/gpu/drm/msm/msm_gpu.h @@ -38,6 +38,8 @@ struct msm_gpu_config { int nr_rings; uint64_t va_start; uint64_t va_end; + uint64_t secure_va_start; + uint64_t secure_va_end; }; /* So far, with hardware that I've seen to date, we can have: @@ -59,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, @@ -114,6 +116,7 @@ struct msm_gpu { int irq; struct msm_gem_address_space *aspace; + struct msm_gem_address_space *secure_aspace; /* Power Control: */ struct regulator *gpu_reg, *gpu_cx; diff --git a/drivers/gpu/drm/msm/msm_snapshot.h b/drivers/gpu/drm/msm/msm_snapshot.h index 247e1358c885..fd560b2129f1 100644 --- a/drivers/gpu/drm/msm/msm_snapshot.h +++ b/drivers/gpu/drm/msm/msm_snapshot.h @@ -71,8 +71,8 @@ static inline bool _snapshot_header(struct msm_snapshot *snapshot, */ #define SNAPSHOT_HEADER(_snapshot, _header, _id, _dwords) \ _snapshot_header((_snapshot), \ - (struct msm_snapshot_section_header *) &(header), \ - sizeof(header), (_dwords) << 2, (_id)) + (struct msm_snapshot_section_header *) &(_header), \ + sizeof(_header), (_dwords) << 2, (_id)) struct msm_gpu; diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c index 41322045ced3..adfe9e54e6f4 100644 --- a/drivers/gpu/drm/msm/sde/sde_crtc.c +++ b/drivers/gpu/drm/msm/sde/sde_crtc.c @@ -1134,12 +1134,12 @@ static int sde_crtc_atomic_check(struct drm_crtc *crtc, /* get plane state for all drm planes associated with crtc state */ drm_atomic_crtc_state_for_each_plane(plane, state) { - pstate = drm_atomic_get_plane_state(state->state, plane); + pstate = drm_atomic_get_existing_plane_state( + state->state, plane); if (IS_ERR_OR_NULL(pstate)) { - rc = PTR_ERR(pstate); - SDE_ERROR("%s: failed to get plane%d state, %d\n", + SDE_DEBUG("%s: failed to get plane%d state, %d\n", sde_crtc->name, plane->base.id, rc); - goto end; + continue; } if (cnt >= ARRAY_SIZE(pstates)) continue; diff --git a/drivers/gpu/drm/msm/sde/sde_rm.c b/drivers/gpu/drm/msm/sde/sde_rm.c index 1d27b27d265c..fca0768e2734 100644 --- a/drivers/gpu/drm/msm/sde/sde_rm.c +++ b/drivers/gpu/drm/msm/sde/sde_rm.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1074,12 +1074,6 @@ void _sde_rm_release_rsvp( } kfree(rsvp); - - (void) msm_property_set_property( - sde_connector_get_propinfo(conn), - sde_connector_get_property_values(conn->state), - CONNECTOR_PROP_TOPOLOGY_NAME, - SDE_RM_TOPOLOGY_UNKNOWN); } void sde_rm_release(struct sde_rm *rm, struct drm_encoder *enc) @@ -1115,6 +1109,12 @@ void sde_rm_release(struct sde_rm *rm, struct drm_encoder *enc) SDE_DEBUG("release rsvp[s%de%d]\n", rsvp->seq, rsvp->enc_id); _sde_rm_release_rsvp(rm, rsvp, conn); + + (void) msm_property_set_property( + sde_connector_get_propinfo(conn), + sde_connector_get_property_values(conn->state), + CONNECTOR_PROP_TOPOLOGY_NAME, + SDE_RM_TOPOLOGY_UNKNOWN); } } @@ -1132,8 +1132,12 @@ static int _sde_rm_commit_rsvp( sde_connector_get_property_values(conn_state), CONNECTOR_PROP_TOPOLOGY_NAME, rsvp->topology); - if (ret) + if (ret) { + SDE_ERROR("failed to set topology name property, ret %d\n", + ret); _sde_rm_release_rsvp(rm, rsvp, conn_state->connector); + return ret; + } /* Swap next rsvp to be the active */ for (type = 0; type < SDE_HW_BLK_MAX; type++) { @@ -1226,6 +1230,12 @@ int sde_rm_reserve( _sde_rm_release_rsvp(rm, rsvp_cur, conn_state->connector); rsvp_cur = NULL; _sde_rm_print_rsvps(rm, SDE_RM_STAGE_AFTER_CLEAR); + (void) msm_property_set_property( + sde_connector_get_propinfo( + conn_state->connector), + sde_connector_get_property_values(conn_state), + CONNECTOR_PROP_TOPOLOGY_NAME, + SDE_RM_TOPOLOGY_UNKNOWN); } /* Check the proposed reservation, store it in hw's "next" field */ diff --git a/drivers/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/infiniband/hw/qib/qib_qp.c b/drivers/infiniband/hw/qib/qib_qp.c index 3eff35c2d453..2684605fe67f 100644 --- a/drivers/infiniband/hw/qib/qib_qp.c +++ b/drivers/infiniband/hw/qib/qib_qp.c @@ -41,13 +41,13 @@ #include "qib.h" -#define BITS_PER_PAGE (PAGE_SIZE*BITS_PER_BYTE) -#define BITS_PER_PAGE_MASK (BITS_PER_PAGE-1) +#define RVT_BITS_PER_PAGE (PAGE_SIZE*BITS_PER_BYTE) +#define RVT_BITS_PER_PAGE_MASK (RVT_BITS_PER_PAGE-1) static inline unsigned mk_qpn(struct qib_qpn_table *qpt, struct qpn_map *map, unsigned off) { - return (map - qpt->map) * BITS_PER_PAGE + off; + return (map - qpt->map) * RVT_BITS_PER_PAGE + off; } static inline unsigned find_next_offset(struct qib_qpn_table *qpt, @@ -59,7 +59,7 @@ static inline unsigned find_next_offset(struct qib_qpn_table *qpt, if (((off & qpt->mask) >> 1) >= n) off = (off | qpt->mask) + 2; } else - off = find_next_zero_bit(map->page, BITS_PER_PAGE, off); + off = find_next_zero_bit(map->page, RVT_BITS_PER_PAGE, off); return off; } @@ -147,8 +147,8 @@ static int alloc_qpn(struct qib_devdata *dd, struct qib_qpn_table *qpt, qpn = 2; if (qpt->mask && ((qpn & qpt->mask) >> 1) >= dd->n_krcv_queues) qpn = (qpn | qpt->mask) + 2; - offset = qpn & BITS_PER_PAGE_MASK; - map = &qpt->map[qpn / BITS_PER_PAGE]; + offset = qpn & RVT_BITS_PER_PAGE_MASK; + map = &qpt->map[qpn / RVT_BITS_PER_PAGE]; max_scan = qpt->nmaps - !offset; for (i = 0;;) { if (unlikely(!map->page)) { @@ -173,7 +173,7 @@ static int alloc_qpn(struct qib_devdata *dd, struct qib_qpn_table *qpt, * We just need to be sure we don't loop * forever. */ - } while (offset < BITS_PER_PAGE && qpn < QPN_MAX); + } while (offset < RVT_BITS_PER_PAGE && qpn < QPN_MAX); /* * In order to keep the number of pages allocated to a * minimum, we scan the all existing pages before increasing @@ -204,9 +204,9 @@ static void free_qpn(struct qib_qpn_table *qpt, u32 qpn) { struct qpn_map *map; - map = qpt->map + qpn / BITS_PER_PAGE; + map = qpt->map + qpn / RVT_BITS_PER_PAGE; if (map->page) - clear_bit(qpn & BITS_PER_PAGE_MASK, map->page); + clear_bit(qpn & RVT_BITS_PER_PAGE_MASK, map->page); } static inline unsigned qpn_hash(struct qib_ibdev *dev, u32 qpn) diff --git a/drivers/input/misc/hbtp_input.c b/drivers/input/misc/hbtp_input.c index 599605a3cf76..56f2732334db 100644 --- a/drivers/input/misc/hbtp_input.c +++ b/drivers/input/misc/hbtp_input.c @@ -1452,8 +1452,10 @@ static int __init hbtp_init(void) hbtp->sensor_data = kzalloc(sizeof(struct hbtp_sensor_data), GFP_KERNEL); - if (!hbtp->sensor_data) + if (!hbtp->sensor_data) { + error = -ENOMEM; goto err_sensordata; + } mutex_init(&hbtp->mutex); mutex_init(&hbtp->sensormutex); @@ -1477,6 +1479,7 @@ static int __init hbtp_init(void) sensor_kobject = kobject_create_and_add("hbtpsensor", kernel_kobj); if (!sensor_kobject) { pr_err("%s: Could not create hbtpsensor kobject\n", __func__); + error = -ENOMEM; goto err_kobject_create; } diff --git a/drivers/input/misc/vl53L0/stmvl53l0_module-cci.c b/drivers/input/misc/vl53L0/stmvl53l0_module-cci.c index fecafe8db949..8520a74c9961 100644 --- a/drivers/input/misc/vl53L0/stmvl53l0_module-cci.c +++ b/drivers/input/misc/vl53L0/stmvl53l0_module-cci.c @@ -111,11 +111,11 @@ static int stmvl53l0_get_dt_data(struct device *dev, struct cci_data *data) vl53l0_errmsg("failed %d\n", __LINE__); return rc; } + vl53l0_dbgmsg("vreg-name: %s min_volt: %d max_volt: %d", + vreg_cfg->cam_vreg->reg_name, + vreg_cfg->cam_vreg->min_voltage, + vreg_cfg->cam_vreg->max_voltage); } - vl53l0_dbgmsg("vreg-name: %s min_volt: %d max_volt: %d", - vreg_cfg->cam_vreg->reg_name, - vreg_cfg->cam_vreg->min_voltage, - vreg_cfg->cam_vreg->max_voltage); rc = msm_sensor_driver_get_gpio_data(&(data->gconf), of_node); if ((rc < 0) || (data->gconf == NULL)) { @@ -289,6 +289,11 @@ static int32_t stmvl53l0_platform_probe(struct platform_device *pdev) if (vl53l0_data) { vl53l0_data->client_object = kzalloc(sizeof(struct cci_data), GFP_KERNEL); + if (!vl53l0_data->client_object) { + rc = -ENOMEM; + kfree(vl53l0_data); + return rc; + } cci_object = (struct cci_data *)vl53l0_data->client_object; } cci_object->client = @@ -380,6 +385,11 @@ int stmvl53l0_power_up_cci(void *cci_object, unsigned int *preset_flag) vl53l0_dbgmsg("Enter"); /* need to init cci first */ + if (!data) { + pr_err("%s:%d failed\n", __func__, __LINE__); + return -EINVAL; + } + ret = stmvl53l0_cci_init(data); if (ret) { vl53l0_errmsg("stmvl53l0_cci_init failed %d\n", __LINE__); @@ -429,7 +439,7 @@ int stmvl53l0_power_up_cci(void *cci_object, unsigned int *preset_flag) } /* actual power up */ - if (data && data->device_type == MSM_CAMERA_PLATFORM_DEVICE) { + if (data->device_type == MSM_CAMERA_PLATFORM_DEVICE) { ret = stmvl53l0_vreg_control(data, 1); if (ret < 0) { vl53l0_errmsg("stmvl53l0_vreg_control failed %d\n", diff --git a/drivers/input/misc/vl53L0/stmvl53l0_module.c b/drivers/input/misc/vl53L0/stmvl53l0_module.c index c46be43a03e5..27672d97448a 100644 --- a/drivers/input/misc/vl53L0/stmvl53l0_module.c +++ b/drivers/input/misc/vl53L0/stmvl53l0_module.c @@ -2115,10 +2115,10 @@ static int stmvl53l0_init_client(struct stmvl53l0_data *data) VL53L0_Error Status = VL53L0_ERROR_NONE; VL53L0_DeviceInfo_t DeviceInfo; VL53L0_DEV vl53l0_dev = data; - uint32_t refSpadCount; - uint8_t isApertureSpads; - uint8_t VhvSettings; - uint8_t PhaseCal; + uint32_t refSpadCount = 0; + uint8_t isApertureSpads = 0; + uint8_t VhvSettings = 0; + uint8_t PhaseCal = 0; vl53l0_dbgmsg("Enter\n"); @@ -2380,17 +2380,17 @@ static int stmvl53l0_config_use_case(struct stmvl53l0_data *data) vl53l0_dev, VL53L0_CHECKENABLE_SIGMA_FINAL_RANGE, 1); - } - if (Status == VL53L0_ERROR_NONE) { - Status = papi_func_tbl->SetLimitCheckEnable( - vl53l0_dev, - VL53L0_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE, - 1); - } else { - vl53l0_errmsg( - "SetLimitCheckEnable(SIGMA_FINAL_RANGE) failed with errcode = %d\n", - Status); + if (Status == VL53L0_ERROR_NONE) { + Status = papi_func_tbl->SetLimitCheckEnable( + vl53l0_dev, + VL53L0_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE, + 1); + } else { + vl53l0_errmsg( + "SetLimitCheckEnable(SIGMA_FINAL_RANGE) failed with errcode = %d\n", + Status); + } } diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h index 25eab453f2b2..e7b96f1ac2c5 100644 --- a/drivers/input/serio/i8042-x86ia64io.h +++ b/drivers/input/serio/i8042-x86ia64io.h @@ -685,6 +685,13 @@ static const struct dmi_system_id __initconst i8042_dmi_reset_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "20046"), }, }, + { + /* Clevo P650RS, 650RP6, Sager NP8152-S, and others */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Notebook"), + DMI_MATCH(DMI_PRODUCT_NAME, "P65xRP"), + }, + }, { } }; diff --git a/drivers/input/touchscreen/st/fts.c b/drivers/input/touchscreen/st/fts.c index bbe872001407..78bdd24af28b 100644 --- a/drivers/input/touchscreen/st/fts.c +++ b/drivers/input/touchscreen/st/fts.c @@ -1252,7 +1252,7 @@ static void fts_event_handler(struct work_struct *work) static int cx_crc_check(void) { unsigned char regAdd1[3] = {FTS_CMD_HW_REG_R, ADDR_CRC_BYTE0, ADDR_CRC_BYTE1}; - unsigned char val; + unsigned char val = 0; unsigned char crc_status; unsigned int error; diff --git a/drivers/input/touchscreen/st/fts_lib/ftsFlash.c b/drivers/input/touchscreen/st/fts_lib/ftsFlash.c index 59c73f4c4edb..f3becac79102 100644 --- a/drivers/input/touchscreen/st/fts_lib/ftsFlash.c +++ b/drivers/input/touchscreen/st/fts_lib/ftsFlash.c @@ -93,7 +93,7 @@ int getFirmwareVersion(u16 *fw_vers, u16 *config_id) int flash_status(void) { u8 cmd[2] = {FLASH_CMD_READSTATUS, 0x00}; - u8 readData; + u8 readData = 0; logError(0, "%s Reading flash_status...\n", tag); if (fts_readCmd(cmd, 2, &readData, FLASH_STATUS_BYTES) < 0) { diff --git a/drivers/input/touchscreen/st/fts_lib/ftsGesture.c b/drivers/input/touchscreen/st/fts_lib/ftsGesture.c index fda4ab281948..ee97a417d4cb 100644 --- a/drivers/input/touchscreen/st/fts_lib/ftsGesture.c +++ b/drivers/input/touchscreen/st/fts_lib/ftsGesture.c @@ -28,7 +28,7 @@ static u8 custom_gesture_index[GESTURE_CUSTOM_NUMBER] = { 0 }; int enableGesture(u8 *mask, int size) { u8 cmd[size+2]; - u8 readData[FIFO_EVENT_SIZE]; + u8 readData[FIFO_EVENT_SIZE] = {0}; int i, res; int event_to_search[4] = {EVENTID_GESTURE, EVENT_TYPE_ENB, 0x00, GESTURE_ENABLE}; @@ -82,7 +82,7 @@ int enableGesture(u8 *mask, int size) int disableGesture(u8 *mask, int size) { u8 cmd[2+GESTURE_MASK_SIZE]; - u8 readData[FIFO_EVENT_SIZE]; + u8 readData[FIFO_EVENT_SIZE] = {0}; u8 temp; int i, res; int event_to_search[4] = { EVENTID_GESTURE, EVENT_TYPE_ENB, 0x00, GESTURE_DISABLE }; @@ -141,7 +141,7 @@ int startAddCustomGesture(u8 gestureID) { u8 cmd[3] = { FTS_CMD_GESTURE_CMD, GESTURE_START_ADD, gestureID }; int res; - u8 readData[FIFO_EVENT_SIZE]; + u8 readData[FIFO_EVENT_SIZE] = {0}; int event_to_search[4] = { EVENTID_GESTURE, EVENT_TYPE_ENB, gestureID, GESTURE_START_ADD }; res = fts_writeFwCmd(cmd, 3); @@ -168,7 +168,7 @@ int finishAddCustomGesture(u8 gestureID) { u8 cmd[3] = { FTS_CMD_GESTURE_CMD, GESTURE_FINISH_ADD, gestureID }; int res; - u8 readData[FIFO_EVENT_SIZE]; + u8 readData[FIFO_EVENT_SIZE] = {0}; int event_to_search[4] = { EVENTID_GESTURE, EVENT_TYPE_ENB, gestureID, GESTURE_FINISH_ADD }; res = fts_writeFwCmd(cmd, 3); @@ -199,7 +199,7 @@ int loadCustomGesture(u8 *template, u8 gestureID) int toWrite, offset = 0; u8 cmd[TEMPLATE_CHUNK + 5]; int event_to_search[4] = { EVENTID_GESTURE, EVENT_TYPE_ENB, gestureID, GESTURE_DATA_ADD }; - u8 readData[FIFO_EVENT_SIZE]; + u8 readData[FIFO_EVENT_SIZE] = {0}; logError(0, "%s Starting adding custom gesture procedure...\n", tag); @@ -359,7 +359,7 @@ int removeCustomGesture(u8 gestureID) int res, index; u8 cmd[3] = { FTS_CMD_GESTURE_CMD, GETURE_REMOVE_CUSTOM, gestureID }; int event_to_search[4] = {EVENTID_GESTURE, EVENT_TYPE_ENB, gestureID, GETURE_REMOVE_CUSTOM }; - u8 readData[FIFO_EVENT_SIZE]; + u8 readData[FIFO_EVENT_SIZE] = {0}; index = gestureID - GESTURE_CUSTOM_OFFSET; diff --git a/drivers/input/touchscreen/st/fts_lib/ftsTest.c b/drivers/input/touchscreen/st/fts_lib/ftsTest.c index 68bd04eff316..3810fd02001a 100644 --- a/drivers/input/touchscreen/st/fts_lib/ftsTest.c +++ b/drivers/input/touchscreen/st/fts_lib/ftsTest.c @@ -301,7 +301,7 @@ int production_test_ito(void) { int res = OK; u8 cmd; - u8 readData[FIFO_EVENT_SIZE]; + u8 readData[FIFO_EVENT_SIZE] = {0}; int eventToSearch[2] = {EVENTID_ERROR_EVENT, EVENT_TYPE_ITO}; /* look for ito event */ logError(0, "%s ITO Production test is starting...\n", tag); @@ -347,7 +347,7 @@ int production_test_initialization(void) { int res; u8 cmd; - u8 readData[FIFO_EVENT_SIZE]; + u8 readData[FIFO_EVENT_SIZE] = {0}; int eventToSearch[2] = {EVENTID_STATUS_UPDATE, EVENT_TYPE_FULL_INITIALIZATION}; logError(0, "%s INITIALIZATION Production test is starting...\n", tag); @@ -397,7 +397,7 @@ int ms_compensation_tuning(void) { int res; u8 cmd; - u8 readData[FIFO_EVENT_SIZE]; + u8 readData[FIFO_EVENT_SIZE] = {0}; int eventToSearch[2] = {EVENTID_STATUS_UPDATE, EVENT_TYPE_MS_TUNING_CMPL}; logError(0, "%s MS INITIALIZATION command sent...\n", tag); @@ -429,7 +429,7 @@ int ss_compensation_tuning(void) { int res; u8 cmd; - u8 readData[FIFO_EVENT_SIZE]; + u8 readData[FIFO_EVENT_SIZE] = {0}; int eventToSearch[2] = {EVENTID_STATUS_UPDATE, EVENT_TYPE_SS_TUNING_CMPL}; logError(0, "%s SS INITIALIZATION command sent...\n", tag); @@ -461,7 +461,7 @@ int lp_timer_calibration(void) { int res; u8 cmd; - u8 readData[FIFO_EVENT_SIZE]; + u8 readData[FIFO_EVENT_SIZE] = {0}; int eventToSearch[2] = {EVENTID_STATUS_UPDATE, EVENT_TYPE_LPTIMER_TUNING_CMPL}; logError(0, "%s LP TIMER CALIBRATION command sent...\n", tag); @@ -493,7 +493,7 @@ int save_cx_tuning(void) { int res; u8 cmd; - u8 readData[FIFO_EVENT_SIZE]; + u8 readData[FIFO_EVENT_SIZE] = {0}; int eventToSearch[2] = {EVENTID_STATUS_UPDATE, EVENT_TYPE_COMP_DATA_SAVED}; logError(0, "%s SAVE CX command sent...\n", tag); diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c index bc5e9a5b1f30..7baeeafa059d 100644 --- a/drivers/md/dm-ioctl.c +++ b/drivers/md/dm-ioctl.c @@ -1843,7 +1843,7 @@ static int ctl_ioctl(uint command, struct dm_ioctl __user *user) if (r) goto out; - param->data_size = sizeof(*param); + param->data_size = offsetof(struct dm_ioctl, data); r = fn(param, input_param_size); if (unlikely(param->flags & DM_BUFFER_FULL_FLAG) && diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 9be39988bf06..d81be5e471d0 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -570,7 +570,7 @@ static int read_balance(struct r1conf *conf, struct r1bio *r1_bio, int *max_sect if (best_dist_disk < 0) { if (is_badblock(rdev, this_sector, sectors, &first_bad, &bad_sectors)) { - if (first_bad < this_sector) + if (first_bad <= this_sector) /* Cannot use this */ continue; best_good_sectors = first_bad - this_sector; diff --git a/drivers/media/dvb-core/dmxdev.c b/drivers/media/dvb-core/dmxdev.c index a9c4237d631a..9b743f5fdcf8 100644 --- a/drivers/media/dvb-core/dmxdev.c +++ b/drivers/media/dvb-core/dmxdev.c @@ -1615,7 +1615,7 @@ static int dvb_dvr_get_event(struct dmxdev *dmxdev, unsigned int f_flags, struct dmx_filter_event *event) { - int res; + int res = 0; if (!((f_flags & O_ACCMODE) == O_RDONLY)) return -EINVAL; @@ -2402,8 +2402,10 @@ static int dvb_dmxdev_set_playback_mode(struct dmxdev_filter *dmxdevfilter, (playback_mode != DMX_PB_MODE_PULL)) return -EINVAL; + if (dmxdev->demux->set_playback_mode == NULL) + return -EINVAL; + if (((dmxdev->source < DMX_SOURCE_DVR0) || - !dmxdev->demux->set_playback_mode || !(caps.caps & DMX_CAP_PULL_MODE)) && (playback_mode == DMX_PB_MODE_PULL)) return -EPERM; @@ -2520,7 +2522,7 @@ static int dvb_dmxdev_release_data(struct dmxdev_filter *dmxdevfilter, static int dvb_dmxdev_get_event(struct dmxdev_filter *dmxdevfilter, struct dmx_filter_event *event) { - int res; + int res = 0; spin_lock_irq(&dmxdevfilter->dev->lock); diff --git a/drivers/media/platform/msm/broadcast/tspp.c b/drivers/media/platform/msm/broadcast/tspp.c index b706d598e6b8..fa566ad01d99 100644 --- a/drivers/media/platform/msm/broadcast/tspp.c +++ b/drivers/media/platform/msm/broadcast/tspp.c @@ -2210,7 +2210,13 @@ int tspp_remove_filter(u32 dev, u32 channel_id, channel = &pdev->channels[channel_id]; src = channel->src; - tspp_filter = &(pdev->filters[src]->filter[filter->priority]); + if ((src == TSPP_SOURCE_TSIF0) || (src == TSPP_SOURCE_TSIF1)) + tspp_filter = &(pdev->filters[src]->filter[filter->priority]); + else { + pr_err("tspp_remove: wrong source type %d", src); + return -EINVAL; + } + /* disable pipe (channel) */ val = readl_relaxed(pdev->base + TSPP_PS_DISABLE); diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h index b283f6277b87..f37e183e35de 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h @@ -469,6 +469,7 @@ struct msm_vfe_axi_stream { */ uint32_t vfe_mask; uint32_t composite_irq[MSM_ISP_COMP_IRQ_MAX]; + int lpm_mode; }; struct msm_vfe_axi_composite_info { @@ -738,6 +739,7 @@ struct msm_vfe_common_dev_data { struct msm_vfe_axi_stream streams[VFE_AXI_SRC_MAX * MAX_VFE]; struct msm_vfe_stats_stream stats_streams[MSM_ISP_STATS_MAX * MAX_VFE]; struct mutex vfe_common_mutex; + uint8_t pd_buf_idx; /* Irq debug Info */ struct msm_vfe_irq_dump vfe_irq_dump; struct msm_vfe_tasklet tasklets[MAX_VFE + 1]; @@ -836,8 +838,6 @@ struct vfe_device { uint32_t bus_err_ign_mask; uint32_t recovery_irq0_mask; uint32_t recovery_irq1_mask; - /* Store the buf_idx for pd stats RDI stream */ - uint8_t pd_buf_idx; /* total bandwidth per vfe */ uint64_t total_bandwidth; }; diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c index a66ca7e93537..b80ef1dc900b 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c @@ -1859,10 +1859,10 @@ void msm_vfe47_cfg_axi_ub_equal_default( axi_data->free_wm[i]) break; - rdi_ub_offset = ((SRC_TO_INTF( + rdi_ub_offset = (SRC_TO_INTF( HANDLE_TO_IDX(axi_data->free_wm[i])) - - VFE_RAW_0 * 2) + plane) * - axi_data->hw_info->min_wm_ub; + VFE_RAW_0) * + axi_data->hw_info->min_wm_ub * 2; wm_ub_size = axi_data->hw_info->min_wm_ub * 2; msm_camera_io_w(rdi_ub_offset << 16 | (wm_ub_size - 1), vfe_dev->vfe_base + diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c index 63e46125c292..f9809615b407 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c @@ -27,6 +27,9 @@ static void __msm_isp_axi_stream_update( struct msm_vfe_axi_stream *stream_info, struct msm_isp_timestamp *ts); +static int msm_isp_update_stream_bandwidth( + struct msm_vfe_axi_stream *stream_info, int enable); + #define DUAL_VFE_AND_VFE1(s, v) ((s->stream_src < RDI_INTF_0) && \ v->is_split && vfe_dev->pdev->id == ISP_VFE1) @@ -841,7 +844,6 @@ static void msm_isp_sync_dual_cam_frame_id( } } - WARN_ON(ms_res->dual_sync_mode == MSM_ISP_DUAL_CAM_ASYNC); /* find highest frame id */ for (i = 0; i < MAX_VFE * VFE_SRC_MAX; i++) { if (ms_res->src_info[i] == NULL) @@ -915,7 +917,7 @@ void msm_isp_increment_frame_id(struct vfe_device *vfe_dev, */ if (ms_res->src_sof_mask & (1 << src_info->dual_hw_ms_info.index)) { - pr_err("Frame out of sync on vfe %d\n", + pr_err_ratelimited("Frame out of sync on vfe %d\n", vfe_dev->pdev->id); /* * set this isp as async mode to force @@ -995,6 +997,7 @@ static void msm_isp_update_pd_stats_idx(struct vfe_device *vfe_dev, uint32_t pingpong_status = 0, pingpong_bit = 0; struct msm_isp_buffer *done_buf = NULL; int vfe_idx = -1; + unsigned long flags; if (frame_src < VFE_RAW_0 || frame_src > VFE_RAW_2) return; @@ -1012,10 +1015,14 @@ static void msm_isp_update_pd_stats_idx(struct vfe_device *vfe_dev, pingpong_bit = ((pingpong_status >> pd_stream_info->wm[vfe_idx][0]) & 0x1); done_buf = pd_stream_info->buf[pingpong_bit]; + spin_lock_irqsave(&vfe_dev->common_data-> + common_dev_data_lock, flags); if (done_buf) - vfe_dev->pd_buf_idx = done_buf->buf_idx; + vfe_dev->common_data->pd_buf_idx = done_buf->buf_idx; else - vfe_dev->pd_buf_idx = 0xF; + vfe_dev->common_data->pd_buf_idx = 0xF; + spin_unlock_irqrestore(&vfe_dev->common_data-> + common_dev_data_lock, flags); } } @@ -2426,46 +2433,42 @@ static void msm_isp_update_intf_stream_cnt( /*Factor in Q2 format*/ #define ISP_DEFAULT_FORMAT_FACTOR 6 #define ISP_BUS_UTILIZATION_FACTOR 6 -static int msm_isp_update_stream_bandwidth(struct vfe_device *vfe_dev) +static int msm_isp_update_stream_bandwidth( + struct msm_vfe_axi_stream *stream_info, int enable) { int i, rc = 0; - struct msm_vfe_axi_stream *stream_info; - uint64_t total_pix_bandwidth = 0, total_rdi_bandwidth = 0; - uint32_t num_pix_streams = 0; + uint64_t total_bandwidth = 0; int vfe_idx; + struct vfe_device *vfe_dev; - for (i = 0; i < VFE_AXI_SRC_MAX; i++) { - stream_info = msm_isp_get_stream_common_data(vfe_dev, i); - if (stream_info->state == ACTIVE || - stream_info->state == START_PENDING) { - vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, - stream_info); - if (stream_info->stream_src < RDI_INTF_0) { - total_pix_bandwidth += + for (i = 0; i < stream_info->num_isp; i++) { + vfe_dev = stream_info->vfe_dev[i]; + vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, + stream_info); + if (enable) { + total_bandwidth = + vfe_dev->total_bandwidth + stream_info->bandwidth[vfe_idx]; - num_pix_streams++; - } else { - total_rdi_bandwidth += + } else { + total_bandwidth = vfe_dev->total_bandwidth - stream_info->bandwidth[vfe_idx]; - } } - } - vfe_dev->total_bandwidth = total_pix_bandwidth + total_rdi_bandwidth; - rc = msm_isp_update_bandwidth(ISP_VFE0 + vfe_dev->pdev->id, - (vfe_dev->total_bandwidth + vfe_dev->hw_info->min_ab), - (vfe_dev->total_bandwidth + vfe_dev->hw_info->min_ib)); - - if (rc < 0) - pr_err("%s: update failed\n", __func__); + vfe_dev->total_bandwidth = total_bandwidth; + rc = msm_isp_update_bandwidth(ISP_VFE0 + vfe_dev->pdev->id, + (total_bandwidth + vfe_dev->hw_info->min_ab), + (total_bandwidth + vfe_dev->hw_info->min_ib)); + if (rc < 0) + pr_err("%s: update failed rc %d stream src %d vfe dev %d\n", + __func__, rc, stream_info->stream_src, + vfe_dev->pdev->id); + } return rc; } int msm_isp_ab_ib_update_lpm_mode(struct vfe_device *vfe_dev, void *arg) { int i, rc = 0; - uint64_t total_bandwidth = 0; - int vfe_idx; uint32_t intf; unsigned long flags; struct msm_vfe_axi_stream *stream_info; @@ -2489,21 +2492,15 @@ int msm_isp_ab_ib_update_lpm_mode(struct vfe_device *vfe_dev, void *arg) intf = SRC_TO_INTF(stream_info->stream_src); vfe_dev->axi_data.src_info[intf].lpm = ab_ib_vote->lpm_mode; - if (stream_info->state == ACTIVE) { - vfe_idx = - msm_isp_get_vfe_idx_for_stream(vfe_dev, - stream_info); - total_bandwidth += - stream_info->bandwidth[ - vfe_idx]; - stream_info->state = PAUSED; + if (stream_info->lpm_mode) { + spin_unlock_irqrestore(&stream_info->lock, + flags); + continue; } + stream_info->lpm_mode = ab_ib_vote->lpm_mode; spin_unlock_irqrestore(&stream_info->lock, flags); + msm_isp_update_stream_bandwidth(stream_info, 0); } - vfe_dev->total_bandwidth -= total_bandwidth; - rc = msm_isp_update_bandwidth(ISP_VFE0 + vfe_dev->pdev->id, - (vfe_dev->total_bandwidth - vfe_dev->hw_info->min_ab), - (vfe_dev->total_bandwidth - vfe_dev->hw_info->min_ib)); } else { for (i = 0; i < ab_ib_vote->num_src; i++) { stream_info = @@ -2515,24 +2512,19 @@ int msm_isp_ab_ib_update_lpm_mode(struct vfe_device *vfe_dev, void *arg) intf = SRC_TO_INTF(stream_info->stream_src); vfe_dev->axi_data.src_info[intf].lpm = ab_ib_vote->lpm_mode; - if (stream_info->state == PAUSED) { - vfe_idx = - msm_isp_get_vfe_idx_for_stream(vfe_dev, - stream_info); - total_bandwidth += - stream_info->bandwidth[ - vfe_idx]; - stream_info->state = ACTIVE; + if (stream_info->lpm_mode == 0) { + spin_unlock_irqrestore(&stream_info->lock, + flags); + continue; } + stream_info->lpm_mode = 0; spin_unlock_irqrestore(&stream_info->lock, flags); + msm_isp_update_stream_bandwidth(stream_info, 1); } - vfe_dev->total_bandwidth += total_bandwidth; - rc = msm_isp_update_bandwidth(ISP_VFE0 + vfe_dev->pdev->id, - (vfe_dev->total_bandwidth + vfe_dev->hw_info->min_ab), - (vfe_dev->total_bandwidth + vfe_dev->hw_info->min_ib)); } return rc; } + static int msm_isp_init_stream_ping_pong_reg( struct msm_vfe_axi_stream *stream_info) { @@ -2941,7 +2933,7 @@ static void __msm_isp_stop_axi_streams(struct vfe_device *vfe_dev, * be INACTIVE */ intf = SRC_TO_INTF(stream_info->stream_src); - if ((!vfe_dev->axi_data.src_info[intf].lpm) || + if (stream_info->lpm_mode == 0 && stream_info->state != PAUSED) { while (stream_info->state != ACTIVE) __msm_isp_axi_stream_update(stream_info, @@ -2959,16 +2951,14 @@ static void __msm_isp_stop_axi_streams(struct vfe_device *vfe_dev, vfe_dev->hw_info->vfe_ops.axi_ops. clear_wm_irq_mask(vfe_dev, stream_info); } - if (stream_info->state == ACTIVE && - !vfe_dev->axi_data.src_info[intf].lpm) { - init_completion(&stream_info->inactive_comp); - stream_info->state = STOP_PENDING; - } else if (vfe_dev->axi_data.src_info[intf].lpm || + init_completion(&stream_info->inactive_comp); + stream_info->state = STOP_PENDING; + if (stream_info->lpm_mode || stream_info->state == PAUSED) { /* don't wait for reg update */ - stream_info->state = STOP_PENDING; - msm_isp_axi_stream_enable_cfg(stream_info); - stream_info->state = INACTIVE; + while (stream_info->state != INACTIVE) + __msm_isp_axi_stream_update(stream_info, + ×tamp); } spin_unlock_irqrestore(&stream_info->lock, flags); } @@ -3029,6 +3019,8 @@ static void __msm_isp_stop_axi_streams(struct vfe_device *vfe_dev, /* clear buffers that are dequeued */ for (i = 0; i < num_streams; i++) { stream_info = streams[i]; + if (stream_info->lpm_mode == 0) + msm_isp_update_stream_bandwidth(stream_info, 0); for (bufq_id = 0; bufq_id < VFE_BUF_QUEUE_MAX; bufq_id++) { bufq_handle = stream_info->bufq_handle[bufq_id]; if (!bufq_handle) @@ -3044,12 +3036,6 @@ static void __msm_isp_stop_axi_streams(struct vfe_device *vfe_dev, } } - for (k = 0; k < MAX_VFE; k++) { - if (!update_vfes[k]) - continue; - msm_isp_update_stream_bandwidth(update_vfes[k]); - } - for (i = 0; i < num_streams; i++) { stream_info = streams[i]; intf = SRC_TO_INTF(stream_info->stream_src); @@ -3143,7 +3129,14 @@ static int msm_isp_start_axi_stream(struct vfe_device *vfe_dev_ioctl, cfg_wm_irq_mask(vfe_dev, stream_info); } } - intf = SRC_TO_INTF(stream_info->stream_src); + intf = SRC_TO_INTF(stream_info->stream_src); + stream_info->lpm_mode = vfe_dev_ioctl-> + axi_data.src_info[intf].lpm; + if (stream_info->lpm_mode == 0) { + spin_unlock_irqrestore(&stream_info->lock, flags); + msm_isp_update_stream_bandwidth(stream_info, 1); + spin_lock_irqsave(&stream_info->lock, flags); + } init_completion(&stream_info->active_comp); stream_info->state = START_PENDING; msm_isp_update_intf_stream_cnt(stream_info, 1); @@ -3153,7 +3146,7 @@ static int msm_isp_start_axi_stream(struct vfe_device *vfe_dev_ioctl, vfe_dev_ioctl->pdev->id); if (src_state) { src_mask |= (1 << SRC_TO_INTF(stream_info->stream_src)); - if (vfe_dev_ioctl->axi_data.src_info[intf].lpm) { + if (stream_info->lpm_mode) { while (stream_info->state != ACTIVE) __msm_isp_axi_stream_update( stream_info, ×tamp); @@ -3187,7 +3180,6 @@ static int msm_isp_start_axi_stream(struct vfe_device *vfe_dev_ioctl, vfe_dev = update_vfes[i]; if (!vfe_dev) continue; - msm_isp_update_stream_bandwidth(vfe_dev); vfe_dev->hw_info->vfe_ops.axi_ops.reload_wm(vfe_dev, vfe_dev->vfe_base, wm_reload_mask[i]); diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c index 73068a615380..ee695bf5dfd9 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c @@ -229,8 +229,12 @@ static int32_t msm_isp_stats_buf_divert(struct vfe_device *vfe_dev, stats_event->pd_stats_idx = 0xF; if (stream_info->stats_type == MSM_ISP_STATS_BF) { - stats_event->pd_stats_idx = vfe_dev->pd_buf_idx; - vfe_dev->pd_buf_idx = 0xF; + spin_lock_irqsave(&vfe_dev->common_data-> + common_dev_data_lock, flags); + stats_event->pd_stats_idx = vfe_dev->common_data->pd_buf_idx; + vfe_dev->common_data->pd_buf_idx = 0xF; + spin_unlock_irqrestore(&vfe_dev->common_data-> + common_dev_data_lock, flags); } if (comp_stats_type_mask == NULL) { stats_event->stats_mask = diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c index c8f5c051424e..2f8134bc3efb 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c @@ -2225,8 +2225,6 @@ static void msm_vfe_iommu_fault_handler(struct iommu_domain *domain, mutex_lock(&vfe_dev->core_mutex); if (vfe_dev->vfe_open_cnt > 0) { - atomic_set(&vfe_dev->error_info.overflow_state, - HALT_ENFORCED); pr_err_ratelimited("%s: fault address is %lx\n", __func__, iova); msm_isp_process_iommu_page_fault(vfe_dev); @@ -2316,7 +2314,7 @@ int msm_isp_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) /* Register page fault handler */ vfe_dev->buf_mgr->pagefault_debug_disable = 0; /* initialize pd_buf_idx with an invalid index 0xF */ - vfe_dev->pd_buf_idx = 0xF; + vfe_dev->common_data->pd_buf_idx = 0xF; cam_smmu_reg_client_page_fault_handler( vfe_dev->buf_mgr->iommu_hdl, @@ -2342,6 +2340,7 @@ int msm_isp_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { long rc = 0; int wm; + int i; struct vfe_device *vfe_dev = v4l2_get_subdevdata(sd); ISP_DBG("%s E open_cnt %u\n", __func__, vfe_dev->vfe_open_cnt); mutex_lock(&vfe_dev->realtime_mutex); @@ -2391,6 +2390,8 @@ int msm_isp_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) msm_isp_end_avtimer(); vfe_dev->vt_enable = 0; } + for (i = 0; i < VFE_SRC_MAX; i++) + vfe_dev->axi_data.src_info[i].lpm = 0; MSM_ISP_DUAL_VFE_MUTEX_UNLOCK(vfe_dev); vfe_dev->is_split = 0; diff --git a/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c b/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c index af6206f83048..f732f5180e81 100644 --- a/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c +++ b/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c @@ -540,20 +540,24 @@ static long msm_buf_mngr_subdev_ioctl(struct v4l2_subdev *sd, k_ioctl = *ptr; switch (k_ioctl.id) { case MSM_CAMERA_BUF_MNGR_IOCTL_ID_GET_BUF_BY_IDX: { - struct msm_buf_mngr_info buf_info, *tmp = NULL; if (k_ioctl.size != sizeof(struct msm_buf_mngr_info)) return -EINVAL; if (!k_ioctl.ioctl_ptr) return -EINVAL; - - MSM_CAM_GET_IOCTL_ARG_PTR(&tmp, &k_ioctl.ioctl_ptr, - sizeof(tmp)); - if (copy_from_user(&buf_info, tmp, - sizeof(struct msm_buf_mngr_info))) { - return -EFAULT; +#ifndef CONFIG_COMPAT + { + struct msm_buf_mngr_info buf_info, *tmp = NULL; + + MSM_CAM_GET_IOCTL_ARG_PTR(&tmp, + &k_ioctl.ioctl_ptr, sizeof(tmp)); + if (copy_from_user(&buf_info, tmp, + sizeof(struct msm_buf_mngr_info))) { + return -EFAULT; + } + k_ioctl.ioctl_ptr = (uintptr_t)&buf_info; } - k_ioctl.ioctl_ptr = (uintptr_t)&buf_info; +#endif argp = &k_ioctl; rc = msm_cam_buf_mgr_ops(cmd, argp); } @@ -674,6 +678,7 @@ static long msm_camera_buf_mgr_internal_compat_ioctl(struct file *file, return -EINVAL; } k_ioctl.ioctl_ptr = (__u64)&buf_info; + k_ioctl.size = sizeof(struct msm_buf_mngr_info); rc = msm_camera_buf_mgr_fetch_buf_info(&buf_info32, &buf_info, (unsigned long)tmp_compat_ioctl_ptr); if (rc < 0) { diff --git a/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c b/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c index e60947ecad21..31d2fdc24322 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c +++ b/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1269,6 +1269,11 @@ static int msm_eeprom_spi_remove(struct spi_device *sdev) return 0; } + if (!e_ctrl->eboard_info) { + pr_err("%s: board info is NULL\n", __func__); + return 0; + } + msm_camera_i2c_dev_put_clk_info( &e_ctrl->i2c_client.spi_client->spi_master->dev, &e_ctrl->eboard_info->power_info.clk_info, @@ -1788,6 +1793,11 @@ static int msm_eeprom_platform_remove(struct platform_device *pdev) return 0; } + if (!e_ctrl->eboard_info) { + pr_err("%s: board info is NULL\n", __func__); + return 0; + } + msm_camera_put_clk_info(e_ctrl->pdev, &e_ctrl->eboard_info->power_info.clk_info, &e_ctrl->eboard_info->power_info.clk_ptr, diff --git a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c index 344f1a6f8d92..891e528f75f1 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c +++ b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -793,6 +793,21 @@ int32_t msm_sensor_driver_probe(void *setting, } } + if (strlen(slave_info->sensor_name) >= MAX_SENSOR_NAME || + strlen(slave_info->eeprom_name) >= MAX_SENSOR_NAME || + strlen(slave_info->actuator_name) >= MAX_SENSOR_NAME || + strlen(slave_info->ois_name) >= MAX_SENSOR_NAME) { + pr_err("failed: name len greater than 32.\n"); + pr_err("sensor name len:%zu, eeprom name len: %zu.\n", + strlen(slave_info->sensor_name), + strlen(slave_info->eeprom_name)); + pr_err("actuator name len: %zu, ois name len:%zu.\n", + strlen(slave_info->actuator_name), + strlen(slave_info->ois_name)); + rc = -EINVAL; + goto free_slave_info; + } + /* Print slave info */ CDBG("camera id %d Slave addr 0x%X addr_type %d\n", slave_info->camera_id, slave_info->slave_addr, @@ -847,9 +862,12 @@ int32_t msm_sensor_driver_probe(void *setting, */ if (slave_info->sensor_id_info.sensor_id == s_ctrl->sensordata->cam_slave_info-> - sensor_id_info.sensor_id) { - pr_err("slot%d: sensor id%d already probed\n", + sensor_id_info.sensor_id && + !(strcmp(slave_info->sensor_name, + s_ctrl->sensordata->cam_slave_info->sensor_name))) { + pr_err("slot%d: sensor name: %s sensor id%d already probed\n", slave_info->camera_id, + slave_info->sensor_name, s_ctrl->sensordata->cam_slave_info-> sensor_id_info.sensor_id); msm_sensor_fill_sensor_info(s_ctrl, @@ -1353,18 +1371,20 @@ static int32_t msm_sensor_driver_i2c_probe(struct i2c_client *client, if (s_ctrl->sensor_i2c_client != NULL) { s_ctrl->sensor_i2c_client->client = client; s_ctrl->sensordata->power_info.dev = &client->dev; + + /* Get clocks information */ + rc = msm_camera_i2c_dev_get_clk_info( + &s_ctrl->sensor_i2c_client->client->dev, + &s_ctrl->sensordata->power_info.clk_info, + &s_ctrl->sensordata->power_info.clk_ptr, + &s_ctrl->sensordata->power_info.clk_info_size); + if (rc < 0) { + pr_err("failed: msm_camera_i2c_dev_get_clk_info rc %d", + rc); + goto FREE_S_CTRL; + } + return rc; } - /* Get clocks information */ - rc = msm_camera_i2c_dev_get_clk_info( - &s_ctrl->sensor_i2c_client->client->dev, - &s_ctrl->sensordata->power_info.clk_info, - &s_ctrl->sensordata->power_info.clk_ptr, - &s_ctrl->sensordata->power_info.clk_info_size); - if (rc < 0) { - pr_err("failed: msm_camera_i2c_dev_get_clk_info rc %d", rc); - goto FREE_S_CTRL; - } - return rc; FREE_S_CTRL: kfree(s_ctrl); return rc; diff --git a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c index 2fc3ce406c27..2d2296893140 100644 --- a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c +++ b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c @@ -6536,10 +6536,8 @@ static int mpq_sdmx_write(struct mpq_demux *mpq_demux, const char *buf, size_t count) { - struct ion_handle *ion_handle = - mpq_demux->demux.dmx.dvr_input.priv_handle; - struct dvb_ringbuffer *rbuf = (struct dvb_ringbuffer *) - mpq_demux->demux.dmx.dvr_input.ringbuff; + struct ion_handle *ion_handle; + struct dvb_ringbuffer *rbuf; struct sdmx_buff_descr buf_desc; u32 read_offset; int ret; @@ -6549,10 +6547,13 @@ static int mpq_sdmx_write(struct mpq_demux *mpq_demux, return -EINVAL; } + ion_handle = mpq_demux->demux.dmx.dvr_input.priv_handle; + rbuf = (struct dvb_ringbuffer *)mpq_demux->demux.dmx.dvr_input.ringbuff; + ret = mpq_sdmx_dvr_buffer_desc(mpq_demux, &buf_desc); if (ret) { MPQ_DVB_ERR_PRINT( - "%s: Failed to init input buffer descriptor. ret = %d\n", + "%s: Failed to init input buffer descriptor. ret = %d\n", __func__, ret); return ret; } 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 9855bee67627..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); @@ -7750,7 +7745,7 @@ static int qseecom_retrieve_ce_data(struct platform_device *pdev) uint32_t hlos_num_ce_hw_instances; uint32_t disk_encrypt_pipe; uint32_t file_encrypt_pipe; - uint32_t hlos_ce_hw_instance[MAX_CE_PIPE_PAIR_PER_UNIT]; + uint32_t hlos_ce_hw_instance[MAX_CE_PIPE_PAIR_PER_UNIT] = {0}; int i; const int *tbl; int size; diff --git a/drivers/mmc/core/bus.h b/drivers/mmc/core/bus.h index 00a19710b6b4..3f3f24b2a757 100644 --- a/drivers/mmc/core/bus.h +++ b/drivers/mmc/core/bus.h @@ -15,7 +15,7 @@ static ssize_t mmc_##name##_show (struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct mmc_card *card = mmc_dev_to_card(dev); \ - return sprintf(buf, fmt, args); \ + return snprintf(buf, PAGE_SIZE, fmt, args); \ } \ static DEVICE_ATTR(name, S_IRUGO, mmc_##name##_show, NULL) diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 691287125895..5eda4f4fb0fe 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -2617,6 +2617,9 @@ static int mmc_partial_init(struct mmc_host *host) if (mmc_card_hs400(card)) { if (card->ext_csd.strobe_support && host->ops->enhanced_strobe) err = host->ops->enhanced_strobe(host); + else if (host->ops->execute_tuning) + err = host->ops->execute_tuning(host, + MMC_SEND_TUNING_BLOCK_HS200); } else if (mmc_card_hs200(card) && host->ops->execute_tuning) { err = host->ops->execute_tuning(host, MMC_SEND_TUNING_BLOCK_HS200); diff --git a/drivers/mmc/host/sdhci-msm-ice.c b/drivers/mmc/host/sdhci-msm-ice.c index 2799b21fb6e3..e73bdfd424cc 100644 --- a/drivers/mmc/host/sdhci-msm-ice.c +++ b/drivers/mmc/host/sdhci-msm-ice.c @@ -377,7 +377,7 @@ int sdhci_msm_ice_cmdq_cfg(struct sdhci_host *host, struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_msm_host *msm_host = pltfm_host->priv; int err = 0; - short key_index; + short key_index = 0; sector_t lba = 0; unsigned int bypass = SDHCI_MSM_ICE_ENABLE_BYPASS; struct request *req; diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 987d61bdda2d..ca72ebfd55a3 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -5004,6 +5004,7 @@ static struct platform_driver sdhci_msm_driver = { .driver = { .name = "sdhci_msm", .owner = THIS_MODULE, + .probe_type = PROBE_PREFER_ASYNCHRONOUS, .of_match_table = sdhci_msm_dt_match, .pm = SDHCI_MSM_PMOPS, }, diff --git a/drivers/mtd/chips/Kconfig b/drivers/mtd/chips/Kconfig index 54479c481a7a..8a25adced79f 100644 --- a/drivers/mtd/chips/Kconfig +++ b/drivers/mtd/chips/Kconfig @@ -111,6 +111,7 @@ config MTD_MAP_BANK_WIDTH_16 config MTD_MAP_BANK_WIDTH_32 bool "Support 256-bit buswidth" if MTD_CFI_GEOMETRY + select MTD_COMPLEX_MAPPINGS if HAS_IOMEM default n help If you wish to support CFI devices on a physical bus which is diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index 49056c33be74..21e5b9ed1ead 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -12031,7 +12031,7 @@ static int tg3_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, int ret; u32 offset, len, b_offset, odd_len; u8 *buf; - __be32 start, end; + __be32 start = 0, end; if (tg3_flag(tp, NO_NVRAM) || eeprom->magic != TG3_EEPROM_MAGIC) diff --git a/drivers/net/ethernet/cavium/liquidio/lio_main.c b/drivers/net/ethernet/cavium/liquidio/lio_main.c index 7445da218bd9..cc1725616f9d 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_main.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_main.c @@ -2823,7 +2823,7 @@ static int liquidio_xmit(struct sk_buff *skb, struct net_device *netdev) if (!g) { netif_info(lio, tx_err, lio->netdev, "Transmit scatter gather: glist null!\n"); - goto lio_xmit_failed; + goto lio_xmit_dma_failed; } cmdsetup.s.gather = 1; @@ -2894,7 +2894,7 @@ static int liquidio_xmit(struct sk_buff *skb, struct net_device *netdev) else status = octnet_send_nic_data_pkt(oct, &ndata, xmit_more); if (status == IQ_SEND_FAILED) - goto lio_xmit_failed; + goto lio_xmit_dma_failed; netif_info(lio, tx_queued, lio->netdev, "Transmit queued successfully\n"); @@ -2908,12 +2908,13 @@ static int liquidio_xmit(struct sk_buff *skb, struct net_device *netdev) return NETDEV_TX_OK; +lio_xmit_dma_failed: + dma_unmap_single(&oct->pci_dev->dev, ndata.cmd.dptr, + ndata.datasize, DMA_TO_DEVICE); lio_xmit_failed: stats->tx_dropped++; netif_info(lio, tx_err, lio->netdev, "IQ%d Transmit dropped:%llu\n", iq_no, stats->tx_dropped); - dma_unmap_single(&oct->pci_dev->dev, ndata.cmd.dptr, - ndata.datasize, DMA_TO_DEVICE); recv_buffer_free(skb); return NETDEV_TX_OK; } diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 06c8bfeaccd6..40cd86614677 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -1110,6 +1110,7 @@ static int macvlan_port_create(struct net_device *dev) static void macvlan_port_destroy(struct net_device *dev) { struct macvlan_port *port = macvlan_port_get_rtnl(dev); + struct sk_buff *skb; dev->priv_flags &= ~IFF_MACVLAN_PORT; netdev_rx_handler_unregister(dev); @@ -1118,7 +1119,15 @@ static void macvlan_port_destroy(struct net_device *dev) * but we need to cancel it and purge left skbs if any. */ cancel_work_sync(&port->bc_work); - __skb_queue_purge(&port->bc_queue); + + while ((skb = __skb_dequeue(&port->bc_queue))) { + const struct macvlan_dev *src = MACVLAN_SKB_CB(skb)->src; + + if (src) + dev_put(src->dev); + + kfree_skb(skb); + } kfree_rcu(port, rcu); } diff --git a/drivers/net/phy/dp83640.c b/drivers/net/phy/dp83640.c index e6cefd0e3262..84b9cca152eb 100644 --- a/drivers/net/phy/dp83640.c +++ b/drivers/net/phy/dp83640.c @@ -1436,8 +1436,6 @@ static bool dp83640_rxtstamp(struct phy_device *phydev, skb_info->tmo = jiffies + SKB_TIMESTAMP_TIMEOUT; skb_queue_tail(&dp83640->rx_queue, skb); schedule_delayed_work(&dp83640->ts_work, SKB_TIMESTAMP_TIMEOUT); - } else { - netif_rx_ni(skb); } return true; diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index bba0ca786aaa..851c0e121807 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -538,7 +538,7 @@ void phy_stop_machine(struct phy_device *phydev) cancel_delayed_work_sync(&phydev->state_queue); mutex_lock(&phydev->lock); - if (phydev->state > PHY_UP) + if (phydev->state > PHY_UP && phydev->state != PHY_HALTED) phydev->state = PHY_UP; mutex_unlock(&phydev->lock); } diff --git a/drivers/net/ppp/pppolac.c b/drivers/net/ppp/pppolac.c index 0184c96579e9..3a45cf805288 100644 --- a/drivers/net/ppp/pppolac.c +++ b/drivers/net/ppp/pppolac.c @@ -206,7 +206,9 @@ static void pppolac_xmit_core(struct work_struct *delivery_work) while ((skb = skb_dequeue(&delivery_queue))) { struct sock *sk_udp = skb->sk; struct kvec iov = {.iov_base = skb->data, .iov_len = skb->len}; - struct msghdr msg = { 0 }; + struct msghdr msg = { + .msg_flags = MSG_NOSIGNAL | MSG_DONTWAIT, + }; iov_iter_kvec(&msg.msg_iter, WRITE | ITER_KVEC, &iov, 1, skb->len); diff --git a/drivers/net/ppp/pppopns.c b/drivers/net/ppp/pppopns.c index d9e06039794e..cdb4fa1af734 100644 --- a/drivers/net/ppp/pppopns.c +++ b/drivers/net/ppp/pppopns.c @@ -189,7 +189,9 @@ static void pppopns_xmit_core(struct work_struct *delivery_work) while ((skb = skb_dequeue(&delivery_queue))) { struct sock *sk_raw = skb->sk; struct kvec iov = {.iov_base = skb->data, .iov_len = skb->len}; - struct msghdr msg = { 0 }; + struct msghdr msg = { + .msg_flags = MSG_NOSIGNAL | MSG_DONTWAIT, + }; iov_iter_kvec(&msg.msg_iter, WRITE | ITER_KVEC, &iov, 1, skb->len); diff --git a/drivers/net/wireless/ath/ath10k/qmi.c b/drivers/net/wireless/ath/ath10k/qmi.c index 9bab797dcdbc..10223605b027 100644 --- a/drivers/net/wireless/ath/ath10k/qmi.c +++ b/drivers/net/wireless/ath/ath10k/qmi.c @@ -888,12 +888,13 @@ void ath10k_snoc_stop_qmi_service(struct ath10k *ar) ath10k_dbg(ar, ATH10K_DBG_SNOC, "Removing QMI service..\n"); + wake_up_all(&ath10k_fw_ready_wait_event); + cancel_work_sync(&qmi_cfg->event_work); + cancel_work_sync(&qmi_cfg->qmi_recv_msg_work); qmi_svc_event_notifier_unregister(WLFW_SERVICE_ID_V01, WLFW_SERVICE_VERS_V01, WLFW_SERVICE_INS_ID_V01, &qmi_cfg->wlfw_clnt_nb); - - wake_up_all(&ath10k_fw_ready_wait_event); destroy_workqueue(qmi_cfg->event_wq); qmi_cfg = NULL; } diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c index 08618cedf775..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; @@ -1146,8 +1151,10 @@ static int ath10k_snoc_hif_power_up(struct ath10k *ar) if (ar->state == ATH10K_STATE_ON || test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags)) { ret = ath10k_snoc_bus_configure(ar); - if (ret) + if (ret) { ath10k_err(ar, "failed to configure bus: %d\n", ret); + return ret; + } } ret = ath10k_snoc_init_pipes(ar); if (ret) { @@ -1196,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/Kconfig b/drivers/net/wireless/ath/wil6210/Kconfig index 8f0bde5825d5..0e66348e7513 100644 --- a/drivers/net/wireless/ath/wil6210/Kconfig +++ b/drivers/net/wireless/ath/wil6210/Kconfig @@ -44,7 +44,7 @@ config WIL6210_TRACING config WIL6210_WRITE_IOCTL bool "wil6210 write ioctl to the device" depends on WIL6210 - default n + default y ---help--- Say Y here to allow write-access from user-space to the device memory through ioctl. This is useful for diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 37898146f01d..69214fb2586c 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -26,6 +26,10 @@ bool disable_ap_sme; module_param(disable_ap_sme, bool, 0444); MODULE_PARM_DESC(disable_ap_sme, " let user space handle AP mode SME"); +static bool ignore_reg_hints = true; +module_param(ignore_reg_hints, bool, 0444); +MODULE_PARM_DESC(ignore_reg_hints, " Ignore OTA regulatory hints (Default: true)"); + #define CHAN60G(_channel, _flags) { \ .band = IEEE80211_BAND_60GHZ, \ .center_freq = 56160 + (2160 * (_channel)), \ @@ -1650,12 +1654,6 @@ static int wil_cfg80211_set_power_mgmt(struct wiphy *wiphy, { struct wil6210_priv *wil = wiphy_to_wil(wiphy); enum wmi_ps_profile_type ps_profile; - int rc; - - if (!test_bit(WMI_FW_CAPABILITY_PS_CONFIG, wil->fw_capabilities)) { - wil_err(wil, "set_power_mgmt not supported\n"); - return -EOPNOTSUPP; - } wil_dbg_misc(wil, "enabled=%d, timeout=%d\n", enabled, timeout); @@ -1665,13 +1663,45 @@ static int wil_cfg80211_set_power_mgmt(struct wiphy *wiphy, else ps_profile = WMI_PS_PROFILE_TYPE_PS_DISABLED; - rc = wmi_ps_dev_profile_cfg(wil, ps_profile); + 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) - wil_err(wil, "wmi_ps_dev_profile_cfg failed (%d)\n", 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, @@ -1703,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) @@ -1743,6 +1775,11 @@ static void wil_wiphy_init(struct wiphy *wiphy) wiphy->vendor_commands = wil_nl80211_vendor_commands; wiphy->vendor_events = wil_nl80211_vendor_events; wiphy->n_vendor_events = ARRAY_SIZE(wil_nl80211_vendor_events); + + if (ignore_reg_hints) { + wiphy->regulatory_flags |= REGULATORY_DISABLE_BEACON_HINTS; + wiphy->regulatory_flags |= REGULATORY_COUNTRY_IE_IGNORE; + } } struct wireless_dev *wil_cfg80211_init(struct device *dev) diff --git a/drivers/net/wireless/ath/wil6210/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/fw_inc.c b/drivers/net/wireless/ath/wil6210/fw_inc.c index f4901587c005..e01acac88825 100644 --- a/drivers/net/wireless/ath/wil6210/fw_inc.c +++ b/drivers/net/wireless/ath/wil6210/fw_inc.c @@ -554,5 +554,7 @@ bool wil_fw_verify_file_exists(struct wil6210_priv *wil, const char *name) rc = request_firmware(&fw, name, wil_to_dev(wil)); if (!rc) release_firmware(fw); - return rc != -ENOENT; + else + wil_dbg_fw(wil, "<%s> not available: %d\n", name, rc); + return !rc; } diff --git a/drivers/net/wireless/ath/wil6210/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 fca8acffeed5..78091b7910c7 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -576,6 +576,12 @@ int wil_priv_init(struct wil6210_priv *wil) if (rx_ring_overflow_thrsh == WIL6210_RX_HIGH_TRSH_INIT) rx_ring_overflow_thrsh = WIL6210_RX_HIGH_TRSH_DEFAULT; + + wil->ps_profile = WMI_PS_PROFILE_TYPE_DEFAULT; + + wil->wakeup_trigger = WMI_WAKEUP_TRIGGER_UCAST | + WMI_WAKEUP_TRIGGER_BCAST; + return 0; out_wmi_wq: @@ -586,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); + } } /** @@ -901,6 +909,24 @@ void wil_abort_scan(struct wil6210_priv *wil, bool sync) } } +int wil_ps_update(struct wil6210_priv *wil, enum wmi_ps_profile_type ps_profile) +{ + int rc; + + if (!test_bit(WMI_FW_CAPABILITY_PS_CONFIG, wil->fw_capabilities)) { + wil_err(wil, "set_power_mgmt not supported\n"); + return -EOPNOTSUPP; + } + + rc = wmi_ps_dev_profile_cfg(wil, ps_profile); + if (rc) + wil_err(wil, "wmi_ps_dev_profile_cfg failed (%d)\n", rc); + else + wil->ps_profile = ps_profile; + + return rc; +} + /* * We reset all the structures, and we reset the UMAC. * After calling this routine, you're expected to reload @@ -950,15 +976,15 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) /* Disable device led before reset*/ wmi_led_cfg(wil, false); + mutex_lock(&wil->p2p_wdev_mutex); + wil_abort_scan(wil, false); + mutex_unlock(&wil->p2p_wdev_mutex); + /* prevent NAPI from being scheduled and prevent wmi commands */ mutex_lock(&wil->wmi_mutex); bitmap_zero(wil->status, wil_status_last); mutex_unlock(&wil->wmi_mutex); - mutex_lock(&wil->p2p_wdev_mutex); - wil_abort_scan(wil, false); - mutex_unlock(&wil->p2p_wdev_mutex); - wil_mask_irq(wil); wmi_event_flush(wil); @@ -1035,6 +1061,9 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) return rc; } + if (wil->ps_profile != WMI_PS_PROFILE_TYPE_DEFAULT) + wil_ps_update(wil, wil->ps_profile); + if (wil->tt_data_set) wmi_set_tt_cfg(wil, &wil->tt_data); diff --git a/drivers/net/wireless/ath/wil6210/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/pmc.c b/drivers/net/wireless/ath/wil6210/pmc.c index b067fdf086d4..2e301b6b32a9 100644 --- a/drivers/net/wireless/ath/wil6210/pmc.c +++ b/drivers/net/wireless/ath/wil6210/pmc.c @@ -200,7 +200,7 @@ void wil_pmc_alloc(struct wil6210_priv *wil, release_pmc_skbs: wil_err(wil, "exit on error: Releasing skbs...\n"); - for (i = 0; pmc->descriptors[i].va && i < num_descriptors; i++) { + for (i = 0; i < num_descriptors && pmc->descriptors[i].va; i++) { dma_free_coherent(dev, descriptor_size, pmc->descriptors[i].va, @@ -283,7 +283,7 @@ void wil_pmc_free(struct wil6210_priv *wil, int send_pmc_cmd) int i; for (i = 0; - pmc->descriptors[i].va && i < pmc->num_descriptors; i++) { + i < pmc->num_descriptors && pmc->descriptors[i].va; i++) { dma_free_coherent(dev, pmc->descriptor_size, pmc->descriptors[i].va, diff --git a/drivers/net/wireless/ath/wil6210/rx_reorder.c b/drivers/net/wireless/ath/wil6210/rx_reorder.c index 7404b6f39c6a..a43cffcf1bbf 100644 --- a/drivers/net/wireless/ath/wil6210/rx_reorder.c +++ b/drivers/net/wireless/ath/wil6210/rx_reorder.c @@ -343,8 +343,16 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) wil_err(wil, "BACK requested unsupported ba_policy == 1\n"); status = WLAN_STATUS_INVALID_QOS_PARAM; } - if (status == WLAN_STATUS_SUCCESS) - agg_wsize = wil_agg_size(wil, req_agg_wsize); + if (status == WLAN_STATUS_SUCCESS) { + if (req_agg_wsize == 0) { + wil_dbg_misc(wil, "Suggest BACK wsize %d\n", + WIL_MAX_AGG_WSIZE); + agg_wsize = WIL_MAX_AGG_WSIZE; + } else { + agg_wsize = min_t(u16, + WIL_MAX_AGG_WSIZE, req_agg_wsize); + } + } rc = wmi_addba_rx_resp(wil, cid, tid, dialog_token, status, agg_amsdu, agg_wsize, agg_timeout); diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 8b5411e4dc34..439fe30936b6 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -37,6 +37,10 @@ bool rx_align_2; module_param(rx_align_2, bool, 0444); MODULE_PARM_DESC(rx_align_2, " align Rx buffers on 4*n+2, default - no"); +bool rx_large_buf; +module_param(rx_large_buf, bool, 0444); +MODULE_PARM_DESC(rx_large_buf, " allocate 8KB RX buffers, default - no"); + static inline uint wil_rx_snaplen(void) { return rx_align_2 ? 6 : 0; @@ -100,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) { @@ -255,7 +304,7 @@ static int wil_vring_alloc_skb(struct wil6210_priv *wil, struct vring *vring, u32 i, int headroom) { struct device *dev = wil_to_dev(wil); - unsigned int sz = mtu_max + ETH_HLEN + wil_rx_snaplen(); + unsigned int sz = wil->rx_buf_len + ETH_HLEN + wil_rx_snaplen(); struct vring_rx_desc dd, *d = ⅆ volatile struct vring_rx_desc *_d = &vring->va[i].rx; dma_addr_t pa; @@ -402,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 * @@ -419,7 +480,7 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil, struct sk_buff *skb; dma_addr_t pa; unsigned int snaplen = wil_rx_snaplen(); - unsigned int sz = mtu_max + ETH_HLEN + snaplen; + unsigned int sz = wil->rx_buf_len + ETH_HLEN + snaplen; u16 dmalen; u8 ftype; int cid; @@ -780,6 +841,20 @@ void wil_rx_handle(struct wil6210_priv *wil, int *quota) wil_rx_refill(wil, v->size); } +static void wil_rx_buf_len_init(struct wil6210_priv *wil) +{ + wil->rx_buf_len = rx_large_buf ? + WIL_MAX_ETH_MTU : TXRX_BUF_LEN_DEFAULT - WIL_MAX_MPDU_OVERHEAD; + if (mtu_max > wil->rx_buf_len) { + /* do not allow RX buffers to be smaller than mtu_max, for + * backward compatibility (mtu_max parameter was also used + * to support receiving large packets) + */ + wil_info(wil, "Override RX buffer to mtu_max(%d)\n", mtu_max); + wil->rx_buf_len = mtu_max; + } +} + int wil_rx_init(struct wil6210_priv *wil, u16 size) { struct vring *vring = &wil->vring_rx; @@ -792,6 +867,8 @@ int wil_rx_init(struct wil6210_priv *wil, u16 size) return -EINVAL; } + wil_rx_buf_len_init(wil); + vring->size = size; rc = wil_vring_alloc(wil, vring); if (rc) @@ -1792,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 0529d10a8268..e76ec6ed9995 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -33,6 +33,7 @@ extern unsigned short rx_ring_overflow_thrsh; extern int agg_wsize; extern u32 vring_idle_trsh; extern bool rx_align_2; +extern bool rx_large_buf; extern bool debug_fw; extern bool disable_ap_sme; @@ -82,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 */ @@ -295,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 */ @@ -423,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 */ }; @@ -670,6 +684,7 @@ struct wil6210_priv { struct work_struct probe_client_worker; /* DMA related */ struct vring vring_rx; + unsigned int rx_buf_len; struct vring vring_tx[WIL6210_MAX_TX_RINGS]; struct vring_tx_data vring_tx_data[WIL6210_MAX_TX_RINGS]; u8 vring2cid_tid[WIL6210_MAX_TX_RINGS][2]; /* [0] - CID, [1] - TID */ @@ -687,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; @@ -705,6 +723,8 @@ struct wil6210_priv { /* High Access Latency Policy voting */ struct wil_halp halp; + enum wmi_ps_profile_type ps_profile; + struct wil_ftm_priv ftm; bool tt_data_set; struct wmi_tt_data tt_data; @@ -714,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) @@ -824,6 +849,8 @@ int wil_if_add(struct wil6210_priv *wil); void wil_if_remove(struct wil6210_priv *wil); int wil_priv_init(struct wil6210_priv *wil); void wil_priv_deinit(struct wil6210_priv *wil); +int wil_ps_update(struct wil6210_priv *wil, + enum wmi_ps_profile_type ps_profile); int wil_reset(struct wil6210_priv *wil, bool no_fw); void wil_fw_error_recovery(struct wil6210_priv *wil); void wil_set_recovery_state(struct wil6210_priv *wil, int state); @@ -974,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 41afbdc34c18..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); @@ -1436,7 +1467,8 @@ int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring) struct wmi_cfg_rx_chain_cmd cmd = { .action = WMI_RX_CHAIN_ADD, .rx_sw_ring = { - .max_mpdu_size = cpu_to_le16(wil_mtu2macbuf(mtu_max)), + .max_mpdu_size = cpu_to_le16( + wil_mtu2macbuf(wil->rx_buf_len)), .ring_mem_base = cpu_to_le64(vring->pa), .ring_size = cpu_to_le16(vring->size), }, @@ -1908,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) { @@ -1997,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/net/wireless/cnss/Kconfig b/drivers/net/wireless/cnss/Kconfig index 4558dc30fec1..8e69a2b469b9 100644 --- a/drivers/net/wireless/cnss/Kconfig +++ b/drivers/net/wireless/cnss/Kconfig @@ -9,6 +9,15 @@ config CNSS This driver also adds support to integrate WLAN module to subsystem restart framework. +config CNSS_ASYNC + bool "Enable/disable cnss pci platform driver asynchronous probe" + depends on CNSS + ---help--- + If enabled, CNSS PCI platform driver would do asynchronous probe. + Using asynchronous probe will allow CNSS PCI platform driver to + probe in parallel with other device drivers and will help to + reduce kernel boot time. + config CNSS_MAC_BUG bool "Enable/disable 0-4K memory initialization for QCA6174" depends on CNSS diff --git a/drivers/net/wireless/cnss/cnss_pci.c b/drivers/net/wireless/cnss/cnss_pci.c index f53ed2693879..48d358c4722a 100644 --- a/drivers/net/wireless/cnss/cnss_pci.c +++ b/drivers/net/wireless/cnss/cnss_pci.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -3067,6 +3067,9 @@ static struct platform_driver cnss_driver = { .name = "cnss", .owner = THIS_MODULE, .of_match_table = cnss_dt_match, +#ifdef CONFIG_CNSS_ASYNC + .probe_type = PROBE_PREFER_ASYNCHRONOUS, +#endif }, }; diff --git a/drivers/nfc/nq-nci.c b/drivers/nfc/nq-nci.c index f4ad5bde06a8..538d8f91ce1b 100644 --- a/drivers/nfc/nq-nci.c +++ b/drivers/nfc/nq-nci.c @@ -1206,6 +1206,7 @@ static struct i2c_driver nqx = { .owner = THIS_MODULE, .name = "nq-nci", .of_match_table = msm_match_table, + .probe_type = PROBE_PREFER_ASYNCHRONOUS, .pm = &nfc_pm_ops, }, }; diff --git a/drivers/pci/host/pci-msm.c b/drivers/pci/host/pci-msm.c index 243afbe44df3..8bb759d10074 100644 --- a/drivers/pci/host/pci-msm.c +++ b/drivers/pci/host/pci-msm.c @@ -6449,7 +6449,6 @@ static int msm_pcie_probe(struct platform_device *pdev) } dev_set_drvdata(&msm_pcie_dev[rc_idx].pdev->dev, &msm_pcie_dev[rc_idx]); - msm_pcie_sysfs_init(&msm_pcie_dev[rc_idx]); ret = msm_pcie_get_resources(&msm_pcie_dev[rc_idx], msm_pcie_dev[rc_idx].pdev); @@ -6500,6 +6499,8 @@ static int msm_pcie_probe(struct platform_device *pdev) goto decrease_rc_num; } + msm_pcie_sysfs_init(&msm_pcie_dev[rc_idx]); + msm_pcie_dev[rc_idx].drv_ready = true; if (msm_pcie_dev[rc_idx].boot_option & diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c index e48c19c522a7..cb95f6e98956 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c @@ -80,6 +80,9 @@ const char *ipa_event_name[] = { __stringify(ECM_DISCONNECT), __stringify(IPA_TETHERING_STATS_UPDATE_STATS), __stringify(IPA_TETHERING_STATS_UPDATE_NETWORK_STATS), + __stringify(IPA_QUOTA_REACH), + __stringify(IPA_SSR_BEFORE_SHUTDOWN), + __stringify(IPA_SSR_AFTER_POWERUP), }; const char *ipa_hdr_l2_type_name[] = { diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_i.h b/drivers/platform/msm/ipa/ipa_v2/ipa_i.h index a14d1fee9c35..bb11230c960a 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_i.h +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_i.h @@ -51,6 +51,7 @@ #define IPA_UC_FINISH_MAX 6 #define IPA_UC_WAIT_MIN_SLEEP 1000 #define IPA_UC_WAII_MAX_SLEEP 1200 +#define IPA_BAM_STOP_MAX_RETRY 10 #define IPA_MAX_STATUS_STAT_NUM 30 diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_qmi_service.h b/drivers/platform/msm/ipa/ipa_v2/ipa_qmi_service.h index 96554af9aefd..1f5d619ef573 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_qmi_service.h +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_qmi_service.h @@ -177,6 +177,9 @@ int rmnet_ipa_set_tether_client_pipe(struct wan_ioctl_set_tether_client_pipe int rmnet_ipa_query_tethering_stats(struct wan_ioctl_query_tether_stats *data, bool reset); +int rmnet_ipa_query_tethering_stats_all( + struct wan_ioctl_query_tether_stats_all *data); + int rmnet_ipa_reset_tethering_stats(struct wan_ioctl_reset_tether_stats *data); int ipa_qmi_get_data_stats(struct ipa_get_data_stats_req_msg_v01 *req, diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_uc.c b/drivers/platform/msm/ipa/ipa_v2/ipa_uc.c index 3dd2eb093317..364cd4b7d38a 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_uc.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_uc.c @@ -590,6 +590,7 @@ int ipa_uc_send_cmd(u32 cmd, u32 opcode, u32 expected_status, { int index; union IpaHwCpuCmdCompletedResponseData_t uc_rsp; + int retries = 0; mutex_lock(&ipa_ctx->uc_ctx.uc_lock); @@ -599,6 +600,7 @@ int ipa_uc_send_cmd(u32 cmd, u32 opcode, u32 expected_status, return -EBADF; } +send_cmd: init_completion(&ipa_ctx->uc_ctx.uc_completion); ipa_ctx->uc_ctx.uc_sram_mmio->cmdParams = cmd; @@ -658,6 +660,19 @@ int ipa_uc_send_cmd(u32 cmd, u32 opcode, u32 expected_status, } if (ipa_ctx->uc_ctx.uc_status != expected_status) { + if (IPA_HW_2_CPU_WDI_RX_FSM_TRANSITION_ERROR == + ipa_ctx->uc_ctx.uc_status) { + retries++; + if (retries == IPA_BAM_STOP_MAX_RETRY) { + IPAERR("Failed after %d tries\n", retries); + } else { + /* sleep for short period to flush IPA */ + usleep_range(IPA_UC_WAIT_MIN_SLEEP, + IPA_UC_WAII_MAX_SLEEP); + goto send_cmd; + } + } + IPAERR("Recevied status %u, Expected status %u\n", ipa_ctx->uc_ctx.uc_status, expected_status); ipa_ctx->uc_ctx.pending_cmd = -1; diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_uc_offload_i.h b/drivers/platform/msm/ipa/ipa_v2/ipa_uc_offload_i.h index 3bec471b4656..a98d60249c0e 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_uc_offload_i.h +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_uc_offload_i.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -441,7 +441,7 @@ enum ipa_hw_offload_channel_states { /** - * enum ipa_hw_2_cpu_cmd_resp_status - Values that represent + * enum ipa_hw_2_cpu_offload_cmd_resp_status - Values that represent * offload related command response status to be sent to CPU. */ enum ipa_hw_2_cpu_offload_cmd_resp_status { @@ -478,6 +478,47 @@ enum ipa_hw_2_cpu_offload_cmd_resp_status { }; /** + * enum ipa_hw_2_cpu_cmd_resp_status - Values that represent WDI related + * command response status to be sent to CPU. + */ +enum ipa_hw_2_cpu_cmd_resp_status { + IPA_HW_2_CPU_WDI_CMD_STATUS_SUCCESS = + FEATURE_ENUM_VAL(IPA_HW_FEATURE_WDI, 0), + IPA_HW_2_CPU_MAX_WDI_TX_CHANNELS = + FEATURE_ENUM_VAL(IPA_HW_FEATURE_WDI, 1), + IPA_HW_2_CPU_WDI_CE_RING_OVERRUN_POSSIBILITY = + FEATURE_ENUM_VAL(IPA_HW_FEATURE_WDI, 2), + IPA_HW_2_CPU_WDI_CE_RING_SET_UP_FAILURE = + FEATURE_ENUM_VAL(IPA_HW_FEATURE_WDI, 3), + IPA_HW_2_CPU_WDI_CE_RING_PARAMS_UNALIGNED = + FEATURE_ENUM_VAL(IPA_HW_FEATURE_WDI, 4), + IPA_HW_2_CPU_WDI_COMP_RING_OVERRUN_POSSIBILITY = + FEATURE_ENUM_VAL(IPA_HW_FEATURE_WDI, 5), + IPA_HW_2_CPU_WDI_COMP_RING_SET_UP_FAILURE = + FEATURE_ENUM_VAL(IPA_HW_FEATURE_WDI, 6), + IPA_HW_2_CPU_WDI_COMP_RING_PARAMS_UNALIGNED = + FEATURE_ENUM_VAL(IPA_HW_FEATURE_WDI, 7), + IPA_HW_2_CPU_WDI_UNKNOWN_TX_CHANNEL = + FEATURE_ENUM_VAL(IPA_HW_FEATURE_WDI, 8), + IPA_HW_2_CPU_WDI_TX_INVALID_FSM_TRANSITION = + FEATURE_ENUM_VAL(IPA_HW_FEATURE_WDI, 9), + IPA_HW_2_CPU_WDI_TX_FSM_TRANSITION_ERROR = + FEATURE_ENUM_VAL(IPA_HW_FEATURE_WDI, 10), + IPA_HW_2_CPU_MAX_WDI_RX_CHANNELS = + FEATURE_ENUM_VAL(IPA_HW_FEATURE_WDI, 11), + IPA_HW_2_CPU_WDI_RX_RING_PARAMS_UNALIGNED = + FEATURE_ENUM_VAL(IPA_HW_FEATURE_WDI, 12), + IPA_HW_2_CPU_WDI_RX_RING_SET_UP_FAILURE = + FEATURE_ENUM_VAL(IPA_HW_FEATURE_WDI, 13), + IPA_HW_2_CPU_WDI_UNKNOWN_RX_CHANNEL = + FEATURE_ENUM_VAL(IPA_HW_FEATURE_WDI, 14), + IPA_HW_2_CPU_WDI_RX_INVALID_FSM_TRANSITION = + FEATURE_ENUM_VAL(IPA_HW_FEATURE_WDI, 15), + IPA_HW_2_CPU_WDI_RX_FSM_TRANSITION_ERROR = + FEATURE_ENUM_VAL(IPA_HW_FEATURE_WDI, 16), +}; + +/** * struct IpaHwSetUpCmd - * * diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_uc_wdi.c b/drivers/platform/msm/ipa/ipa_v2/ipa_uc_wdi.c index f60669132865..56b4bf1a2d1e 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_uc_wdi.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_uc_wdi.c @@ -110,47 +110,6 @@ enum ipa_cpu_2_hw_wdi_commands { }; /** - * enum ipa_hw_2_cpu_cmd_resp_status - Values that represent WDI related - * command response status to be sent to CPU. - */ -enum ipa_hw_2_cpu_cmd_resp_status { - IPA_HW_2_CPU_WDI_CMD_STATUS_SUCCESS = - FEATURE_ENUM_VAL(IPA_HW_FEATURE_WDI, 0), - IPA_HW_2_CPU_MAX_WDI_TX_CHANNELS = - FEATURE_ENUM_VAL(IPA_HW_FEATURE_WDI, 1), - IPA_HW_2_CPU_WDI_CE_RING_OVERRUN_POSSIBILITY = - FEATURE_ENUM_VAL(IPA_HW_FEATURE_WDI, 2), - IPA_HW_2_CPU_WDI_CE_RING_SET_UP_FAILURE = - FEATURE_ENUM_VAL(IPA_HW_FEATURE_WDI, 3), - IPA_HW_2_CPU_WDI_CE_RING_PARAMS_UNALIGNED = - FEATURE_ENUM_VAL(IPA_HW_FEATURE_WDI, 4), - IPA_HW_2_CPU_WDI_COMP_RING_OVERRUN_POSSIBILITY = - FEATURE_ENUM_VAL(IPA_HW_FEATURE_WDI, 5), - IPA_HW_2_CPU_WDI_COMP_RING_SET_UP_FAILURE = - FEATURE_ENUM_VAL(IPA_HW_FEATURE_WDI, 6), - IPA_HW_2_CPU_WDI_COMP_RING_PARAMS_UNALIGNED = - FEATURE_ENUM_VAL(IPA_HW_FEATURE_WDI, 7), - IPA_HW_2_CPU_WDI_UNKNOWN_TX_CHANNEL = - FEATURE_ENUM_VAL(IPA_HW_FEATURE_WDI, 8), - IPA_HW_2_CPU_WDI_TX_INVALID_FSM_TRANSITION = - FEATURE_ENUM_VAL(IPA_HW_FEATURE_WDI, 9), - IPA_HW_2_CPU_WDI_TX_FSM_TRANSITION_ERROR = - FEATURE_ENUM_VAL(IPA_HW_FEATURE_WDI, 10), - IPA_HW_2_CPU_MAX_WDI_RX_CHANNELS = - FEATURE_ENUM_VAL(IPA_HW_FEATURE_WDI, 11), - IPA_HW_2_CPU_WDI_RX_RING_PARAMS_UNALIGNED = - FEATURE_ENUM_VAL(IPA_HW_FEATURE_WDI, 12), - IPA_HW_2_CPU_WDI_RX_RING_SET_UP_FAILURE = - FEATURE_ENUM_VAL(IPA_HW_FEATURE_WDI, 13), - IPA_HW_2_CPU_WDI_UNKNOWN_RX_CHANNEL = - FEATURE_ENUM_VAL(IPA_HW_FEATURE_WDI, 14), - IPA_HW_2_CPU_WDI_RX_INVALID_FSM_TRANSITION = - FEATURE_ENUM_VAL(IPA_HW_FEATURE_WDI, 15), - IPA_HW_2_CPU_WDI_RX_FSM_TRANSITION_ERROR = - FEATURE_ENUM_VAL(IPA_HW_FEATURE_WDI, 16), -}; - -/** * enum ipa_hw_wdi_errors - WDI specific error types. * @IPA_HW_WDI_ERROR_NONE : No error persists * @IPA_HW_WDI_CHANNEL_ERROR : Error is specific to channel diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c index d53121292c03..be3c890db25c 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c @@ -946,7 +946,7 @@ int ipa2_get_ep_mapping(enum ipa_client_type client) void ipa2_set_client(int index, enum ipacm_client_enum client, bool uplink) { - if (client >= IPACM_CLIENT_MAX || client < IPACM_CLIENT_USB) { + if (client > IPACM_CLIENT_MAX || client < IPACM_CLIENT_USB) { IPAERR("Bad client number! client =%d\n", client); } else if (index >= IPA_MAX_NUM_PIPES || index < 0) { IPAERR("Bad pipe index! index =%d\n", index); diff --git a/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c index 774077494ea5..da014427852b 100644 --- a/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c +++ b/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c @@ -2334,6 +2334,29 @@ static struct platform_driver rmnet_ipa_driver = { .remove = ipa_wwan_remove, }; +/** + * rmnet_ipa_send_ssr_notification(bool ssr_done) - send SSR notification + * + * This function sends the SSR notification before modem shutdown and + * after_powerup from SSR framework, to user-space module + */ +static void rmnet_ipa_send_ssr_notification(bool ssr_done) +{ + struct ipa_msg_meta msg_meta; + int rc; + + memset(&msg_meta, 0, sizeof(struct ipa_msg_meta)); + if (ssr_done) + msg_meta.msg_type = IPA_SSR_AFTER_POWERUP; + else + msg_meta.msg_type = IPA_SSR_BEFORE_SHUTDOWN; + rc = ipa_send_msg(&msg_meta, NULL, NULL); + if (rc) { + IPAWANERR("ipa_send_msg failed: %d\n", rc); + return; + } +} + static int ssr_notifier_cb(struct notifier_block *this, unsigned long code, void *data) @@ -2341,6 +2364,8 @@ static int ssr_notifier_cb(struct notifier_block *this, if (ipa_rmnet_ctx.ipa_rmnet_ssr) { if (SUBSYS_BEFORE_SHUTDOWN == code) { pr_info("IPA received MPSS BEFORE_SHUTDOWN\n"); + /* send SSR before-shutdown notification to IPACM */ + rmnet_ipa_send_ssr_notification(false); atomic_set(&is_ssr, 1); ipa_q6_pre_shutdown_cleanup(); if (ipa_netdevs[0]) @@ -2517,6 +2542,26 @@ static void rmnet_ipa_get_network_stats_and_update(void) } /** + * rmnet_ipa_send_quota_reach_ind() - send quota_reach notification from + * IPA Modem + * This function sends the quota_reach indication from the IPA Modem driver + * via QMI, to user-space module + */ +static void rmnet_ipa_send_quota_reach_ind(void) +{ + struct ipa_msg_meta msg_meta; + int rc; + + memset(&msg_meta, 0, sizeof(struct ipa_msg_meta)); + msg_meta.msg_type = IPA_QUOTA_REACH; + rc = ipa_send_msg(&msg_meta, NULL, NULL); + if (rc) { + IPAWANERR("ipa_send_msg failed: %d\n", rc); + return; + } +} + +/** * rmnet_ipa_poll_tethering_stats() - Tethering stats polling IOCTL handler * @data - IOCTL data * @@ -2796,7 +2841,7 @@ int rmnet_ipa_query_tethering_stats_modem( IPAWANERR("reset the pipe stats\n"); } else { /* print tethered-client enum */ - IPAWANDBG_LOW("Tethered-client enum(%d)\n", data->ipa_client); + IPAWANDBG("Tethered-client enum(%d)\n", data->ipa_client); } rc = ipa_qmi_get_data_stats(req, resp); @@ -2805,10 +2850,6 @@ int rmnet_ipa_query_tethering_stats_modem( kfree(req); kfree(resp); return rc; - } else if (reset) { - kfree(req); - kfree(resp); - return 0; } if (resp->dl_dst_pipe_stats_list_valid) { @@ -2854,7 +2895,7 @@ int rmnet_ipa_query_tethering_stats_modem( } } } - IPAWANDBG_LOW("v4_rx_p(%lu) v6_rx_p(%lu) v4_rx_b(%lu) v6_rx_b(%lu)\n", + IPAWANDBG("v4_rx_p(%lu) v6_rx_p(%lu) v4_rx_b(%lu) v6_rx_b(%lu)\n", (unsigned long int) data->ipv4_rx_packets, (unsigned long int) data->ipv6_rx_packets, (unsigned long int) data->ipv4_rx_bytes, @@ -2904,7 +2945,7 @@ int rmnet_ipa_query_tethering_stats_modem( } } } - IPAWANDBG_LOW("tx_p_v4(%lu)v6(%lu)tx_b_v4(%lu) v6(%lu)\n", + IPAWANDBG("tx_p_v4(%lu)v6(%lu)tx_b_v4(%lu) v6(%lu)\n", (unsigned long int) data->ipv4_tx_packets, (unsigned long int) data->ipv6_tx_packets, (unsigned long int) data->ipv4_tx_bytes, @@ -2946,6 +2987,49 @@ int rmnet_ipa_query_tethering_stats(struct wan_ioctl_query_tether_stats *data, return rc; } +int rmnet_ipa_query_tethering_stats_all( + struct wan_ioctl_query_tether_stats_all *data) +{ + struct wan_ioctl_query_tether_stats tether_stats; + enum ipa_upstream_type upstream_type; + int rc = 0; + + memset(&tether_stats, 0, sizeof(struct wan_ioctl_query_tether_stats)); + /* get IPA backhaul type */ + upstream_type = find_upstream_type(data->upstreamIface); + + if (upstream_type == IPA_UPSTEAM_MAX) { + IPAWANERR(" Wrong upstreamIface name %s\n", + data->upstreamIface); + } else if (upstream_type == IPA_UPSTEAM_WLAN) { + IPAWANDBG_LOW(" query wifi-backhaul stats\n"); + rc = rmnet_ipa_query_tethering_stats_wifi( + &tether_stats, data->reset_stats); + if (rc) { + IPAWANERR("wlan WAN_IOC_QUERY_TETHER_STATS failed\n"); + return rc; + } + data->tx_bytes = tether_stats.ipv4_tx_bytes + + tether_stats.ipv6_tx_bytes; + data->rx_bytes = tether_stats.ipv4_rx_bytes + + tether_stats.ipv6_rx_bytes; + } else { + IPAWANDBG_LOW(" query modem-backhaul stats\n"); + tether_stats.ipa_client = data->ipa_client; + rc = rmnet_ipa_query_tethering_stats_modem( + &tether_stats, data->reset_stats); + if (rc) { + IPAWANERR("modem WAN_IOC_QUERY_TETHER_STATS failed\n"); + return rc; + } + data->tx_bytes = tether_stats.ipv4_tx_bytes + + tether_stats.ipv6_tx_bytes; + data->rx_bytes = tether_stats.ipv4_rx_bytes + + tether_stats.ipv6_rx_bytes; + } + return rc; +} + int rmnet_ipa_reset_tethering_stats(struct wan_ioctl_reset_tether_stats *data) { enum ipa_upstream_type upstream_type; @@ -3047,6 +3131,8 @@ void ipa_broadcast_quota_reach_ind(u32 mux_id, IPAWANERR("putting nlmsg: <%s> <%s> <%s>\n", alert_msg, iface_name_l, iface_name_m); kobject_uevent_env(&(ipa_netdevs[0]->dev.kobj), KOBJ_CHANGE, envp); + + rmnet_ipa_send_quota_reach_ind(); } /** @@ -3071,6 +3157,9 @@ void ipa_q6_handshake_complete(bool ssr_bootup) */ ipa2_proxy_clk_unvote(); + /* send SSR power-up notification to IPACM */ + rmnet_ipa_send_ssr_notification(true); + /* * It is required to recover the network stats after * SSR recovery diff --git a/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa_fd_ioctl.c b/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa_fd_ioctl.c index 46bfe021eb4b..02bdd0334e7f 100644 --- a/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa_fd_ioctl.c +++ b/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa_fd_ioctl.c @@ -47,6 +47,10 @@ #define WAN_IOC_QUERY_DL_FILTER_STATS32 _IOWR(WAN_IOC_MAGIC, \ WAN_IOCTL_QUERY_DL_FILTER_STATS, \ compat_uptr_t) +#define WAN_IOC_QUERY_TETHER_STATS_ALL32 _IOWR(WAN_IOC_MAGIC, \ + WAN_IOCTL_QUERY_TETHER_STATS_ALL, \ + compat_uptr_t) + #endif static unsigned int dev_num = 1; @@ -238,6 +242,32 @@ static long wan_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) } break; + case WAN_IOC_QUERY_TETHER_STATS_ALL: + IPAWANDBG_LOW("got WAN_IOC_QUERY_TETHER_STATS_ALL :>>>\n"); + pyld_sz = sizeof(struct wan_ioctl_query_tether_stats_all); + param = kzalloc(pyld_sz, GFP_KERNEL); + if (!param) { + retval = -ENOMEM; + break; + } + if (copy_from_user(param, (u8 *)arg, pyld_sz)) { + retval = -EFAULT; + break; + } + + if (rmnet_ipa_query_tethering_stats_all( + (struct wan_ioctl_query_tether_stats_all *)param)) { + IPAWANERR("WAN_IOC_QUERY_TETHER_STATS failed\n"); + retval = -EFAULT; + break; + } + + if (copy_to_user((u8 *)arg, param, pyld_sz)) { + retval = -EFAULT; + break; + } + break; + case WAN_IOC_RESET_TETHER_STATS: IPAWANDBG_LOW("got WAN_IOC_RESET_TETHER_STATS :>>>\n"); pyld_sz = sizeof(struct wan_ioctl_reset_tether_stats); diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_client.c b/drivers/platform/msm/ipa/ipa_v3/ipa_client.c index 81eae05d7ed9..e349ade46075 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_client.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_client.c @@ -857,6 +857,8 @@ static int ipa3_reset_with_open_aggr_frame_wa(u32 clnt_hdl, struct gsi_xfer_elem xfer_elem; int i; int aggr_active_bitmap = 0; + bool pipe_suspended = false; + struct ipa_ep_cfg_ctrl ctrl; IPADBG("Applying reset channel with open aggregation frame WA\n"); ipahal_write_reg(IPA_AGGR_FORCE_CLOSE, (1 << clnt_hdl)); @@ -883,6 +885,15 @@ static int ipa3_reset_with_open_aggr_frame_wa(u32 clnt_hdl, if (result) return -EFAULT; + ipahal_read_reg_n_fields(IPA_ENDP_INIT_CTRL_n, clnt_hdl, &ctrl); + if (ctrl.ipa_ep_suspend) { + IPADBG("pipe is suspended, remove suspend\n"); + pipe_suspended = true; + ctrl.ipa_ep_suspend = false; + ipahal_write_reg_n_fields(IPA_ENDP_INIT_CTRL_n, + clnt_hdl, &ctrl); + } + /* Start channel and put 1 Byte descriptor on it */ gsi_res = gsi_start_channel(ep->gsi_chan_hdl); if (gsi_res != GSI_STATUS_SUCCESS) { @@ -942,6 +953,13 @@ static int ipa3_reset_with_open_aggr_frame_wa(u32 clnt_hdl, */ msleep(IPA_POLL_AGGR_STATE_SLEEP_MSEC); + if (pipe_suspended) { + IPADBG("suspend the pipe again\n"); + ctrl.ipa_ep_suspend = true; + ipahal_write_reg_n_fields(IPA_ENDP_INIT_CTRL_n, + clnt_hdl, &ctrl); + } + /* Restore channels properties */ result = ipa3_restore_channel_properties(ep, &orig_chan_props, &orig_chan_scratch); @@ -956,6 +974,12 @@ queue_xfer_fail: ipa3_stop_gsi_channel(clnt_hdl); dma_free_coherent(ipa3_ctx->pdev, 1, buff, dma_addr); start_chan_fail: + if (pipe_suspended) { + IPADBG("suspend the pipe again\n"); + ctrl.ipa_ep_suspend = true; + ipahal_write_reg_n_fields(IPA_ENDP_INIT_CTRL_n, + clnt_hdl, &ctrl); + } ipa3_restore_channel_properties(ep, &orig_chan_props, &orig_chan_scratch); restore_props_fail: diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c index 72eb3808c7a4..fbf84ab7d2d4 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c @@ -61,6 +61,9 @@ const char *ipa3_event_name[] = { __stringify(ECM_DISCONNECT), __stringify(IPA_TETHERING_STATS_UPDATE_STATS), __stringify(IPA_TETHERING_STATS_UPDATE_NETWORK_STATS), + __stringify(IPA_QUOTA_REACH), + __stringify(IPA_SSR_BEFORE_SHUTDOWN), + __stringify(IPA_SSR_AFTER_POWERUP), }; const char *ipa3_hdr_l2_type_name[] = { diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c index f23062702f28..0492fa27c5b7 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c @@ -1568,7 +1568,7 @@ int ipa3_teardown_sys_pipe(u32 clnt_hdl) BUG(); return result; } - result = gsi_reset_channel(ep->gsi_chan_hdl); + result = ipa3_reset_gsi_channel(clnt_hdl); if (result != GSI_STATUS_SUCCESS) { IPAERR("Failed to reset chan: %d.\n", result); BUG(); diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.h b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.h index 6cd82f84bf13..d5d850309696 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.h @@ -190,6 +190,9 @@ int rmnet_ipa3_set_tether_client_pipe(struct wan_ioctl_set_tether_client_pipe int rmnet_ipa3_query_tethering_stats(struct wan_ioctl_query_tether_stats *data, bool reset); +int rmnet_ipa3_query_tethering_stats_all( + struct wan_ioctl_query_tether_stats_all *data); + int rmnet_ipa3_reset_tethering_stats(struct wan_ioctl_reset_tether_stats *data); int ipa3_qmi_get_data_stats(struct ipa_get_data_stats_req_msg_v01 *req, diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c index 57fa2465c9ea..e49bdc8c7083 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c @@ -1205,6 +1205,8 @@ int ipa3_connect_wdi_pipe(struct ipa_wdi_in_params *in, IPADBG("Skipping endpoint configuration.\n"); } + ipa3_enable_data_path(ipa_ep_idx); + out->clnt_hdl = ipa_ep_idx; if (!ep->skip_ep_cfg && IPA_CLIENT_IS_PROD(in->sys.client)) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c index 5ffc1f23f47c..d19de2a7bdb5 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c @@ -1002,7 +1002,7 @@ u8 ipa3_get_qmb_master_sel(enum ipa_client_type client) void ipa3_set_client(int index, enum ipacm_client_enum client, bool uplink) { - if (client >= IPACM_CLIENT_MAX || client < IPACM_CLIENT_USB) { + if (client > IPACM_CLIENT_MAX || client < IPACM_CLIENT_USB) { IPAERR("Bad client number! client =%d\n", client); } else if (index >= IPA3_MAX_NUM_PIPES || index < 0) { IPAERR("Bad pipe index! index =%d\n", index); diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c index 3855e0d46ca9..585f9e6bd492 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c @@ -646,6 +646,21 @@ static void ipareg_construct_endp_init_ctrl_n(enum ipahal_reg_name reg, IPA_ENDP_INIT_CTRL_n_ENDP_DELAY_BMSK); } +static void ipareg_parse_endp_init_ctrl_n(enum ipahal_reg_name reg, + void *fields, u32 val) +{ + struct ipa_ep_cfg_ctrl *ep_ctrl = + (struct ipa_ep_cfg_ctrl *)fields; + + ep_ctrl->ipa_ep_suspend = + ((val & IPA_ENDP_INIT_CTRL_n_ENDP_SUSPEND_BMSK) >> + IPA_ENDP_INIT_CTRL_n_ENDP_SUSPEND_SHFT); + + ep_ctrl->ipa_ep_delay = + ((val & IPA_ENDP_INIT_CTRL_n_ENDP_DELAY_BMSK) >> + IPA_ENDP_INIT_CTRL_n_ENDP_DELAY_SHFT); +} + static void ipareg_construct_endp_init_ctrl_scnd_n(enum ipahal_reg_name reg, const void *fields, u32 *val) { @@ -1018,7 +1033,8 @@ static struct ipahal_reg_obj ipahal_reg_objs[IPA_HW_MAX][IPA_REG_MAX] = { ipareg_construct_endp_init_nat_n, ipareg_parse_dummy, 0x0000080C, 0x70}, [IPA_HW_v3_0][IPA_ENDP_INIT_CTRL_n] = { - ipareg_construct_endp_init_ctrl_n, ipareg_parse_dummy, + ipareg_construct_endp_init_ctrl_n, + ipareg_parse_endp_init_ctrl_n, 0x00000800, 0x70}, [IPA_HW_v3_0][IPA_ENDP_INIT_CTRL_SCND_n] = { ipareg_construct_endp_init_ctrl_scnd_n, ipareg_parse_dummy, diff --git a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c index 04e5862cd960..1bd4f7fda1b7 100644 --- a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c @@ -2455,6 +2455,29 @@ static struct platform_driver rmnet_ipa_driver = { .remove = ipa3_wwan_remove, }; +/** + * rmnet_ipa_send_ssr_notification(bool ssr_done) - send SSR notification + * + * This function sends the SSR notification before modem shutdown and + * after_powerup from SSR framework, to user-space module + */ +static void rmnet_ipa_send_ssr_notification(bool ssr_done) +{ + struct ipa_msg_meta msg_meta; + int rc; + + memset(&msg_meta, 0, sizeof(struct ipa_msg_meta)); + if (ssr_done) + msg_meta.msg_type = IPA_SSR_AFTER_POWERUP; + else + msg_meta.msg_type = IPA_SSR_BEFORE_SHUTDOWN; + rc = ipa_send_msg(&msg_meta, NULL, NULL); + if (rc) { + IPAWANERR("ipa_send_msg failed: %d\n", rc); + return; + } +} + static int ipa3_ssr_notifier_cb(struct notifier_block *this, unsigned long code, void *data) @@ -2465,6 +2488,8 @@ static int ipa3_ssr_notifier_cb(struct notifier_block *this, switch (code) { case SUBSYS_BEFORE_SHUTDOWN: IPAWANINFO("IPA received MPSS BEFORE_SHUTDOWN\n"); + /* send SSR before-shutdown notification to IPACM */ + rmnet_ipa_send_ssr_notification(false); atomic_set(&rmnet_ipa3_ctx->is_ssr, 1); ipa3_q6_pre_shutdown_cleanup(); if (IPA_NETDEV()) @@ -2641,6 +2666,26 @@ static void rmnet_ipa_get_network_stats_and_update(void) } /** + * rmnet_ipa_send_quota_reach_ind() - send quota_reach notification from + * IPA Modem + * This function sends the quota_reach indication from the IPA Modem driver + * via QMI, to user-space module + */ +static void rmnet_ipa_send_quota_reach_ind(void) +{ + struct ipa_msg_meta msg_meta; + int rc; + + memset(&msg_meta, 0, sizeof(struct ipa_msg_meta)); + msg_meta.msg_type = IPA_QUOTA_REACH; + rc = ipa_send_msg(&msg_meta, NULL, NULL); + if (rc) { + IPAWANERR("ipa_send_msg failed: %d\n", rc); + return; + } +} + +/** * rmnet_ipa3_poll_tethering_stats() - Tethering stats polling IOCTL handler * @data - IOCTL data * @@ -2921,7 +2966,7 @@ static int rmnet_ipa3_query_tethering_stats_modem( IPAWANERR("reset the pipe stats\n"); } else { /* print tethered-client enum */ - IPAWANDBG_LOW("Tethered-client enum(%d)\n", data->ipa_client); + IPAWANDBG("Tethered-client enum(%d)\n", data->ipa_client); } rc = ipa3_qmi_get_data_stats(req, resp); @@ -2930,10 +2975,6 @@ static int rmnet_ipa3_query_tethering_stats_modem( kfree(req); kfree(resp); return rc; - } else if (reset) { - kfree(req); - kfree(resp); - return 0; } if (resp->dl_dst_pipe_stats_list_valid) { @@ -3071,6 +3112,49 @@ int rmnet_ipa3_query_tethering_stats(struct wan_ioctl_query_tether_stats *data, return rc; } +int rmnet_ipa3_query_tethering_stats_all( + struct wan_ioctl_query_tether_stats_all *data) +{ + struct wan_ioctl_query_tether_stats tether_stats; + enum ipa_upstream_type upstream_type; + int rc = 0; + + memset(&tether_stats, 0, sizeof(struct wan_ioctl_query_tether_stats)); + /* get IPA backhaul type */ + upstream_type = find_upstream_type(data->upstreamIface); + + if (upstream_type == IPA_UPSTEAM_MAX) { + IPAWANERR(" Wrong upstreamIface name %s\n", + data->upstreamIface); + } else if (upstream_type == IPA_UPSTEAM_WLAN) { + IPAWANDBG_LOW(" query wifi-backhaul stats\n"); + rc = rmnet_ipa3_query_tethering_stats_wifi( + &tether_stats, data->reset_stats); + if (rc) { + IPAWANERR("wlan WAN_IOC_QUERY_TETHER_STATS failed\n"); + return rc; + } + data->tx_bytes = tether_stats.ipv4_tx_bytes + + tether_stats.ipv6_tx_bytes; + data->rx_bytes = tether_stats.ipv4_rx_bytes + + tether_stats.ipv6_rx_bytes; + } else { + IPAWANDBG_LOW(" query modem-backhaul stats\n"); + tether_stats.ipa_client = data->ipa_client; + rc = rmnet_ipa3_query_tethering_stats_modem( + &tether_stats, data->reset_stats); + if (rc) { + IPAWANERR("modem WAN_IOC_QUERY_TETHER_STATS failed\n"); + return rc; + } + data->tx_bytes = tether_stats.ipv4_tx_bytes + + tether_stats.ipv6_tx_bytes; + data->rx_bytes = tether_stats.ipv4_rx_bytes + + tether_stats.ipv6_rx_bytes; + } + return rc; +} + int rmnet_ipa3_reset_tethering_stats(struct wan_ioctl_reset_tether_stats *data) { enum ipa_upstream_type upstream_type; @@ -3168,6 +3252,8 @@ void ipa3_broadcast_quota_reach_ind(u32 mux_id, alert_msg, iface_name_l, iface_name_m); kobject_uevent_env(&(IPA_NETDEV()->dev.kobj), KOBJ_CHANGE, envp); + + rmnet_ipa_send_quota_reach_ind(); } /** @@ -3192,6 +3278,9 @@ void ipa3_q6_handshake_complete(bool ssr_bootup) */ ipa3_proxy_clk_unvote(); + /* send SSR power-up notification to IPACM */ + rmnet_ipa_send_ssr_notification(true); + /* * It is required to recover the network stats after * SSR recovery diff --git a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa_fd_ioctl.c b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa_fd_ioctl.c index ffd127a21ed1..51bbec464e4d 100644 --- a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa_fd_ioctl.c +++ b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa_fd_ioctl.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -47,6 +47,9 @@ #define WAN_IOC_QUERY_DL_FILTER_STATS32 _IOWR(WAN_IOC_MAGIC, \ WAN_IOCTL_QUERY_DL_FILTER_STATS, \ compat_uptr_t) +#define WAN_IOC_QUERY_TETHER_STATS_ALL32 _IOWR(WAN_IOC_MAGIC, \ + WAN_IOCTL_QUERY_TETHER_STATS_ALL, \ + compat_uptr_t) #endif static unsigned int dev_num = 1; @@ -265,6 +268,32 @@ static long ipa3_wan_ioctl(struct file *filp, } break; + case WAN_IOC_QUERY_TETHER_STATS_ALL: + IPAWANDBG_LOW("got WAN_IOC_QUERY_TETHER_STATS_ALL :>>>\n"); + pyld_sz = sizeof(struct wan_ioctl_query_tether_stats_all); + param = kzalloc(pyld_sz, GFP_KERNEL); + if (!param) { + retval = -ENOMEM; + break; + } + if (copy_from_user(param, (u8 *)arg, pyld_sz)) { + retval = -EFAULT; + break; + } + + if (rmnet_ipa3_query_tethering_stats_all( + (struct wan_ioctl_query_tether_stats_all *)param)) { + IPAWANERR("WAN_IOC_QUERY_TETHER_STATS failed\n"); + retval = -EFAULT; + break; + } + + if (copy_to_user((u8 *)arg, param, pyld_sz)) { + retval = -EFAULT; + break; + } + break; + case WAN_IOC_RESET_TETHER_STATS: IPAWANDBG_LOW("device %s got WAN_IOC_RESET_TETHER_STATS :>>>\n", DRIVER_NAME); diff --git a/drivers/platform/msm/msm_11ad/msm_11ad.c b/drivers/platform/msm/msm_11ad/msm_11ad.c index f1e348969c7b..4d4aad84b9d7 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: @@ -1237,6 +1336,17 @@ static void msm_11ad_set_boost_affinity(struct msm11ad_ctx *ctx) dev_warn(ctx->dev, "failed to set CPU boost affinity\n"); } +static void msm_11ad_clear_boost_affinity(struct msm11ad_ctx *ctx) +{ + int rc; + + irq_modify_status(ctx->pcidev->irq, IRQ_NO_BALANCING, 0); + rc = irq_set_affinity_hint(ctx->pcidev->irq, NULL); + if (rc) + dev_warn(ctx->dev, + "Failed clear affinity, rc=%d\n", rc); +} + /* hooks for the wil6210 driver */ static int ops_bus_request(void *handle, u32 kbps /* KBytes/Sec */) { @@ -1286,8 +1396,7 @@ static int ops_bus_request(void *handle, u32 kbps /* KBytes/Sec */) dev_err(ctx->dev, "Failed disable boost rc=%d\n", rc); - irq_modify_status(ctx->pcidev->irq, - IRQ_NO_BALANCING, 0); + msm_11ad_clear_boost_affinity(ctx); dev_dbg(ctx->dev, "CPU boost disabled\n"); } ctx->is_cpu_boosted = needs_boost; @@ -1315,7 +1424,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 +1482,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 +1531,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 +1548,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/platform/msm/msm_ext_display.c b/drivers/platform/msm/msm_ext_display.c index 6f9a13040cd5..c7c1b1567bf3 100644 --- a/drivers/platform/msm/msm_ext_display.c +++ b/drivers/platform/msm/msm_ext_display.c @@ -654,6 +654,7 @@ int msm_ext_disp_register_audio_codec(struct platform_device *pdev, { int ret = 0; struct msm_ext_disp *ext_disp = NULL; + struct msm_ext_disp_list *node = NULL; if (!pdev || !ops) { pr_err("Invalid params\n"); @@ -671,17 +672,23 @@ int msm_ext_disp_register_audio_codec(struct platform_device *pdev, if ((ext_disp->current_disp != EXT_DISPLAY_TYPE_MAX) && ext_disp->ops) { pr_err("Codec already registered\n"); - ret = -EINVAL; - goto end; + mutex_unlock(&ext_disp->lock); + return -EINVAL; } ext_disp->ops = ops; - pr_debug("audio codec registered\n"); - -end: mutex_unlock(&ext_disp->lock); + list_for_each_entry(node, &ext_disp->display_list, list) { + struct msm_ext_disp_init_data *data = node->data; + + if (data->codec_ops.codec_ready) + data->codec_ops.codec_ready(data->pdev); + } + + pr_debug("audio codec registered\n"); + return ret; } diff --git a/drivers/platform/msm/seemp_core/seemp_logk.c b/drivers/platform/msm/seemp_core/seemp_logk.c index d0f21943cb0f..264db54f0d6e 100644 --- a/drivers/platform/msm/seemp_core/seemp_logk.c +++ b/drivers/platform/msm/seemp_core/seemp_logk.c @@ -287,7 +287,7 @@ static bool seemp_logk_get_bit_from_vector(__u8 *pVec, __u32 index) unsigned int bit_num = index%8; unsigned char byte; - if (DIV_ROUND_UP(index, 8) > MASK_BUFFER_SIZE) + if (byte_num >= MASK_BUFFER_SIZE) return false; byte = pVec[byte_num]; diff --git a/drivers/power/supply/qcom/qpnp-fg-gen3.c b/drivers/power/supply/qcom/qpnp-fg-gen3.c index 4368709118ac..d0f7a5e1e227 100644 --- a/drivers/power/supply/qcom/qpnp-fg-gen3.c +++ b/drivers/power/supply/qcom/qpnp-fg-gen3.c @@ -3366,6 +3366,16 @@ static int fg_hw_init(struct fg_chip *chip) return rc; } + if (is_debug_batt_id(chip)) { + val = ESR_NO_PULL_DOWN; + rc = fg_masked_write(chip, BATT_INFO_ESR_PULL_DN_CFG(chip), + ESR_PULL_DOWN_MODE_MASK, val); + if (rc < 0) { + pr_err("Error in writing esr_pull_down, rc=%d\n", rc); + return rc; + } + } + return 0; } diff --git a/drivers/power/supply/qcom/qpnp-smb2.c b/drivers/power/supply/qcom/qpnp-smb2.c index 94b9e9c4d912..b2597987292b 100644 --- a/drivers/power/supply/qcom/qpnp-smb2.c +++ b/drivers/power/supply/qcom/qpnp-smb2.c @@ -266,8 +266,9 @@ module_param_named( debug_mask, __debug_mask, int, S_IRUSR | S_IWUSR ); -#define MICRO_1P5A 1500000 -#define MICRO_P1A 100000 +#define MICRO_1P5A 1500000 +#define MICRO_P1A 100000 +#define OTG_DEFAULT_DEGLITCH_TIME_MS 50 static int smb2_parse_dt(struct smb2 *chip) { struct smb_charger *chg = &chip->chg; @@ -400,6 +401,12 @@ static int smb2_parse_dt(struct smb2 *chip) chg->suspend_input_on_debug_batt = of_property_read_bool(node, "qcom,suspend-input-on-debug-batt"); + + rc = of_property_read_u32(node, "qcom,otg-deglitch-time-ms", + &chg->otg_delay_ms); + if (rc < 0) + chg->otg_delay_ms = OTG_DEFAULT_DEGLITCH_TIME_MS; + return 0; } diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c index a191391a3904..cc50e0f478d1 100644 --- a/drivers/power/supply/qcom/smb-lib.c +++ b/drivers/power/supply/qcom/smb-lib.c @@ -3750,26 +3750,6 @@ static void smblib_handle_typec_debounce_done(struct smb_charger *chg, smblib_typec_mode_name[pval.intval]); } -irqreturn_t smblib_handle_usb_typec_change_for_uusb(struct smb_charger *chg) -{ - int rc; - u8 stat; - - rc = smblib_read(chg, TYPE_C_STATUS_3_REG, &stat); - if (rc < 0) { - smblib_err(chg, "Couldn't read TYPE_C_STATUS_3 rc=%d\n", rc); - return IRQ_HANDLED; - } - smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_3 = 0x%02x OTG=%d\n", - stat, !!(stat & (U_USB_GND_NOVBUS_BIT | U_USB_GND_BIT))); - - extcon_set_cable_state_(chg->extcon, EXTCON_USB_HOST, - !!(stat & (U_USB_GND_NOVBUS_BIT | U_USB_GND_BIT))); - power_supply_changed(chg->usb_psy); - - return IRQ_HANDLED; -} - static void smblib_usb_typec_change(struct smb_charger *chg) { int rc; @@ -3804,7 +3784,11 @@ irqreturn_t smblib_handle_usb_typec_change(int irq, void *data) struct smb_charger *chg = irq_data->parent_data; if (chg->micro_usb_mode) { - smblib_handle_usb_typec_change_for_uusb(chg); + cancel_delayed_work_sync(&chg->uusb_otg_work); + vote(chg->awake_votable, OTG_DELAY_VOTER, true, 0); + smblib_dbg(chg, PR_INTERRUPT, "Scheduling OTG work\n"); + schedule_delayed_work(&chg->uusb_otg_work, + msecs_to_jiffies(chg->otg_delay_ms)); return IRQ_HANDLED; } @@ -3889,6 +3873,30 @@ irqreturn_t smblib_handle_wdog_bark(int irq, void *data) /*************** * Work Queues * ***************/ +static void smblib_uusb_otg_work(struct work_struct *work) +{ + struct smb_charger *chg = container_of(work, struct smb_charger, + uusb_otg_work.work); + int rc; + u8 stat; + bool otg; + + rc = smblib_read(chg, TYPE_C_STATUS_3_REG, &stat); + if (rc < 0) { + smblib_err(chg, "Couldn't read TYPE_C_STATUS_3 rc=%d\n", rc); + goto out; + } + + otg = !!(stat & (U_USB_GND_NOVBUS_BIT | U_USB_GND_BIT)); + extcon_set_cable_state_(chg->extcon, EXTCON_USB_HOST, otg); + smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_3 = 0x%02x OTG=%d\n", + stat, otg); + power_supply_changed(chg->usb_psy); + +out: + vote(chg->awake_votable, OTG_DELAY_VOTER, false, 0); +} + static void smblib_hvdcp_detect_work(struct work_struct *work) { @@ -4482,6 +4490,7 @@ int smblib_init(struct smb_charger *chg) INIT_DELAYED_WORK(&chg->icl_change_work, smblib_icl_change_work); INIT_DELAYED_WORK(&chg->pl_enable_work, smblib_pl_enable_work); INIT_WORK(&chg->legacy_detection_work, smblib_legacy_detection_work); + INIT_DELAYED_WORK(&chg->uusb_otg_work, smblib_uusb_otg_work); chg->fake_capacity = -EINVAL; chg->fake_input_current_limited = -EINVAL; @@ -4536,6 +4545,7 @@ int smblib_deinit(struct smb_charger *chg) cancel_delayed_work_sync(&chg->icl_change_work); cancel_delayed_work_sync(&chg->pl_enable_work); cancel_work_sync(&chg->legacy_detection_work); + cancel_delayed_work_sync(&chg->uusb_otg_work); power_supply_unreg_notifier(&chg->nb); smblib_destroy_votables(chg); qcom_batt_deinit(); diff --git a/drivers/power/supply/qcom/smb-lib.h b/drivers/power/supply/qcom/smb-lib.h index 5dc60ecb9436..3fedff8897ee 100644 --- a/drivers/power/supply/qcom/smb-lib.h +++ b/drivers/power/supply/qcom/smb-lib.h @@ -64,6 +64,7 @@ enum print_reason { #define CC2_WA_VOTER "CC2_WA_VOTER" #define QNOVO_VOTER "QNOVO_VOTER" #define BATT_PROFILE_VOTER "BATT_PROFILE_VOTER" +#define OTG_DELAY_VOTER "OTG_DELAY_VOTER" #define VCONN_MAX_ATTEMPTS 3 #define OTG_MAX_ATTEMPTS 3 @@ -230,6 +231,7 @@ struct smb_charger { bool external_vconn; struct smb_chg_freq chg_freq; int smb_version; + int otg_delay_ms; /* locks */ struct mutex lock; @@ -290,6 +292,7 @@ struct smb_charger { struct delayed_work icl_change_work; struct delayed_work pl_enable_work; struct work_struct legacy_detection_work; + struct delayed_work uusb_otg_work; /* cached status */ int voltage_min_uv; diff --git a/drivers/regulator/onsemi-ncp6335d.c b/drivers/regulator/onsemi-ncp6335d.c index 595fde1c825f..3b4ca4f81527 100644 --- a/drivers/regulator/onsemi-ncp6335d.c +++ b/drivers/regulator/onsemi-ncp6335d.c @@ -153,6 +153,20 @@ static void ncp633d_slew_delay(struct ncp6335d_info *dd, udelay(delay); } +static int ncp6335d_is_enabled(struct regulator_dev *rdev) +{ + int rc, val = 0; + struct ncp6335d_info *dd = rdev_get_drvdata(rdev); + + rc = ncp6335x_read(dd, dd->vsel_reg, &val); + if (rc) + dev_err(dd->dev, "Unable to read enable register rc(%d)", rc); + + dump_registers(dd, dd->vsel_reg, __func__); + + return ((val & NCP6335D_ENABLE) ? 1 : 0); +} + static int ncp6335d_enable(struct regulator_dev *rdev) { int rc; @@ -297,6 +311,7 @@ static struct regulator_ops ncp6335d_ops = { .set_voltage = ncp6335d_set_voltage, .get_voltage = ncp6335d_get_voltage, .list_voltage = ncp6335d_list_voltage, + .is_enabled = ncp6335d_is_enabled, .enable = ncp6335d_enable, .disable = ncp6335d_disable, .set_mode = ncp6335d_set_mode, @@ -305,6 +320,7 @@ static struct regulator_ops ncp6335d_ops = { static struct regulator_desc rdesc = { .name = "ncp6335d", + .supply_name = "vin", .owner = THIS_MODULE, .n_voltages = NCP6335D_VOLTAGE_STEPS, .ops = &ncp6335d_ops, @@ -748,7 +764,7 @@ int __init ncp6335d_regulator_init(void) return i2c_add_driver(&ncp6335d_regulator_driver); } EXPORT_SYMBOL(ncp6335d_regulator_init); -arch_initcall(ncp6335d_regulator_init); +subsys_initcall(ncp6335d_regulator_init); static void __exit ncp6335d_regulator_exit(void) { diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c index 2882bcac918a..0b096730c72a 100644 --- a/drivers/scsi/cxlflash/main.c +++ b/drivers/scsi/cxlflash/main.c @@ -996,6 +996,8 @@ static int wait_port_online(__be64 __iomem *fc_regs, u32 delay_us, u32 nretry) do { msleep(delay_us / 1000); status = readq_be(&fc_regs[FC_MTIP_STATUS / 8]); + if (status == U64_MAX) + nretry /= 2; } while ((status & FC_MTIP_STATUS_MASK) != FC_MTIP_STATUS_ONLINE && nretry--); @@ -1027,6 +1029,8 @@ static int wait_port_offline(__be64 __iomem *fc_regs, u32 delay_us, u32 nretry) do { msleep(delay_us / 1000); status = readq_be(&fc_regs[FC_MTIP_STATUS / 8]); + if (status == U64_MAX) + nretry /= 2; } while ((status & FC_MTIP_STATUS_MASK) != FC_MTIP_STATUS_OFFLINE && nretry--); @@ -1137,7 +1141,7 @@ static const struct asyc_intr_info ainfo[] = { {SISL_ASTATUS_FC0_LOGI_F, "login failed", 0, CLR_FC_ERROR}, {SISL_ASTATUS_FC0_LOGI_S, "login succeeded", 0, SCAN_HOST}, {SISL_ASTATUS_FC0_LINK_DN, "link down", 0, 0}, - {SISL_ASTATUS_FC0_LINK_UP, "link up", 0, SCAN_HOST}, + {SISL_ASTATUS_FC0_LINK_UP, "link up", 0, 0}, {SISL_ASTATUS_FC1_OTHER, "other error", 1, CLR_FC_ERROR | LINK_RESET}, {SISL_ASTATUS_FC1_LOGO, "target initiated LOGO", 1, 0}, {SISL_ASTATUS_FC1_CRC_T, "CRC threshold exceeded", 1, LINK_RESET}, @@ -1145,7 +1149,7 @@ static const struct asyc_intr_info ainfo[] = { {SISL_ASTATUS_FC1_LOGI_F, "login failed", 1, CLR_FC_ERROR}, {SISL_ASTATUS_FC1_LOGI_S, "login succeeded", 1, SCAN_HOST}, {SISL_ASTATUS_FC1_LINK_DN, "link down", 1, 0}, - {SISL_ASTATUS_FC1_LINK_UP, "link up", 1, SCAN_HOST}, + {SISL_ASTATUS_FC1_LINK_UP, "link up", 1, 0}, {0x0, "", 0, 0} /* terminator */ }; @@ -1962,6 +1966,11 @@ retry: * cxlflash_eh_host_reset_handler() - reset the host adapter * @scp: SCSI command from stack identifying host. * + * Following a reset, the state is evaluated again in case an EEH occurred + * during the reset. In such a scenario, the host reset will either yield + * until the EEH recovery is complete or return success or failure based + * upon the current device state. + * * Return: * SUCCESS as defined in scsi/scsi.h * FAILED as defined in scsi/scsi.h @@ -1993,7 +2002,8 @@ static int cxlflash_eh_host_reset_handler(struct scsi_cmnd *scp) } else cfg->state = STATE_NORMAL; wake_up_all(&cfg->reset_waitq); - break; + ssleep(1); + /* fall through */ case STATE_RESET: wait_event(cfg->reset_waitq, cfg->state != STATE_RESET); if (cfg->state == STATE_NORMAL) @@ -2534,6 +2544,9 @@ static void drain_ioctls(struct cxlflash_cfg *cfg) * @pdev: PCI device struct. * @state: PCI channel state. * + * When an EEH occurs during an active reset, wait until the reset is + * complete and then take action based upon the device state. + * * Return: PCI_ERS_RESULT_NEED_RESET or PCI_ERS_RESULT_DISCONNECT */ static pci_ers_result_t cxlflash_pci_error_detected(struct pci_dev *pdev, @@ -2547,6 +2560,10 @@ static pci_ers_result_t cxlflash_pci_error_detected(struct pci_dev *pdev, switch (state) { case pci_channel_io_frozen: + wait_event(cfg->reset_waitq, cfg->state != STATE_RESET); + if (cfg->state == STATE_FAILTERM) + return PCI_ERS_RESULT_DISCONNECT; + cfg->state = STATE_RESET; scsi_block_requests(cfg->host); drain_ioctls(cfg); diff --git a/drivers/scsi/ufs/Kconfig b/drivers/scsi/ufs/Kconfig index b3ed361eff26..fb2f2159c0e1 100644 --- a/drivers/scsi/ufs/Kconfig +++ b/drivers/scsi/ufs/Kconfig @@ -106,3 +106,15 @@ config SCSI_UFS_TEST The UFS unit-tests register as a block device test utility to the test-iosched and will be initiated when the test-iosched will be chosen to be the active I/O scheduler. + +config SCSI_UFSHCD_CMD_LOGGING + bool "Universal Flash Storage host controller driver layer command logging support" + depends on SCSI_UFSHCD + help + This selects the UFS host controller driver layer command logging. + UFS host controller driver layer command logging records all the + command information sent from UFS host controller for debugging + purpose. + + Select this if you want above mentioned debug information captured. + If unsure, say N. diff --git a/drivers/scsi/ufs/ufs-qcom-ice.c b/drivers/scsi/ufs/ufs-qcom-ice.c index 814d1dcfe90e..0c862639fa3e 100644 --- a/drivers/scsi/ufs/ufs-qcom-ice.c +++ b/drivers/scsi/ufs/ufs-qcom-ice.c @@ -394,8 +394,8 @@ int ufs_qcom_ice_cfg_start(struct ufs_qcom_host *qcom_host, } + memset(&ice_set, 0, sizeof(ice_set)); if (qcom_host->ice.vops->config_start) { - memset(&ice_set, 0, sizeof(ice_set)); spin_lock_irqsave( &qcom_host->ice_work_lock, flags); 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/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index c5393d517432..a90c51a113d2 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -516,14 +516,145 @@ static inline void ufshcd_remove_non_printable(char *val) *val = ' '; } +#define UFSHCD_MAX_CMD_LOGGING 100 + #ifdef CONFIG_TRACEPOINTS -static void ufshcd_add_command_trace(struct ufs_hba *hba, - unsigned int tag, const char *str) +static inline void ufshcd_add_command_trace(struct ufs_hba *hba, + struct ufshcd_cmd_log_entry *entry, u8 opcode) +{ + if (trace_ufshcd_command_enabled()) { + u32 intr = ufshcd_readl(hba, REG_INTERRUPT_STATUS); + + trace_ufshcd_command(dev_name(hba->dev), entry->str, entry->tag, + entry->doorbell, entry->transfer_len, intr, + entry->lba, opcode); + } +} +#else +static inline void ufshcd_add_command_trace(struct ufs_hba *hba, + struct ufshcd_cmd_log_entry *entry, u8 opcode) +{ +} +#endif + +#ifdef CONFIG_SCSI_UFSHCD_CMD_LOGGING +static void ufshcd_cmd_log_init(struct ufs_hba *hba) +{ + /* Allocate log entries */ + if (!hba->cmd_log.entries) { + hba->cmd_log.entries = kzalloc(UFSHCD_MAX_CMD_LOGGING * + sizeof(struct ufshcd_cmd_log_entry), GFP_KERNEL); + if (!hba->cmd_log.entries) + return; + dev_dbg(hba->dev, "%s: cmd_log.entries initialized\n", + __func__); + } +} + +static void __ufshcd_cmd_log(struct ufs_hba *hba, char *str, char *cmd_type, + unsigned int tag, u8 cmd_id, u8 idn, u8 lun, + sector_t lba, int transfer_len, u8 opcode) +{ + struct ufshcd_cmd_log_entry *entry; + + if (!hba->cmd_log.entries) + return; + + entry = &hba->cmd_log.entries[hba->cmd_log.pos]; + entry->lun = lun; + entry->str = str; + entry->cmd_type = cmd_type; + entry->cmd_id = cmd_id; + entry->lba = lba; + entry->transfer_len = transfer_len; + entry->idn = idn; + entry->doorbell = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL); + entry->tag = tag; + entry->tstamp = ktime_get(); + entry->outstanding_reqs = hba->outstanding_reqs; + entry->seq_num = hba->cmd_log.seq_num; + hba->cmd_log.seq_num++; + hba->cmd_log.pos = + (hba->cmd_log.pos + 1) % UFSHCD_MAX_CMD_LOGGING; + + ufshcd_add_command_trace(hba, entry, opcode); +} + +static void ufshcd_cmd_log(struct ufs_hba *hba, char *str, char *cmd_type, + unsigned int tag, u8 cmd_id, u8 idn) +{ + __ufshcd_cmd_log(hba, str, cmd_type, tag, cmd_id, idn, + 0xff, (sector_t)-1, -1, -1); +} + +static void ufshcd_dme_cmd_log(struct ufs_hba *hba, char *str, u8 cmd_id) +{ + ufshcd_cmd_log(hba, str, "dme", 0xff, cmd_id, 0xff); +} + +static void ufshcd_cmd_log_print(struct ufs_hba *hba) +{ + int i; + int pos; + struct ufshcd_cmd_log_entry *p; + + if (!hba->cmd_log.entries) + return; + + pos = hba->cmd_log.pos; + for (i = 0; i < UFSHCD_MAX_CMD_LOGGING; i++) { + p = &hba->cmd_log.entries[pos]; + pos = (pos + 1) % UFSHCD_MAX_CMD_LOGGING; + + if (ktime_to_us(p->tstamp)) { + pr_err("%s: %s: seq_no=%u lun=0x%x cmd_id=0x%02x lba=0x%llx txfer_len=%d tag=%u, doorbell=0x%x outstanding=0x%x idn=%d time=%lld us\n", + p->cmd_type, p->str, p->seq_num, + p->lun, p->cmd_id, (unsigned long long)p->lba, + p->transfer_len, p->tag, p->doorbell, + p->outstanding_reqs, p->idn, + ktime_to_us(p->tstamp)); + usleep_range(1000, 1100); + } + } +} +#else +static void ufshcd_cmd_log_init(struct ufs_hba *hba) +{ +} + +static void __ufshcd_cmd_log(struct ufs_hba *hba, char *str, char *cmd_type, + unsigned int tag, u8 cmd_id, u8 idn, u8 lun, + sector_t lba, int transfer_len, u8 opcode) +{ + struct ufshcd_cmd_log_entry entry; + + entry.str = str; + entry.lba = lba; + entry.transfer_len = transfer_len; + entry.doorbell = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL); + entry.tag = tag; + + ufshcd_add_command_trace(hba, &entry, opcode); +} + +static void ufshcd_dme_cmd_log(struct ufs_hba *hba, char *str, u8 cmd_id) +{ +} + +static void ufshcd_cmd_log_print(struct ufs_hba *hba) +{ +} +#endif + +#ifdef CONFIG_TRACEPOINTS +static inline void ufshcd_cond_add_cmd_trace(struct ufs_hba *hba, + unsigned int tag, const char *str) { - sector_t lba = -1; - u8 opcode = 0; - u32 intr, doorbell; struct ufshcd_lrb *lrbp; + char *cmd_type; + u8 opcode = 0; + u8 cmd_id = 0, idn = 0; + sector_t lba = -1; int transfer_len = -1; lrbp = &hba->lrb[tag]; @@ -537,23 +668,28 @@ static void ufshcd_add_command_trace(struct ufs_hba *hba, */ if (lrbp->cmd->request && lrbp->cmd->request->bio) lba = - lrbp->cmd->request->bio->bi_iter.bi_sector; + lrbp->cmd->request->bio->bi_iter.bi_sector; transfer_len = be32_to_cpu( lrbp->ucd_req_ptr->sc.exp_data_transfer_len); } } - intr = ufshcd_readl(hba, REG_INTERRUPT_STATUS); - doorbell = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL); - trace_ufshcd_command(dev_name(hba->dev), str, tag, - doorbell, transfer_len, intr, lba, opcode); -} + if (lrbp->cmd && (lrbp->command_type == UTP_CMD_TYPE_SCSI)) { + cmd_type = "scsi"; + cmd_id = (u8)(*lrbp->cmd->cmnd); + } else if (lrbp->command_type == UTP_CMD_TYPE_DEV_MANAGE) { + if (hba->dev_cmd.type == DEV_CMD_TYPE_NOP) { + cmd_type = "nop"; + cmd_id = 0; + } else if (hba->dev_cmd.type == DEV_CMD_TYPE_QUERY) { + cmd_type = "query"; + cmd_id = hba->dev_cmd.query.request.upiu_req.opcode; + idn = hba->dev_cmd.query.request.upiu_req.idn; + } + } -static inline void ufshcd_cond_add_cmd_trace(struct ufs_hba *hba, - unsigned int tag, const char *str) -{ - if (trace_ufshcd_command_enabled()) - ufshcd_add_command_trace(hba, tag, str); + __ufshcd_cmd_log(hba, (char *) str, cmd_type, tag, cmd_id, idn, + lrbp->lun, lba, transfer_len, opcode); } #else static inline void ufshcd_cond_add_cmd_trace(struct ufs_hba *hba, @@ -1370,6 +1506,7 @@ start: } spin_unlock_irqrestore(hba->host->host_lock, flags); out: + hba->ufs_stats.clk_hold.ts = ktime_get(); return rc; } EXPORT_SYMBOL_GPL(ufshcd_hold); @@ -1474,6 +1611,7 @@ static void __ufshcd_release(struct ufs_hba *hba, bool no_sched) hba->clk_gating.state = REQ_CLKS_OFF; trace_ufshcd_clk_gating(dev_name(hba->dev), hba->clk_gating.state); + hba->ufs_stats.clk_rel.ts = ktime_get(); hrtimer_start(&hba->clk_gating.gate_hrtimer, ms_to_ktime(hba->clk_gating.delay_ms), @@ -1920,8 +2058,10 @@ static void ufshcd_hibern8_exit_work(struct work_struct *work) /* Exit from hibern8 */ if (ufshcd_is_link_hibern8(hba)) { + hba->ufs_stats.clk_hold.ctx = H8_EXIT_WORK; ufshcd_hold(hba, false); ret = ufshcd_uic_hibern8_exit(hba); + hba->ufs_stats.clk_rel.ctx = H8_EXIT_WORK; ufshcd_release(hba, false); if (!ret) { spin_lock_irqsave(hba->host->host_lock, flags); @@ -2263,6 +2403,7 @@ ufshcd_dispatch_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd) hba->active_uic_cmd = uic_cmd; + ufshcd_dme_cmd_log(hba, "send", hba->active_uic_cmd->command); /* Write Args */ ufshcd_writel(hba, uic_cmd->argument1, REG_UIC_COMMAND_ARG_1); ufshcd_writel(hba, uic_cmd->argument2, REG_UIC_COMMAND_ARG_2); @@ -2296,6 +2437,8 @@ ufshcd_wait_for_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd) if (ret) ufsdbg_set_err_state(hba); + ufshcd_dme_cmd_log(hba, "cmp1", hba->active_uic_cmd->command); + spin_lock_irqsave(hba->host->host_lock, flags); hba->active_uic_cmd = NULL; spin_unlock_irqrestore(hba->host->host_lock, flags); @@ -2344,6 +2487,7 @@ ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd) int ret; unsigned long flags; + hba->ufs_stats.clk_hold.ctx = UIC_CMD_SEND; ufshcd_hold_all(hba); mutex_lock(&hba->uic_cmd_mutex); ufshcd_add_delay_before_dme_cmd(hba); @@ -2357,6 +2501,7 @@ ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd) ufshcd_save_tstamp_of_last_dme_cmd(hba); mutex_unlock(&hba->uic_cmd_mutex); ufshcd_release_all(hba); + hba->ufs_stats.clk_rel.ctx = UIC_CMD_SEND; ufsdbg_error_inject_dispatcher(hba, ERR_INJECT_UIC, 0, &ret); @@ -2834,6 +2979,7 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) goto out; } + hba->ufs_stats.clk_hold.ctx = QUEUE_CMD; err = ufshcd_hold(hba, true); if (err) { err = SCSI_MLQUEUE_HOST_BUSY; @@ -2847,6 +2993,7 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) if (err) { clear_bit_unlock(tag, &hba->lrb_in_use); err = SCSI_MLQUEUE_HOST_BUSY; + hba->ufs_stats.clk_rel.ctx = QUEUE_CMD; ufshcd_release(hba, true); goto out; } @@ -4113,6 +4260,8 @@ static int ufshcd_uic_pwr_ctrl(struct ufs_hba *hba, struct uic_command *cmd) cmd->command, status); ret = (status != PWR_OK) ? status : -1; } + ufshcd_dme_cmd_log(hba, "cmp2", hba->active_uic_cmd->command); + out: if (ret) { ufsdbg_set_err_state(hba); @@ -4216,8 +4365,10 @@ static int ufshcd_uic_change_pwr_mode(struct ufs_hba *hba, u8 mode) uic_cmd.command = UIC_CMD_DME_SET; uic_cmd.argument1 = UIC_ARG_MIB(PA_PWRMODE); uic_cmd.argument3 = mode; + hba->ufs_stats.clk_hold.ctx = PWRCTL_CMD_SEND; ufshcd_hold_all(hba); ret = ufshcd_uic_pwr_ctrl(hba, &uic_cmd); + hba->ufs_stats.clk_rel.ctx = PWRCTL_CMD_SEND; ufshcd_release_all(hba); out: return ret; @@ -5385,6 +5536,7 @@ static void __ufshcd_transfer_req_compl(struct ufs_hba *hba, update_req_stats(hba, lrbp); /* Mark completed command as NULL in LRB */ lrbp->cmd = NULL; + hba->ufs_stats.clk_rel.ctx = XFR_REQ_COMPL; __ufshcd_release(hba, false); __ufshcd_hibern8_release(hba, false); if (cmd->request) { @@ -5421,7 +5573,7 @@ static void __ufshcd_transfer_req_compl(struct ufs_hba *hba, } else if (lrbp->command_type == UTP_CMD_TYPE_DEV_MANAGE) { if (hba->dev_cmd.complete) { ufshcd_cond_add_cmd_trace(hba, index, - "dev_complete"); + "dcmp"); complete(hba->dev_cmd.complete); } } @@ -5907,6 +6059,7 @@ static void ufshcd_err_handler(struct work_struct *work) if (unlikely((hba->clk_gating.state != CLKS_ON) && ufshcd_is_auto_hibern8_supported(hba))) { spin_unlock_irqrestore(hba->host->host_lock, flags); + hba->ufs_stats.clk_hold.ctx = ERR_HNDLR_WORK; ufshcd_hold(hba, false); spin_lock_irqsave(hba->host->host_lock, flags); clks_enabled = true; @@ -5943,6 +6096,7 @@ static void ufshcd_err_handler(struct work_struct *work) ufshcd_print_host_state(hba); ufshcd_print_pwr_info(hba); ufshcd_print_tmrs(hba, hba->outstanding_tasks); + ufshcd_cmd_log_print(hba); spin_lock_irqsave(hba->host->host_lock, flags); } } @@ -6049,8 +6203,10 @@ skip_err_handling: hba->silence_err_logs = false; - if (clks_enabled) + if (clks_enabled) { __ufshcd_release(hba, false); + hba->ufs_stats.clk_rel.ctx = ERR_HNDLR_WORK; + } out: ufshcd_clear_eh_in_progress(hba); spin_unlock_irqrestore(hba->host->host_lock, flags); @@ -6286,7 +6442,8 @@ static irqreturn_t ufshcd_intr(int irq, void *__hba) spin_lock(hba->host->host_lock); intr_status = ufshcd_readl(hba, REG_INTERRUPT_STATUS); - + hba->ufs_stats.last_intr_status = intr_status; + hba->ufs_stats.last_intr_ts = ktime_get(); /* * There could be max of hba->nutrs reqs in flight and in worst case * if the reqs get finished 1 by 1 after the interrupt status is @@ -6365,6 +6522,7 @@ static int ufshcd_issue_tm_cmd(struct ufs_hba *hba, int lun_id, int task_id, * the maximum wait time is bounded by %TM_CMD_TIMEOUT. */ wait_event(hba->tm_tag_wq, ufshcd_get_tm_free_slot(hba, &free_slot)); + hba->ufs_stats.clk_hold.ctx = TM_CMD_SEND; ufshcd_hold_all(hba); spin_lock_irqsave(host->host_lock, flags); @@ -6422,6 +6580,7 @@ static int ufshcd_issue_tm_cmd(struct ufs_hba *hba, int lun_id, int task_id, clear_bit(free_slot, &hba->tm_condition); ufshcd_put_tm_slot(hba, free_slot); wake_up(&hba->tm_tag_wq); + hba->ufs_stats.clk_rel.ctx = TM_CMD_SEND; ufshcd_release_all(hba); return err; @@ -6449,6 +6608,7 @@ static int ufshcd_eh_device_reset_handler(struct scsi_cmnd *cmd) hba = shost_priv(host); tag = cmd->request->tag; + ufshcd_cmd_log_print(hba); lrbp = &hba->lrb[tag]; err = ufshcd_issue_tm_cmd(hba, lrbp->lun, 0, UFS_LOGICAL_RESET, &resp); if (err || resp != UPIU_TASK_MANAGEMENT_FUNC_COMPL) { @@ -9315,6 +9475,7 @@ static int ufshcd_devfreq_scale(struct ufs_hba *hba, bool scale_up) int ret = 0; /* let's not get into low power until clock scaling is completed */ + hba->ufs_stats.clk_hold.ctx = CLK_SCALE_WORK; ufshcd_hold_all(hba); ret = ufshcd_clock_scaling_prepare(hba); @@ -9378,6 +9539,7 @@ scale_up_gear: clk_scaling_unprepare: ufshcd_clock_scaling_unprepare(hba); out: + hba->ufs_stats.clk_rel.ctx = CLK_SCALE_WORK; ufshcd_release_all(hba); return ret; } @@ -9809,6 +9971,8 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) */ ufshcd_set_ufs_dev_active(hba); + ufshcd_cmd_log_init(hba); + async_schedule(ufshcd_async_scan, hba); ufsdbg_add_debugfs(hba); diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index c34a998aac17..d66205ff9f5d 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -3,7 +3,7 @@ * * This code is based on drivers/scsi/ufs/ufshcd.h * Copyright (C) 2011-2013 Samsung India Software Operations - * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. * * Authors: * Santosh Yaraganavi <santosh.sy@samsung.com> @@ -519,7 +519,7 @@ struct ufs_init_prefetch { u32 icc_level; }; -#define UIC_ERR_REG_HIST_LENGTH 8 +#define UIC_ERR_REG_HIST_LENGTH 20 /** * struct ufs_uic_err_reg_hist - keeps history of uic errors * @pos: index to indicate cyclic buffer position @@ -588,6 +588,22 @@ struct ufshcd_req_stat { }; #endif +enum ufshcd_ctx { + QUEUE_CMD, + ERR_HNDLR_WORK, + H8_EXIT_WORK, + UIC_CMD_SEND, + PWRCTL_CMD_SEND, + TM_CMD_SEND, + XFR_REQ_COMPL, + CLK_SCALE_WORK, +}; + +struct ufshcd_clk_ctx { + ktime_t ts; + enum ufshcd_ctx ctx; +}; + /** * struct ufs_stats - keeps usage/err statistics * @enabled: enable tag stats for debugfs @@ -616,6 +632,10 @@ struct ufs_stats { int query_stats_arr[UPIU_QUERY_OPCODE_MAX][MAX_QUERY_IDN]; #endif + u32 last_intr_status; + ktime_t last_intr_ts; + struct ufshcd_clk_ctx clk_hold; + struct ufshcd_clk_ctx clk_rel; u32 hibern8_exit_cnt; ktime_t last_hibern8_exit_tstamp; struct ufs_uic_err_reg_hist pa_err; @@ -641,6 +661,27 @@ struct ufs_stats { UFSHCD_DBG_PRINT_TMRS_EN | UFSHCD_DBG_PRINT_PWR_EN | \ UFSHCD_DBG_PRINT_HOST_STATE_EN) +struct ufshcd_cmd_log_entry { + char *str; /* context like "send", "complete" */ + char *cmd_type; /* "scsi", "query", "nop", "dme" */ + u8 lun; + u8 cmd_id; + sector_t lba; + int transfer_len; + u8 idn; /* used only for query idn */ + u32 doorbell; + u32 outstanding_reqs; + u32 seq_num; + unsigned int tag; + ktime_t tstamp; +}; + +struct ufshcd_cmd_log { + struct ufshcd_cmd_log_entry *entries; + int pos; + u32 seq_num; +}; + /** * struct ufs_hba - per adapter private structure * @mmio_base: UFSHCI base register address @@ -856,6 +897,7 @@ struct ufs_hba { struct ufs_clk_gating clk_gating; struct ufs_hibern8_on_idle hibern8_on_idle; + struct ufshcd_cmd_log cmd_log; /* Control to enable/disable host capabilities */ u32 caps; diff --git a/drivers/soc/qcom/icnss_utils.c b/drivers/soc/qcom/icnss_utils.c index 5e187d5df8b3..a7a0ffa2c18e 100644 --- a/drivers/soc/qcom/icnss_utils.c +++ b/drivers/soc/qcom/icnss_utils.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -16,7 +16,7 @@ #define ICNSS_MAX_CH_NUM 45 static DEFINE_MUTEX(unsafe_channel_list_lock); -static DEFINE_MUTEX(dfs_nol_info_lock); +static DEFINE_SPINLOCK(dfs_nol_info_lock); static struct icnss_unsafe_channel_list { u16 unsafe_ch_count; @@ -77,27 +77,24 @@ EXPORT_SYMBOL(icnss_get_wlan_unsafe_channel); int icnss_wlan_set_dfs_nol(const void *info, u16 info_len) { void *temp; + void *old_nol_info; struct icnss_dfs_nol_info *dfs_info; - mutex_lock(&dfs_nol_info_lock); - if (!info || !info_len) { - mutex_unlock(&dfs_nol_info_lock); + if (!info || !info_len) return -EINVAL; - } - temp = kmalloc(info_len, GFP_KERNEL); - if (!temp) { - mutex_unlock(&dfs_nol_info_lock); + temp = kmalloc(info_len, GFP_ATOMIC); + if (!temp) return -ENOMEM; - } memcpy(temp, info, info_len); + spin_lock_bh(&dfs_nol_info_lock); dfs_info = &dfs_nol_info; - kfree(dfs_info->dfs_nol_info); - + old_nol_info = dfs_info->dfs_nol_info; dfs_info->dfs_nol_info = temp; dfs_info->dfs_nol_info_len = info_len; - mutex_unlock(&dfs_nol_info_lock); + spin_unlock_bh(&dfs_nol_info_lock); + kfree(old_nol_info); return 0; } @@ -108,24 +105,21 @@ int icnss_wlan_get_dfs_nol(void *info, u16 info_len) int len; struct icnss_dfs_nol_info *dfs_info; - mutex_lock(&dfs_nol_info_lock); - if (!info || !info_len) { - mutex_unlock(&dfs_nol_info_lock); + if (!info || !info_len) return -EINVAL; - } - dfs_info = &dfs_nol_info; + spin_lock_bh(&dfs_nol_info_lock); + dfs_info = &dfs_nol_info; if (dfs_info->dfs_nol_info == NULL || dfs_info->dfs_nol_info_len == 0) { - mutex_unlock(&dfs_nol_info_lock); + spin_unlock_bh(&dfs_nol_info_lock); return -ENOENT; } len = min(info_len, dfs_info->dfs_nol_info_len); - memcpy(info, dfs_info->dfs_nol_info, len); - mutex_unlock(&dfs_nol_info_lock); + spin_unlock_bh(&dfs_nol_info_lock); return len; } diff --git a/drivers/soc/qcom/memshare/msm_memshare.c b/drivers/soc/qcom/memshare/msm_memshare.c index b8417513ca55..7406dba44320 100644 --- a/drivers/soc/qcom/memshare/msm_memshare.c +++ b/drivers/soc/qcom/memshare/msm_memshare.c @@ -498,6 +498,7 @@ static int handle_alloc_generic_req(void *req_h, void *req, void *conn_h) struct mem_alloc_generic_resp_msg_v01 *alloc_resp; int rc, resp = 0; int client_id; + uint32_t size = 0; alloc_req = (struct mem_alloc_generic_req_msg_v01 *)req; pr_debug("memshare: alloc request client id: %d proc _id: %d\n", @@ -523,12 +524,12 @@ 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) { - rc = memshare_alloc(memsh_drv->dev, alloc_req->num_bytes, + if (alloc_req->client_id == 1 && alloc_req->num_bytes > 0) + size = alloc_req->num_bytes + MEMSHARE_GUARD_BYTES; + else + size = alloc_req->num_bytes; + rc = memshare_alloc(memsh_drv->dev, size, &memblock[client_id]); if (rc) { pr_err("In %s,Unable to allocate memory for requested client\n", @@ -536,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); @@ -963,8 +969,10 @@ static int memshare_child_probe(struct platform_device *pdev) * Memshare allocation for guaranteed clients */ if (memblock[num_clients].guarantee) { + if (client_id == 1 && size > 0) + size += MEMSHARE_GUARD_BYTES; rc = memshare_alloc(memsh_child->dev, - memblock[num_clients].size, + size, &memblock[num_clients]); if (rc) { pr_err("In %s, Unable to allocate memory for guaranteed clients, rc: %d\n", diff --git a/drivers/soc/qcom/memshare/msm_memshare.h b/drivers/soc/qcom/memshare/msm_memshare.h index 398907532977..c7123fb1314b 100644 --- a/drivers/soc/qcom/memshare/msm_memshare.h +++ b/drivers/soc/qcom/memshare/msm_memshare.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -24,6 +24,7 @@ #define GPS 0 #define CHECK 0 #define FREE 1 +#define MEMSHARE_GUARD_BYTES (4*1024) struct mem_blocks { /* Client Id information */ diff --git a/drivers/soc/qcom/msm_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/qbt1000.c b/drivers/soc/qcom/qbt1000.c index 4ba92436bd06..6e7d34ac9163 100644 --- a/drivers/soc/qcom/qbt1000.c +++ b/drivers/soc/qcom/qbt1000.c @@ -377,6 +377,12 @@ static long qbt1000_ioctl(struct file *file, unsigned cmd, unsigned long arg) drvdata = file->private_data; + if (IS_ERR(priv_arg)) { + dev_err(drvdata->dev, "%s: invalid user space pointer %lu\n", + __func__, arg); + return -EINVAL; + } + mutex_lock(&drvdata->mutex); pr_debug("qbt1000_ioctl %d\n", cmd); @@ -401,6 +407,13 @@ static long qbt1000_ioctl(struct file *file, unsigned cmd, unsigned long arg) goto end; } + if (strcmp(app.name, FP_APP_NAME)) { + dev_err(drvdata->dev, "%s: Invalid app name\n", + __func__); + rc = -EINVAL; + goto end; + } + if (drvdata->app_handle) { dev_err(drvdata->dev, "%s: LOAD app already loaded, unloading first\n", __func__); @@ -414,6 +427,7 @@ static long qbt1000_ioctl(struct file *file, unsigned cmd, unsigned long arg) } pr_debug("app %s load before\n", app.name); + app.name[MAX_NAME_SIZE - 1] = '\0'; /* start the TZ app */ rc = qseecom_start_app( @@ -427,7 +441,8 @@ static long qbt1000_ioctl(struct file *file, unsigned cmd, unsigned long arg) pr_err("App %s failed to set bw\n", app.name); } } else { - pr_err("app %s failed to load\n", app.name); + dev_err(drvdata->dev, "%s: Fingerprint Trusted App failed to load\n", + __func__); goto end; } @@ -447,9 +462,7 @@ static long qbt1000_ioctl(struct file *file, unsigned cmd, unsigned long arg) pr_debug("app %s load after\n", app.name); - if (!strcmp(app.name, FP_APP_NAME)) - drvdata->fp_app_handle = drvdata->app_handle; - + drvdata->fp_app_handle = drvdata->app_handle; break; } case QBT1000_UNLOAD_APP: diff --git a/drivers/soc/qcom/qpnp-haptic.c b/drivers/soc/qcom/qpnp-haptic.c index 70cf11359e97..d86f8671705a 100644 --- a/drivers/soc/qcom/qpnp-haptic.c +++ b/drivers/soc/qcom/qpnp-haptic.c @@ -85,6 +85,7 @@ #define QPNP_HAP_PM660_RES_CAL_PERIOD_MAX 256 #define QPNP_HAP_WF_SOURCE_MASK GENMASK(5, 4) #define QPNP_HAP_WF_SOURCE_SHIFT 4 +#define QPNP_HAP_VMAX_OVD_BIT BIT(6) #define QPNP_HAP_VMAX_MASK GENMASK(5, 1) #define QPNP_HAP_VMAX_SHIFT 1 #define QPNP_HAP_VMAX_MIN_MV 116 @@ -117,6 +118,8 @@ #define QPNP_HAP_WAV_REP_MAX 128 #define QPNP_HAP_WAV_S_REP_MIN 1 #define QPNP_HAP_WAV_S_REP_MAX 8 +#define QPNP_HAP_WF_AMP_MASK GENMASK(5, 1) +#define QPNP_HAP_WF_OVD_BIT BIT(6) #define QPNP_HAP_BRAKE_PAT_MASK 0x3 #define QPNP_HAP_ILIM_MIN_MA 400 #define QPNP_HAP_ILIM_MAX_MA 800 @@ -135,21 +138,20 @@ #define QPNP_HAP_WAV_SINE 0 #define QPNP_HAP_WAV_SQUARE 1 #define QPNP_HAP_WAV_SAMP_LEN 8 -#define QPNP_HAP_WAV_SAMP_MAX 0x7E +#define QPNP_HAP_WAV_SAMP_MAX 0x3E #define QPNP_HAP_BRAKE_PAT_LEN 4 -#define QPNP_HAP_PLAY_EN 0x80 +#define QPNP_HAP_PLAY_EN_BIT BIT(7) #define QPNP_HAP_EN_BIT BIT(7) #define QPNP_HAP_BRAKE_MASK BIT(0) #define QPNP_HAP_AUTO_RES_MASK BIT(7) #define AUTO_RES_ENABLE BIT(7) #define AUTO_RES_ERR_BIT 0x10 #define SC_FOUND_BIT 0x08 -#define SC_MAX_DURATION 5 +#define SC_MAX_COUNT 5 #define QPNP_HAP_TIMEOUT_MS_MAX 15000 #define QPNP_HAP_STR_SIZE 20 #define QPNP_HAP_MAX_RETRIES 5 -#define QPNP_HAP_CYCLS 5 #define QPNP_TEST_TIMER_MS 5 #define QPNP_HAP_TIME_REQ_FOR_BACK_EMF_GEN 20000 @@ -262,6 +264,22 @@ struct qpnp_pwm_info { }; /* + * qpnp_hap_lra_ares_cfg - Haptic auto_resonance configuration + * @ lra_qwd_drive_duration - LRA QWD drive duration + * @ calibrate_at_eop - Calibrate at EOP + * @ lra_res_cal_period - LRA resonance calibration period + * @ auto_res_mode - auto resonace mode + * @ lra_high_z - high z option line + */ +struct qpnp_hap_lra_ares_cfg { + int lra_qwd_drive_duration; + int calibrate_at_eop; + enum qpnp_hap_high_z lra_high_z; + u16 lra_res_cal_period; + u8 auto_res_mode; +}; + +/* * qpnp_hap - Haptic data structure * @ spmi - spmi device * @ hap_timer - hrtimer @@ -270,6 +288,7 @@ struct qpnp_pwm_info { * @ work - worker * @ sc_work - worker to handle short circuit condition * @ pwm_info - pwm info + * @ ares_cfg - auto resonance configuration * @ lock - mutex lock * @ wf_lock - mutex lock for waveform * @ init_drive_period_code - the initial lra drive period code @@ -281,10 +300,7 @@ struct qpnp_pwm_info { percentage variation on the higher side. * @ drive_period_code_min_limit - calculated drive period code with percentage variation on the lower side - * @ lra_res_cal_period - LRA resonance calibration period * @ play_mode - play mode - * @ auto_res_mode - auto resonace mode - * @ lra_high_z - high z option line * @ timeout_ms - max timeout in ms * @ time_required_to_generate_back_emf_us - the time required for sufficient back-emf to be generated for auto resonance to be successful @@ -293,6 +309,7 @@ struct qpnp_pwm_info { * @ sc_deb_cycles - short circuit debounce cycles * @ int_pwm_freq_khz - internal pwm frequency in khz * @ wave_play_rate_us - play rate for waveform + * @ play_time_ms - play time set by the user * @ ext_pwm_freq_khz - external pwm frequency in khz * @ wave_rep_cnt - waveform repeat count * @ wave_s_rep_cnt - waveform sample repeat count @@ -305,14 +322,12 @@ struct qpnp_pwm_info { * @ wave_samp - array of wave samples * @ shadow_wave_samp - shadow array of wave samples * @ brake_pat - pattern for active breaking - * @ reg_play - play register - * @ lra_res_cal_period - period for resonance calibration - * @ sc_duration - counter to determine the duration of short circuit condition + * @ sc_count - counter to determine the duration of short circuit condition * @ lra_hw_auto_resonance - enable hardware auto resonance * @ state - current state of haptics + * @ module_en - haptics module enable status * @ wf_update - waveform update flag * @ pwm_cfg_state - pwm mode configuration state - * @ buffer_cfg_state - buffer mode configuration state * @ en_brake - brake state * @ sup_brake_pat - support custom brake pattern * @ correct_lra_drive_freq - correct LRA Drive Frequency @@ -320,6 +335,9 @@ struct qpnp_pwm_info { * @ clk_trim_error_code - MISC clock trim error code * @ perform_lra_auto_resonance_search - whether lra auto resonance search * algorithm should be performed or not. + * @ auto_mode - Auto mode selection + * @ override_auto_mode_config - Flag to override auto mode configuration with + * user specified values through sysfs. */ struct qpnp_hap { struct platform_device *pdev; @@ -333,14 +351,12 @@ struct qpnp_hap { struct hrtimer hap_test_timer; struct work_struct test_work; struct qpnp_pwm_info pwm_info; + struct qpnp_hap_lra_ares_cfg ares_cfg; struct mutex lock; struct mutex wf_lock; spinlock_t bus_lock; struct completion completion; enum qpnp_hap_mode play_mode; - enum qpnp_hap_high_z lra_high_z; - int lra_qwd_drive_duration; - int calibrate_at_eop; u32 misc_clk_trim_error_reg; u32 init_drive_period_code; u32 timeout_ms; @@ -350,6 +366,7 @@ struct qpnp_hap { u32 sc_deb_cycles; u32 int_pwm_freq_khz; u32 wave_play_rate_us; + u32 play_time_ms; u32 ext_pwm_freq_khz; u32 wave_rep_cnt; u32 wave_s_rep_cnt; @@ -360,7 +377,6 @@ struct qpnp_hap { u16 last_rate_cfg; u16 drive_period_code_max_limit; u16 drive_period_code_min_limit; - u16 lra_res_cal_period; u8 drive_period_code_max_limit_percent_variation; u8 drive_period_code_min_limit_percent_variation; u8 act_type; @@ -368,23 +384,24 @@ struct qpnp_hap { u8 wave_samp[QPNP_HAP_WAV_SAMP_LEN]; u8 shadow_wave_samp[QPNP_HAP_WAV_SAMP_LEN]; u8 brake_pat[QPNP_HAP_BRAKE_PAT_LEN]; - u8 reg_play; - u8 sc_duration; + u8 sc_count; u8 ext_pwm_dtest_line; u8 pmic_subtype; - u8 auto_res_mode; u8 clk_trim_error_code; bool lra_hw_auto_resonance; bool vcc_pon_enabled; bool state; + bool module_en; bool manage_pon_supply; bool wf_update; bool pwm_cfg_state; - bool buffer_cfg_state; bool en_brake; bool sup_brake_pat; bool correct_lra_drive_freq; bool perform_lra_auto_resonance_search; + bool auto_mode; + bool override_auto_mode_config; + bool play_irq_en; }; static struct qpnp_hap *ghap; @@ -502,36 +519,50 @@ static void qpnp_handle_sc_irq(struct work_struct *work) /* clear short circuit register */ if (val & SC_FOUND_BIT) { - hap->sc_duration++; + hap->sc_count++; val = QPNP_HAP_SC_CLR; qpnp_hap_write_reg(hap, QPNP_HAP_SC_CLR_REG(hap->base), val); } } +#define QPNP_HAP_CYCLES 4 static int qpnp_hap_mod_enable(struct qpnp_hap *hap, bool on) { + unsigned long wait_time_us; u8 val; int rc, i; + if (hap->module_en == on) + return 0; + if (!on) { - for (i = 0; i < QPNP_HAP_MAX_RETRIES; i++) { - /* wait for 4 cycles of play rate */ - unsigned long sleep_time = - QPNP_HAP_CYCLS * hap->wave_play_rate_us; + /* + * Wait for 4 cycles of play rate for play time is > 20 ms and + * wait for play time when play time is < 20 ms. This way, there + * will be an improvement in waiting time polling BUSY status. + */ + if (hap->play_time_ms <= 20) + wait_time_us = hap->play_time_ms * 1000; + else + wait_time_us = QPNP_HAP_CYCLES * hap->wave_play_rate_us; + for (i = 0; i < QPNP_HAP_MAX_RETRIES; i++) { rc = qpnp_hap_read_reg(hap, QPNP_HAP_STATUS(hap->base), &val); + if (rc < 0) + return rc; pr_debug("HAP_STATUS=0x%x\n", val); - /* wait for QPNP_HAP_CYCLS cycles of play rate */ + /* wait for play_rate cycles */ if (val & QPNP_HAP_STATUS_BUSY) { - usleep_range(sleep_time, sleep_time + 1); + usleep_range(wait_time_us, wait_time_us + 1); if (hap->play_mode == QPNP_HAP_DIRECT || hap->play_mode == QPNP_HAP_PWM) break; - } else + } else { break; + } } if (i >= QPNP_HAP_MAX_RETRIES) @@ -543,27 +574,18 @@ static int qpnp_hap_mod_enable(struct qpnp_hap *hap, bool on) if (rc < 0) return rc; + hap->module_en = on; return 0; } -static int qpnp_hap_play(struct qpnp_hap *hap, int on) +static int qpnp_hap_play(struct qpnp_hap *hap, bool on) { u8 val; int rc; - val = hap->reg_play; - if (on) - val |= QPNP_HAP_PLAY_EN; - else - val &= ~QPNP_HAP_PLAY_EN; - + val = on ? QPNP_HAP_PLAY_EN_BIT : 0; rc = qpnp_hap_write_reg(hap, QPNP_HAP_PLAY_REG(hap->base), val); - if (rc < 0) - return rc; - - hap->reg_play = val; - - return 0; + return rc; } /* sysfs show debug registers */ @@ -624,13 +646,13 @@ static irqreturn_t qpnp_hap_sc_irq(int irq, void *_hap) pr_debug("Short circuit detected\n"); - if (hap->sc_duration < SC_MAX_DURATION) { + if (hap->sc_count < SC_MAX_COUNT) { qpnp_hap_read_reg(hap, QPNP_HAP_STATUS(hap->base), &val); if (val & SC_FOUND_BIT) schedule_delayed_work(&hap->sc_work, QPNP_HAP_SC_IRQ_STATUS_DELAY); else - hap->sc_duration = 0; + hap->sc_count = 0; } else { /* Disable haptics module if the duration of short circuit * exceeds the maximum limit (5 secs). @@ -645,9 +667,11 @@ static irqreturn_t qpnp_hap_sc_irq(int irq, void *_hap) } /* configuration api for buffer mode */ -static int qpnp_hap_buffer_config(struct qpnp_hap *hap) +static int qpnp_hap_buffer_config(struct qpnp_hap *hap, u8 *wave_samp, + bool overdrive) { - u8 val = 0; + u8 buf[QPNP_HAP_WAV_SAMP_LEN], val; + u8 *ptr; int rc, i; /* Configure the WAVE_REPEAT register */ @@ -668,16 +692,27 @@ static int qpnp_hap_buffer_config(struct qpnp_hap *hap) if (rc) return rc; + /* Don't set override bit in waveform sample for PM660 */ + if (hap->pmic_subtype == PM660_SUBTYPE) + overdrive = false; + + if (wave_samp) + ptr = wave_samp; + else + ptr = hap->wave_samp; + /* Configure WAVE_SAMPLE1 to WAVE_SAMPLE8 register */ - for (i = 0, val = 0; i < QPNP_HAP_WAV_SAMP_LEN; i++) { - val = hap->wave_samp[i]; - rc = qpnp_hap_write_reg(hap, - QPNP_HAP_WAV_S_REG_BASE(hap->base) + i, val); - if (rc) - return rc; + for (i = 0; i < QPNP_HAP_WAV_SAMP_LEN; i++) { + buf[i] = ptr[i] & QPNP_HAP_WF_AMP_MASK; + if (buf[i]) + buf[i] |= (overdrive ? QPNP_HAP_WF_OVD_BIT : 0); } - hap->buffer_cfg_state = true; + rc = qpnp_hap_write_mult_reg(hap, QPNP_HAP_WAV_S_REG_BASE(hap->base), + buf, QPNP_HAP_WAV_SAMP_LEN); + if (rc) + return rc; + return 0; } @@ -736,10 +771,12 @@ static int qpnp_hap_pwm_config(struct qpnp_hap *hap) return 0; } -static int qpnp_hap_lra_auto_res_config(struct qpnp_hap *hap) +static int qpnp_hap_lra_auto_res_config(struct qpnp_hap *hap, + struct qpnp_hap_lra_ares_cfg *tmp_cfg) { + struct qpnp_hap_lra_ares_cfg *ares_cfg; int rc; - u8 val, mask; + u8 val = 0, mask = 0; /* disable auto resonance for ERM */ if (hap->act_type == QPNP_HAP_ERM) { @@ -751,59 +788,73 @@ static int qpnp_hap_lra_auto_res_config(struct qpnp_hap *hap) if (hap->lra_hw_auto_resonance) { rc = qpnp_hap_masked_write_reg(hap, - QPNP_HAP_PM660_HW_AUTO_RES_MODE_BIT, QPNP_HAP_AUTO_RES_CTRL(hap->base), + QPNP_HAP_PM660_HW_AUTO_RES_MODE_BIT, QPNP_HAP_PM660_HW_AUTO_RES_MODE_BIT); if (rc) return rc; } - if (hap->lra_res_cal_period < QPNP_HAP_RES_CAL_PERIOD_MIN) - hap->lra_res_cal_period = QPNP_HAP_RES_CAL_PERIOD_MIN; + if (tmp_cfg) + ares_cfg = tmp_cfg; + else + ares_cfg = &hap->ares_cfg; + + if (ares_cfg->lra_res_cal_period < QPNP_HAP_RES_CAL_PERIOD_MIN) + ares_cfg->lra_res_cal_period = QPNP_HAP_RES_CAL_PERIOD_MIN; if (hap->pmic_subtype == PM660_SUBTYPE) { - if (hap->lra_res_cal_period > + if (ares_cfg->lra_res_cal_period > QPNP_HAP_PM660_RES_CAL_PERIOD_MAX) - hap->lra_res_cal_period = + ares_cfg->lra_res_cal_period = QPNP_HAP_PM660_RES_CAL_PERIOD_MAX; - if (hap->auto_res_mode == QPNP_HAP_PM660_AUTO_RES_QWD) - hap->lra_res_cal_period = 0; + if (ares_cfg->auto_res_mode == QPNP_HAP_PM660_AUTO_RES_QWD) + ares_cfg->lra_res_cal_period = 0; + + if (ares_cfg->lra_res_cal_period) + val = ilog2(ares_cfg->lra_res_cal_period / + QPNP_HAP_RES_CAL_PERIOD_MIN) + 1; } else { - if (hap->lra_res_cal_period > QPNP_HAP_RES_CAL_PERIOD_MAX) - hap->lra_res_cal_period = QPNP_HAP_RES_CAL_PERIOD_MAX; - } + if (ares_cfg->lra_res_cal_period > QPNP_HAP_RES_CAL_PERIOD_MAX) + ares_cfg->lra_res_cal_period = + QPNP_HAP_RES_CAL_PERIOD_MAX; - val = mask = 0; - if (hap->lra_res_cal_period) - val = ilog2(hap->lra_res_cal_period / - QPNP_HAP_RES_CAL_PERIOD_MIN); + if (ares_cfg->lra_res_cal_period) + val = ilog2(ares_cfg->lra_res_cal_period / + QPNP_HAP_RES_CAL_PERIOD_MIN); + } if (hap->pmic_subtype == PM660_SUBTYPE) { - val |= hap->auto_res_mode << + val |= ares_cfg->auto_res_mode << QPNP_HAP_PM660_AUTO_RES_MODE_SHIFT; mask = QPNP_HAP_PM660_AUTO_RES_MODE_BIT; - val |= hap->lra_high_z << + val |= ares_cfg->lra_high_z << QPNP_HAP_PM660_CALIBRATE_DURATION_SHIFT; mask |= QPNP_HAP_PM660_CALIBRATE_DURATION_MASK; - if (hap->lra_qwd_drive_duration != -EINVAL) { - val |= hap->lra_qwd_drive_duration << + if (ares_cfg->lra_qwd_drive_duration != -EINVAL) { + val |= ares_cfg->lra_qwd_drive_duration << QPNP_HAP_PM660_QWD_DRIVE_DURATION_SHIFT; mask |= QPNP_HAP_PM660_QWD_DRIVE_DURATION_BIT; } - if (hap->calibrate_at_eop != -EINVAL) { - val |= hap->calibrate_at_eop << + if (ares_cfg->calibrate_at_eop != -EINVAL) { + val |= ares_cfg->calibrate_at_eop << QPNP_HAP_PM660_CALIBRATE_AT_EOP_SHIFT; mask |= QPNP_HAP_PM660_CALIBRATE_AT_EOP_BIT; } mask |= QPNP_HAP_PM660_LRA_RES_CAL_PER_MASK; } else { - val |= (hap->auto_res_mode << QPNP_HAP_AUTO_RES_MODE_SHIFT); - val |= (hap->lra_high_z << QPNP_HAP_LRA_HIGH_Z_SHIFT); + val |= (ares_cfg->auto_res_mode << + QPNP_HAP_AUTO_RES_MODE_SHIFT); + val |= (ares_cfg->lra_high_z << QPNP_HAP_LRA_HIGH_Z_SHIFT); mask = QPNP_HAP_AUTO_RES_MODE_MASK | QPNP_HAP_LRA_HIGH_Z_MASK | QPNP_HAP_LRA_RES_CAL_PER_MASK; } + pr_debug("mode: %d hi_z period: %d cal_period: %d\n", + ares_cfg->auto_res_mode, ares_cfg->lra_high_z, + ares_cfg->lra_res_cal_period); + rc = qpnp_hap_masked_write_reg(hap, QPNP_HAP_LRA_AUTO_RES_REG(hap->base), mask, val); return rc; @@ -822,19 +873,29 @@ static int qpnp_hap_play_mode_config(struct qpnp_hap *hap) } /* configuration api for max voltage */ -static int qpnp_hap_vmax_config(struct qpnp_hap *hap) +static int qpnp_hap_vmax_config(struct qpnp_hap *hap, int vmax_mv, + bool overdrive) { u8 val = 0; int rc; - if (hap->vmax_mv < QPNP_HAP_VMAX_MIN_MV) - hap->vmax_mv = QPNP_HAP_VMAX_MIN_MV; - else if (hap->vmax_mv > QPNP_HAP_VMAX_MAX_MV) - hap->vmax_mv = QPNP_HAP_VMAX_MAX_MV; + if (vmax_mv < 0) + return -EINVAL; - val = (hap->vmax_mv / QPNP_HAP_VMAX_MIN_MV) << QPNP_HAP_VMAX_SHIFT; + /* Allow setting override bit in VMAX_CFG only for PM660 */ + if (hap->pmic_subtype != PM660_SUBTYPE) + overdrive = false; + + if (vmax_mv < QPNP_HAP_VMAX_MIN_MV) + vmax_mv = QPNP_HAP_VMAX_MIN_MV; + else if (vmax_mv > QPNP_HAP_VMAX_MAX_MV) + vmax_mv = QPNP_HAP_VMAX_MAX_MV; + + val = (vmax_mv / QPNP_HAP_VMAX_MIN_MV) << QPNP_HAP_VMAX_SHIFT; + if (overdrive) + val |= QPNP_HAP_VMAX_OVD_BIT; rc = qpnp_hap_masked_write_reg(hap, QPNP_HAP_VMAX_REG(hap->base), - QPNP_HAP_VMAX_MASK, val); + QPNP_HAP_VMAX_MASK | QPNP_HAP_VMAX_OVD_BIT, val); return rc; } @@ -912,6 +973,41 @@ static int qpnp_hap_int_pwm_config(struct qpnp_hap *hap) return rc; } +static int qpnp_hap_brake_config(struct qpnp_hap *hap, u8 *brake_pat) +{ + int rc, i; + u32 temp; + u8 *pat_ptr, val; + + if (!hap->en_brake) + return 0; + + /* Configure BRAKE register */ + rc = qpnp_hap_masked_write_reg(hap, QPNP_HAP_EN_CTL2_REG(hap->base), + QPNP_HAP_BRAKE_MASK, (u8)hap->en_brake); + if (rc) + return rc; + + if (!brake_pat) + pat_ptr = hap->brake_pat; + else + pat_ptr = brake_pat; + + if (hap->sup_brake_pat) { + for (i = QPNP_HAP_BRAKE_PAT_LEN - 1, val = 0; i >= 0; i--) { + pat_ptr[i] &= QPNP_HAP_BRAKE_PAT_MASK; + temp = i << 1; + val |= pat_ptr[i] << temp; + } + rc = qpnp_hap_write_reg(hap, QPNP_HAP_BRAKE_REG(hap->base), + val); + if (rc) + return rc; + } + + return 0; +} + /* DT parsing api for buffer mode */ static int qpnp_hap_parse_buffer_dt(struct qpnp_hap *hap) { @@ -920,6 +1016,9 @@ static int qpnp_hap_parse_buffer_dt(struct qpnp_hap *hap) u32 temp; int rc, i; + if (hap->wave_rep_cnt > 0 || hap->wave_s_rep_cnt > 0) + return 0; + hap->wave_rep_cnt = QPNP_HAP_WAV_REP_MIN; rc = of_property_read_u32(pdev->dev.of_node, "qcom,wave-rep-cnt", &temp); @@ -1251,6 +1350,25 @@ static ssize_t qpnp_hap_wf_s_rep_store(struct device *dev, return count; } +static int parse_string(const char *in_buf, char *out_buf) +{ + int i; + + if (snprintf(out_buf, QPNP_HAP_STR_SIZE, "%s", in_buf) + > QPNP_HAP_STR_SIZE) + return -EINVAL; + + for (i = 0; i < strlen(out_buf); i++) { + if (out_buf[i] == ' ' || out_buf[i] == '\n' || + out_buf[i] == '\t') { + out_buf[i] = '\0'; + break; + } + } + + return 0; +} + /* sysfs store function for play mode*/ static ssize_t qpnp_hap_play_mode_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -1259,17 +1377,12 @@ static ssize_t qpnp_hap_play_mode_store(struct device *dev, struct qpnp_hap *hap = container_of(timed_dev, struct qpnp_hap, timed_dev); char str[QPNP_HAP_STR_SIZE + 1]; - int rc = 0, temp, old_mode, i; + int rc = 0, temp, old_mode; - if (snprintf(str, QPNP_HAP_STR_SIZE, "%s", buf) > QPNP_HAP_STR_SIZE) - return -EINVAL; + rc = parse_string(buf, str); + if (rc < 0) + return rc; - for (i = 0; i < strlen(str); i++) { - if (str[i] == ' ' || str[i] == '\n' || str[i] == '\t') { - str[i] = '\0'; - break; - } - } if (strcmp(str, "buffer") == 0) temp = QPNP_HAP_BUFFER; else if (strcmp(str, "direct") == 0) @@ -1284,10 +1397,10 @@ static ssize_t qpnp_hap_play_mode_store(struct device *dev, if (temp == hap->play_mode) return count; - if (temp == QPNP_HAP_BUFFER && !hap->buffer_cfg_state) { + if (temp == QPNP_HAP_BUFFER) { rc = qpnp_hap_parse_buffer_dt(hap); if (!rc) - rc = qpnp_hap_buffer_config(hap); + rc = qpnp_hap_buffer_config(hap, NULL, false); } else if (temp == QPNP_HAP_PWM && !hap->pwm_cfg_state) { rc = qpnp_hap_parse_pwm_dt(hap); if (!rc) @@ -1436,6 +1549,245 @@ static ssize_t qpnp_hap_ramp_test_data_show(struct device *dev, } +static ssize_t qpnp_hap_auto_res_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct timed_output_dev *timed_dev = dev_get_drvdata(dev); + struct qpnp_hap *hap = container_of(timed_dev, struct qpnp_hap, + timed_dev); + char *str; + + if (hap->pmic_subtype == PM660_SUBTYPE) { + switch (hap->ares_cfg.auto_res_mode) { + case QPNP_HAP_PM660_AUTO_RES_ZXD: + str = "ZXD"; + break; + case QPNP_HAP_PM660_AUTO_RES_QWD: + str = "QWD"; + break; + default: + str = "None"; + break; + } + } else { + switch (hap->ares_cfg.auto_res_mode) { + case QPNP_HAP_AUTO_RES_NONE: + str = "None"; + break; + case QPNP_HAP_AUTO_RES_ZXD: + str = "ZXD"; + break; + case QPNP_HAP_AUTO_RES_QWD: + str = "QWD"; + break; + case QPNP_HAP_AUTO_RES_MAX_QWD: + str = "MAX_QWD"; + break; + case QPNP_HAP_AUTO_RES_ZXD_EOP: + str = "ZXD_EOP"; + break; + default: + str = "None"; + break; + } + } + + return snprintf(buf, PAGE_SIZE, "%s\n", str); +} + +static ssize_t qpnp_hap_auto_res_mode_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct timed_output_dev *timed_dev = dev_get_drvdata(dev); + struct qpnp_hap *hap = container_of(timed_dev, struct qpnp_hap, + timed_dev); + char str[QPNP_HAP_STR_SIZE + 1]; + int rc = 0, temp; + + rc = parse_string(buf, str); + if (rc < 0) + return rc; + + if (hap->pmic_subtype == PM660_SUBTYPE) { + if (strcmp(str, "ZXD") == 0 || + strcmp(str, "zxd") == 0) + temp = QPNP_HAP_PM660_AUTO_RES_ZXD; + else if (strcmp(str, "QWD") == 0 || + strcmp(str, "qwd") == 0) + temp = QPNP_HAP_PM660_AUTO_RES_QWD; + else { + pr_err("Should be ZXD or QWD\n"); + return -EINVAL; + } + } else { + if (strcmp(str, "None") == 0) + temp = QPNP_HAP_AUTO_RES_NONE; + else if (strcmp(str, "ZXD") == 0 || + strcmp(str, "zxd") == 0) + temp = QPNP_HAP_AUTO_RES_ZXD; + else if (strcmp(str, "QWD") == 0 || + strcmp(str, "qwd") == 0) + temp = QPNP_HAP_AUTO_RES_QWD; + else if (strcmp(str, "ZXD_EOP") == 0 || + strcmp(str, "zxd_eop") == 0) + temp = QPNP_HAP_AUTO_RES_ZXD_EOP; + else if (strcmp(str, "MAX_QWD") == 0 || + strcmp(str, "max_qwd") == 0) + temp = QPNP_HAP_AUTO_RES_MAX_QWD; + else { + pr_err("Should be None or ZXD or QWD or ZXD_EOP or MAX_QWD\n"); + return -EINVAL; + } + } + + hap->ares_cfg.auto_res_mode = temp; + return count; +} + +static ssize_t qpnp_hap_hi_z_period_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct timed_output_dev *timed_dev = dev_get_drvdata(dev); + struct qpnp_hap *hap = container_of(timed_dev, struct qpnp_hap, + timed_dev); + char *str; + + switch (hap->ares_cfg.lra_high_z) { + case QPNP_HAP_LRA_HIGH_Z_NONE: + str = "high_z_none"; + break; + case QPNP_HAP_LRA_HIGH_Z_OPT1: + str = "high_z_opt1"; + break; + case QPNP_HAP_LRA_HIGH_Z_OPT2: + str = "high_z_opt2"; + break; + case QPNP_HAP_LRA_HIGH_Z_OPT3: + str = "high_z_opt3"; + break; + } + + return snprintf(buf, PAGE_SIZE, "%s\n", str); +} + +static ssize_t qpnp_hap_hi_z_period_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct timed_output_dev *timed_dev = dev_get_drvdata(dev); + struct qpnp_hap *hap = container_of(timed_dev, struct qpnp_hap, + timed_dev); + int data, rc; + + rc = kstrtoint(buf, 10, &data); + if (rc) + return rc; + + if (data < QPNP_HAP_LRA_HIGH_Z_NONE + || data > QPNP_HAP_LRA_HIGH_Z_OPT3) { + pr_err("Invalid high Z configuration\n"); + return -EINVAL; + } + + hap->ares_cfg.lra_high_z = data; + return count; +} + +static ssize_t qpnp_hap_calib_period_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct timed_output_dev *timed_dev = dev_get_drvdata(dev); + struct qpnp_hap *hap = container_of(timed_dev, struct qpnp_hap, + timed_dev); + + return snprintf(buf, PAGE_SIZE, "%d\n", + hap->ares_cfg.lra_res_cal_period); +} + +static ssize_t qpnp_hap_calib_period_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct timed_output_dev *timed_dev = dev_get_drvdata(dev); + struct qpnp_hap *hap = container_of(timed_dev, struct qpnp_hap, + timed_dev); + int data, rc; + + rc = kstrtoint(buf, 10, &data); + if (rc) + return rc; + + if (data < QPNP_HAP_RES_CAL_PERIOD_MIN) { + pr_err("Invalid auto resonance calibration period\n"); + return -EINVAL; + } + + if (hap->pmic_subtype == PM660_SUBTYPE) { + if (data > QPNP_HAP_PM660_RES_CAL_PERIOD_MAX) { + pr_err("Invalid auto resonance calibration period\n"); + return -EINVAL; + } + } else { + if (data > QPNP_HAP_RES_CAL_PERIOD_MAX) { + pr_err("Invalid auto resonance calibration period\n"); + return -EINVAL; + } + } + + hap->ares_cfg.lra_res_cal_period = data; + return count; +} + +static ssize_t qpnp_hap_override_auto_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct timed_output_dev *timed_dev = dev_get_drvdata(dev); + struct qpnp_hap *hap = container_of(timed_dev, struct qpnp_hap, + timed_dev); + + return snprintf(buf, PAGE_SIZE, "%d\n", hap->override_auto_mode_config); +} + +static ssize_t qpnp_hap_override_auto_mode_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct timed_output_dev *timed_dev = dev_get_drvdata(dev); + struct qpnp_hap *hap = container_of(timed_dev, struct qpnp_hap, + timed_dev); + int data, rc; + + rc = kstrtoint(buf, 10, &data); + if (rc) + return rc; + + hap->override_auto_mode_config = data; + return count; +} + +static ssize_t qpnp_hap_vmax_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct timed_output_dev *timed_dev = dev_get_drvdata(dev); + struct qpnp_hap *hap = container_of(timed_dev, struct qpnp_hap, + timed_dev); + + return snprintf(buf, PAGE_SIZE, "%d\n", hap->vmax_mv); +} + +static ssize_t qpnp_hap_vmax_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct timed_output_dev *timed_dev = dev_get_drvdata(dev); + struct qpnp_hap *hap = container_of(timed_dev, struct qpnp_hap, + timed_dev); + int data, rc; + + rc = kstrtoint(buf, 10, &data); + if (rc) + return rc; + + hap->vmax_mv = data; + return count; +} + /* sysfs attributes */ static struct device_attribute qpnp_hap_attrs[] = { __ATTR(wf_s0, 0664, qpnp_hap_wf_s0_show, qpnp_hap_wf_s0_store), @@ -1457,6 +1809,16 @@ static struct device_attribute qpnp_hap_attrs[] = { qpnp_hap_ramp_test_data_store), __ATTR(min_max_test, 0664, qpnp_hap_min_max_test_data_show, qpnp_hap_min_max_test_data_store), + __ATTR(auto_res_mode, 0664, qpnp_hap_auto_res_mode_show, + qpnp_hap_auto_res_mode_store), + __ATTR(high_z_period, 0664, qpnp_hap_hi_z_period_show, + qpnp_hap_hi_z_period_store), + __ATTR(calib_period, 0664, qpnp_hap_calib_period_show, + qpnp_hap_calib_period_store), + __ATTR(override_auto_mode_config, 0664, + qpnp_hap_override_auto_mode_show, + qpnp_hap_override_auto_mode_store), + __ATTR(vmax_mv, 0664, qpnp_hap_vmax_show, qpnp_hap_vmax_store), }; static int calculate_lra_code(struct qpnp_hap *hap) @@ -1515,9 +1877,47 @@ static int calculate_lra_code(struct qpnp_hap *hap) static int qpnp_hap_auto_res_enable(struct qpnp_hap *hap, int enable) { int rc = 0; - u8 val; + u32 back_emf_delay_us = hap->time_required_to_generate_back_emf_us; + u8 val, auto_res_mode_qwd; + + if (hap->act_type != QPNP_HAP_LRA) + return 0; + + if (hap->pmic_subtype == PM660_SUBTYPE) + auto_res_mode_qwd = (hap->ares_cfg.auto_res_mode == + QPNP_HAP_PM660_AUTO_RES_QWD); + else + auto_res_mode_qwd = (hap->ares_cfg.auto_res_mode == + QPNP_HAP_AUTO_RES_QWD); + + /* + * Do not enable auto resonance if auto mode is enabled and auto + * resonance mode is QWD, meaning short pattern. + */ + if (hap->auto_mode && auto_res_mode_qwd && enable) { + pr_debug("auto_mode enabled, not enabling auto_res\n"); + return 0; + } + + if (!hap->correct_lra_drive_freq && !auto_res_mode_qwd) { + pr_debug("correct_lra_drive_freq: %d auto_res_mode_qwd: %d\n", + hap->correct_lra_drive_freq, auto_res_mode_qwd); + return 0; + } val = enable ? AUTO_RES_ENABLE : 0; + /* + * For auto resonance detection to work properly, sufficient back-emf + * has to be generated. In general, back-emf takes some time to build + * up. When the auto resonance mode is chosen as QWD, high-z will be + * applied for every LRA cycle and hence there won't be enough back-emf + * at the start-up. Hence, the motor needs to vibrate for few LRA cycles + * after the PLAY bit is asserted. Enable the auto resonance after + * 'time_required_to_generate_back_emf_us' is completed. + */ + if (enable) + usleep_range(back_emf_delay_us, back_emf_delay_us + 1); + if (hap->pmic_subtype == PM660_SUBTYPE) rc = qpnp_hap_masked_write_reg(hap, QPNP_HAP_AUTO_RES_CTRL(hap->base), @@ -1534,6 +1934,7 @@ static int qpnp_hap_auto_res_enable(struct qpnp_hap *hap, int enable) else hap->status_flags &= ~AUTO_RESONANCE_ENABLED; + pr_debug("auto_res %sabled\n", enable ? "en" : "dis"); return rc; } @@ -1617,65 +2018,57 @@ static enum hrtimer_restart detect_auto_res_error(struct hrtimer *timer) return HRTIMER_RESTART; } +static bool is_sw_lra_auto_resonance_control(struct qpnp_hap *hap) +{ + if (hap->act_type != QPNP_HAP_LRA) + return false; + + if (hap->lra_hw_auto_resonance) + return false; + + if (!hap->correct_lra_drive_freq) + return false; + + if (hap->auto_mode && hap->play_mode == QPNP_HAP_BUFFER) + return false; + + return true; +} + /* set api for haptics */ -static int qpnp_hap_set(struct qpnp_hap *hap, int on) +static int qpnp_hap_set(struct qpnp_hap *hap, bool on) { - u8 auto_res_mode_qwd; int rc = 0; unsigned long timeout_ns = POLL_TIME_AUTO_RES_ERR_NS; - u32 back_emf_delay_us = hap->time_required_to_generate_back_emf_us; if (hap->play_mode == QPNP_HAP_PWM) { - if (on) + if (on) { rc = pwm_enable(hap->pwm_info.pwm_dev); - else + if (rc < 0) + return rc; + } else { pwm_disable(hap->pwm_info.pwm_dev); + } } else if (hap->play_mode == QPNP_HAP_BUFFER || hap->play_mode == QPNP_HAP_DIRECT) { if (on) { - /* - * For auto resonance detection to work properly, - * sufficient back-emf has to be generated. In general, - * back-emf takes some time to build up. When the auto - * resonance mode is chosen as QWD, high-z will be - * applied for every LRA cycle and hence there won't be - * enough back-emf at the start-up. Hence, the motor - * needs to vibrate for few LRA cycles after the PLAY - * bit is asserted. So disable the auto resonance here - * and enable it after the sleep of - * 'time_required_to_generate_back_emf_us' is completed. - */ - if (hap->pmic_subtype == PM660_SUBTYPE) - auto_res_mode_qwd = (hap->auto_res_mode == - QPNP_HAP_PM660_AUTO_RES_QWD); - else - auto_res_mode_qwd = (hap->auto_res_mode == - QPNP_HAP_AUTO_RES_QWD); - - if ((hap->act_type == QPNP_HAP_LRA) && - (hap->correct_lra_drive_freq || - auto_res_mode_qwd)) - qpnp_hap_auto_res_enable(hap, 0); + rc = qpnp_hap_auto_res_enable(hap, 0); + if (rc < 0) + return rc; rc = qpnp_hap_mod_enable(hap, on); if (rc < 0) return rc; rc = qpnp_hap_play(hap, on); + if (rc < 0) + return rc; - if ((hap->act_type == QPNP_HAP_LRA) && - (hap->correct_lra_drive_freq || - auto_res_mode_qwd)) { - usleep_range(back_emf_delay_us, - (back_emf_delay_us + 1)); + rc = qpnp_hap_auto_res_enable(hap, 1); + if (rc < 0) + return rc; - rc = qpnp_hap_auto_res_enable(hap, 1); - if (rc < 0) - return rc; - } - if (hap->act_type == QPNP_HAP_LRA && - hap->correct_lra_drive_freq && - !hap->lra_hw_auto_resonance) { + if (is_sw_lra_auto_resonance_control(hap)) { /* * Start timer to poll Auto Resonance error bit */ @@ -1683,7 +2076,7 @@ static int qpnp_hap_set(struct qpnp_hap *hap, int on) hrtimer_cancel(&hap->auto_res_err_poll_timer); hrtimer_start(&hap->auto_res_err_poll_timer, ktime_set(0, timeout_ns), - HRTIMER_MODE_REL); + HRTIMER_MODE_REL); mutex_unlock(&hap->lock); } } else { @@ -1691,54 +2084,182 @@ static int qpnp_hap_set(struct qpnp_hap *hap, int on) if (rc < 0) return rc; - if (hap->act_type == QPNP_HAP_LRA && - hap->correct_lra_drive_freq && - (hap->status_flags & AUTO_RESONANCE_ENABLED) && - !hap->lra_hw_auto_resonance) { + if (is_sw_lra_auto_resonance_control(hap) && + (hap->status_flags & AUTO_RESONANCE_ENABLED)) update_lra_frequency(hap); - } rc = qpnp_hap_mod_enable(hap, on); - if (hap->act_type == QPNP_HAP_LRA && - hap->correct_lra_drive_freq && - !hap->lra_hw_auto_resonance) { + if (rc < 0) + return rc; + + if (is_sw_lra_auto_resonance_control(hap)) hrtimer_cancel(&hap->auto_res_err_poll_timer); - } } } return rc; } +static int qpnp_hap_auto_mode_config(struct qpnp_hap *hap, int time_ms) +{ + struct qpnp_hap_lra_ares_cfg ares_cfg; + enum qpnp_hap_mode old_play_mode; + u8 old_ares_mode; + u8 brake_pat[QPNP_HAP_BRAKE_PAT_LEN] = {0}; + u8 wave_samp[QPNP_HAP_WAV_SAMP_LEN] = {0}; + int rc, vmax_mv; + + /* For now, this is for LRA only */ + if (hap->act_type == QPNP_HAP_ERM) + return 0; + + old_ares_mode = hap->ares_cfg.auto_res_mode; + old_play_mode = hap->play_mode; + pr_debug("auto_mode, time_ms: %d\n", time_ms); + if (time_ms <= 20) { + wave_samp[0] = QPNP_HAP_WAV_SAMP_MAX; + wave_samp[1] = QPNP_HAP_WAV_SAMP_MAX; + if (time_ms > 15) + wave_samp[2] = QPNP_HAP_WAV_SAMP_MAX; + + /* short pattern */ + rc = qpnp_hap_parse_buffer_dt(hap); + if (!rc) + rc = qpnp_hap_buffer_config(hap, wave_samp, true); + if (rc < 0) { + pr_err("Error in configuring buffer mode %d\n", + rc); + return rc; + } + + ares_cfg.lra_high_z = QPNP_HAP_LRA_HIGH_Z_OPT1; + ares_cfg.lra_res_cal_period = QPNP_HAP_RES_CAL_PERIOD_MIN; + if (hap->pmic_subtype == PM660_SUBTYPE) { + ares_cfg.auto_res_mode = + QPNP_HAP_PM660_AUTO_RES_QWD; + ares_cfg.lra_qwd_drive_duration = 0; + ares_cfg.calibrate_at_eop = 0; + } else { + ares_cfg.auto_res_mode = QPNP_HAP_AUTO_RES_QWD; + ares_cfg.lra_qwd_drive_duration = -EINVAL; + ares_cfg.calibrate_at_eop = -EINVAL; + } + + vmax_mv = QPNP_HAP_VMAX_MAX_MV; + rc = qpnp_hap_vmax_config(hap, vmax_mv, true); + if (rc < 0) + return rc; + + rc = qpnp_hap_brake_config(hap, brake_pat); + if (rc < 0) + return rc; + + /* enable play_irq for buffer mode */ + if (hap->play_irq >= 0 && !hap->play_irq_en) { + enable_irq(hap->play_irq); + hap->play_irq_en = true; + } + + hap->play_mode = QPNP_HAP_BUFFER; + hap->wave_shape = QPNP_HAP_WAV_SQUARE; + } else { + /* long pattern */ + ares_cfg.lra_high_z = QPNP_HAP_LRA_HIGH_Z_OPT1; + if (hap->pmic_subtype == PM660_SUBTYPE) { + ares_cfg.auto_res_mode = + QPNP_HAP_PM660_AUTO_RES_ZXD; + ares_cfg.lra_res_cal_period = + QPNP_HAP_PM660_RES_CAL_PERIOD_MAX; + ares_cfg.lra_qwd_drive_duration = 0; + ares_cfg.calibrate_at_eop = 1; + } else { + ares_cfg.auto_res_mode = QPNP_HAP_AUTO_RES_ZXD_EOP; + ares_cfg.lra_res_cal_period = + QPNP_HAP_RES_CAL_PERIOD_MAX; + ares_cfg.lra_qwd_drive_duration = -EINVAL; + ares_cfg.calibrate_at_eop = -EINVAL; + } + + vmax_mv = hap->vmax_mv; + rc = qpnp_hap_vmax_config(hap, vmax_mv, false); + if (rc < 0) + return rc; + + brake_pat[0] = 0x3; + rc = qpnp_hap_brake_config(hap, brake_pat); + if (rc < 0) + return rc; + + /* enable play_irq for direct mode */ + if (hap->play_irq >= 0 && hap->play_irq_en) { + disable_irq(hap->play_irq); + hap->play_irq_en = false; + } + + hap->play_mode = QPNP_HAP_DIRECT; + hap->wave_shape = QPNP_HAP_WAV_SINE; + } + + if (hap->override_auto_mode_config) { + rc = qpnp_hap_lra_auto_res_config(hap, NULL); + } else { + hap->ares_cfg.auto_res_mode = ares_cfg.auto_res_mode; + rc = qpnp_hap_lra_auto_res_config(hap, &ares_cfg); + } + + if (rc < 0) { + hap->ares_cfg.auto_res_mode = old_ares_mode; + return rc; + } + + rc = qpnp_hap_play_mode_config(hap); + if (rc < 0) { + hap->play_mode = old_play_mode; + return rc; + } + + rc = qpnp_hap_masked_write_reg(hap, QPNP_HAP_CFG2_REG(hap->base), + QPNP_HAP_WAV_SHAPE_MASK, hap->wave_shape); + if (rc < 0) + return rc; + + return 0; +} + /* enable interface from timed output class */ -static void qpnp_hap_td_enable(struct timed_output_dev *dev, int value) +static void qpnp_hap_td_enable(struct timed_output_dev *dev, int time_ms) { struct qpnp_hap *hap = container_of(dev, struct qpnp_hap, timed_dev); + int rc; - mutex_lock(&hap->lock); + if (time_ms <= 0) + return; - if (hap->act_type == QPNP_HAP_LRA && - hap->correct_lra_drive_freq && - !hap->lra_hw_auto_resonance) + if (time_ms < 10) + time_ms = 10; + + mutex_lock(&hap->lock); + if (is_sw_lra_auto_resonance_control(hap)) hrtimer_cancel(&hap->auto_res_err_poll_timer); hrtimer_cancel(&hap->hap_timer); - if (value == 0) { - if (hap->state == 0) { + if (hap->auto_mode) { + rc = qpnp_hap_auto_mode_config(hap, time_ms); + if (rc < 0) { + pr_err("Unable to do auto mode config\n"); mutex_unlock(&hap->lock); return; } - hap->state = 0; - } else { - value = (value > hap->timeout_ms ? - hap->timeout_ms : value); - hap->state = 1; - hrtimer_start(&hap->hap_timer, - ktime_set(value / 1000, (value % 1000) * 1000000), - HRTIMER_MODE_REL); } + + time_ms = (time_ms > hap->timeout_ms ? hap->timeout_ms : time_ms); + hap->play_time_ms = time_ms; + hap->state = 1; + hrtimer_start(&hap->hap_timer, + ktime_set(time_ms / 1000, (time_ms % 1000) * 1000000), + HRTIMER_MODE_REL); mutex_unlock(&hap->lock); schedule_work(&hap->work); } @@ -1824,7 +2345,7 @@ static void qpnp_hap_worker(struct work_struct *work) /* Disable haptics module if the duration of short circuit * exceeds the maximum limit (5 secs). */ - if (hap->sc_duration == SC_MAX_DURATION) { + if (hap->sc_count >= SC_MAX_COUNT) { rc = qpnp_hap_write_reg(hap, QPNP_HAP_EN_CTL_REG(hap->base), val); } else { @@ -1890,7 +2411,7 @@ static int qpnp_haptic_suspend(struct device *dev) hrtimer_cancel(&hap->hap_timer); cancel_work_sync(&hap->work); /* turn-off haptic */ - qpnp_hap_set(hap, 0); + qpnp_hap_set(hap, false); return 0; } @@ -1902,8 +2423,7 @@ static SIMPLE_DEV_PM_OPS(qpnp_haptic_pm_ops, qpnp_haptic_suspend, NULL); static int qpnp_hap_config(struct qpnp_hap *hap) { u8 val = 0; - u32 temp; - int rc, i; + int rc; /* * This denotes the percentage error in rc clock multiplied by 10 @@ -1917,7 +2437,7 @@ static int qpnp_hap_config(struct qpnp_hap *hap) return rc; /* Configure auto resonance parameters */ - rc = qpnp_hap_lra_auto_res_config(hap); + rc = qpnp_hap_lra_auto_res_config(hap, NULL); if (rc) return rc; @@ -1927,7 +2447,7 @@ static int qpnp_hap_config(struct qpnp_hap *hap) return rc; /* Configure the VMAX register */ - rc = qpnp_hap_vmax_config(hap); + rc = qpnp_hap_vmax_config(hap, hap->vmax_mv, false); if (rc) return rc; @@ -2037,32 +2557,12 @@ static int qpnp_hap_config(struct qpnp_hap *hap) hap->drive_period_code_min_limit); } - /* Configure BRAKE register */ - rc = qpnp_hap_masked_write_reg(hap, QPNP_HAP_EN_CTL2_REG(hap->base), - QPNP_HAP_BRAKE_MASK, (u8)hap->en_brake); - if (rc) - return rc; - - if (hap->en_brake && hap->sup_brake_pat) { - for (i = QPNP_HAP_BRAKE_PAT_LEN - 1, val = 0; i >= 0; i--) { - hap->brake_pat[i] &= QPNP_HAP_BRAKE_PAT_MASK; - temp = i << 1; - val |= hap->brake_pat[i] << temp; - } - rc = qpnp_hap_write_reg(hap, QPNP_HAP_BRAKE_REG(hap->base), - val); - if (rc) - return rc; - } - - /* Cache play register */ - rc = qpnp_hap_read_reg(hap, QPNP_HAP_PLAY_REG(hap->base), &val); + rc = qpnp_hap_brake_config(hap, NULL); if (rc < 0) return rc; - hap->reg_play = val; if (hap->play_mode == QPNP_HAP_BUFFER) - rc = qpnp_hap_buffer_config(hap); + rc = qpnp_hap_buffer_config(hap, NULL, false); else if (hap->play_mode == QPNP_HAP_PWM) rc = qpnp_hap_pwm_config(hap); else if (hap->play_mode == QPNP_HAP_AUDIO) @@ -2083,8 +2583,10 @@ static int qpnp_hap_config(struct qpnp_hap *hap) } /* use play_irq only for buffer mode */ - if (hap->play_mode != QPNP_HAP_BUFFER) + if (hap->play_mode != QPNP_HAP_BUFFER) { disable_irq(hap->play_irq); + hap->play_irq_en = false; + } } /* setup short circuit irq */ @@ -2099,7 +2601,7 @@ static int qpnp_hap_config(struct qpnp_hap *hap) } } - hap->sc_duration = 0; + hap->sc_count = 0; return rc; } @@ -2173,30 +2675,31 @@ static int qpnp_hap_parse_dt(struct qpnp_hap *hap) "qcom,lra-auto-res-mode", &temp_str); if (!rc) { if (hap->pmic_subtype == PM660_SUBTYPE) { - hap->auto_res_mode = + hap->ares_cfg.auto_res_mode = QPNP_HAP_PM660_AUTO_RES_QWD; if (strcmp(temp_str, "zxd") == 0) - hap->auto_res_mode = + hap->ares_cfg.auto_res_mode = QPNP_HAP_PM660_AUTO_RES_ZXD; else if (strcmp(temp_str, "qwd") == 0) - hap->auto_res_mode = + hap->ares_cfg.auto_res_mode = QPNP_HAP_PM660_AUTO_RES_QWD; } else { - hap->auto_res_mode = QPNP_HAP_AUTO_RES_ZXD_EOP; + hap->ares_cfg.auto_res_mode = + QPNP_HAP_AUTO_RES_ZXD_EOP; if (strcmp(temp_str, "none") == 0) - hap->auto_res_mode = + hap->ares_cfg.auto_res_mode = QPNP_HAP_AUTO_RES_NONE; else if (strcmp(temp_str, "zxd") == 0) - hap->auto_res_mode = + hap->ares_cfg.auto_res_mode = QPNP_HAP_AUTO_RES_ZXD; else if (strcmp(temp_str, "qwd") == 0) - hap->auto_res_mode = + hap->ares_cfg.auto_res_mode = QPNP_HAP_AUTO_RES_QWD; else if (strcmp(temp_str, "max-qwd") == 0) - hap->auto_res_mode = + hap->ares_cfg.auto_res_mode = QPNP_HAP_AUTO_RES_MAX_QWD; else - hap->auto_res_mode = + hap->ares_cfg.auto_res_mode = QPNP_HAP_AUTO_RES_ZXD_EOP; } } else if (rc != -EINVAL) { @@ -2204,42 +2707,48 @@ static int qpnp_hap_parse_dt(struct qpnp_hap *hap) return rc; } - hap->lra_high_z = QPNP_HAP_LRA_HIGH_Z_OPT3; + hap->ares_cfg.lra_high_z = QPNP_HAP_LRA_HIGH_Z_OPT3; rc = of_property_read_string(pdev->dev.of_node, "qcom,lra-high-z", &temp_str); if (!rc) { if (strcmp(temp_str, "none") == 0) - hap->lra_high_z = QPNP_HAP_LRA_HIGH_Z_NONE; + hap->ares_cfg.lra_high_z = + QPNP_HAP_LRA_HIGH_Z_NONE; + else if (strcmp(temp_str, "opt1") == 0) + hap->ares_cfg.lra_high_z = + QPNP_HAP_LRA_HIGH_Z_OPT1; + else if (strcmp(temp_str, "opt2") == 0) + hap->ares_cfg.lra_high_z = + QPNP_HAP_LRA_HIGH_Z_OPT2; + else + hap->ares_cfg.lra_high_z = + QPNP_HAP_LRA_HIGH_Z_OPT3; + if (hap->pmic_subtype == PM660_SUBTYPE) { if (strcmp(temp_str, "opt0") == 0) - hap->lra_high_z = + hap->ares_cfg.lra_high_z = QPNP_HAP_LRA_HIGH_Z_NONE; } - else if (strcmp(temp_str, "opt1") == 0) - hap->lra_high_z = QPNP_HAP_LRA_HIGH_Z_OPT1; - else if (strcmp(temp_str, "opt2") == 0) - hap->lra_high_z = QPNP_HAP_LRA_HIGH_Z_OPT2; - else - hap->lra_high_z = QPNP_HAP_LRA_HIGH_Z_OPT3; } else if (rc != -EINVAL) { pr_err("Unable to read LRA high-z\n"); return rc; } - hap->lra_qwd_drive_duration = -EINVAL; + hap->ares_cfg.lra_qwd_drive_duration = -EINVAL; rc = of_property_read_u32(pdev->dev.of_node, "qcom,lra-qwd-drive-duration", - &hap->lra_qwd_drive_duration); + &hap->ares_cfg.lra_qwd_drive_duration); - hap->calibrate_at_eop = -EINVAL; + hap->ares_cfg.calibrate_at_eop = -EINVAL; rc = of_property_read_u32(pdev->dev.of_node, - "qcom,lra-calibrate-at-eop", &hap->calibrate_at_eop); + "qcom,lra-calibrate-at-eop", + &hap->ares_cfg.calibrate_at_eop); - hap->lra_res_cal_period = QPNP_HAP_RES_CAL_PERIOD_MAX; + hap->ares_cfg.lra_res_cal_period = QPNP_HAP_RES_CAL_PERIOD_MAX; rc = of_property_read_u32(pdev->dev.of_node, "qcom,lra-res-cal-period", &temp); if (!rc) { - hap->lra_res_cal_period = temp; + hap->ares_cfg.lra_res_cal_period = temp; } else if (rc != -EINVAL) { pr_err("Unable to read cal period\n"); return rc; @@ -2271,7 +2780,7 @@ static int qpnp_hap_parse_dt(struct qpnp_hap *hap) hap->drive_period_code_min_limit_percent_variation = (u8) temp; - if (hap->auto_res_mode == QPNP_HAP_AUTO_RES_QWD) { + if (hap->ares_cfg.auto_res_mode == QPNP_HAP_AUTO_RES_QWD) { hap->time_required_to_generate_back_emf_us = QPNP_HAP_TIME_REQ_FOR_BACK_EMF_GEN; rc = of_property_read_u32(pdev->dev.of_node, @@ -2409,6 +2918,8 @@ static int qpnp_hap_parse_dt(struct qpnp_hap *hap) if (of_find_property(pdev->dev.of_node, "vcc_pon-supply", NULL)) hap->manage_pon_supply = true; + hap->auto_mode = of_property_read_bool(pdev->dev.of_node, + "qcom,lra-auto-mode"); return 0; } @@ -2503,12 +3014,9 @@ static int qpnp_haptic_probe(struct platform_device *pdev) hap->timed_dev.get_time = qpnp_hap_get_time; hap->timed_dev.enable = qpnp_hap_td_enable; - if (hap->act_type == QPNP_HAP_LRA && hap->correct_lra_drive_freq && - !hap->lra_hw_auto_resonance) { - hrtimer_init(&hap->auto_res_err_poll_timer, CLOCK_MONOTONIC, - HRTIMER_MODE_REL); - hap->auto_res_err_poll_timer.function = detect_auto_res_error; - } + hrtimer_init(&hap->auto_res_err_poll_timer, CLOCK_MONOTONIC, + HRTIMER_MODE_REL); + hap->auto_res_err_poll_timer.function = detect_auto_res_error; rc = timed_output_dev_register(&hap->timed_dev); if (rc < 0) { @@ -2546,9 +3054,7 @@ sysfs_fail: timed_output_dev_unregister(&hap->timed_dev); timed_output_fail: cancel_work_sync(&hap->work); - if (hap->act_type == QPNP_HAP_LRA && hap->correct_lra_drive_freq && - !hap->lra_hw_auto_resonance) - hrtimer_cancel(&hap->auto_res_err_poll_timer); + hrtimer_cancel(&hap->auto_res_err_poll_timer); hrtimer_cancel(&hap->hap_timer); mutex_destroy(&hap->lock); mutex_destroy(&hap->wf_lock); @@ -2566,9 +3072,7 @@ static int qpnp_haptic_remove(struct platform_device *pdev) &qpnp_hap_attrs[i].attr); cancel_work_sync(&hap->work); - if (hap->act_type == QPNP_HAP_LRA && hap->correct_lra_drive_freq && - !hap->lra_hw_auto_resonance) - hrtimer_cancel(&hap->auto_res_err_poll_timer); + hrtimer_cancel(&hap->auto_res_err_poll_timer); hrtimer_cancel(&hap->hap_timer); timed_output_dev_unregister(&hap->timed_dev); mutex_destroy(&hap->lock); 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/smcinvoke.c b/drivers/soc/qcom/smcinvoke.c index 99ae24735f05..f69ff47ae0f7 100644 --- a/drivers/soc/qcom/smcinvoke.c +++ b/drivers/soc/qcom/smcinvoke.c @@ -429,10 +429,17 @@ long smcinvoke_ioctl(struct file *filp, unsigned cmd, unsigned long arg) if (ret) goto out; - ret = marshal_out(in_msg, inmsg_size, &req, args_buf); + /* + * if invoke op results in an err, no need to marshal_out and + * copy args buf to user space + */ + if (!req.result) { + ret = marshal_out(in_msg, inmsg_size, &req, args_buf); - ret |= copy_to_user((void __user *)(uintptr_t)(req.args), + ret |= copy_to_user( + (void __user *)(uintptr_t)(req.args), args_buf, nr_args * req.argsize); + } ret |= copy_to_user((void __user *)arg, &req, sizeof(req)); if (ret) goto out; 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/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c index 58bf3d2f52bd..49ed6de1a95e 100644 --- a/drivers/staging/android/ion/ion.c +++ b/drivers/staging/android/ion/ion.c @@ -3,7 +3,7 @@ * drivers/staging/android/ion/ion.c * * Copyright (C) 2011 Google, Inc. - * Copyright (c) 2011-2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -122,8 +122,6 @@ struct ion_handle { int id; }; -static struct ion_device *ion_dev; - bool ion_buffer_fault_user_mappings(struct ion_buffer *buffer) { return (buffer->flags & ION_FLAG_CACHED) && @@ -844,32 +842,45 @@ void ion_unmap_kernel(struct ion_client *client, struct ion_handle *handle) } EXPORT_SYMBOL(ion_unmap_kernel); -static int ion_debug_client_show(struct seq_file *s, void *unused) +static struct mutex debugfs_mutex; +static struct rb_root *ion_root_client; +static int is_client_alive(struct ion_client *client) { - struct ion_client *client = s->private; - struct rb_node *n, *cnode; - bool found = false; - - down_write(&ion_dev->lock); + struct rb_node *node; + struct ion_client *tmp; + struct ion_device *dev; - if (!client || (client->dev != ion_dev)) { - up_write(&ion_dev->lock); - return -EINVAL; - } + node = ion_root_client->rb_node; + dev = container_of(ion_root_client, struct ion_device, clients); - cnode = rb_first(&ion_dev->clients); - for ( ; cnode; cnode = rb_next(cnode)) { - struct ion_client *c = rb_entry(cnode, - struct ion_client, node); - if (client == c) { - found = true; - break; + down_read(&dev->lock); + while (node) { + tmp = rb_entry(node, struct ion_client, node); + if (client < tmp) { + node = node->rb_left; + } else if (client > tmp) { + node = node->rb_right; + } else { + up_read(&dev->lock); + return 1; } } - if (!found) { - up_write(&ion_dev->lock); - return -EINVAL; + up_read(&dev->lock); + return 0; +} + +static int ion_debug_client_show(struct seq_file *s, void *unused) +{ + struct ion_client *client = s->private; + struct rb_node *n; + + mutex_lock(&debugfs_mutex); + if (!is_client_alive(client)) { + seq_printf(s, "ion_client 0x%pK dead, can't dump its buffers\n", + client); + mutex_unlock(&debugfs_mutex); + return 0; } seq_printf(s, "%16.16s: %16.16s : %16.16s : %12.12s\n", @@ -890,7 +901,7 @@ static int ion_debug_client_show(struct seq_file *s, void *unused) seq_printf(s, "\n"); } mutex_unlock(&client->lock); - up_write(&ion_dev->lock); + mutex_unlock(&debugfs_mutex); return 0; } @@ -1021,7 +1032,7 @@ void ion_client_destroy(struct ion_client *client) struct rb_node *n; pr_debug("%s: %d\n", __func__, __LINE__); - mutex_lock(&client->lock); + mutex_lock(&debugfs_mutex); while ((n = rb_first(&client->handles))) { struct ion_handle *handle = rb_entry(n, struct ion_handle, node); @@ -1029,7 +1040,6 @@ void ion_client_destroy(struct ion_client *client) } idr_destroy(&client->idr); - mutex_unlock(&client->lock); down_write(&dev->lock); if (client->task) @@ -1042,6 +1052,7 @@ void ion_client_destroy(struct ion_client *client) kfree(client->display_name); kfree(client->name); kfree(client); + mutex_unlock(&debugfs_mutex); } EXPORT_SYMBOL(ion_client_destroy); @@ -1462,6 +1473,28 @@ int ion_share_dma_buf_fd(struct ion_client *client, struct ion_handle *handle) } EXPORT_SYMBOL(ion_share_dma_buf_fd); +bool ion_dma_buf_is_secure(struct dma_buf *dmabuf) +{ + struct ion_buffer *buffer; + enum ion_heap_type type; + + /* Return false if we didn't create the buffer */ + if (!dmabuf || dmabuf->ops != &dma_buf_ops) + return false; + + buffer = dmabuf->priv; + + if (!buffer || !buffer->heap) + return false; + + type = buffer->heap->type; + + return (type == (enum ion_heap_type)ION_HEAP_TYPE_SECURE_DMA || + type == (enum ion_heap_type)ION_HEAP_TYPE_SYSTEM_SECURE) ? + true : false; +} +EXPORT_SYMBOL(ion_dma_buf_is_secure); + struct ion_handle *ion_import_dma_buf(struct ion_client *client, int fd) { struct dma_buf *dmabuf; @@ -1838,7 +1871,7 @@ static int ion_debug_heap_show(struct seq_file *s, void *unused) seq_printf(s, "%16s %16s %16s\n", "client", "pid", "size"); seq_puts(s, "----------------------------------------------------\n"); - down_read(&dev->lock); + mutex_lock(&debugfs_mutex); for (n = rb_first(&dev->clients); n; n = rb_next(n)) { struct ion_client *client = rb_entry(n, struct ion_client, node); @@ -1857,7 +1890,8 @@ static int ion_debug_heap_show(struct seq_file *s, void *unused) client->pid, size); } } - up_read(&dev->lock); + mutex_unlock(&debugfs_mutex); + seq_puts(s, "----------------------------------------------------\n"); seq_puts(s, "orphaned allocations (info is from last known client):\n"); mutex_lock(&dev->buffer_lock); @@ -2095,7 +2129,8 @@ debugfs_done: init_rwsem(&idev->lock); plist_head_init(&idev->heaps); idev->clients = RB_ROOT; - ion_dev = idev; + ion_root_client = &idev->clients; + mutex_init(&debugfs_mutex); return idev; } EXPORT_SYMBOL(ion_device_create); diff --git a/drivers/staging/android/ion/ion.h b/drivers/staging/android/ion/ion.h index 5f99ea16617a..73902ebafca6 100644 --- a/drivers/staging/android/ion/ion.h +++ b/drivers/staging/android/ion/ion.h @@ -2,7 +2,7 @@ * drivers/staging/android/ion/ion.h * * Copyright (C) 2011 Google, Inc. - * Copyright (c) 2011-2014, The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2014,2017 The Linux Foundation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -209,6 +209,16 @@ int ion_share_dma_buf_fd(struct ion_client *client, struct ion_handle *handle); */ struct ion_handle *ion_import_dma_buf(struct ion_client *client, int fd); +/** + * ion_dma_buf_is_secure() - Returns true if the dma buf is secure + * dmabuf + * @dmabuf: pointer to a dma-buf + * + * Given a dma-buf pointer, return true if ion created it and it is from + * a secure heap. + */ +bool ion_dma_buf_is_secure(struct dma_buf *dmabuf); + #else static inline void ion_reserve(struct ion_platform_data *data) { @@ -272,5 +282,10 @@ static inline int ion_handle_get_flags(struct ion_client *client, return -ENODEV; } +bool ion_dma_buf_is_secure(struct dma_buf *dmabuf) +{ + return false; +} + #endif /* CONFIG_ION */ #endif /* _LINUX_ION_H */ diff --git a/drivers/staging/rdma/ehca/ehca_mrmw.c b/drivers/staging/rdma/ehca/ehca_mrmw.c index f914b30999f8..4d52ca42644a 100644 --- a/drivers/staging/rdma/ehca/ehca_mrmw.c +++ b/drivers/staging/rdma/ehca/ehca_mrmw.c @@ -1921,7 +1921,7 @@ static int ehca_set_pagebuf_user2(struct ehca_mr_pginfo *pginfo, u64 *kpage) { int ret = 0; - u64 pgaddr, prev_pgaddr; + u64 pgaddr, prev_pgaddr = 0; u32 j = 0; int kpages_per_hwpage = pginfo->hwpage_size / PAGE_SIZE; int nr_kpages = kpages_per_hwpage; @@ -2417,6 +2417,7 @@ static int ehca_reg_bmap_mr_rpages(struct ehca_shca *shca, ehca_err(&shca->ib_device, "kpage alloc failed"); return -ENOMEM; } + hret = H_SUCCESS; for (top = 0; top < EHCA_MAP_ENTRIES; top++) { if (!ehca_bmap_valid(ehca_bmap->top[top])) continue; diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 83ff1724ec79..cf3da51a3536 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -5850,17 +5850,15 @@ static pci_ers_result_t serial8250_io_slot_reset(struct pci_dev *dev) static void serial8250_io_resume(struct pci_dev *dev) { struct serial_private *priv = pci_get_drvdata(dev); - const struct pciserial_board *board; + struct serial_private *new; if (!priv) return; - board = priv->board; - kfree(priv); - priv = pciserial_init_ports(dev, board); - - if (!IS_ERR(priv)) { - pci_set_drvdata(dev, priv); + new = pciserial_init_ports(dev, priv->board); + if (!IS_ERR(new)) { + pci_set_drvdata(dev, new); + kfree(priv); } } diff --git a/drivers/usb/gadget/function/f_audio_source.c b/drivers/usb/gadget/function/f_audio_source.c index a2a9185a0143..51ab794ef6f9 100644 --- a/drivers/usb/gadget/function/f_audio_source.c +++ b/drivers/usb/gadget/function/f_audio_source.c @@ -17,6 +17,7 @@ #include <linux/device.h> #include <linux/usb/audio.h> #include <linux/wait.h> +#include <linux/pm_qos.h> #include <sound/core.h> #include <sound/initval.h> #include <sound/pcm.h> @@ -268,6 +269,8 @@ struct audio_dev { /* number of frames sent since start_time */ s64 frames_sent; struct audio_source_config *config; + /* for creating and issuing QoS requests */ + struct pm_qos_request pm_qos; }; static inline struct audio_dev *func_to_audio(struct usb_function *f) @@ -740,6 +743,10 @@ static int audio_pcm_open(struct snd_pcm_substream *substream) runtime->hw.channels_max = 2; audio->substream = substream; + + /* Add the QoS request and set the latency to 0 */ + pm_qos_add_request(&audio->pm_qos, PM_QOS_CPU_DMA_LATENCY, 0); + return 0; } @@ -749,6 +756,10 @@ static int audio_pcm_close(struct snd_pcm_substream *substream) unsigned long flags; spin_lock_irqsave(&audio->lock, flags); + + /* Remove the QoS request */ + pm_qos_remove_request(&audio->pm_qos); + audio->substream = NULL; spin_unlock_irqrestore(&audio->lock, flags); diff --git a/drivers/usb/gadget/function/f_cdev.c b/drivers/usb/gadget/function/f_cdev.c index d45f4be4a075..34ec15ab9010 100644 --- a/drivers/usb/gadget/function/f_cdev.c +++ b/drivers/usb/gadget/function/f_cdev.c @@ -48,7 +48,7 @@ #define DEVICE_NAME "at_usb" #define MODULE_NAME "msm_usb_bridge" -#define NUM_INSTANCE 2 +#define NUM_INSTANCE 3 #define MAX_CDEV_INST_NAME 15 #define MAX_CDEV_FUNC_NAME 5 @@ -823,8 +823,10 @@ static void cser_free_inst(struct usb_function_instance *fi) opts = container_of(fi, struct f_cdev_opts, func_inst); - device_destroy(fcdev_classp, MKDEV(major, opts->port->minor)); - cdev_del(&opts->port->fcdev_cdev); + if (opts->port) { + device_destroy(fcdev_classp, MKDEV(major, opts->port->minor)); + cdev_del(&opts->port->fcdev_cdev); + } usb_cser_chardev_deinit(); kfree(opts->func_name); kfree(opts->port); diff --git a/drivers/usb/gadget/function/f_midi.c b/drivers/usb/gadget/function/f_midi.c index 4ebd744434c6..79f554f1fb23 100644 --- a/drivers/usb/gadget/function/f_midi.c +++ b/drivers/usb/gadget/function/f_midi.c @@ -370,7 +370,9 @@ static int f_midi_set_alt(struct usb_function *f, unsigned intf, unsigned alt) /* allocate a bunch of read buffers and queue them all at once. */ for (i = 0; i < midi->qlen && err == 0; i++) { struct usb_request *req = - midi_alloc_ep_req(midi->out_ep, midi->buflen); + midi_alloc_ep_req(midi->out_ep, + max_t(unsigned, midi->buflen, + bulk_out_desc.wMaxPacketSize)); if (req == NULL) return -ENOMEM; diff --git a/drivers/usb/gadget/function/f_mtp.c b/drivers/usb/gadget/function/f_mtp.c index 4a0b3a0aa65e..999433ae2d72 100644 --- a/drivers/usb/gadget/function/f_mtp.c +++ b/drivers/usb/gadget/function/f_mtp.c @@ -47,6 +47,7 @@ #define MTP_BULK_BUFFER_SIZE 16384 #define INTR_BUFFER_SIZE 28 #define MAX_INST_NAME_LEN 40 +#define MTP_MAX_FILE_SIZE 0xFFFFFFFFL /* String IDs */ #define INTERFACE_STRING_INDEX 0 @@ -868,14 +869,11 @@ static void send_file_work(struct work_struct *data) /* prepend MTP data header */ header = (struct mtp_data_header *)req->buf; /* - * Set length as 0xffffffff, if it is greater than - * 0xffffffff. Otherwise host will throw error, if file - * size greater than 0xffffffff being transferred. - */ - if (count > 0xffffffffLL) - header->length = 0xffffffff; - else - header->length = __cpu_to_le32(count); + * set file size with header according to + * MTP Specification v1.0 + */ + header->length = (count > MTP_MAX_FILE_SIZE) ? + MTP_MAX_FILE_SIZE : __cpu_to_le32(count); header->type = __cpu_to_le16(2); /* data packet */ header->command = __cpu_to_le16(dev->xfer_command); header->transaction_id = @@ -1490,6 +1488,7 @@ mtp_function_bind(struct usb_configuration *c, struct usb_function *f) mtp_fullspeed_out_desc.bEndpointAddress; } + fi_mtp->func_inst.f = &dev->function; DBG(cdev, "%s speed %s: IN/%s, OUT/%s\n", gadget_is_superspeed(c->cdev->gadget) ? "super" : (gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full"), @@ -1501,9 +1500,10 @@ static void mtp_function_unbind(struct usb_configuration *c, struct usb_function *f) { struct mtp_dev *dev = func_to_mtp(f); + struct mtp_instance *fi_mtp; struct usb_request *req; int i; - + fi_mtp = container_of(f->fi, struct mtp_instance, func_inst); mtp_string_defs[INTERFACE_STRING_INDEX].id = 0; mutex_lock(&dev->read_mutex); while ((req = mtp_req_get(dev, &dev->tx_idle))) @@ -1517,6 +1517,7 @@ mtp_function_unbind(struct usb_configuration *c, struct usb_function *f) dev->is_ptp = false; kfree(f->os_desc_table); f->os_desc_n = 0; + fi_mtp->func_inst.f = NULL; } static int mtp_function_set_alt(struct usb_function *f, @@ -1854,6 +1855,8 @@ struct usb_function_instance *alloc_inst_mtp_ptp(bool mtp_config) config_group_init_type_name(&fi_mtp->func_inst.group, "", &mtp_func_type); + mutex_init(&fi_mtp->dev->read_mutex); + return &fi_mtp->func_inst; } EXPORT_SYMBOL_GPL(alloc_inst_mtp_ptp); @@ -1914,9 +1917,7 @@ struct usb_function *function_alloc_mtp_ptp(struct usb_function_instance *fi, dev->function.setup = mtp_ctrlreq_configfs; dev->function.free_func = mtp_free; dev->is_ptp = !mtp_config; - fi->f = &dev->function; - mutex_init(&dev->read_mutex); return &dev->function; } EXPORT_SYMBOL_GPL(function_alloc_mtp_ptp); diff --git a/drivers/usb/gadget/function/f_qdss.c b/drivers/usb/gadget/function/f_qdss.c index 88db253aeef4..777acb489875 100644 --- a/drivers/usb/gadget/function/f_qdss.c +++ b/drivers/usb/gadget/function/f_qdss.c @@ -474,6 +474,7 @@ static void usb_qdss_disconnect_work(struct work_struct *work) { struct f_qdss *qdss; int status; + unsigned long flags; qdss = container_of(work, struct f_qdss, disconnect_w); pr_debug("usb_qdss_disconnect_work\n"); @@ -496,6 +497,14 @@ static void usb_qdss_disconnect_work(struct work_struct *work) status = set_qdss_data_connection(qdss, 0); if (status) pr_err("qdss_disconnect error"); + + spin_lock_irqsave(&qdss->lock, flags); + if (qdss->endless_req) { + usb_ep_free_request(qdss->port.data, + qdss->endless_req); + qdss->endless_req = NULL; + } + spin_unlock_irqrestore(&qdss->lock, flags); } /* @@ -528,6 +537,8 @@ static void usb_qdss_connect_work(struct work_struct *work) { struct f_qdss *qdss; int status; + struct usb_request *req = NULL; + unsigned long flags; qdss = container_of(work, struct f_qdss, connect_w); @@ -548,8 +559,13 @@ static void usb_qdss_connect_work(struct work_struct *work) if (qdss->ch.notify) qdss->ch.notify(qdss->ch.priv, USB_QDSS_CONNECT, NULL, &qdss->ch); + spin_lock_irqsave(&qdss->lock, flags); + req = qdss->endless_req; + spin_unlock_irqrestore(&qdss->lock, flags); + if (!req) + return; - status = usb_ep_queue(qdss->port.data, qdss->endless_req, GFP_ATOMIC); + status = usb_ep_queue(qdss->port.data, req, GFP_ATOMIC); if (status) pr_err("%s: usb_ep_queue error (%d)\n", __func__, status); } @@ -849,9 +865,11 @@ void usb_qdss_close(struct usb_qdss_ch *ch) return; } - usb_ep_dequeue(qdss->port.data, qdss->endless_req); - usb_ep_free_request(qdss->port.data, qdss->endless_req); - qdss->endless_req = NULL; + if (qdss->endless_req) { + usb_ep_dequeue(qdss->port.data, qdss->endless_req); + usb_ep_free_request(qdss->port.data, qdss->endless_req); + qdss->endless_req = NULL; + } gadget = qdss->gadget; ch->app_conn = 0; spin_unlock_irqrestore(&qdss_lock, flags); diff --git a/drivers/usb/phy/phy-msm-qusb-v2.c b/drivers/usb/phy/phy-msm-qusb-v2.c index 6fb91134b0c5..5df091a5454b 100644 --- a/drivers/usb/phy/phy-msm-qusb-v2.c +++ b/drivers/usb/phy/phy-msm-qusb-v2.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -90,6 +90,7 @@ struct qusb_phy { struct regulator *vdda18; struct regulator *vdda12; int vdd_levels[3]; /* none, low, high */ + int vdda33_levels[3]; int init_seq_len; int *qusb_phy_init_seq; int host_init_seq_len; @@ -236,8 +237,8 @@ static int qusb_phy_enable_power(struct qusb_phy *qphy, bool on, goto disable_vdda18; } - ret = regulator_set_voltage(qphy->vdda33, QUSB2PHY_3P3_VOL_MIN, - QUSB2PHY_3P3_VOL_MAX); + ret = regulator_set_voltage(qphy->vdda33, qphy->vdda33_levels[0], + qphy->vdda33_levels[2]); if (ret) { dev_err(qphy->phy.dev, "Unable to set voltage for vdda33:%d\n", ret); @@ -262,7 +263,7 @@ disable_vdda33: dev_err(qphy->phy.dev, "Unable to disable vdda33:%d\n", ret); unset_vdd33: - ret = regulator_set_voltage(qphy->vdda33, 0, QUSB2PHY_3P3_VOL_MAX); + ret = regulator_set_voltage(qphy->vdda33, 0, qphy->vdda33_levels[2]); if (ret) dev_err(qphy->phy.dev, "Unable to set (0) voltage for vdda33:%d\n", ret); @@ -455,6 +456,15 @@ static int qusb_phy_init(struct usb_phy *phy) if (ret) return ret; + /* bump up vdda33 voltage to operating level*/ + ret = regulator_set_voltage(qphy->vdda33, qphy->vdda33_levels[1], + qphy->vdda33_levels[2]); + if (ret) { + dev_err(qphy->phy.dev, + "Unable to set voltage for vdda33:%d\n", ret); + return ret; + } + qusb_phy_enable_clocks(qphy, true); /* Perform phy reset */ @@ -1016,6 +1026,19 @@ static int qusb_phy_probe(struct platform_device *pdev) return ret; } + ret = of_property_read_u32_array(dev->of_node, + "qcom,vdda33-voltage-level", + (u32 *) qphy->vdda33_levels, + ARRAY_SIZE(qphy->vdda33_levels)); + if (ret == -EINVAL) { + qphy->vdda33_levels[0] = QUSB2PHY_3P3_VOL_MIN; + qphy->vdda33_levels[1] = QUSB2PHY_3P3_VOL_MIN; + qphy->vdda33_levels[2] = QUSB2PHY_3P3_VOL_MAX; + } else if (ret) { + dev_err(dev, "error reading qcom,vdda33-voltage-level property\n"); + return ret; + } + qphy->vdd = devm_regulator_get(dev, "vdd"); if (IS_ERR(qphy->vdd)) { dev_err(dev, "unable to get vdd supply\n"); diff --git a/drivers/video/fbdev/msm/dsi_status_6g.c b/drivers/video/fbdev/msm/dsi_status_6g.c index 869ff1d9df37..d24b19ea77ad 100644 --- a/drivers/video/fbdev/msm/dsi_status_6g.c +++ b/drivers/video/fbdev/msm/dsi_status_6g.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -17,6 +17,7 @@ #include "mdss_dsi.h" #include "mdss_mdp.h" +#include "mdss_debug.h" /* * mdss_check_te_status() - Check the status of panel for TE based ESD. @@ -157,6 +158,7 @@ void mdss_check_dsi_ctrl_status(struct work_struct *work, uint32_t interval) ctl->ops.wait_pingpong(ctl, NULL); pr_debug("%s: DSI ctrl wait for ping pong done\n", __func__); + MDSS_XLOG(mipi->mode); mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON); ret = ctrl_pdata->check_status(ctrl_pdata); diff --git a/drivers/video/fbdev/msm/mdss.h b/drivers/video/fbdev/msm/mdss.h index 796246a856b4..1c984d02755e 100644 --- a/drivers/video/fbdev/msm/mdss.h +++ b/drivers/video/fbdev/msm/mdss.h @@ -45,6 +45,7 @@ enum mdss_mdp_clk_type { MDSS_CLK_MDP_LUT, MDSS_CLK_MDP_VSYNC, MDSS_CLK_MNOC_AHB, + MDSS_CLK_THROTTLE_AXI, MDSS_MAX_CLK }; diff --git a/drivers/video/fbdev/msm/mdss_compat_utils.c b/drivers/video/fbdev/msm/mdss_compat_utils.c index e9ba77501b38..2b9c71441d68 100644 --- a/drivers/video/fbdev/msm/mdss_compat_utils.c +++ b/drivers/video/fbdev/msm/mdss_compat_utils.c @@ -119,6 +119,9 @@ static unsigned int __do_compat_ioctl_nr(unsigned int cmd32) static void __copy_atomic_commit_struct(struct mdp_layer_commit *commit, struct mdp_layer_commit32 *commit32) { + unsigned int destSize = sizeof(commit->commit_v1.reserved); + unsigned int srcSize = sizeof(commit32->commit_v1.reserved); + unsigned int count = (destSize <= srcSize ? destSize : srcSize); commit->version = commit32->version; commit->commit_v1.flags = commit32->commit_v1.flags; commit->commit_v1.input_layer_cnt = @@ -127,7 +130,7 @@ static void __copy_atomic_commit_struct(struct mdp_layer_commit *commit, commit->commit_v1.right_roi = commit32->commit_v1.right_roi; commit->commit_v1.bl_level = commit32->commit_v1.bl_level; memcpy(&commit->commit_v1.reserved, &commit32->commit_v1.reserved, - sizeof(commit32->commit_v1.reserved)); + count); } static struct mdp_input_layer32 *__create_layer_list32( @@ -220,6 +223,7 @@ static struct mdp_input_layer *__create_layer_list( layer->flags = layer32->flags; layer->pipe_ndx = layer32->pipe_ndx; + layer->rect_num = layer32->rect_num; layer->horz_deci = layer32->horz_deci; layer->vert_deci = layer32->vert_deci; layer->z_order = layer32->z_order; diff --git a/drivers/video/fbdev/msm/mdss_compat_utils.h b/drivers/video/fbdev/msm/mdss_compat_utils.h index 4f44cd1c9471..b7fa401f52d2 100644 --- a/drivers/video/fbdev/msm/mdss_compat_utils.h +++ b/drivers/video/fbdev/msm/mdss_compat_utils.h @@ -515,7 +515,8 @@ struct mdp_input_layer32 { struct mdp_layer_buffer buffer; compat_caddr_t pp_info; int error_code; - uint32_t reserved[6]; + uint32_t rect_num; + uint32_t reserved[5]; }; struct mdp_output_layer32 { diff --git a/drivers/video/fbdev/msm/mdss_debug.c b/drivers/video/fbdev/msm/mdss_debug.c index ddb7a4c31f68..8cb6c7157230 100644 --- a/drivers/video/fbdev/msm/mdss_debug.c +++ b/drivers/video/fbdev/msm/mdss_debug.c @@ -1077,7 +1077,7 @@ static ssize_t mdss_debug_perf_bw_limit_read(struct file *file, struct mdss_data_type *mdata = file->private_data; struct mdss_max_bw_settings *temp_settings; int len = 0, i; - char buf[256]; + char buf[256] = {'\0'}; if (!mdata) return -ENODEV; diff --git a/drivers/video/fbdev/msm/mdss_debug_xlog.c b/drivers/video/fbdev/msm/mdss_debug_xlog.c index bf4117650e3c..aeefc81657b0 100644 --- a/drivers/video/fbdev/msm/mdss_debug_xlog.c +++ b/drivers/video/fbdev/msm/mdss_debug_xlog.c @@ -93,6 +93,48 @@ static inline bool mdss_xlog_is_enabled(u32 flag) (flag == MDSS_XLOG_ALL && mdss_dbg_xlog.xlog_enable); } +static void __halt_vbif_xin(void) +{ + struct mdss_data_type *mdata = mdss_mdp_get_mdata(); + + pr_err("Halting VBIF-XIN\n"); + MDSS_VBIF_WRITE(mdata, MMSS_VBIF_XIN_HALT_CTRL0, 0xFFFFFFFF, false); +} + +static void __halt_vbif_axi(void) +{ + struct mdss_data_type *mdata = mdss_mdp_get_mdata(); + + pr_err("Halting VBIF-AXI\n"); + MDSS_VBIF_WRITE(mdata, MMSS_VBIF_AXI_HALT_CTRL0, 0xFFFFFFFF, false); +} + +static void __dump_vbif_state(void) +{ + struct mdss_data_type *mdata = mdss_mdp_get_mdata(); + unsigned int reg_vbif_src_err, reg_vbif_err_info, + reg_vbif_xin_halt_ctrl0, reg_vbif_xin_halt_ctrl1, + reg_vbif_axi_halt_ctrl0, reg_vbif_axi_halt_ctrl1; + + reg_vbif_src_err = MDSS_VBIF_READ(mdata, + MMSS_VBIF_SRC_ERR, false); + reg_vbif_err_info = MDSS_VBIF_READ(mdata, + MMSS_VBIF_ERR_INFO, false); + reg_vbif_xin_halt_ctrl0 = MDSS_VBIF_READ(mdata, + MMSS_VBIF_XIN_HALT_CTRL0, false); + reg_vbif_xin_halt_ctrl1 = MDSS_VBIF_READ(mdata, + MMSS_VBIF_XIN_HALT_CTRL1, false); + reg_vbif_axi_halt_ctrl0 = MDSS_VBIF_READ(mdata, + MMSS_VBIF_AXI_HALT_CTRL0, false); + reg_vbif_axi_halt_ctrl1 = MDSS_VBIF_READ(mdata, + MMSS_VBIF_AXI_HALT_CTRL1, false); + pr_err("VBIF SRC_ERR=%x, ERR_INFO=%x\n", + reg_vbif_src_err, reg_vbif_err_info); + pr_err("VBIF XIN_HALT_CTRL0=%x, XIN_HALT_CTRL1=%x, AXI_HALT_CTRL0=%x, AXI_HALT_CTRL1=%x\n" + , reg_vbif_xin_halt_ctrl0, reg_vbif_xin_halt_ctrl1, + reg_vbif_axi_halt_ctrl0, reg_vbif_axi_halt_ctrl1); +} + void mdss_xlog(const char *name, int line, int flag, ...) { unsigned long flags; @@ -611,8 +653,17 @@ static void mdss_xlog_dump_array(struct mdss_debug_base *blk_arr[], mdss_dump_dsi_debug_bus(mdss_dbg_xlog.enable_dsi_dbgbus_dump, &mdss_dbg_xlog.dsi_dbgbus_dump); - if (dead && mdss_dbg_xlog.panic_on_err) + if (dead && mdss_dbg_xlog.panic_on_err) { + mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON); + __dump_vbif_state(); + __halt_vbif_xin(); + usleep_range(10000, 10010); + __halt_vbif_axi(); + usleep_range(10000, 10010); + __dump_vbif_state(); + mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF); panic(name); + } } static void xlog_debug_work(struct work_struct *work) diff --git a/drivers/video/fbdev/msm/mdss_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/drivers/video/fbdev/msm/mdss_fb.c b/drivers/video/fbdev/msm/mdss_fb.c index 698c5633cf6a..4eca9cb39223 100644 --- a/drivers/video/fbdev/msm/mdss_fb.c +++ b/drivers/video/fbdev/msm/mdss_fb.c @@ -2121,6 +2121,7 @@ static int mdss_fb_blank(int blank_mode, struct fb_info *info) mdss_mdp_enable_panel_disable_mode(mfd, false); ret = mdss_fb_blank_sub(blank_mode, info, mfd->op_enable); + MDSS_XLOG(blank_mode); end: mutex_unlock(&mfd->mdss_sysfs_lock); diff --git a/drivers/video/fbdev/msm/mdss_hdmi_edid.c b/drivers/video/fbdev/msm/mdss_hdmi_edid.c index 599f6cb44c63..102c22cba7dd 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_edid.c +++ b/drivers/video/fbdev/msm/mdss_hdmi_edid.c @@ -1283,6 +1283,7 @@ static void hdmi_edid_extract_speaker_allocation_data( static void hdmi_edid_extract_sink_caps(struct hdmi_edid_ctrl *edid_ctrl, const u8 *in_buf) { + u8 len; const u8 *vsd = NULL; if (!edid_ctrl) { @@ -1297,13 +1298,29 @@ static void hdmi_edid_extract_sink_caps(struct hdmi_edid_ctrl *edid_ctrl, edid_ctrl->basic_audio_supp = false; pr_debug("%s: basic audio supported: %s\n", __func__, edid_ctrl->basic_audio_supp ? "true" : "false"); + vsd = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, + VENDOR_SPECIFIC_DATA_BLOCK, &len); + + if (vsd == NULL || len == 0 || len > MAX_DATA_BLOCK_SIZE) + return; + + /* Max TMDS clock is in multiples of 5Mhz. */ + edid_ctrl->sink_caps.max_pclk_in_hz = vsd[7] * 5000000; vsd = hdmi_edid_find_hfvsdb(in_buf); if (vsd) { - /* Max pixel clock is in multiples of 5Mhz. */ - edid_ctrl->sink_caps.max_pclk_in_hz = - vsd[5]*5000000; + /* + * HF-VSDB define larger TMDS clock than VSDB. If sink + * supports TMDS Character Rates > 340M, the sink shall + * set Max_TMDS_Character_Rates appropriately and non-zero. + * Or, if sink dose not support TMDS Character Rates > 340M, + * the sink shall set this filed to 0. The max TMDS support + * clock Rate = Max_TMDS_Character_Rates * 5Mhz. + */ + if (vsd[5] != 0) + edid_ctrl->sink_caps.max_pclk_in_hz = + vsd[5] * 5000000; edid_ctrl->sink_caps.scdc_present = (vsd[6] & 0x80) ? true : false; edid_ctrl->sink_caps.scramble_support = @@ -2425,6 +2442,25 @@ bool hdmi_edid_is_dvi_mode(void *input) } /** + * hdmi_edid_get_sink_caps_max_tmds_clk() - get max tmds clock supported. + * Sink side's limitation should be concerned as well. + * @input: edid parser data + * + * Return: max tmds clock + */ +u32 hdmi_edid_get_sink_caps_max_tmds_clk(void *input) +{ + struct hdmi_edid_ctrl *edid_ctrl = (struct hdmi_edid_ctrl *)input; + + if (!edid_ctrl) { + DEV_ERR("%s: invalid input\n", __func__); + return 0; + } + + return edid_ctrl->sink_caps.max_pclk_in_hz; +} + +/** * hdmi_edid_get_deep_color() - get deep color info supported by sink * @input: edid parser data * diff --git a/drivers/video/fbdev/msm/mdss_hdmi_edid.h b/drivers/video/fbdev/msm/mdss_hdmi_edid.h index 557e9326a81d..af802bb45f89 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_edid.h +++ b/drivers/video/fbdev/msm/mdss_hdmi_edid.h @@ -81,5 +81,6 @@ void hdmi_edid_config_override(void *input, bool enable, struct hdmi_edid_override_data *data); void hdmi_edid_set_max_pclk_rate(void *input, u32 max_pclk_khz); bool hdmi_edid_is_audio_supported(void *input); +u32 hdmi_edid_get_sink_caps_max_tmds_clk(void *input); #endif /* __HDMI_EDID_H__ */ diff --git a/drivers/video/fbdev/msm/mdss_hdmi_tx.c b/drivers/video/fbdev/msm/mdss_hdmi_tx.c index 42845f9ff192..8fa229aaa174 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_tx.c +++ b/drivers/video/fbdev/msm/mdss_hdmi_tx.c @@ -2224,6 +2224,14 @@ static int hdmi_tx_read_sink_info(struct hdmi_tx_ctrl *hdmi_ctrl) status = hdmi_edid_parser(data); if (status) DEV_ERR("%s: edid parse failed\n", __func__); + else + /* + * Updata HDMI max supported TMDS clock, consider + * both sink and source capicity. + */ + hdmi_edid_set_max_pclk_rate(data, + min(hdmi_edid_get_sink_caps_max_tmds_clk(data) / 1000, + hdmi_ctrl->max_pclk_khz)); } bail: if (hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_DDC_PM, false)) diff --git a/drivers/video/fbdev/msm/mdss_mdp.c b/drivers/video/fbdev/msm/mdss_mdp.c index a645a3495593..d88d87bd2092 100644 --- a/drivers/video/fbdev/msm/mdss_mdp.c +++ b/drivers/video/fbdev/msm/mdss_mdp.c @@ -1373,7 +1373,9 @@ static inline void __mdss_mdp_reg_access_clk_enable( mdss_mdp_clk_update(MDSS_CLK_AHB, 1); mdss_mdp_clk_update(MDSS_CLK_AXI, 1); mdss_mdp_clk_update(MDSS_CLK_MDP_CORE, 1); + mdss_mdp_clk_update(MDSS_CLK_THROTTLE_AXI, 1); } else { + mdss_mdp_clk_update(MDSS_CLK_THROTTLE_AXI, 0); mdss_mdp_clk_update(MDSS_CLK_MDP_CORE, 0); mdss_mdp_clk_update(MDSS_CLK_AXI, 0); mdss_mdp_clk_update(MDSS_CLK_AHB, 0); @@ -1415,6 +1417,7 @@ static void __mdss_mdp_clk_control(struct mdss_data_type *mdata, bool enable) mdss_mdp_clk_update(MDSS_CLK_AXI, 1); mdss_mdp_clk_update(MDSS_CLK_MDP_CORE, 1); mdss_mdp_clk_update(MDSS_CLK_MDP_LUT, 1); + mdss_mdp_clk_update(MDSS_CLK_THROTTLE_AXI, 1); if (mdata->vsync_ena) mdss_mdp_clk_update(MDSS_CLK_MDP_VSYNC, 1); } else { @@ -1430,6 +1433,7 @@ static void __mdss_mdp_clk_control(struct mdss_data_type *mdata, bool enable) mdss_mdp_clk_update(MDSS_CLK_AXI, 0); mdss_mdp_clk_update(MDSS_CLK_AHB, 0); mdss_mdp_clk_update(MDSS_CLK_MNOC_AHB, 0); + mdss_mdp_clk_update(MDSS_CLK_THROTTLE_AXI, 0); /* release iommu control */ mdss_iommu_ctrl(0); @@ -1915,8 +1919,7 @@ static int mdss_mdp_irq_clk_setup(struct mdss_data_type *mdata) if (mdss_mdp_irq_clk_register(mdata, "bus_clk", MDSS_CLK_AXI) || mdss_mdp_irq_clk_register(mdata, "iface_clk", MDSS_CLK_AHB) || - mdss_mdp_irq_clk_register(mdata, "core_clk", - MDSS_CLK_MDP_CORE)) + mdss_mdp_irq_clk_register(mdata, "core_clk", MDSS_CLK_MDP_CORE)) return -EINVAL; /* lut_clk is not present on all MDSS revisions */ @@ -1928,6 +1931,10 @@ static int mdss_mdp_irq_clk_setup(struct mdss_data_type *mdata) /* this clk is not present on all MDSS revisions */ mdss_mdp_irq_clk_register(mdata, "mnoc_clk", MDSS_CLK_MNOC_AHB); + /* this clk is not present on all MDSS revisions */ + mdss_mdp_irq_clk_register(mdata, "throttle_bus_clk", + MDSS_CLK_THROTTLE_AXI); + /* Setting the default clock rate to the max supported.*/ mdss_mdp_set_clk_rate(mdata->max_mdp_clk_rate, false); pr_debug("mdp clk rate=%ld\n", diff --git a/drivers/video/fbdev/msm/mdss_mdp.h b/drivers/video/fbdev/msm/mdss_mdp.h index a2139f495f52..fd2c2cdb3820 100644 --- a/drivers/video/fbdev/msm/mdss_mdp.h +++ b/drivers/video/fbdev/msm/mdss_mdp.h @@ -2023,6 +2023,8 @@ void mdss_mdp_set_supported_formats(struct mdss_data_type *mdata); int mdss_mdp_dest_scaler_setup_locked(struct mdss_mdp_mixer *mixer); void *mdss_mdp_intf_get_ctx_base(struct mdss_mdp_ctl *ctl, int intf_num); +int mdss_mdp_mixer_get_hw_num(struct mdss_mdp_mixer *mixer); + #ifdef CONFIG_FB_MSM_MDP_NONE struct mdss_data_type *mdss_mdp_get_mdata(void) { diff --git a/drivers/video/fbdev/msm/mdss_mdp_ctl.c b/drivers/video/fbdev/msm/mdss_mdp_ctl.c index 1f29a9f86e24..c062de3c1e59 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_ctl.c +++ b/drivers/video/fbdev/msm/mdss_mdp_ctl.c @@ -4802,7 +4802,7 @@ static void __mdss_mdp_mixer_get_offsets(u32 mixer_num, offsets[2] = MDSS_MDP_REG_CTL_LAYER_EXTN2(mixer_num); } -static inline int __mdss_mdp_mixer_get_hw_num(struct mdss_mdp_mixer *mixer) +int mdss_mdp_mixer_get_hw_num(struct mdss_mdp_mixer *mixer) { struct mdss_data_type *mdata = mdss_mdp_get_mdata(); @@ -4858,7 +4858,7 @@ static void __mdss_mdp_mixer_write_cfg(struct mdss_mdp_mixer *mixer, if (!mixer) return; - mixer_num = __mdss_mdp_mixer_get_hw_num(mixer); + mixer_num = mdss_mdp_mixer_get_hw_num(mixer); if (cfg) { for (i = 0; i < NUM_MIXERCFG_REGS; i++) @@ -4905,7 +4905,7 @@ bool mdss_mdp_mixer_reg_has_pipe(struct mdss_mdp_mixer *mixer, memset(&mixercfg, 0, sizeof(mixercfg)); - mixer_num = __mdss_mdp_mixer_get_hw_num(mixer); + mixer_num = mdss_mdp_mixer_get_hw_num(mixer); __mdss_mdp_mixer_get_offsets(mixer_num, offs, NUM_MIXERCFG_REGS); for (i = 0; i < NUM_MIXERCFG_REGS; i++) @@ -5130,7 +5130,7 @@ static void mdss_mdp_mixer_setup(struct mdss_mdp_ctl *master_ctl, mixercfg.cursor_enabled = true; update_mixer: - mixer_num = __mdss_mdp_mixer_get_hw_num(mixer_hw); + mixer_num = mdss_mdp_mixer_get_hw_num(mixer_hw); ctl_hw->flush_bits |= BIT(mixer_num < 5 ? 6 + mixer_num : 20); /* Read GC enable/disable status on LM */ @@ -5775,6 +5775,7 @@ int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg, mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON); if (ctl->ops.avr_ctrl_fnc) { + /* avr_ctrl_fnc will configure both master & slave */ ret = ctl->ops.avr_ctrl_fnc(ctl, true); if (ret) { pr_err("error configuring avr ctrl registers ctl=%d err=%d\n", @@ -5784,16 +5785,6 @@ int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg, } } - if (sctl && sctl->ops.avr_ctrl_fnc) { - ret = sctl->ops.avr_ctrl_fnc(sctl, true); - if (ret) { - pr_err("error configuring avr ctrl registers sctl=%d err=%d\n", - sctl->num, ret); - mutex_unlock(&ctl->lock); - return ret; - } - } - mutex_lock(&ctl->flush_lock); /* @@ -6046,6 +6037,10 @@ int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg, ctl_flush_bits |= ctl->flush_bits; ATRACE_BEGIN("flush_kickoff"); + + MDSS_XLOG(ctl->intf_num, ctl_flush_bits, sctl_flush_bits, + mdss_mdp_ctl_read(ctl, MDSS_MDP_REG_CTL_FLUSH), split_lm_valid); + mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_FLUSH, ctl_flush_bits); if (sctl) { if (sctl_flush_bits) { @@ -6057,8 +6052,6 @@ int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg, } ctl->commit_in_progress = false; - MDSS_XLOG(ctl->intf_num, ctl_flush_bits, sctl_flush_bits, - split_lm_valid); wmb(); ctl->flush_reg_data = ctl_flush_bits; ctl->flush_bits = 0; diff --git a/drivers/video/fbdev/msm/mdss_mdp_debug.c b/drivers/video/fbdev/msm/mdss_mdp_debug.c index 1ad6810a6bb6..1035d23fe9ce 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_debug.c +++ b/drivers/video/fbdev/msm/mdss_mdp_debug.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1757,6 +1757,8 @@ void mdss_mdp_hw_rev_debug_caps_init(struct mdss_data_type *mdata) break; case MDSS_MDP_HW_REV_300: case MDSS_MDP_HW_REV_301: + case MDSS_MDP_HW_REV_320: + case MDSS_MDP_HW_REV_330: mdata->dbg_bus = dbg_bus_msm8998; mdata->dbg_bus_size = ARRAY_SIZE(dbg_bus_msm8998); mdata->vbif_dbg_bus = vbif_dbg_bus_msm8998; diff --git a/drivers/video/fbdev/msm/mdss_mdp_hwio.h b/drivers/video/fbdev/msm/mdss_mdp_hwio.h index d9e2b042bfc3..78bfab7d8ce8 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_hwio.h +++ b/drivers/video/fbdev/msm/mdss_mdp_hwio.h @@ -829,6 +829,8 @@ enum mdss_mdp_pingpong_index { #define MMSS_VBIF_WR_LIM_CONF 0x0C0 #define MDSS_VBIF_WRITE_GATHER_EN 0x0AC +#define MMSS_VBIF_SRC_ERR 0x194 +#define MMSS_VBIF_ERR_INFO 0x1A0 #define MMSS_VBIF_XIN_HALT_CTRL0 0x200 #define MMSS_VBIF_XIN_HALT_CTRL1 0x204 #define MMSS_VBIF_AXI_HALT_CTRL0 0x208 diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_video.c b/drivers/video/fbdev/msm/mdss_mdp_intf_video.c index 13c70822e266..587150bbc9fa 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_intf_video.c +++ b/drivers/video/fbdev/msm/mdss_mdp_intf_video.c @@ -72,6 +72,7 @@ struct mdss_mdp_video_ctx { u8 ref_cnt; u8 timegen_en; + bool timegen_flush_pending; bool polling_en; u32 poll_cnt; struct completion vsync_comp; @@ -451,13 +452,32 @@ static int mdss_mdp_video_intf_recovery(void *data, int event) } } +static int mdss_mdp_video_wait_one_frame(struct mdss_mdp_ctl *ctl) +{ + u32 frame_time, frame_rate; + int ret = 0; + struct mdss_panel_data *pdata = ctl->panel_data; + + if (pdata == NULL) { + frame_rate = DEFAULT_FRAME_RATE; + } else { + frame_rate = mdss_panel_get_framerate(&pdata->panel_info); + if (!(frame_rate >= 24 && frame_rate <= 240)) + frame_rate = 24; + } + + frame_time = ((1000/frame_rate) + 1); + + msleep(frame_time); + + return ret; +} + static void mdss_mdp_video_avr_vtotal_setup(struct mdss_mdp_ctl *ctl, struct intf_timing_params *p, struct mdss_mdp_video_ctx *ctx) { struct mdss_data_type *mdata = ctl->mdata; - struct mdss_mdp_ctl *sctl = NULL; - struct mdss_mdp_video_ctx *sctx = NULL; if (test_bit(MDSS_CAPS_AVR_SUPPORTED, mdata->mdss_caps_map)) { struct mdss_panel_data *pdata = ctl->panel_data; @@ -484,14 +504,11 @@ static void mdss_mdp_video_avr_vtotal_setup(struct mdss_mdp_ctl *ctl, /* * Make sure config goes through + * and queue timegen flush */ wmb(); - sctl = mdss_mdp_get_split_ctl(ctl); - if (sctl) - sctx = (struct mdss_mdp_video_ctx *) - sctl->intf_ctx[MASTER_CTX]; - mdss_mdp_video_timegen_flush(ctl, sctx); + ctx->timegen_flush_pending = true; MDSS_XLOG(pinfo->min_fps, pinfo->default_fps, avr_vtotal); } @@ -687,8 +704,10 @@ static void mdss_mdp_video_timegen_flush(struct mdss_mdp_ctl *ctl, ctl_flush |= (BIT(31) >> (sctx->intf_num - MDSS_MDP_INTF0)); } + MDSS_XLOG(ctl->intf_num, sctx?sctx->intf_num:0xf00, ctl_flush, + mdss_mdp_ctl_read(ctl, MDSS_MDP_REG_CTL_FLUSH)); mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_FLUSH, ctl_flush); - MDSS_XLOG(ctl->intf_num, sctx?sctx->intf_num:0xf00, ctl_flush); + } static inline void video_vsync_irq_enable(struct mdss_mdp_ctl *ctl, bool clear) @@ -2464,25 +2483,41 @@ static int mdss_mdp_video_early_wake_up(struct mdss_mdp_ctl *ctl) static int mdss_mdp_video_avr_ctrl(struct mdss_mdp_ctl *ctl, bool enable) { struct mdss_mdp_video_ctx *ctx = NULL, *sctx = NULL; + struct mdss_mdp_ctl *sctl; ctx = (struct mdss_mdp_video_ctx *) ctl->intf_ctx[MASTER_CTX]; if (!ctx || !ctx->ref_cnt) { pr_err("invalid master ctx\n"); return -EINVAL; } - mdss_mdp_video_avr_ctrl_setup(ctx, ctl, ctl->is_master, - enable); - if (is_pingpong_split(ctl->mfd)) { + sctl = mdss_mdp_get_split_ctl(ctl); + if (sctl) { + sctx = (struct mdss_mdp_video_ctx *) sctl->intf_ctx[MASTER_CTX]; + } else if (is_pingpong_split(ctl->mfd)) { sctx = (struct mdss_mdp_video_ctx *) ctl->intf_ctx[SLAVE_CTX]; if (!sctx || !sctx->ref_cnt) { pr_err("invalid slave ctx\n"); return -EINVAL; } - mdss_mdp_video_avr_ctrl_setup(sctx, ctl, false, - enable); } + if (ctx->timegen_flush_pending) { + mdss_mdp_video_timegen_flush(ctl, sctx); + + /* wait a frame for flush to be completed */ + mdss_mdp_video_wait_one_frame(ctl); + + ctx->timegen_flush_pending = false; + if (sctx) + sctx->timegen_flush_pending = false; + } + + mdss_mdp_video_avr_ctrl_setup(ctx, ctl, ctl->is_master, enable); + + if (sctx) + mdss_mdp_video_avr_ctrl_setup(sctx, ctl, false, enable); + return 0; } diff --git a/drivers/video/fbdev/msm/mdss_mdp_layer.c b/drivers/video/fbdev/msm/mdss_mdp_layer.c index 09a34223c2a5..472f1e8e8e3b 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_layer.c +++ b/drivers/video/fbdev/msm/mdss_mdp_layer.c @@ -2160,115 +2160,157 @@ static int __multirect_validate_mode(struct msm_fb_data_type *mfd, return 0; } -static int __update_multirect_info(struct msm_fb_data_type *mfd, - struct mdss_mdp_validate_info_t *validate_info_list, - struct mdp_input_layer *layer_list, int ndx, int layer_cnt) +/* + * linear search for a layer with given source pipe and rectangle number. + * If rectangle number is invalid, it's dropped from search criteria + */ +static int find_layer(enum mdss_mdp_sspp_index pnum, + int rect_num, + struct mdp_input_layer *layer_list, + size_t layer_cnt, int start_index) { - struct mdss_data_type *mdata = mdss_mdp_get_mdata(); - struct mdss_mdp_validate_info_t *vinfo[MDSS_MDP_PIPE_MAX_RECTS]; - int i, ptype, max_rects, mode; - int cnt = 1; + int i; - mode = __multirect_layer_flags_to_mode(layer_list[ndx].flags); - if (IS_ERR_VALUE(mode)) - return mode; + if (start_index < 0) + start_index = 0; - pr_debug("layer #%d pipe_ndx=%d multirect mode=%d\n", - ndx, layer_list[ndx].pipe_ndx, mode); + if (start_index >= layer_cnt) + return -EINVAL; - vinfo[0] = &validate_info_list[ndx]; - vinfo[0]->layer = &layer_list[ndx]; - vinfo[0]->multirect.mode = mode; - vinfo[0]->multirect.num = MDSS_MDP_PIPE_RECT0; - vinfo[0]->multirect.next = NULL; + for (i = start_index; i < layer_cnt; i++) { + if (get_pipe_num_from_ndx(layer_list[i].pipe_ndx) == pnum && + (rect_num < MDSS_MDP_PIPE_RECT0 || + rect_num >= MDSS_MDP_PIPE_MAX_RECTS || + layer_list[i].rect_num == rect_num)) + return i; + } - /* nothing to be done if multirect is disabled */ - if (mode == MDSS_MDP_PIPE_MULTIRECT_NONE) - return cnt; + return -ENOENT; /* no match found */ +} - ptype = get_pipe_type_from_ndx(layer_list[ndx].pipe_ndx); - if (ptype == MDSS_MDP_PIPE_TYPE_INVALID) { - pr_err("invalid pipe ndx %d\n", layer_list[ndx].pipe_ndx); - return -EINVAL; - } +static int __validate_multirect_param(struct msm_fb_data_type *mfd, + struct mdss_mdp_validate_info_t *validate_info_list, + struct mdp_input_layer *layer_list, + int ndx, size_t layer_count) +{ + int multirect_mode; + int pnum; + int rect_num; + + /* populate v_info with default values */ + validate_info_list[ndx].layer = &layer_list[ndx]; + validate_info_list[ndx].multirect.max_rects = MDSS_MDP_PIPE_MAX_RECTS; + validate_info_list[ndx].multirect.next = NULL; + validate_info_list[ndx].multirect.num = MDSS_MDP_PIPE_RECT0; + validate_info_list[ndx].multirect.mode = MDSS_MDP_PIPE_MULTIRECT_NONE; + + multirect_mode = __multirect_layer_flags_to_mode( + layer_list[ndx].flags); + if (IS_ERR_VALUE(multirect_mode)) + return multirect_mode; - max_rects = mdata->rects_per_sspp[ptype] ? : 1; + /* nothing to be done if multirect is disabled */ + if (multirect_mode == MDSS_MDP_PIPE_MULTIRECT_NONE) + return 0; - for (i = ndx + 1; i < layer_cnt; i++) { - if (layer_list[ndx].pipe_ndx == layer_list[i].pipe_ndx) { - if (cnt >= max_rects) { - pr_err("more than %d layers of type %d with same pipe_ndx=%d indexes=%d %d\n", - max_rects, ptype, - layer_list[ndx].pipe_ndx, ndx, i); - return -EINVAL; - } + validate_info_list[ndx].multirect.mode = multirect_mode; - mode = __multirect_layer_flags_to_mode( - layer_list[i].flags); - if (IS_ERR_VALUE(mode)) - return mode; + pnum = get_pipe_num_from_ndx(layer_list[ndx].pipe_ndx); + if (get_pipe_type_from_num(pnum) != MDSS_MDP_PIPE_TYPE_DMA) { + pr_err("Multirect not supported on pipe ndx 0x%x\n", + layer_list[ndx].pipe_ndx); + return -EINVAL; + } - if (mode != vinfo[0]->multirect.mode) { - pr_err("unable to set different multirect modes for pipe_ndx=%d (%d %d)\n", - layer_list[ndx].pipe_ndx, ndx, i); - return -EINVAL; - } + rect_num = layer_list[ndx].rect_num; + if (rect_num >= MDSS_MDP_PIPE_MAX_RECTS) + return -EINVAL; + validate_info_list[ndx].multirect.num = rect_num; - pr_debug("found matching pair for pipe_ndx=%d (%d %d)\n", - layer_list[i].pipe_ndx, ndx, i); + return 0; +} - vinfo[cnt] = &validate_info_list[i]; - vinfo[cnt]->multirect.num = cnt; - vinfo[cnt]->multirect.next = vinfo[0]->layer; - vinfo[cnt]->multirect.mode = mode; - vinfo[cnt]->layer = &layer_list[i]; +static int __update_multirect_info(struct msm_fb_data_type *mfd, + struct mdss_mdp_validate_info_t *validate_info_list, + struct mdp_input_layer *layer_list, + int ndx, size_t layer_cnt, int is_rect_num_valid) +{ + int ret; + int pair_rect_num = -1; + int pair_index; + + if (!is_rect_num_valid) + layer_list[ndx].rect_num = MDSS_MDP_PIPE_RECT0; + + ret = __validate_multirect_param(mfd, validate_info_list, + layer_list, ndx, layer_cnt); + /* return if we hit error or multirectangle mode is disabled. */ + if (IS_ERR_VALUE(ret) || + (!ret && validate_info_list[ndx].multirect.mode == + MDSS_MDP_PIPE_MULTIRECT_NONE)) + return ret; - vinfo[cnt - 1]->multirect.next = vinfo[cnt]->layer; - cnt++; - } - } + if (is_rect_num_valid) + pair_rect_num = (validate_info_list[ndx].multirect.num == + MDSS_MDP_PIPE_RECT0) ? MDSS_MDP_PIPE_RECT1 : + MDSS_MDP_PIPE_RECT0; - if (cnt == 1) { - pr_err("multirect mode enabled but unable to find extra rects for pipe_ndx=%x\n", + pair_index = find_layer(get_pipe_num_from_ndx( + layer_list[ndx].pipe_ndx), pair_rect_num, + layer_list, layer_cnt, ndx + 1); + if (IS_ERR_VALUE(pair_index)) { + pr_err("Multirect pair not found for pipe ndx 0x%x\n", layer_list[ndx].pipe_ndx); return -EINVAL; } - return cnt; + if (!is_rect_num_valid) + layer_list[pair_index].rect_num = MDSS_MDP_PIPE_RECT1; + + ret = __validate_multirect_param(mfd, validate_info_list, + layer_list, pair_index, layer_cnt); + if (IS_ERR_VALUE(ret) || + (validate_info_list[ndx].multirect.mode != + validate_info_list[pair_index].multirect.mode)) + return -EINVAL; + + validate_info_list[ndx].multirect.next = &layer_list[pair_index]; + validate_info_list[pair_index].multirect.next = &layer_list[ndx]; + + return 0; } static int __validate_multirect(struct msm_fb_data_type *mfd, - struct mdss_mdp_validate_info_t *validate_info_list, - struct mdp_input_layer *layer_list, int ndx, int layer_cnt) + struct mdss_mdp_validate_info_t *validate_info_list, + struct mdp_input_layer *layer_list, + int ndx, size_t layer_cnt, int is_rect_num_valid) { - struct mdp_input_layer *layers[MDSS_MDP_PIPE_MAX_RECTS] = { 0 }; - int i, cnt, rc; - - cnt = __update_multirect_info(mfd, validate_info_list, - layer_list, ndx, layer_cnt); - if (IS_ERR_VALUE(cnt)) - return cnt; - - if (cnt <= 1) { - /* nothing to validate in single rect mode */ - return 0; - } else if (cnt > 2) { - pr_err("unsupported multirect configuration, multirect cnt=%d\n", - cnt); - return -EINVAL; - } + int ret; + int i; + struct mdp_input_layer *layers[MDSS_MDP_PIPE_MAX_RECTS]; + struct mdp_input_layer *pair_layer; + + ret = __update_multirect_info(mfd, validate_info_list, + layer_list, ndx, layer_cnt, is_rect_num_valid); + /* return if we hit error or multirectangle mode is disabled. */ + if (IS_ERR_VALUE(ret) || + (!ret && validate_info_list[ndx].multirect.mode == + MDSS_MDP_PIPE_MULTIRECT_NONE)) + return ret; - layers[0] = validate_info_list[ndx].layer; - layers[1] = validate_info_list[ndx].multirect.next; + layers[validate_info_list[ndx].multirect.num] = &layer_list[ndx]; + pair_layer = validate_info_list[ndx].multirect.next; + layers[pair_layer->rect_num] = pair_layer; + /* check against smart DMA v1.0 restrictions */ for (i = 0; i < ARRAY_SIZE(__multirect_validators); i++) { - if (!__multirect_validators[i](layers, cnt)) + if (!__multirect_validators[i](layers, + MDSS_MDP_PIPE_MAX_RECTS)) return -EINVAL; } - - rc = __multirect_validate_mode(mfd, layers, cnt); - if (IS_ERR_VALUE(rc)) - return rc; + ret = __multirect_validate_mode(mfd, layers, MDSS_MDP_PIPE_MAX_RECTS); + if (IS_ERR_VALUE(ret)) + return ret; return 0; } @@ -2416,14 +2458,14 @@ static int __validate_layers(struct msm_fb_data_type *mfd, if (!validate_info_list[i].layer) { ret = __validate_multirect(mfd, validate_info_list, - layer_list, i, layer_count); + layer_list, i, layer_count, + !!(commit->flags & MDP_COMMIT_RECT_NUM)); if (ret) { pr_err("error validating multirect config. ret=%d i=%d\n", ret, i); goto end; } } - rect_num = validate_info_list[i].multirect.num; BUG_ON(rect_num >= MDSS_MDP_PIPE_MAX_RECTS); @@ -2782,7 +2824,8 @@ int mdss_mdp_layer_pre_commit(struct msm_fb_data_type *mfd, for (i = 0; i < layer_count; i++) { if (!validate_info_list[i].layer) { ret = __update_multirect_info(mfd, validate_info_list, - layer_list, i, layer_count); + layer_list, i, layer_count, + !!(commit->flags & MDP_COMMIT_RECT_NUM)); if (IS_ERR_VALUE(ret)) { pr_err("error updating multirect config. ret=%d i=%d\n", ret, i); @@ -3035,6 +3078,12 @@ int mdss_mdp_layer_pre_commit_wfd(struct msm_fb_data_type *mfd, wfd = mdp5_data->wfd; output_layer = commit->output_layer; + if (output_layer->buffer.plane_count > MAX_PLANES) { + pr_err("Output buffer plane_count exceeds MAX_PLANES limit:%d\n", + output_layer->buffer.plane_count); + return -EINVAL; + } + data = mdss_mdp_wfd_add_data(wfd, output_layer); if (IS_ERR_OR_NULL(data)) return PTR_ERR(data); diff --git a/drivers/video/fbdev/msm/mdss_mdp_overlay.c b/drivers/video/fbdev/msm/mdss_mdp_overlay.c index 8c612e2b83fb..87fff44af389 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_overlay.c +++ b/drivers/video/fbdev/msm/mdss_mdp_overlay.c @@ -3053,6 +3053,13 @@ static void mdss_mdp_overlay_pan_display(struct msm_fb_data_type *mfd) goto pipe_release; } + if (l_pipe_allocated && + (l_pipe->multirect.num == MDSS_MDP_PIPE_RECT1)) { + pr_err("Invalid: L_Pipe-%d is assigned for RECT-%d\n", + l_pipe->num, l_pipe->multirect.num); + goto pipe_release; + } + if (mdss_mdp_pipe_map(l_pipe)) { pr_err("unable to map base pipe\n"); goto pipe_release; @@ -3100,6 +3107,16 @@ static void mdss_mdp_overlay_pan_display(struct msm_fb_data_type *mfd) goto iommu_disable; } + if (l_pipe_allocated && r_pipe_allocated && + (l_pipe->num != r_pipe->num) && + (r_pipe->multirect.num == + MDSS_MDP_PIPE_RECT1)) { + pr_err("Invalid: L_Pipe-%d,RECT-%d R_Pipe-%d,RECT-%d\n", + l_pipe->num, l_pipe->multirect.num, + r_pipe->num, l_pipe->multirect.num); + goto iommu_disable; + } + if (mdss_mdp_pipe_map(r_pipe)) { pr_err("unable to map right base pipe\n"); goto iommu_disable; diff --git a/drivers/video/fbdev/msm/mdss_mdp_pp.c b/drivers/video/fbdev/msm/mdss_mdp_pp.c index f128f82fab04..2e85072c4cf7 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_pp.c +++ b/drivers/video/fbdev/msm/mdss_mdp_pp.c @@ -2599,6 +2599,7 @@ int mdss_mdp_dest_scaler_setup_locked(struct mdss_mdp_mixer *mixer) u32 op_mode; u32 mask; char *ds_offset; + int mixer_num = 0; if (!mixer || !mixer->ctl || !mixer->ctl->mdata) return -EINVAL; @@ -2658,6 +2659,14 @@ int mdss_mdp_dest_scaler_setup_locked(struct mdss_mdp_mixer *mixer) pr_err("Failed setup destination scaler\n"); return ret; } + /* Set LM Flush in order to update DS registers */ + if (ds->flags & DS_SCALE_UPDATE) { + mutex_lock(&ctl->flush_lock); + mixer_num = mdss_mdp_mixer_get_hw_num(mixer); + ctl->flush_bits |= + BIT(mixer_num < 5 ? 6 + mixer_num : 20); + mutex_unlock(&ctl->flush_lock); + } /* * Clearing the flag because we don't need to program the block * for each commit if there is no change. diff --git a/drivers/video/fbdev/msm/mdss_mdp_util.c b/drivers/video/fbdev/msm/mdss_mdp_util.c index d0bf61679f61..22656175edf8 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_util.c +++ b/drivers/video/fbdev/msm/mdss_mdp_util.c @@ -1095,7 +1095,7 @@ static int mdss_mdp_get_img(struct msmfb_data *img, return ret; } } - if (!*start) { + if (start && !*start) { pr_err("start address is zero!\n"); mdss_mdp_put_img(data, rotator, dir); return -ENOMEM; diff --git a/drivers/video/fbdev/msm/mdss_mdp_wfd.c b/drivers/video/fbdev/msm/mdss_mdp_wfd.c index 71a07f6b7d39..7868dc0f1999 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_wfd.c +++ b/drivers/video/fbdev/msm/mdss_mdp_wfd.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -322,6 +322,12 @@ int mdss_mdp_wb_import_data(struct device *device, if (wfd_data->layer.flags & MDP_LAYER_SECURE_SESSION) flags = MDP_SECURE_OVERLAY_SESSION; + if (buffer->plane_count > MAX_PLANES) { + pr_err("buffer plane_count exceeds MAX_PLANES limit:%d", + buffer->plane_count); + return -EINVAL; + } + memset(planes, 0, sizeof(planes)); for (i = 0; i < buffer->plane_count; i++) { diff --git a/drivers/video/fbdev/msm/mdss_rotator.c b/drivers/video/fbdev/msm/mdss_rotator.c index fdd1c0153ce0..399a12e3dcc8 100644 --- a/drivers/video/fbdev/msm/mdss_rotator.c +++ b/drivers/video/fbdev/msm/mdss_rotator.c @@ -501,6 +501,12 @@ static int mdss_rotator_import_buffer(struct mdp_layer_buffer *buffer, memset(planes, 0, sizeof(planes)); + if (buffer->plane_count > MAX_PLANES) { + pr_err("buffer plane_count exceeds MAX_PLANES limit:%d\n", + buffer->plane_count); + return -EINVAL; + } + for (i = 0; i < buffer->plane_count; i++) { planes[i].memory_id = buffer->planes[i].fd; planes[i].offset = buffer->planes[i].offset; @@ -2104,6 +2110,20 @@ struct mdss_rot_entry_container *mdss_rotator_req_init( struct mdss_rot_entry_container *req; int size, i; + /* + * Check input and output plane_count from each given item + * are within the MAX_PLANES limit + */ + for (i = 0 ; i < count; i++) { + if ((items[i].input.plane_count > MAX_PLANES) || + (items[i].output.plane_count > MAX_PLANES)) { + pr_err("Input/Output plane_count exceeds MAX_PLANES limit, input:%d, output:%d\n", + items[i].input.plane_count, + items[i].output.plane_count); + return ERR_PTR(-EINVAL); + } + } + size = sizeof(struct mdss_rot_entry_container); size += sizeof(struct mdss_rot_entry) * count; req = devm_kzalloc(&mgr->pdev->dev, size, GFP_KERNEL); diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 94906aaa9b7c..e2f6a79e9b01 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -227,6 +227,7 @@ struct smb_version_operations { /* verify the message */ int (*check_message)(char *, unsigned int); bool (*is_oplock_break)(char *, struct TCP_Server_Info *); + int (*handle_cancelled_mid)(char *, struct TCP_Server_Info *); void (*downgrade_oplock)(struct TCP_Server_Info *, struct cifsInodeInfo *, bool); /* process transaction2 response */ @@ -1289,12 +1290,19 @@ struct mid_q_entry { void *callback_data; /* general purpose pointer for callback */ void *resp_buf; /* pointer to received SMB header */ int mid_state; /* wish this were enum but can not pass to wait_event */ + unsigned int mid_flags; __le16 command; /* smb command code */ bool large_buf:1; /* if valid response, is pointer to large buf */ bool multiRsp:1; /* multiple trans2 responses for one request */ bool multiEnd:1; /* both received */ }; +struct close_cancelled_open { + struct cifs_fid fid; + struct cifs_tcon *tcon; + struct work_struct work; +}; + /* Make code in transport.c a little cleaner by moving update of optional stats into function below */ #ifdef CONFIG_CIFS_STATS2 @@ -1426,6 +1434,9 @@ static inline void free_dfs_info_array(struct dfs_info3_param *param, #define MID_RESPONSE_MALFORMED 0x10 #define MID_SHUTDOWN 0x20 +/* Flags */ +#define MID_WAIT_CANCELLED 1 /* Cancelled while waiting for response */ + /* Types of response buffer returned from SendReceive2 */ #define CIFS_NO_BUFFER 0 /* Response buffer not returned */ #define CIFS_SMALL_BUFFER 1 diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index b1104ed8f54c..5e2f8b8ca08a 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -1424,6 +1424,8 @@ cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid) length = discard_remaining_data(server); dequeue_mid(mid, rdata->result); + mid->resp_buf = server->smallbuf; + server->smallbuf = NULL; return length; } @@ -1538,6 +1540,8 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid) return cifs_readv_discard(server, mid); dequeue_mid(mid, false); + mid->resp_buf = server->smallbuf; + server->smallbuf = NULL; return length; } diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 5d59f25521ce..156bc18eac69 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -924,10 +924,19 @@ cifs_demultiplex_thread(void *p) server->lstrp = jiffies; if (mid_entry != NULL) { + if ((mid_entry->mid_flags & MID_WAIT_CANCELLED) && + mid_entry->mid_state == MID_RESPONSE_RECEIVED && + server->ops->handle_cancelled_mid) + server->ops->handle_cancelled_mid( + mid_entry->resp_buf, + server); + if (!mid_entry->multiRsp || mid_entry->multiEnd) mid_entry->callback(mid_entry); - } else if (!server->ops->is_oplock_break || - !server->ops->is_oplock_break(buf, server)) { + } else if (server->ops->is_oplock_break && + server->ops->is_oplock_break(buf, server)) { + cifs_dbg(FYI, "Received oplock break\n"); + } else { cifs_dbg(VFS, "No task to wake, unknown frame received! NumMids %d\n", atomic_read(&midCount)); cifs_dump_mem("Received Data is: ", buf, diff --git a/fs/cifs/smb2misc.c b/fs/cifs/smb2misc.c index e5bc85e49be7..76ccf20fbfb7 100644 --- a/fs/cifs/smb2misc.c +++ b/fs/cifs/smb2misc.c @@ -630,3 +630,47 @@ smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server) cifs_dbg(FYI, "Can not process oplock break for non-existent connection\n"); return false; } + +void +smb2_cancelled_close_fid(struct work_struct *work) +{ + struct close_cancelled_open *cancelled = container_of(work, + struct close_cancelled_open, work); + + cifs_dbg(VFS, "Close unmatched open\n"); + + SMB2_close(0, cancelled->tcon, cancelled->fid.persistent_fid, + cancelled->fid.volatile_fid); + cifs_put_tcon(cancelled->tcon); + kfree(cancelled); +} + +int +smb2_handle_cancelled_mid(char *buffer, struct TCP_Server_Info *server) +{ + struct smb2_hdr *hdr = (struct smb2_hdr *)buffer; + struct smb2_create_rsp *rsp = (struct smb2_create_rsp *)buffer; + struct cifs_tcon *tcon; + struct close_cancelled_open *cancelled; + + if (hdr->Command != SMB2_CREATE || hdr->Status != STATUS_SUCCESS) + return 0; + + cancelled = kzalloc(sizeof(*cancelled), GFP_KERNEL); + if (!cancelled) + return -ENOMEM; + + tcon = smb2_find_smb_tcon(server, hdr->SessionId, hdr->TreeId); + if (!tcon) { + kfree(cancelled); + return -ENOENT; + } + + cancelled->fid.persistent_fid = rsp->PersistentFileId; + cancelled->fid.volatile_fid = rsp->VolatileFileId; + cancelled->tcon = tcon; + INIT_WORK(&cancelled->work, smb2_cancelled_close_fid); + queue_work(cifsiod_wq, &cancelled->work); + + return 0; +} diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index be34b4860675..087918c4612a 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -1511,6 +1511,7 @@ struct smb_version_operations smb20_operations = { .clear_stats = smb2_clear_stats, .print_stats = smb2_print_stats, .is_oplock_break = smb2_is_valid_oplock_break, + .handle_cancelled_mid = smb2_handle_cancelled_mid, .downgrade_oplock = smb2_downgrade_oplock, .need_neg = smb2_need_neg, .negotiate = smb2_negotiate, @@ -1589,6 +1590,7 @@ struct smb_version_operations smb21_operations = { .clear_stats = smb2_clear_stats, .print_stats = smb2_print_stats, .is_oplock_break = smb2_is_valid_oplock_break, + .handle_cancelled_mid = smb2_handle_cancelled_mid, .downgrade_oplock = smb2_downgrade_oplock, .need_neg = smb2_need_neg, .negotiate = smb2_negotiate, @@ -1670,6 +1672,7 @@ struct smb_version_operations smb30_operations = { .print_stats = smb2_print_stats, .dump_share_caps = smb2_dump_share_caps, .is_oplock_break = smb2_is_valid_oplock_break, + .handle_cancelled_mid = smb2_handle_cancelled_mid, .downgrade_oplock = smb2_downgrade_oplock, .need_neg = smb2_need_neg, .negotiate = smb2_negotiate, @@ -1757,6 +1760,7 @@ struct smb_version_operations smb311_operations = { .print_stats = smb2_print_stats, .dump_share_caps = smb2_dump_share_caps, .is_oplock_break = smb2_is_valid_oplock_break, + .handle_cancelled_mid = smb2_handle_cancelled_mid, .downgrade_oplock = smb2_downgrade_oplock, .need_neg = smb2_need_neg, .negotiate = smb2_negotiate, diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h index 0a406ae78129..adc5234486c3 100644 --- a/fs/cifs/smb2proto.h +++ b/fs/cifs/smb2proto.h @@ -47,6 +47,10 @@ extern struct mid_q_entry *smb2_setup_request(struct cifs_ses *ses, struct smb_rqst *rqst); extern struct mid_q_entry *smb2_setup_async_request( struct TCP_Server_Info *server, struct smb_rqst *rqst); +extern struct cifs_ses *smb2_find_smb_ses(struct TCP_Server_Info *server, + __u64 ses_id); +extern struct cifs_tcon *smb2_find_smb_tcon(struct TCP_Server_Info *server, + __u64 ses_id, __u32 tid); extern int smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server); extern int smb3_calc_signature(struct smb_rqst *rqst, @@ -157,6 +161,9 @@ extern int SMB2_set_compression(const unsigned int xid, struct cifs_tcon *tcon, extern int SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon, const u64 persistent_fid, const u64 volatile_fid, const __u8 oplock_level); +extern int smb2_handle_cancelled_mid(char *buffer, + struct TCP_Server_Info *server); +void smb2_cancelled_close_fid(struct work_struct *work); extern int SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_file_id, u64 volatile_file_id, struct kstatfs *FSData); diff --git a/fs/cifs/smb2transport.c b/fs/cifs/smb2transport.c index d4c5b6f109a7..69e3b322bbfe 100644 --- a/fs/cifs/smb2transport.c +++ b/fs/cifs/smb2transport.c @@ -115,22 +115,68 @@ smb3_crypto_shash_allocate(struct TCP_Server_Info *server) } static struct cifs_ses * -smb2_find_smb_ses(struct smb2_hdr *smb2hdr, struct TCP_Server_Info *server) +smb2_find_smb_ses_unlocked(struct TCP_Server_Info *server, __u64 ses_id) { struct cifs_ses *ses; - spin_lock(&cifs_tcp_ses_lock); list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) { - if (ses->Suid != smb2hdr->SessionId) + if (ses->Suid != ses_id) continue; - spin_unlock(&cifs_tcp_ses_lock); return ses; } + + return NULL; +} + +struct cifs_ses * +smb2_find_smb_ses(struct TCP_Server_Info *server, __u64 ses_id) +{ + struct cifs_ses *ses; + + spin_lock(&cifs_tcp_ses_lock); + ses = smb2_find_smb_ses_unlocked(server, ses_id); spin_unlock(&cifs_tcp_ses_lock); + return ses; +} + +static struct cifs_tcon * +smb2_find_smb_sess_tcon_unlocked(struct cifs_ses *ses, __u32 tid) +{ + struct cifs_tcon *tcon; + + list_for_each_entry(tcon, &ses->tcon_list, tcon_list) { + if (tcon->tid != tid) + continue; + ++tcon->tc_count; + return tcon; + } + return NULL; } +/* + * Obtain tcon corresponding to the tid in the given + * cifs_ses + */ + +struct cifs_tcon * +smb2_find_smb_tcon(struct TCP_Server_Info *server, __u64 ses_id, __u32 tid) +{ + struct cifs_ses *ses; + struct cifs_tcon *tcon; + + spin_lock(&cifs_tcp_ses_lock); + ses = smb2_find_smb_ses_unlocked(server, ses_id); + if (!ses) { + spin_unlock(&cifs_tcp_ses_lock); + return NULL; + } + tcon = smb2_find_smb_sess_tcon_unlocked(ses, tid); + spin_unlock(&cifs_tcp_ses_lock); + + return tcon; +} int smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) @@ -143,7 +189,7 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) struct smb2_hdr *smb2_pdu = (struct smb2_hdr *)iov[0].iov_base; struct cifs_ses *ses; - ses = smb2_find_smb_ses(smb2_pdu, server); + ses = smb2_find_smb_ses(server, smb2_pdu->SessionId); if (!ses) { cifs_dbg(VFS, "%s: Could not find session\n", __func__); return 0; @@ -314,7 +360,7 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) struct smb2_hdr *smb2_pdu = (struct smb2_hdr *)iov[0].iov_base; struct cifs_ses *ses; - ses = smb2_find_smb_ses(smb2_pdu, server); + ses = smb2_find_smb_ses(server, smb2_pdu->SessionId); if (!ses) { cifs_dbg(VFS, "%s: Could not find session\n", __func__); return 0; diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 87abe8ed074c..54af10204e83 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -786,9 +786,11 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses, rc = wait_for_response(ses->server, midQ); if (rc != 0) { + cifs_dbg(FYI, "Cancelling wait for mid %llu\n", midQ->mid); send_cancel(ses->server, buf, midQ); spin_lock(&GlobalMid_Lock); if (midQ->mid_state == MID_REQUEST_SUBMITTED) { + midQ->mid_flags |= MID_WAIT_CANCELLED; midQ->callback = DeleteMidQEntry; spin_unlock(&GlobalMid_Lock); cifs_small_buf_release(buf); diff --git a/fs/ext4/crypto.c b/fs/ext4/crypto.c index 664f42c850b7..e14b1b8fceb0 100644 --- a/fs/ext4/crypto.c +++ b/fs/ext4/crypto.c @@ -497,11 +497,6 @@ static int ext4_d_revalidate(struct dentry *dentry, unsigned int flags) return 0; } ci = EXT4_I(d_inode(dir))->i_crypt_info; - if (ci && ci->ci_keyring_key && - (ci->ci_keyring_key->flags & ((1 << KEY_FLAG_INVALIDATED) | - (1 << KEY_FLAG_REVOKED) | - (1 << KEY_FLAG_DEAD)))) - ci = NULL; /* this should eventually be an flag in d_flags */ cached_with_key = dentry->d_fsdata != NULL; diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c index 3a2594665b44..c21826be1cb3 100644 --- a/fs/ext4/ioctl.c +++ b/fs/ext4/ioctl.c @@ -626,6 +626,9 @@ resizefs_out: struct ext4_encryption_policy policy; int err = 0; + if (!ext4_has_feature_encrypt(sb)) + return -EOPNOTSUPP; + if (copy_from_user(&policy, (struct ext4_encryption_policy __user *)arg, sizeof(policy))) { diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 92ac61c3ccf7..d2e75fe2e072 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -918,6 +918,79 @@ loff_t max_file_size(unsigned bits) return result; } +static inline bool sanity_check_area_boundary(struct super_block *sb, + struct f2fs_super_block *raw_super) +{ + u32 segment0_blkaddr = le32_to_cpu(raw_super->segment0_blkaddr); + u32 cp_blkaddr = le32_to_cpu(raw_super->cp_blkaddr); + u32 sit_blkaddr = le32_to_cpu(raw_super->sit_blkaddr); + u32 nat_blkaddr = le32_to_cpu(raw_super->nat_blkaddr); + u32 ssa_blkaddr = le32_to_cpu(raw_super->ssa_blkaddr); + u32 main_blkaddr = le32_to_cpu(raw_super->main_blkaddr); + u32 segment_count_ckpt = le32_to_cpu(raw_super->segment_count_ckpt); + u32 segment_count_sit = le32_to_cpu(raw_super->segment_count_sit); + u32 segment_count_nat = le32_to_cpu(raw_super->segment_count_nat); + u32 segment_count_ssa = le32_to_cpu(raw_super->segment_count_ssa); + u32 segment_count_main = le32_to_cpu(raw_super->segment_count_main); + u32 segment_count = le32_to_cpu(raw_super->segment_count); + u32 log_blocks_per_seg = le32_to_cpu(raw_super->log_blocks_per_seg); + + if (segment0_blkaddr != cp_blkaddr) { + f2fs_msg(sb, KERN_INFO, + "Mismatch start address, segment0(%u) cp_blkaddr(%u)", + segment0_blkaddr, cp_blkaddr); + return true; + } + + if (cp_blkaddr + (segment_count_ckpt << log_blocks_per_seg) != + sit_blkaddr) { + f2fs_msg(sb, KERN_INFO, + "Wrong CP boundary, start(%u) end(%u) blocks(%u)", + cp_blkaddr, sit_blkaddr, + segment_count_ckpt << log_blocks_per_seg); + return true; + } + + if (sit_blkaddr + (segment_count_sit << log_blocks_per_seg) != + nat_blkaddr) { + f2fs_msg(sb, KERN_INFO, + "Wrong SIT boundary, start(%u) end(%u) blocks(%u)", + sit_blkaddr, nat_blkaddr, + segment_count_sit << log_blocks_per_seg); + return true; + } + + if (nat_blkaddr + (segment_count_nat << log_blocks_per_seg) != + ssa_blkaddr) { + f2fs_msg(sb, KERN_INFO, + "Wrong NAT boundary, start(%u) end(%u) blocks(%u)", + nat_blkaddr, ssa_blkaddr, + segment_count_nat << log_blocks_per_seg); + return true; + } + + if (ssa_blkaddr + (segment_count_ssa << log_blocks_per_seg) != + main_blkaddr) { + f2fs_msg(sb, KERN_INFO, + "Wrong SSA boundary, start(%u) end(%u) blocks(%u)", + ssa_blkaddr, main_blkaddr, + segment_count_ssa << log_blocks_per_seg); + return true; + } + + if (main_blkaddr + (segment_count_main << log_blocks_per_seg) != + segment0_blkaddr + (segment_count << log_blocks_per_seg)) { + f2fs_msg(sb, KERN_INFO, + "Wrong MAIN_AREA boundary, start(%u) end(%u) blocks(%u)", + main_blkaddr, + segment0_blkaddr + (segment_count << log_blocks_per_seg), + segment_count_main << log_blocks_per_seg); + return true; + } + + return false; +} + static int sanity_check_raw_super(struct super_block *sb, struct f2fs_super_block *raw_super) { @@ -973,6 +1046,23 @@ static int sanity_check_raw_super(struct super_block *sb, le32_to_cpu(raw_super->log_sectorsize)); return 1; } + + /* check reserved ino info */ + if (le32_to_cpu(raw_super->node_ino) != 1 || + le32_to_cpu(raw_super->meta_ino) != 2 || + le32_to_cpu(raw_super->root_ino) != 3) { + f2fs_msg(sb, KERN_INFO, + "Invalid Fs Meta Ino: node(%u) meta(%u) root(%u)", + le32_to_cpu(raw_super->node_ino), + le32_to_cpu(raw_super->meta_ino), + le32_to_cpu(raw_super->root_ino)); + return 1; + } + + /* check CP/SIT/NAT/SSA/MAIN_AREA area boundary */ + if (sanity_check_area_boundary(sb, raw_super)) + return 1; + return 0; } diff --git a/fs/mbcache.c b/fs/mbcache.c index 187477ded6b3..ab1da987d1ae 100644 --- a/fs/mbcache.c +++ b/fs/mbcache.c @@ -262,7 +262,6 @@ mb_cache_shrink_scan(struct shrinker *shrink, struct shrink_control *sc) list_del_init(&ce->e_lru_list); if (ce->e_used || ce->e_queued || atomic_read(&ce->e_refcnt)) continue; - spin_unlock(&mb_cache_spinlock); /* Prevent any find or get operation on the entry */ hlist_bl_lock(ce->e_block_hash_p); hlist_bl_lock(ce->e_index_hash_p); @@ -271,10 +270,10 @@ mb_cache_shrink_scan(struct shrinker *shrink, struct shrink_control *sc) !list_empty(&ce->e_lru_list)) { hlist_bl_unlock(ce->e_index_hash_p); hlist_bl_unlock(ce->e_block_hash_p); - spin_lock(&mb_cache_spinlock); continue; } __mb_cache_entry_unhash_unlock(ce); + spin_unlock(&mb_cache_spinlock); list_add_tail(&ce->e_lru_list, &free_list); spin_lock(&mb_cache_spinlock); } @@ -516,7 +515,6 @@ mb_cache_entry_alloc(struct mb_cache *cache, gfp_t gfp_flags) if (ce->e_used || ce->e_queued || atomic_read(&ce->e_refcnt)) continue; - spin_unlock(&mb_cache_spinlock); /* * Prevent any find or get operation on the * entry. @@ -530,13 +528,13 @@ mb_cache_entry_alloc(struct mb_cache *cache, gfp_t gfp_flags) hlist_bl_unlock(ce->e_index_hash_p); hlist_bl_unlock(ce->e_block_hash_p); l = &mb_cache_lru_list; - spin_lock(&mb_cache_spinlock); continue; } mb_assert(list_empty(&ce->e_lru_list)); mb_assert(!(ce->e_used || ce->e_queued || atomic_read(&ce->e_refcnt))); __mb_cache_entry_unhash_unlock(ce); + spin_unlock(&mb_cache_spinlock); goto found; } } @@ -670,6 +668,7 @@ mb_cache_entry_get(struct mb_cache *cache, struct block_device *bdev, cache->c_bucket_bits); block_hash_p = &cache->c_block_hash[bucket]; /* First serialize access to the block corresponding hash chain. */ + spin_lock(&mb_cache_spinlock); hlist_bl_lock(block_hash_p); hlist_bl_for_each_entry(ce, l, block_hash_p, e_block_list) { mb_assert(ce->e_block_hash_p == block_hash_p); @@ -678,9 +677,11 @@ mb_cache_entry_get(struct mb_cache *cache, struct block_device *bdev, * Prevent a free from removing the entry. */ atomic_inc(&ce->e_refcnt); + if (!list_empty(&ce->e_lru_list)) + list_del_init(&ce->e_lru_list); hlist_bl_unlock(block_hash_p); + spin_unlock(&mb_cache_spinlock); __spin_lock_mb_cache_entry(ce); - atomic_dec(&ce->e_refcnt); if (ce->e_used > 0) { DEFINE_WAIT(wait); while (ce->e_used > 0) { @@ -695,13 +696,9 @@ mb_cache_entry_get(struct mb_cache *cache, struct block_device *bdev, finish_wait(&mb_cache_queue, &wait); } ce->e_used += 1 + MB_CACHE_WRITER; + atomic_dec(&ce->e_refcnt); __spin_unlock_mb_cache_entry(ce); - if (!list_empty(&ce->e_lru_list)) { - spin_lock(&mb_cache_spinlock); - list_del_init(&ce->e_lru_list); - spin_unlock(&mb_cache_spinlock); - } if (!__mb_cache_entry_is_block_hashed(ce)) { __mb_cache_entry_release(ce); return NULL; @@ -710,6 +707,7 @@ mb_cache_entry_get(struct mb_cache *cache, struct block_device *bdev, } } hlist_bl_unlock(block_hash_p); + spin_unlock(&mb_cache_spinlock); return NULL; } diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c index 00575d776d91..7162ab7bc093 100644 --- a/fs/nfsd/nfs3xdr.c +++ b/fs/nfsd/nfs3xdr.c @@ -358,6 +358,7 @@ nfs3svc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p, { unsigned int len, v, hdr, dlen; u32 max_blocksize = svc_max_payload(rqstp); + struct kvec *head = rqstp->rq_arg.head; p = decode_fh(p, &args->fh); if (!p) @@ -367,6 +368,8 @@ nfs3svc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p, args->count = ntohl(*p++); args->stable = ntohl(*p++); len = args->len = ntohl(*p++); + if ((void *)p > head->iov_base + head->iov_len) + return 0; /* * The count must equal the amount of data passed. */ @@ -377,9 +380,8 @@ nfs3svc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p, * Check to make sure that we got the right number of * bytes. */ - hdr = (void*)p - rqstp->rq_arg.head[0].iov_base; - dlen = rqstp->rq_arg.head[0].iov_len + rqstp->rq_arg.page_len - - hdr; + hdr = (void*)p - head->iov_base; + dlen = head->iov_len + rqstp->rq_arg.page_len - hdr; /* * Round the length of the data which was specified up to * the next multiple of XDR units and then compare that @@ -396,7 +398,7 @@ nfs3svc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p, len = args->len = max_blocksize; } rqstp->rq_vec[0].iov_base = (void*)p; - rqstp->rq_vec[0].iov_len = rqstp->rq_arg.head[0].iov_len - hdr; + rqstp->rq_vec[0].iov_len = head->iov_len - hdr; v = 0; while (len > rqstp->rq_vec[v].iov_len) { len -= rqstp->rq_vec[v].iov_len; @@ -471,6 +473,8 @@ nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, __be32 *p, /* first copy and check from the first page */ old = (char*)p; vec = &rqstp->rq_arg.head[0]; + if ((void *)old > vec->iov_base + vec->iov_len) + return 0; avail = vec->iov_len - (old - (char*)vec->iov_base); while (len && avail && *old) { *new++ = *old++; diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index ad4e2377dd63..5be1fa6b676d 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -656,6 +656,37 @@ static __be32 map_new_errors(u32 vers, __be32 nfserr) return nfserr; } +/* + * A write procedure can have a large argument, and a read procedure can + * have a large reply, but no NFSv2 or NFSv3 procedure has argument and + * reply that can both be larger than a page. The xdr code has taken + * advantage of this assumption to be a sloppy about bounds checking in + * some cases. Pending a rewrite of the NFSv2/v3 xdr code to fix that + * problem, we enforce these assumptions here: + */ +static bool nfs_request_too_big(struct svc_rqst *rqstp, + struct svc_procedure *proc) +{ + /* + * The ACL code has more careful bounds-checking and is not + * susceptible to this problem: + */ + if (rqstp->rq_prog != NFS_PROGRAM) + return false; + /* + * Ditto NFSv4 (which can in theory have argument and reply both + * more than a page): + */ + if (rqstp->rq_vers >= 4) + return false; + /* The reply will be small, we're OK: */ + if (proc->pc_xdrressize > 0 && + proc->pc_xdrressize < XDR_QUADLEN(PAGE_SIZE)) + return false; + + return rqstp->rq_arg.len > PAGE_SIZE; +} + int nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp) { @@ -668,6 +699,11 @@ nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp) rqstp->rq_vers, rqstp->rq_proc); proc = rqstp->rq_procinfo; + if (nfs_request_too_big(rqstp, proc)) { + dprintk("nfsd: NFSv%d argument too large\n", rqstp->rq_vers); + *statp = rpc_garbage_args; + return 1; + } /* * Give the xdr decoder a chance to change this if it wants * (necessary in the NFSv4.0 compound case) diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c index 79d964aa8079..bf913201a6ad 100644 --- a/fs/nfsd/nfsxdr.c +++ b/fs/nfsd/nfsxdr.c @@ -280,6 +280,7 @@ nfssvc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd_writeargs *args) { unsigned int len, hdr, dlen; + struct kvec *head = rqstp->rq_arg.head; int v; p = decode_fh(p, &args->fh); @@ -300,9 +301,10 @@ nfssvc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p, * Check to make sure that we got the right number of * bytes. */ - hdr = (void*)p - rqstp->rq_arg.head[0].iov_base; - dlen = rqstp->rq_arg.head[0].iov_len + rqstp->rq_arg.page_len - - hdr; + hdr = (void*)p - head->iov_base; + if (hdr > head->iov_len) + return 0; + dlen = head->iov_len + rqstp->rq_arg.page_len - hdr; /* * Round the length of the data which was specified up to @@ -316,7 +318,7 @@ nfssvc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p, return 0; rqstp->rq_vec[0].iov_base = (void*)p; - rqstp->rq_vec[0].iov_len = rqstp->rq_arg.head[0].iov_len - hdr; + rqstp->rq_vec[0].iov_len = head->iov_len - hdr; v = 0; while (len > rqstp->rq_vec[v].iov_len) { len -= rqstp->rq_vec[v].iov_len; diff --git a/fs/timerfd.c b/fs/timerfd.c index 815e5348f048..0548c572839c 100644 --- a/fs/timerfd.c +++ b/fs/timerfd.c @@ -40,6 +40,7 @@ struct timerfd_ctx { short unsigned settime_flags; /* to show in fdinfo */ struct rcu_head rcu; struct list_head clist; + spinlock_t cancel_lock; bool might_cancel; }; @@ -113,7 +114,7 @@ void timerfd_clock_was_set(void) rcu_read_unlock(); } -static void timerfd_remove_cancel(struct timerfd_ctx *ctx) +static void __timerfd_remove_cancel(struct timerfd_ctx *ctx) { if (ctx->might_cancel) { ctx->might_cancel = false; @@ -123,6 +124,13 @@ static void timerfd_remove_cancel(struct timerfd_ctx *ctx) } } +static void timerfd_remove_cancel(struct timerfd_ctx *ctx) +{ + spin_lock(&ctx->cancel_lock); + __timerfd_remove_cancel(ctx); + spin_unlock(&ctx->cancel_lock); +} + static bool timerfd_canceled(struct timerfd_ctx *ctx) { if (!ctx->might_cancel || ctx->moffs.tv64 != KTIME_MAX) @@ -133,6 +141,7 @@ static bool timerfd_canceled(struct timerfd_ctx *ctx) static void timerfd_setup_cancel(struct timerfd_ctx *ctx, int flags) { + spin_lock(&ctx->cancel_lock); if ((ctx->clockid == CLOCK_REALTIME || ctx->clockid == CLOCK_REALTIME_ALARM || ctx->clockid == CLOCK_POWEROFF_ALARM) && @@ -143,9 +152,10 @@ static void timerfd_setup_cancel(struct timerfd_ctx *ctx, int flags) list_add_rcu(&ctx->clist, &cancel_list); spin_unlock(&cancel_lock); } - } else if (ctx->might_cancel) { - timerfd_remove_cancel(ctx); + } else { + __timerfd_remove_cancel(ctx); } + spin_unlock(&ctx->cancel_lock); } static ktime_t timerfd_get_remaining(struct timerfd_ctx *ctx) @@ -398,6 +408,7 @@ SYSCALL_DEFINE2(timerfd_create, int, clockid, int, flags) return -ENOMEM; init_waitqueue_head(&ctx->wqh); + spin_lock_init(&ctx->cancel_lock); ctx->clockid = clockid; if (isalarm(ctx)) { diff --git a/include/linux/msm_ext_display.h b/include/linux/msm_ext_display.h index fc53e861eba4..9a03b79e09d7 100644 --- a/include/linux/msm_ext_display.h +++ b/include/linux/msm_ext_display.h @@ -114,6 +114,7 @@ struct msm_ext_disp_intf_ops { * @cable_status: cable connected/disconnected * @get_intf_id: id of connected interface * @acknowledge: acknowledge audio status + * @codec_ready: notify when codec is ready */ struct msm_ext_disp_audio_codec_ops { int (*audio_info_setup)(struct platform_device *pdev, @@ -124,6 +125,7 @@ struct msm_ext_disp_audio_codec_ops { int (*get_intf_id)(struct platform_device *pdev); void (*teardown_done)(struct platform_device *pdev); int (*acknowledge)(struct platform_device *pdev, u32 ack); + void (*codec_ready)(struct platform_device *pdev); }; /* diff --git a/include/linux/mtd/map.h b/include/linux/mtd/map.h index 366cf77953b5..806d0ab845e0 100644 --- a/include/linux/mtd/map.h +++ b/include/linux/mtd/map.h @@ -122,18 +122,13 @@ #endif #ifdef CONFIG_MTD_MAP_BANK_WIDTH_32 -# ifdef map_bankwidth -# undef map_bankwidth -# define map_bankwidth(map) ((map)->bankwidth) -# undef map_bankwidth_is_large -# define map_bankwidth_is_large(map) (map_bankwidth(map) > BITS_PER_LONG/8) -# undef map_words -# define map_words(map) map_calc_words(map) -# else -# define map_bankwidth(map) 32 -# define map_bankwidth_is_large(map) (1) -# define map_words(map) map_calc_words(map) -# endif +/* always use indirect access for 256-bit to preserve kernel stack */ +# undef map_bankwidth +# define map_bankwidth(map) ((map)->bankwidth) +# undef map_bankwidth_is_large +# define map_bankwidth_is_large(map) (map_bankwidth(map) > BITS_PER_LONG/8) +# undef map_words +# define map_words(map) map_calc_words(map) #define map_bankwidth_is_32(map) (map_bankwidth(map) == 32) #undef MAX_MAP_BANKWIDTH #define MAX_MAP_BANKWIDTH 32 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 bcb53faaf678..084232a1d06e 100644 --- a/include/sound/apr_audio-v2.h +++ b/include/sound/apr_audio-v2.h @@ -15,6 +15,7 @@ #define _APR_AUDIO_V2_H_ #include <linux/qdsp6v2/apr.h> +#include <linux/msm_audio.h> /* size of header needed for passing data out of band */ #define APR_CMD_OB_HDR_SZ 12 @@ -447,6 +448,18 @@ struct adm_param_data_v5 { #define ASM_STREAM_PP_EVENT 0x00013214 #define DSP_STREAM_CMD "ADSP Stream Cmd" #define DSP_STREAM_CALLBACK "ADSP Stream Callback Event" +#define DSP_STREAM_CALLBACK_QUEUE_SIZE 1024 + +struct dsp_stream_callback_list { + struct list_head list; + struct msm_adsp_event_data event; +}; + +struct dsp_stream_callback_prtd { + uint16_t event_count; + struct list_head event_queue; + spinlock_t prtd_spin_lock; +}; /* set customized mixing on matrix mixer */ #define ADM_CMD_SET_PSPD_MTMX_STRTR_PARAMS_V5 0x00010344 @@ -6321,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 { @@ -10320,10 +10389,33 @@ struct asm_session_mtmx_strtr_param_clk_rec_t { u32 flags; } __packed; + +/* Parameter used by #ASM_SESSION_MTMX_STRTR_MODULE_ID_AVSYNC to + * realize smoother adjustment of audio session clock for a specified session. + * The desired audio session clock adjustment(in micro seconds) is specified + * using the command #ASM_SESSION_CMD_ADJUST_SESSION_CLOCK_V2. + * Delaying/Advancing the session clock would be implemented by inserting + * interpolated/dropping audio samples in the playback path respectively. + * Also, this parameter has to be configured before the Audio Session is put + * to RUN state to avoid cold start latency/glitches in the playback. + */ + +#define ASM_SESSION_MTMX_PARAM_ADJUST_SESSION_TIME_CTL 0x00013217 + +struct asm_session_mtmx_param_adjust_session_time_ctl_t { + /* Specifies whether the module is enabled or not + * @values + * 0 -- disabled + * 1 -- enabled + */ + u32 enable; +}; + union asm_session_mtmx_strtr_param_config { struct asm_session_mtmx_strtr_param_window_v2_t window_param; struct asm_session_mtmx_strtr_param_render_mode_t render_param; struct asm_session_mtmx_strtr_param_clk_rec_t clk_rec_param; + struct asm_session_mtmx_param_adjust_session_time_ctl_t adj_time_param; } __packed; struct asm_mtmx_strtr_params { diff --git a/include/sound/q6asm-v2.h b/include/sound/q6asm-v2.h index 41fcdeb50831..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); @@ -655,6 +660,10 @@ int q6asm_send_mtmx_strtr_render_mode(struct audio_client *ac, int q6asm_send_mtmx_strtr_clk_rec_mode(struct audio_client *ac, uint32_t clk_rec_mode); +/* Enable adjust session clock in DSP */ +int q6asm_send_mtmx_strtr_enable_adjust_session_clock(struct audio_client *ac, + bool enable); + /* Retrieve the current DSP path delay */ int q6asm_get_path_delay(struct audio_client *ac); @@ -662,4 +671,8 @@ int q6asm_get_path_delay(struct audio_client *ac); uint8_t q6asm_get_buf_index_from_token(uint32_t token); uint8_t q6asm_get_stream_id_from_token(uint32_t token); +/* Adjust session clock in DSP */ +int q6asm_adjust_session_clock(struct audio_client *ac, + uint32_t adjust_time_lsw, + uint32_t adjust_time_msw); #endif /* __Q6_ASM_H__ */ diff --git a/include/uapi/drm/drm.h b/include/uapi/drm/drm.h index 3801584a0c53..24c76d138317 100644 --- a/include/uapi/drm/drm.h +++ b/include/uapi/drm/drm.h @@ -58,6 +58,10 @@ typedef unsigned long drm_handle_t; #endif +#if defined(__cplusplus) +extern "C" { +#endif + #define DRM_NAME "drm" /**< Name in kernel, /dev, and /proc */ #define DRM_MIN_ORDER 5 /**< At least 2^5 bytes = 32 bytes */ #define DRM_MAX_ORDER 22 /**< Up to 2^22 bytes = 4MB */ @@ -372,7 +376,11 @@ struct drm_buf_pub { */ struct drm_buf_map { int count; /**< Length of the buffer list */ +#ifdef __cplusplus + void __user *virt; +#else void __user *virtual; /**< Mmap'd area in user-virtual */ +#endif struct drm_buf_pub __user *list; /**< Buffer information */ }; @@ -679,7 +687,15 @@ struct drm_prime_handle { __s32 fd; }; -#include <drm/drm_mode.h> +#if defined(__cplusplus) +} +#endif + +#include "drm_mode.h" + +#if defined(__cplusplus) +extern "C" { +#endif #define DRM_IOCTL_BASE 'd' #define DRM_IO(nr) _IO(DRM_IOCTL_BASE,nr) @@ -874,4 +890,8 @@ typedef struct drm_scatter_gather drm_scatter_gather_t; typedef struct drm_set_version drm_set_version_t; #endif +#if defined(__cplusplus) +} +#endif + #endif diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h index 53d7c80f5eb0..7f203a5f83cb 100644 --- a/include/uapi/drm/drm_fourcc.h +++ b/include/uapi/drm/drm_fourcc.h @@ -26,6 +26,10 @@ #include <linux/types.h> +#if defined(__cplusplus) +extern "C" { +#endif + #define fourcc_code(a, b, c, d) ((__u32)(a) | ((__u32)(b) << 8) | \ ((__u32)(c) << 16) | ((__u32)(d) << 24)) @@ -237,4 +241,8 @@ */ #define DRM_FORMAT_MOD_QCOM_COMPRESSED fourcc_mod_code(QCOM, 1) +#if defined(__cplusplus) +} +#endif + #endif /* DRM_FOURCC_H */ diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h index 1c5e74f1ea39..0630e0f64b9c 100644 --- a/include/uapi/drm/drm_mode.h +++ b/include/uapi/drm/drm_mode.h @@ -29,6 +29,10 @@ #include <linux/types.h> +#if defined(__cplusplus) +extern "C" { +#endif + #define DRM_DISPLAY_INFO_LEN 32 #define DRM_CONNECTOR_NAME_LEN 32 #define DRM_DISPLAY_MODE_LEN 32 @@ -599,4 +603,8 @@ struct drm_mode_destroy_blob { __u32 blob_id; }; +#if defined(__cplusplus) +} +#endif + #endif diff --git a/include/uapi/drm/drm_sarea.h b/include/uapi/drm/drm_sarea.h index 413a5642d49f..12285bc929a1 100644 --- a/include/uapi/drm/drm_sarea.h +++ b/include/uapi/drm/drm_sarea.h @@ -34,6 +34,10 @@ #include <drm/drm.h> +#if defined(__cplusplus) +extern "C" { +#endif + /* SAREA area needs to be at least a page */ #if defined(__alpha__) #define SAREA_MAX 0x2000U @@ -83,4 +87,8 @@ typedef struct drm_sarea_frame drm_sarea_frame_t; typedef struct drm_sarea drm_sarea_t; #endif +#if defined(__cplusplus) +} +#endif + #endif /* _DRM_SAREA_H_ */ diff --git a/include/uapi/drm/msm_drm.h b/include/uapi/drm/msm_drm.h index db65513ad656..48c49741d77f 100644 --- a/include/uapi/drm/msm_drm.h +++ b/include/uapi/drm/msm_drm.h @@ -22,6 +22,10 @@ #include <drm/drm.h> #include <drm/sde_drm.h> +#if defined(__cplusplus) +extern "C" { +#endif + /* Please note that modifications to all structs defined here are * subject to backwards-compatibility constraints: * 1) Do not use pointers, use __u64 instead for 32 bit / 64 bit @@ -78,6 +82,7 @@ struct drm_msm_param { #define MSM_BO_SCANOUT 0x00000001 /* scanout capable */ #define MSM_BO_GPU_READONLY 0x00000002 #define MSM_BO_PRIVILEGED 0x00000004 +#define MSM_BO_SECURE 0x00000008 /* Allocate and map as secure */ #define MSM_BO_CACHE_MASK 0x000f0000 /* cache modes */ #define MSM_BO_CACHED 0x00010000 @@ -86,6 +91,7 @@ struct drm_msm_param { #define MSM_BO_FLAGS (MSM_BO_SCANOUT | \ MSM_BO_GPU_READONLY | \ + MSM_BO_SECURE | \ MSM_BO_CACHED | \ MSM_BO_WC | \ MSM_BO_UNCACHED) @@ -139,7 +145,11 @@ struct drm_msm_gem_cpu_fini { */ struct drm_msm_gem_submit_reloc { __u32 submit_offset; /* in, offset from submit_bo */ - __u32 or; /* in, value OR'd with result */ +#ifdef __cplusplus + __u32 or_val; +#else + __u32 or; /* in, value OR'd with result */ +#endif __s32 shift; /* in, amount of left shift (can be negative) */ __u32 reloc_idx; /* in, index of reloc_bo buffer */ __u64 reloc_offset; /* in, offset from start of reloc_bo */ @@ -385,4 +395,9 @@ struct drm_msm_gem_sync { struct drm_msm_counter_read) #define DRM_IOCTL_MSM_GEM_SYNC DRM_IOW(DRM_COMMAND_BASE + DRM_MSM_GEM_SYNC,\ struct drm_msm_gem_sync) + +#if defined(__cplusplus) +} +#endif + #endif /* __MSM_DRM_H__ */ diff --git a/include/uapi/linux/ipv6_route.h b/include/uapi/linux/ipv6_route.h index f6598d1c886e..316e838b7470 100644 --- a/include/uapi/linux/ipv6_route.h +++ b/include/uapi/linux/ipv6_route.h @@ -34,7 +34,7 @@ #define RTF_PREF(pref) ((pref) << 27) #define RTF_PREF_MASK 0x18000000 -#define RTF_PCPU 0x40000000 +#define RTF_PCPU 0x40000000 /* read-only: can not be set by user */ #define RTF_LOCAL 0x80000000 diff --git a/include/uapi/linux/msm_audio.h b/include/uapi/linux/msm_audio.h index 36b66c7cde76..f306949eb5e6 100644 --- a/include/uapi/linux/msm_audio.h +++ b/include/uapi/linux/msm_audio.h @@ -460,4 +460,14 @@ struct msm_hwacc_effects_config { __s32 topology; }; +#define ADSP_STREAM_PP_EVENT 0 +#define ADSP_STREAM_ENCDEC_EVENT 1 +#define ADSP_STREAM_EVENT_MAX 2 + +struct msm_adsp_event_data { + __u32 event_type; + __u32 payload_len; + __u8 payload[0]; +}; + #endif diff --git a/include/uapi/linux/msm_ipa.h b/include/uapi/linux/msm_ipa.h index 16e4b8e30b07..51569b7e7aa0 100644 --- a/include/uapi/linux/msm_ipa.h +++ b/include/uapi/linux/msm_ipa.h @@ -394,10 +394,20 @@ enum ipa_tethering_stats_event { IPA_TETHERING_STATS_UPDATE_STATS = IPA_ECM_EVENT_MAX, IPA_TETHERING_STATS_UPDATE_NETWORK_STATS, IPA_TETHERING_STATS_EVENT_MAX, - IPA_EVENT_MAX_NUM = IPA_TETHERING_STATS_EVENT_MAX }; -#define IPA_EVENT_MAX ((int)IPA_EVENT_MAX_NUM) +enum ipa_quota_event { + IPA_QUOTA_REACH = IPA_TETHERING_STATS_EVENT_MAX, + IPA_QUOTA_EVENT_MAX, +}; + +enum ipa_ssr_event { + IPA_SSR_BEFORE_SHUTDOWN = IPA_QUOTA_EVENT_MAX, + IPA_SSR_AFTER_POWERUP, + IPA_SSR_EVENT_MAX +}; + +#define IPA_EVENT_MAX_NUM ((int)IPA_SSR_EVENT_MAX) /** * enum ipa_rm_resource_name - IPA RM clients identification names diff --git a/include/uapi/linux/msm_mdp_ext.h b/include/uapi/linux/msm_mdp_ext.h index 35029f227f8b..da9ee3bcc525 100644 --- a/include/uapi/linux/msm_mdp_ext.h +++ b/include/uapi/linux/msm_mdp_ext.h @@ -178,6 +178,12 @@ VALIDATE/COMMIT FLAG CONFIGURATION */ #define MDP_COMMIT_CWB_DSPP 0x1000 +/* + * Flag to indicate that rectangle number is being assigned + * by userspace in multi-rectangle mode + */ +#define MDP_COMMIT_RECT_NUM 0x2000 + #define MDP_COMMIT_VERSION_1_0 0x00010000 #define OUT_LAYER_COLOR_SPACE @@ -425,8 +431,14 @@ struct mdp_input_layer { */ int error_code; + /* + * For source pipes supporting multi-rectangle, this field identifies + * the rectangle index of the source pipe. + */ + uint32_t rect_num; + /* 32bits reserved value for future usage. */ - uint32_t reserved[6]; + uint32_t reserved[5]; }; struct mdp_output_layer { diff --git a/include/uapi/linux/rmnet_ipa_fd_ioctl.h b/include/uapi/linux/rmnet_ipa_fd_ioctl.h index 228bfe8274c6..f04ac495a5c0 100644 --- a/include/uapi/linux/rmnet_ipa_fd_ioctl.h +++ b/include/uapi/linux/rmnet_ipa_fd_ioctl.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -32,6 +32,7 @@ #define WAN_IOCTL_RESET_TETHER_STATS 7 #define WAN_IOCTL_QUERY_DL_FILTER_STATS 8 #define WAN_IOCTL_ADD_FLT_RULE_EX 9 +#define WAN_IOCTL_QUERY_TETHER_STATS_ALL 10 /* User space may not have this defined. */ #ifndef IFNAMSIZ @@ -99,6 +100,16 @@ struct wan_ioctl_query_tether_stats { uint64_t ipv6_rx_bytes; }; +struct wan_ioctl_query_tether_stats_all { + /* Name of the upstream interface */ + char upstreamIface[IFNAMSIZ]; + /* enum of tether interface */ + enum ipacm_client_enum ipa_client; + uint8_t reset_stats; + uint64_t tx_bytes; + uint64_t rx_bytes; +}; + struct wan_ioctl_reset_tether_stats { /* Name of the upstream interface, not support now */ char upstreamIface[IFNAMSIZ]; @@ -155,4 +166,8 @@ struct wan_ioctl_query_dl_filter_stats { WAN_IOCTL_ADD_FLT_RULE_EX, \ struct ipa_install_fltr_rule_req_ex_msg_v01 *) +#define WAN_IOC_QUERY_TETHER_STATS_ALL _IOWR(WAN_IOC_MAGIC, \ + WAN_IOCTL_QUERY_TETHER_STATS_ALL, \ + struct wan_ioctl_query_tether_stats_all *) + #endif /* _RMNET_IPA_FD_IOCTL_H */ diff --git a/include/uapi/sound/compress_offload.h b/include/uapi/sound/compress_offload.h index 30481056cce1..866ec3d2af69 100644 --- a/include/uapi/sound/compress_offload.h +++ b/include/uapi/sound/compress_offload.h @@ -149,6 +149,8 @@ struct snd_compr_audio_info { * @SNDRV_COMPRESS_CLK_REC_MODE: clock recovery mode ( none or auto) * @SNDRV_COMPRESS_RENDER_WINDOW: render window * @SNDRV_COMPRESS_START_DELAY: start delay + * @SNDRV_COMPRESS_ENABLE_ADJUST_SESSION_CLOCK: enable dsp drift correction + * @SNDRV_COMPRESS_ADJUST_SESSION_CLOCK: set drift correction value */ enum sndrv_compress_encoder { SNDRV_COMPRESS_ENCODER_PADDING = 1, @@ -160,6 +162,8 @@ enum sndrv_compress_encoder { SNDRV_COMPRESS_CLK_REC_MODE = 7, SNDRV_COMPRESS_RENDER_WINDOW = 8, SNDRV_COMPRESS_START_DELAY = 9, + SNDRV_COMPRESS_ENABLE_ADJUST_SESSION_CLOCK = 10, + SNDRV_COMPRESS_ADJUST_SESSION_CLOCK = 11, }; #define SNDRV_COMPRESS_PATH_DELAY SNDRV_COMPRESS_PATH_DELAY @@ -167,6 +171,9 @@ enum sndrv_compress_encoder { #define SNDRV_COMPRESS_CLK_REC_MODE SNDRV_COMPRESS_CLK_REC_MODE #define SNDRV_COMPRESS_RENDER_WINDOW SNDRV_COMPRESS_RENDER_WINDOW #define SNDRV_COMPRESS_START_DELAY SNDRV_COMPRESS_START_DELAY +#define SNDRV_COMPRESS_ENABLE_ADJUST_SESSION_CLOCK \ + SNDRV_COMPRESS_ENABLE_ADJUST_SESSION_CLOCK +#define SNDRV_COMPRESS_ADJUST_SESSION_CLOCK SNDRV_COMPRESS_ADJUST_SESSION_CLOCK /** * struct snd_compr_metadata - compressed stream metadata diff --git a/kernel/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/net/9p/client.c b/net/9p/client.c index ea79ee9a7348..f5feac4ff4ec 100644 --- a/net/9p/client.c +++ b/net/9p/client.c @@ -2101,6 +2101,10 @@ int p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset) trace_9p_protocol_dump(clnt, req->rc); goto free_and_error; } + if (rsize < count) { + pr_err("bogus RREADDIR count (%d > %d)\n", count, rsize); + count = rsize; + } p9_debug(P9_DEBUG_9P, "<<< RREADDIR count %d\n", count); diff --git a/net/core/neighbour.c b/net/core/neighbour.c index f1e575d7f21a..54ab748238d1 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -859,7 +859,8 @@ static void neigh_probe(struct neighbour *neigh) if (skb) skb = skb_clone(skb, GFP_ATOMIC); write_unlock(&neigh->lock); - neigh->ops->solicit(neigh, skb); + if (neigh->ops->solicit) + neigh->ops->solicit(neigh, skb); atomic_inc(&neigh->probes); kfree_skb(skb); } diff --git a/net/core/netpoll.c b/net/core/netpoll.c index 94acfc89ad97..440aa9f6e0a8 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -105,15 +105,21 @@ static void queue_process(struct work_struct *work) while ((skb = skb_dequeue(&npinfo->txq))) { struct net_device *dev = skb->dev; struct netdev_queue *txq; + unsigned int q_index; if (!netif_device_present(dev) || !netif_running(dev)) { kfree_skb(skb); continue; } - txq = skb_get_tx_queue(dev, skb); - local_irq_save(flags); + /* check if skb->queue_mapping is still valid */ + q_index = skb_get_queue_mapping(skb); + if (unlikely(q_index >= dev->real_num_tx_queues)) { + q_index = q_index % dev->real_num_tx_queues; + skb_set_queue_mapping(skb, q_index); + } + txq = netdev_get_tx_queue(dev, q_index); HARD_TX_LOCK(dev, txq, smp_processor_id()); if (netif_xmit_frozen_or_stopped(txq) || netpoll_start_xmit(skb, dev, txq) != NETDEV_TX_OK) { diff --git a/net/ipv4/route.c b/net/ipv4/route.c index d162ce41f761..7e31491e9396 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -2571,7 +2571,7 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh) skb_reset_network_header(skb); /* Bugfix: need to give ip_route_input enough of an IP header to not gag. */ - ip_hdr(skb)->protocol = IPPROTO_ICMP; + ip_hdr(skb)->protocol = IPPROTO_UDP; skb_reserve(skb, MAX_HEADER + sizeof(struct iphdr)); src = tb[RTA_SRC] ? nla_get_in_addr(tb[RTA_SRC]) : 0; diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 4ab7735e43ab..62815497f29c 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -2269,6 +2269,7 @@ int tcp_disconnect(struct sock *sk, int flags) tcp_init_send_head(sk); memset(&tp->rx_opt, 0, sizeof(tp->rx_opt)); __sk_dst_reset(sk); + tcp_saved_syn_free(tp); WARN_ON(inet->inet_num && !icsk->icsk_bind_hash); diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index 8b11a49c7dd7..600975c5eacf 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -1049,7 +1049,7 @@ static int ip6_tnl_xmit2(struct sk_buff *skb, struct ip6_tnl *t = netdev_priv(dev); struct net *net = t->net; struct net_device_stats *stats = &t->dev->stats; - struct ipv6hdr *ipv6h = ipv6_hdr(skb); + struct ipv6hdr *ipv6h; struct ipv6_tel_txoption opt; struct dst_entry *dst = NULL, *ndst = NULL; struct net_device *tdev; @@ -1061,26 +1061,28 @@ static int ip6_tnl_xmit2(struct sk_buff *skb, /* NBMA tunnel */ if (ipv6_addr_any(&t->parms.raddr)) { - struct in6_addr *addr6; - struct neighbour *neigh; - int addr_type; + if (skb->protocol == htons(ETH_P_IPV6)) { + struct in6_addr *addr6; + struct neighbour *neigh; + int addr_type; - if (!skb_dst(skb)) - goto tx_err_link_failure; + if (!skb_dst(skb)) + goto tx_err_link_failure; - neigh = dst_neigh_lookup(skb_dst(skb), - &ipv6_hdr(skb)->daddr); - if (!neigh) - goto tx_err_link_failure; + neigh = dst_neigh_lookup(skb_dst(skb), + &ipv6_hdr(skb)->daddr); + if (!neigh) + goto tx_err_link_failure; - addr6 = (struct in6_addr *)&neigh->primary_key; - addr_type = ipv6_addr_type(addr6); + addr6 = (struct in6_addr *)&neigh->primary_key; + addr_type = ipv6_addr_type(addr6); - if (addr_type == IPV6_ADDR_ANY) - addr6 = &ipv6_hdr(skb)->daddr; + if (addr_type == IPV6_ADDR_ANY) + addr6 = &ipv6_hdr(skb)->daddr; - memcpy(&fl6->daddr, addr6, sizeof(fl6->daddr)); - neigh_release(neigh); + memcpy(&fl6->daddr, addr6, sizeof(fl6->daddr)); + neigh_release(neigh); + } } else if (!(t->parms.flags & (IP6_TNL_F_USE_ORIG_TCLASS | IP6_TNL_F_USE_ORIG_FWMARK))) { /* enable the cache only only if the routing decision does diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index d9843e5a667f..8361d73ab653 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c @@ -774,7 +774,8 @@ failure: * Delete a VIF entry */ -static int mif6_delete(struct mr6_table *mrt, int vifi, struct list_head *head) +static int mif6_delete(struct mr6_table *mrt, int vifi, int notify, + struct list_head *head) { struct mif_device *v; struct net_device *dev; @@ -820,7 +821,7 @@ static int mif6_delete(struct mr6_table *mrt, int vifi, struct list_head *head) dev->ifindex, &in6_dev->cnf); } - if (v->flags & MIFF_REGISTER) + if ((v->flags & MIFF_REGISTER) && !notify) unregister_netdevice_queue(dev, head); dev_put(dev); @@ -1330,7 +1331,6 @@ static int ip6mr_device_event(struct notifier_block *this, struct mr6_table *mrt; struct mif_device *v; int ct; - LIST_HEAD(list); if (event != NETDEV_UNREGISTER) return NOTIFY_DONE; @@ -1339,10 +1339,9 @@ static int ip6mr_device_event(struct notifier_block *this, v = &mrt->vif6_table[0]; for (ct = 0; ct < mrt->maxvif; ct++, v++) { if (v->dev == dev) - mif6_delete(mrt, ct, &list); + mif6_delete(mrt, ct, 1, NULL); } } - unregister_netdevice_many(&list); return NOTIFY_DONE; } @@ -1551,7 +1550,7 @@ static void mroute_clean_tables(struct mr6_table *mrt, bool all) for (i = 0; i < mrt->maxvif; i++) { if (!all && (mrt->vif6_table[i].flags & VIFF_STATIC)) continue; - mif6_delete(mrt, i, &list); + mif6_delete(mrt, i, 0, &list); } unregister_netdevice_many(&list); @@ -1704,7 +1703,7 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, uns if (copy_from_user(&mifi, optval, sizeof(mifi_t))) return -EFAULT; rtnl_lock(); - ret = mif6_delete(mrt, mifi, NULL); + ret = mif6_delete(mrt, mifi, 0, NULL); rtnl_unlock(); return ret; diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index d503b7f373a3..6896830feabb 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -1145,8 +1145,7 @@ static int rawv6_ioctl(struct sock *sk, int cmd, unsigned long arg) spin_lock_bh(&sk->sk_receive_queue.lock); skb = skb_peek(&sk->sk_receive_queue); if (skb) - amount = skb_tail_pointer(skb) - - skb_transport_header(skb); + amount = skb->len; spin_unlock_bh(&sk->sk_receive_queue.lock); return put_user(amount, (int __user *)arg); } diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 31e172cd84ac..ff1499293938 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -1756,6 +1756,10 @@ static struct rt6_info *ip6_route_info_create(struct fib6_config *cfg) int addr_type; int err = -EINVAL; + /* RTF_PCPU is an internal flag; can not be set by userspace */ + if (cfg->fc_flags & RTF_PCPU) + goto out; + if (cfg->fc_dst_len > 128 || cfg->fc_src_len > 128) goto out; #ifndef CONFIG_IPV6_SUBTREES diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c index ec17cbe8a02b..d3dec414fd44 100644 --- a/net/l2tp/l2tp_core.c +++ b/net/l2tp/l2tp_core.c @@ -278,7 +278,8 @@ struct l2tp_session *l2tp_session_find(struct net *net, struct l2tp_tunnel *tunn } EXPORT_SYMBOL_GPL(l2tp_session_find); -struct l2tp_session *l2tp_session_find_nth(struct l2tp_tunnel *tunnel, int nth) +struct l2tp_session *l2tp_session_get_nth(struct l2tp_tunnel *tunnel, int nth, + bool do_ref) { int hash; struct l2tp_session *session; @@ -288,6 +289,9 @@ struct l2tp_session *l2tp_session_find_nth(struct l2tp_tunnel *tunnel, int nth) for (hash = 0; hash < L2TP_HASH_SIZE; hash++) { hlist_for_each_entry(session, &tunnel->session_hlist[hash], hlist) { if (++count > nth) { + l2tp_session_inc_refcount(session); + if (do_ref && session->ref) + session->ref(session); read_unlock_bh(&tunnel->hlist_lock); return session; } @@ -298,7 +302,7 @@ struct l2tp_session *l2tp_session_find_nth(struct l2tp_tunnel *tunnel, int nth) return NULL; } -EXPORT_SYMBOL_GPL(l2tp_session_find_nth); +EXPORT_SYMBOL_GPL(l2tp_session_get_nth); /* Lookup a session by interface name. * This is very inefficient but is only used by management interfaces. diff --git a/net/l2tp/l2tp_core.h b/net/l2tp/l2tp_core.h index 763e8e241ce3..555d962a62d2 100644 --- a/net/l2tp/l2tp_core.h +++ b/net/l2tp/l2tp_core.h @@ -243,7 +243,8 @@ out: struct l2tp_session *l2tp_session_find(struct net *net, struct l2tp_tunnel *tunnel, u32 session_id); -struct l2tp_session *l2tp_session_find_nth(struct l2tp_tunnel *tunnel, int nth); +struct l2tp_session *l2tp_session_get_nth(struct l2tp_tunnel *tunnel, int nth, + bool do_ref); struct l2tp_session *l2tp_session_find_by_ifname(struct net *net, char *ifname); struct l2tp_tunnel *l2tp_tunnel_find(struct net *net, u32 tunnel_id); struct l2tp_tunnel *l2tp_tunnel_find_nth(struct net *net, int nth); diff --git a/net/l2tp/l2tp_debugfs.c b/net/l2tp/l2tp_debugfs.c index 2d6760a2ae34..d100aed3d06f 100644 --- a/net/l2tp/l2tp_debugfs.c +++ b/net/l2tp/l2tp_debugfs.c @@ -53,7 +53,7 @@ static void l2tp_dfs_next_tunnel(struct l2tp_dfs_seq_data *pd) static void l2tp_dfs_next_session(struct l2tp_dfs_seq_data *pd) { - pd->session = l2tp_session_find_nth(pd->tunnel, pd->session_idx); + pd->session = l2tp_session_get_nth(pd->tunnel, pd->session_idx, true); pd->session_idx++; if (pd->session == NULL) { @@ -238,10 +238,14 @@ static int l2tp_dfs_seq_show(struct seq_file *m, void *v) } /* Show the tunnel or session context */ - if (pd->session == NULL) + if (!pd->session) { l2tp_dfs_seq_tunnel_show(m, pd->tunnel); - else + } else { l2tp_dfs_seq_session_show(m, pd->session); + if (pd->session->deref) + pd->session->deref(pd->session); + l2tp_session_dec_refcount(pd->session); + } out: return 0; diff --git a/net/l2tp/l2tp_netlink.c b/net/l2tp/l2tp_netlink.c index 2caaa84ce92d..665cc74df5c5 100644 --- a/net/l2tp/l2tp_netlink.c +++ b/net/l2tp/l2tp_netlink.c @@ -827,7 +827,7 @@ static int l2tp_nl_cmd_session_dump(struct sk_buff *skb, struct netlink_callback goto out; } - session = l2tp_session_find_nth(tunnel, si); + session = l2tp_session_get_nth(tunnel, si, false); if (session == NULL) { ti++; tunnel = NULL; @@ -837,8 +837,11 @@ static int l2tp_nl_cmd_session_dump(struct sk_buff *skb, struct netlink_callback if (l2tp_nl_session_send(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, NLM_F_MULTI, - session, L2TP_CMD_SESSION_GET) < 0) + session, L2TP_CMD_SESSION_GET) < 0) { + l2tp_session_dec_refcount(session); break; + } + l2tp_session_dec_refcount(session); si++; } diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c index 1ad18c55064c..8ab9c5d74416 100644 --- a/net/l2tp/l2tp_ppp.c +++ b/net/l2tp/l2tp_ppp.c @@ -467,6 +467,10 @@ static void pppol2tp_session_close(struct l2tp_session *session) static void pppol2tp_session_destruct(struct sock *sk) { struct l2tp_session *session = sk->sk_user_data; + + skb_queue_purge(&sk->sk_receive_queue); + skb_queue_purge(&sk->sk_write_queue); + if (session) { sk->sk_user_data = NULL; BUG_ON(session->magic != L2TP_SESSION_MAGIC); @@ -505,9 +509,6 @@ static int pppol2tp_release(struct socket *sock) l2tp_session_queue_purge(session); sock_put(sk); } - skb_queue_purge(&sk->sk_receive_queue); - skb_queue_purge(&sk->sk_write_queue); - release_sock(sk); /* This will delete the session context via @@ -1574,7 +1575,7 @@ static void pppol2tp_next_tunnel(struct net *net, struct pppol2tp_seq_data *pd) static void pppol2tp_next_session(struct net *net, struct pppol2tp_seq_data *pd) { - pd->session = l2tp_session_find_nth(pd->tunnel, pd->session_idx); + pd->session = l2tp_session_get_nth(pd->tunnel, pd->session_idx, true); pd->session_idx++; if (pd->session == NULL) { @@ -1701,10 +1702,14 @@ static int pppol2tp_seq_show(struct seq_file *m, void *v) /* Show the tunnel or session context. */ - if (pd->session == NULL) + if (!pd->session) { pppol2tp_seq_tunnel_show(m, pd->tunnel); - else + } else { pppol2tp_seq_session_show(m, pd->session); + if (pd->session->deref) + pd->session->deref(pd->session); + l2tp_session_dec_refcount(pd->session); + } out: return 0; @@ -1863,4 +1868,4 @@ MODULE_DESCRIPTION("PPP over L2TP over UDP"); MODULE_LICENSE("GPL"); MODULE_VERSION(PPPOL2TP_DRV_VERSION); MODULE_ALIAS("pppox-proto-" __stringify(PX_PROTO_OL2TP)); -MODULE_ALIAS_L2TP_PWTYPE(11); +MODULE_ALIAS_L2TP_PWTYPE(7); diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 96fe1c103bf9..2141d047301d 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -2087,7 +2087,7 @@ static int netlink_dump(struct sock *sk) if (!skb) { alloc_size = alloc_min_size; skb = netlink_alloc_skb(sk, alloc_size, nlk->portid, - (GFP_KERNEL & ~__GFP_DIRECT_RECLAIM)); + GFP_KERNEL); } if (!skb) goto errout_skb; diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index d76800108ddb..f8d6a0ca9c03 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -3626,6 +3626,8 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv return -EBUSY; if (copy_from_user(&val, optval, sizeof(val))) return -EFAULT; + if (val > INT_MAX) + return -EINVAL; po->tp_reserve = val; return 0; } @@ -4150,6 +4152,8 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u, rb->frames_per_block = req->tp_block_size / req->tp_frame_size; if (unlikely(rb->frames_per_block == 0)) goto out; + if (unlikely(req->tp_block_size > UINT_MAX / req->tp_block_nr)) + goto out; if (unlikely((rb->frames_per_block * req->tp_block_nr) != req->tp_frame_nr)) goto out; diff --git a/net/rds/cong.c b/net/rds/cong.c index e6144b8246fd..6641bcf7c185 100644 --- a/net/rds/cong.c +++ b/net/rds/cong.c @@ -299,7 +299,7 @@ void rds_cong_set_bit(struct rds_cong_map *map, __be16 port) i = be16_to_cpu(port) / RDS_CONG_MAP_PAGE_BITS; off = be16_to_cpu(port) % RDS_CONG_MAP_PAGE_BITS; - __set_bit_le(off, (void *)map->m_page_addrs[i]); + set_bit_le(off, (void *)map->m_page_addrs[i]); } void rds_cong_clear_bit(struct rds_cong_map *map, __be16 port) @@ -313,7 +313,7 @@ void rds_cong_clear_bit(struct rds_cong_map *map, __be16 port) i = be16_to_cpu(port) / RDS_CONG_MAP_PAGE_BITS; off = be16_to_cpu(port) % RDS_CONG_MAP_PAGE_BITS; - __clear_bit_le(off, (void *)map->m_page_addrs[i]); + clear_bit_le(off, (void *)map->m_page_addrs[i]); } static int rds_cong_test_bit(struct rds_cong_map *map, __be16 port) diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c index e384d6aefa3a..1090a52c03cd 100644 --- a/net/sched/act_mirred.c +++ b/net/sched/act_mirred.c @@ -36,14 +36,15 @@ static DEFINE_SPINLOCK(mirred_list_lock); static void tcf_mirred_release(struct tc_action *a, int bind) { struct tcf_mirred *m = to_mirred(a); - struct net_device *dev = rcu_dereference_protected(m->tcfm_dev, 1); + struct net_device *dev; /* We could be called either in a RCU callback or with RTNL lock held. */ spin_lock_bh(&mirred_list_lock); list_del(&m->tcfm_list); - spin_unlock_bh(&mirred_list_lock); + dev = rcu_dereference_protected(m->tcfm_dev, 1); if (dev) dev_put(dev); + spin_unlock_bh(&mirred_list_lock); } static const struct nla_policy mirred_policy[TCA_MIRRED_MAX + 1] = { diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 5758818435f3..c96d666cef29 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -6394,6 +6394,9 @@ int sctp_inet_listen(struct socket *sock, int backlog) if (sock->state != SS_UNCONNECTED) goto out; + if (!sctp_sstate(sk, LISTENING) && !sctp_sstate(sk, CLOSED)) + goto out; + /* If backlog is zero, disable listening. */ if (!backlog) { if (sctp_sstate(sk, CLOSED)) diff --git a/net/wireless/db.txt b/net/wireless/db.txt index 55087dc93424..c8c4f547b4f1 100644 --- a/net/wireless/db.txt +++ b/net/wireless/db.txt @@ -84,7 +84,7 @@ country AT: DFS-ETSI (5900 - 5920 @ 10), (30) (5910 - 5930 @ 10), (30) # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (40), NO-OUTDOOR + (57000 - 66000 @ 2160), (40) country AU: DFS-FCC (2402 - 2482 @ 40), (20) @@ -93,7 +93,6 @@ country AU: DFS-FCC (5490 - 5590 @ 80), (24), DFS (5650 - 5730 @ 80), (24), DFS (5735 - 5835 @ 80), (30) - # 60 gHz band channels 1-4 (57240 - 65880 @ 2160), (43), NO-OUTDOOR @@ -139,7 +138,7 @@ country BE: DFS-ETSI (5900 - 5920 @ 10), (30) (5910 - 5930 @ 10), (30) # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (40) + (57000 - 66000 @ 2160), (40) country BF: DFS-FCC (2402 - 2482 @ 40), (20) @@ -163,7 +162,7 @@ country BG: DFS-ETSI (5900 - 5920 @ 10), (30) (5910 - 5930 @ 10), (30) # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (40), NO-OUTDOOR + (57000 - 66000 @ 2160), (40) country BH: (2402 - 2482 @ 40), (20) @@ -193,7 +192,6 @@ country BO: DFS-ETSI (2402 - 2482 @ 40), (20) (5250 - 5330 @ 80), (30), DFS (5735 - 5835 @ 80), (30) - # 60 gHz band channels 1-3, FCC (57240 - 63720 @ 2160), (40) @@ -203,7 +201,6 @@ country BR: DFS-FCC (5250 - 5330 @ 80), (24), DFS, AUTO-BW (5490 - 5730 @ 160), (24), DFS (5735 - 5835 @ 80), (30) - # 60 gHz band channels 1-3 (57240 - 63720 @ 2160), (40) @@ -239,7 +236,6 @@ country CA: DFS-FCC (5490 - 5590 @ 80), (24), DFS (5650 - 5730 @ 80), (24), DFS (5735 - 5835 @ 80), (30) - # 60 gHz band channels 1-3 (57240 - 63720 @ 2160), (40) @@ -264,9 +260,8 @@ country CH: DFS-ETSI (5890 - 5910 @ 10), (30) (5900 - 5920 @ 10), (30) (5910 - 5930 @ 10), (30) - # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (40), NO-OUTDOOR + (57000 - 66000 @ 2160), (40) country CI: DFS-FCC (2402 - 2482 @ 40), (20) @@ -279,7 +274,6 @@ country CL: (2402 - 2482 @ 40), (20) (5170 - 5330 @ 160), (20) (5735 - 5835 @ 80), (20) - # 60 gHz band channels 1-3 (57240 - 63720 @ 2160), (50), NO-OUTDOOR @@ -304,7 +298,6 @@ country CR: DFS-FCC (5250 - 5330 @ 20), (24), DFS (5490 - 5730 @ 20), (24), DFS (5735 - 5835 @ 20), (30) - # 60 gHz band channels 1-3 (57240 - 63720 @ 2160), (30) @@ -330,7 +323,7 @@ country CY: DFS-ETSI (5900 - 5920 @ 10), (30) (5910 - 5930 @ 10), (30) # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (40), NO-OUTDOOR + (57000 - 66000 @ 2160), (40) # Data from http://www.ctu.eu/164/download/VOR/VOR-12-08-2005-34.pdf # and http://www.ctu.eu/164/download/VOR/VOR-12-05-2007-6-AN.pdf @@ -349,7 +342,7 @@ country CZ: DFS-ETSI (5900 - 5920 @ 10), (30) (5910 - 5930 @ 10), (30) # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (40), NO-OUTDOOR + (57000 - 66000 @ 2160), (40) # Data from "Frequenznutzungsplan" (as published in April 2008), downloaded from # http://www.bundesnetzagentur.de/cae/servlet/contentblob/38448/publicationFile/2659/Frequenznutzungsplan2008_Id17448pdf.pdf @@ -372,7 +365,7 @@ country DE: DFS-ETSI (5900 - 5920 @ 10), (30) (5910 - 5930 @ 10), (30) # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (40), NO-OUTDOOR + (57000 - 66000 @ 2160), (40) country DK: DFS-ETSI (2402 - 2482 @ 40), (20) @@ -389,7 +382,7 @@ country DK: DFS-ETSI (5900 - 5920 @ 10), (30) (5910 - 5930 @ 10), (30) # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (40), NO-OUTDOOR + (57000 - 66000 @ 2160), (40) country DM: DFS-FCC (2402 - 2472 @ 40), (30) @@ -415,7 +408,6 @@ country EC: DFS-FCC (5250 - 5330 @ 20), (24), DFS (5490 - 5730 @ 20), (24), DFS (5735 - 5835 @ 20), (30) - # 60 gHz band channels 1-3, FCC (57240 - 63720 @ 2160), (40) @@ -434,7 +426,7 @@ country EE: DFS-ETSI (5900 - 5920 @ 10), (30) (5910 - 5930 @ 10), (30) # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (40), NO-OUTDOOR + (57000 - 66000 @ 2160), (40) country EG: DFS-ETSI (2402 - 2482 @ 40), (20) @@ -456,7 +448,7 @@ country ES: DFS-ETSI (5900 - 5920 @ 10), (30) (5910 - 5930 @ 10), (30) # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (40), NO-OUTDOOR + (57000 - 66000 @ 2160), (40) country ET: DFS-ETSI (2402 - 2482 @ 40), (20) @@ -479,7 +471,7 @@ country FI: DFS-ETSI (5900 - 5920 @ 10), (30) (5910 - 5930 @ 10), (30) # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (40), NO-OUTDOOR + (57000 - 66000 @ 2160), (40) country FM: DFS-FCC (2402 - 2472 @ 40), (30) @@ -503,7 +495,7 @@ country FR: DFS-ETSI (5900 - 5920 @ 10), (30) (5910 - 5930 @ 10), (30) # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (40), NO-OUTDOOR + (57000 - 66000 @ 2160), (40) country GB: DFS-ETSI (2402 - 2482 @ 40), (20) @@ -520,7 +512,7 @@ country GB: DFS-ETSI (5900 - 5920 @ 10), (30) (5910 - 5930 @ 10), (30) # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (40), NO-OUTDOOR + (57000 - 66000 @ 2160), (40) country GD: DFS-FCC (2402 - 2472 @ 40), (30) @@ -574,7 +566,7 @@ country GR: DFS-ETSI (5900 - 5920 @ 10), (30) (5910 - 5930 @ 10), (30) # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (40), NO-OUTDOOR + (57000 - 66000 @ 2160), (40) country GT: DFS-ETSI (2402 - 2482 @ 40), (20) @@ -588,7 +580,6 @@ country GU: DFS-FCC (5250 - 5330 @ 80), (24), DFS, AUTO-BW (5490 - 5730 @ 160), (24), DFS (5735 - 5835 @ 80), (30) - # 60 gHz band channels 1-3, FCC (57240 - 63720 @ 2160), (40) @@ -602,7 +593,6 @@ country HK: DFS-FCC (5250 - 5330 @ 80), (24), DFS, AUTO-BW (5490 - 5730 @ 160), (24), DFS (5735 - 5835 @ 80), (30) - # 60 gHz band channels 1-4, ref: FCC/EU (57240 - 65880 @ 2160), (40) @@ -611,7 +601,6 @@ country HN: (5170 - 5330 @ 160), (24) (5490 - 5730 @ 160), (24) (5735 - 5835 @ 80), (30) - # 60 gHz band channels 1-3, FCC (57240 - 63720 @ 2160), (40) @@ -630,7 +619,7 @@ country HR: DFS-ETSI (5900 - 5920 @ 10), (30) (5910 - 5930 @ 10), (30) # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (40), NO-OUTDOOR + (57000 - 66000 @ 2160), (40) country HT: DFS-FCC (2402 - 2472 @ 40), (30) @@ -654,7 +643,7 @@ country HU: DFS-ETSI (5900 - 5920 @ 10), (30) (5910 - 5930 @ 10), (30) # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (40), NO-OUTDOOR + (57000 - 66000 @ 2160), (40) country ID: # ref: http://www.postel.go.id/content/ID/regulasi/standardisasi/kepdir/bwa%205,8%20ghz.pdf @@ -676,15 +665,14 @@ country IE: DFS-ETSI (5900 - 5920 @ 10), (30) (5910 - 5930 @ 10), (30) # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (40), NO-OUTDOOR + (57000 - 66000 @ 2160), (40) country IL: DFS-ETSI (2402 - 2482 @ 40), (20) (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW - # 60 gHz band channels 1-4, base on Etsi En 302 567 - (57240 - 65880 @ 2160), (40), NO-OUTDOOR + (57000 - 66000 @ 2160), (40) country IN: (2402 - 2482 @ 40), (20) @@ -710,7 +698,7 @@ country IS: DFS-ETSI (5900 - 5920 @ 10), (30) (5910 - 5930 @ 10), (30) # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (40), NO-OUTDOOR + (57000 - 66000 @ 2160), (40) country IT: DFS-ETSI (2402 - 2482 @ 40), (20) @@ -727,7 +715,7 @@ country IT: DFS-ETSI (5900 - 5920 @ 10), (30) (5910 - 5930 @ 10), (30) # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (40), NO-OUTDOOR + (57000 - 66000 @ 2160), (40) country JM: DFS-FCC (2402 - 2482 @ 40), (20) @@ -735,7 +723,6 @@ country JM: DFS-FCC (5250 - 5330 @ 80), (24), DFS, AUTO-BW (5490 - 5730 @ 160), (24), DFS (5735 - 5835 @ 80), (30) - # 60 gHz band channels 1-3, FCC (57240 - 63720 @ 2160), (40) @@ -743,9 +730,8 @@ country JO: (2402 - 2482 @ 40), (20) (5170 - 5250 @ 80), (23) (5735 - 5835 @ 80), (23) - # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (40), NO-OUTDOOR + ((57000 - 66000 @ 2160), (40) country JP: DFS-JP (2402 - 2482 @ 40), (20) @@ -831,9 +817,8 @@ country LI: DFS-ETSI (5890 - 5910 @ 10), (30) (5900 - 5920 @ 10), (30) (5910 - 5930 @ 10), (30) - # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (40), NO-OUTDOOR + (57000 - 66000 @ 2160), (40) country LK: DFS-FCC (2402 - 2482 @ 40), (20) @@ -863,7 +848,7 @@ country LT: DFS-ETSI (5900 - 5920 @ 10), (30) (5910 - 5930 @ 10), (30) # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (40), NO-OUTDOOR + (57000 - 66000 @ 2160), (40) country LU: DFS-ETSI (2402 - 2482 @ 40), (20) @@ -880,7 +865,7 @@ country LU: DFS-ETSI (5900 - 5920 @ 10), (30) (5910 - 5930 @ 10), (30) # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (40), NO-OUTDOOR + (57000 - 66000 @ 2160), (40) country LV: DFS-ETSI (2402 - 2482 @ 40), (20) @@ -896,17 +881,15 @@ country LV: DFS-ETSI (5890 - 5910 @ 10), (30) (5900 - 5920 @ 10), (30) (5910 - 5930 @ 10), (30) - # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (40), NO-OUTDOOR + (57000 - 66000 @ 2160), (40) country MA: DFS-ETSI (2402 - 2482 @ 40), (20) (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW - # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (40), NO-OUTDOOR + (57000 - 66000 @ 2160), (40) country MC: DFS-ETSI (2402 - 2482 @ 40), (20) @@ -993,7 +976,7 @@ country MT: DFS-ETSI (5900 - 5920 @ 10), (30) (5910 - 5930 @ 10), (30) # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (40), NO-OUTDOOR + (57000 - 66000 @ 2160), (40) country MU: DFS-FCC (2402 - 2482 @ 40), (20) @@ -1020,7 +1003,6 @@ country MX: DFS-FCC (5250 - 5330 @ 80), (24), DFS, AUTO-BW (5490 - 5730 @ 160), (24), DFS (5735 - 5835 @ 80), (30) - # 60 gHz band channels 1-3, FCC (57240 - 63720 @ 2160), (40) @@ -1030,7 +1012,6 @@ country MY: DFS-FCC (5250 - 5330 @ 80), (24), DFS, AUTO-BW (5490 - 5650 @ 160), (24), DFS (5735 - 5815 @ 80), (24) - # 60 gHz band channels 1-3 (57240 - 63720 @ 2160), (40) @@ -1052,7 +1033,6 @@ country NI: DFS-FCC (5250 - 5330 @ 80), (24), DFS, AUTO-BW (5490 - 5730 @ 160), (24), DFS (5735 - 5835 @ 80), (30) - # 60 gHz band channels 1-3, FCC (57240 - 63720 @ 2160), (40) @@ -1071,7 +1051,7 @@ country NL: DFS-ETSI (5900 - 5920 @ 10), (30) (5910 - 5930 @ 10), (30) # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (40), NO-OUTDOOR + (57000 - 66000 @ 2160), (40) country NO: DFS-ETSI (2402 - 2482 @ 40), (20) @@ -1088,7 +1068,7 @@ country NO: DFS-ETSI (5900 - 5920 @ 10), (30) (5910 - 5930 @ 10), (30) # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (40), NO-OUTDOOR + (57000 - 66000 @ 2160), (40) country NP: (2402 - 2482 @ 40), (20) @@ -1101,9 +1081,8 @@ country NZ: DFS-FCC (5250 - 5330 @ 80), (24), DFS, AUTO-BW (5490 - 5730 @ 160), (24), DFS (5735 - 5835 @ 80), (30) - # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (40), NO-OUTDOOR + (57000 - 66000 @ 2160), (40) country OM: DFS-ETSI (2402 - 2482 @ 40), (20) @@ -1143,9 +1122,8 @@ country PH: DFS-FCC (5250 - 5330 @ 80), (24), DFS, AUTO-BW (5490 - 5730 @ 160), (24), DFS (5735 - 5835 @ 80), (30) - # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (40), NO-OUTDOOR + (57000 - 66000 @ 2160), (40) country PK: (2402 - 2482 @ 40), (30) @@ -1166,7 +1144,7 @@ country PL: DFS-ETSI (5900 - 5920 @ 10), (30) (5910 - 5930 @ 10), (30) # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (40), NO-OUTDOOR + (57000 - 66000 @ 2160), (40) country PM: DFS-ETSI (2402 - 2482 @ 40), (20) @@ -1203,7 +1181,7 @@ country PT: DFS-ETSI (5900 - 5920 @ 10), (30) (5910 - 5930 @ 10), (30) # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (40), NO-OUTDOOR + (57000 - 66000 @ 2160), (40) country PW: DFS-FCC (2402 - 2472 @ 40), (30) @@ -1218,7 +1196,6 @@ country PY: DFS-FCC (5250 - 5330 @ 80), (24), DFS, AUTO-BW (5490 - 5730 @ 160), (24), DFS (5735 - 5835 @ 80), (30) - # 60 gHz band channels 1-3, FCC (57240 - 63720 @ 2160), (40) @@ -1247,7 +1224,7 @@ country RO: DFS-ETSI (5900 - 5920 @ 10), (30) (5910 - 5930 @ 10), (30) # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (40), NO-OUTDOOR + (57000 - 66000 @ 2160), (40) # Source: # http://www.ratel.rs/upload/documents/Plan_namene/Plan_namene-sl_glasnik.pdf @@ -1257,14 +1234,13 @@ country RS: DFS-ETSI (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (40), NO-OUTDOOR + (57000 - 66000 @ 2160), (40) country RU: (2402 - 2482 @ 40), (20) (5170 - 5330 @ 160), (23) (5490 - 5730 @ 160), (30) (5735 - 5835 @ 80), (30) - # 60 gHz band channels 1-4 (57240 - 65880 @ 2160), (40) @@ -1296,7 +1272,7 @@ country SE: DFS-ETSI (5900 - 5920 @ 10), (30) (5910 - 5930 @ 10), (30) # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (40), NO-OUTDOOR + (57000 - 66000 @ 2160), (40) country SG: DFS-FCC (2402 - 2482 @ 40), (20) @@ -1304,9 +1280,8 @@ country SG: DFS-FCC (5250 - 5330 @ 80), (24), DFS, AUTO-BW (5490 - 5730 @ 160), (24), DFS (5735 - 5835 @ 80), (30) - # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (40), NO-OUTDOOR + (57000 - 66000 @ 2160), (40), NO-OUTDOOR country SI: DFS-ETSI (2402 - 2482 @ 40), (20) @@ -1323,7 +1298,7 @@ country SI: DFS-ETSI (5900 - 5920 @ 10), (30) (5910 - 5930 @ 10), (30) # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (40), NO-OUTDOOR + (57000 - 66000 @ 2160), (40) country SK: DFS-ETSI (2402 - 2482 @ 40), (20) @@ -1340,7 +1315,7 @@ country SK: DFS-ETSI (5900 - 5920 @ 10), (30) (5910 - 5930 @ 10), (30) # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (40), NO-OUTDOOR + (57000 - 66000 @ 2160), (40) country SN: (2402 - 2482 @ 40), (20) @@ -1388,7 +1363,6 @@ country TH: DFS-FCC (5250 - 5330 @ 80), (24), DFS, AUTO-BW (5490 - 5730 @ 160), (24), DFS (5735 - 5835 @ 80), (30) - # 60 gHz band channels 1-4 (57240 - 65880 @ 2160), (40) @@ -1408,7 +1382,6 @@ country TT: (5170 - 5330 @ 160), (27) (5490 - 5730 @ 160), (36) (5735 - 5835 @ 80), (36) - # 60 gHz band channels 1-3, FCC (57240 - 63720 @ 2160), (40) @@ -1418,7 +1391,6 @@ country TW: DFS-FCC (5250 - 5330 @ 80), (24), DFS, AUTO-BW (5490 - 5730 @ 160), (24), DFS (5735 - 5835 @ 80), (30) - # 60 gHz band channels 1-3, FCC (57240 - 63720 @ 2160), (40) @@ -1477,7 +1449,6 @@ country UY: DFS-FCC (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5735 - 5835 @ 80), (30) - # 60 gHz band channels 1-4 (57240 - 65880 @ 2160), (40) @@ -1511,7 +1482,6 @@ country VN: DFS-FCC (5250 - 5330 @ 80), (24), DFS, AUTO-BW (5490 - 5730 @ 160), (24), DFS (5735 - 5835 @ 80), (30) - # 60 gHz band channels 1-4 (57240 - 65880 @ 2160), (40) @@ -1556,7 +1526,6 @@ country ZA: DFS-FCC (5250 - 5330 @ 80), (24), DFS, AUTO-BW (5490 - 5730 @ 160), (24), DFS (5735 - 5835 @ 80), (30) - # 60 gHz band channels 1-4 (57240 - 65880 @ 2160), (40), NO-OUTDOOR diff --git a/sound/core/seq/seq_lock.c b/sound/core/seq/seq_lock.c index 3b693e924db7..12ba83367b1b 100644 --- a/sound/core/seq/seq_lock.c +++ b/sound/core/seq/seq_lock.c @@ -28,19 +28,16 @@ /* wait until all locks are released */ void snd_use_lock_sync_helper(snd_use_lock_t *lockp, const char *file, int line) { - int max_count = 5 * HZ; + int warn_count = 5 * HZ; if (atomic_read(lockp) < 0) { pr_warn("ALSA: seq_lock: lock trouble [counter = %d] in %s:%d\n", atomic_read(lockp), file, line); return; } while (atomic_read(lockp) > 0) { - if (max_count == 0) { - pr_warn("ALSA: seq_lock: timeout [%d left] in %s:%d\n", atomic_read(lockp), file, line); - break; - } + if (warn_count-- == 0) + pr_warn("ALSA: seq_lock: waiting [%d left] in %s:%d\n", atomic_read(lockp), file, line); schedule_timeout_uninterruptible(1); - max_count--; } } diff --git a/sound/firewire/lib.h b/sound/firewire/lib.h index f3f6f84c48d6..bb5f8cdea3e2 100644 --- a/sound/firewire/lib.h +++ b/sound/firewire/lib.h @@ -42,7 +42,7 @@ struct snd_fw_async_midi_port { struct snd_rawmidi_substream *substream; snd_fw_async_midi_port_fill fill; - unsigned int consume_bytes; + int consume_bytes; }; int snd_fw_async_midi_port_init(struct snd_fw_async_midi_port *port, diff --git a/sound/ppc/awacs.c b/sound/ppc/awacs.c index 09da7b52bc2e..1468e4b7bf93 100644 --- a/sound/ppc/awacs.c +++ b/sound/ppc/awacs.c @@ -991,6 +991,7 @@ snd_pmac_awacs_init(struct snd_pmac *chip) if (err < 0) return err; } + master_vol = NULL; if (pm7500) err = build_mixers(chip, ARRAY_SIZE(snd_pmac_awacs_mixers_pmac7500), 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/codecs/sdm660_cdc/msm-digital-cdc.c b/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c index c6074570bb50..6c702c8fc35f 100644 --- a/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c +++ b/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c @@ -30,6 +30,7 @@ #include "msm-digital-cdc.h" #include "msm-cdc-common.h" #include "../../msm/sdm660-common.h" +#include "../../../../drivers/base/regmap/internal.h" #define DRV_NAME "msm_digital_codec" #define MCLK_RATE_9P6MHZ 9600000 @@ -71,6 +72,8 @@ static int msm_digcdc_clock_control(bool flag) { int ret = -EINVAL; struct msm_asoc_mach_data *pdata = NULL; + struct msm_dig_priv *msm_dig_cdc = + snd_soc_codec_get_drvdata(registered_digcodec); pdata = snd_soc_card_get_drvdata(registered_digcodec->component.card); @@ -84,6 +87,12 @@ static int msm_digcdc_clock_control(bool flag) if (ret < 0) { pr_err("%s:failed to enable the MCLK\n", __func__); + /* + * Avoid access to lpass register + * as clock enable failed during SSR. + */ + if (ret == -ENODEV) + msm_dig_cdc->regmap->cache_only = true; mutex_unlock(&pdata->cdc_int_mclk0_mutex); return ret; } diff --git a/sound/soc/codecs/wsa881x-analog.c b/sound/soc/codecs/wsa881x-analog.c index fa1d099e082a..ff160dcb0952 100644 --- a/sound/soc/codecs/wsa881x-analog.c +++ b/sound/soc/codecs/wsa881x-analog.c @@ -1309,7 +1309,6 @@ static int wsa881x_i2c_probe(struct i2c_client *client, ret = -EINVAL; goto err; } - i2c_set_clientdata(client, pdata); dev_set_drvdata(&client->dev, client); pdata->regmap[WSA881X_DIGITAL_SLAVE] = @@ -1367,7 +1366,7 @@ err: static int wsa881x_i2c_remove(struct i2c_client *client) { - struct wsa881x_pdata *wsa881x = i2c_get_clientdata(client); + struct wsa881x_pdata *wsa881x = client->dev.platform_data; snd_soc_unregister_codec(&client->dev); i2c_set_clientdata(client, NULL); @@ -1414,6 +1413,7 @@ static struct i2c_driver wsa881x_codec_driver = { .driver = { .name = "wsa881x-i2c-codec", .owner = THIS_MODULE, + .probe_type = PROBE_PREFER_ASYNCHRONOUS, #ifdef CONFIG_PM_SLEEP .pm = &wsa881x_i2c_pm_ops, #endif diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index 7a5c9a36c1db..daba8c56b43b 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -139,7 +139,7 @@ static struct snd_soc_dai_link byt_dailink[] = { .codec_dai_name = "snd-soc-dummy-dai", .codec_name = "snd-soc-dummy", .platform_name = "sst-mfld-platform", - .ignore_suspend = 1, + .nonatomic = true, .dynamic = 1, .dpcm_playback = 1, .dpcm_capture = 1, @@ -166,6 +166,7 @@ static struct snd_soc_dai_link byt_dailink[] = { | SND_SOC_DAIFMT_CBS_CFS, .be_hw_params_fixup = byt_codec_fixup, .ignore_suspend = 1, + .nonatomic = true, .dpcm_playback = 1, .dpcm_capture = 1, .ops = &byt_be_ssp2_ops, 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/audio_cal_utils.c b/sound/soc/msm/qdsp6v2/audio_cal_utils.c index 0194dc4d58f1..4f2531a3da63 100644 --- a/sound/soc/msm/qdsp6v2/audio_cal_utils.c +++ b/sound/soc/msm/qdsp6v2/audio_cal_utils.c @@ -643,7 +643,9 @@ done: return cal_block; err: kfree(cal_block->cal_info); + cal_block->cal_info = NULL; kfree(cal_block->client_info); + cal_block->client_info = NULL; kfree(cal_block); cal_block = NULL; return cal_block; diff --git a/sound/soc/msm/qdsp6v2/msm-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 5bd3b6d7014e..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> @@ -302,6 +303,39 @@ exit: return ret; } +static int msm_compr_enable_adjust_session_clock(struct audio_client *ac, + bool enable) +{ + int ret; + + pr_debug("%s, enable adjust_session %d\n", __func__, enable); + + ret = q6asm_send_mtmx_strtr_enable_adjust_session_clock(ac, enable); + if (ret) + pr_err("%s, adjust session clock can't be set error %d\n", + __func__, ret); + + return ret; +} + +static int msm_compr_adjust_session_clock(struct audio_client *ac, + uint32_t adjust_session_lsw, uint32_t adjust_session_msw) +{ + int ret; + + pr_debug("%s, adjust_session_time_msw 0x%x adjust_session_time_lsw 0x%x\n", + __func__, adjust_session_msw, adjust_session_lsw); + + ret = q6asm_adjust_session_clock(ac, + adjust_session_lsw, + adjust_session_msw); + if (ret) + pr_err("%s, adjust session clock can't be set error %d\n", + __func__, ret); + + return ret; +} + static int msm_compr_set_volume(struct snd_compr_stream *cstream, uint32_t volume_l, uint32_t volume_r) { @@ -709,21 +743,20 @@ 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__); return; } - ret = msm_adsp_inform_mixer_ctl(rtd, DSP_STREAM_CALLBACK, - payload); + ret = msm_adsp_inform_mixer_ctl(rtd, payload); if (ret) { pr_err("%s: failed to inform mixer ctrl. err = %d\n", __func__, ret); return; } - break; case ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY: case ASM_DATA_EVENT_ENC_SR_CM_CHANGE_NOTIFY: { @@ -1550,6 +1583,7 @@ static int msm_compr_playback_open(struct snd_compr_stream *cstream) pr_debug("%s: session ID %d\n", __func__, prtd->audio_client->session); prtd->audio_client->perf_mode = false; prtd->session_id = prtd->audio_client->session; + msm_adsp_init_mixer_ctl_pp_event_queue(rtd); return 0; } @@ -1705,7 +1739,7 @@ static int msm_compr_playback_free(struct snd_compr_stream *cstream) q6asm_audio_client_buf_free_contiguous(dir, ac); q6asm_audio_client_free(ac); - + msm_adsp_clean_mixer_ctl_pp_event_queue(soc_prtd); kfree(pdata->audio_effects[soc_prtd->dai_link->be_id]); pdata->audio_effects[soc_prtd->dai_link->be_id] = NULL; kfree(pdata->dec_params[soc_prtd->dai_link->be_id]); @@ -2875,6 +2909,14 @@ static int msm_compr_set_metadata(struct snd_compr_stream *cstream, } else if (metadata->key == SNDRV_COMPRESS_START_DELAY) { prtd->start_delay_lsw = metadata->value[0]; prtd->start_delay_msw = metadata->value[1]; + } else if (metadata->key == + SNDRV_COMPRESS_ENABLE_ADJUST_SESSION_CLOCK) { + return msm_compr_enable_adjust_session_clock(ac, + metadata->value[0]); + } else if (metadata->key == SNDRV_COMPRESS_ADJUST_SESSION_CLOCK) { + return msm_compr_adjust_session_clock(ac, + metadata->value[0], + metadata->value[1]); } return 0; @@ -3547,7 +3589,119 @@ 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", + __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; + } + + 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", @@ -3558,20 +3712,20 @@ 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; } @@ -3586,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; @@ -3937,7 +4090,6 @@ static int msm_compr_add_audio_adsp_stream_callback_control( .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, .info = msm_adsp_stream_callback_info, .get = msm_adsp_stream_callback_get, - .put = msm_adsp_stream_callback_put, .private_value = 0, } }; @@ -3978,6 +4130,7 @@ static int msm_compr_add_audio_adsp_stream_callback_control( } kctl->private_data = NULL; + free_mixer_str: kfree(mixer_str); done: @@ -4165,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; @@ -4188,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-hdmi-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-hdmi-v2.c index 26b7f3f26b26..45868f508a60 100644 --- a/sound/soc/msm/qdsp6v2/msm-dai-q6-hdmi-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-hdmi-v2.c @@ -174,7 +174,7 @@ static const struct snd_kcontrol_new hdmi_config_controls[] = { { .access = SNDRV_CTL_ELEM_ACCESS_READ, .iface = SNDRV_CTL_ELEM_IFACE_PCM, - .name = "HDMI RX Drift", + .name = "HDMI Drift", .info = msm_dai_q6_ext_disp_drift_info, .get = msm_dai_q6_ext_disp_drift_get, }, @@ -191,7 +191,7 @@ static const struct snd_kcontrol_new display_port_config_controls[] = { { .access = SNDRV_CTL_ELEM_ACCESS_READ, .iface = SNDRV_CTL_ELEM_IFACE_PCM, - .name = "DISPLAY Port RX Drift", + .name = "DISPLAY_PORT Drift", .info = msm_dai_q6_ext_disp_drift_info, .get = msm_dai_q6_ext_disp_drift_get, }, diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c index 201ca652c10b..64b1961794b9 100644 --- a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c @@ -2321,6 +2321,44 @@ static const struct snd_kcontrol_new afe_enc_config_controls[] = { msm_dai_q6_afe_input_bit_format_put), }; +static int msm_dai_q6_slim_rx_drift_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; + uinfo->count = sizeof(struct afe_param_id_dev_timing_stats); + + return 0; +} + +static int msm_dai_q6_slim_rx_drift_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int ret = -EINVAL; + struct afe_param_id_dev_timing_stats timing_stats; + struct snd_soc_dai *dai = kcontrol->private_data; + struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev); + + if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) { + pr_err("%s: afe port not started. dai_data->status_mask = %ld\n", + __func__, *dai_data->status_mask); + goto done; + } + + memset(&timing_stats, 0, sizeof(struct afe_param_id_dev_timing_stats)); + ret = afe_get_av_dev_drift(&timing_stats, dai->id); + if (ret) { + pr_err("%s: Error getting AFE Drift for port %d, err=%d\n", + __func__, dai->id, ret); + + goto done; + } + + memcpy(ucontrol->value.bytes.data, (void *)&timing_stats, + sizeof(struct afe_param_id_dev_timing_stats)); +done: + return ret; +} + static const char * const afe_cal_mode_text[] = { "CAL_MODE_DEFAULT", "CAL_MODE_NONE" }; @@ -2373,6 +2411,29 @@ static const struct snd_kcontrol_new usb_audio_cfg_controls[] = { msm_dai_q6_usb_audio_endian_cfg_put), }; +static const struct snd_kcontrol_new avd_drift_config_controls[] = { + { + .access = SNDRV_CTL_ELEM_ACCESS_READ, + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "SLIMBUS_0_RX DRIFT", + .info = msm_dai_q6_slim_rx_drift_info, + .get = msm_dai_q6_slim_rx_drift_get, + }, + { + .access = SNDRV_CTL_ELEM_ACCESS_READ, + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "SLIMBUS_6_RX DRIFT", + .info = msm_dai_q6_slim_rx_drift_info, + .get = msm_dai_q6_slim_rx_drift_get, + }, + { + .access = SNDRV_CTL_ELEM_ACCESS_READ, + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "SLIMBUS_7_RX DRIFT", + .info = msm_dai_q6_slim_rx_drift_info, + .get = msm_dai_q6_slim_rx_drift_get, + }, +}; static int msm_dai_q6_dai_probe(struct snd_soc_dai *dai) { struct msm_dai_q6_dai_data *dai_data; @@ -2422,6 +2483,9 @@ static int msm_dai_q6_dai_probe(struct snd_soc_dai *dai) rc = snd_ctl_add(dai->component->card->snd_card, snd_ctl_new1(&afe_enc_config_controls[2], dai_data)); + rc = snd_ctl_add(dai->component->card->snd_card, + snd_ctl_new1(&avd_drift_config_controls[2], + dai)); break; case RT_PROXY_DAI_001_RX: rc = snd_ctl_add(dai->component->card->snd_card, @@ -2449,6 +2513,16 @@ static int msm_dai_q6_dai_probe(struct snd_soc_dai *dai) snd_ctl_new1(&usb_audio_cfg_controls[3], dai_data)); break; + case SLIMBUS_0_RX: + rc = snd_ctl_add(dai->component->card->snd_card, + snd_ctl_new1(&avd_drift_config_controls[0], + dai)); + break; + case SLIMBUS_6_RX: + rc = snd_ctl_add(dai->component->card->snd_card, + snd_ctl_new1(&avd_drift_config_controls[1], + dai)); + break; } if (IS_ERR_VALUE(rc)) dev_err(dai->dev, "%s: err add config ctl, DAI = %s\n", @@ -4952,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; @@ -4959,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, @@ -5031,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) { @@ -5826,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, @@ -7856,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, @@ -7890,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) { @@ -7901,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) { @@ -7912,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) { @@ -7923,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) { @@ -7934,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 73eadfa4eebb..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; @@ -239,8 +241,7 @@ static void event_handler(uint32_t opcode, return; } - ret = msm_adsp_inform_mixer_ctl(rtd, DSP_STREAM_CALLBACK, - payload); + ret = msm_adsp_inform_mixer_ctl(rtd, payload); if (ret) { pr_err("%s: failed to inform mixer ctl. err = %d\n", __func__, ret); @@ -691,6 +692,7 @@ static int msm_pcm_open(struct snd_pcm_substream *substream) prtd->set_channel_map = false; prtd->reset_event = false; runtime->private_data = prtd; + msm_adsp_init_mixer_ctl_pp_event_queue(soc_prtd); return 0; } @@ -833,6 +835,7 @@ static int msm_pcm_playback_close(struct snd_pcm_substream *substream) } msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->be_id, SNDRV_PCM_STREAM_PLAYBACK); + msm_adsp_clean_mixer_ctl_pp_event_queue(soc_prtd); kfree(prtd); runtime->private_data = NULL; @@ -1074,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__); @@ -1102,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; @@ -1187,7 +1195,6 @@ static int msm_pcm_add_audio_adsp_stream_callback_control( .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, .info = msm_adsp_stream_callback_info, .get = msm_adsp_stream_callback_get, - .put = msm_adsp_stream_callback_put, .private_value = 0, } }; @@ -1231,6 +1238,7 @@ static int msm_pcm_add_audio_adsp_stream_callback_control( } kctl->private_data = NULL; + free_mixer_str: kfree(mixer_str); done: diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c index e199a6a0de0b..0f63fd6bbd00 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c @@ -8115,6 +8115,9 @@ static const struct snd_kcontrol_new primary_mi2s_rx_port_mixer_controls[] = { SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_PRI_MI2S_RX, MSM_BACKEND_DAI_SLIMBUS_0_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), + SOC_SINGLE_EXT("SLIM_8_TX", MSM_BACKEND_DAI_PRI_MI2S_RX, + MSM_BACKEND_DAI_SLIMBUS_8_TX, 1, 0, msm_routing_get_port_mixer, + msm_routing_put_port_mixer), }; static const struct snd_kcontrol_new usb_rx_port_mixer_controls[] = { @@ -8145,6 +8148,9 @@ static const struct snd_kcontrol_new quat_mi2s_rx_port_mixer_controls[] = { SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), + SOC_SINGLE_EXT("SLIM_8_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, + MSM_BACKEND_DAI_SLIMBUS_8_TX, 1, 0, msm_routing_get_port_mixer, + msm_routing_put_port_mixer), }; static const struct snd_kcontrol_new pri_tdm_rx_0_port_mixer_controls[] = { @@ -9235,6 +9241,9 @@ static const struct snd_kcontrol_new tert_mi2s_rx_port_mixer_controls[] = { SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_RX, MSM_BACKEND_DAI_SECONDARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), + SOC_SINGLE_EXT("SLIM_8_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_RX, + MSM_BACKEND_DAI_SLIMBUS_8_TX, 1, 0, msm_routing_get_port_mixer, + msm_routing_put_port_mixer), }; static const struct snd_kcontrol_new sec_mi2s_rx_port_mixer_controls[] = { @@ -9256,6 +9265,9 @@ static const struct snd_kcontrol_new sec_mi2s_rx_port_mixer_controls[] = { SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_SECONDARY_MI2S_RX, MSM_BACKEND_DAI_INT_FM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), + SOC_SINGLE_EXT("SLIM_8_TX", MSM_BACKEND_DAI_SECONDARY_MI2S_RX, + MSM_BACKEND_DAI_SLIMBUS_8_TX, 1, 0, msm_routing_get_port_mixer, + msm_routing_put_port_mixer), }; static const struct snd_kcontrol_new lsm1_mixer_controls[] = { @@ -13881,6 +13893,7 @@ static const struct snd_soc_dapm_route intercon[] = { {"PRI_MI2S_RX Port Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"}, {"PRI_MI2S_RX Port Mixer", "INTERNAL_FM_TX", "INT_FM_TX"}, {"PRI_MI2S_RX Port Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"}, + {"PRI_MI2S_RX Port Mixer", "SLIM_8_TX", "SLIMBUS_8_TX"}, {"PRI_MI2S_RX", NULL, "PRI_MI2S_RX Port Mixer"}, {"SEC_MI2S_RX Port Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"}, @@ -13889,6 +13902,7 @@ static const struct snd_soc_dapm_route intercon[] = { {"SEC_MI2S_RX Port Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"}, {"SEC_MI2S_RX Port Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"}, {"SEC_MI2S_RX Port Mixer", "INTERNAL_FM_TX", "INT_FM_TX"}, + {"SEC_MI2S_RX Port Mixer", "SLIM_8_TX", "SLIMBUS_8_TX"}, {"SEC_MI2S_RX", NULL, "SEC_MI2S_RX Port Mixer"}, {"TERT_MI2S_RX Port Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"}, @@ -13896,6 +13910,7 @@ static const struct snd_soc_dapm_route intercon[] = { {"TERT_MI2S_RX Port Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"}, {"TERT_MI2S_RX Port Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"}, {"TERT_MI2S_RX Port Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"}, + {"TERT_MI2S_RX Port Mixer", "SLIM_8_TX", "SLIMBUS_8_TX"}, {"TERT_MI2S_RX", NULL, "TERT_MI2S_RX Port Mixer"}, {"QUAT_MI2S_RX Port Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"}, @@ -13905,6 +13920,7 @@ static const struct snd_soc_dapm_route intercon[] = { {"QUAT_MI2S_RX Port Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"}, {"QUAT_MI2S_RX Port Mixer", "INTERNAL_FM_TX", "INT_FM_TX"}, {"QUAT_MI2S_RX Port Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"}, + {"QUAT_MI2S_RX Port Mixer", "SLIM_8_TX", "SLIMBUS_8_TX"}, {"QUAT_MI2S_RX", NULL, "QUAT_MI2S_RX Port Mixer"}, /* Backend Enablement */ diff --git a/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c b/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c index d4e78604f868..cac28f43e5ae 100644 --- a/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c +++ b/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c @@ -45,21 +45,6 @@ enum { EQ_BAND_MAX, }; -struct msm_audio_eq_band { - uint16_t band_idx; /* The band index, 0 .. 11 */ - uint32_t filter_type; /* Filter band type */ - uint32_t center_freq_hz; /* Filter band center frequency */ - uint32_t filter_gain; /* Filter band initial gain (dB) */ - /* Range is +12 dB to -12 dB with 1dB increments. */ - uint32_t q_factor; -} __packed; - -struct msm_audio_eq_stream_config { - uint32_t enable; /* Number of consequtive bands specified */ - uint32_t num_bands; - struct msm_audio_eq_band eq_bands[EQ_BAND_MAX]; -} __packed; - /* Audio Sphere data structures */ struct msm_audio_pp_asphere_state_s { uint32_t enabled; @@ -817,18 +802,133 @@ static int msm_qti_pp_asphere_set(struct snd_kcontrol *kcontrol, return 0; } +int msm_adsp_init_mixer_ctl_pp_event_queue(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_kcontrol *kctl; + const char *deviceNo = "NN"; + char *mixer_str = NULL; + int ctl_len = 0, ret = 0; + const char *mixer_ctl_name = DSP_STREAM_CALLBACK; + struct dsp_stream_callback_prtd *kctl_prtd = NULL; + + if (!rtd) { + pr_err("%s: rtd is NULL\n", __func__); + ret = -EINVAL; + goto done; + } + + ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1; + mixer_str = kzalloc(ctl_len, GFP_KERNEL); + if (!mixer_str) { + ret = -EINVAL; + goto done; + } + + snprintf(mixer_str, ctl_len, "%s %d", mixer_ctl_name, + rtd->pcm->device); + kctl = snd_soc_card_get_kcontrol(rtd->card, mixer_str); + kfree(mixer_str); + if (!kctl) { + pr_err("%s: failed to get kctl.\n", __func__); + ret = -EINVAL; + goto done; + } + + if (kctl->private_data != NULL) { + pr_err("%s: kctl_prtd is not NULL at initialization.\n", + __func__); + return -EINVAL; + } + + kctl_prtd = kzalloc(sizeof(struct dsp_stream_callback_prtd), + GFP_KERNEL); + if (!kctl_prtd) { + ret = -ENOMEM; + goto done; + } + + spin_lock_init(&kctl_prtd->prtd_spin_lock); + INIT_LIST_HEAD(&kctl_prtd->event_queue); + kctl_prtd->event_count = 0; + kctl->private_data = kctl_prtd; + +done: + return ret; +} + +int msm_adsp_clean_mixer_ctl_pp_event_queue(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_kcontrol *kctl; + const char *deviceNo = "NN"; + char *mixer_str = NULL; + int ctl_len = 0, ret = 0; + struct dsp_stream_callback_list *node, *n; + unsigned long spin_flags; + const char *mixer_ctl_name = DSP_STREAM_CALLBACK; + struct dsp_stream_callback_prtd *kctl_prtd = NULL; + + if (!rtd) { + pr_err("%s: rtd is NULL\n", __func__); + ret = -EINVAL; + goto done; + } + + ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1; + mixer_str = kzalloc(ctl_len, GFP_KERNEL); + if (!mixer_str) { + ret = -EINVAL; + goto done; + } + + snprintf(mixer_str, ctl_len, "%s %d", mixer_ctl_name, + rtd->pcm->device); + kctl = snd_soc_card_get_kcontrol(rtd->card, mixer_str); + kfree(mixer_str); + if (!kctl) { + pr_err("%s: failed to get kctl.\n", __func__); + ret = -EINVAL; + goto done; + } + + kctl_prtd = (struct dsp_stream_callback_prtd *) + kctl->private_data; + if (kctl_prtd != NULL) { + spin_lock_irqsave(&kctl_prtd->prtd_spin_lock, spin_flags); + /* clean the queue */ + list_for_each_entry_safe(node, n, + &kctl_prtd->event_queue, list) { + list_del(&node->list); + kctl_prtd->event_count--; + pr_debug("%s: %d remaining events after del.\n", + __func__, kctl_prtd->event_count); + kfree(node); + } + spin_unlock_irqrestore(&kctl_prtd->prtd_spin_lock, spin_flags); + } + + kfree(kctl_prtd); + kctl->private_data = NULL; + +done: + return ret; +} int msm_adsp_inform_mixer_ctl(struct snd_soc_pcm_runtime *rtd, - const char *mixer_ctl_name, uint32_t *payload) { /* adsp pp event notifier */ struct snd_kcontrol *kctl; struct snd_ctl_elem_value control; - uint32_t payload_size = 0; const char *deviceNo = "NN"; char *mixer_str = NULL; int ctl_len = 0, ret = 0; + struct dsp_stream_callback_list *new_event; + struct dsp_stream_callback_list *oldest_event; + unsigned long spin_flags; + struct dsp_stream_callback_prtd *kctl_prtd = NULL; + struct msm_adsp_event_data *event_data = NULL; + const char *mixer_ctl_name = DSP_STREAM_CALLBACK; + struct snd_ctl_elem_info kctl_info; if (!rtd || !payload) { pr_err("%s: %s is NULL\n", __func__, @@ -837,6 +937,12 @@ int msm_adsp_inform_mixer_ctl(struct snd_soc_pcm_runtime *rtd, goto done; } + if (rtd->card->snd_card == NULL) { + pr_err("%s: snd_card is null.\n", __func__); + ret = -EINVAL; + goto done; + } + ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1; mixer_str = kzalloc(ctl_len, GFP_ATOMIC); if (!mixer_str) { @@ -854,21 +960,59 @@ int msm_adsp_inform_mixer_ctl(struct snd_soc_pcm_runtime *rtd, goto done; } - control.id = kctl->id; - payload_size = payload[0]; - /* Copy complete payload */ - memcpy(control.value.bytes.data, (void *)payload, - sizeof(payload_size) + payload_size); - kctl->put(kctl, &control); - if (rtd->card->snd_card == NULL) { - pr_err("%s: snd_card is null.\n", __func__); + event_data = (struct msm_adsp_event_data *)payload; + kctl->info(kctl, &kctl_info); + if (sizeof(struct msm_adsp_event_data) + + event_data->payload_len > kctl_info.count) { + pr_err("%s: payload length exceeds limit of %u bytes.\n", + __func__, kctl_info.count); ret = -EINVAL; goto done; } + kctl_prtd = (struct dsp_stream_callback_prtd *) + kctl->private_data; + if (kctl_prtd == NULL) { + /* queue is not initialized */ + ret = -EINVAL; + pr_err("%s: event queue is not initialized.\n", __func__); + goto done; + } + + new_event = kzalloc(sizeof(struct dsp_stream_callback_list) + + event_data->payload_len, + GFP_ATOMIC); + if (new_event == NULL) { + ret = -ENOMEM; + goto done; + } + memcpy((void *)&new_event->event, (void *)payload, + event_data->payload_len + + sizeof(struct msm_adsp_event_data)); + + spin_lock_irqsave(&kctl_prtd->prtd_spin_lock, spin_flags); + while (kctl_prtd->event_count >= DSP_STREAM_CALLBACK_QUEUE_SIZE) { + pr_info("%s: queue of size %d is full. delete oldest one.\n", + __func__, DSP_STREAM_CALLBACK_QUEUE_SIZE); + oldest_event = list_first_entry(&kctl_prtd->event_queue, + struct dsp_stream_callback_list, list); + pr_info("%s: event deleted: type %d length %d\n", + __func__, oldest_event->event.event_type, + oldest_event->event.payload_len); + list_del(&oldest_event->list); + kctl_prtd->event_count--; + kfree(oldest_event); + } + + list_add_tail(&new_event->list, &kctl_prtd->event_queue); + kctl_prtd->event_count++; + spin_unlock_irqrestore(&kctl_prtd->prtd_spin_lock, spin_flags); + + control.id = kctl->id; snd_ctl_notify(rtd->card->snd_card, SNDRV_CTL_EVENT_MASK_INFO, &control.id); + done: return ret; } @@ -877,44 +1021,8 @@ int msm_adsp_stream_cmd_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; - uinfo->count = 512; - - return 0; -} - -int msm_adsp_stream_callback_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - uint32_t payload_size = 0, last_payload_size = 0; - - /* fetch payload size in first four bytes */ - memcpy(&payload_size, ucontrol->value.bytes.data, sizeof(uint32_t)); - - if (kcontrol->private_data == NULL) { - /* buffer is empty */ - kcontrol->private_data = - kzalloc(payload_size + sizeof(payload_size), - GFP_ATOMIC); - if (kcontrol->private_data == NULL) - return -ENOMEM; - } else { - memcpy(&last_payload_size, kcontrol->private_data, - sizeof(uint32_t)); - if (last_payload_size < payload_size) { - /* new payload size exceeds old one. - * reallocate buffer - */ - kfree(kcontrol->private_data); - kcontrol->private_data = - kzalloc(payload_size + sizeof(payload_size), - GFP_ATOMIC); - if (kcontrol->private_data == NULL) - return -ENOMEM; - } - } - - memcpy(kcontrol->private_data, ucontrol->value.bytes.data, - sizeof(uint32_t) + payload_size); + uinfo->count = + sizeof(((struct snd_ctl_elem_value *)0)->value.bytes.data); return 0; } @@ -923,26 +1031,53 @@ int msm_adsp_stream_callback_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { uint32_t payload_size = 0; + struct dsp_stream_callback_list *oldest_event; + unsigned long spin_flags; + struct dsp_stream_callback_prtd *kctl_prtd = NULL; + int ret = 0; - if (kcontrol->private_data == NULL) { - pr_err("%s: ASM Stream PP Event Data Unavailable\n", __func__); - return -EINVAL; + kctl_prtd = (struct dsp_stream_callback_prtd *) + kcontrol->private_data; + if (kctl_prtd == NULL) { + pr_err("%s: ASM Stream PP event queue is not initialized.\n", + __func__); + ret = -EINVAL; + goto done; + } + + spin_lock_irqsave(&kctl_prtd->prtd_spin_lock, spin_flags); + pr_debug("%s: %d events in queue.\n", __func__, kctl_prtd->event_count); + if (list_empty(&kctl_prtd->event_queue)) { + pr_err("%s: ASM Stream PP event queue is empty.\n", __func__); + ret = -EINVAL; + spin_unlock_irqrestore(&kctl_prtd->prtd_spin_lock, spin_flags); + goto done; } - memcpy(&payload_size, kcontrol->private_data, sizeof(uint32_t)); - memcpy(ucontrol->value.bytes.data, kcontrol->private_data, - sizeof(uint32_t) + payload_size); - kfree(kcontrol->private_data); - kcontrol->private_data = NULL; + oldest_event = list_first_entry(&kctl_prtd->event_queue, + struct dsp_stream_callback_list, list); + list_del(&oldest_event->list); + kctl_prtd->event_count--; + spin_unlock_irqrestore(&kctl_prtd->prtd_spin_lock, spin_flags); - return 0; + payload_size = oldest_event->event.payload_len; + pr_debug("%s: event fetched: type %d length %d\n", + __func__, oldest_event->event.event_type, + oldest_event->event.payload_len); + memcpy(ucontrol->value.bytes.data, &oldest_event->event, + sizeof(struct msm_adsp_event_data) + payload_size); + kfree(oldest_event); + +done: + return ret; } int msm_adsp_stream_callback_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; - uinfo->count = 512; + uinfo->count = + sizeof(((struct snd_ctl_elem_value *)0)->value.bytes.data); return 0; } diff --git a/sound/soc/msm/qdsp6v2/msm-qti-pp-config.h b/sound/soc/msm/qdsp6v2/msm-qti-pp-config.h index 70ce20fbd8f8..6ffcbdbd543e 100644 --- a/sound/soc/msm/qdsp6v2/msm-qti-pp-config.h +++ b/sound/soc/msm/qdsp6v2/msm-qti-pp-config.h @@ -14,12 +14,11 @@ #include <sound/soc.h> int msm_adsp_inform_mixer_ctl(struct snd_soc_pcm_runtime *rtd, - const char *mixer_ctl_name, uint32_t *payload); +int msm_adsp_init_mixer_ctl_pp_event_queue(struct snd_soc_pcm_runtime *rtd); +int msm_adsp_clean_mixer_ctl_pp_event_queue(struct snd_soc_pcm_runtime *rtd); int msm_adsp_stream_cmd_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo); -int msm_adsp_stream_callback_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol); int msm_adsp_stream_callback_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); int msm_adsp_stream_callback_info(struct snd_kcontrol *kcontrol, diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c index 0cf386a3c2fc..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( @@ -1675,7 +1689,7 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) int32_t ret = 0; union asm_token_struct asm_token; uint8_t buf_index; - char *pp_event_package = NULL; + struct msm_adsp_event_data *pp_event_package = NULL; uint32_t payload_size = 0; if (ac == NULL) { @@ -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,25 +2063,40 @@ 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 size + actual payload + * package is composed of event type + size + actual payload */ payload_size = data->payload_size; - pp_event_package = - kzalloc(payload_size + sizeof(payload_size), + pp_event_package = kzalloc(payload_size + + sizeof(struct msm_adsp_event_data), GFP_ATOMIC); if (!pp_event_package) return -ENOMEM; - memcpy((void *)pp_event_package, - &payload_size, sizeof(payload_size)); - memcpy((void *)pp_event_package + sizeof(payload_size), - data->payload, payload_size); + + pp_event_package->event_type = i; + pp_event_package->payload_len = payload_size; + memcpy((void *)pp_event_package->payload, + data->payload, payload_size); ac->cb(data->opcode, data->token, (void *)pp_event_package, ac->priv); kfree(pp_event_package); return 0; + case ASM_SESSION_CMDRSP_ADJUST_SESSION_CLOCK_V2: + pr_debug("%s: ASM_SESSION_CMDRSP_ADJUST_SESSION_CLOCK_V2 sesion %d status 0x%x msw %u lsw %u\n", + __func__, ac->session, payload[0], payload[2], + payload[1]); + wake_up(&ac->cmd_wait); + break; case ASM_SESSION_CMDRSP_GET_PATH_DELAY_V2: pr_debug("%s: ASM_SESSION_CMDRSP_GET_PATH_DELAY_V2 session %d status 0x%x msw %u lsw %u\n", __func__, ac->session, payload[0], payload[2], @@ -2602,7 +2637,9 @@ int q6asm_open_write_compressed(struct audio_client *ac, uint32_t format, case FORMAT_GEN_COMPR: open.fmt_id = ASM_MEDIA_FMT_GENERIC_COMPRESSED; break; - + case FORMAT_TRUEHD: + open.fmt_id = ASM_MEDIA_FMT_TRUEHD; + break; default: pr_err("%s: Invalid format[%d]\n", __func__, format); rc = -EINVAL; @@ -2775,9 +2812,6 @@ static int __q6asm_open_write(struct audio_client *ac, uint32_t format, case FORMAT_GEN_COMPR: open.dec_fmt_id = ASM_MEDIA_FMT_GENERIC_COMPRESSED; break; - case FORMAT_TRUEHD: - open.dec_fmt_id = ASM_MEDIA_FMT_TRUEHD; - break; default: pr_err("%s: Invalid format 0x%x\n", __func__, format); rc = -EINVAL; @@ -6892,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) { @@ -8039,6 +8223,80 @@ exit: return rc; } +int q6asm_send_mtmx_strtr_enable_adjust_session_clock(struct audio_client *ac, + bool enable) +{ + struct asm_mtmx_strtr_params matrix; + struct asm_session_mtmx_param_adjust_session_time_ctl_t adjust_time; + int sz = 0; + int rc = 0; + + pr_debug("%s: adjust session enable %d\n", __func__, enable); + + if (!ac) { + pr_err("%s: audio client handle is NULL\n", __func__); + rc = -EINVAL; + goto exit; + } + + if (ac->apr == NULL) { + pr_err("%s: ac->apr is NULL\n", __func__); + rc = -EINVAL; + goto exit; + } + + adjust_time.enable = enable; + memset(&matrix, 0, sizeof(struct asm_mtmx_strtr_params)); + sz = sizeof(struct asm_mtmx_strtr_params); + q6asm_add_hdr(ac, &matrix.hdr, sz, TRUE); + atomic_set(&ac->cmd_state, -1); + matrix.hdr.opcode = ASM_SESSION_CMD_SET_MTMX_STRTR_PARAMS_V2; + + matrix.param.data_payload_addr_lsw = 0; + matrix.param.data_payload_addr_msw = 0; + matrix.param.mem_map_handle = 0; + matrix.param.data_payload_size = + sizeof(struct asm_stream_param_data_v2) + + sizeof(struct asm_session_mtmx_param_adjust_session_time_ctl_t); + matrix.param.direction = 0; /* RX */ + matrix.data.module_id = ASM_SESSION_MTMX_STRTR_MODULE_ID_AVSYNC; + matrix.data.param_id = ASM_SESSION_MTMX_PARAM_ADJUST_SESSION_TIME_CTL; + matrix.data.param_size = + sizeof(struct asm_session_mtmx_param_adjust_session_time_ctl_t); + matrix.data.reserved = 0; + matrix.config.adj_time_param.enable = adjust_time.enable; + + rc = apr_send_pkt(ac->apr, (uint32_t *) &matrix); + if (rc < 0) { + pr_err("%s: enable adjust session failed failed paramid [0x%x]\n", + __func__, matrix.data.param_id); + rc = -EINVAL; + goto exit; + } + + rc = wait_event_timeout(ac->cmd_wait, + (atomic_read(&ac->cmd_state) >= 0), 5*HZ); + if (!rc) { + pr_err("%s: enable adjust session failed failed paramid [0x%x]\n", + __func__, matrix.data.param_id); + rc = -ETIMEDOUT; + goto exit; + } + + if (atomic_read(&ac->cmd_state) > 0) { + pr_err("%s: DSP returned error[%s]\n", + __func__, adsp_err_get_err_str( + atomic_read(&ac->cmd_state))); + rc = adsp_err_get_lnx_err_code( + atomic_read(&ac->cmd_state)); + goto exit; + } + rc = 0; +exit: + return rc; +} + + static int __q6asm_cmd(struct audio_client *ac, int cmd, uint32_t stream_id) { struct apr_hdr hdr; @@ -8428,6 +8686,68 @@ fail_cmd: return -EINVAL; } +int q6asm_adjust_session_clock(struct audio_client *ac, + uint32_t adjust_time_lsw, + uint32_t adjust_time_msw) +{ + int rc = 0; + int sz = 0; + struct asm_session_cmd_adjust_session_clock_v2 adjust_clock; + + pr_debug("%s: adjust_time_lsw is %x, adjust_time_msw is %x\n", __func__, + adjust_time_lsw, adjust_time_msw); + + if (!ac) { + pr_err("%s: audio client handle is NULL\n", __func__); + rc = -EINVAL; + goto fail_cmd; + } + + if (ac->apr == NULL) { + pr_err("%s: ac->apr is NULL", __func__); + rc = -EINVAL; + goto fail_cmd; + } + + sz = sizeof(struct asm_session_cmd_adjust_session_clock_v2); + q6asm_add_hdr(ac, &adjust_clock.hdr, sz, TRUE); + atomic_set(&ac->cmd_state, -1); + adjust_clock.hdr.opcode = ASM_SESSION_CMD_ADJUST_SESSION_CLOCK_V2; + + adjust_clock.adjustime_lsw = adjust_time_lsw; + adjust_clock.adjustime_msw = adjust_time_msw; + + + rc = apr_send_pkt(ac->apr, (uint32_t *) &adjust_clock); + if (rc < 0) { + pr_err("%s: adjust_clock send failed paramid [0x%x]\n", + __func__, adjust_clock.hdr.opcode); + rc = -EINVAL; + goto fail_cmd; + } + + rc = wait_event_timeout(ac->cmd_wait, + (atomic_read(&ac->cmd_state) >= 0), 5*HZ); + if (!rc) { + pr_err("%s: timeout, adjust_clock paramid[0x%x]\n", + __func__, adjust_clock.hdr.opcode); + rc = -ETIMEDOUT; + goto fail_cmd; + } + + if (atomic_read(&ac->cmd_state) > 0) { + pr_err("%s: DSP returned error[%s]\n", + __func__, adsp_err_get_err_str( + atomic_read(&ac->cmd_state))); + rc = adsp_err_get_lnx_err_code( + atomic_read(&ac->cmd_state)); + goto fail_cmd; + } + rc = 0; +fail_cmd: + return rc; +} + /* * q6asm_get_path_delay() - get the path delay for an audio session * @ac: audio client handle diff --git a/sound/usb/format.c b/sound/usb/format.c index 2cc3b92f1fba..cb23dd1670b3 100644 --- a/sound/usb/format.c +++ b/sound/usb/format.c @@ -90,6 +90,11 @@ static u64 parse_audio_format_i_type(struct snd_usb_audio *chip, sample_bytes = SUBSLOTSIZE_24_BIT; break; } + + default: + usb_audio_err(chip, "%u:%d : Invalid wMaxPacketSize\n", + fp->iface, fp->altsetting); + return pcm_formats; } format = 1 << format; break; diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index b9d9d2e99c78..70dfdd22102e 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -1632,6 +1632,10 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, break; } break; + + default: + usb_audio_err(state->chip, "Invalid unit %u\n", unitid); + return -EINVAL; } } diff --git a/sound/usb/stream.c b/sound/usb/stream.c index 2bb503576134..a7d7c3a0ac3e 100644 --- a/sound/usb/stream.c +++ b/sound/usb/stream.c @@ -652,6 +652,16 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no) case UAC_VERSION_3: { int wMaxPacketSize; + /* + * Allocate a dummy instance of fmt and set format type + * to UAC_FORMAT_TYPE_I for BADD support; free fmt + * after its last usage + */ + fmt = kzalloc(sizeof(*fmt), GFP_KERNEL); + if (!fmt) + return -ENOMEM; + + fmt->bFormatType = UAC_FORMAT_TYPE_I; format = UAC_FORMAT_TYPE_I_PCM; clock = BADD_CLOCK_SOURCE; wMaxPacketSize = le16_to_cpu(get_endpoint(alts, 0) @@ -678,6 +688,7 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no) dev_err(&dev->dev, "%u:%d: invalid wMaxPacketSize\n", iface_no, altno); + kfree(fmt); continue; } } @@ -776,6 +787,8 @@ populate_fp: continue; } + if (protocol == UAC_VERSION_3) + kfree(fmt); /* Create chmap */ if (fp->channels != num_channels) chconfig = 0; diff --git a/sound/usb/usb_audio_qmi_svc.c b/sound/usb/usb_audio_qmi_svc.c index 14ea2239fe11..28c5a3736a9c 100644 --- a/sound/usb/usb_audio_qmi_svc.c +++ b/sound/usb/usb_audio_qmi_svc.c @@ -497,6 +497,12 @@ static int prepare_qmi_response(struct snd_usb_substream *subs, resp->usb_audio_subslot_size = SUBSLOTSIZE_24_BIT; break; } + + default: + pr_err("%d: %u: Invalid wMaxPacketSize\n", + subs->interface, subs->altset_idx); + ret = -EINVAL; + goto err; } resp->usb_audio_subslot_size_valid = 1; } else { |
