diff options
162 files changed, 3458 insertions, 518 deletions
diff --git a/Documentation/devicetree/bindings/drm/msm/hdmi-display.txt b/Documentation/devicetree/bindings/drm/msm/hdmi-display.txt index aaa3722659ab..9329fb74dea0 100644 --- a/Documentation/devicetree/bindings/drm/msm/hdmi-display.txt +++ b/Documentation/devicetree/bindings/drm/msm/hdmi-display.txt @@ -50,7 +50,7 @@ Example: qcom,mode-v-pulse-width = <10>; qcom,mode-v-back-porch = <72>; qcom,mode-v-active-high; - qcom,mode-refersh-rate = <30>; + qcom,mode-refresh-rate = <30>; qcom,mode-clock-in-khz = <297000>; }; }; diff --git a/Documentation/devicetree/bindings/media/video/msm-csid.txt b/Documentation/devicetree/bindings/media/video/msm-csid.txt index 340d98688b76..e580c056b3eb 100644 --- a/Documentation/devicetree/bindings/media/video/msm-csid.txt +++ b/Documentation/devicetree/bindings/media/video/msm-csid.txt @@ -12,8 +12,8 @@ Required properties: - "qcom,csid-v3.5" - "qcom,csid-v4.0" - "qcom,csid-v3.4.2" - - "qcom,csid-v3.5.1" - "qcom,csid-v3.4.3" + - "qcom,csid-v3.5.1" - "qcom,csid-v5.0" - reg : offset and length of the register set for the device for the csid operating in compatible mode. diff --git a/Documentation/devicetree/bindings/spi/spi_qsd.txt b/Documentation/devicetree/bindings/spi/spi_qsd.txt index 1edf0820398a..b3007eb9ceea 100644 --- a/Documentation/devicetree/bindings/spi/spi_qsd.txt +++ b/Documentation/devicetree/bindings/spi/spi_qsd.txt @@ -1,7 +1,8 @@ Qualcomm Serial Peripheral Interface (SPI) Required properties: -- compatible : Should be "qcom,spi-qup-v2". +- compatible : Should be "qcom,spi-qup-v2". Should "qcom,qup-v26" for + controllers that support spi slave mode. - reg : Offset and length of the register regions for the device - reg-names : Register region names referenced in reg above. Required register resource entries are: @@ -72,6 +73,7 @@ the following properties. clock phase (CPHA) mode - spi-cs-high : (optional) Empty property indicating device requires chip select active high +- qcom,slv-ctrl : Set this flag to configure QUP as SPI slave controller. Example: aliases { diff --git a/Documentation/devicetree/bindings/usb/dwc3.txt b/Documentation/devicetree/bindings/usb/dwc3.txt index ddca4c39e2de..7328b2847e02 100644 --- a/Documentation/devicetree/bindings/usb/dwc3.txt +++ b/Documentation/devicetree/bindings/usb/dwc3.txt @@ -61,6 +61,7 @@ Optional properties: - snps,num-gsi-evt-buffs: If present, specifies number of GSI based hardware accelerated event buffers. 1 event buffer is needed per h/w accelerated endpoint. - xhci-imod-value: Interrupt moderation interval for host mode (in increments of 250nsec). + - usb-core-id: Differentiates between different controllers present on a device. This is usually a subnode to DWC3 glue to which it is connected. diff --git a/arch/arm/boot/dts/qcom/Makefile b/arch/arm/boot/dts/qcom/Makefile index 8829ef5fd221..f7ba268b233e 100644 --- a/arch/arm/boot/dts/qcom/Makefile +++ b/arch/arm/boot/dts/qcom/Makefile @@ -113,7 +113,8 @@ dtb-$(CONFIG_ARCH_MSM8996) += msm8996-v2-pmi8994-cdp.dtb \ apq8096-v3-pmi8994-mdm9x55-slimbus-mtp.dtb \ apq8096-v3-pmi8996-mdm9x55-i2s-mtp.dtb \ apq8096-v3-pmi8996-mdm9x55-slimbus-mtp.dtb \ - apq8096-v3-pmi8996-dragonboard.dtb + apq8096-v3-pmi8996-dragonboard.dtb \ + msm8996-auto-mizar.dtb dtb-$(CONFIG_MSM_GVM_QUIN) += vplatform-lfv-msm8996-telematics.dtb \ vplatform-lfv-msm8996-ivi.dtb diff --git a/arch/arm/boot/dts/qcom/dsi-adv7533-1080p.dtsi b/arch/arm/boot/dts/qcom/dsi-adv7533-1080p.dtsi index 7994285f13f1..6cf9ed195e0a 100644 --- a/arch/arm/boot/dts/qcom/dsi-adv7533-1080p.dtsi +++ b/arch/arm/boot/dts/qcom/dsi-adv7533-1080p.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -36,13 +36,6 @@ qcom,mdss-dsi-bpp = <24>; qcom,mdss-dsi-underflow-color = <0xff>; qcom,mdss-dsi-border-color = <0>; - qcom,mdss-dsi-on-command = [ - 05 01 00 00 c8 00 02 11 00 - 05 01 00 00 0a 00 02 29 00]; - qcom,mdss-dsi-off-command = [05 01 00 00 00 00 02 28 00 - 05 01 00 00 00 00 02 10 00]; - qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; - qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; qcom,mdss-dsi-h-sync-pulse = <1>; qcom,mdss-dsi-traffic-mode = "non_burst_sync_pulse"; qcom,mdss-dsi-bllp-eof-power-mode; diff --git a/arch/arm/boot/dts/qcom/dsi-adv7533-720p.dtsi b/arch/arm/boot/dts/qcom/dsi-adv7533-720p.dtsi index b84488c0cef3..a3bbc6f80de2 100644 --- a/arch/arm/boot/dts/qcom/dsi-adv7533-720p.dtsi +++ b/arch/arm/boot/dts/qcom/dsi-adv7533-720p.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -36,13 +36,6 @@ dsi_adv7533_720p: qcom,mdss_dsi_adv7533_720p { qcom,mdss-dsi-bpp = <24>; qcom,mdss-dsi-underflow-color = <0xff>; qcom,mdss-dsi-border-color = <0>; - qcom,mdss-dsi-on-command = [ - 05 01 00 00 c8 00 02 11 00 - 05 01 00 00 0a 00 02 29 00]; - qcom,mdss-dsi-off-command = [05 01 00 00 00 00 02 28 00 - 05 01 00 00 00 00 02 10 00]; - qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; - qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; qcom,mdss-dsi-h-sync-pulse = <1>; qcom,mdss-dsi-traffic-mode = "non_burst_sync_pulse"; qcom,mdss-dsi-bllp-eof-power-mode; diff --git a/arch/arm/boot/dts/qcom/msm8996-auto-mizar.dts b/arch/arm/boot/dts/qcom/msm8996-auto-mizar.dts new file mode 100644 index 000000000000..3a7d009c12a4 --- /dev/null +++ b/arch/arm/boot/dts/qcom/msm8996-auto-mizar.dts @@ -0,0 +1,328 @@ +/* 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 <dt-bindings/gpio/gpio.h> +#include "msm8996pro.dtsi" +#include "msm8996-pm8994.dtsi" +#include "msm8996-agave-adp.dtsi" +#include "msm8996pro-auto.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. MSM 8996pro AUTO ADP"; + compatible = "qcom,msm8996-adp", "qcom,msm8996", "qcom,adp"; + qcom,msm-id = <315 0x10001>; + qcom,board-id = <0x06010019 0>, <0x00010001 0>; +}; + +&spi_9 { + status = "ok"; + can-controller@0 { + compatible = "renesas,rh850"; + reg = <0>; + interrupt-parent = <&tlmm>; + interrupts = <122 0>; + spi-max-frequency = <5000000>; + }; +}; + +&soc { + qcom,msm-ssc-sensors { + status = "disabled"; + }; + + qcom,msm-thermal { + qcom,hotplug-temp = <115>; + qcom,hotplug-temp-hysteresis = <25>; + qcom,therm-reset-temp = <119>; + }; + + qcom,adv7481@70 { + status = "disabled"; + }; + + qcom,ntn_avb { + qcom,ntn-rc-num = <2>; + }; + + i2c@75b6000 { /* BLSP8 */ + /* ADV7533 HDMI Bridge Chip removed on ADP Lite */ + adv7533@39 { + status = "disabled"; + }; + + adv7533@3d { + status = "disabled"; + }; + }; + +}; + +&cci { + qcom,camera@0 { + pinctrl-names = "cam_default", "cam_suspend","default"; + pinctrl-2 = <&mx9296_pwr>; + qcom,cci-master = <0>; + }; +}; + +&tlmm { + pcie2 { + pcie2_perst_default: pcie2_perst_default { + mux { + pins = "gpio90"; + function = "gpio"; + }; + + config { + pins = "gpio90"; + drive-strength = <2>; + bias-pull-down; + }; + }; + + pcie2_wake_default: pcie2_wake_default { + mux { + pins = "gpio54"; + function = "gpio"; + }; + + config { + pins = "gpio54"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; + + mx9296_pwr: mx9296_pwr { + mux { + pins = "gpio21"; + function = "gpio"; + }; + + config { + pins = "gpio21"; + drive-strength = <2>; + bias-pull-up; + output-high; + }; + }; +}; + +&pil_modem { + pinctrl-names = "default"; + pinctrl-0 = <&modem_mux>; +}; + +&slim_msm { + status = "disabled"; +}; + +&pm8994_mpps { + mpp@a500 { /* MPP 6 */ + qcom,mode = <1>; /* Digital output */ + qcom,output-type = <0>; /* CMOS logic */ + qcom,vin-sel = <2>; /* S4 1.8V */ + qcom,src-sel = <0>; /* Constant */ + qcom,master-en = <1>; /* Enable GPIO */ + status = "okay"; + }; +}; + +&sdhc_2 { + cd-gpios = <&tlmm 38 GPIO_ACTIVE_LOW>; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on_sbc>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off + &sdc2_cd_on_sbc>; +}; + +&i2c_7 { + silabs4705@11 { /* SiLabs FM chip, slave id 0x11*/ + status = "disabled"; + }; +}; + +&pcie0 { + qcom,phy-sequence = <0x404 0x01 0x00 + 0x034 0x1c 0x00 + 0x038 0x10 0x00 + 0x174 0x33 0x00 + 0x194 0x06 0x00 + 0x0c8 0x42 0x00 + 0x128 0x00 0x00 + 0x144 0xff 0x00 + 0x148 0x1f 0x00 + 0x178 0x01 0x00 + 0x19c 0x01 0x00 + 0x18c 0x00 0x00 + 0x184 0x0a 0x00 + 0x00c 0x09 0x00 + 0x0d0 0x82 0x00 + 0x0e4 0x03 0x00 + 0x0e0 0x55 0x00 + 0x0dc 0x55 0x00 + 0x054 0x00 0x00 + 0x050 0x1a 0x00 + 0x04c 0x0a 0x00 + 0x174 0x33 0x00 + 0x03c 0x02 0x00 + 0x040 0x1f 0x00 + 0x0ac 0x04 0x00 + 0x078 0x0b 0x00 + 0x084 0x16 0x00 + 0x090 0x28 0x00 + 0x10c 0x00 0x00 + 0x108 0x80 0x00 + 0x010 0x00 0x00 + 0x01c 0x31 0x00 + 0x020 0x01 0x00 + 0x014 0x02 0x00 + 0x018 0x00 0x00 + 0x024 0x2f 0x00 + 0x028 0x19 0x00 + 0x0c4 0x15 0x00 + 0x070 0x0f 0x00 + 0x048 0x0f 0x00 + 0x074 0x19 0x00 + 0x038 0x10 0x00 + 0x178 0x00 0x00 + 0x0c4 0x40 0x00 + 0x400 0x00 0x00 + 0x408 0x03 0x00>; + + qcom,port-phy-sequence = <0x1068 0x45 0x00 + 0x1094 0x06 0x00 + 0x1310 0x1c 0x00 + 0x1318 0x17 0x00 + 0x12d8 0x01 0x00 + 0x12dc 0x00 0x00 + 0x12e0 0xdb 0x00 + 0x1320 0x18 0x00 + 0x121c 0x04 0x00 + 0x1210 0x04 0x00 + 0x1458 0x4c 0x00 + 0x14a0 0x00 0x00 + 0x14a4 0x01 0x00 + 0x14a8 0x05 0x00 + 0x1248 0x4b 0x00 + 0x131c 0x14 0x00 + 0x1454 0x05 0x00 + 0x1404 0x02 0x00 + 0x146c 0x00 0x00 + 0x1460 0xa3 0x00 + 0x1318 0x19 0x00 + 0x1428 0x0e 0x00 + 0x1054 0x08 0x00 + 0x14f8 0x04 0x00 + 0x14ec 0x06 0x00 + 0x104c 0x2e 0x00 + 0x1404 0x03 0x0a + 0x1400 0x00 0x00 + 0x1408 0x0a 0x00>; + + /delete-property/qcom,l1-supported; + /delete-property/qcom,l1ss-supported; + qcom,aux-clk-sync; + qcom,boot-option = <0x0>; +}; + +&pcie1 { + qcom,phy-sequence = <0x404 0x01 0x00 + 0x034 0x1c 0x00 + 0x038 0x10 0x00 + 0x174 0x33 0x00 + 0x194 0x06 0x00 + 0x0c8 0x42 0x00 + 0x128 0x00 0x00 + 0x144 0xff 0x00 + 0x148 0x1f 0x00 + 0x178 0x01 0x00 + 0x19c 0x01 0x00 + 0x18c 0x00 0x00 + 0x184 0x0a 0x00 + 0x00c 0x09 0x00 + 0x0d0 0x82 0x00 + 0x0e4 0x03 0x00 + 0x0e0 0x55 0x00 + 0x0dc 0x55 0x00 + 0x054 0x00 0x00 + 0x050 0x1a 0x00 + 0x04c 0x0a 0x00 + 0x174 0x33 0x00 + 0x03c 0x02 0x00 + 0x040 0x1f 0x00 + 0x0ac 0x04 0x00 + 0x078 0x0b 0x00 + 0x084 0x16 0x00 + 0x090 0x28 0x00 + 0x10c 0x00 0x00 + 0x108 0x80 0x00 + 0x010 0x00 0x00 + 0x01c 0x31 0x00 + 0x020 0x01 0x00 + 0x014 0x02 0x00 + 0x018 0x00 0x00 + 0x024 0x2f 0x00 + 0x028 0x19 0x00 + 0x0c4 0x15 0x00 + 0x070 0x0f 0x00 + 0x048 0x0f 0x00 + 0x074 0x19 0x00 + 0x038 0x10 0x00 + 0x178 0x00 0x00 + 0x0c4 0x40 0x00 + 0x400 0x00 0x00 + 0x408 0x03 0x00>; + + qcom,port-phy-sequence = <0x2068 0x45 0x00 + 0x2094 0x06 0x00 + 0x2310 0x1c 0x00 + 0x2318 0x17 0x00 + 0x22d8 0x01 0x00 + 0x22dc 0x00 0x00 + 0x22e0 0xdb 0x00 + 0x2320 0x18 0x00 + 0x221c 0x04 0x00 + 0x2210 0x04 0x00 + 0x2458 0x4c 0x00 + 0x24a0 0x00 0x00 + 0x24a4 0x01 0x00 + 0x24a8 0x05 0x00 + 0x2248 0x4b 0x00 + 0x231c 0x14 0x00 + 0x2454 0x05 0x00 + 0x2404 0x02 0x00 + 0x246c 0x00 0x00 + 0x2460 0xa3 0x00 + 0x2318 0x19 0x00 + 0x2428 0x0e 0x00 + 0x2054 0x08 0x00 + 0x24f8 0x04 0x00 + 0x24ec 0x06 0x00 + 0x204c 0x2e 0x00 + 0x2404 0x03 0x0a + 0x2400 0x00 0x00 + 0x2408 0x0a 0x00>; + + /delete-property/qcom,l1-supported; + /delete-property/qcom,l1ss-supported; + /delete-property/qcom,aux-clk-sync; + qcom,boot-option = <0x0>; +}; + +&pcie2 { + qcom,boot-option = <0x0>; + perst-gpio = <&tlmm 90 0>; + wake-gpio = <&tlmm 54 0>; +}; diff --git a/arch/arm/boot/dts/qcom/msm8996-cv2x.dtsi b/arch/arm/boot/dts/qcom/msm8996-cv2x.dtsi index f5391e727396..e96ed3020679 100644 --- a/arch/arm/boot/dts/qcom/msm8996-cv2x.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996-cv2x.dtsi @@ -352,15 +352,21 @@ pinctrl-0 = <&ap2mdm_active &mdm2ap_active>; pinctrl-1 = <&ap2mdm_sleep &mdm2ap_sleep>; interrupt-map = <0 &tlmm 108 0x3 - 1 &tlmm 107 0x3 + 1 &tlmm 106 0x3 2 &tlmm 112 0x3>; qcom,mdm2ap-errfatal-gpio = <&tlmm 108 0x00>; qcom,ap2mdm-errfatal-gpio = <&tlmm 109 0x00>; qcom,mdm2ap-status-gpio = <&tlmm 106 0x00>; qcom,ap2mdm-status-gpio = <&tlmm 107 0x00>; - qcom,ap2mdm-soft-reset-gpio = <&pm8994_mpps 2 GPIO_ACTIVE_LOW>; + qcom,ap2mdm-soft-reset-gpio = <&pm8994_mpps 2 0x00>; qcom,ap2mdm-vddmin-gpio = <&tlmm 111 0x00>; qcom,mdm2ap-vddmin-gpio = <&tlmm 112 0x00>; + qcom,mdm-auto-boot; + qcom,ignore-ssr-failure; + qcom,mdm-link-info = "0302_02.01.00"; + qcom,mdm-statusline-not-a-powersource; + qcom,mdm-userspace-handle-shutdown; + qcom,pil-force-shutdown; status = "okay"; }; diff --git a/arch/arm/boot/dts/qcom/msm8996.dtsi b/arch/arm/boot/dts/qcom/msm8996.dtsi index 34d93a473645..9694490a39a2 100644 --- a/arch/arm/boot/dts/qcom/msm8996.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996.dtsi @@ -250,8 +250,8 @@ label = "cont_splash_mem"; }; - cont_splash_mem_hdmi: cont_splash_mem_hdmi@b1c00000 { - reg = <0 0xb1c00000 0 0x23ff000>; + cont_splash_mem_hdmi: cont_splash_mem_hdmi@bdd00000 { + reg = <0 0xbdd00000 0 0x23ff000>; label = "cont_splash_mem_hdmi"; }; }; @@ -2289,6 +2289,13 @@ qcom,reset-ep-after-lpm-resume; }; + usb_audio_qmi_dev { + compatible = "qcom,usb-audio-qmi-dev"; + iommus = <&lpass_q6_smmu 12>; + qcom,usb-audio-stream-id = <12>; + qcom,usb-audio-intr-num = <1>; + }; + qcom,lpass@9300000 { compatible = "qcom,pil-tz-generic"; reg = <0x9300000 0x00100>; @@ -3683,9 +3690,10 @@ compatible = "qcom,msm-pcm-hostless"; }; - qcom,msm-ssc-sensors { + ssc_sensors: qcom,msm-ssc-sensors { compatible = "qcom,msm-ssc-sensors"; status = "ok"; + qcom,firmware-name = "slpi"; }; qcom,msm-pacman { diff --git a/arch/arm/boot/dts/qcom/sdm660-mtp.dts b/arch/arm/boot/dts/qcom/sdm660-mtp.dts index 32b294ee6883..68e4491193d5 100644 --- a/arch/arm/boot/dts/qcom/sdm660-mtp.dts +++ b/arch/arm/boot/dts/qcom/sdm660-mtp.dts @@ -29,3 +29,12 @@ &tavil_snd { qcom,msm-mbhc-moist-cfg = <0>, <0>, <3>; }; + +&slim_aud { + /delete-node/tasha_codec; +}; + +&soc { + /delete-node/sound-9335; +}; + diff --git a/arch/arm/boot/dts/qcom/sdm660-qrd.dts b/arch/arm/boot/dts/qcom/sdm660-qrd.dts index 3284e805a093..4e7cc547e6cd 100644 --- a/arch/arm/boot/dts/qcom/sdm660-qrd.dts +++ b/arch/arm/boot/dts/qcom/sdm660-qrd.dts @@ -86,3 +86,12 @@ qcom,afe-power-off-delay-us = <6>; }; }; + +&slim_aud { + /delete-node/wcd934x_cdc; +}; + +&soc { + /delete-node/sound-tavil; +}; + diff --git a/arch/arm/boot/dts/qcom/vplatform-lfv-msm8996.dtsi b/arch/arm/boot/dts/qcom/vplatform-lfv-msm8996.dtsi index 08aa412f1ff4..7815399f23b1 100644 --- a/arch/arm/boot/dts/qcom/vplatform-lfv-msm8996.dtsi +++ b/arch/arm/boot/dts/qcom/vplatform-lfv-msm8996.dtsi @@ -24,11 +24,8 @@ }; psci { - compatible = "arm,psci"; + compatible = "arm,psci-1.0"; method = "smc"; - cpu_suspend = <0xc4000001>; - cpu_off = <0x84000002>; - cpu_on = <0xc4000003>; }; soc: soc { }; diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index d61f3ae80e15..3cb501b93da6 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -652,6 +652,13 @@ config HOTPLUG_CPU Say Y here to experiment with turning CPUs off and on. CPUs can be controlled through /sys/devices/system/cpu. +config ARCH_ENABLE_MEMORY_HOTPLUG + depends on !NUMA + def_bool y + +config ARCH_ENABLE_MEMORY_HOTREMOVE + def_bool y + # The GPIO number here must be sorted by descending number. In case of # a multiplatform kernel, we just want the highest value required by the # selected platforms. @@ -738,6 +745,10 @@ config ARCH_HAS_CACHE_LINE_SIZE source "mm/Kconfig" +config ARCH_MEMORY_PROBE + def_bool y + depends on MEMORY_HOTPLUG + config SECCOMP bool "Enable seccomp to safely compute untrusted bytecode" ---help--- diff --git a/arch/arm64/configs/msm-auto-gvm-perf_defconfig b/arch/arm64/configs/msm-auto-gvm-perf_defconfig index 1c4e19d9b859..70673d4959eb 100644 --- a/arch/arm64/configs/msm-auto-gvm-perf_defconfig +++ b/arch/arm64/configs/msm-auto-gvm-perf_defconfig @@ -44,6 +44,9 @@ CONFIG_ARMV8_DEPRECATED=y CONFIG_SWP_EMULATION=y CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y CONFIG_COMPAT=y +CONFIG_PM_AUTOSLEEP=y +CONFIG_PM_WAKELOCKS=y +CONFIG_PM_WAKELOCKS_LIMIT=0 CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y diff --git a/arch/arm64/configs/msm-auto-gvm_defconfig b/arch/arm64/configs/msm-auto-gvm_defconfig index 05ade778b2ae..455c7581f51f 100644 --- a/arch/arm64/configs/msm-auto-gvm_defconfig +++ b/arch/arm64/configs/msm-auto-gvm_defconfig @@ -42,6 +42,10 @@ CONFIG_ARMV8_DEPRECATED=y CONFIG_SWP_EMULATION=y CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y CONFIG_COMPAT=y +CONFIG_PM_AUTOSLEEP=y +CONFIG_PM_WAKELOCKS=y +CONFIG_PM_WAKELOCKS_LIMIT=0 +CONFIG_PM_DEBUG=y CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y diff --git a/arch/arm64/configs/msm-auto-perf_defconfig b/arch/arm64/configs/msm-auto-perf_defconfig index 554be1743f18..728bfc43bbee 100644 --- a/arch/arm64/configs/msm-auto-perf_defconfig +++ b/arch/arm64/configs/msm-auto-perf_defconfig @@ -57,6 +57,8 @@ CONFIG_SCHED_MC=y CONFIG_NR_CPUS=8 CONFIG_PREEMPT=y CONFIG_HZ_100=y +CONFIG_MEMORY_HOTPLUG=y +CONFIG_MEMORY_HOTREMOVE=y CONFIG_CMA=y CONFIG_ZSMALLOC=y CONFIG_BALANCE_ANON_FILE_RECLAIM=y @@ -320,6 +322,7 @@ CONFIG_SOUNDWIRE=y CONFIG_SPI=y CONFIG_SPI_QUP=y CONFIG_SPI_SPIDEV=y +CONFIG_SPI_SLAVE=y CONFIG_SPMI=y CONFIG_PPS_CLIENT_GPIO=y CONFIG_PINCTRL_MSM8996=y @@ -377,7 +380,7 @@ CONFIG_MSM_AIS=y CONFIG_MSM_AIS_DEBUG=y CONFIG_MSM_AIS_CAMERA_SENSOR=y # CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set -CONFIG_VIDEO_ADV7481=y +CONFIG_VIDEO_ADV7481=m CONFIG_QCOM_KGSL=y CONFIG_DRM=y CONFIG_MSM_BA_V4L2=y @@ -457,6 +460,7 @@ 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_BAM_DMA=y CONFIG_QCOM_SPS_DMA=y diff --git a/arch/arm64/configs/msm-auto_defconfig b/arch/arm64/configs/msm-auto_defconfig index 4677d30c2db8..4c54fa07aaa2 100644 --- a/arch/arm64/configs/msm-auto_defconfig +++ b/arch/arm64/configs/msm-auto_defconfig @@ -54,6 +54,8 @@ CONFIG_SCHED_MC=y CONFIG_NR_CPUS=8 CONFIG_PREEMPT=y CONFIG_HZ_100=y +CONFIG_MEMORY_HOTPLUG=y +CONFIG_MEMORY_HOTREMOVE=y CONFIG_CMA=y CONFIG_CMA_DEBUGFS=y CONFIG_ZSMALLOC=y @@ -323,6 +325,7 @@ CONFIG_SOUNDWIRE=y CONFIG_SPI=y CONFIG_SPI_QUP=y CONFIG_SPI_SPIDEV=y +CONFIG_SPI_SLAVE=y CONFIG_SPMI=y CONFIG_PPS_CLIENT_GPIO=y CONFIG_PINCTRL_MSM8996=y @@ -381,7 +384,7 @@ CONFIG_MSM_AIS=y CONFIG_MSM_AIS_DEBUG=y CONFIG_MSM_AIS_CAMERA_SENSOR=y # CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set -CONFIG_VIDEO_ADV7481=y +CONFIG_VIDEO_ADV7481=m CONFIG_QCOM_KGSL=y CONFIG_DRM=y CONFIG_MSM_BA_V4L2=y @@ -462,6 +465,7 @@ CONFIG_ESOC_DEV=y CONFIG_ESOC_CLIENT=y CONFIG_ESOC_DEBUG=y CONFIG_ESOC_MDM_4x=y +CONFIG_ESOC_MDM_DRV=y CONFIG_DMADEVICES=y CONFIG_QCOM_BAM_DMA=y CONFIG_QCOM_SPS_DMA=y diff --git a/arch/arm64/configs/msm-perf_defconfig b/arch/arm64/configs/msm-perf_defconfig index 842f495bb17e..7c043bbf0d69 100644 --- a/arch/arm64/configs/msm-perf_defconfig +++ b/arch/arm64/configs/msm-perf_defconfig @@ -413,6 +413,7 @@ CONFIG_LOGO=y CONFIG_SOUND=y CONFIG_SND=y CONFIG_SND_USB_AUDIO=y +CONFIG_SND_USB_AUDIO_QMI=y CONFIG_SND_SOC=y CONFIG_SND_SOC_MSM8996=y CONFIG_UHID=y diff --git a/arch/arm64/configs/msm_defconfig b/arch/arm64/configs/msm_defconfig index 38f8092e7d8a..7600064df6c6 100644 --- a/arch/arm64/configs/msm_defconfig +++ b/arch/arm64/configs/msm_defconfig @@ -401,6 +401,7 @@ CONFIG_LOGO=y CONFIG_SOUND=y CONFIG_SND=y CONFIG_SND_USB_AUDIO=y +CONFIG_SND_USB_AUDIO_QMI=y CONFIG_SND_SOC=y CONFIG_SND_SOC_MSM8996=y CONFIG_UHID=y diff --git a/arch/arm64/include/asm/mmu.h b/arch/arm64/include/asm/mmu.h index 990124a67eeb..7ad6b91d12c5 100644 --- a/arch/arm64/include/asm/mmu.h +++ b/arch/arm64/include/asm/mmu.h @@ -35,5 +35,12 @@ extern void create_pgd_mapping(struct mm_struct *mm, phys_addr_t phys, unsigned long virt, phys_addr_t size, pgprot_t prot); extern void *fixmap_remap_fdt(phys_addr_t dt_phys); +#ifdef CONFIG_MEMORY_HOTPLUG +extern void hotplug_paging(phys_addr_t start, phys_addr_t size); +#ifdef CONFIG_MEMORY_HOTREMOVE +extern void remove_pagetable(unsigned long start, + unsigned long end, bool direct); +#endif +#endif #endif diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h index 72b1c3fa1576..ecd7dc14330c 100644 --- a/arch/arm64/include/asm/pgtable.h +++ b/arch/arm64/include/asm/pgtable.h @@ -461,6 +461,11 @@ static inline phys_addr_t pmd_page_paddr(pmd_t pmd) return pmd_val(pmd) & PHYS_MASK & (s32)PAGE_MASK; } +static inline unsigned long pmd_page_vaddr(pmd_t pmd) +{ + return (unsigned long) __va(pmd_page_paddr(pmd)); +} + /* Find an entry in the third-level page table. */ #define pte_index(addr) (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) @@ -512,6 +517,11 @@ static inline phys_addr_t pud_page_paddr(pud_t pud) return pud_val(pud) & PHYS_MASK & (s32)PAGE_MASK; } +static inline unsigned long pud_page_vaddr(pud_t pud) +{ + return (unsigned long) __va(pud_page_paddr(pud)); +} + /* Find an entry in the second-level page table. */ #define pmd_index(addr) (((addr) >> PMD_SHIFT) & (PTRS_PER_PMD - 1)) @@ -564,6 +574,11 @@ static inline phys_addr_t pgd_page_paddr(pgd_t pgd) return pgd_val(pgd) & PHYS_MASK & (s32)PAGE_MASK; } +static inline unsigned long pgd_page_vaddr(pgd_t pgd) +{ + return (unsigned long) __va(pgd_page_paddr(pgd)); +} + /* Find an entry in the frst-level page table. */ #define pud_index(addr) (((addr) >> PUD_SHIFT) & (PTRS_PER_PUD - 1)) diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c index b4ef9ea679a1..7fd74d55c68e 100644 --- a/arch/arm64/mm/init.c +++ b/arch/arm64/mm/init.c @@ -152,6 +152,7 @@ static void __init arm64_memory_present(void) #endif static phys_addr_t memory_limit = (phys_addr_t)ULLONG_MAX; +static phys_addr_t bootloader_memory_limit; /* * Limit the memory size that was specified via FDT. @@ -205,6 +206,11 @@ void __init arm64_memblock_init(void) * via the linear mapping. */ if (memory_limit != (phys_addr_t)ULLONG_MAX) { + /* + * Save bootloader imposed memory limit before we overwirte + * memblock. + */ + bootloader_memory_limit = memblock_end_of_DRAM(); memblock_enforce_memory_limit(memory_limit); memblock_add(__pa(_text), (u64)(_end - _text)); } @@ -495,3 +501,137 @@ static int __init register_mem_limit_dumper(void) return 0; } __initcall(register_mem_limit_dumper); + +#ifdef CONFIG_MEMORY_HOTPLUG +int arch_add_memory(int nid, u64 start, u64 size, bool for_device) +{ + pg_data_t *pgdat; + struct zone *zone; + unsigned long start_pfn = start >> PAGE_SHIFT; + unsigned long nr_pages = size >> PAGE_SHIFT; + unsigned long end_pfn = start_pfn + nr_pages; + unsigned long max_sparsemem_pfn = 1UL << (MAX_PHYSMEM_BITS-PAGE_SHIFT); + int ret; + + if (end_pfn > max_sparsemem_pfn) { + pr_err("end_pfn too big"); + return -1; + } + hotplug_paging(start, size); + + /* + * Mark the first page in the range as unusable. This is needed + * because __add_section (within __add_pages) wants pfn_valid + * of it to be false, and in arm64 pfn falid is implemented by + * just checking at the nomap flag for existing blocks. + * + * A small trick here is that __add_section() requires only + * phys_start_pfn (that is the first pfn of a section) to be + * invalid. Regardless of whether it was assumed (by the function + * author) that all pfns within a section are either all valid + * or all invalid, it allows to avoid looping twice (once here, + * second when memblock_clear_nomap() is called) through all + * pfns of the section and modify only one pfn. Thanks to that, + * further, in __add_zone() only this very first pfn is skipped + * and corresponding page is not flagged reserved. Therefore it + * is enough to correct this setup only for it. + * + * When arch_add_memory() returns the walk_memory_range() function + * is called and passed with online_memory_block() callback, + * which execution finally reaches the memory_block_action() + * function, where also only the first pfn of a memory block is + * checked to be reserved. Above, it was first pfn of a section, + * here it is a block but + * (drivers/base/memory.c): + * sections_per_block = block_sz / MIN_MEMORY_BLOCK_SIZE; + * (include/linux/memory.h): + * #define MIN_MEMORY_BLOCK_SIZE (1UL << SECTION_SIZE_BITS) + * so we can consider block and section equivalently + */ + memblock_mark_nomap(start, 1<<PAGE_SHIFT); + + pgdat = NODE_DATA(nid); + + zone = pgdat->node_zones + + zone_for_memory(nid, start, size, ZONE_NORMAL, for_device); + ret = __add_pages(nid, zone, start_pfn, nr_pages); + + /* + * Make the pages usable after they have been added. + * This will make pfn_valid return true + */ + memblock_clear_nomap(start, 1<<PAGE_SHIFT); + + /* + * This is a hack to avoid having to mix arch specific code + * into arch independent code. SetPageReserved is supposed + * to be called by __add_zone (within __add_section, within + * __add_pages). However, when it is called there, it assumes that + * pfn_valid returns true. For the way pfn_valid is implemented + * in arm64 (a check on the nomap flag), the only way to make + * this evaluate true inside __add_zone is to clear the nomap + * flags of blocks in architecture independent code. + * + * To avoid this, we set the Reserved flag here after we cleared + * the nomap flag in the line above. + */ + SetPageReserved(pfn_to_page(start_pfn)); + + if (ret) + pr_warn("%s: Problem encountered in __add_pages() ret=%d\n", + __func__, ret); + + return ret; +} + +#ifdef CONFIG_MEMORY_HOTREMOVE +static void kernel_physical_mapping_remove(unsigned long start, + unsigned long end) +{ + start = (unsigned long)__va(start); + end = (unsigned long)__va(end); + + remove_pagetable(start, end, true); + +} + +int arch_remove_memory(u64 start, u64 size) +{ + unsigned long start_pfn = start >> PAGE_SHIFT; + unsigned long nr_pages = size >> PAGE_SHIFT; + struct page *page = pfn_to_page(start_pfn); + struct zone *zone; + int ret = 0; + + zone = page_zone(page); + ret = __remove_pages(zone, start_pfn, nr_pages); + WARN_ON_ONCE(ret); + + kernel_physical_mapping_remove(start, start + size); + + return ret; +} + +#endif /* CONFIG_MEMORY_HOTREMOVE */ +static int arm64_online_page(struct page *page) +{ + unsigned long target_pfn = page_to_pfn(page); + unsigned long limit = __phys_to_pfn(bootloader_memory_limit); + + if (target_pfn >= limit) + return -EINVAL; + + __online_page_set_limits(page); + __online_page_increment_counters(page); + __online_page_free(page); + + return 0; +} + +static int __init arm64_memory_hotplug_init(void) +{ + set_online_page_callback(&arm64_online_page); + return 0; +} +subsys_initcall(arm64_memory_hotplug_init); +#endif /* CONFIG_MEMORY_HOTPLUG */ diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c index 6c444d968323..8c063d39bc17 100644 --- a/arch/arm64/mm/mmu.c +++ b/arch/arm64/mm/mmu.c @@ -605,6 +605,423 @@ void __init paging_init(void) bootmem_init(); } +#ifdef CONFIG_MEMORY_HOTPLUG +static phys_addr_t pgd_pgtable_alloc(void) +{ + void *ptr = (void *)__get_free_page(PGALLOC_GFP); + if (!ptr || !pgtable_page_ctor(virt_to_page(ptr))) + BUG(); + + /* Ensure the zeroed page is visible to the page table walker */ + dsb(ishst); + return __pa(ptr); +} + +/* + * hotplug_paging() is used by memory hotplug to build new page tables + * for hot added memory. + */ +void hotplug_paging(phys_addr_t start, phys_addr_t size) +{ + + struct page *pg; + phys_addr_t pgd_phys = pgd_pgtable_alloc(); + pgd_t *pgd = pgd_set_fixmap(pgd_phys); + + memcpy(pgd, swapper_pg_dir, PAGE_SIZE); + + __create_pgd_mapping(pgd, start, __phys_to_virt(start), size, + PAGE_KERNEL, pgd_pgtable_alloc); + + cpu_replace_ttbr1(__va(pgd_phys)); + memcpy(swapper_pg_dir, pgd, PAGE_SIZE); + cpu_replace_ttbr1(swapper_pg_dir); + + pgd_clear_fixmap(); + + pg = phys_to_page(pgd_phys); + pgtable_page_dtor(pg); + __free_pages(pg, 0); +} + +#ifdef CONFIG_MEMORY_HOTREMOVE +#define PAGE_INUSE 0xFD + +static void free_pagetable(struct page *page, int order, bool direct) +{ + unsigned long magic; + unsigned int nr_pages = 1 << order; + + /* bootmem page has reserved flag */ + if (PageReserved(page)) { + __ClearPageReserved(page); + + magic = (unsigned long)page->lru.next; + if (magic == SECTION_INFO || magic == MIX_SECTION_INFO) { + while (nr_pages--) + put_page_bootmem(page++); + } else { + while (nr_pages--) + free_reserved_page(page++); + } + } else { + /* + * Only direct pagetable allocation (those allocated via + * hotplug) call the pgtable_page_ctor; vmemmap pgtable + * allocations don't. + */ + if (direct) + pgtable_page_dtor(page); + + free_pages((unsigned long)page_address(page), order); + } +} + +static void free_pte_table(pmd_t *pmd, bool direct) +{ + pte_t *pte_start, *pte; + struct page *page; + int i; + + pte_start = (pte_t *) pmd_page_vaddr(*pmd); + /* Check if there is no valid entry in the PMD */ + for (i = 0; i < PTRS_PER_PTE; i++) { + pte = pte_start + i; + if (!pte_none(*pte)) + return; + } + + page = pmd_page(*pmd); + + free_pagetable(page, 0, direct); + + /* + * This spin lock could be only taken in _pte_aloc_kernel + * in mm/memory.c and nowhere else (for arm64). Not sure if + * the function above can be called concurrently. In doubt, + * I am living it here for now, but it probably can be removed + */ + spin_lock(&init_mm.page_table_lock); + pmd_clear(pmd); + spin_unlock(&init_mm.page_table_lock); +} + +static void free_pmd_table(pud_t *pud, bool direct) +{ + pmd_t *pmd_start, *pmd; + struct page *page; + int i; + + pmd_start = (pmd_t *) pud_page_vaddr(*pud); + /* Check if there is no valid entry in the PMD */ + for (i = 0; i < PTRS_PER_PMD; i++) { + pmd = pmd_start + i; + if (!pmd_none(*pmd)) + return; + } + + page = pud_page(*pud); + + free_pagetable(page, 0, direct); + + /* + * This spin lock could be only taken in _pte_aloc_kernel + * in mm/memory.c and nowhere else (for arm64). Not sure if + * the function above can be called concurrently. In doubt, + * I am living it here for now, but it probably can be removed + */ + spin_lock(&init_mm.page_table_lock); + pud_clear(pud); + spin_unlock(&init_mm.page_table_lock); +} + +/* + * When the PUD is folded on the PGD (three levels of paging), + * there's no need to free PUDs + */ +#if CONFIG_PGTABLE_LEVELS > 3 +static void free_pud_table(pgd_t *pgd, bool direct) +{ + pud_t *pud_start, *pud; + struct page *page; + int i; + + pud_start = (pud_t *) pgd_page_vaddr(*pgd); + /* Check if there is no valid entry in the PUD */ + for (i = 0; i < PTRS_PER_PUD; i++) { + pud = pud_start + i; + if (!pud_none(*pud)) + return; + } + + page = pgd_page(*pgd); + + free_pagetable(page, 0, direct); + + /* + * This spin lock could be only + * taken in _pte_aloc_kernel in + * mm/memory.c and nowhere else + * (for arm64). Not sure if the + * function above can be called + * concurrently. In doubt, + * I am living it here for now, + * but it probably can be removed. + */ + spin_lock(&init_mm.page_table_lock); + pgd_clear(pgd); + spin_unlock(&init_mm.page_table_lock); +} +#endif + +static void remove_pte_table(pte_t *pte, unsigned long addr, + unsigned long end, bool direct) +{ + unsigned long next; + void *page_addr; + + for (; addr < end; addr = next, pte++) { + next = (addr + PAGE_SIZE) & PAGE_MASK; + if (next > end) + next = end; + + if (!pte_present(*pte)) + continue; + + if (PAGE_ALIGNED(addr) && PAGE_ALIGNED(next)) { + /* + * Do not free direct mapping pages since they were + * freed when offlining, or simplely not in use. + */ + if (!direct) + free_pagetable(pte_page(*pte), 0, direct); + + /* + * This spin lock could be only + * taken in _pte_aloc_kernel in + * mm/memory.c and nowhere else + * (for arm64). Not sure if the + * function above can be called + * concurrently. In doubt, + * I am living it here for now, + * but it probably can be removed. + */ + spin_lock(&init_mm.page_table_lock); + pte_clear(&init_mm, addr, pte); + spin_unlock(&init_mm.page_table_lock); + } else { + /* + * If we are here, we are freeing vmemmap pages since + * direct mapped memory ranges to be freed are aligned. + * + * If we are not removing the whole page, it means + * other page structs in this page are being used and + * we canot remove them. So fill the unused page_structs + * with 0xFD, and remove the page when it is wholly + * filled with 0xFD. + */ + memset((void *)addr, PAGE_INUSE, next - addr); + + page_addr = page_address(pte_page(*pte)); + if (!memchr_inv(page_addr, PAGE_INUSE, PAGE_SIZE)) { + free_pagetable(pte_page(*pte), 0, direct); + + /* + * This spin lock could be only + * taken in _pte_aloc_kernel in + * mm/memory.c and nowhere else + * (for arm64). Not sure if the + * function above can be called + * concurrently. In doubt, + * I am living it here for now, + * but it probably can be removed. + */ + spin_lock(&init_mm.page_table_lock); + pte_clear(&init_mm, addr, pte); + spin_unlock(&init_mm.page_table_lock); + } + } + } + + // I am adding this flush here in simmetry to the x86 code. + // Why do I need to call it here and not in remove_p[mu]d + flush_tlb_all(); +} + +static void remove_pmd_table(pmd_t *pmd, unsigned long addr, + unsigned long end, bool direct) +{ + unsigned long next; + void *page_addr; + pte_t *pte; + + for (; addr < end; addr = next, pmd++) { + next = pmd_addr_end(addr, end); + + if (!pmd_present(*pmd)) + continue; + + // check if we are using 2MB section mappings + if (pmd_sect(*pmd)) { + if (PAGE_ALIGNED(addr) && PAGE_ALIGNED(next)) { + if (!direct) { + free_pagetable(pmd_page(*pmd), + get_order(PMD_SIZE), direct); + } + /* + * This spin lock could be only + * taken in _pte_aloc_kernel in + * mm/memory.c and nowhere else + * (for arm64). Not sure if the + * function above can be called + * concurrently. In doubt, + * I am living it here for now, + * but it probably can be removed. + */ + spin_lock(&init_mm.page_table_lock); + pmd_clear(pmd); + spin_unlock(&init_mm.page_table_lock); + } else { + /* If here, we are freeing vmemmap pages. */ + memset((void *)addr, PAGE_INUSE, next - addr); + + page_addr = page_address(pmd_page(*pmd)); + if (!memchr_inv(page_addr, PAGE_INUSE, + PMD_SIZE)) { + free_pagetable(pmd_page(*pmd), + get_order(PMD_SIZE), direct); + + /* + * This spin lock could be only + * taken in _pte_aloc_kernel in + * mm/memory.c and nowhere else + * (for arm64). Not sure if the + * function above can be called + * concurrently. In doubt, + * I am living it here for now, + * but it probably can be removed. + */ + spin_lock(&init_mm.page_table_lock); + pmd_clear(pmd); + spin_unlock(&init_mm.page_table_lock); + } + } + continue; + } + + BUG_ON(!pmd_table(*pmd)); + + pte = pte_offset_map(pmd, addr); + remove_pte_table(pte, addr, next, direct); + free_pte_table(pmd, direct); + } +} + +static void remove_pud_table(pud_t *pud, unsigned long addr, + unsigned long end, bool direct) +{ + unsigned long next; + pmd_t *pmd; + void *page_addr; + + for (; addr < end; addr = next, pud++) { + next = pud_addr_end(addr, end); + if (!pud_present(*pud)) + continue; + /* + * If we are using 4K granules, check if we are using + * 1GB section mapping. + */ + if (pud_sect(*pud)) { + if (PAGE_ALIGNED(addr) && PAGE_ALIGNED(next)) { + if (!direct) { + free_pagetable(pud_page(*pud), + get_order(PUD_SIZE), direct); + } + + /* + * This spin lock could be only + * taken in _pte_aloc_kernel in + * mm/memory.c and nowhere else + * (for arm64). Not sure if the + * function above can be called + * concurrently. In doubt, + * I am living it here for now, + * but it probably can be removed. + */ + spin_lock(&init_mm.page_table_lock); + pud_clear(pud); + spin_unlock(&init_mm.page_table_lock); + } else { + /* If here, we are freeing vmemmap pages. */ + memset((void *)addr, PAGE_INUSE, next - addr); + + page_addr = page_address(pud_page(*pud)); + if (!memchr_inv(page_addr, PAGE_INUSE, + PUD_SIZE)) { + + free_pagetable(pud_page(*pud), + get_order(PUD_SIZE), direct); + + /* + * This spin lock could be only + * taken in _pte_aloc_kernel in + * mm/memory.c and nowhere else + * (for arm64). Not sure if the + * function above can be called + * concurrently. In doubt, + * I am living it here for now, + * but it probably can be removed. + */ + spin_lock(&init_mm.page_table_lock); + pud_clear(pud); + spin_unlock(&init_mm.page_table_lock); + } + } + continue; + } + + BUG_ON(!pud_table(*pud)); + + pmd = pmd_offset(pud, addr); + remove_pmd_table(pmd, addr, next, direct); + free_pmd_table(pud, direct); + } +} + +void remove_pagetable(unsigned long start, unsigned long end, bool direct) +{ + unsigned long next; + unsigned long addr; + pgd_t *pgd; + pud_t *pud; + + for (addr = start; addr < end; addr = next) { + next = pgd_addr_end(addr, end); + + pgd = pgd_offset_k(addr); + if (pgd_none(*pgd)) + continue; + + pud = pud_offset(pgd, addr); + remove_pud_table(pud, addr, next, direct); + /* + * When the PUD is folded on the PGD (three levels of paging), + * I did already clear the PMD page in free_pmd_table, + * and reset the corresponding PGD==PUD entry. + */ +#if CONFIG_PGTABLE_LEVELS > 3 + free_pud_table(pgd, direct); +#endif + } + + flush_tlb_all(); +} + + +#endif /* CONFIG_MEMORY_HOTREMOVE */ +#endif /* CONFIG_MEMORY_HOTPLUG */ + /* * Check whether a kernel address is valid (derived from arch/x86/). */ @@ -656,6 +1073,7 @@ int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node) pgd_t *pgd; pud_t *pud; pmd_t *pmd; + int ret = 0; do { next = pmd_addr_end(addr, end); @@ -673,19 +1091,30 @@ int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node) void *p = NULL; p = vmemmap_alloc_block_buf(PMD_SIZE, node); - if (!p) - return -ENOMEM; + if (!p) { +#ifdef CONFIG_MEMORY_HOTPLUG + vmemmap_free(start, end); +#endif + ret = -ENOMEM; + break; + } set_pmd(pmd, __pmd(__pa(p) | PROT_SECT_NORMAL)); } else vmemmap_verify((pte_t *)pmd, node, addr, next); } while (addr = next, addr != end); - return 0; + if (ret) + return vmemmap_populate_basepages(start, end, node); + else + return ret; } #endif /* CONFIG_ARM64_64K_PAGES */ void vmemmap_free(unsigned long start, unsigned long end) { +#ifdef CONFIG_MEMORY_HOTREMOVE + remove_pagetable(start, end, false); +#endif } #endif /* CONFIG_SPARSEMEM_VMEMMAP */ diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 9e31197f4b6d..2c33b1251afb 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -466,9 +466,8 @@ struct binder_ref { }; enum binder_deferred_state { - BINDER_DEFERRED_PUT_FILES = 0x01, - BINDER_DEFERRED_FLUSH = 0x02, - BINDER_DEFERRED_RELEASE = 0x04, + BINDER_DEFERRED_FLUSH = 0x01, + BINDER_DEFERRED_RELEASE = 0x02, }; /** @@ -505,8 +504,6 @@ struct binder_priority { * (invariant after initialized) * @tsk task_struct for group_leader of process * (invariant after initialized) - * @files files_struct for process - * (invariant after initialized) * @deferred_work_node: element for binder_deferred_list * (protected by binder_deferred_lock) * @deferred_work: bitmap of deferred work to perform @@ -553,7 +550,6 @@ struct binder_proc { struct list_head waiting_threads; int pid; struct task_struct *tsk; - struct files_struct *files; struct hlist_node deferred_work_node; int deferred_work; bool is_dead; @@ -949,22 +945,34 @@ static void binder_free_thread(struct binder_thread *thread); static void binder_free_proc(struct binder_proc *proc); static void binder_inc_node_tmpref_ilocked(struct binder_node *node); +struct files_struct *binder_get_files_struct(struct binder_proc *proc) +{ + return get_files_struct(proc->tsk); +} + static int task_get_unused_fd_flags(struct binder_proc *proc, int flags) { - struct files_struct *files = proc->files; + struct files_struct *files; unsigned long rlim_cur; unsigned long irqs; + int ret; + files = binder_get_files_struct(proc); if (files == NULL) return -ESRCH; - if (!lock_task_sighand(proc->tsk, &irqs)) - return -EMFILE; + if (!lock_task_sighand(proc->tsk, &irqs)) { + ret = -EMFILE; + goto err; + } rlim_cur = task_rlimit(proc->tsk, RLIMIT_NOFILE); unlock_task_sighand(proc->tsk, &irqs); - return __alloc_fd(files, 0, rlim_cur, flags); + ret = __alloc_fd(files, 0, rlim_cur, flags); +err: + put_files_struct(files); + return ret; } /* @@ -973,8 +981,12 @@ static int task_get_unused_fd_flags(struct binder_proc *proc, int flags) static void task_fd_install( struct binder_proc *proc, unsigned int fd, struct file *file) { - if (proc->files) - __fd_install(proc->files, fd, file); + struct files_struct *files = binder_get_files_struct(proc); + + if (files) { + __fd_install(files, fd, file); + put_files_struct(files); + } } /* @@ -982,18 +994,20 @@ static void task_fd_install( */ static long task_close_fd(struct binder_proc *proc, unsigned int fd) { + struct files_struct *files = binder_get_files_struct(proc); int retval; - if (proc->files == NULL) + if (files == NULL) return -ESRCH; - retval = __close_fd(proc->files, fd); + retval = __close_fd(files, fd); /* can't restart close syscall because file table entry was cleared */ if (unlikely(retval == -ERESTARTSYS || retval == -ERESTARTNOINTR || retval == -ERESTARTNOHAND || retval == -ERESTART_RESTARTBLOCK)) retval = -EINTR; + put_files_struct(files); return retval; } @@ -4811,7 +4825,6 @@ static void binder_vma_close(struct vm_area_struct *vma) (vma->vm_end - vma->vm_start) / SZ_1K, vma->vm_flags, (unsigned long)pgprot_val(vma->vm_page_prot)); binder_alloc_vma_close(&proc->alloc); - binder_defer_work(proc, BINDER_DEFERRED_PUT_FILES); } static int binder_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) @@ -4853,10 +4866,8 @@ static int binder_mmap(struct file *filp, struct vm_area_struct *vma) vma->vm_private_data = proc; ret = binder_alloc_mmap_handler(&proc->alloc, vma); - if (ret) - return ret; - proc->files = get_files_struct(current); - return 0; + + return ret; err_bad_arg: pr_err("binder_mmap: %d %lx-%lx %s failed %d\n", @@ -5035,8 +5046,6 @@ static void binder_deferred_release(struct binder_proc *proc) struct rb_node *n; int threads, nodes, incoming_refs, outgoing_refs, active_transactions; - BUG_ON(proc->files); - mutex_lock(&binder_procs_lock); hlist_del(&proc->proc_node); mutex_unlock(&binder_procs_lock); @@ -5118,8 +5127,6 @@ static void binder_deferred_release(struct binder_proc *proc) static void binder_deferred_func(struct work_struct *work) { struct binder_proc *proc; - struct files_struct *files; - int defer; do { @@ -5136,21 +5143,11 @@ static void binder_deferred_func(struct work_struct *work) } mutex_unlock(&binder_deferred_lock); - files = NULL; - if (defer & BINDER_DEFERRED_PUT_FILES) { - files = proc->files; - if (files) - proc->files = NULL; - } - if (defer & BINDER_DEFERRED_FLUSH) binder_deferred_flush(proc); if (defer & BINDER_DEFERRED_RELEASE) binder_deferred_release(proc); /* frees proc */ - - if (files) - put_files_struct(files); } while (proc); } static DECLARE_WORK(binder_deferred_work, binder_deferred_func); diff --git a/drivers/base/memory.c b/drivers/base/memory.c index 48c0a1d0dd3a..861c36f8ec22 100644 --- a/drivers/base/memory.c +++ b/drivers/base/memory.c @@ -476,7 +476,36 @@ out: } static DEVICE_ATTR(probe, S_IWUSR, NULL, memory_probe_store); -#endif + +#ifdef CONFIG_MEMORY_HOTREMOVE +static ssize_t +memory_remove_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + u64 phys_addr; + int nid, ret; + unsigned long pages_per_block = PAGES_PER_SECTION * sections_per_block; + + ret = kstrtoull(buf, 0, &phys_addr); + if (ret) + return ret; + + if (phys_addr & ((pages_per_block << PAGE_SHIFT) - 1)) + return -EINVAL; + + nid = memory_add_physaddr_to_nid(phys_addr); + ret = lock_device_hotplug_sysfs(); + if (ret) + return ret; + + remove_memory(nid, phys_addr, + MIN_MEMORY_BLOCK_SIZE * sections_per_block); + unlock_device_hotplug(); + return count; +} +static DEVICE_ATTR(remove, S_IWUSR, NULL, memory_remove_store); +#endif /* CONFIG_MEMORY_HOTREMOVE */ +#endif /* CONFIG_ARCH_MEMORY_PROBE */ #ifdef CONFIG_MEMORY_FAILURE /* @@ -728,6 +757,9 @@ bool is_memblock_offlined(struct memory_block *mem) static struct attribute *memory_root_attrs[] = { #ifdef CONFIG_ARCH_MEMORY_PROBE &dev_attr_probe.attr, +#ifdef CONFIG_MEMORY_HOTREMOVE + &dev_attr_remove.attr, +#endif #endif #ifdef CONFIG_MEMORY_FAILURE diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c index 5df8e1234505..071c94457d34 100644 --- a/drivers/bluetooth/ath3k.c +++ b/drivers/bluetooth/ath3k.c @@ -209,13 +209,27 @@ static int ath3k_load_firmware(struct usb_device *udev, { u8 *send_buf; int err, pipe, len, size, sent = 0; - int count = firmware->size; + int count; BT_DBG("udev %p", udev); + if (!firmware || !firmware->data || firmware->size <= 0) { + err = -EINVAL; + BT_ERR("Not a valid FW file"); + return err; + } + + count = firmware->size; + + if (count < FW_HDR_SIZE) { + err = -EINVAL; + BT_ERR("ath3k loading invalid size of file"); + return err; + } + pipe = usb_sndctrlpipe(udev, 0); - send_buf = kmalloc(BULK_SIZE, GFP_KERNEL); + send_buf = kzalloc(BULK_SIZE, GFP_KERNEL); if (!send_buf) { BT_ERR("Can't allocate memory chunk for firmware"); return -ENOMEM; diff --git a/drivers/bluetooth/btqca.c b/drivers/bluetooth/btqca.c index 4a6208168850..0db4a00e7641 100644 --- a/drivers/bluetooth/btqca.c +++ b/drivers/bluetooth/btqca.c @@ -27,6 +27,9 @@ #define VERSION "0.1" +#define MAX_PATCH_FILE_SIZE (100*1024) +#define MAX_NVM_FILE_SIZE (10*1024) + static int rome_patch_ver_req(struct hci_dev *hdev, u32 *rome_version) { struct sk_buff *skb; @@ -285,27 +288,59 @@ static int rome_download_firmware(struct hci_dev *hdev, struct rome_config *config) { const struct firmware *fw; + u32 type_len, length; + struct tlv_type_hdr *tlv; int ret; - BT_INFO("%s: ROME Downloading %s", hdev->name, config->fwname); - + BT_INFO("%s: ROME Downloading file: %s", hdev->name, config->fwname); ret = request_firmware(&fw, config->fwname, &hdev->dev); - if (ret) { - BT_ERR("%s: Failed to request file: %s (%d)", hdev->name, - config->fwname, ret); + + if (ret || !fw || !fw->data || fw->size <= 0) { + BT_ERR("Failed to request file: err = (%d)", ret); + ret = ret ? ret : -EINVAL; return ret; } + if (config->type == TLV_TYPE_PATCH && + (fw->size > MAX_PATCH_FILE_SIZE)) { + ret = -EINVAL; + BT_ERR("TLV_PATCH dload: wrong patch file sizes"); + goto exit; + } else if (config->type == TLV_TYPE_NVM && + (fw->size > MAX_NVM_FILE_SIZE)) { + ret = -EINVAL; + BT_ERR("TLV_NVM dload: wrong NVM file sizes"); + goto exit; + } else { + ret = -EINVAL; + BT_ERR("TLV_NVM dload: wrong config type selected"); + goto exit; + } - rome_tlv_check_data(config, fw); + if (fw->size < sizeof(struct tlv_type_hdr)) { + ret = -EINVAL; + BT_ERR("Firware size smaller to fit minimum value"); + goto exit; + } + tlv = (struct tlv_type_hdr *)fw->data; + type_len = le32_to_cpu(tlv->type_len); + length = (type_len >> 8) & 0x00ffffff; + + if (fw->size - 4 != length) { + ret = -EINVAL; + BT_ERR("Requested size not matching size in header"); + goto exit; + } + + rome_tlv_check_data(config, fw); ret = rome_tlv_download_request(hdev, fw); + if (ret) { - BT_ERR("%s: Failed to download file: %s (%d)", hdev->name, - config->fwname, ret); + BT_ERR("Failed to download FW: error = (%d)", ret); } +exit: release_firmware(fw); - return ret; } @@ -316,8 +351,9 @@ int qca_set_bdaddr_rome(struct hci_dev *hdev, const bdaddr_t *bdaddr) int err; cmd[0] = EDL_NVM_ACCESS_SET_REQ_CMD; - cmd[1] = 0x02; /* TAG ID */ - cmd[2] = sizeof(bdaddr_t); /* size */ + /* Set the TAG ID of 0x02 for NVM set and size of tag */ + cmd[1] = 0x02; + cmd[2] = sizeof(bdaddr_t); memcpy(cmd + 3, bdaddr, sizeof(bdaddr_t)); skb = __hci_cmd_sync_ev(hdev, EDL_NVM_ACCESS_OPCODE, sizeof(cmd), cmd, HCI_VENDOR_PKT, HCI_INIT_TIMEOUT); diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c index 77c8f279b4f5..10753f2765f5 100644 --- a/drivers/char/adsprpc.c +++ b/drivers/char/adsprpc.c @@ -56,7 +56,7 @@ #define ADSP_MMAP_HEAP_ADDR 4 #define ADSP_MMAP_REMOTE_HEAP_ADDR 8 #define FASTRPC_ENOSUCH 39 -#define VMID_SSC_Q6 5 +#define VMID_SSC_Q6 38 #define VMID_ADSP_Q6 6 #define AC_VM_ADSP_HEAP_SHARED 33 #define DEBUGFS_SIZE 1024 diff --git a/drivers/clk/msm/mdss/mdss-dp-pll-8998-util.c b/drivers/clk/msm/mdss/mdss-dp-pll-8998-util.c index 0bd7e6413a6b..2d40fdeabcae 100644 --- a/drivers/clk/msm/mdss/mdss-dp-pll-8998-util.c +++ b/drivers/clk/msm/mdss/mdss-dp-pll-8998-util.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 @@ -128,10 +128,10 @@ int vco_divided_clk_set_div(struct div_clk *clk, int div) auxclk_div = MDSS_PLL_REG_R(dp_res->phy_base, DP_PHY_VCO_DIV); auxclk_div &= ~0x03; /* bits 0 to 1 */ - auxclk_div |= 1; /* Default divider */ - if (div == 4) auxclk_div |= 2; + else + auxclk_div |= 1; /* Default divider */ MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_VCO_DIV, auxclk_div); diff --git a/drivers/esoc/esoc-mdm-4x.c b/drivers/esoc/esoc-mdm-4x.c index 6eab3ea187c6..b24457d575c8 100644 --- a/drivers/esoc/esoc-mdm-4x.c +++ b/drivers/esoc/esoc-mdm-4x.c @@ -1088,6 +1088,13 @@ static int mdm9x55_setup_hw(struct mdm_ctrl *mdm, esoc->parent = mdm->dev; esoc->owner = THIS_MODULE; esoc->np = pdev->dev.of_node; + + esoc->auto_boot = of_property_read_bool(esoc->np, + "qcom,mdm-auto-boot"); + esoc->statusline_not_a_powersource = of_property_read_bool(esoc->np, + "qcom,mdm-statusline-not-a-powersource"); + esoc->userspace_handle_shutdown = of_property_read_bool(esoc->np, + "qcom,mdm-userspace-handle-shutdown"); set_esoc_clink_data(esoc, mdm); ret = esoc_clink_register(esoc); if (ret) { @@ -1103,6 +1110,8 @@ static int mdm9x55_setup_hw(struct mdm_ctrl *mdm, mdm->debug_fail = false; mdm->esoc = esoc; mdm->init = 0; + if (esoc->auto_boot) + gpio_direction_output(MDM_GPIO(mdm, AP2MDM_STATUS), 1); return 0; } diff --git a/drivers/esoc/esoc-mdm-pon.c b/drivers/esoc/esoc-mdm-pon.c index 4ae3b7520f77..4d8ff4968038 100644 --- a/drivers/esoc/esoc-mdm-pon.c +++ b/drivers/esoc/esoc-mdm-pon.c @@ -141,13 +141,17 @@ static int mdm4x_power_down(struct mdm_ctrl *mdm) static int mdm9x55_power_down(struct mdm_ctrl *mdm) { struct device *dev = mdm->dev; - int soft_reset_direction = mdm->soft_reset_inverted ? 1 : 0; + int soft_reset_direction_assert = 0, + soft_reset_direction_de_assert = 1; + + if (mdm->soft_reset_inverted) { + soft_reset_direction_assert = 1; + soft_reset_direction_de_assert = 0; + } /* Assert the soft reset line whether mdm2ap_status went low or not */ gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET), - soft_reset_direction); + soft_reset_direction_assert); dev_dbg(dev, "Doing a hard reset\n"); - gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET), - soft_reset_direction); /* * Currently, there is a debounce timer on the charm PMIC. It is * necessary to hold the PMIC RESET low for 406ms @@ -155,6 +159,8 @@ static int mdm9x55_power_down(struct mdm_ctrl *mdm) * reset has occurred before the function exits. */ msleep(406); + gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET), + soft_reset_direction_de_assert); return 0; } diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c index 0f77e35ef287..f70a0ea022d8 100644 --- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c +++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c @@ -1342,7 +1342,56 @@ fail: return ret; } -static void _sde_hdmi_hdp_disable(struct sde_hdmi *sde_hdmi) +int sde_hdmi_core_enable(struct sde_hdmi *sde_hdmi) +{ + struct hdmi *hdmi = sde_hdmi->ctrl.ctrl; + const struct hdmi_platform_config *config = hdmi->config; + struct device *dev = &hdmi->pdev->dev; + int i, ret; + struct drm_connector *connector; + struct msm_drm_private *priv; + struct sde_kms *sde_kms; + + connector = hdmi->connector; + priv = connector->dev->dev_private; + sde_kms = to_sde_kms(priv->kms); + + for (i = 0; i < config->hpd_reg_cnt; i++) { + ret = regulator_enable(hdmi->hpd_regs[i]); + if (ret) { + SDE_ERROR("failed to enable hpd regulator: %s (%d)\n", + config->hpd_reg_names[i], ret); + } + } + + ret = pinctrl_pm_select_default_state(dev); + if (ret) + SDE_ERROR("pinctrl state chg failed: %d\n", ret); + + ret = _sde_hdmi_gpio_config(hdmi, true); + if (ret) + SDE_ERROR("failed to configure GPIOs: %d\n", ret); + + for (i = 0; i < config->hpd_clk_cnt; i++) { + if (config->hpd_freq && config->hpd_freq[i]) { + ret = clk_set_rate(hdmi->hpd_clks[i], + config->hpd_freq[i]); + if (ret) + pr_warn("failed to set clk %s (%d)\n", + config->hpd_clk_names[i], ret); + } + + ret = clk_prepare_enable(hdmi->hpd_clks[i]); + if (ret) { + SDE_ERROR("failed to enable hpd clk: %s (%d)\n", + config->hpd_clk_names[i], ret); + } + } + + return ret; +} + +static void _sde_hdmi_hpd_disable(struct sde_hdmi *sde_hdmi) { struct hdmi *hdmi = sde_hdmi->ctrl.ctrl; const struct hdmi_platform_config *config = hdmi->config; @@ -1373,6 +1422,12 @@ static void _sde_hdmi_hdp_disable(struct sde_hdmi *sde_hdmi) } } +void sde_hdmi_core_disable(struct sde_hdmi *sde_hdmi) +{ + /* HPD contains all the core clock and pwr */ + _sde_hdmi_hpd_disable(sde_hdmi); +} + static void _sde_hdmi_cec_update_phys_addr(struct sde_hdmi *display) { struct edid *edid = display->edid_ctrl->edid; @@ -2217,7 +2272,8 @@ int sde_hdmi_connector_pre_deinit(struct drm_connector *connector, return -EINVAL; } - _sde_hdmi_hdp_disable(sde_hdmi); + if (!sde_hdmi->non_pluggable) + _sde_hdmi_hpd_disable(sde_hdmi); return 0; } @@ -2389,9 +2445,14 @@ int sde_hdmi_connector_post_init(struct drm_connector *connector, INIT_WORK(&sde_hdmi->hpd_work, _sde_hdmi_hotplug_work); /* Enable HPD detection */ - rc = _sde_hdmi_hpd_enable(sde_hdmi); - if (rc) - SDE_ERROR("failed to enable HPD: %d\n", rc); + if (!sde_hdmi->non_pluggable) { + rc = _sde_hdmi_hpd_enable(sde_hdmi); + if (rc) + SDE_ERROR("failed to enable HPD: %d\n", rc); + } else { + /* Disable HPD interrupt */ + hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL, 0); + } _sde_hdmi_get_tx_version(sde_hdmi); @@ -2799,7 +2860,6 @@ static int _sde_hdmi_parse_dt_modes(struct device_node *np, u32 v_front_porch, v_pulse_width, v_back_porch; bool h_active_high, v_active_high; u32 flags = 0; - root_node = of_get_child_by_name(np, "qcom,customize-modes"); if (!root_node) { root_node = of_parse_phandle(np, "qcom,customize-modes", 0); @@ -2887,10 +2947,10 @@ static int _sde_hdmi_parse_dt_modes(struct device_node *np, v_active_high = of_property_read_bool(node, "qcom,mode-v-active-high"); - rc = of_property_read_u32(node, "qcom,mode-refersh-rate", + rc = of_property_read_u32(node, "qcom,mode-refresh-rate", &mode->vrefresh); if (rc) { - SDE_ERROR("failed to read refersh-rate, rc=%d\n", rc); + SDE_ERROR("failed to read refresh-rate, rc=%d\n", rc); goto fail; } diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h index 865998c6a126..471472ea23cf 100644 --- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h +++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h @@ -302,6 +302,22 @@ sde_hdmi_connector_detect(struct drm_connector *connector, void *display); /** + * sde_hdmi_core_enable()- turn on clk and pwr for hdmi core + * @sde_hdmi: Pointer to sde_hdmi structure + * + * Return: error code + */ +int sde_hdmi_core_enable(struct sde_hdmi *sde_hdmi); + +/** + * sde_hdmi_core_disable()- turn off clk and pwr for hdmi core + * @sde_hdmi: Pointer to sde_hdmi structure + * + * Return: none + */ +void sde_hdmi_core_disable(struct sde_hdmi *sde_hdmi); + +/** * sde_hdmi_connector_get_modes - add drm modes via drm_mode_probed_add() * @connector: Pointer to drm connector structure * @display: Pointer to private display handle 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 0c143059b749..01283aa30450 100644 --- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c +++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c @@ -106,6 +106,8 @@ struct sde_hdmi_bridge { #define HDMI_AVI_IFRAME_LINE_NUMBER 1 #define HDMI_VENDOR_IFRAME_LINE_NUMBER 3 +static int _sde_hdmi_bridge_setup_scrambler(struct hdmi *hdmi, + struct drm_display_mode *mode); void _sde_hdmi_bridge_destroy(struct drm_bridge *bridge) { } @@ -129,6 +131,8 @@ static void _sde_hdmi_bridge_power_on(struct drm_bridge *bridge) struct sde_hdmi_bridge *sde_hdmi_bridge = to_hdmi_bridge(bridge); struct hdmi *hdmi = sde_hdmi_bridge->hdmi; const struct hdmi_platform_config *config = hdmi->config; + struct sde_connector *c_conn = to_sde_connector(hdmi->connector); + struct sde_hdmi *display = (struct sde_hdmi *)c_conn->display; int i, ret; for (i = 0; i < config->pwr_reg_cnt; i++) { @@ -155,6 +159,13 @@ static void _sde_hdmi_bridge_power_on(struct drm_bridge *bridge) config->pwr_clk_names[i], ret); } } + + if (display->non_pluggable) { + ret = sde_hdmi_core_enable(display); + if (ret) + SDE_ERROR("failed to enable hpd clks: %d\n", ret); + } + _sde_hdmi_bridge_setup_scrambler(hdmi, &display->mode); } static void _sde_hdmi_bridge_power_off(struct drm_bridge *bridge) @@ -162,6 +173,8 @@ static void _sde_hdmi_bridge_power_off(struct drm_bridge *bridge) struct sde_hdmi_bridge *sde_hdmi_bridge = to_hdmi_bridge(bridge); struct hdmi *hdmi = sde_hdmi_bridge->hdmi; const struct hdmi_platform_config *config = hdmi->config; + struct sde_connector *c_conn = to_sde_connector(hdmi->connector); + struct sde_hdmi *display = (struct sde_hdmi *)c_conn->display; int i, ret; /* Wait for vsync */ @@ -177,6 +190,9 @@ static void _sde_hdmi_bridge_power_off(struct drm_bridge *bridge) config->pwr_reg_names[i], ret); } } + + if (display->non_pluggable) + sde_hdmi_core_disable(display); } static int _sde_hdmi_bridge_ddc_clear_irq(struct hdmi *hdmi, @@ -488,6 +504,9 @@ 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); + /* turn on scrambler, scrambler was skipped if HDMI is off */ + _sde_hdmi_bridge_setup_scrambler(hdmi, &display->mode); + mutex_lock(&display->display_lock); if (display->codec_ready) sde_hdmi_notify_clients(display, display->connected); @@ -578,6 +597,9 @@ static void _sde_hdmi_bridge_disable(struct drm_bridge *bridge) display->sink_hdcp_ver = SDE_HDMI_HDCP_NONE; display->sink_hdcp22_support = false; + if (sde_hdmi_tx_is_hdcp_enabled(display)) + sde_hdmi_hdcp_off(display); + sde_hdmi_clear_hdr_info(bridge); mutex_unlock(&display->display_lock); } @@ -592,9 +614,6 @@ static void _sde_hdmi_bridge_post_disable(struct drm_bridge *bridge) sde_hdmi_notify_clients(display, display->connected); - if (sde_hdmi_tx_is_hdcp_enabled(display)) - sde_hdmi_hdcp_off(display); - sde_hdmi_audio_off(hdmi); DRM_DEBUG("power down"); @@ -603,10 +622,16 @@ static void _sde_hdmi_bridge_post_disable(struct drm_bridge *bridge) if (phy) phy->funcs->powerdown(phy); + /* HDMI teardown sequence */ + sde_hdmi_ctrl_reset(hdmi); + if (hdmi->power_on) { _sde_hdmi_bridge_power_off(bridge); hdmi->power_on = false; } + + /* Powering-on the controller for HPD */ + sde_hdmi_ctrl_cfg(hdmi, 1); } static void _sde_hdmi_bridge_set_avi_infoframe(struct hdmi *hdmi, @@ -890,7 +915,8 @@ static void _sde_hdmi_bridge_mode_set(struct drm_bridge *bridge, } _sde_hdmi_save_mode(hdmi, mode); - _sde_hdmi_bridge_setup_scrambler(hdmi, mode); + if (hdmi->power_on) + _sde_hdmi_bridge_setup_scrambler(hdmi, mode); _sde_hdmi_bridge_setup_deep_color(hdmi); } diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_hdcp2p2.c b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_hdcp2p2.c index 51f5c8d8dde6..a4f47756ad9b 100644 --- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_hdcp2p2.c +++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_hdcp2p2.c @@ -234,10 +234,16 @@ static void sde_hdmi_hdcp2p2_off(void *input) flush_kthread_worker(&ctrl->worker); - sde_hdmi_hdcp2p2_ddc_disable((void *)ctrl->init_data.cb_data); - cdata.context = input; sde_hdmi_hdcp2p2_wakeup(&cdata); + + /* There could be upto one frame delay + * between the time encryption disable is + * requested till the time we get encryption + * disabled interrupt + */ + msleep(20); + sde_hdmi_hdcp2p2_ddc_disable((void *)ctrl->init_data.cb_data); } static int sde_hdmi_hdcp2p2_authenticate(void *input) diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.c b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.c index a291a1112aeb..8ce90b9bc162 100644 --- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.c +++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.c @@ -681,6 +681,78 @@ static void _sde_hdmi_scrambler_ddc_reset(struct hdmi *hdmi) hdmi_write(hdmi, REG_HDMI_SCRAMBLER_STATUS_DDC_CTRL, reg_val); } +void sde_hdmi_ctrl_cfg(struct hdmi *hdmi, bool power_on) +{ + uint32_t ctrl = 0; + unsigned long flags; + + spin_lock_irqsave(&hdmi->reg_lock, flags); + ctrl = hdmi_read(hdmi, REG_HDMI_CTRL); + + if (power_on) + ctrl |= HDMI_CTRL_ENABLE; + else + ctrl &= ~HDMI_CTRL_ENABLE; + + hdmi_write(hdmi, REG_HDMI_CTRL, ctrl); + spin_unlock_irqrestore(&hdmi->reg_lock, flags); + + HDMI_UTIL_DEBUG("HDMI Core: %s, HDMI_CTRL=0x%08x\n", + power_on ? "Enable" : "Disable", ctrl); +} + +static void sde_hdmi_clear_pkt_send(struct hdmi *hdmi) +{ + uint32_t reg_val; + + /* Clear audio sample send */ + reg_val = hdmi_read(hdmi, HDMI_AUDIO_PKT_CTRL); + reg_val &= ~BIT(0); + hdmi_write(hdmi, HDMI_AUDIO_PKT_CTRL, reg_val); + + /* Clear sending VBI ctrl packets */ + reg_val = hdmi_read(hdmi, HDMI_VBI_PKT_CTRL); + reg_val &= ~(BIT(4) | BIT(8) | BIT(12)); + hdmi_write(hdmi, HDMI_VBI_PKT_CTRL, reg_val); + + /* Clear sending infoframe packets */ + reg_val = hdmi_read(hdmi, HDMI_INFOFRAME_CTRL0); + reg_val &= ~(BIT(0) | BIT(4) | BIT(8) | BIT(12) + | BIT(15) | BIT(19)); + hdmi_write(hdmi, HDMI_INFOFRAME_CTRL0, reg_val); + + /* Clear sending general ctrl packets */ + reg_val = hdmi_read(hdmi, HDMI_GEN_PKT_CTRL); + reg_val &= ~(BIT(0) | BIT(4)); + hdmi_write(hdmi, HDMI_GEN_PKT_CTRL, reg_val); +} + +void sde_hdmi_ctrl_reset(struct hdmi *hdmi) +{ + uint32_t reg_val; + + /* Assert HDMI CTRL SW reset */ + reg_val = hdmi_read(hdmi, HDMI_CTRL_SW_RESET); + reg_val |= BIT(0); + hdmi_write(hdmi, HDMI_CTRL_SW_RESET, reg_val); + + /* disable the controller and put to known state */ + sde_hdmi_ctrl_cfg(hdmi, 0); + + /* disable the audio engine */ + reg_val = hdmi_read(hdmi, HDMI_AUDIO_CFG); + reg_val &= ~BIT(0); + hdmi_write(hdmi, HDMI_AUDIO_CFG, reg_val); + + /* clear sending packets to sink */ + sde_hdmi_clear_pkt_send(hdmi); + + /* De-assert HDMI CTRL SW reset */ + reg_val = hdmi_read(hdmi, HDMI_CTRL_SW_RESET); + reg_val &= ~BIT(0); + hdmi_write(hdmi, HDMI_CTRL_SW_RESET, reg_val); +} + void _sde_hdmi_scrambler_ddc_disable(void *hdmi_display) { struct sde_hdmi *display = (struct sde_hdmi *)hdmi_display; diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.h b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.h index 3cef7e6aca39..340e665f2c28 100644 --- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.h +++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.h @@ -198,4 +198,7 @@ int sde_hdmi_sink_dc_support(struct drm_connector *connector, struct drm_display_mode *mode); u8 sde_hdmi_hdr_get_ops(u8 curr_state, u8 new_state); +void sde_hdmi_ctrl_reset(struct hdmi *hdmi); +void sde_hdmi_ctrl_cfg(struct hdmi *hdmi, bool power_on); + #endif /* _SDE_HDMI_UTIL_H_ */ diff --git a/drivers/gpu/drm/msm/sde/sde_plane.c b/drivers/gpu/drm/msm/sde/sde_plane.c index 9cbee5243e6d..f5f125c3f71c 100644 --- a/drivers/gpu/drm/msm/sde/sde_plane.c +++ b/drivers/gpu/drm/msm/sde/sde_plane.c @@ -1808,8 +1808,8 @@ static void _sde_plane_install_properties(struct drm_plane *plane, char feature_name[256]; struct sde_phy_plane *pp; uint32_t features = 0xFFFFFFFF, nformats = 64; - u32 maxlinewidth = -1, maxupscale = -1, maxdwnscale = -1; - u32 maxhdeciexp = -1, maxvdeciexp = -1; + u32 maxlinewidth = 0, maxupscale = 0, maxdwnscale = 0; + u32 maxhdeciexp = 0, maxvdeciexp = 0; if (!plane || !psde) { SDE_ERROR("invalid plane\n"); diff --git a/drivers/gpu/drm/msm/sde_dbg.c b/drivers/gpu/drm/msm/sde_dbg.c index 5a0c5e677ed8..ea133619cf62 100644 --- a/drivers/gpu/drm/msm/sde_dbg.c +++ b/drivers/gpu/drm/msm/sde_dbg.c @@ -153,6 +153,7 @@ struct sde_dbg_vbif_debug_bus { * @reg_base_list: list of register dumping regions * @root: base debugfs root * @dev: device pointer + * @mutex: mutex to serialize access to serialze dumps, debugfs access * @power_ctrl: callback structure for enabling power for reading hw registers * @req_dump_blks: list of blocks requested for dumping * @panic_on_err: whether to kernel panic after triggering dump via debugfs @@ -167,6 +168,7 @@ static struct sde_dbg_base { struct list_head reg_base_list; struct dentry *root; struct device *dev; + struct mutex mutex; struct sde_dbg_power_ctrl power_ctrl; struct sde_dbg_reg_base *req_dump_blks[SDE_DBG_BASE_MAX]; @@ -1450,6 +1452,8 @@ static void _sde_dump_array(struct sde_dbg_reg_base *blk_arr[], { int i; + mutex_lock(&sde_dbg_base.mutex); + for (i = 0; i < len; i++) { if (blk_arr[i] != NULL) _sde_dump_reg_by_ranges(blk_arr[i], @@ -1466,6 +1470,8 @@ static void _sde_dump_array(struct sde_dbg_reg_base *blk_arr[], if (do_panic && sde_dbg_base.panic_on_err) panic(name); + + mutex_unlock(&sde_dbg_base.mutex); } /** @@ -1663,6 +1669,7 @@ int sde_dbg_init(struct dentry *debugfs_root, struct device *dev, { int i; + mutex_init(&sde_dbg_base.mutex); INIT_LIST_HEAD(&sde_dbg_base.reg_base_list); sde_dbg_base.dev = dev; sde_dbg_base.power_ctrl = *power_ctrl; @@ -1718,6 +1725,7 @@ void sde_dbg_destroy(void) sde_dbg_base_evtlog = NULL; sde_evtlog_destroy(sde_dbg_base.evtlog); sde_dbg_base.evtlog = NULL; + mutex_destroy(&sde_dbg_base.mutex); } /** @@ -1730,11 +1738,14 @@ static int sde_dbg_reg_base_release(struct inode *inode, struct file *file) { struct sde_dbg_reg_base *dbg = file->private_data; + mutex_lock(&sde_dbg_base.mutex); if (dbg && dbg->buf) { kfree(dbg->buf); dbg->buf_len = 0; dbg->buf = NULL; } + mutex_unlock(&sde_dbg_base.mutex); + return 0; } @@ -1753,6 +1764,7 @@ static ssize_t sde_dbg_reg_base_offset_write(struct file *file, u32 off = 0; u32 cnt = DEFAULT_BASE_REG_CNT; char buf[24]; + ssize_t rc = count; if (!dbg) return -ENODEV; @@ -1768,24 +1780,33 @@ static ssize_t sde_dbg_reg_base_offset_write(struct file *file, if (sscanf(buf, "%x %x", &off, &cnt) != 2) return -EFAULT; - if (off > dbg->max_offset) - return -EINVAL; + mutex_lock(&sde_dbg_base.mutex); + if (off > dbg->max_offset) { + rc = -EINVAL; + goto exit; + } - if (off % sizeof(u32)) - return -EINVAL; + if (off % sizeof(u32)) { + rc = -EINVAL; + goto exit; + } if (cnt > (dbg->max_offset - off)) cnt = dbg->max_offset - off; - if (cnt % sizeof(u32)) - return -EINVAL; + if (cnt % sizeof(u32)) { + rc = -EINVAL; + goto exit; + } dbg->off = off; dbg->cnt = cnt; +exit: + mutex_unlock(&sde_dbg_base.mutex); pr_debug("offset=%x cnt=%x\n", off, cnt); - return count; + return rc; } /** @@ -1808,14 +1829,20 @@ static ssize_t sde_dbg_reg_base_offset_read(struct file *file, if (*ppos) return 0; /* the end */ + mutex_lock(&sde_dbg_base.mutex); len = snprintf(buf, sizeof(buf), "0x%08zx %zx\n", dbg->off, dbg->cnt); - if (len < 0 || len >= sizeof(buf)) + if (len < 0 || len >= sizeof(buf)) { + mutex_unlock(&sde_dbg_base.mutex); return 0; + } - if ((count < sizeof(buf)) || copy_to_user(buff, buf, len)) + if ((count < sizeof(buf)) || copy_to_user(buff, buf, len)) { + mutex_unlock(&sde_dbg_base.mutex); return -EFAULT; + } *ppos += len; /* increase offset */ + mutex_unlock(&sde_dbg_base.mutex); return len; } @@ -1851,8 +1878,11 @@ static ssize_t sde_dbg_reg_base_reg_write(struct file *file, if (cnt < 2) return -EFAULT; - if (off >= dbg->max_offset) + mutex_lock(&sde_dbg_base.mutex); + if (off >= dbg->max_offset) { + mutex_unlock(&sde_dbg_base.mutex); return -EFAULT; + } _sde_dbg_enable_power(true); @@ -1860,6 +1890,8 @@ static ssize_t sde_dbg_reg_base_reg_write(struct file *file, _sde_dbg_enable_power(false); + mutex_unlock(&sde_dbg_base.mutex); + pr_debug("addr=%zx data=%x\n", off, data); return count; @@ -1883,6 +1915,7 @@ static ssize_t sde_dbg_reg_base_reg_read(struct file *file, return -ENODEV; } + mutex_lock(&sde_dbg_base.mutex); if (!dbg->buf) { char *hwbuf; char dump_buf[64]; @@ -1897,12 +1930,15 @@ static ssize_t sde_dbg_reg_base_reg_read(struct file *file, dbg->buf = kzalloc(dbg->buf_len, GFP_KERNEL); - if (!dbg->buf) + if (!dbg->buf) { + mutex_unlock(&sde_dbg_base.mutex); return -ENOMEM; + } hwbuf = kzalloc(ROW_BYTES, GFP_KERNEL); if (!hwbuf) { kfree(dbg->buf); + mutex_unlock(&sde_dbg_base.mutex); return -ENOMEM; } @@ -1934,16 +1970,20 @@ static ssize_t sde_dbg_reg_base_reg_read(struct file *file, kfree(hwbuf); } - if (*ppos >= dbg->buf_len) + if (*ppos >= dbg->buf_len) { + mutex_unlock(&sde_dbg_base.mutex); return 0; /* done reading */ + } len = min(count, dbg->buf_len - (size_t) *ppos); if (copy_to_user(user_buf, dbg->buf + *ppos, len)) { + mutex_unlock(&sde_dbg_base.mutex); pr_err("failed to copy to user\n"); return -EFAULT; } *ppos += len; /* increase offset */ + mutex_unlock(&sde_dbg_base.mutex); return len; } diff --git a/drivers/gpu/msm/adreno_dispatch.c b/drivers/gpu/msm/adreno_dispatch.c index 862d832823f7..fc7799722026 100644 --- a/drivers/gpu/msm/adreno_dispatch.c +++ b/drivers/gpu/msm/adreno_dispatch.c @@ -677,7 +677,7 @@ static int sendcmd(struct adreno_device *adreno_dev, * then set up the timer. If this misses, then preemption is indeed a * thing and the timer will be set up in due time */ - if (!adreno_in_preempt_state(adreno_dev, ADRENO_PREEMPT_NONE)) { + if (adreno_in_preempt_state(adreno_dev, ADRENO_PREEMPT_NONE)) { if (drawqueue_is_current(dispatch_q)) mod_timer(&dispatcher->timer, dispatch_q->expires); } diff --git a/drivers/gpu/msm/kgsl_debugfs.c b/drivers/gpu/msm/kgsl_debugfs.c index 37d92428f02c..592257a332d1 100644 --- a/drivers/gpu/msm/kgsl_debugfs.c +++ b/drivers/gpu/msm/kgsl_debugfs.c @@ -299,6 +299,7 @@ static int print_sparse_mem_entry(int id, void *ptr, void *data) if (!(m->flags & KGSL_MEMFLAGS_SPARSE_VIRT)) return 0; + spin_lock(&entry->bind_lock); node = rb_first(&entry->bind_tree); while (node != NULL) { @@ -309,6 +310,7 @@ static int print_sparse_mem_entry(int id, void *ptr, void *data) obj->v_off, obj->size, obj->p_off); node = rb_next(node); } + spin_unlock(&entry->bind_lock); seq_putc(s, '\n'); diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c index 57d99c451952..1ca8dca68470 100644 --- a/drivers/gpu/msm/kgsl_iommu.c +++ b/drivers/gpu/msm/kgsl_iommu.c @@ -118,9 +118,11 @@ void kgsl_print_global_pt_entries(struct seq_file *s) if (memdesc == NULL) continue; - seq_printf(s, "0x%16.16llX-0x%16.16llX %16llu %s\n", - memdesc->gpuaddr, memdesc->gpuaddr + memdesc->size - 1, - memdesc->size, global_pt_entries[i].name); + seq_printf(s, "0x%pK-0x%pK %16llu %s\n", + (uint64_t *)(uintptr_t) memdesc->gpuaddr, + (uint64_t *)(uintptr_t) (memdesc->gpuaddr + + memdesc->size - 1), memdesc->size, + global_pt_entries[i].name); } } diff --git a/drivers/media/i2c/adv7481.c b/drivers/media/i2c/adv7481.c index 4f3887c087ce..74d7b9584827 100644 --- a/drivers/media/i2c/adv7481.c +++ b/drivers/media/i2c/adv7481.c @@ -2506,3 +2506,4 @@ module_driver(adv7481_driver, platform_driver_register, platform_driver_unregister); MODULE_DESCRIPTION("ADI ADV7481 HDMI/MHL/SD video receiver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/i2c/adv7481_reg.h b/drivers/media/i2c/adv7481_reg.h index 60b1301abbe6..b0bb5784d2ef 100644 --- a/drivers/media/i2c/adv7481_reg.h +++ b/drivers/media/i2c/adv7481_reg.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and diff --git a/drivers/media/platform/msm/ais/common/msm_camera_io_util.c b/drivers/media/platform/msm/ais/common/msm_camera_io_util.c index 22518c2cae7d..a09237f3d5ef 100644 --- a/drivers/media/platform/msm/ais/common/msm_camera_io_util.c +++ b/drivers/media/platform/msm/ais/common/msm_camera_io_util.c @@ -501,6 +501,7 @@ vreg_get_fail: } return -ENODEV; } +EXPORT_SYMBOL(msm_camera_config_vreg); int msm_camera_enable_vreg(struct device *dev, struct camera_vreg_t *cam_vreg, int num_vreg, enum msm_camera_vreg_name_t *vreg_seq, @@ -574,6 +575,7 @@ disable_vreg: } return rc; } +EXPORT_SYMBOL(msm_camera_enable_vreg); void msm_camera_bus_scale_cfg(uint32_t bus_perf_client, enum msm_bus_perf_setting perf_setting) diff --git a/drivers/media/platform/msm/ais/sensor/actuator/msm_actuator.c b/drivers/media/platform/msm/ais/sensor/actuator/msm_actuator.c index 40806d5a164f..f11c2652728a 100644 --- a/drivers/media/platform/msm/ais/sensor/actuator/msm_actuator.c +++ b/drivers/media/platform/msm/ais/sensor/actuator/msm_actuator.c @@ -98,6 +98,11 @@ static void msm_actuator_parse_i2c_params(struct msm_actuator_ctrl_t *a_ctrl, return; } + if (a_ctrl->i2c_reg_tbl == NULL) { + pr_err("failed. i2c reg tabl is NULL"); + return; + } + size = a_ctrl->reg_tbl_size; write_arr = a_ctrl->reg_tbl; i2c_tbl = a_ctrl->i2c_reg_tbl; @@ -1290,9 +1295,11 @@ static int32_t msm_actuator_set_param(struct msm_actuator_ctrl_t *a_ctrl, if (copy_from_user(&a_ctrl->region_params, (void __user *)set_info->af_tuning_params.region_params, - a_ctrl->region_size * sizeof(struct region_params_t))) + a_ctrl->region_size * sizeof(struct region_params_t))) { + a_ctrl->total_steps = 0; + pr_err("Error copying region_params\n"); return -EFAULT; - + } if (a_ctrl->act_device_type == MSM_CAMERA_PLATFORM_DEVICE) { cci_client = a_ctrl->i2c_client.cci_client; cci_client->sid = diff --git a/drivers/media/platform/msm/ais/sensor/cci/msm_cci.c b/drivers/media/platform/msm/ais/sensor/cci/msm_cci.c index 42f8c4dcfaa0..a7771441e950 100644 --- a/drivers/media/platform/msm/ais/sensor/cci/msm_cci.c +++ b/drivers/media/platform/msm/ais/sensor/cci/msm_cci.c @@ -2011,6 +2011,7 @@ struct v4l2_subdev *msm_cci_get_subdev(void) { return g_cci_subdev; } +EXPORT_SYMBOL(msm_cci_get_subdev); static int msm_cci_probe(struct platform_device *pdev) { diff --git a/drivers/media/platform/msm/ais/sensor/io/msm_camera_cci_i2c.c b/drivers/media/platform/msm/ais/sensor/io/msm_camera_cci_i2c.c index 8f2fd0f9e24d..8fa4d7c80477 100644 --- a/drivers/media/platform/msm/ais/sensor/io/msm_camera_cci_i2c.c +++ b/drivers/media/platform/msm/ais/sensor/io/msm_camera_cci_i2c.c @@ -63,6 +63,7 @@ int32_t msm_camera_cci_i2c_read(struct msm_camera_i2c_client *client, S_I2C_DBG("%s addr = 0x%x data: 0x%x\n", __func__, addr, *data); return rc; } +EXPORT_SYMBOL(msm_camera_cci_i2c_read); int32_t msm_camera_cci_i2c_read_seq(struct msm_camera_i2c_client *client, uint32_t addr, uint8_t *data, uint32_t num_byte) @@ -110,6 +111,7 @@ int32_t msm_camera_cci_i2c_read_seq(struct msm_camera_i2c_client *client, kfree(buf); return rc; } +EXPORT_SYMBOL(msm_camera_cci_i2c_read_seq); int32_t msm_camera_cci_i2c_write(struct msm_camera_i2c_client *client, uint32_t addr, uint16_t data, @@ -145,6 +147,7 @@ int32_t msm_camera_cci_i2c_write(struct msm_camera_i2c_client *client, rc = cci_ctrl.status; return rc; } +EXPORT_SYMBOL(msm_camera_cci_i2c_write); int32_t msm_camera_cci_i2c_write_seq(struct msm_camera_i2c_client *client, uint32_t addr, uint8_t *data, uint32_t num_byte) @@ -193,6 +196,7 @@ int32_t msm_camera_cci_i2c_write_seq(struct msm_camera_i2c_client *client, reg_conf_tbl = NULL; return rc; } +EXPORT_SYMBOL(msm_camera_cci_i2c_write_seq); static int32_t msm_camera_cci_i2c_write_table_cmd( struct msm_camera_i2c_client *client, @@ -265,6 +269,7 @@ int32_t msm_camera_cci_i2c_write_table( return msm_camera_cci_i2c_write_table_cmd(client, write_setting, MSM_CCI_I2C_WRITE); } +EXPORT_SYMBOL(msm_camera_cci_i2c_write_table); int32_t msm_camera_cci_i2c_write_seq_table( struct msm_camera_i2c_client *client, @@ -311,6 +316,7 @@ int32_t msm_camera_cci_i2c_write_seq_table( client->addr_type = client_addr_type; return rc; } +EXPORT_SYMBOL(msm_camera_cci_i2c_write_seq_table); int32_t msm_camera_cci_i2c_write_table_w_microdelay( struct msm_camera_i2c_client *client, @@ -344,6 +350,7 @@ int32_t msm_camera_cci_i2c_write_table_w_microdelay( rc = cci_ctrl.status; return rc; } +EXPORT_SYMBOL(msm_camera_cci_i2c_write_table_w_microdelay); static int32_t msm_camera_cci_i2c_compare(struct msm_camera_i2c_client *client, uint32_t addr, uint16_t data, @@ -435,6 +442,7 @@ int32_t msm_camera_cci_i2c_poll(struct msm_camera_i2c_client *client, return rc; } +EXPORT_SYMBOL(msm_camera_cci_i2c_poll); static int32_t msm_camera_cci_i2c_set_mask(struct msm_camera_i2c_client *client, uint32_t addr, uint16_t mask, @@ -585,3 +593,4 @@ int32_t msm_sensor_cci_i2c_util(struct msm_camera_i2c_client *client, } return cci_ctrl.status; } +EXPORT_SYMBOL(msm_sensor_cci_i2c_util); diff --git a/drivers/media/platform/msm/ais/sensor/io/msm_camera_dt_util.c b/drivers/media/platform/msm/ais/sensor/io/msm_camera_dt_util.c index 66300e3f7359..d94f082e6765 100644 --- a/drivers/media/platform/msm/ais/sensor/io/msm_camera_dt_util.c +++ b/drivers/media/platform/msm/ais/sensor/io/msm_camera_dt_util.c @@ -1234,6 +1234,7 @@ ERROR1: *num_vreg = 0; return rc; } +EXPORT_SYMBOL(msm_camera_get_dt_vreg_data); static int msm_camera_enable_i2c_mux(struct msm_camera_i2c_conf *i2c_conf) { diff --git a/drivers/media/platform/msm/camera_v2/camera/camera.c b/drivers/media/platform/msm/camera_v2/camera/camera.c index aeeb5cae3096..ccdd4622c120 100644 --- a/drivers/media/platform/msm/camera_v2/camera/camera.c +++ b/drivers/media/platform/msm/camera_v2/camera/camera.c @@ -459,7 +459,9 @@ static int camera_v4l2_subscribe_event(struct v4l2_fh *fh, int rc = 0; struct camera_v4l2_private *sp = fh_to_private(fh); + mutex_lock(&sp->lock); rc = v4l2_event_subscribe(&sp->fh, sub, 5, NULL); + mutex_unlock(&sp->lock); return rc; } @@ -470,7 +472,9 @@ static int camera_v4l2_unsubscribe_event(struct v4l2_fh *fh, int rc = 0; struct camera_v4l2_private *sp = fh_to_private(fh); + mutex_lock(&sp->lock); rc = v4l2_event_unsubscribe(&sp->fh, sub); + mutex_unlock(&sp->lock); return rc; } diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.h b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.h index 21fab0590b55..34cac9daea89 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.h +++ b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.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 @@ -98,6 +98,8 @@ struct msm_isp_buffer { struct timeval *tv; /* Indicates whether buffer is used as ping ot pong buffer */ uint32_t pingpong_bit; + /* Indicates buffer is reconfig due to drop frame */ + uint32_t is_drop_reconfig; /*Native buffer*/ struct list_head list; diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp.c index 22eb86f4f875..23e27e1179d1 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.c @@ -453,11 +453,69 @@ static long msm_isp_v4l2_fops_ioctl(struct file *file, unsigned int cmd, return video_usercopy(file, cmd, arg, msm_isp_subdev_do_ioctl); } +static void isp_vma_open(struct vm_area_struct *vma) +{ + pr_debug("%s: open called\n", __func__); +} + +static void isp_vma_close(struct vm_area_struct *vma) +{ + pr_debug("%s: close called\n", __func__); +} + +static int isp_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf) +{ + struct page *page; + struct vfe_device *vfe_dev = vma->vm_private_data; + struct isp_proc *isp_page = NULL; + + isp_page = vfe_dev->isp_page; + + pr_debug("%s: vfeid:%d u_virt_addr:0x%lx k_virt_addr:%pK\n", + __func__, vfe_dev->pdev->id, vma->vm_start, + (void *)isp_page); + if (isp_page != NULL) { + page = virt_to_page(isp_page); + get_page(page); + vmf->page = page; + isp_page->kernel_sofid = + vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id; + isp_page->vfeid = vfe_dev->pdev->id; + } + return 0; +} + +static const struct vm_operations_struct isp_vm_ops = { + .open = isp_vma_open, + .close = isp_vma_close, + .fault = isp_vma_fault, +}; + +static int msm_isp_v4l2_fops_mmap(struct file *filep, + struct vm_area_struct *vma) +{ + int ret = -EINVAL; + struct video_device *vdev = video_devdata(filep); + struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); + struct vfe_device *vfe_dev = v4l2_get_subdevdata(sd); + + vma->vm_ops = &isp_vm_ops; + vma->vm_flags |= + (unsigned long)(VM_DONTEXPAND | VM_DONTDUMP); + vma->vm_private_data = vfe_dev; + isp_vma_open(vma); + ret = 0; + pr_debug("%s: isp mmap is called vm_start: 0x%lx\n", + __func__, vma->vm_start); + return ret; +} + static struct v4l2_file_operations msm_isp_v4l2_fops = { #ifdef CONFIG_COMPAT .compat_ioctl32 = msm_isp_v4l2_fops_ioctl, #endif - .unlocked_ioctl = msm_isp_v4l2_fops_ioctl + .unlocked_ioctl = msm_isp_v4l2_fops_ioctl, + .mmap = msm_isp_v4l2_fops_mmap }; static int vfe_set_common_data(struct platform_device *pdev) @@ -671,6 +729,8 @@ int vfe_hw_probe(struct platform_device *pdev) msm_isp_v4l2_fops.compat_ioctl32 = msm_isp_v4l2_fops_ioctl; #endif + msm_isp_v4l2_fops.mmap = msm_isp_v4l2_fops_mmap; + vfe_dev->subdev.sd.devnode->fops = &msm_isp_v4l2_fops; vfe_dev->buf_mgr = &vfe_buf_mgr; @@ -687,6 +747,14 @@ int vfe_hw_probe(struct platform_device *pdev) msm_isp_enable_debugfs(vfe_dev, msm_isp_bw_request_history); vfe_dev->buf_mgr->init_done = 1; vfe_dev->vfe_open_cnt = 0; + /*Allocate a page in kernel and map it to camera user process*/ + vfe_dev->isp_page = (struct isp_proc *)get_zeroed_page(GFP_KERNEL); + if (vfe_dev->isp_page == NULL) { + pr_err("%s: no enough memory\n", __func__); + rc = -ENOMEM; + goto probe_fail3; + } + vfe_dev->isp_page->vfeid = vfe_dev->pdev->id; return rc; probe_fail3: 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 b2d152bf4ef0..d336e1ef1bd7 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h @@ -759,6 +759,11 @@ struct msm_vfe_common_subdev { struct msm_vfe_common_dev_data *common_data; }; +struct isp_proc { + uint32_t kernel_sofid; + uint32_t vfeid; +}; + struct vfe_device { /* Driver private data */ struct platform_device *pdev; @@ -842,6 +847,7 @@ struct vfe_device { uint32_t recovery_irq1_mask; /* total bandwidth per vfe */ uint64_t total_bandwidth; + struct isp_proc *isp_page; }; struct vfe_parent_device { diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c index e04229fed666..d3c418511ece 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c @@ -1342,6 +1342,7 @@ static void msm_vfe40_cfg_camif(struct vfe_device *vfe_dev, struct msm_vfe_pix_cfg *pix_cfg) { uint16_t first_pixel, last_pixel, first_line, last_line; + uint16_t epoch_line1; struct msm_vfe_camif_cfg *camif_cfg = &pix_cfg->camif_cfg; uint32_t val, subsample_period, subsample_pattern; struct msm_vfe_camif_subsample_cfg *subsample_cfg = @@ -1357,6 +1358,14 @@ static void msm_vfe40_cfg_camif(struct vfe_device *vfe_dev, last_pixel = camif_cfg->last_pixel; first_line = camif_cfg->first_line; last_line = camif_cfg->last_line; + epoch_line1 = camif_cfg->epoch_line1; + + if ((epoch_line1 <= 0) || (epoch_line1 > last_line)) + epoch_line1 = last_line - 50; + + if ((last_line - epoch_line1) > 100) + epoch_line1 = last_line - 100; + subsample_period = camif_cfg->subsample_cfg.irq_subsample_period; subsample_pattern = camif_cfg->subsample_cfg.irq_subsample_pattern; @@ -1368,6 +1377,14 @@ static void msm_vfe40_cfg_camif(struct vfe_device *vfe_dev, msm_camera_io_w(first_line << 16 | last_line, vfe_dev->vfe_base + 0x308); + + /*configure EPOCH0: 20 lines, and + * configure EPOCH1: epoch_line1 before EOF + */ + msm_camera_io_w_mb(0x140000 | epoch_line1, + vfe_dev->vfe_base + 0x318); + pr_debug("%s:%d: epoch_line1: %d\n", + __func__, __LINE__, epoch_line1); if (subsample_period && subsample_pattern) { val = msm_camera_io_r(vfe_dev->vfe_base + 0x2F8); val &= 0xFFE0FFFF; @@ -1489,9 +1506,8 @@ static void msm_vfe40_update_camif_state(struct vfe_device *vfe_dev, msm_camera_io_w(0x0, vfe_dev->vfe_base + 0x30); msm_camera_io_w_mb(0x81, vfe_dev->vfe_base + 0x34); msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x24); - msm_vfe40_config_irq(vfe_dev, 0xF7, 0x81, + msm_vfe40_config_irq(vfe_dev, 0xFF, 0x81, MSM_ISP_IRQ_ENABLE); - msm_camera_io_w_mb(0x140000, vfe_dev->vfe_base + 0x318); bus_en = ((vfe_dev->axi_data. 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 70950a88fc66..146ed1f14467 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c @@ -699,7 +699,7 @@ void msm_vfe47_process_epoch_irq(struct vfe_device *vfe_dev, void msm_isp47_preprocess_camif_irq(struct vfe_device *vfe_dev, uint32_t irq_status0) { - if (irq_status0 & BIT(1)) + if (irq_status0 & BIT(3)) vfe_dev->axi_data.src_info[VFE_PIX_0].accept_frame = false; if (irq_status0 & BIT(0)) vfe_dev->axi_data.src_info[VFE_PIX_0].accept_frame = true; @@ -788,7 +788,7 @@ long msm_vfe47_reset_hardware(struct vfe_device *vfe_dev, msm_camera_io_w(0xFFFFFEFF, vfe_dev->vfe_base + 0x68); msm_camera_io_w(0x1, vfe_dev->vfe_base + 0x58); vfe_dev->hw_info->vfe_ops.axi_ops. - reload_wm(vfe_dev, vfe_dev->vfe_base, 0x0031FFFF); + reload_wm(vfe_dev, vfe_dev->vfe_base, 0x0011FFFF); } if (blocking_call) { @@ -1368,6 +1368,7 @@ void msm_vfe47_cfg_camif(struct vfe_device *vfe_dev, struct msm_vfe_pix_cfg *pix_cfg) { uint16_t first_pixel, last_pixel, first_line, last_line; + uint16_t epoch_line1; struct msm_vfe_camif_cfg *camif_cfg = &pix_cfg->camif_cfg; struct msm_vfe_testgen_cfg *testgen_cfg = &pix_cfg->testgen_cfg; uint32_t val, subsample_period, subsample_pattern; @@ -1390,6 +1391,14 @@ void msm_vfe47_cfg_camif(struct vfe_device *vfe_dev, last_pixel = camif_cfg->last_pixel; first_line = camif_cfg->first_line; last_line = camif_cfg->last_line; + epoch_line1 = camif_cfg->epoch_line1; + + if ((epoch_line1 <= 0) || (epoch_line1 > last_line)) + epoch_line1 = last_line - 50; + + if ((last_line - epoch_line1) > 100) + epoch_line1 = last_line - 100; + subsample_period = camif_cfg->subsample_cfg.irq_subsample_period; subsample_pattern = camif_cfg->subsample_cfg.irq_subsample_pattern; @@ -1420,6 +1429,13 @@ void msm_vfe47_cfg_camif(struct vfe_device *vfe_dev, msm_camera_io_w(first_line << 16 | last_line, vfe_dev->vfe_base + 0x48C); + /*configure EPOCH0: 20 lines, and + * configure EPOCH1: epoch_line1 before EOF + */ + msm_camera_io_w_mb(0x140000 | epoch_line1, + vfe_dev->vfe_base + 0x4A0); + pr_debug("%s:%d: epoch_line1: %d\n", + __func__, __LINE__, epoch_line1); msm_camera_io_w(((irq_sub_period - 1) << 8) | 0 << 5 | (frame_sub_period - 1), vfe_dev->vfe_base + 0x494); msm_camera_io_w(0xFFFFFFFF, vfe_dev->vfe_base + 0x498); @@ -1597,7 +1613,7 @@ void msm_vfe47_update_camif_state(struct vfe_device *vfe_dev, val = msm_camera_io_r(vfe_dev->vfe_base + 0x47C); if (update_state == ENABLE_CAMIF) { vfe_dev->hw_info->vfe_ops.irq_ops.config_irq(vfe_dev, - 0x15, 0x91, + 0x1F, 0x91, MSM_ISP_IRQ_ENABLE); if ((vfe_dev->hvx_cmd > HVX_DISABLE) && @@ -1618,8 +1634,6 @@ void msm_vfe47_update_camif_state(struct vfe_device *vfe_dev, msm_camera_io_w(val, vfe_dev->vfe_base + 0x47C); msm_camera_io_w_mb(0x4, vfe_dev->vfe_base + 0x478); msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x478); - /* configure EPOCH0 for 20 lines */ - msm_camera_io_w_mb(0x140000, vfe_dev->vfe_base + 0x4A0); /* testgen GO*/ if (vfe_dev->axi_data.src_info[VFE_PIX_0].input_mux == TESTGEN) msm_camera_io_w(1, vfe_dev->vfe_base + 0xC58); 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 5bcb3034b82a..15f8061b9919 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 @@ -719,13 +719,7 @@ void msm_isp_check_for_output_error(struct vfe_device *vfe_dev, sof_info->stream_get_buf_fail_mask = 0; axi_data = &vfe_dev->axi_data; - /* report that registers are not updated and return empty buffer for - * controllable outputs - */ - if (!vfe_dev->reg_updated) { - sof_info->regs_not_updated = - vfe_dev->reg_update_requested; - } + for (i = 0; i < RDI_INTF_0; i++) { stream_info = msm_isp_get_stream_common_data(vfe_dev, i); @@ -747,6 +741,12 @@ void msm_isp_check_for_output_error(struct vfe_device *vfe_dev, if (stream_info->controllable_output && !vfe_dev->reg_updated) { if (stream_info->undelivered_request_cnt) { + /*report that registers are not updated + * and return empty buffer for controllable + * outputs + */ + sof_info->regs_not_updated = + !vfe_dev->reg_updated; pr_err("Drop frame no reg update\n"); if (msm_isp_drop_frame(vfe_dev, stream_info, ts, sof_info)) { @@ -933,6 +933,8 @@ void msm_isp_increment_frame_id(struct vfe_device *vfe_dev, } if (frame_src == VFE_PIX_0) { + vfe_dev->isp_page->kernel_sofid = + vfe_dev->axi_data.src_info[frame_src].frame_id; if (!src_info->frame_id && !src_info->reg_update_frame_id && ((src_info->frame_id - @@ -1646,23 +1648,30 @@ static void msm_isp_reload_ping_pong_offset( } static int msm_isp_update_deliver_count(struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info, uint32_t pingpong_bit) + struct msm_vfe_axi_stream *stream_info, uint32_t pingpong_bit, + struct msm_isp_buffer *done_buf) { int rc = 0; if (!stream_info->controllable_output) goto done; - if (!stream_info->undelivered_request_cnt) { + if (!stream_info->undelivered_request_cnt || + (done_buf == NULL)) { pr_err_ratelimited("%s:%d error undelivered_request_cnt 0\n", __func__, __LINE__); rc = -EINVAL; goto done; } else { + if ((done_buf->is_drop_reconfig == 1) && + (stream_info->sw_ping_pong_bit == -1)) { + goto done; + } /*After wm reload, we get bufdone for ping buffer*/ if (stream_info->sw_ping_pong_bit == -1) stream_info->sw_ping_pong_bit = 0; - stream_info->undelivered_request_cnt--; + if (done_buf->is_drop_reconfig != 1) + stream_info->undelivered_request_cnt--; if (pingpong_bit != stream_info->sw_ping_pong_bit) { pr_err("%s:%d ping pong bit actual %d sw %d\n", __func__, __LINE__, pingpong_bit, @@ -1908,7 +1917,8 @@ int msm_isp_cfg_offline_ping_pong_address(struct vfe_device *vfe_dev, } static int msm_isp_cfg_ping_pong_address( - struct msm_vfe_axi_stream *stream_info, uint32_t pingpong_status) + struct msm_vfe_axi_stream *stream_info, uint32_t pingpong_status, + struct msm_isp_buffer *buf) { int i; int j; @@ -1917,7 +1927,6 @@ static int msm_isp_cfg_ping_pong_address( uint32_t buffer_size_byte = 0; int32_t word_per_line = 0; dma_addr_t paddr; - struct msm_isp_buffer *buf = NULL; /* Isolate pingpong_bit from pingpong_status */ @@ -1928,10 +1937,11 @@ static int msm_isp_cfg_ping_pong_address( if (stream_info->buf[!pingpong_bit]) { pr_err("stream %x buffer already set for pingpong %d\n", stream_info->stream_src, !pingpong_bit); - return 0; + return 1; } - buf = msm_isp_get_stream_buffer(vfe_dev, stream_info); + if (buf == NULL) + buf = msm_isp_get_stream_buffer(vfe_dev, stream_info); if (!buf) { msm_isp_cfg_stream_scratch(stream_info, pingpong_status); @@ -2165,6 +2175,7 @@ int msm_isp_drop_frame(struct vfe_device *vfe_dev, struct msm_isp_bufq *bufq = NULL; uint32_t pingpong_bit; int vfe_idx; + int rc = -1; if (!vfe_dev || !stream_info || !ts || !sof_info) { pr_err("%s %d vfe_dev %pK stream_info %pK ts %pK op_info %pK\n", @@ -2181,17 +2192,42 @@ int msm_isp_drop_frame(struct vfe_device *vfe_dev, pingpong_bit = (~(pingpong_status >> stream_info->wm[vfe_idx][0]) & 0x1); done_buf = stream_info->buf[pingpong_bit]; - if (done_buf) { - bufq = vfe_dev->buf_mgr->ops->get_bufq(vfe_dev->buf_mgr, - done_buf->bufq_handle); - if (!bufq) { - spin_unlock_irqrestore(&stream_info->lock, flags); - pr_err("%s: Invalid bufq buf_handle %x\n", - __func__, done_buf->bufq_handle); - return -EINVAL; + if (done_buf && + (stream_info->composite_irq[MSM_ISP_COMP_IRQ_EPOCH] == 0)) { + if ((stream_info->sw_ping_pong_bit != -1) && + !vfe_dev->reg_updated) { + rc = msm_isp_cfg_ping_pong_address( + stream_info, ~pingpong_status, done_buf); + if (rc < 0) { + ISP_DBG("%s: Error configuring ping_pong\n", + __func__); + bufq = vfe_dev->buf_mgr->ops->get_bufq( + vfe_dev->buf_mgr, + done_buf->bufq_handle); + if (!bufq) { + spin_unlock_irqrestore( + &stream_info->lock, + flags); + pr_err("%s: Invalid bufq buf_handle %x\n", + __func__, + done_buf->bufq_handle); + return -EINVAL; + } + sof_info->reg_update_fail_mask_ext |= + (bufq->bufq_handle & 0xFF); + } + } + /*Avoid Drop Frame and re-issue pingpong cfg*/ + /*this notify is per ping and pong buffer*/ + done_buf->is_drop_reconfig = 1; + stream_info->current_framedrop_period = 1; + /*Avoid Multiple request frames for single SOF*/ + vfe_dev->axi_data.src_info[VFE_PIX_0].accept_frame = false; + + if (stream_info->current_framedrop_period != + stream_info->requested_framedrop_period) { + msm_isp_cfg_framedrop_reg(stream_info); } - sof_info->reg_update_fail_mask_ext |= - (bufq->bufq_handle & 0xFF); } spin_unlock_irqrestore(&stream_info->lock, flags); @@ -2201,6 +2237,8 @@ int msm_isp_drop_frame(struct vfe_device *vfe_dev, /* no buf done come */ msm_isp_process_axi_irq_stream(vfe_dev, stream_info, pingpong_status, ts); + if (done_buf) + done_buf->is_drop_reconfig = 0; } return 0; } @@ -2505,7 +2543,7 @@ static int msm_isp_init_stream_ping_pong_reg( /* Set address for both PING & PO NG register */ rc = msm_isp_cfg_ping_pong_address( - stream_info, VFE_PING_FLAG); + stream_info, VFE_PING_FLAG, NULL); /* No buffer available on start is not error */ if (rc == -ENOMEM && stream_info->stream_type != BURST_STREAM) return 0; @@ -2517,7 +2555,7 @@ static int msm_isp_init_stream_ping_pong_reg( if (stream_info->stream_type != BURST_STREAM || stream_info->runtime_num_burst_capture > 1) { rc = msm_isp_cfg_ping_pong_address( - stream_info, VFE_PONG_FLAG); + stream_info, VFE_PONG_FLAG, NULL); /* No buffer available on start is not error */ if (rc == -ENOMEM) return 0; @@ -3516,7 +3554,7 @@ static int msm_isp_request_frame(struct vfe_device *vfe_dev, if (stream_info->undelivered_request_cnt == 1) { rc = msm_isp_cfg_ping_pong_address(stream_info, - VFE_PING_FLAG); + VFE_PING_FLAG, NULL); if (rc) { spin_unlock_irqrestore(&stream_info->lock, flags); stream_info->undelivered_request_cnt--; @@ -3549,10 +3587,10 @@ static int msm_isp_request_frame(struct vfe_device *vfe_dev, * now. */ rc = msm_isp_cfg_ping_pong_address(stream_info, - VFE_PONG_FLAG); + VFE_PONG_FLAG, NULL); } else { rc = msm_isp_cfg_ping_pong_address( - stream_info, pingpong_status); + stream_info, pingpong_status, NULL); } if (rc) { stream_info->undelivered_request_cnt--; @@ -3574,6 +3612,9 @@ static int msm_isp_request_frame(struct vfe_device *vfe_dev, if (0 == rc) msm_isp_reset_framedrop(vfe_dev, stream_info); + /*Avoid Multiple request frames for single SOF*/ + vfe_dev->axi_data.src_info[frame_src].accept_frame = false; + spin_unlock_irqrestore(&stream_info->lock, flags); return rc; @@ -4057,6 +4098,10 @@ void msm_isp_process_axi_irq_stream(struct vfe_device *vfe_dev, done_buf = stream_info->buf[pingpong_bit]; if (vfe_dev->buf_mgr->frameId_mismatch_recovery == 1) { + if (done_buf) { + if (done_buf->is_drop_reconfig == 1) + done_buf->is_drop_reconfig = 0; + } pr_err_ratelimited("%s: Mismatch Recovery in progress, drop frame!\n", __func__); spin_unlock_irqrestore(&stream_info->lock, flags); @@ -4076,14 +4121,26 @@ void msm_isp_process_axi_irq_stream(struct vfe_device *vfe_dev, stream_info->frame_id++; stream_info->buf[pingpong_bit] = NULL; + if (stream_info->controllable_output && + (done_buf != NULL) && + (stream_info->sw_ping_pong_bit == -1) && + (done_buf->is_drop_reconfig == 1)) { + /*When wm reloaded and corresponding reg_update fail + * then buffer is reconfig as PING buffer. so, avoid + * NULL assignment to PING buffer and eventually + * next AXI_DONE or buf_done can be successful + */ + stream_info->buf[pingpong_bit] = done_buf; + } + if (stream_info->stream_type == CONTINUOUS_STREAM || stream_info->runtime_num_burst_capture > 1) { rc = msm_isp_cfg_ping_pong_address( - stream_info, pingpong_status); + stream_info, pingpong_status, NULL); if (rc < 0) ISP_DBG("%s: Error configuring ping_pong\n", __func__); - } else if (done_buf) { + } else if (done_buf && (done_buf->is_drop_reconfig != 1)) { msm_isp_cfg_stream_scratch(stream_info, pingpong_status); } @@ -4107,8 +4164,10 @@ void msm_isp_process_axi_irq_stream(struct vfe_device *vfe_dev, } rc = msm_isp_update_deliver_count(vfe_dev, stream_info, - pingpong_bit); + pingpong_bit, done_buf); if (rc) { + if (done_buf->is_drop_reconfig == 1) + done_buf->is_drop_reconfig = 0; spin_unlock_irqrestore(&stream_info->lock, flags); pr_err_ratelimited("%s:VFE%d get done buf fail\n", __func__, vfe_dev->pdev->id); @@ -4117,17 +4176,28 @@ void msm_isp_process_axi_irq_stream(struct vfe_device *vfe_dev, return; } - spin_unlock_irqrestore(&stream_info->lock, flags); if ((done_buf->frame_id != frame_id) && vfe_dev->axi_data.enable_frameid_recovery) { + if (done_buf->is_drop_reconfig == 1) + done_buf->is_drop_reconfig = 0; + spin_unlock_irqrestore(&stream_info->lock, flags); msm_isp_handle_done_buf_frame_id_mismatch(vfe_dev, stream_info, done_buf, time_stamp, frame_id); return; } - msm_isp_process_done_buf(vfe_dev, stream_info, + if (done_buf->is_drop_reconfig == 1) { + /*When ping/pong buf is already reconfigured + * then dont issue buf-done for current buffer + */ + done_buf->is_drop_reconfig = 0; + spin_unlock_irqrestore(&stream_info->lock, flags); + } else { + spin_unlock_irqrestore(&stream_info->lock, flags); + msm_isp_process_done_buf(vfe_dev, stream_info, done_buf, time_stamp, frame_id); + } } void msm_isp_process_axi_irq(struct vfe_device *vfe_dev, diff --git a/drivers/media/platform/msm/camera_v2/msm.c b/drivers/media/platform/msm/camera_v2/msm.c index 194a6583103e..6a969401e950 100644 --- a/drivers/media/platform/msm/camera_v2/msm.c +++ b/drivers/media/platform/msm/camera_v2/msm.c @@ -35,6 +35,7 @@ static struct v4l2_device *msm_v4l2_dev; static struct list_head ordered_sd_list; static struct mutex ordered_sd_mtx; +static struct mutex v4l2_event_mtx; static struct pm_qos_request msm_v4l2_pm_qos_request; @@ -852,13 +853,25 @@ static long msm_private_ioctl(struct file *file, void *fh, static int msm_unsubscribe_event(struct v4l2_fh *fh, const struct v4l2_event_subscription *sub) { - return v4l2_event_unsubscribe(fh, sub); + int rc; + + mutex_lock(&v4l2_event_mtx); + rc = v4l2_event_unsubscribe(fh, sub); + mutex_unlock(&v4l2_event_mtx); + + return rc; } static int msm_subscribe_event(struct v4l2_fh *fh, const struct v4l2_event_subscription *sub) { - return v4l2_event_subscribe(fh, sub, 5, NULL); + int rc; + + mutex_lock(&v4l2_event_mtx); + rc = v4l2_event_subscribe(fh, sub, 5, NULL); + mutex_unlock(&v4l2_event_mtx); + + return rc; } static const struct v4l2_ioctl_ops g_msm_ioctl_ops = { @@ -1376,6 +1389,7 @@ static int msm_probe(struct platform_device *pdev) spin_lock_init(&msm_eventq_lock); spin_lock_init(&msm_pid_lock); mutex_init(&ordered_sd_mtx); + mutex_init(&v4l2_event_mtx); INIT_LIST_HEAD(&ordered_sd_list); cam_debugfs_root = debugfs_create_dir(MSM_CAM_LOGSYNC_FILE_BASEDIR, diff --git a/drivers/media/platform/msm/camera_v2/sensor/csid/include/msm_csid_3_5_1_hwreg.h b/drivers/media/platform/msm/camera_v2/sensor/csid/include/msm_csid_3_5_1_hwreg.h new file mode 100644 index 000000000000..13e560dc207d --- /dev/null +++ b/drivers/media/platform/msm/camera_v2/sensor/csid/include/msm_csid_3_5_1_hwreg.h @@ -0,0 +1,64 @@ +/* Copyright (c) 2015, 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_CSID_3_5_1_HWREG_H +#define MSM_CSID_3_5_1_HWREG_H + +#include <sensor/csid/msm_csid.h> + +static uint8_t csid_lane_assign_v3_5_1[PHY_LANE_MAX] = {0, 4, 1, 2, 3}; + +static struct csid_reg_parms_t csid_v3_5_1 = { + /* MIPI CSID registers */ + 0x0, + 0x4, + 0x8, + 0x10, + 0x14, + 0x18, + 0x1C, + 0x20, + 0x24, + 0x64, + 0x68, + 0x6C, + 0x70, + 0x74, + 0x78, + 0x7C, + 0x80, + 0x88, + 0x8C, + 0x90, + 0x94, + 0x98, + 0x9C, + 0xA0, + 0xA8, + 0xAC, + 0xB4, + 0xB8, + 0xBC, + 11, + 0x7FFF, + 0x4, + 17, + 0x30050001, + 0xC, + 0x84, + 0xA4, + 0x7f010800, + 20, + 17, + 16, +}; +#endif diff --git a/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c b/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c index 7ae071176ef4..9473fb0dc44e 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c +++ b/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c @@ -27,6 +27,7 @@ #include "include/msm_csid_3_4_1_hwreg.h" #include "include/msm_csid_3_4_2_hwreg.h" #include "include/msm_csid_3_6_0_hwreg.h" +#include "include/msm_csid_3_5_1_hwreg.h" #include "cam_hw_ops.h" #define V4L2_IDENT_CSID 50002 @@ -44,6 +45,7 @@ #define CSID_VERSION_V36 0x30060000 #define CSID_VERSION_V37 0x30070000 #define CSID_VERSION_V35 0x30050000 +#define CSID_VERSION_V35_1 0x30050001 #define CSID_VERSION_V40 0x40000000 #define CSID_VERSION_V50 0x50000000 #define MSM_CSID_DRV_NAME "msm_csid" @@ -1186,6 +1188,12 @@ static int csid_probe(struct platform_device *pdev) csid_lane_assign_v3_5; new_csid_dev->hw_dts_version = CSID_VERSION_V35; } else if (of_device_is_compatible(new_csid_dev->pdev->dev.of_node, + "qcom,csid-v3.5.1")) { + new_csid_dev->ctrl_reg->csid_reg = csid_v3_5_1; + new_csid_dev->ctrl_reg->csid_lane_assign = + csid_lane_assign_v3_5_1; + new_csid_dev->hw_dts_version = CSID_VERSION_V35_1; + } else if (of_device_is_compatible(new_csid_dev->pdev->dev.of_node, "qcom,csid-v5.0")) { new_csid_dev->ctrl_reg->csid_reg = csid_v3_5; new_csid_dev->ctrl_reg->csid_lane_assign = diff --git a/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c index 8d091320cbca..a8d7c1f8b489 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c +++ b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c @@ -437,6 +437,11 @@ static int msm_csiphy_2phase_lane_config( csiphybase = csiphy_dev->base; lane_mask = csiphy_params->lane_mask & 0x1f; + + lane_enable = msm_camera_io_r(csiphybase + + csiphy_dev->ctrl_reg->csiphy_3ph_reg. + mipi_csiphy_3ph_cmn_ctrl5.addr); + for (i = 0; i < MAX_DPHY_DATA_LN; i++) { if (mask == 0x2) { if (lane_mask & mask) @@ -474,7 +479,11 @@ static int msm_csiphy_2phase_lane_config( clk_lane = 0; } - if (csiphy_params->combo_mode == 1) { + /* In combo mode setting the 4th lane + * as clk_lane for 1 lane sensor, checking + * the lane_mask == 0x18 for one lane sensor + */ + if ((csiphy_params->combo_mode == 1) && (lane_mask == 0x18)) { val |= 0xA; if (mask == csiphy_dev->ctrl_reg-> csiphy_reg.combo_clk_mask) { @@ -520,6 +529,12 @@ static int msm_csiphy_2phase_lane_config( mipi_csiphy_2ph_lnn_cfg4.data, csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. mipi_csiphy_2ph_lnn_cfg4.addr + offset); + if (lane_mask == 0x18) + msm_camera_io_w(0x80, + csiphybase + + csiphy_dev->ctrl_reg->csiphy_3ph_reg. + mipi_csiphy_2ph_lnn_cfg1.addr + offset); + } else { msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg. mipi_csiphy_2ph_lnn_cfg1.data, @@ -540,8 +555,8 @@ static int msm_csiphy_2phase_lane_config( csiphy_dev->ctrl_reg->csiphy_3ph_reg. mipi_csiphy_2ph_lnn_cfg5.addr + offset); } - if (clk_lane == 1 && - csiphy_dev->hw_version == CSIPHY_VERSION_V342) { + if (clk_lane == 1 && lane_mask != 0x18 && + (csiphy_dev->hw_version == CSIPHY_VERSION_V342)) { msm_camera_io_w(0x1f, csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg. 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 167ed5492088..3f180735dd95 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 @@ -1428,8 +1428,8 @@ static int32_t msm_sensor_driver_i2c_probe(struct i2c_client *client, rc); goto FREE_S_CTRL; } - return rc; } + return rc; FREE_S_CTRL: kfree(s_ctrl); return rc; diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c index 08bbed147c86..76e1b60512d0 100644 --- a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c +++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c @@ -2009,6 +2009,18 @@ ioctl32_error: } #endif +static int sde_rotator_ctrl_subscribe_event(struct v4l2_fh *fh, + const struct v4l2_event_subscription *sub) +{ + return -EINVAL; +} + +static int sde_rotator_event_unsubscribe(struct v4l2_fh *fh, + const struct v4l2_event_subscription *sub) +{ + return -EINVAL; +} + /* V4l2 ioctl handlers */ static const struct v4l2_ioctl_ops sde_rotator_ioctl_ops = { .vidioc_querycap = sde_rotator_querycap, @@ -2033,8 +2045,8 @@ static const struct v4l2_ioctl_ops sde_rotator_ioctl_ops = { .vidioc_s_parm = sde_rotator_s_parm, .vidioc_default = sde_rotator_private_ioctl, .vidioc_log_status = v4l2_ctrl_log_status, - .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, - .vidioc_unsubscribe_event = v4l2_event_unsubscribe, + .vidioc_subscribe_event = sde_rotator_ctrl_subscribe_event, + .vidioc_unsubscribe_event = sde_rotator_event_unsubscribe, }; /* diff --git a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c index de5a2dececdf..e81162f3c4ad 100644 --- a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c +++ b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c @@ -456,14 +456,15 @@ static int msm_vidc_probe_vidc_device(struct platform_device *pdev) struct device *dev; int nr = BASE_DEVICE_NUMBER; - core = kzalloc(sizeof(*core), GFP_KERNEL); - if (!core || !vidc_driver) { - dprintk(VIDC_ERR, - "Failed to allocate memory for device core\n"); - rc = -ENOMEM; - goto err_no_mem; + if (!vidc_driver) { + dprintk(VIDC_ERR, "Invalid vidc driver\n"); + return -EINVAL; } + core = kzalloc(sizeof(*core), GFP_KERNEL); + if (!core) + return -ENOMEM; + dev_set_drvdata(&pdev->dev, core); rc = msm_vidc_initialize_core(pdev, core); if (rc) { @@ -628,7 +629,6 @@ err_v4l2_register: err_core_init: dev_set_drvdata(&pdev->dev, NULL); kfree(core); -err_no_mem: return rc; } diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c index c80f535d95e1..5959f61c677c 100644 --- a/drivers/media/platform/msm/vidc/msm_vdec.c +++ b/drivers/media/platform/msm/vidc/msm_vdec.c @@ -1957,6 +1957,8 @@ const struct vb2_ops *msm_vdec_get_vb2q_ops(void) int msm_vdec_inst_init(struct msm_vidc_inst *inst) { int rc = 0; + struct msm_vidc_format *fmt = NULL; + if (!inst) { dprintk(VIDC_ERR, "Invalid input = %pK\n", inst); return -EINVAL; @@ -1964,12 +1966,34 @@ int msm_vdec_inst_init(struct msm_vidc_inst *inst) inst->prop.height[CAPTURE_PORT] = DEFAULT_HEIGHT; inst->prop.width[CAPTURE_PORT] = DEFAULT_WIDTH; inst->prop.num_planes[CAPTURE_PORT] = 2; - inst->fmts[CAPTURE_PORT] = vdec_formats[0]; + + /* By default, initialize CAPTURE port to NV12 format */ + fmt = msm_comm_get_pixel_fmt_fourcc(vdec_formats, + ARRAY_SIZE(vdec_formats), V4L2_PIX_FMT_NV12, + CAPTURE_PORT); + if (!fmt || fmt->type != CAPTURE_PORT) { + dprintk(VIDC_ERR, + "vdec_formats corrupted\n"); + return -EINVAL; + } + memcpy(&inst->fmts[fmt->type], fmt, + sizeof(struct msm_vidc_format)); inst->prop.height[OUTPUT_PORT] = DEFAULT_HEIGHT; inst->prop.width[OUTPUT_PORT] = DEFAULT_WIDTH; inst->prop.num_planes[OUTPUT_PORT] = 1; - inst->fmts[OUTPUT_PORT] = vdec_formats[2]; + + /* By default, initialize OUTPUT port to H264 decoder */ + fmt = msm_comm_get_pixel_fmt_fourcc(vdec_formats, + ARRAY_SIZE(vdec_formats), V4L2_PIX_FMT_H264, + OUTPUT_PORT); + if (!fmt || fmt->type != OUTPUT_PORT) { + dprintk(VIDC_ERR, + "vdec_formats corrupted\n"); + return -EINVAL; + } + memcpy(&inst->fmts[fmt->type], fmt, + sizeof(struct msm_vidc_format)); inst->capability.height.min = MIN_SUPPORTED_HEIGHT; inst->capability.height.max = DEFAULT_HEIGHT; diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c index ec6695a670b0..ebdafd66e590 100644 --- a/drivers/media/platform/msm/vidc/msm_venc.c +++ b/drivers/media/platform/msm/vidc/msm_venc.c @@ -4096,6 +4096,8 @@ const struct v4l2_ctrl_ops *msm_venc_get_ctrl_ops(void) int msm_venc_inst_init(struct msm_vidc_inst *inst) { int rc = 0; + struct msm_vidc_format *fmt = NULL; + if (!inst) { dprintk(VIDC_ERR, "Invalid input = %pK\n", inst); return -EINVAL; @@ -4103,12 +4105,34 @@ int msm_venc_inst_init(struct msm_vidc_inst *inst) inst->prop.height[CAPTURE_PORT] = DEFAULT_HEIGHT; inst->prop.width[CAPTURE_PORT] = DEFAULT_WIDTH; inst->prop.num_planes[CAPTURE_PORT] = 1; - inst->fmts[CAPTURE_PORT] = venc_formats[4]; + + /* By default, initialize CAPTURE port to H264 encoder */ + fmt = msm_comm_get_pixel_fmt_fourcc(venc_formats, + ARRAY_SIZE(venc_formats), V4L2_PIX_FMT_H264, + CAPTURE_PORT); + if (!fmt || fmt->type != CAPTURE_PORT) { + dprintk(VIDC_ERR, + "venc_formats corrupted\n"); + return -EINVAL; + } + memcpy(&inst->fmts[fmt->type], fmt, + sizeof(struct msm_vidc_format)); inst->prop.height[OUTPUT_PORT] = DEFAULT_HEIGHT; inst->prop.width[OUTPUT_PORT] = DEFAULT_WIDTH; inst->prop.num_planes[OUTPUT_PORT] = 1; - inst->fmts[OUTPUT_PORT] = venc_formats[0]; + + /* By default, initialize OUTPUT port to NV12 format */ + fmt = msm_comm_get_pixel_fmt_fourcc(venc_formats, + ARRAY_SIZE(venc_formats), V4L2_PIX_FMT_NV12, + OUTPUT_PORT); + if (!fmt || fmt->type != OUTPUT_PORT) { + dprintk(VIDC_ERR, + "venc_formats corrupted\n"); + return -EINVAL; + } + memcpy(&inst->fmts[fmt->type], fmt, + sizeof(struct msm_vidc_format)); inst->capability.height.min = MIN_SUPPORTED_HEIGHT; inst->capability.height.max = DEFAULT_HEIGHT; diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c index a343bc2d59e4..02bfc459614f 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc.c +++ b/drivers/media/platform/msm/vidc/msm_vidc.c @@ -516,7 +516,6 @@ static inline bool is_dynamic_output_buffer_mode(struct v4l2_buffer *b, inst->buffer_mode_set[CAPTURE_PORT] == HAL_BUFFER_MODE_DYNAMIC; } - static inline void save_v4l2_buffer(struct v4l2_buffer *b, struct buffer_info *binfo) { @@ -529,71 +528,22 @@ static inline void save_v4l2_buffer(struct v4l2_buffer *b, } populate_buf_info(binfo, b, i); } -} - -static int __map_and_update_binfo(struct msm_vidc_inst *inst, - struct buffer_info *binfo, - struct v4l2_buffer *b, u32 i) -{ - int rc = 0; - struct msm_smem *same_fd_handle = NULL; - - if (i >= VIDEO_MAX_PLANES) { - dprintk(VIDC_ERR, "Num planes exceeds max: %d, %d\n", - i, VIDEO_MAX_PLANES); - rc = -EINVAL; - goto exit; - } - - same_fd_handle = get_same_fd_buffer( - inst, b->m.planes[i].reserved[0]); - - if (same_fd_handle) { - binfo->device_addr[i] = - same_fd_handle->device_addr + binfo->buff_off[i]; - b->m.planes[i].m.userptr = binfo->device_addr[i]; - binfo->handle[i] = same_fd_handle; - } else { - binfo->handle[i] = map_buffer(inst, &b->m.planes[i], - get_hal_buffer_type(inst, b)); - if (!binfo->handle[i]) - return -EINVAL; - - binfo->mapped[i] = true; - binfo->device_addr[i] = binfo->handle[i]->device_addr + - binfo->buff_off[i]; - b->m.planes[i].m.userptr = binfo->device_addr[i]; - } - -exit: - return rc; -} - -static int __handle_fw_referenced_buffers(struct msm_vidc_inst *inst, - struct buffer_info *binfo, - struct v4l2_buffer *b) -{ - int rc = 0; - u32 i = 0; if (EXTRADATA_IDX(b->length)) { i = EXTRADATA_IDX(b->length); if (b->m.planes[i].length) - rc = __map_and_update_binfo(inst, binfo, b, i); + binfo->device_addr[i] = binfo->handle[i]->device_addr + + binfo->buff_off[i]; } - - if (rc) - dprintk(VIDC_ERR, "%s: Failed to map extradata\n", __func__); - - return rc; } int map_and_register_buf(struct msm_vidc_inst *inst, struct v4l2_buffer *b) { struct buffer_info *binfo = NULL; struct buffer_info *temp = NULL, *iterator = NULL; - int plane = 0, rc = 0; - u32 i = 0; + int plane = 0; + int i = 0, rc = 0; + struct msm_smem *same_fd_handle = NULL; if (!b || !inst) { dprintk(VIDC_ERR, "%s: invalid input\n", __func__); @@ -669,23 +619,39 @@ int map_and_register_buf(struct msm_vidc_inst *inst, struct v4l2_buffer *b) rc = 0; goto exit; } else if (rc == 2) { - rc = __handle_fw_referenced_buffers(inst, temp, b); - if (!rc) - rc = -EEXIST; + rc = -EEXIST; goto exit; } + same_fd_handle = get_same_fd_buffer( + inst, b->m.planes[i].reserved[0]); + populate_buf_info(binfo, b, i); + if (same_fd_handle) { + binfo->device_addr[i] = + same_fd_handle->device_addr + binfo->buff_off[i]; + b->m.planes[i].m.userptr = binfo->device_addr[i]; + binfo->mapped[i] = false; + binfo->handle[i] = same_fd_handle; + } else { + binfo->handle[i] = map_buffer(inst, &b->m.planes[i], + get_hal_buffer_type(inst, b)); + if (!binfo->handle[i]) { + rc = -EINVAL; + goto exit; + } - rc = __map_and_update_binfo(inst, binfo, b, i); - if (rc) - goto map_err; + binfo->mapped[i] = true; + binfo->device_addr[i] = binfo->handle[i]->device_addr + + binfo->buff_off[i]; + b->m.planes[i].m.userptr = binfo->device_addr[i]; + } /* We maintain one ref count for all planes*/ if (!i && is_dynamic_output_buffer_mode(b, inst)) { rc = buf_ref_get(inst, binfo); if (rc < 0) - goto map_err; + goto exit; } dprintk(VIDC_DBG, "%s: [MAP] binfo = %pK, handle[%d] = %pK, device_addr = %pa, fd = %d, offset = %d, mapped = %d\n", @@ -699,9 +665,6 @@ int map_and_register_buf(struct msm_vidc_inst *inst, struct v4l2_buffer *b) mutex_unlock(&inst->registeredbufs.lock); return 0; -map_err: - if (binfo->handle[0] && binfo->mapped[0]) - msm_comm_smem_free(inst, binfo->handle[0]); exit: kfree(binfo); return rc; @@ -771,7 +734,6 @@ int unmap_and_deregister_buf(struct msm_vidc_inst *inst, temp->handle[i] = 0; temp->device_addr[i] = 0; temp->uvaddr[i] = 0; - temp->mapped[i] = false; } } if (!keep_node) { @@ -786,7 +748,6 @@ exit: return 0; } - int qbuf_dynamic_buf(struct msm_vidc_inst *inst, struct buffer_info *binfo) { diff --git a/drivers/misc/qcom/qdsp6v2/audio_hwacc_effects.c b/drivers/misc/qcom/qdsp6v2/audio_hwacc_effects.c index e602650c4cb5..ebe9ab763a68 100644 --- a/drivers/misc/qcom/qdsp6v2/audio_hwacc_effects.c +++ b/drivers/misc/qcom/qdsp6v2/audio_hwacc_effects.c @@ -161,7 +161,6 @@ static int audio_effects_shared_ioctl(struct file *file, unsigned cmd, pr_err("%s: Read buffer Allocation failed rc = %d\n", __func__, rc); rc = -ENOMEM; - mutex_unlock(&effects->lock); goto readbuf_fail; } atomic_set(&effects->out_count, effects->config.output.num_buf); @@ -176,7 +175,6 @@ static int audio_effects_shared_ioctl(struct file *file, unsigned cmd, if (rc < 0) { pr_err("%s: pcm read block config failed\n", __func__); rc = -EINVAL; - mutex_unlock(&effects->lock); goto cfg_fail; } pr_debug("%s: dec: sample_rate: %d, num_channels: %d, bit_width: %d\n", @@ -191,7 +189,6 @@ static int audio_effects_shared_ioctl(struct file *file, unsigned cmd, pr_err("%s: pcm write format block config failed\n", __func__); rc = -EINVAL; - mutex_unlock(&effects->lock); goto cfg_fail; } @@ -325,6 +322,7 @@ ioctl_fail: readbuf_fail: q6asm_audio_client_buf_free_contiguous(IN, effects->ac); + mutex_unlock(&effects->lock); return rc; cfg_fail: q6asm_audio_client_buf_free_contiguous(IN, @@ -332,6 +330,7 @@ cfg_fail: q6asm_audio_client_buf_free_contiguous(OUT, effects->ac); effects->buf_alloc = 0; + mutex_unlock(&effects->lock); return rc; } diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index 063e00517660..7d2ceda7f80e 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -3170,6 +3170,16 @@ static struct mmc_cmdq_req *mmc_blk_cmdq_rw_prep( return &mqrq->cmdq_req; } +static void mmc_blk_cmdq_requeue_rw_rq(struct mmc_queue *mq, + struct request *req) +{ + struct mmc_card *card = mq->card; + struct mmc_host *host = card->host; + + blk_requeue_request(req->q, req); + mmc_put_card(host->card); +} + static int mmc_blk_cmdq_issue_rw_rq(struct mmc_queue *mq, struct request *req) { struct mmc_queue_req *active_mqrq; @@ -3217,6 +3227,15 @@ static int mmc_blk_cmdq_issue_rw_rq(struct mmc_queue *mq, struct request *req) wait_event_interruptible(ctx->queue_empty_wq, (!ctx->active_reqs)); + if (ret) { + /* clear pending request */ + WARN_ON(!test_and_clear_bit(req->tag, + &host->cmdq_ctx.data_active_reqs)); + WARN_ON(!test_and_clear_bit(req->tag, + &host->cmdq_ctx.active_reqs)); + mmc_cmdq_clk_scaling_stop_busy(host, true, false); + } + return ret; } @@ -4042,6 +4061,13 @@ static int mmc_blk_cmdq_issue_rq(struct mmc_queue *mq, struct request *req) ret = mmc_blk_cmdq_issue_flush_rq(mq, req); } else { ret = mmc_blk_cmdq_issue_rw_rq(mq, req); + /* + * If issuing of the request fails with eitehr EBUSY or + * EAGAIN error, re-queue the request. + * This case would occur with ICE calls. + */ + if (ret == -EBUSY || ret == -EAGAIN) + mmc_blk_cmdq_requeue_rw_rq(mq, req); } } diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index cfd56d9fa2ca..8c6861564ed2 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -1166,9 +1166,11 @@ static int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) return 0; } -static void mmc_start_cmdq_request(struct mmc_host *host, +static int mmc_start_cmdq_request(struct mmc_host *host, struct mmc_request *mrq) { + int ret = 0; + if (mrq->data) { pr_debug("%s: blksz %d blocks %d flags %08x tsac %lu ms nsac %d\n", mmc_hostname(host), mrq->data->blksz, @@ -1190,11 +1192,21 @@ static void mmc_start_cmdq_request(struct mmc_host *host, } mmc_host_clk_hold(host); - if (likely(host->cmdq_ops->request)) - host->cmdq_ops->request(host, mrq); - else - pr_err("%s: %s: issue request failed\n", mmc_hostname(host), - __func__); + if (likely(host->cmdq_ops->request)) { + ret = host->cmdq_ops->request(host, mrq); + } else { + ret = -ENOENT; + pr_err("%s: %s: cmdq request host op is not available\n", + mmc_hostname(host), __func__); + } + + if (ret) { + mmc_host_clk_release(host); + pr_err("%s: %s: issue request failed, err=%d\n", + mmc_hostname(host), __func__, ret); + } + + return ret; } /** @@ -1681,8 +1693,7 @@ int mmc_cmdq_start_req(struct mmc_host *host, struct mmc_cmdq_req *cmdq_req) mrq->cmd->error = -ENOMEDIUM; return -ENOMEDIUM; } - mmc_start_cmdq_request(host, mrq); - return 0; + return mmc_start_cmdq_request(host, mrq); } EXPORT_SYMBOL(mmc_cmdq_start_req); diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index 21836eac001e..65d7dbe1dea4 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -1159,6 +1159,8 @@ static void mmc_sd_detect(struct mmc_host *host) return; } + mmc_power_up(host, host->ocr_avail); + /* * Just check if our card has been removed. */ diff --git a/drivers/mmc/host/cmdq_hci.c b/drivers/mmc/host/cmdq_hci.c index 3f741f83a436..83d24fcaf2ab 100644 --- a/drivers/mmc/host/cmdq_hci.c +++ b/drivers/mmc/host/cmdq_hci.c @@ -805,7 +805,7 @@ static int cmdq_request(struct mmc_host *mmc, struct mmc_request *mrq) if (err) { pr_err("%s: failed to configure crypto: err %d tag %d\n", mmc_hostname(mmc), err, tag); - goto out; + goto ice_err; } } @@ -823,7 +823,7 @@ static int cmdq_request(struct mmc_host *mmc, struct mmc_request *mrq) if (err) { pr_err("%s: %s: failed to setup tx desc: %d\n", mmc_hostname(mmc), __func__, err); - goto out; + goto desc_err; } cq_host->mrq_slot[tag] = mrq; @@ -843,6 +843,22 @@ ring_doorbell: /* Commit the doorbell write immediately */ wmb(); + return err; + +desc_err: + if (cq_host->ops->crypto_cfg_end) { + err = cq_host->ops->crypto_cfg_end(mmc, mrq); + if (err) { + pr_err("%s: failed to end ice config: err %d tag %d\n", + mmc_hostname(mmc), err, tag); + } + } + if (!(cq_host->caps & CMDQ_CAP_CRYPTO_SUPPORT) && + cq_host->ops->crypto_cfg_reset) + cq_host->ops->crypto_cfg_reset(mmc, tag); +ice_err: + if (err) + cmdq_runtime_pm_put(cq_host); out: return err; } diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 8b8bea5d546a..55033aed6d6b 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -1304,6 +1304,9 @@ static int ath10k_core_fetch_firmware_files(struct ath10k *ar) fw_file = &ar->normal_mode_fw.fw_file; fw_file->wmi_op_version = ATH10K_FW_WMI_OP_VERSION_TLV; fw_file->htt_op_version = ATH10K_FW_HTT_OP_VERSION_TLV; + __set_bit(ATH10K_FW_FEATURE_WOWLAN_SUPPORT, + fw_file->fw_features); + __set_bit(WMI_SERVICE_WOW, ar->wmi.svc_map); return 0; } diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index ffcf30756b9e..f194d434b97c 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -24,6 +24,7 @@ #include <linux/pci.h> #include <linux/uuid.h> #include <linux/time.h> +#include <linux/inetdevice.h> #include <soc/qcom/socinfo.h> #include "htt.h" @@ -430,6 +431,8 @@ struct ath10k_vif { struct work_struct ap_csa_work; struct delayed_work connection_loss_work; struct cfg80211_bitrate_mask bitrate_mask; + struct wmi_ns_arp_offload_req arp_offload; + struct wmi_ns_arp_offload_req ns_offload; }; struct ath10k_vif_iter { diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c index c01f59955797..aa20ebbefe94 100644 --- a/drivers/net/wireless/ath/ath10k/htc.c +++ b/drivers/net/wireless/ath/ath10k/htc.c @@ -86,7 +86,8 @@ static void ath10k_htc_prepare_tx_skb(struct ath10k_htc_ep *ep, hdr->eid = ep->eid; hdr->len = __cpu_to_le16(skb->len - sizeof(*hdr)); hdr->flags = 0; - hdr->flags |= ATH10K_HTC_FLAG_NEED_CREDIT_UPDATE; + if (ep->tx_credit_flow_enabled) + hdr->flags |= ATH10K_HTC_FLAG_NEED_CREDIT_UPDATE; spin_lock_bh(&ep->htc->tx_lock); hdr->seq_no = ep->seq_no++; diff --git a/drivers/net/wireless/ath/ath10k/hw.c b/drivers/net/wireless/ath/ath10k/hw.c index 1d37b2c8426b..caf63b8bbba4 100644 --- a/drivers/net/wireless/ath/ath10k/hw.c +++ b/drivers/net/wireless/ath/ath10k/hw.c @@ -509,6 +509,7 @@ const struct ath10k_hw_values wcn3990_values = { .num_target_ce_config_wlan = 12, .ce_desc_meta_data_mask = 0xFFF0, .ce_desc_meta_data_lsb = 4, + .default_listen_interval = 1, }; struct fw_flag wcn3990_fw_flags = { diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index e0af0f766b02..8aa696ed2e72 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -369,6 +369,7 @@ struct ath10k_hw_values { u8 num_target_ce_config_wlan; u16 ce_desc_meta_data_mask; u8 ce_desc_meta_data_lsb; + u8 default_listen_interval; }; extern const struct ath10k_hw_values qca988x_values; diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 5a84626dff14..9fcc2866d830 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -1387,6 +1387,10 @@ static int ath10k_vdev_start_restart(struct ath10k_vif *arvif, lockdep_assert_held(&ar->conf_mutex); + /* Clear arp and ns offload cache */ + memset(&arvif->arp_offload, 0, sizeof(arvif->arp_offload)); + memset(&arvif->ns_offload, 0, sizeof(arvif->ns_offload)); + reinit_completion(&ar->vdev_setup_done); reinit_completion(&ar->vdev_delete_done); @@ -7578,6 +7582,7 @@ static const struct ieee80211_ops ath10k_ops = { #ifdef CONFIG_PM .suspend = ath10k_wow_op_suspend, .resume = ath10k_wow_op_resume, + .set_wakeup = ath10k_wow_op_set_wakeup, #endif #ifdef CONFIG_MAC80211_DEBUGFS .sta_add_debugfs = ath10k_sta_add_debugfs, diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c index c42d7eebf465..a1a4812feeed 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.c +++ b/drivers/net/wireless/ath/ath10k/snoc.c @@ -30,7 +30,8 @@ #include <linux/regulator/consumer.h> #include <linux/clk.h> -#define WCN3990_MAX_IRQ 12 +#define WCN3990_MAX_IRQ 12 +#define WCN3990_WAKE_IRQ_CE 2 const char *ce_name[WCN3990_MAX_IRQ] = { "WLAN_CE_0", @@ -1161,7 +1162,8 @@ static int ath10k_snoc_hif_power_up(struct ath10k *ar) atomic_set(&ar_snoc->pm_ops_inprogress, 0); } - if (ar->state == ATH10K_STATE_ON || + if ((ar->state == ATH10K_STATE_ON) || + (ar->state == ATH10K_STATE_RESTARTING) || test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags)) { ret = ath10k_snoc_bus_configure(ar); if (ret) { @@ -1571,6 +1573,50 @@ static int ath10k_hw_power_off(struct ath10k *ar) return ret; } +static int ath10k_snoc_hif_suspend(struct ath10k *ar) +{ + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + int ret = 0; + + if (!ar_snoc) + return -EINVAL; + + if (!device_may_wakeup(ar->dev)) + return -EINVAL; + + ret = enable_irq_wake(ar_snoc->ce_irqs[WCN3990_WAKE_IRQ_CE].irq_line); + if (ret) { + ath10k_dbg(ar, ATH10K_DBG_SNOC, + "HIF Suspend: Failed to enable wakeup IRQ\n"); + return ret; + } + + ath10k_dbg(ar, ATH10K_DBG_SNOC, "HIF Suspended\n"); + return ret; +} + +static int ath10k_snoc_hif_resume(struct ath10k *ar) +{ + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + int ret = 0; + + if (!ar_snoc) + return -EINVAL; + + if (!device_may_wakeup(ar->dev)) + return -EINVAL; + + ret = disable_irq_wake(ar_snoc->ce_irqs[WCN3990_WAKE_IRQ_CE].irq_line); + if (ret) { + ath10k_dbg(ar, ATH10K_DBG_SNOC, + "HIF Resume: Failed to disable wakeup IRQ\n"); + return ret; + } + + ath10k_dbg(ar, ATH10K_DBG_SNOC, "HIF Resumed\n"); + return ret; +} + static const struct ath10k_hif_ops ath10k_snoc_hif_ops = { .tx_sg = ath10k_snoc_hif_tx_sg, .start = ath10k_snoc_hif_start, @@ -1583,6 +1629,8 @@ static const struct ath10k_hif_ops ath10k_snoc_hif_ops = { .power_down = ath10k_snoc_hif_power_down, .read32 = ath10k_snoc_read32, .write32 = ath10k_snoc_write32, + .suspend = ath10k_snoc_hif_suspend, + .resume = ath10k_snoc_hif_resume, }; static const struct ath10k_bus_ops ath10k_snoc_bus_ops = { diff --git a/drivers/net/wireless/ath/ath10k/wmi-ops.h b/drivers/net/wireless/ath/ath10k/wmi-ops.h index 8bb01c1a35f7..dcb0da51530a 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-ops.h +++ b/drivers/net/wireless/ath/ath10k/wmi-ops.h @@ -160,6 +160,8 @@ struct wmi_ops { u32 num_ac); struct sk_buff *(*gen_sta_keepalive)(struct ath10k *ar, const struct wmi_sta_keepalive_arg *arg); + struct sk_buff *(*gen_set_arp_ns_offload)(struct ath10k *ar, + struct ath10k_vif *arvif); struct sk_buff *(*gen_wow_enable)(struct ath10k *ar); struct sk_buff *(*gen_wow_add_wakeup_event)(struct ath10k *ar, u32 vdev_id, enum wmi_wow_wakeup_event event, @@ -1187,6 +1189,23 @@ ath10k_wmi_sta_keepalive(struct ath10k *ar, } static inline int +ath10k_wmi_set_arp_ns_offload(struct ath10k *ar, struct ath10k_vif *arvif) +{ + struct sk_buff *skb; + u32 cmd_id; + + if (!ar->wmi.ops->gen_set_arp_ns_offload) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_set_arp_ns_offload(ar, arvif); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + cmd_id = ar->wmi.cmd->set_arp_ns_offload_cmdid; + return ath10k_wmi_cmd_send(ar, skb, cmd_id); +} + +static inline int ath10k_wmi_wow_enable(struct ath10k *ar) { struct sk_buff *skb; diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index f5360444a083..aeeccade58b9 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -3010,6 +3010,83 @@ ath10k_wmi_tlv_op_gen_tdls_peer_update(struct ath10k *ar, } static struct sk_buff * +ath10k_wmi_tlv_op_gen_set_arp_ns_offload(struct ath10k *ar, + struct ath10k_vif *arvif) +{ + struct wmi_tlv_arp_ns_offload_cmd *cmd; + struct wmi_tlv *tlv; + struct sk_buff *skb; + size_t len; + void *ptr; + int i; + struct wmi_ns_arp_offload_req *arp = &arvif->arp_offload; + struct wmi_ns_offload *ns_tuple; + struct wmi_arp_offload *arp_tuple; + + len = sizeof(*cmd) + sizeof(*tlv) + + sizeof(*tlv) + WMI_MAX_NS_OFFLOADS * + (sizeof(struct wmi_ns_offload) + sizeof(*tlv)) + + sizeof(*tlv) + WMI_MAX_ARP_OFFLOADS * + (sizeof(struct wmi_arp_offload) + sizeof(*tlv)); + + skb = ath10k_wmi_alloc_skb(ar, len); + if (!skb) + return ERR_PTR(-ENOMEM); + + ptr = (void *)skb->data; + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_SET_ARP_NS_OFFLOAD_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (struct wmi_tlv_arp_ns_offload_cmd *)tlv->value; + cmd->flags = __cpu_to_le32(0); + cmd->vdev_id = __cpu_to_le32(arvif->vdev_id); + + ptr += (sizeof(*tlv) + sizeof(*cmd)); + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_STRUCT); + tlv->len = __cpu_to_le16(WMI_MAX_NS_OFFLOADS * + (sizeof(struct wmi_ns_offload) + sizeof(*tlv))); + ptr += sizeof(*tlv); + tlv = ptr; + + for (i = 0; i < WMI_MAX_NS_OFFLOADS; i++) { + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_NS_OFFLOAD_TUPLE); + tlv->len = __cpu_to_le16(sizeof(struct wmi_ns_offload)); + ns_tuple = (struct wmi_ns_offload *)tlv->value; + ns_tuple->flags |= __cpu_to_le32(WMI_ARP_NS_OFFLOAD_DISABLE); + ptr += (sizeof(*tlv) + sizeof(struct wmi_ns_offload)); + tlv = ptr; + } + + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_STRUCT); + tlv->len = __cpu_to_le16(WMI_MAX_ARP_OFFLOADS * + (sizeof(struct wmi_arp_offload) + sizeof(*tlv))); + ptr += sizeof(*tlv); + tlv = ptr; + + for (i = 0; i < WMI_MAX_ARP_OFFLOADS; i++) { + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_ARP_OFFLOAD_TUPLE); + tlv->len = __cpu_to_le16(sizeof(struct wmi_arp_offload)); + arp_tuple = (struct wmi_arp_offload *)tlv->value; + if (arp->enable_offload && (i == 0)) { + arp_tuple->flags |= + __cpu_to_le32(WMI_ARPOFF_FLAGS_VALID); + memcpy(&arp_tuple->target_ipaddr, + &arp->params.ipv4_addr, + sizeof(arp_tuple->target_ipaddr)); + } else { + arp_tuple->flags |= + __cpu_to_le32(WMI_ARP_NS_OFFLOAD_DISABLE); + } + ptr += (sizeof(*tlv) + sizeof(struct wmi_arp_offload)); + tlv = ptr; + } + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv set arp ns offload\n"); + return skb; +} + +static struct sk_buff * ath10k_wmi_tlv_op_gen_wow_enable(struct ath10k *ar) { struct wmi_tlv_wow_enable_cmd *cmd; @@ -3028,6 +3105,8 @@ ath10k_wmi_tlv_op_gen_wow_enable(struct ath10k *ar) cmd = (void *)tlv->value; cmd->enable = __cpu_to_le32(1); + if (QCA_REV_WCN3990(ar)) + cmd->pause_iface_config = __cpu_to_le32(1); ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv wow enable\n"); return skb; @@ -3693,6 +3772,7 @@ static const struct wmi_ops wmi_tlv_ops = { .gen_p2p_go_bcn_ie = ath10k_wmi_tlv_op_gen_p2p_go_bcn_ie, .gen_vdev_sta_uapsd = ath10k_wmi_tlv_op_gen_vdev_sta_uapsd, .gen_sta_keepalive = ath10k_wmi_tlv_op_gen_sta_keepalive, + .gen_set_arp_ns_offload = ath10k_wmi_tlv_op_gen_set_arp_ns_offload, .gen_wow_enable = ath10k_wmi_tlv_op_gen_wow_enable, .gen_wow_add_wakeup_event = ath10k_wmi_tlv_op_gen_wow_add_wakeup_event, .gen_wow_host_wakeup_ind = ath10k_wmi_tlv_gen_wow_host_wakeup_ind, diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.h b/drivers/net/wireless/ath/ath10k/wmi-tlv.h index 500d1d8f441f..1d4aed14fbb4 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.h +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.h @@ -1554,6 +1554,13 @@ struct wmi_tlv_wow_add_del_event_cmd { struct wmi_tlv_wow_enable_cmd { __le32 enable; + __le32 pause_iface_config; +} __packed; + +struct wmi_tlv_arp_ns_offload_cmd { + __le32 flags; + __le32 vdev_id; + __le32 num_ns_ext_tuples; } __packed; struct wmi_tlv_wow_host_wakeup_ind { diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index f59e5f86708b..9b17ef150303 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -20,6 +20,8 @@ #include <linux/types.h> #include <net/mac80211.h> +#include <linux/ipv6.h> +#include <linux/in.h> /* * This file specifies the WMI interface for the Unified Software @@ -2884,6 +2886,53 @@ struct wmi_start_scan_common { __le32 scan_ctrl_flags; } __packed; +/* ARP-NS offload data structure */ +#define WMI_NSOFF_MAX_TARGET_IPS 2 +#define WMI_MAX_NS_OFFLOADS 2 +#define WMI_MAX_ARP_OFFLOADS 2 +#define WMI_ARPOFF_FLAGS_VALID BIT(0) +#define WMI_IPV4_ARP_REPLY_OFFLOAD 0 +#define WMI_ARP_NS_OFFLOAD_DISABLE 0 +#define WMI_ARP_NS_OFFLOAD_ENABLE 1 + +struct wmi_ns_offload_info { + struct in6_addr src_addr; + struct in6_addr self_addr[TARGET_NUM_STATIONS]; + struct in6_addr target_addr[TARGET_NUM_STATIONS]; + struct wmi_mac_addr self_macaddr; + u8 src_ipv6_addr_valid; + struct in6_addr target_addr_valid; + struct in6_addr target_addr_ac_type; + u8 slot_idx; +} __packed; + +struct wmi_ns_arp_offload_req { + u8 offload_type; + u8 enable_offload; + __le32 num_ns_offload_count; + union { + struct in_addr ipv4_addr; + struct in6_addr ipv6_addr; + } params; + struct wmi_ns_offload_info offload_info; + struct wmi_mac_addr bssid; +} __packed; + +struct wmi_ns_offload { + __le32 flags; + struct in6_addr target_ipaddr[WMI_NSOFF_MAX_TARGET_IPS]; + struct in6_addr solicitation_ipaddr; + struct in6_addr remote_ipaddr; + struct wmi_mac_addr target_mac; +} __packed; + +struct wmi_arp_offload { + __le32 flags; + struct in_addr target_ipaddr; + struct in_addr remote_ipaddr; + struct wmi_mac_addr target_mac; +} __packed; + struct wmi_start_scan_tlvs { /* TLV parameters. These includes channel list, ssid list, bssid list, * extra ies. diff --git a/drivers/net/wireless/ath/ath10k/wow.c b/drivers/net/wireless/ath/ath10k/wow.c index 77100d42f401..429fcce3dd1e 100644 --- a/drivers/net/wireless/ath/ath10k/wow.c +++ b/drivers/net/wireless/ath/ath10k/wow.c @@ -224,6 +224,102 @@ static int ath10k_wow_wakeup(struct ath10k *ar) return 0; } +static int +ath10k_wow_fill_vdev_arp_offload_struct(struct ath10k_vif *arvif, + bool enable_offload) +{ + struct in_device *in_dev; + struct in_ifaddr *ifa; + bool offload_params_found = false; + struct wireless_dev *wdev = ieee80211_vif_to_wdev(arvif->vif); + struct wmi_ns_arp_offload_req *arp = &arvif->arp_offload; + + if (!enable_offload) { + arp->offload_type = __cpu_to_le16(WMI_IPV4_ARP_REPLY_OFFLOAD); + arp->enable_offload = __cpu_to_le16(WMI_ARP_NS_OFFLOAD_DISABLE); + return 0; + } + + if (!wdev) + return -ENODEV; + if (!wdev->netdev) + return -ENODEV; + in_dev = __in_dev_get_rtnl(wdev->netdev); + if (!in_dev) + return -ENODEV; + + arp->offload_type = __cpu_to_le16(WMI_IPV4_ARP_REPLY_OFFLOAD); + arp->enable_offload = __cpu_to_le16(WMI_ARP_NS_OFFLOAD_ENABLE); + for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) { + if (!memcmp(ifa->ifa_label, wdev->netdev->name, IFNAMSIZ)) { + offload_params_found = true; + break; + } + } + + if (!offload_params_found) + return -ENODEV; + memcpy(&arp->params.ipv4_addr, &ifa->ifa_local, + sizeof(arp->params.ipv4_addr)); + + return 0; +} + +static int ath10k_wow_enable_ns_arp_offload(struct ath10k *ar, bool offload) +{ + struct ath10k_vif *arvif; + int ret; + + list_for_each_entry(arvif, &ar->arvifs, list) { + if (arvif->vdev_type != WMI_VDEV_TYPE_STA) + continue; + + if (!arvif->is_up) + continue; + + ret = ath10k_wow_fill_vdev_arp_offload_struct(arvif, offload); + if (ret) { + ath10k_err(ar, "ARP-offload config failed, vdev: %d\n", + arvif->vdev_id); + return ret; + } + + ret = ath10k_wmi_set_arp_ns_offload(ar, arvif); + if (ret) { + ath10k_err(ar, "failed to send offload cmd, vdev: %d\n", + arvif->vdev_id); + return ret; + } + } + + return 0; +} + +static int ath10k_config_wow_listen_interval(struct ath10k *ar) +{ + int ret; + u32 param = ar->wmi.vdev_param->listen_interval; + u8 listen_interval = ar->hw_values->default_listen_interval; + struct ath10k_vif *arvif; + + if (!listen_interval) + return 0; + + list_for_each_entry(arvif, &ar->arvifs, list) { + if (arvif->vdev_type != WMI_VDEV_TYPE_STA) + continue; + ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, + param, listen_interval); + if (ret) { + ath10k_err(ar, "failed to config LI for vdev_id: %d\n", + arvif->vdev_id); + return ret; + } + } + + return 0; +} + int ath10k_wow_op_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) { @@ -238,11 +334,17 @@ int ath10k_wow_op_suspend(struct ieee80211_hw *hw, goto exit; } + ret = ath10k_wow_enable_ns_arp_offload(ar, true); + if (ret) { + ath10k_warn(ar, "failed to enable ARP-NS offload: %d\n", ret); + goto exit; + } + ret = ath10k_wow_cleanup(ar); if (ret) { ath10k_warn(ar, "failed to clear wow wakeup events: %d\n", ret); - goto exit; + goto disable_ns_arp_offload; } ret = ath10k_wow_set_wakeups(ar, wowlan); @@ -252,6 +354,13 @@ int ath10k_wow_op_suspend(struct ieee80211_hw *hw, goto cleanup; } + ret = ath10k_config_wow_listen_interval(ar); + if (ret) { + ath10k_warn(ar, "failed to config wow listen interval: %d\n", + ret); + goto cleanup; + } + ret = ath10k_wow_enable(ar); if (ret) { ath10k_warn(ar, "failed to start wow: %d\n", ret); @@ -272,11 +381,26 @@ wakeup: cleanup: ath10k_wow_cleanup(ar); +disable_ns_arp_offload: + ath10k_wow_enable_ns_arp_offload(ar, false); + exit: mutex_unlock(&ar->conf_mutex); return ret ? 1 : 0; } +void ath10k_wow_op_set_wakeup(struct ieee80211_hw *hw, bool enabled) +{ + struct ath10k *ar = hw->priv; + + mutex_lock(&ar->conf_mutex); + if (test_bit(ATH10K_FW_FEATURE_WOWLAN_SUPPORT, + ar->running_fw->fw_file.fw_features)) { + device_set_wakeup_enable(ar->dev, enabled); + } + mutex_unlock(&ar->conf_mutex); +} + int ath10k_wow_op_resume(struct ieee80211_hw *hw) { struct ath10k *ar = hw->priv; @@ -297,8 +421,14 @@ int ath10k_wow_op_resume(struct ieee80211_hw *hw) } ret = ath10k_wow_wakeup(ar); - if (ret) + if (ret) { ath10k_warn(ar, "failed to wakeup from wow: %d\n", ret); + goto exit; + } + + ret = ath10k_wow_enable_ns_arp_offload(ar, false); + if (ret) + ath10k_warn(ar, "failed to disable ARP-NS offload: %d\n", ret); exit: if (ret) { @@ -336,5 +466,7 @@ int ath10k_wow_init(struct ath10k *ar) ar->wow.wowlan_support.n_patterns = ar->wow.max_num_patterns; ar->hw->wiphy->wowlan = &ar->wow.wowlan_support; + device_set_wakeup_capable(ar->dev, true); + return 0; } diff --git a/drivers/net/wireless/ath/ath10k/wow.h b/drivers/net/wireless/ath/ath10k/wow.h index abbb04b6d1bd..9745b9ddc7f5 100644 --- a/drivers/net/wireless/ath/ath10k/wow.h +++ b/drivers/net/wireless/ath/ath10k/wow.h @@ -28,6 +28,7 @@ int ath10k_wow_init(struct ath10k *ar); int ath10k_wow_op_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan); int ath10k_wow_op_resume(struct ieee80211_hw *hw); +void ath10k_wow_op_set_wakeup(struct ieee80211_hw *hw, bool enabled); #else diff --git a/drivers/net/wireless/cnss2/pci.c b/drivers/net/wireless/cnss2/pci.c index 8d34d74477eb..9bf4c7e11c66 100644 --- a/drivers/net/wireless/cnss2/pci.c +++ b/drivers/net/wireless/cnss2/pci.c @@ -129,9 +129,10 @@ int cnss_suspend_pci_link(struct cnss_pci_data *pci_priv) pci_disable_device(pci_priv->pci_dev); - ret = pci_set_power_state(pci_priv->pci_dev, PCI_D3hot); - if (ret) - cnss_pr_err("Failed to set D3Hot, err = %d\n", ret); + if (pci_priv->pci_dev->device != QCA6174_DEVICE_ID) { + if (pci_set_power_state(pci_priv->pci_dev, PCI_D3hot)) + cnss_pr_err("Failed to set D3Hot, err = %d\n", ret); + } ret = cnss_set_pci_link(pci_priv, PCI_LINK_DOWN); if (ret) diff --git a/drivers/platform/msm/gpio-usbdetect.c b/drivers/platform/msm/gpio-usbdetect.c index adf47fc32548..1628253fb545 100644 --- a/drivers/platform/msm/gpio-usbdetect.c +++ b/drivers/platform/msm/gpio-usbdetect.c @@ -49,8 +49,8 @@ static irqreturn_t gpio_usbdetect_vbus_irq(int irq, void *data) usb->vbus_state = gpio_get_value(usb->gpio); if (usb->vbus_state) { dev_dbg(&usb->pdev->dev, "setting vbus notification\n"); - extcon_set_cable_state_(usb->extcon_dev, EXTCON_USB, 1); extcon_set_cable_state_(usb->extcon_dev, EXTCON_USB_SPEED, 1); + extcon_set_cable_state_(usb->extcon_dev, EXTCON_USB, 1); } else { dev_dbg(&usb->pdev->dev, "setting vbus removed notification\n"); extcon_set_cable_state_(usb->extcon_dev, EXTCON_USB, 0); @@ -85,8 +85,8 @@ static irqreturn_t gpio_usbdetect_id_irq_thread(int irq, void *data) } else { dev_dbg(&usb->pdev->dev, "starting usb HOST\n"); disable_irq(usb->vbus_det_irq); - extcon_set_cable_state_(usb->extcon_dev, EXTCON_USB_HOST, 1); extcon_set_cable_state_(usb->extcon_dev, EXTCON_USB_SPEED, 1); + extcon_set_cable_state_(usb->extcon_dev, EXTCON_USB_HOST, 1); } return IRQ_HANDLED; } diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_flt.c b/drivers/platform/msm/ipa/ipa_v2/ipa_flt.c index 72542bf6dd5d..c0af295c7362 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_flt.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_flt.c @@ -23,10 +23,10 @@ static int ipa_generate_hw_rule_from_eq( const struct ipa_ipfltri_rule_eq *attrib, u8 **buf) { - int num_offset_meq_32 = attrib->num_offset_meq_32; - int num_ihl_offset_range_16 = attrib->num_ihl_offset_range_16; - int num_ihl_offset_meq_32 = attrib->num_ihl_offset_meq_32; - int num_offset_meq_128 = attrib->num_offset_meq_128; + uint8_t num_offset_meq_32 = attrib->num_offset_meq_32; + uint8_t num_ihl_offset_range_16 = attrib->num_ihl_offset_range_16; + uint8_t num_ihl_offset_meq_32 = attrib->num_ihl_offset_meq_32; + uint8_t num_offset_meq_128 = attrib->num_offset_meq_128; int i; if (attrib->tos_eq_present) { diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_qmi_service.c b/drivers/platform/msm/ipa/ipa_v2/ipa_qmi_service.c index 119d17cae9f5..e33d0d86ac95 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_qmi_service.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_qmi_service.c @@ -512,6 +512,7 @@ int qmi_filter_request_send(struct ipa_install_fltr_rule_req_msg_v01 *req) struct ipa_install_fltr_rule_resp_msg_v01 resp; struct msg_desc req_desc, resp_desc; int rc; + int i; /* check if the filter rules from IPACM is valid */ if (req->filter_spec_list_len == 0) { @@ -521,6 +522,38 @@ int qmi_filter_request_send(struct ipa_install_fltr_rule_req_msg_v01 *req) req->filter_spec_list_len); } + if (req->filter_spec_list_len >= QMI_IPA_MAX_FILTERS_V01) { + IPAWANDBG( + "IPACM passes the number of filtering rules exceed limit\n"); + return -EINVAL; + } else if (req->source_pipe_index_valid != 0) { + IPAWANDBG( + "IPACM passes source_pipe_index_valid not zero 0 != %d\n", + req->source_pipe_index_valid); + return -EINVAL; + } else if (req->source_pipe_index >= ipa_ctx->ipa_num_pipes) { + IPAWANDBG( + "IPACM passes source pipe index not valid ID = %d\n", + req->source_pipe_index); + return -EINVAL; + } + for (i = 0; i < req->filter_spec_list_len; i++) { + if ((req->filter_spec_list[i].ip_type != + QMI_IPA_IP_TYPE_V4_V01) && + (req->filter_spec_list[i].ip_type != + QMI_IPA_IP_TYPE_V6_V01)) + return -EINVAL; + if (req->filter_spec_list[i].is_mux_id_valid == false) + return -EINVAL; + if (req->filter_spec_list[i].is_routing_table_index_valid + == false) + return -EINVAL; + if ((req->filter_spec_list[i].filter_action <= + QMI_IPA_FILTER_ACTION_INVALID_V01) && + (req->filter_spec_list[i].filter_action > + QMI_IPA_FILTER_ACTION_EXCEPTION_V01)) + return -EINVAL; + } mutex_lock(&ipa_qmi_lock); if (ipa_qmi_ctx != NULL) { /* cache the qmi_filter_request */ @@ -675,6 +708,27 @@ int qmi_filter_notify_send(struct ipa_fltr_installed_notif_req_msg_v01 *req) return -EINVAL; } + if (req->install_status != IPA_QMI_RESULT_SUCCESS_V01) { + IPAWANERR(" UL filter rule for pipe %d install_status = %d\n", + req->source_pipe_index, req->install_status); + return -EINVAL; + } else if (req->source_pipe_index >= ipa_ctx->ipa_num_pipes) { + IPAWANERR("IPACM passes source pipe index not valid ID = %d\n", + req->source_pipe_index); + return -EINVAL; + } else if (((req->embedded_pipe_index_valid != true) || + (req->embedded_call_mux_id_valid != true)) && + ((req->embedded_pipe_index_valid != false) || + (req->embedded_call_mux_id_valid != false))) { + IPAWANERR( + "IPACM passes embedded pipe and mux valid not valid\n"); + return -EINVAL; + } else if (req->embedded_pipe_index >= ipa_ctx->ipa_num_pipes) { + IPAWANERR("IPACM passes source pipe index not valid ID = %d\n", + req->source_pipe_index); + return -EINVAL; + } + mutex_lock(&ipa_qmi_lock); if (ipa_qmi_ctx != NULL) { /* cache the qmi_filter_request */ diff --git a/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c index 23e4d2b0d6e8..b158b2b1c326 100644 --- a/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c +++ b/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c @@ -649,6 +649,8 @@ static int wwan_add_ul_flt_rule_to_ipa(void) return -ENOMEM; } + memset(req, 0, sizeof(struct ipa_fltr_installed_notif_req_msg_v01)); + param->commit = 1; param->ep = IPA_CLIENT_APPS_LAN_WAN_PROD; param->global = false; @@ -1517,8 +1519,8 @@ static int ipa_wwan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) /* Get driver name */ case RMNET_IOCTL_GET_DRIVER_NAME: memcpy(&extend_ioctl_data.u.if_name, - ipa_netdevs[0]->name, - sizeof(IFNAMSIZ)); + ipa_netdevs[0]->name, IFNAMSIZ); + extend_ioctl_data.u.if_name[IFNAMSIZ - 1] = '\0'; if (copy_to_user((u8 *)ifr->ifr_ifru.ifru_data, &extend_ioctl_data, sizeof(struct rmnet_ioctl_extended_s))) @@ -1664,6 +1666,7 @@ static int ipa_wwan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) sizeof(wan_msg->upstream_ifname); strlcpy(wan_msg->upstream_ifname, extend_ioctl_data.u.if_name, len); + wan_msg->upstream_ifname[len - 1] = '\0'; memset(&msg_meta, 0, sizeof(struct ipa_msg_meta)); msg_meta.msg_type = WAN_XLAT_CONNECT; msg_meta.msg_len = sizeof(struct ipa_wan_msg); diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c index e9fd1560b1e8..a869b6419e5e 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c @@ -4306,6 +4306,7 @@ static int ipa3_post_init(const struct ipa3_plat_drv_res *resource_p, ipa3_register_panic_hdlr(); ipa3_ctx->q6_proxy_clk_vote_valid = true; + ipa3_ctx->q6_proxy_clk_vote_cnt++; mutex_lock(&ipa3_ctx->lock); ipa3_ctx->ipa_initialization_complete = true; @@ -4413,6 +4414,9 @@ static ssize_t ipa3_write(struct file *file, const char __user *buf, return -EFAULT; } + if (count > 0) + dbg_buff[count - 1] = '\0'; + /* Prevent consequent calls from trying to load the FW again. */ if (ipa3_is_ready()) return count; @@ -4887,6 +4891,7 @@ static int ipa3_pre_init(const struct ipa3_plat_drv_res *resource_p, mutex_init(&ipa3_ctx->nat_mem.lock); mutex_init(&ipa3_ctx->q6_proxy_clk_vote_mutex); mutex_init(&ipa3_ctx->ipa_cne_evt_lock); + ipa3_ctx->q6_proxy_clk_vote_cnt = 0; idr_init(&ipa3_ctx->ipa_idr); spin_lock_init(&ipa3_ctx->idr_lock); diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h index 8e6db8f63fc1..a4c5e425dc83 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h @@ -1240,6 +1240,7 @@ struct ipa3_context { u32 curr_ipa_clk_rate; bool q6_proxy_clk_vote_valid; struct mutex q6_proxy_clk_vote_mutex; + u32 q6_proxy_clk_vote_cnt; u32 ipa_num_pipes; struct ipa3_wlan_comm_memb wc_memb; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c index 4897c4dccf59..afe8db7a7284 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c @@ -603,13 +603,46 @@ int ipa3_qmi_filter_request_send(struct ipa_install_fltr_rule_req_msg_v01 *req) struct ipa_install_fltr_rule_resp_msg_v01 resp; struct msg_desc req_desc, resp_desc; int rc; + int i; /* check if the filter rules from IPACM is valid */ - if (req->filter_spec_ex_list_len == 0) { + if (req->filter_spec_list_len == 0) IPAWANDBG("IPACM pass zero rules to Q6\n"); - } else { + else IPAWANDBG("IPACM pass %u rules to Q6\n", - req->filter_spec_ex_list_len); + req->filter_spec_list_len); + + if (req->filter_spec_list_len >= QMI_IPA_MAX_FILTERS_V01) { + IPAWANDBG( + "IPACM passes the number of filtering rules exceed limit\n"); + return -EINVAL; + } else if (req->source_pipe_index_valid != 0) { + IPAWANDBG( + "IPACM passes source_pipe_index_valid not zero 0 != %d\n", + req->source_pipe_index_valid); + return -EINVAL; + } else if (req->source_pipe_index >= ipa3_ctx->ipa_num_pipes) { + IPAWANDBG( + "IPACM passes source pipe index not valid ID = %d\n", + req->source_pipe_index); + return -EINVAL; + } + for (i = 0; i < req->filter_spec_list_len; i++) { + if ((req->filter_spec_list[i].ip_type != + QMI_IPA_IP_TYPE_V4_V01) && + (req->filter_spec_list[i].ip_type != + QMI_IPA_IP_TYPE_V6_V01)) + return -EINVAL; + if (req->filter_spec_list[i].is_mux_id_valid == false) + return -EINVAL; + if (req->filter_spec_list[i].is_routing_table_index_valid + == false) + return -EINVAL; + if ((req->filter_spec_list[i].filter_action <= + QMI_IPA_FILTER_ACTION_INVALID_V01) && + (req->filter_spec_list[i].filter_action > + QMI_IPA_FILTER_ACTION_EXCEPTION_V01)) + return -EINVAL; } mutex_lock(&ipa3_qmi_lock); @@ -653,6 +686,7 @@ int ipa3_qmi_filter_request_ex_send( struct ipa_install_fltr_rule_resp_ex_msg_v01 resp; struct msg_desc req_desc, resp_desc; int rc; + int i; /* check if the filter rules from IPACM is valid */ if (req->filter_spec_ex_list_len == 0) { @@ -662,6 +696,34 @@ int ipa3_qmi_filter_request_ex_send( req->filter_spec_ex_list_len); } + if (req->filter_spec_ex_list_len >= QMI_IPA_MAX_FILTERS_EX_V01) { + IPAWANDBG( + "IPACM pass the number of filtering rules exceed limit\n"); + return -EINVAL; + } else if (req->source_pipe_index_valid != 0) { + IPAWANDBG( + "IPACM passes source_pipe_index_valid not zero 0 != %d\n", + req->source_pipe_index_valid); + return -EINVAL; + } + + for (i = 0; i < req->filter_spec_ex_list_len-1; i++) { + if ((req->filter_spec_ex_list[i].ip_type != + QMI_IPA_IP_TYPE_V4_V01) && + (req->filter_spec_ex_list[i].ip_type != + QMI_IPA_IP_TYPE_V6_V01)) + return -EINVAL; + if (req->filter_spec_ex_list[i].is_mux_id_valid == false) + return -EINVAL; + if (req->filter_spec_ex_list[i].is_routing_table_index_valid + == false) + return -EINVAL; + if ((req->filter_spec_ex_list[i].filter_action <= + QMI_IPA_FILTER_ACTION_INVALID_V01) && + (req->filter_spec_ex_list[i].filter_action > + QMI_IPA_FILTER_ACTION_EXCEPTION_V01)) + return -EINVAL; + } mutex_lock(&ipa3_qmi_lock); if (ipa3_qmi_ctx != NULL) { /* cache the qmi_filter_request */ @@ -862,6 +924,31 @@ int ipa3_qmi_filter_notify_send( IPAWANERR("Source pipe index invalid\n"); return -EINVAL; } + if (req->install_status != IPA_QMI_RESULT_SUCCESS_V01) { + IPAWANERR(" UL filter rule for pipe %d install_status = %d\n", + req->source_pipe_index, req->install_status); + return -EINVAL; + } else if (req->rule_id_valid != 1) { + IPAWANERR(" UL filter rule for pipe %d rule_id_valid = %d\n", + req->source_pipe_index, req->rule_id_valid); + return -EINVAL; + } else if (req->source_pipe_index >= ipa3_ctx->ipa_num_pipes) { + IPAWANDBG( + "IPACM passes source pipe index not valid ID = %d\n", + req->source_pipe_index); + return -EINVAL; + } else if (((req->embedded_pipe_index_valid != true) || + (req->embedded_call_mux_id_valid != true)) && + ((req->embedded_pipe_index_valid != false) || + (req->embedded_call_mux_id_valid != false))) { + IPAWANERR( + "IPACM passes embedded pipe and mux valid not valid\n"); + return -EINVAL; + } else if (req->embedded_pipe_index >= ipa3_ctx->ipa_num_pipes) { + IPAWANERR("IPACM passes source pipe index not valid ID = %d\n", + req->source_pipe_index); + return -EINVAL; + } mutex_lock(&ipa3_qmi_lock); if (ipa3_qmi_ctx != NULL) { 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 d3837a05fdc2..b92c08d3c133 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c @@ -618,8 +618,9 @@ static void ipa_save_uc_smmu_mapping_pa(int res_idx, phys_addr_t pa, unsigned long iova, size_t len) { IPADBG("--res_idx=%d pa=0x%pa iova=0x%lx sz=0x%zx\n", res_idx, - &pa, iova, len); - wdi_res[res_idx].res = kzalloc(sizeof(struct ipa_wdi_res), GFP_KERNEL); + &pa, iova, len); + wdi_res[res_idx].res = kzalloc(sizeof(*wdi_res[res_idx].res), + GFP_KERNEL); if (!wdi_res[res_idx].res) BUG(); wdi_res[res_idx].nents = 1; @@ -645,7 +646,8 @@ static void ipa_save_uc_smmu_mapping_sgt(int res_idx, struct sg_table *sgt, return; } - wdi_res[res_idx].res = kcalloc(sgt->nents, sizeof(struct ipa_wdi_res), + wdi_res[res_idx].res = kcalloc(sgt->nents, + sizeof(*wdi_res[res_idx].res), GFP_KERNEL); if (!wdi_res[res_idx].res) BUG(); diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c index 29f2046610c8..74176d1aa47a 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c @@ -2989,7 +2989,9 @@ void ipa3_proxy_clk_unvote(void) mutex_lock(&ipa3_ctx->q6_proxy_clk_vote_mutex); if (ipa3_ctx->q6_proxy_clk_vote_valid) { IPA_ACTIVE_CLIENTS_DEC_SPECIAL("PROXY_CLK_VOTE"); - ipa3_ctx->q6_proxy_clk_vote_valid = false; + ipa3_ctx->q6_proxy_clk_vote_cnt--; + if (ipa3_ctx->q6_proxy_clk_vote_cnt == 0) + ipa3_ctx->q6_proxy_clk_vote_valid = false; } mutex_unlock(&ipa3_ctx->q6_proxy_clk_vote_mutex); } @@ -3005,8 +3007,10 @@ void ipa3_proxy_clk_vote(void) return; mutex_lock(&ipa3_ctx->q6_proxy_clk_vote_mutex); - if (!ipa3_ctx->q6_proxy_clk_vote_valid) { + if (!ipa3_ctx->q6_proxy_clk_vote_valid || + (ipa3_ctx->q6_proxy_clk_vote_cnt > 0)) { IPA_ACTIVE_CLIENTS_INC_SPECIAL("PROXY_CLK_VOTE"); + ipa3_ctx->q6_proxy_clk_vote_cnt++; ipa3_ctx->q6_proxy_clk_vote_valid = true; } mutex_unlock(&ipa3_ctx->q6_proxy_clk_vote_mutex); diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_fltrt.c b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_fltrt.c index 053a581b1d26..b7ed529e9160 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_fltrt.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_fltrt.c @@ -1216,10 +1216,10 @@ static int ipa_fltrt_calc_extra_wrd_bytes( static int ipa_fltrt_generate_hw_rule_bdy_from_eq( const struct ipa_ipfltri_rule_eq *attrib, u8 **buf) { - int num_offset_meq_32 = attrib->num_offset_meq_32; - int num_ihl_offset_range_16 = attrib->num_ihl_offset_range_16; - int num_ihl_offset_meq_32 = attrib->num_ihl_offset_meq_32; - int num_offset_meq_128 = attrib->num_offset_meq_128; + uint8_t num_offset_meq_32 = attrib->num_offset_meq_32; + uint8_t num_ihl_offset_range_16 = attrib->num_ihl_offset_range_16; + uint8_t num_ihl_offset_meq_32 = attrib->num_ihl_offset_meq_32; + uint8_t num_offset_meq_128 = attrib->num_offset_meq_128; int i; int extra_bytes; u8 *extra; 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 d0aa42c81750..9fe7b6c59302 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c @@ -1566,6 +1566,8 @@ void ipahal_get_aggr_force_close_valmask(int ep_idx, return; } + memset(valmask, 0, sizeof(struct ipahal_reg_valmask)); + if (ipahal_ctx->hw_type <= IPA_HW_v3_1) { shft = IPA_AGGR_FORCE_CLOSE_AGGR_FORCE_CLOSE_PIPE_BITMAP_SHFT; bmsk = IPA_AGGR_FORCE_CLOSE_AGGR_FORCE_CLOSE_PIPE_BITMAP_BMSK; diff --git a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c index 01ef670dba51..e49402afb6a2 100644 --- a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c @@ -678,6 +678,8 @@ static int ipa3_wwan_add_ul_flt_rule_to_ipa(void) param->global = false; param->num_rules = (uint8_t)1; + memset(req, 0, sizeof(struct ipa_fltr_installed_notif_req_msg_v01)); + for (i = 0; i < rmnet_ipa3_ctx->num_q6_rules; i++) { param->ip = ipa3_qmi_ctx->q6_ul_filter_rule[i].ip; memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add)); @@ -1651,8 +1653,8 @@ static int ipa3_wwan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) /* Get driver name */ case RMNET_IOCTL_GET_DRIVER_NAME: memcpy(&extend_ioctl_data.u.if_name, - IPA_NETDEV()->name, - sizeof(IFNAMSIZ)); + IPA_NETDEV()->name, IFNAMSIZ); + extend_ioctl_data.u.if_name[IFNAMSIZ - 1] = '\0'; if (copy_to_user((u8 *)ifr->ifr_ifru.ifru_data, &extend_ioctl_data, sizeof(struct rmnet_ioctl_extended_s))) @@ -1745,6 +1747,7 @@ static int ipa3_wwan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) sizeof(wan_msg->upstream_ifname); strlcpy(wan_msg->upstream_ifname, extend_ioctl_data.u.if_name, len); + wan_msg->upstream_ifname[len-1] = '\0'; memset(&msg_meta, 0, sizeof(struct ipa_msg_meta)); msg_meta.msg_type = WAN_XLAT_CONNECT; msg_meta.msg_len = sizeof(struct ipa_wan_msg); diff --git a/drivers/platform/msm/ipa/test/ipa_ut_framework.c b/drivers/platform/msm/ipa/test/ipa_ut_framework.c index 3bf9ac11f2d1..dfc8442e0862 100644 --- a/drivers/platform/msm/ipa/test/ipa_ut_framework.c +++ b/drivers/platform/msm/ipa/test/ipa_ut_framework.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, The Linux Foundation. All rights reserved. +/* 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 @@ -215,6 +215,10 @@ static ssize_t ipa_ut_dbgfs_meta_test_write(struct file *file, IPA_UT_DBG("Entry\n"); mutex_lock(&ipa_ut_ctx->lock); + if (file == NULL) { + rc = -EFAULT; + goto unlock_mutex; + } suite = file->f_inode->i_private; ipa_assert_on(!suite); meta_type = (long)(file->private_data); @@ -470,6 +474,10 @@ static ssize_t ipa_ut_dbgfs_test_write(struct file *file, IPA_UT_DBG("Entry\n"); mutex_lock(&ipa_ut_ctx->lock); + if (file == NULL) { + rc = -EFAULT; + goto unlock_mutex; + } test = file->f_inode->i_private; ipa_assert_on(!test); diff --git a/drivers/platform/msm/mhi/mhi_bhi.c b/drivers/platform/msm/mhi/mhi_bhi.c index 68ef2595f3c3..a931b1c139bc 100644 --- a/drivers/platform/msm/mhi/mhi_bhi.c +++ b/drivers/platform/msm/mhi/mhi_bhi.c @@ -641,7 +641,6 @@ int bhi_probe(struct mhi_device_ctxt *mhi_dev_ctxt) image += to_copy; } - fw_table->sequence++; release_firmware(firmware); /* allocate memory and setup rddm table */ @@ -662,7 +661,6 @@ int bhi_probe(struct mhi_device_ctxt *mhi_dev_ctxt) rddm_table->bhie_mem_info[i].phys_addr; sg_dma_len(itr) = size; } - rddm_table->sequence++; } else { /* out of memory for rddm, not fatal error */ mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, diff --git a/drivers/platform/msm/mhi/mhi_iface.c b/drivers/platform/msm/mhi/mhi_iface.c index ce6d1257cfbb..7423c13842fa 100644 --- a/drivers/platform/msm/mhi/mhi_iface.c +++ b/drivers/platform/msm/mhi/mhi_iface.c @@ -459,6 +459,7 @@ static int mhi_plat_probe(struct platform_device *pdev) return r; } INIT_WORK(&bhi_ctxt->fw_load_work, bhi_firmware_download); + bhi_ctxt->fw_table.sequence = 1; } mhi_dev_ctxt->flags.bb_required = diff --git a/drivers/platform/msm/mhi/mhi_main.c b/drivers/platform/msm/mhi/mhi_main.c index 739915c4af6f..9ee459806ab5 100644 --- a/drivers/platform/msm/mhi/mhi_main.c +++ b/drivers/platform/msm/mhi/mhi_main.c @@ -1898,6 +1898,7 @@ int mhi_register_device(struct mhi_device *mhi_device, if (mhi_device->support_rddm) { mhi_dev_ctxt->bhi_ctxt.support_rddm = true; mhi_dev_ctxt->bhi_ctxt.rddm_size = mhi_device->rddm_size; + mhi_dev_ctxt->bhi_ctxt.rddm_table.sequence = 1; mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Device support rddm of size:0x%lx bytes\n", diff --git a/drivers/platform/msm/sps/bam.c b/drivers/platform/msm/sps/bam.c index c94536398dac..8eb29a3fc66d 100644 --- a/drivers/platform/msm/sps/bam.c +++ b/drivers/platform/msm/sps/bam.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 @@ -707,7 +707,7 @@ static inline u32 bam_get_register_offset(void *base, enum bam_regs reg, struct sps_bam *dev = to_sps_bam_dev(base); if ((dev == NULL) || (&dev->base != base)) { - SPS_ERR(sps, "%s:Failed to get dev for base addr 0x%p\n", + SPS_ERR(sps, "%s:Failed to get dev for base addr 0x%pK\n", __func__, base); return SPS_ERROR; } @@ -756,7 +756,7 @@ static inline u32 bam_read_reg(void *base, enum bam_regs reg, u32 param) struct sps_bam *dev = to_sps_bam_dev(base); if ((dev == NULL) || (&dev->base != base)) { - SPS_ERR(sps, "%s:Failed to get dev for base addr 0x%p\n", + SPS_ERR(sps, "%s:Failed to get dev for base addr 0x%pK\n", __func__, base); return SPS_ERROR; } @@ -767,7 +767,7 @@ static inline u32 bam_read_reg(void *base, enum bam_regs reg, u32 param) return offset; } val = ioread32(dev->base + offset); - SPS_DBG(dev, "sps:bam 0x%p(va) offset 0x%x reg 0x%x r_val 0x%x.\n", + SPS_DBG(dev, "sps:bam 0x%pK(va) offset 0x%x reg 0x%x r_val 0x%x.\n", dev->base, offset, reg, val); return val; } @@ -788,7 +788,7 @@ static inline u32 bam_read_reg_field(void *base, enum bam_regs reg, u32 param, struct sps_bam *dev = to_sps_bam_dev(base); if ((dev == NULL) || (&dev->base != base)) { - SPS_ERR(sps, "%s:Failed to get dev for base addr 0x%p\n", + SPS_ERR(sps, "%s:Failed to get dev for base addr 0x%pK\n", __func__, base); return SPS_ERROR; } @@ -802,7 +802,7 @@ static inline u32 bam_read_reg_field(void *base, enum bam_regs reg, u32 param, val = ioread32(dev->base + offset); val &= mask; /* clear other bits */ val >>= shift; - SPS_DBG(dev, "sps:bam 0x%p(va) read reg 0x%x mask 0x%x r_val 0x%x.\n", + SPS_DBG(dev, "sps:bam 0x%pK(va) read reg 0x%x mask 0x%x r_val 0x%x.\n", dev->base, offset, mask, val); return val; } @@ -823,7 +823,7 @@ static inline void bam_write_reg(void *base, enum bam_regs reg, struct sps_bam *dev = to_sps_bam_dev(base); if ((dev == NULL) || (&dev->base != base)) { - SPS_ERR(sps, "%s:Failed to get dev for base addr 0x%p\n", + SPS_ERR(sps, "%s:Failed to get dev for base addr 0x%pK\n", __func__, base); return; } @@ -834,7 +834,7 @@ static inline void bam_write_reg(void *base, enum bam_regs reg, return; } iowrite32(val, dev->base + offset); - SPS_DBG(dev, "sps:bam 0x%p(va) write reg 0x%x w_val 0x%x.\n", + SPS_DBG(dev, "sps:bam 0x%pK(va) write reg 0x%x w_val 0x%x.\n", dev->base, offset, val); } @@ -854,7 +854,7 @@ static inline void bam_write_reg_field(void *base, enum bam_regs reg, struct sps_bam *dev = to_sps_bam_dev(base); if ((dev == NULL) || (&dev->base != base)) { - SPS_ERR(sps, "%s:Failed to get dev for base addr 0x%p\n", + SPS_ERR(sps, "%s:Failed to get dev for base addr 0x%pK\n", __func__, base); return; } @@ -870,7 +870,7 @@ static inline void bam_write_reg_field(void *base, enum bam_regs reg, tmp &= ~mask; /* clear written bits */ val = tmp | (val << shift); iowrite32(val, dev->base + offset); - SPS_DBG(dev, "sps:bam 0x%p(va) write reg 0x%x w_val 0x%x.\n", + SPS_DBG(dev, "sps:bam 0x%pK(va) write reg 0x%x w_val 0x%x.\n", dev->base, offset, val); } @@ -888,28 +888,28 @@ int bam_init(void *base, u32 ee, struct sps_bam *dev = to_sps_bam_dev(base); if ((dev == NULL) || (&dev->base != base)) { - SPS_ERR(sps, "%s:Failed to get dev for base addr 0x%p\n", + SPS_ERR(sps, "%s:Failed to get dev for base addr 0x%pK\n", __func__, base); return SPS_ERROR; } - SPS_DBG3(dev, "sps:%s:bam=%pa 0x%p(va).ee=%d.", __func__, + SPS_DBG3(dev, "sps:%s:bam=%pa 0x%pK(va).ee=%d.", __func__, BAM_ID(dev), dev->base, ee); ver = bam_read_reg_field(base, REVISION, 0, BAM_REVISION); if ((ver < BAM_MIN_VERSION) || (ver > BAM_MAX_VERSION)) { - SPS_ERR(dev, "sps:bam 0x%p(va) Invalid BAM REVISION 0x%x.\n", + SPS_ERR(dev, "sps:bam 0x%pK(va) Invalid BAM REVISION 0x%x.\n", dev->base, ver); return -ENODEV; } else - SPS_DBG(dev, "sps:REVISION of BAM 0x%p is 0x%x.\n", + SPS_DBG(dev, "sps:REVISION of BAM 0x%pK is 0x%x.\n", dev->base, ver); if (summing_threshold == 0) { summing_threshold = 4; SPS_ERR(dev, - "sps:bam 0x%p(va) summing_threshold is zero,use default 4.\n", + "sps:bam 0x%pK(va) summing_threshold is zero,use default 4.\n", dev->base); } @@ -1009,12 +1009,12 @@ int bam_security_init(void *base, u32 ee, u32 vmid, u32 pipe_mask) struct sps_bam *dev = to_sps_bam_dev(base); if ((dev == NULL) || (&dev->base != base)) { - SPS_ERR(sps, "%s:Failed to get dev for base addr 0x%p\n", + SPS_ERR(sps, "%s:Failed to get dev for base addr 0x%pK\n", __func__, base); return SPS_ERROR; } - SPS_DBG3(dev, "sps:%s:bam=%pa 0x%p(va).", __func__, + SPS_DBG3(dev, "sps:%s:bam=%pa 0x%pK(va).", __func__, BAM_ID(dev), dev->base); /* @@ -1025,14 +1025,14 @@ int bam_security_init(void *base, u32 ee, u32 vmid, u32 pipe_mask) num_pipes = bam_read_reg_field(base, NUM_PIPES, 0, BAM_NUM_PIPES); if (version < 3 || version > 0x1F) { SPS_ERR(dev, - "sps:bam 0x%p(va) security is not supported for this BAM version 0x%x.\n", + "sps:bam 0x%pK(va) security is not supported for this BAM version 0x%x.\n", dev->base, version); return -ENODEV; } if (num_pipes > BAM_MAX_PIPES) { SPS_ERR(dev, - "sps:bam 0x%p(va) the number of pipes is more than the maximum number allowed.\n", + "sps:bam 0x%pK(va) the number of pipes is more than the maximum number allowed.\n", dev->base); return -ENODEV; } @@ -1080,12 +1080,12 @@ int bam_check(void *base, u32 *version, u32 ee, u32 *num_pipes) struct sps_bam *dev = to_sps_bam_dev(base); if ((dev == NULL) || (&dev->base != base)) { - SPS_ERR(sps, "%s:Failed to get dev for base addr 0x%p\n", + SPS_ERR(sps, "%s:Failed to get dev for base addr 0x%pK\n", __func__, base); return SPS_ERROR; } - SPS_DBG3(dev, "sps:%s:bam=%pa 0x%p(va).", + SPS_DBG3(dev, "sps:%s:bam=%pa 0x%pK(va).", __func__, BAM_ID(dev), dev->base); if (!enhd_pipe) @@ -1094,7 +1094,7 @@ int bam_check(void *base, u32 *version, u32 ee, u32 *num_pipes) enabled = bam_get_pipe_attr(base, ee, true); if (!enabled) { - SPS_ERR(dev, "sps:%s:bam 0x%p(va) is not enabled.\n", + SPS_ERR(dev, "sps:%s:bam 0x%pK(va) is not enabled.\n", __func__, dev->base); return -ENODEV; } @@ -1110,7 +1110,7 @@ int bam_check(void *base, u32 *version, u32 ee, u32 *num_pipes) /* Check BAM version */ if ((ver < BAM_MIN_VERSION) || (ver > BAM_MAX_VERSION)) { - SPS_ERR(dev, "sps:%s:bam 0x%p(va) Invalid BAM version 0x%x.\n", + SPS_ERR(dev, "sps:%s:bam 0x%pK(va) Invalid BAM version 0x%x.\n", __func__, dev->base, ver); return -ENODEV; } @@ -1127,11 +1127,11 @@ void bam_exit(void *base, u32 ee) struct sps_bam *dev = to_sps_bam_dev(base); if ((dev == NULL) || (&dev->base != base)) { - SPS_ERR(sps, "%s:Failed to get dev for base addr 0x%p\n", + SPS_ERR(sps, "%s:Failed to get dev for base addr 0x%pK\n", __func__, base); return; } - SPS_DBG3(dev, "sps:%s:bam=%pa 0x%p(va).ee=%d.", + SPS_DBG3(dev, "sps:%s:bam=%pa 0x%pK(va).ee=%d.", __func__, BAM_ID(dev), dev->base, ee); bam_write_reg_field(base, IRQ_SRCS_MSK_EE, ee, BAM_IRQ, 0); @@ -1155,7 +1155,7 @@ void bam_output_register_content(void *base, u32 ee) struct sps_bam *dev = to_sps_bam_dev(base); if ((dev == NULL) || (&dev->base != base)) { - SPS_ERR(sps, "%s:Failed to get dev for base addr 0x%p\n", + SPS_ERR(sps, "%s:Failed to get dev for base addr 0x%pK\n", __func__, base); return; } @@ -1166,7 +1166,7 @@ void bam_output_register_content(void *base, u32 ee) num_pipes = bam_read_reg_field(base, NUM_PIPES, 0, BAM_NUM_PIPES); - SPS_INFO(dev, "sps:bam %pa 0x%p(va) has %d pipes.", + SPS_INFO(dev, "sps:bam %pa 0x%pK(va) has %d pipes.", BAM_ID(dev), dev->base, num_pipes); pipe_attr = enhd_pipe ? @@ -1193,7 +1193,7 @@ u32 bam_check_irq_source(void *base, u32 ee, u32 mask, struct sps_bam *dev = to_sps_bam_dev(base); if ((dev == NULL) || (&dev->base != base)) { - SPS_ERR(sps, "%s:Failed to get dev for base addr 0x%p\n", + SPS_ERR(sps, "%s:Failed to get dev for base addr 0x%pK\n", __func__, base); return SPS_ERROR; } @@ -1205,13 +1205,13 @@ u32 bam_check_irq_source(void *base, u32 ee, u32 mask, status = bam_read_reg(base, IRQ_STTS, 0); if (status & IRQ_STTS_BAM_ERROR_IRQ) { - SPS_ERR(dev, "sps:bam %pa 0x%p(va);bam irq status=" + SPS_ERR(dev, "sps:bam %pa 0x%pK(va);bam irq status=" "0x%x.\nsps: BAM_ERROR_IRQ\n", BAM_ID(dev), dev->base, status); bam_output_register_content(base, ee); *cb_case = SPS_CALLBACK_BAM_ERROR_IRQ; } else if (status & IRQ_STTS_BAM_HRESP_ERR_IRQ) { - SPS_ERR(dev, "sps:bam %pa 0x%p(va);bam irq status=" + SPS_ERR(dev, "sps:bam %pa 0x%pK(va);bam irq status=" "0x%x.\nsps: BAM_HRESP_ERR_IRQ\n", BAM_ID(dev), dev->base, status); bam_output_register_content(base, ee); @@ -1219,13 +1219,13 @@ u32 bam_check_irq_source(void *base, u32 ee, u32 mask, #ifdef CONFIG_SPS_SUPPORT_NDP_BAM } else if (status & IRQ_STTS_BAM_TIMER_IRQ) { SPS_DBG1(dev, - "sps:bam 0x%p(va);receive BAM_TIMER_IRQ\n", + "sps:bam 0x%pK(va);receive BAM_TIMER_IRQ\n", dev->base); *cb_case = SPS_CALLBACK_BAM_TIMER_IRQ; #endif } else SPS_INFO(dev, - "sps:bam %pa 0x%p(va);bam irq status=0x%x.\n", + "sps:bam %pa 0x%pK(va);bam irq status=0x%x.\n", BAM_ID(dev), dev->base, status); bam_write_reg(base, IRQ_CLR, 0, status); @@ -1243,11 +1243,11 @@ void bam_pipe_reset(void *base, u32 pipe) struct sps_bam *dev = to_sps_bam_dev(base); if ((dev == NULL) || (&dev->base != base)) { - SPS_ERR(sps, "%s:Failed to get dev for base addr 0x%p\n", + SPS_ERR(sps, "%s:Failed to get dev for base addr 0x%pK\n", __func__, base); return; } - SPS_DBG2(dev, "sps:%s:bam=%pa 0x%p(va).pipe=%d.", + SPS_DBG2(dev, "sps:%s:bam=%pa 0x%pK(va).pipe=%d.", __func__, BAM_ID(dev), dev->base, pipe); bam_write_reg(base, P_RST, pipe, 1); @@ -1264,11 +1264,11 @@ void bam_disable_pipe(void *base, u32 pipe) struct sps_bam *dev = to_sps_bam_dev(base); if ((dev == NULL) || (&dev->base != base)) { - SPS_ERR(sps, "%s:Failed to get dev for base addr 0x%p\n", + SPS_ERR(sps, "%s:Failed to get dev for base addr 0x%pK\n", __func__, base); return; } - SPS_DBG2(dev, "sps:%s:bam=0x%p(va).pipe=%d.", __func__, base, pipe); + SPS_DBG2(dev, "sps:%s:bam=0x%pK(va).pipe=%d.", __func__, base, pipe); bam_write_reg_field(base, P_CTRL, pipe, P_EN, 0); wmb(); /* ensure pipe is disabled */ } @@ -1281,20 +1281,20 @@ bool bam_pipe_check_zlt(void *base, u32 pipe) struct sps_bam *dev = to_sps_bam_dev(base); if ((dev == NULL) || (&dev->base != base)) { - SPS_ERR(sps, "%s:Failed to get dev for base addr 0x%p\n", + SPS_ERR(sps, "%s:Failed to get dev for base addr 0x%pK\n", __func__, base); return false; } if (bam_read_reg_field(base, P_HALT, pipe, P_HALT_P_LAST_DESC_ZLT)) { SPS_DBG(dev, - "sps:%s:bam=0x%p(va).pipe=%d: the last desc is ZLT.", + "sps:%s:bam=0x%pK(va).pipe=%d: the last desc is ZLT.", __func__, base, pipe); return true; } SPS_DBG(dev, - "sps:%s:bam=0x%p(va).pipe=%d: the last desc is not ZLT.", + "sps:%s:bam=0x%pK(va).pipe=%d: the last desc is not ZLT.", __func__, base, pipe); return false; } @@ -1307,20 +1307,20 @@ bool bam_pipe_check_pipe_empty(void *base, u32 pipe) struct sps_bam *dev = to_sps_bam_dev(base); if ((dev == NULL) || (&dev->base != base)) { - SPS_ERR(sps, "%s:Failed to get dev for base addr 0x%p\n", + SPS_ERR(sps, "%s:Failed to get dev for base addr 0x%pK\n", __func__, base); return false; } if (bam_read_reg_field(base, P_HALT, pipe, P_HALT_P_PIPE_EMPTY)) { SPS_DBG(dev, - "sps:%s:bam=0x%p(va).pipe=%d: desc FIFO is empty.", + "sps:%s:bam=0x%pK(va).pipe=%d: desc FIFO is empty.", __func__, base, pipe); return true; } SPS_DBG(dev, - "sps:%s:bam=0x%p(va).pipe=%d: desc FIFO is not empty.", + "sps:%s:bam=0x%pK(va).pipe=%d: desc FIFO is not empty.", __func__, base, pipe); return false; } @@ -1334,11 +1334,11 @@ int bam_pipe_init(void *base, u32 pipe, struct bam_pipe_parameters *param, struct sps_bam *dev = to_sps_bam_dev(base); if ((dev == NULL) || (&dev->base != base)) { - SPS_ERR(sps, "%s:Failed to get dev for base addr 0x%p\n", + SPS_ERR(sps, "%s:Failed to get dev for base addr 0x%pK\n", __func__, base); return SPS_ERROR; } - SPS_DBG2(dev, "sps:%s:bam=%pa 0x%p(va).pipe=%d.", + SPS_DBG2(dev, "sps:%s:bam=%pa 0x%pK(va).pipe=%d.", __func__, BAM_ID(dev), dev->base, pipe); /* Reset the BAM pipe */ @@ -1372,7 +1372,7 @@ int bam_pipe_init(void *base, u32 pipe, struct bam_pipe_parameters *param, bam_write_reg_field(base, P_CTRL, pipe, P_LOCK_GROUP, param->lock_group); - SPS_DBG(dev, "sps:bam=0x%p(va).pipe=%d.lock_group=%d.\n", + SPS_DBG(dev, "sps:bam=0x%pK(va).pipe=%d.lock_group=%d.\n", dev->base, pipe, param->lock_group); #endif @@ -1388,7 +1388,7 @@ int bam_pipe_init(void *base, u32 pipe, struct bam_pipe_parameters *param, bam_write_reg(base, P_EVNT_DEST_ADDR, pipe, peer_dest_addr); - SPS_DBG2(dev, "sps:bam=0x%p(va).pipe=%d.peer_bam=0x%x." + SPS_DBG2(dev, "sps:bam=0x%pK(va).pipe=%d.peer_bam=0x%x." "peer_pipe=%d.\n", dev->base, pipe, (u32) param->peer_phys_addr, @@ -1424,11 +1424,11 @@ void bam_pipe_exit(void *base, u32 pipe, u32 ee) struct sps_bam *dev = to_sps_bam_dev(base); if ((dev == NULL) || (&dev->base != base)) { - SPS_ERR(sps, "%s:Failed to get dev for base addr 0x%p\n", + SPS_ERR(sps, "%s:Failed to get dev for base addr 0x%pK\n", __func__, base); return; } - SPS_DBG2(dev, "sps:%s:bam=%pa 0x%p(va).pipe=%d.", + SPS_DBG2(dev, "sps:%s:bam=%pa 0x%pK(va).pipe=%d.", __func__, BAM_ID(dev), dev->base, pipe); bam_write_reg(base, P_IRQ_EN, pipe, 0); @@ -1449,15 +1449,15 @@ void bam_pipe_enable(void *base, u32 pipe) struct sps_bam *dev = to_sps_bam_dev(base); if ((dev == NULL) || (&dev->base != base)) { - SPS_ERR(sps, "%s:Failed to get dev for base addr 0x%p\n", + SPS_ERR(sps, "%s:Failed to get dev for base addr 0x%pK\n", __func__, base); return; } - SPS_DBG2(dev, "sps:%s:bam=%pa 0x%p(va).pipe=%d.", + SPS_DBG2(dev, "sps:%s:bam=%pa 0x%pK(va).pipe=%d.", __func__, BAM_ID(dev), dev->base, pipe); if (bam_read_reg_field(base, P_CTRL, pipe, P_EN)) - SPS_DBG2(dev, "sps:bam=0x%p(va).pipe=%d is already enabled.\n", + SPS_DBG2(dev, "sps:bam=0x%pK(va).pipe=%d is already enabled.\n", dev->base, pipe); else bam_write_reg_field(base, P_CTRL, pipe, P_EN, 1); @@ -1472,11 +1472,11 @@ void bam_pipe_disable(void *base, u32 pipe) struct sps_bam *dev = to_sps_bam_dev(base); if ((dev == NULL) || (&dev->base != base)) { - SPS_ERR(sps, "%s:Failed to get dev for base addr 0x%p\n", + SPS_ERR(sps, "%s:Failed to get dev for base addr 0x%pK\n", __func__, base); return; } - SPS_DBG2(dev, "sps:%s:bam=%pa 0x%p(va).pipe=%d.", + SPS_DBG2(dev, "sps:%s:bam=%pa 0x%pK(va).pipe=%d.", __func__, BAM_ID(dev), dev->base, pipe); bam_write_reg_field(base, P_CTRL, pipe, P_EN, 0); @@ -1501,12 +1501,12 @@ void bam_pipe_set_irq(void *base, u32 pipe, enum bam_enable irq_en, struct sps_bam *dev = to_sps_bam_dev(base); if ((dev == NULL) || (&dev->base != base)) { - SPS_ERR(sps, "%s:Failed to get dev for base addr 0x%p\n", + SPS_ERR(sps, "%s:Failed to get dev for base addr 0x%pK\n", __func__, base); return; } SPS_DBG2(dev, - "sps:%s:bam=%pa 0x%p(va).pipe=%d; irq_en:%d; src_mask:0x%x; ee:%d.\n", + "sps:%s:bam=%pa 0x%pK(va).pipe=%d; irq_en:%d; src_mask:0x%x; ee:%d.\n", __func__, BAM_ID(dev), dev->base, pipe, irq_en, src_mask, ee); if (src_mask & BAM_PIPE_IRQ_RST_ERROR) { diff --git a/drivers/platform/msm/sps/sps.c b/drivers/platform/msm/sps/sps.c index e7710f929e71..59a9b911553c 100644 --- a/drivers/platform/msm/sps/sps.c +++ b/drivers/platform/msm/sps/sps.c @@ -931,7 +931,7 @@ static int sps_device_init(void) goto exit_err; } - SPS_DBG3(sps, "sps:bamdma_bam.phys=%pa.virt=0x%p.", + SPS_DBG3(sps, "sps:bamdma_bam.phys=%pa.virt=0x%pK.", &bamdma_props.phys_addr, bamdma_props.virt_addr); @@ -946,7 +946,7 @@ static int sps_device_init(void) goto exit_err; } - SPS_DBG3(sps, "sps:bamdma_dma.phys=%pa.virt=0x%p.", + SPS_DBG3(sps, "sps:bamdma_dma.phys=%pa.virt=0x%pK.", &bamdma_props.periph_phys_addr, bamdma_props.periph_virt_addr); diff --git a/drivers/platform/msm/sps/sps_bam.c b/drivers/platform/msm/sps/sps_bam.c index 38a6474dd06f..74b6894f889f 100644 --- a/drivers/platform/msm/sps/sps_bam.c +++ b/drivers/platform/msm/sps/sps_bam.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 @@ -508,12 +508,12 @@ int sps_bam_enable(struct sps_bam *dev) if (dev->props.logging_number > 0) dev->props.logging_number--; SPS_INFO(dev, - "sps:BAM %pa (va:0x%p) enabled: ver:0x%x, number of pipes:%d\n", + "sps:BAM %pa (va:0x%pK) enabled: ver:0x%x, number of pipes:%d\n", BAM_ID(dev), dev->base, dev->version, dev->props.num_pipes); } else SPS_DBG3(dev, - "sps:BAM %pa (va:0x%p) enabled: ver:0x%x, number of pipes:%d\n", + "sps:BAM %pa (va:0x%pK) enabled: ver:0x%x, number of pipes:%d\n", BAM_ID(dev), dev->base, dev->version, dev->props.num_pipes); @@ -2127,7 +2127,7 @@ int sps_bam_pipe_get_event(struct sps_bam *dev, if (pipe->sys.no_queue) { SPS_ERR(dev, - "sps:Invalid connection for event: BAM %pa pipe %d context 0x%p\n", + "sps:Invalid connection for event: BAM %pa pipe %d context 0x%pK\n", BAM_ID(dev), pipe_index, pipe); notify->event_id = SPS_EVENT_INVALID; return SPS_ERROR; diff --git a/drivers/platform/msm/sps/sps_mem.c b/drivers/platform/msm/sps/sps_mem.c index becb9a15882a..db36e64f96d8 100644 --- a/drivers/platform/msm/sps/sps_mem.c +++ b/drivers/platform/msm/sps/sps_mem.c @@ -1,4 +1,5 @@ -/* Copyright (c) 2011-2013, 2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2013, 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 @@ -129,7 +130,7 @@ int sps_mem_init(phys_addr_t pipemem_phys_base, u32 pipemem_size) iomem_offset = 0; SPS_DBG(sps, - "sps:sps_mem_init.iomem_phys=%pa,iomem_virt=0x%p.", + "sps:sps_mem_init.iomem_phys=%pa,iomem_virt=0x%pK.", &iomem_phys, iomem_virt); } diff --git a/drivers/platform/msm/sps/sps_rm.c b/drivers/platform/msm/sps/sps_rm.c index ec64e6c25465..db5db28d5f9e 100644 --- a/drivers/platform/msm/sps/sps_rm.c +++ b/drivers/platform/msm/sps/sps_rm.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-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 @@ -723,8 +723,7 @@ int sps_rm_state_change(struct sps_pipe *pipe, u32 state) state == SPS_STATE_ALLOCATE) { if (sps_rm_alloc(pipe)) { SPS_ERR(pipe->bam, - "sps:Fail to allocate resource for" - " BAM 0x%p pipe %d.\n", + "sps:Fail to allocate resource for BAM 0x%pK pipe %d.\n", pipe->bam, pipe->pipe_index); return SPS_ERROR; } @@ -745,7 +744,7 @@ int sps_rm_state_change(struct sps_pipe *pipe, u32 state) result = sps_bam_pipe_connect(pipe, ¶ms); if (result) { SPS_ERR(pipe->bam, - "sps:Failed to connect BAM 0x%p pipe %d", + "sps:Failed to connect BAM 0x%pK pipe %d", pipe->bam, pipe->pipe_index); return SPS_ERROR; } diff --git a/drivers/power/qcom/msm-core.c b/drivers/power/qcom/msm-core.c index 825c27e7a4c1..224a52a0306d 100644 --- a/drivers/power/qcom/msm-core.c +++ b/drivers/power/qcom/msm-core.c @@ -409,9 +409,10 @@ static int update_userspace_power(struct sched_params __user *argp) if (!sp) return -ENOMEM; - + mutex_lock(&policy_update_mutex); sp->power = allocate_2d_array_uint32_t(node->sp->num_of_freqs); if (IS_ERR_OR_NULL(sp->power)) { + mutex_unlock(&policy_update_mutex); ret = PTR_ERR(sp->power); kfree(sp); return ret; @@ -455,6 +456,7 @@ static int update_userspace_power(struct sched_params __user *argp) } } spin_unlock(&update_lock); + mutex_unlock(&policy_update_mutex); for_each_possible_cpu(cpu) { if (!pdata_valid[cpu]) @@ -468,6 +470,7 @@ static int update_userspace_power(struct sched_params __user *argp) return 0; failed: + mutex_unlock(&policy_update_mutex); for (i = 0; i < TEMP_DATA_POINTS; i++) kfree(sp->power[i]); kfree(sp->power); diff --git a/drivers/power/supply/qcom/qpnp-fg-gen3.c b/drivers/power/supply/qcom/qpnp-fg-gen3.c index 491dda6ff7e8..b1a57d8853e8 100644 --- a/drivers/power/supply/qcom/qpnp-fg-gen3.c +++ b/drivers/power/supply/qcom/qpnp-fg-gen3.c @@ -2733,6 +2733,49 @@ static bool is_profile_load_required(struct fg_chip *chip) return true; } +static void fg_update_batt_profile(struct fg_chip *chip) +{ + int rc, offset; + u8 val; + + rc = fg_sram_read(chip, PROFILE_INTEGRITY_WORD, + SW_CONFIG_OFFSET, &val, 1, FG_IMA_DEFAULT); + if (rc < 0) { + pr_err("Error in reading SW_CONFIG_OFFSET, rc=%d\n", rc); + return; + } + + /* + * If the RCONN had not been updated, no need to update battery + * profile. Else, update the battery profile so that the profile + * modified by bootloader or HLOS matches with the profile read + * from device tree. + */ + + if (!(val & RCONN_CONFIG_BIT)) + return; + + rc = fg_sram_read(chip, ESR_RSLOW_CHG_WORD, + ESR_RSLOW_CHG_OFFSET, &val, 1, FG_IMA_DEFAULT); + if (rc < 0) { + pr_err("Error in reading ESR_RSLOW_CHG_OFFSET, rc=%d\n", rc); + return; + } + offset = (ESR_RSLOW_CHG_WORD - PROFILE_LOAD_WORD) * 4 + + ESR_RSLOW_CHG_OFFSET; + chip->batt_profile[offset] = val; + + rc = fg_sram_read(chip, ESR_RSLOW_DISCHG_WORD, + ESR_RSLOW_DISCHG_OFFSET, &val, 1, FG_IMA_DEFAULT); + if (rc < 0) { + pr_err("Error in reading ESR_RSLOW_DISCHG_OFFSET, rc=%d\n", rc); + return; + } + offset = (ESR_RSLOW_DISCHG_WORD - PROFILE_LOAD_WORD) * 4 + + ESR_RSLOW_DISCHG_OFFSET; + chip->batt_profile[offset] = val; +} + static void clear_battery_profile(struct fg_chip *chip) { u8 val = 0; @@ -2816,6 +2859,8 @@ static void profile_load_work(struct work_struct *work) if (!chip->profile_available) goto out; + fg_update_batt_profile(chip); + if (!is_profile_load_required(chip)) goto done; @@ -2877,6 +2922,10 @@ done: rc); } + rc = fg_rconn_config(chip); + if (rc < 0) + pr_err("Error in configuring Rconn, rc=%d\n", rc); + batt_psy_initialized(chip); fg_notify_charger(chip); chip->profile_loaded = true; @@ -4076,12 +4125,6 @@ static int fg_hw_init(struct fg_chip *chip) return rc; } - rc = fg_rconn_config(chip); - if (rc < 0) { - pr_err("Error in configuring Rconn, rc=%d\n", rc); - return rc; - } - fg_encode(chip->sp, FG_SRAM_ESR_TIGHT_FILTER, chip->dt.esr_tight_flt_upct, buf); rc = fg_sram_write(chip, chip->sp[FG_SRAM_ESR_TIGHT_FILTER].addr_word, diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c index 93512f155c52..7acf5fab573b 100644 --- a/drivers/power/supply/qcom/smb-lib.c +++ b/drivers/power/supply/qcom/smb-lib.c @@ -2695,17 +2695,13 @@ int smblib_set_prop_pd_voltage_max(struct smb_charger *chg, return rc; } -int smblib_set_prop_pd_active(struct smb_charger *chg, - const union power_supply_propval *val) +static int __smblib_set_prop_pd_active(struct smb_charger *chg, bool pd_active) { int rc; bool orientation, sink_attached, hvdcp; u8 stat; - if (!get_effective_result(chg->pd_allowed_votable)) - return -EINVAL; - - chg->pd_active = val->intval; + chg->pd_active = pd_active; if (chg->pd_active) { vote(chg->apsd_disable_votable, PD_VOTER, true, 0); vote(chg->pd_allowed_votable, PD_VOTER, true, 0); @@ -2793,6 +2789,15 @@ int smblib_set_prop_pd_active(struct smb_charger *chg, return rc; } +int smblib_set_prop_pd_active(struct smb_charger *chg, + const union power_supply_propval *val) +{ + if (!get_effective_result(chg->pd_allowed_votable)) + return -EINVAL; + + return __smblib_set_prop_pd_active(chg, val->intval); +} + int smblib_set_prop_ship_mode(struct smb_charger *chg, const union power_supply_propval *val) { @@ -3544,6 +3549,13 @@ static void smblib_handle_hvdcp_check_timeout(struct smb_charger *chg, /* enforce DCP ICL if specified */ vote(chg->usb_icl_votable, DCP_VOTER, chg->dcp_icl_ua != -EINVAL, chg->dcp_icl_ua); + + /* + * if pd is not allowed, then set pd_active = false right here, + * so that it starts the hvdcp engine + */ + if (!get_effective_result(chg->pd_allowed_votable)) + __smblib_set_prop_pd_active(chg, 0); } smblib_dbg(chg, PR_INTERRUPT, "IRQ: smblib_handle_hvdcp_check_timeout %s\n", @@ -4188,7 +4200,7 @@ irqreturn_t smblib_handle_usb_typec_change(int irq, void *data) if (chg->cc2_detach_wa_active || chg->typec_en_dis_active || chg->try_sink_active) { - smblib_dbg(chg, PR_INTERRUPT, "Ignoring since %s active\n", + smblib_dbg(chg, PR_MISC | PR_INTERRUPT, "Ignoring since %s active\n", chg->cc2_detach_wa_active ? "cc2_detach_wa" : "typec_en_dis"); return IRQ_HANDLED; @@ -4699,7 +4711,9 @@ static void smblib_legacy_detection_work(struct work_struct *work) smblib_err(chg, "Couldn't disable type-c rc=%d\n", rc); /* wait for the adapter to turn off VBUS */ - msleep(500); + msleep(1000); + + smblib_dbg(chg, PR_MISC, "legacy workaround enabling typec\n"); rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG, @@ -4708,7 +4722,7 @@ static void smblib_legacy_detection_work(struct work_struct *work) smblib_err(chg, "Couldn't enable type-c rc=%d\n", rc); /* wait for type-c detection to complete */ - msleep(100); + msleep(400); rc = smblib_read(chg, TYPE_C_STATUS_5_REG, &stat); if (rc < 0) { @@ -4720,6 +4734,8 @@ static void smblib_legacy_detection_work(struct work_struct *work) vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, false, 0); legacy = stat & TYPEC_LEGACY_CABLE_STATUS_BIT; rp_high = chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_HIGH; + smblib_dbg(chg, PR_MISC, "legacy workaround done legacy = %d rp_high = %d\n", + legacy, rp_high); if (!legacy || !rp_high) vote(chg->hvdcp_disable_votable_indirect, VBUS_CC_SHORT_VOTER, false, 0); diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index b0e2e292e3cb..bb6518159d12 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -510,7 +510,7 @@ sg_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos) old_hdr->result = EIO; break; case DID_ERROR: - old_hdr->result = (srp->sense_b[0] == 0 && + old_hdr->result = (srp->sense_b[0] == 0 && hp->masked_status == GOOD) ? 0 : EIO; break; default: @@ -898,8 +898,10 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg) return -ENXIO; if (!access_ok(VERIFY_WRITE, p, SZ_SG_IO_HDR)) return -EFAULT; + mutex_lock(&sfp->parentdp->open_rel_lock); result = sg_new_write(sfp, filp, p, SZ_SG_IO_HDR, 1, read_only, 1, &srp); + mutex_unlock(&sfp->parentdp->open_rel_lock); if (result < 0) return result; result = wait_event_interruptible(sfp->read_wait, @@ -939,8 +941,10 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg) sfp->low_dma = 1; if ((0 == sfp->low_dma) && !sfp->res_in_use) { val = (int) sfp->reserve.bufflen; + mutex_lock(&sfp->parentdp->open_rel_lock); sg_remove_scat(sfp, &sfp->reserve); sg_build_reserve(sfp, val); + mutex_unlock(&sfp->parentdp->open_rel_lock); } } else { if (atomic_read(&sdp->detaching)) @@ -1009,8 +1013,8 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg) result = get_user(val, ip); if (result) return result; - if (val < 0) - return -EINVAL; + if (val < 0) + return -EINVAL; val = min_t(int, val, max_sectors_bytes(sdp->device->request_queue)); mutex_lock(&sfp->f_mutex); @@ -1020,9 +1024,10 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg) mutex_unlock(&sfp->f_mutex); return -EBUSY; } - + mutex_lock(&sfp->parentdp->open_rel_lock); sg_remove_scat(sfp, &sfp->reserve); sg_build_reserve(sfp, val); + mutex_unlock(&sfp->parentdp->open_rel_lock); } mutex_unlock(&sfp->f_mutex); return 0; @@ -1149,14 +1154,14 @@ static long sg_compat_ioctl(struct file *filp, unsigned int cmd_in, unsigned lon return -ENXIO; sdev = sdp->device; - if (sdev->host->hostt->compat_ioctl) { + if (sdev->host->hostt->compat_ioctl) { int ret; ret = sdev->host->hostt->compat_ioctl(sdev, cmd_in, (void __user *)arg); return ret; } - + return -ENOIOCTLCMD; } #endif @@ -1646,7 +1651,7 @@ init_sg(void) else def_reserved_size = sg_big_buff; - rc = register_chrdev_region(MKDEV(SCSI_GENERIC_MAJOR, 0), + rc = register_chrdev_region(MKDEV(SCSI_GENERIC_MAJOR, 0), SG_MAX_DEVS, "sg"); if (rc) return rc; @@ -2304,7 +2309,7 @@ static const struct file_operations adio_fops = { }; static int sg_proc_single_open_dressz(struct inode *inode, struct file *file); -static ssize_t sg_proc_write_dressz(struct file *filp, +static ssize_t sg_proc_write_dressz(struct file *filp, const char __user *buffer, size_t count, loff_t *off); static const struct file_operations dressz_fops = { .owner = THIS_MODULE, @@ -2444,7 +2449,7 @@ static int sg_proc_single_open_adio(struct inode *inode, struct file *file) return single_open(file, sg_proc_seq_show_int, &sg_allow_dio); } -static ssize_t +static ssize_t sg_proc_write_adio(struct file *filp, const char __user *buffer, size_t count, loff_t *off) { @@ -2465,7 +2470,7 @@ static int sg_proc_single_open_dressz(struct inode *inode, struct file *file) return single_open(file, sg_proc_seq_show_int, &sg_big_buff); } -static ssize_t +static ssize_t sg_proc_write_dressz(struct file *filp, const char __user *buffer, size_t count, loff_t *off) { @@ -2640,6 +2645,9 @@ static void sg_proc_debug_helper(struct seq_file *s, Sg_device * sdp) seq_puts(s, srp->done ? ((1 == srp->done) ? "rcv:" : "fin:") : "act:"); + seq_printf(s, srp->done ? + ((1 == srp->done) ? "rcv:" : "fin:") + : "act:"); seq_printf(s, " id=%d blen=%d", srp->header.pack_id, blen); if (srp->done) diff --git a/drivers/scsi/ufs/ufs-qcom-debugfs.c b/drivers/scsi/ufs/ufs-qcom-debugfs.c index 494ecd1c5f79..db4ecec6cf2f 100644 --- a/drivers/scsi/ufs/ufs-qcom-debugfs.c +++ b/drivers/scsi/ufs/ufs-qcom-debugfs.c @@ -121,7 +121,8 @@ static ssize_t ufs_qcom_dbg_testbus_cfg_write(struct file *file, struct ufs_hba *hba = host->hba; - ret = simple_write_to_buffer(configuration, TESTBUS_CFG_BUFF_LINE_SIZE, + ret = simple_write_to_buffer(configuration, + TESTBUS_CFG_BUFF_LINE_SIZE - 1, &buff_pos, ubuf, cnt); if (ret < 0) { dev_err(host->hba->dev, "%s: failed to read user data\n", diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 35575c071760..34109bbe69ac 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -884,7 +884,6 @@ static void ufshcd_print_host_state(struct ufs_hba *hba) hba->capabilities, hba->caps); dev_err(hba->dev, "quirks=0x%x, dev. quirks=0x%x\n", hba->quirks, hba->dev_quirks); - ufshcd_print_fsm_state(hba); } /** @@ -6834,6 +6833,7 @@ static int ufshcd_abort(struct scsi_cmnd *cmd) */ scsi_print_command(cmd); if (!hba->req_abort_count) { + ufshcd_print_fsm_state(hba); ufshcd_print_host_regs(hba); ufshcd_print_host_state(hba); ufshcd_print_pwr_info(hba); @@ -8760,7 +8760,6 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op) goto enable_gating; } - flush_work(&hba->eeh_work); ret = ufshcd_link_state_transition(hba, req_link_state, 1); if (ret) goto set_dev_active; diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c index 83efbbe25e6b..73d6bea83b95 100644 --- a/drivers/soc/qcom/icnss.c +++ b/drivers/soc/qcom/icnss.c @@ -2493,7 +2493,8 @@ static int icnss_modem_notifier_nb(struct notifier_block *nb, icnss_pr_vdbg("Modem-Notify: event %lu\n", code); - if (code == SUBSYS_AFTER_SHUTDOWN) { + if (code == SUBSYS_AFTER_SHUTDOWN && + notif->crashed == CRASH_STATUS_ERR_FATAL) { ret = icnss_assign_msa_perm_all(priv, ICNSS_MSA_PERM_DUMP_COLLECT); if (!ret) { @@ -2511,8 +2512,17 @@ static int icnss_modem_notifier_nb(struct notifier_block *nb, if (code != SUBSYS_BEFORE_SHUTDOWN) return NOTIFY_OK; - if (test_bit(ICNSS_PDR_REGISTERED, &priv->state)) + if (test_bit(ICNSS_PDR_REGISTERED, &priv->state)) { + set_bit(ICNSS_FW_DOWN, &priv->state); + icnss_ignore_qmi_timeout(true); + + fw_down_data.crashed = !!notif->crashed; + if (test_bit(ICNSS_FW_READY, &priv->state)) + icnss_call_driver_uevent(priv, + ICNSS_UEVENT_FW_DOWN, + &fw_down_data); return NOTIFY_OK; + } icnss_pr_info("Modem went down, state: 0x%lx, crashed: %d\n", priv->state, notif->crashed); @@ -2646,14 +2656,18 @@ static int icnss_service_notifier_notify(struct notifier_block *nb, icnss_pr_info("PD service down, pd_state: %d, state: 0x%lx: cause: %s\n", *state, priv->state, icnss_pdr_cause[cause]); event_post: - set_bit(ICNSS_FW_DOWN, &priv->state); - icnss_ignore_qmi_timeout(true); - clear_bit(ICNSS_HOST_TRIGGERED_PDR, &priv->state); + if (!test_bit(ICNSS_FW_DOWN, &priv->state)) { + set_bit(ICNSS_FW_DOWN, &priv->state); + icnss_ignore_qmi_timeout(true); - fw_down_data.crashed = event_data->crashed; - if (test_bit(ICNSS_FW_READY, &priv->state)) - icnss_call_driver_uevent(priv, ICNSS_UEVENT_FW_DOWN, - &fw_down_data); + fw_down_data.crashed = event_data->crashed; + if (test_bit(ICNSS_FW_READY, &priv->state)) + icnss_call_driver_uevent(priv, + ICNSS_UEVENT_FW_DOWN, + &fw_down_data); + } + + clear_bit(ICNSS_HOST_TRIGGERED_PDR, &priv->state); icnss_driver_event_post(ICNSS_DRIVER_EVENT_PD_SERVICE_DOWN, ICNSS_EVENT_SYNC, event_data); done: @@ -2805,7 +2819,8 @@ enable_pdr: return 0; } -int icnss_register_driver(struct icnss_driver_ops *ops) +int __icnss_register_driver(struct icnss_driver_ops *ops, + struct module *owner, const char *mod_name) { int ret = 0; @@ -2836,7 +2851,7 @@ int icnss_register_driver(struct icnss_driver_ops *ops) out: return ret; } -EXPORT_SYMBOL(icnss_register_driver); +EXPORT_SYMBOL(__icnss_register_driver); int icnss_unregister_driver(struct icnss_driver_ops *ops) { @@ -2862,7 +2877,7 @@ out: } EXPORT_SYMBOL(icnss_unregister_driver); -int icnss_ce_request_irq(unsigned int ce_id, +int icnss_ce_request_irq(struct device *dev, unsigned int ce_id, irqreturn_t (*handler)(int, void *), unsigned long flags, const char *name, void *ctx) { @@ -2870,7 +2885,7 @@ int icnss_ce_request_irq(unsigned int ce_id, unsigned int irq; struct ce_irq_list *irq_entry; - if (!penv || !penv->pdev) { + if (!penv || !penv->pdev || !dev) { ret = -ENODEV; goto out; } @@ -2909,13 +2924,13 @@ out: } EXPORT_SYMBOL(icnss_ce_request_irq); -int icnss_ce_free_irq(unsigned int ce_id, void *ctx) +int icnss_ce_free_irq(struct device *dev, unsigned int ce_id, void *ctx) { int ret = 0; unsigned int irq; struct ce_irq_list *irq_entry; - if (!penv || !penv->pdev) { + if (!penv || !penv->pdev || !dev) { ret = -ENODEV; goto out; } @@ -2945,11 +2960,11 @@ out: } EXPORT_SYMBOL(icnss_ce_free_irq); -void icnss_enable_irq(unsigned int ce_id) +void icnss_enable_irq(struct device *dev, unsigned int ce_id) { unsigned int irq; - if (!penv || !penv->pdev) { + if (!penv || !penv->pdev || !dev) { icnss_pr_err("Platform driver not initialized\n"); return; } @@ -2969,11 +2984,11 @@ void icnss_enable_irq(unsigned int ce_id) } EXPORT_SYMBOL(icnss_enable_irq); -void icnss_disable_irq(unsigned int ce_id) +void icnss_disable_irq(struct device *dev, unsigned int ce_id) { unsigned int irq; - if (!penv || !penv->pdev) { + if (!penv || !penv->pdev || !dev) { icnss_pr_err("Platform driver not initialized\n"); return; } @@ -2994,9 +3009,9 @@ void icnss_disable_irq(unsigned int ce_id) } EXPORT_SYMBOL(icnss_disable_irq); -int icnss_get_soc_info(struct icnss_soc_info *info) +int icnss_get_soc_info(struct device *dev, struct icnss_soc_info *info) { - if (!penv) { + if (!penv || !dev) { icnss_pr_err("Platform driver not initialized\n"); return -EINVAL; } @@ -3016,10 +3031,13 @@ int icnss_get_soc_info(struct icnss_soc_info *info) } EXPORT_SYMBOL(icnss_get_soc_info); -int icnss_set_fw_log_mode(uint8_t fw_log_mode) +int icnss_set_fw_log_mode(struct device *dev, uint8_t fw_log_mode) { int ret; + if (!dev) + return -ENODEV; + icnss_pr_dbg("FW log mode: %u\n", fw_log_mode); ret = wlfw_ini_send_sync_msg(fw_log_mode); @@ -3102,7 +3120,7 @@ out: } EXPORT_SYMBOL(icnss_athdiag_write); -int icnss_wlan_enable(struct icnss_wlan_enable_cfg *config, +int icnss_wlan_enable(struct device *dev, struct icnss_wlan_enable_cfg *config, enum icnss_driver_mode mode, const char *host_version) { @@ -3110,6 +3128,9 @@ int icnss_wlan_enable(struct icnss_wlan_enable_cfg *config, u32 i; int ret; + if (!dev) + return -ENODEV; + icnss_pr_dbg("Mode: %d, config: %p, host_version: %s\n", mode, config, host_version); @@ -3176,23 +3197,26 @@ out: } EXPORT_SYMBOL(icnss_wlan_enable); -int icnss_wlan_disable(enum icnss_driver_mode mode) +int icnss_wlan_disable(struct device *dev, enum icnss_driver_mode mode) { + if (!dev) + return -ENODEV; + return wlfw_wlan_mode_send_sync_msg(QMI_WLFW_OFF_V01); } EXPORT_SYMBOL(icnss_wlan_disable); -bool icnss_is_qmi_disable(void) +bool icnss_is_qmi_disable(struct device *dev) { return test_bit(SKIP_QMI, &quirks) ? true : false; } EXPORT_SYMBOL(icnss_is_qmi_disable); -int icnss_get_ce_id(int irq) +int icnss_get_ce_id(struct device *dev, int irq) { int i; - if (!penv || !penv->pdev) + if (!penv || !penv->pdev || !dev) return -ENODEV; for (i = 0; i < ICNSS_MAX_IRQ_REGISTRATIONS; i++) { @@ -3206,11 +3230,11 @@ int icnss_get_ce_id(int irq) } EXPORT_SYMBOL(icnss_get_ce_id); -int icnss_get_irq(int ce_id) +int icnss_get_irq(struct device *dev, int ce_id) { int irq; - if (!penv || !penv->pdev) + if (!penv || !penv->pdev || !dev) return -ENODEV; if (ce_id >= ICNSS_MAX_IRQ_REGISTRATIONS) @@ -3644,7 +3668,7 @@ static int icnss_test_mode_fw_test_off(struct icnss_priv *priv) goto out; } - icnss_wlan_disable(ICNSS_OFF); + icnss_wlan_disable(&priv->pdev->dev, ICNSS_OFF); ret = icnss_hw_power_off(priv); @@ -3685,7 +3709,7 @@ static int icnss_test_mode_fw_test(struct icnss_priv *priv, set_bit(ICNSS_FW_TEST_MODE, &priv->state); - ret = icnss_wlan_enable(NULL, mode, NULL); + ret = icnss_wlan_enable(&priv->pdev->dev, NULL, mode, NULL); if (ret) goto power_off; diff --git a/drivers/soc/qcom/msm_bus/msm_bus_dbg_voter.c b/drivers/soc/qcom/msm_bus/msm_bus_dbg_voter.c index a876484859eb..ba1adb8acea7 100644 --- a/drivers/soc/qcom/msm_bus/msm_bus_dbg_voter.c +++ b/drivers/soc/qcom/msm_bus/msm_bus_dbg_voter.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. * * This program is Mree software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -27,6 +27,7 @@ struct msm_bus_floor_client_type { }; static struct class *bus_floor_class; +static DEFINE_RT_MUTEX(msm_bus_floor_vote_lock); #define MAX_VOTER_NAME (50) #define DEFAULT_NODE_WIDTH (8) #define DBG_NAME(s) (strnstr(s, "-", 7) + 1) @@ -64,18 +65,22 @@ static ssize_t bus_floor_active_only_store(struct device *dev, { struct msm_bus_floor_client_type *cl; + rt_mutex_lock(&msm_bus_floor_vote_lock); cl = dev_get_drvdata(dev); if (!cl) { pr_err("%s: Can't find cl", __func__); + rt_mutex_unlock(&msm_bus_floor_vote_lock); return 0; } if (sscanf(buf, "%d", &cl->active_only) != 1) { pr_err("%s:return error", __func__); + rt_mutex_unlock(&msm_bus_floor_vote_lock); return -EINVAL; } + rt_mutex_unlock(&msm_bus_floor_vote_lock); return n; } @@ -100,20 +105,24 @@ static ssize_t bus_floor_vote_store(struct device *dev, struct msm_bus_floor_client_type *cl; int ret = 0; + rt_mutex_lock(&msm_bus_floor_vote_lock); cl = dev_get_drvdata(dev); if (!cl) { pr_err("%s: Can't find cl", __func__); + rt_mutex_unlock(&msm_bus_floor_vote_lock); return 0; } if (sscanf(buf, "%llu", &cl->cur_vote_hz) != 1) { pr_err("%s:return error", __func__); + rt_mutex_unlock(&msm_bus_floor_vote_lock); return -EINVAL; } ret = msm_bus_floor_vote_context(dev_name(dev), cl->cur_vote_hz, cl->active_only); + rt_mutex_unlock(&msm_bus_floor_vote_lock); return n; } @@ -126,15 +135,18 @@ static ssize_t bus_floor_vote_store_api(struct device *dev, char name[10]; u64 vote_khz = 0; + rt_mutex_lock(&msm_bus_floor_vote_lock); cl = dev_get_drvdata(dev); if (!cl) { pr_err("%s: Can't find cl", __func__); + rt_mutex_unlock(&msm_bus_floor_vote_lock); return 0; } if (sscanf(buf, "%9s %llu", name, &vote_khz) != 2) { pr_err("%s:return error", __func__); + rt_mutex_unlock(&msm_bus_floor_vote_lock); return -EINVAL; } @@ -142,6 +154,7 @@ static ssize_t bus_floor_vote_store_api(struct device *dev, __func__, name, vote_khz); ret = msm_bus_floor_vote(name, vote_khz); + rt_mutex_unlock(&msm_bus_floor_vote_lock); return n; } diff --git a/drivers/soc/qcom/qdsp6v2/msm_audio_ion_vm.c b/drivers/soc/qcom/qdsp6v2/msm_audio_ion_vm.c index a3aa8823d8ce..afc40461e8e8 100644 --- a/drivers/soc/qcom/qdsp6v2/msm_audio_ion_vm.c +++ b/drivers/soc/qcom/qdsp6v2/msm_audio_ion_vm.c @@ -22,7 +22,6 @@ #include <linux/msm_audio_ion.h> #include <linux/habmm.h> #include "../../../staging/android/ion/ion_priv.h" -#include "../../../staging/android/ion/ion_hvenv_driver.h" #define MSM_AUDIO_ION_PROBED (1 << 0) @@ -628,7 +627,7 @@ struct ion_client *msm_audio_ion_client_create(const char *name) { struct ion_client *pclient = NULL; - pclient = hvenv_ion_client_create(name); + pclient = msm_ion_client_create(name); return pclient; } diff --git a/drivers/soc/qcom/service-locator.c b/drivers/soc/qcom/service-locator.c index f19db5fe99b3..52355699e4f3 100644 --- a/drivers/soc/qcom/service-locator.c +++ b/drivers/soc/qcom/service-locator.c @@ -149,11 +149,10 @@ static void service_locator_recv_msg(struct work_struct *work) do { pr_debug("Notified about a Receive event\n"); - ret = qmi_recv_msg(service_locator.clnt_handle); - if (ret < 0) - pr_err("Error receiving message rc:%d. Retrying...\n", - ret); - } while (ret == 0); + } while ((ret = qmi_recv_msg(service_locator.clnt_handle)) == 0); + + if (ret != -ENOMSG) + pr_err("Error receiving message rc:%d\n", ret); } @@ -190,7 +189,7 @@ static int servreg_loc_send_msg(struct msg_desc *req_desc, */ rc = qmi_send_req_wait(service_locator.clnt_handle, req_desc, req, sizeof(*req), resp_desc, resp, sizeof(*resp), - msecs_to_jiffies(QMI_SERVREG_LOC_SERVER_TIMEOUT)); + QMI_SERVREG_LOC_SERVER_TIMEOUT); if (rc < 0) { pr_err("QMI send req failed for client %s, ret - %d\n", pd->client_name, rc); diff --git a/drivers/spi/spi_qsd.c b/drivers/spi/spi_qsd.c index da58f19dd6e6..73396072a052 100644 --- a/drivers/spi/spi_qsd.c +++ b/drivers/spi/spi_qsd.c @@ -33,6 +33,7 @@ #include <linux/debugfs.h> #include <linux/gpio.h> #include <linux/of.h> +#include <linux/of_device.h> #include <linux/of_gpio.h> #include <linux/dma-mapping.h> #include <linux/sched.h> @@ -52,6 +53,7 @@ static int msm_spi_pm_suspend_runtime(struct device *device); static inline void msm_spi_dma_unmap_buffers(struct msm_spi *dd); static int get_local_resources(struct msm_spi *dd); static void put_local_resources(struct msm_spi *dd); +static void msm_spi_slv_setup(struct msm_spi *dd); static inline int msm_spi_configure_gsbi(struct msm_spi *dd, struct platform_device *pdev) @@ -84,7 +86,10 @@ static inline int msm_spi_configure_gsbi(struct msm_spi *dd, static inline void msm_spi_register_init(struct msm_spi *dd) { - writel_relaxed(0x00000001, dd->base + SPI_SW_RESET); + if (dd->pdata->is_slv_ctrl) + writel_relaxed(0x00000002, dd->base + SPI_SW_RESET); + else + writel_relaxed(0x00000001, dd->base + SPI_SW_RESET); msm_spi_set_state(dd, SPI_OP_STATE_RESET); writel_relaxed(0x00000000, dd->base + SPI_OPERATIONAL); writel_relaxed(0x00000000, dd->base + SPI_CONFIG); @@ -932,6 +937,7 @@ static inline void msm_spi_ack_transfer(struct msm_spi *dd) static inline irqreturn_t msm_spi_qup_irq(int irq, void *dev_id) { u32 op, ret = IRQ_NONE; + u32 slv; struct msm_spi *dd = dev_id; if (pm_runtime_suspended(dd->dev)) { @@ -945,7 +951,9 @@ static inline irqreturn_t msm_spi_qup_irq(int irq, void *dev_id) } op = readl_relaxed(dd->base + SPI_OPERATIONAL); + slv = readl_relaxed(dd->base + SPI_SLAVE_IRQ_STATUS); writel_relaxed(op, dd->base + SPI_OPERATIONAL); + writel_relaxed(slv, dd->base + SPI_SLAVE_IRQ_STATUS); /* * Ensure service flag was cleared before further * processing of interrupt. @@ -1234,7 +1242,10 @@ msm_spi_use_dma(struct msm_spi *dd, struct spi_transfer *tr, u8 bpw) static void msm_spi_set_transfer_mode(struct msm_spi *dd, u8 bpw, u32 read_count) { - if (msm_spi_use_dma(dd, dd->cur_transfer, bpw)) { + if (dd->pdata->is_slv_ctrl) { + dd->tx_mode = SPI_BAM_MODE; + dd->rx_mode = SPI_BAM_MODE; + } else if (msm_spi_use_dma(dd, dd->cur_transfer, bpw)) { dd->tx_mode = SPI_BAM_MODE; dd->rx_mode = SPI_BAM_MODE; } else { @@ -1353,7 +1364,7 @@ static void get_transfer_length(struct msm_spi *dd) static int msm_spi_process_transfer(struct msm_spi *dd) { u8 bpw; - u32 max_speed; + u32 max_speed = 0; u32 read_count; u32 timeout; u32 spi_ioc; @@ -1392,7 +1403,7 @@ static int msm_spi_process_transfer(struct msm_spi *dd) DIV_ROUND_UP(max_speed, MSEC_PER_SEC))); read_count = DIV_ROUND_UP(dd->cur_msg_len, dd->bytes_per_word); - if (dd->spi->mode & SPI_LOOP) + if (dd->spi->mode & SPI_LOOP && !dd->pdata->is_slv_ctrl) int_loopback = 1; if (msm_spi_set_state(dd, SPI_OP_STATE_RESET)) @@ -1414,8 +1425,11 @@ static int msm_spi_process_transfer(struct msm_spi *dd) msm_spi_set_qup_io_modes(dd); msm_spi_set_spi_config(dd, bpw); msm_spi_set_qup_config(dd, bpw); - spi_ioc = msm_spi_set_spi_io_control(dd); + if (!dd->pdata->is_slv_ctrl) + spi_ioc = msm_spi_set_spi_io_control(dd); msm_spi_set_qup_op_mask(dd); + if (dd->pdata->is_slv_ctrl) + msm_spi_slv_setup(dd); /* The output fifo interrupt handler will handle all writes after the first. Restricting this to one write avoids contention @@ -1482,12 +1496,20 @@ transfer_end: dd->rx_mode = SPI_MODE_NONE; msm_spi_set_state(dd, SPI_OP_STATE_RESET); - if (!dd->cur_transfer->cs_change) + if (!dd->cur_transfer->cs_change && !dd->pdata->is_slv_ctrl) writel_relaxed(spi_ioc & ~SPI_IO_C_MX_CS_MODE, dd->base + SPI_IO_CONTROL); return status; } +static int msm_spi_slv_abort(struct spi_master *spi) +{ + struct msm_spi *dd = spi_master_get_devdata(spi); + + complete_all(&dd->tx_transfer_complete); + complete_all(&dd->rx_transfer_complete); + return 0; +} static inline void msm_spi_set_cs(struct spi_device *spi, bool set_flag) { @@ -1753,6 +1775,32 @@ static int msm_spi_unprepare_transfer_hardware(struct spi_master *master) return 0; } +static void msm_spi_slv_setup(struct msm_spi *dd) +{ + u32 spi_config = readl_relaxed(dd->base + SPI_CONFIG); + u32 qup_config = readl_relaxed(dd->base + QUP_CONFIG); + u32 irq_en = GENMASK(6, 0); + + qup_config &= ~QUP_CFG_MODE; + qup_config |= QUP_CONFIG_SPI_SLAVE; + qup_config |= (SPI_EN_EXT_OUT_FLAG | APP_CLK_ON_EN | CORE_CLK_ON_EN + | FIFO_CLK_ON_EN | CORE_EX_CLK_ON_EN); + spi_config |= SPI_CFG_SLAVE_OP; + writel_relaxed(qup_config, dd->base + QUP_CONFIG); + writel_relaxed(spi_config, dd->base + SPI_CONFIG); + writel_relaxed(irq_en, (dd->base + SPI_SLAVE_IRQ_EN)); + if (dd->read_buf && !dd->write_buf) { + u32 slv_cfg = + readl_relaxed(dd->base + SPI_SLAVE_CONFIG); + slv_cfg |= (RX_UNBALANCED_MASK | SPI_S_CGC_EN); + writel_relaxed(slv_cfg, (dd->base + SPI_SLAVE_CONFIG)); + } + /* + * Ensure Slave setup completes before returning. + */ + mb(); +} + static int msm_spi_setup(struct spi_device *spi) { struct msm_spi *dd; @@ -2248,6 +2296,8 @@ struct msm_spi_platform_data *msm_spi_dt_to_pdata( &pdata->rt_priority, DT_OPT, DT_BOOL, 0}, {"qcom,shared", &pdata->is_shared, DT_OPT, DT_BOOL, 0}, + {"qcom,slv-ctrl", + &pdata->is_slv_ctrl, DT_OPT, DT_BOOL, 0}, {NULL, NULL, 0, 0, 0}, }; @@ -2451,6 +2501,12 @@ err_clk_get: return rc; } +static const struct of_device_id msm_spi_dt_match[] = { + { .compatible = "qcom,spi-qup-v2", }, + { .compatible = "qcom,qup-v26", }, + {} +}; + static int msm_spi_probe(struct platform_device *pdev) { struct spi_master *master; @@ -2481,6 +2537,9 @@ static int msm_spi_probe(struct platform_device *pdev) dd = spi_master_get_devdata(master); if (pdev->dev.of_node) { + const struct of_device_id *dev_id; + enum msm_spi_qup_version ver; + dd->qup_ver = SPI_QUP_VERSION_BFAM; master->dev.of_node = pdev->dev.of_node; pdata = msm_spi_dt_to_pdata(pdev, dd); @@ -2495,6 +2554,17 @@ static int msm_spi_probe(struct platform_device *pdev) "using default bus_num %d\n", pdev->id); else master->bus_num = pdev->id = rc; + + dev_id = of_match_device(msm_spi_dt_match, &pdev->dev); + if (dev_id) + ver = SPI_QUP_VERSION_SPI_SLV; + else + ver = SPI_QUP_VERSION_BFAM; + + if (ver >= SPI_QUP_VERSION_SPI_SLV) + dd->slv_support = true; + else + dd->slv_support = false; } else { pdata = pdev->dev.platform_data; dd->qup_ver = SPI_QUP_VERSION_NONE; @@ -2553,6 +2623,21 @@ static int msm_spi_probe(struct platform_device *pdev) } spi_dma_mask(&pdev->dev); + + if (pdata && pdata->is_slv_ctrl) { + if (!dd->slv_support) { + rc = -ENXIO; + dev_err(&pdev->dev, "QUP ver %d, no slv support\n", + dd->qup_ver); + goto err_probe_res; + } + + master->slave = true; + master->set_cs = NULL; + master->setup = NULL; + master->slave_abort = msm_spi_slv_abort; + } + skip_dma_resources: spin_lock_init(&dd->queue_lock); @@ -2753,13 +2838,6 @@ static int msm_spi_remove(struct platform_device *pdev) return 0; } -static struct of_device_id msm_spi_dt_match[] = { - { - .compatible = "qcom,spi-qup-v2", - }, - {} -}; - static const struct dev_pm_ops msm_spi_dev_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(msm_spi_suspend, msm_spi_resume) SET_RUNTIME_PM_OPS(msm_spi_pm_suspend_runtime, diff --git a/drivers/spi/spi_qsd.h b/drivers/spi/spi_qsd.h index 47d69965f18a..6632fe806e41 100644 --- a/drivers/spi/spi_qsd.h +++ b/drivers/spi/spi_qsd.h @@ -38,6 +38,7 @@ #define QUP_MX_WRITE_CNT_CURRENT 0x0154 #define QUP_CONFIG_SPI_MODE 0x0100 +#define QUP_CONFIG_SPI_SLAVE 0x0400 #endif #define GSBI_CTRL_REG 0x0 @@ -72,17 +73,26 @@ #define SPI_OUTPUT_FIFO QSD_REG(0x0100) QUP_REG(0x0110) #define SPI_INPUT_FIFO QSD_REG(0x0200) QUP_REG(0x0218) #define SPI_STATE QSD_REG(SPI_OPERATIONAL) QUP_REG(0x0004) +#define SPI_SLAVE_IRQ_STATUS (0x0330) +#define SPI_SLAVE_IRQ_EN (0x0334) +#define SPI_SLAVE_CONFIG (0x0338) /* QUP_CONFIG fields */ #define SPI_CFG_N 0x0000001F #define SPI_NO_INPUT 0x00000080 #define SPI_NO_OUTPUT 0x00000040 #define SPI_EN_EXT_OUT_FLAG 0x00010000 +#define QUP_CFG_MODE 0x00000F00 +#define APP_CLK_ON_EN BIT(12) +#define CORE_CLK_ON_EN BIT(13) +#define FIFO_CLK_ON_EN BIT(14) +#define CORE_EX_CLK_ON_EN BIT(15) /* SPI_CONFIG fields */ #define SPI_CFG_LOOPBACK 0x00000100 #define SPI_CFG_INPUT_FIRST 0x00000200 #define SPI_CFG_HS_MODE 0x00000400 +#define SPI_CFG_SLAVE_OP 0x00000020 /* SPI_IO_CONTROL fields */ #define SPI_IO_C_FORCE_CS 0x00000800 @@ -128,6 +138,23 @@ #define SPI_OP_STATE_CLEAR_BITS 0x2 +/* SPI SLAVE IRQ_STATUS/EN fields */ +#define CS_N_ASSERT BIT(0) +#define CS_N_DEASSERT BIT(1) +#define CS_N_ETXT BIT(2) +#define TX_UNDERFLOW BIT(3) +#define RX_OVERFLOW_WAIT_EOT BIT(4) +#define RX_OVERFLOW_NO_EOT BIT(5) +#define CS_N_ERXT BIT(6) + +/* SPI_SLAVE_CONFIG Fields */ +#define RX_N_SHIFT BIT(0) +#define PAUSE_ON_ERR_DIS BIT(1) +#define SPI_S_CGC_EN BIT(2) +#define RX_UNBALANCED_MASK BIT(3) +#define SLAVE_DIS_RESET_ST BIT(4) +#define SLAVE_AUTO_PAUSE_EOT BIT(7) + #define SPI_PINCTRL_STATE_DEFAULT "spi_default" #define SPI_PINCTRL_STATE_SLEEP "spi_sleep" @@ -177,6 +204,7 @@ enum msm_spi_state { enum msm_spi_qup_version { SPI_QUP_VERSION_NONE = 0x0, SPI_QUP_VERSION_BFAM = 0x2, + SPI_QUP_VERSION_SPI_SLV = 0x26, }; enum msm_spi_pipe_direction { @@ -376,6 +404,7 @@ struct msm_spi { struct pinctrl_state *pins_sleep; bool is_init_complete; bool pack_words; + bool slv_support; }; /* Forward declaration */ diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index c31c753b6e28..72ee12782b6c 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -2264,6 +2264,16 @@ usb_hcd_get_xfer_ring_dma_addr(struct usb_device *udev, return hcd->driver->get_xfer_ring_dma_addr(hcd, udev, ep); } +int usb_hcd_get_controller_id(struct usb_device *udev) +{ + struct usb_hcd *hcd = bus_to_hcd(udev->bus); + + if (!HCD_RH_RUNNING(hcd)) + return -EINVAL; + + return hcd->driver->get_core_id(hcd); +} + #ifdef CONFIG_PM int hcd_bus_suspend(struct usb_device *rhdev, pm_message_t msg) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index c08a524f3dab..5644051b4010 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -4294,6 +4294,8 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1, enum usb_device_speed oldspeed = udev->speed; const char *speed; int devnum = udev->devnum; + char *error_event[] = { + "USB_DEVICE_ERROR=Device_No_Response", NULL }; /* root hub ports have a slightly longer reset period * (from USB 2.0 spec, section 7.1.7.5) @@ -4467,6 +4469,8 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1, if (r != -ENODEV) dev_err(&udev->dev, "device descriptor read/64, error %d\n", r); + kobject_uevent_env(&udev->parent->dev.kobj, + KOBJ_CHANGE, error_event); retval = -EMSGSIZE; continue; } @@ -4519,6 +4523,8 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1, dev_err(&udev->dev, "device descriptor read/8, error %d\n", retval); + kobject_uevent_env(&udev->parent->dev.kobj, + KOBJ_CHANGE, error_event); if (retval >= 0) retval = -EMSGSIZE; } else { diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 062677f8e91d..e64fd6570a23 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -717,6 +717,15 @@ dma_addr_t usb_get_xfer_ring_dma_addr(struct usb_device *dev, } EXPORT_SYMBOL(usb_get_xfer_ring_dma_addr); +int usb_get_controller_id(struct usb_device *dev) +{ + if (dev->state == USB_STATE_NOTATTACHED) + return -EINVAL; + + return usb_hcd_get_controller_id(dev); +} +EXPORT_SYMBOL(usb_get_controller_id); + /*-------------------------------------------------------------------*/ /* * __usb_get_extra_descriptor() finds a descriptor of specific type in the diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index c244d908fa4f..24ecbc469eb6 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -282,7 +282,7 @@ out: return ret; } -static void dwc3_ep0_stall_and_restart(struct dwc3 *dwc) +void dwc3_ep0_stall_and_restart(struct dwc3 *dwc) { struct dwc3_ep *dep; diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 94709587f238..f108aecbfe52 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -2882,6 +2882,15 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc) dwc3_writel(dwc->regs, DWC3_DCTL, reg); dwc->test_mode = false; + /* + * From SNPS databook section 8.1.2 + * the EP0 should be in setup phase. So ensure + * that EP0 is in setup phase by issuing a stall + * and restart if EP0 is not in setup phase. + */ + if (dwc->ep0state != EP0_SETUP_PHASE) + dwc3_ep0_stall_and_restart(dwc); + dwc3_stop_active_transfers(dwc); dwc3_clear_stall_all_ep(dwc); diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h index baa83cf9638b..5b3ffbe3056d 100644 --- a/drivers/usb/dwc3/gadget.h +++ b/drivers/usb/dwc3/gadget.h @@ -98,6 +98,7 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req, void dwc3_ep0_interrupt(struct dwc3 *dwc, const struct dwc3_event_depevt *event); void dwc3_ep0_out_start(struct dwc3 *dwc); +void dwc3_ep0_stall_and_restart(struct dwc3 *dwc); int __dwc3_gadget_ep0_set_halt(struct usb_ep *ep, int value); int dwc3_gadget_ep0_set_halt(struct usb_ep *ep, int value); int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request, diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index bb02b3be17f7..2cbd90a7db43 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -49,7 +49,7 @@ static void *ffs_ipc_log; if (ffs_ipc_log) \ ipc_log_string(ffs_ipc_log, "%s: " fmt, __func__, \ ##__VA_ARGS__); \ - pr_debug(fmt, ##__VA_ARGS__); \ + pr_debug("%s: " fmt, __func__, ##__VA_ARGS__); \ } while (0) /* Reference counter handling */ @@ -68,6 +68,18 @@ __ffs_data_got_descs(struct ffs_data *ffs, char *data, size_t len); static int __must_check __ffs_data_got_strings(struct ffs_data *ffs, char *data, size_t len); +/* ffs instance status */ +static DEFINE_MUTEX(ffs_ep_lock); +static bool ffs_inst_exist; +static struct f_fs_opts *g_opts; + +/* Free instance structures */ +static void ffs_inst_clean(struct f_fs_opts *opts); +static void ffs_inst_clean_delay(void); +static int ffs_inst_exist_check(void); + +/* Global ffs_data pointer */ +static struct ffs_data *g_ffs_data; /* The function structure ***************************************************/ @@ -288,6 +300,10 @@ static ssize_t ffs_ep0_write(struct file *file, const char __user *buf, ffs_log("enter:len %zu state %d setup_state %d flags %lu", len, ffs->state, ffs->setup_state, ffs->flags); + ret = ffs_inst_exist_check(); + if (ret < 0) + return ret; + /* Fast check if setup was canceled */ if (ffs_setup_state_clear_cancelled(ffs) == FFS_SETUP_CANCELLED) return -EIDRM; @@ -474,6 +490,10 @@ static ssize_t ffs_ep0_read(struct file *file, char __user *buf, ffs_log("enter:len %zu state %d setup_state %d flags %lu", len, ffs->state, ffs->setup_state, ffs->flags); + ret = ffs_inst_exist_check(); + if (ret < 0) + return ret; + /* Fast check if setup was canceled */ if (ffs_setup_state_clear_cancelled(ffs) == FFS_SETUP_CANCELLED) return -EIDRM; @@ -574,12 +594,17 @@ done_mutex: static int ffs_ep0_open(struct inode *inode, struct file *file) { struct ffs_data *ffs = inode->i_private; + int ret; ENTER(); ffs_log("state %d setup_state %d flags %lu opened %d", ffs->state, ffs->setup_state, ffs->flags, atomic_read(&ffs->opened)); + ret = ffs_inst_exist_check(); + if (ret < 0) + return ret; + if (unlikely(ffs->state == FFS_CLOSING)) return -EBUSY; @@ -618,6 +643,10 @@ static long ffs_ep0_ioctl(struct file *file, unsigned code, unsigned long value) ffs_log("state %d setup_state %d flags %lu opened %d", ffs->state, ffs->setup_state, ffs->flags, atomic_read(&ffs->opened)); + ret = ffs_inst_exist_check(); + if (ret < 0) + return ret; + if (code == FUNCTIONFS_INTERFACE_REVMAP) { struct ffs_function *func = ffs->func; ret = func ? ffs_func_revmap_intf(func, value) : -ENODEV; @@ -639,6 +668,10 @@ static unsigned int ffs_ep0_poll(struct file *file, poll_table *wait) ffs_log("enter:state %d setup_state %d flags %lu opened %d", ffs->state, ffs->setup_state, ffs->flags, atomic_read(&ffs->opened)); + ret = ffs_inst_exist_check(); + if (ret < 0) + return ret; + poll_wait(file, &ffs->ev.waitq, wait); ret = ffs_mutex_lock(&ffs->mutex, file->f_flags & O_NONBLOCK); @@ -1045,12 +1078,17 @@ static int ffs_epfile_open(struct inode *inode, struct file *file) { struct ffs_epfile *epfile = inode->i_private; + int ret; ENTER(); ffs_log("enter:state %d setup_state %d flag %lu", epfile->ffs->state, epfile->ffs->setup_state, epfile->ffs->flags); + ret = ffs_inst_exist_check(); + if (ret < 0) + return ret; + if (WARN_ON(epfile->ffs->state != FFS_ACTIVE)) return -ENODEV; @@ -1105,11 +1143,16 @@ static ssize_t ffs_epfile_write_iter(struct kiocb *kiocb, struct iov_iter *from) { struct ffs_io_data io_data, *p = &io_data; ssize_t res; + int ret; ENTER(); ffs_log("enter"); + ret = ffs_inst_exist_check(); + if (ret < 0) + return ret; + if (!is_sync_kiocb(kiocb)) { p = kmalloc(sizeof(io_data), GFP_KERNEL); if (unlikely(!p)) @@ -1146,11 +1189,16 @@ static ssize_t ffs_epfile_read_iter(struct kiocb *kiocb, struct iov_iter *to) { struct ffs_io_data io_data, *p = &io_data; ssize_t res; + int ret; ENTER(); ffs_log("enter"); + ret = ffs_inst_exist_check(); + if (ret < 0) + return ret; + if (!is_sync_kiocb(kiocb)) { p = kmalloc(sizeof(io_data), GFP_KERNEL); if (unlikely(!p)) @@ -1227,6 +1275,10 @@ static long ffs_epfile_ioctl(struct file *file, unsigned code, ffs_log("enter:state %d setup_state %d flag %lu", epfile->ffs->state, epfile->ffs->setup_state, epfile->ffs->flags); + ret = ffs_inst_exist_check(); + if (ret < 0) + return ret; + if (WARN_ON(epfile->ffs->state != FFS_ACTIVE)) return -ENODEV; @@ -1582,7 +1634,6 @@ ffs_fs_kill_sb(struct super_block *sb) if (sb->s_fs_info) { ffs_release_dev(sb->s_fs_info); ffs_data_closed(sb->s_fs_info); - ffs_data_put(sb->s_fs_info); } ffs_log("exit"); @@ -1667,11 +1718,16 @@ static void ffs_data_put(struct ffs_data *ffs) smp_mb__before_atomic(); if (unlikely(atomic_dec_and_test(&ffs->ref))) { pr_info("%s(): freeing\n", __func__); + /* Clear g_ffs_data */ + ffs_dev_lock(); + g_ffs_data = NULL; + ffs_dev_unlock(); ffs_data_clear(ffs); BUG_ON(waitqueue_active(&ffs->ev.waitq) || waitqueue_active(&ffs->ep0req_completion.wait)); kfree(ffs->dev_name); kfree(ffs); + ffs_inst_clean_delay(); } ffs_log("exit"); @@ -1736,6 +1792,11 @@ static struct ffs_data *ffs_data_new(void) /* XXX REVISIT need to update it in some places, or do we? */ ffs->ev.can_stall = 1; + /* Store ffs to g_ffs_data */ + ffs_dev_lock(); + g_ffs_data = ffs; + ffs_dev_unlock(); + ffs_log("exit"); return ffs; @@ -3621,17 +3682,71 @@ static struct config_item_type ffs_func_type = { /* Function registration interface ******************************************/ -static void ffs_free_inst(struct usb_function_instance *f) +static int ffs_inst_exist_check(void) { - struct f_fs_opts *opts; + mutex_lock(&ffs_ep_lock); - opts = to_f_fs_opts(f); + if (unlikely(ffs_inst_exist == false)) { + mutex_unlock(&ffs_ep_lock); + pr_err_ratelimited( + "%s: f_fs instance freed already.\n", + __func__); + return -ENODEV; + } + + mutex_unlock(&ffs_ep_lock); + + return 0; +} + +static void ffs_inst_clean(struct f_fs_opts *opts) +{ + g_opts = NULL; ffs_dev_lock(); _ffs_free_dev(opts->dev); ffs_dev_unlock(); kfree(opts); } +static void ffs_inst_clean_delay(void) +{ + mutex_lock(&ffs_ep_lock); + + if (unlikely(ffs_inst_exist == false)) { + if (g_opts) { + ffs_inst_clean(g_opts); + pr_err_ratelimited("%s: Delayed free memory\n", + __func__); + } + mutex_unlock(&ffs_ep_lock); + return; + } + + mutex_unlock(&ffs_ep_lock); +} + +static void ffs_free_inst(struct usb_function_instance *f) +{ + struct f_fs_opts *opts; + + opts = to_f_fs_opts(f); + + mutex_lock(&ffs_ep_lock); + if (opts->dev->ffs_data + && atomic_read(&opts->dev->ffs_data->opened)) { + ffs_inst_exist = false; + mutex_unlock(&ffs_ep_lock); + ffs_log("%s: Dev is open, free mem when dev close\n", + __func__); + return; + } + + ffs_inst_clean(opts); + ffs_inst_exist = false; + g_opts = NULL; + mutex_unlock(&ffs_ep_lock); +} + #define MAX_INST_NAME_LEN 40 static int ffs_set_inst_name(struct usb_function_instance *fi, const char *name) @@ -3649,6 +3764,14 @@ static int ffs_set_inst_name(struct usb_function_instance *fi, const char *name) if (!ptr) return -ENOMEM; + mutex_lock(&ffs_ep_lock); + if (g_opts) { + mutex_unlock(&ffs_ep_lock); + ffs_log("%s: prev inst do not freed yet\n", __func__); + return -EBUSY; + } + mutex_unlock(&ffs_ep_lock); + opts = to_f_fs_opts(fi); tmp = NULL; @@ -3663,10 +3786,27 @@ static int ffs_set_inst_name(struct usb_function_instance *fi, const char *name) } opts->dev->name_allocated = true; + /* + * If ffs instance is freed and created once, new allocated + * opts->dev need to initialize opts->dev->ffs_data, and + * ffs_private_data also need to update new allocated opts->dev + * address. + */ + if (g_ffs_data) + opts->dev->ffs_data = g_ffs_data; + + if (opts->dev->ffs_data) + opts->dev->ffs_data->private_data = opts->dev; + ffs_dev_unlock(); kfree(tmp); + mutex_lock(&ffs_ep_lock); + ffs_inst_exist = true; + g_opts = opts; + mutex_unlock(&ffs_ep_lock); + return 0; } diff --git a/drivers/usb/gadget/function/f_gsi.c b/drivers/usb/gadget/function/f_gsi.c index 18e3c5cdcc24..67f7e75a9219 100644 --- a/drivers/usb/gadget/function/f_gsi.c +++ b/drivers/usb/gadget/function/f_gsi.c @@ -554,6 +554,9 @@ static int ipa_suspend_work_handler(struct gsi_data_port *d_port) if (!usb_gsi_ep_op(gsi->d_port.in_ep, (void *) &f_suspend, GSI_EP_OP_CHECK_FOR_SUSPEND)) { ret = -EFAULT; + block_db = false; + usb_gsi_ep_op(d_port->in_ep, (void *)&block_db, + GSI_EP_OP_SET_CLR_BLOCK_DBL); goto done; } diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index c6998f086e12..be72953f9737 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -233,6 +233,10 @@ static int xhci_plat_probe(struct platform_device *pdev) hcd_to_bus(xhci->shared_hcd)->skip_resume = true; + if (device_property_read_u32(pdev->dev.parent, "usb-core-id", + &xhci->core_id)) + xhci->core_id = -EINVAL; + hcd->usb_phy = devm_usb_get_phy_by_phandle(&pdev->dev, "usb-phy", 0); if (IS_ERR(hcd->usb_phy)) { ret = PTR_ERR(hcd->usb_phy); diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 641e0280ad5a..be9258c6efda 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -5031,6 +5031,13 @@ dma_addr_t xhci_get_xfer_ring_dma_addr(struct usb_hcd *hcd, return 0; } +int xhci_get_core_id(struct usb_hcd *hcd) +{ + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + + return xhci->core_id; +} + static const struct hc_driver xhci_hc_driver = { .description = "xhci-hcd", .product_desc = "xHCI Host Controller", @@ -5095,6 +5102,7 @@ static const struct hc_driver xhci_hc_driver = { .get_sec_event_ring_dma_addr = xhci_get_sec_event_ring_dma_addr, .get_xfer_ring_dma_addr = xhci_get_xfer_ring_dma_addr, .get_dcba_dma_addr = xhci_get_dcba_dma_addr, + .get_core_id = xhci_get_core_id, }; void xhci_init_driver(struct hc_driver *drv, diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index c665806983be..ac637dc6e3cc 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1519,6 +1519,8 @@ struct xhci_hcd { /* secondary interrupter */ struct xhci_intr_reg __iomem **sec_ir_set; + int core_id; + /* Cached register copies of read-only HC data */ __u32 hcs_params1; __u32 hcs_params2; @@ -1946,6 +1948,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength); int xhci_hub_status_data(struct usb_hcd *hcd, char *buf); int xhci_find_raw_port_number(struct usb_hcd *hcd, int port1); +int xhci_get_core_id(struct usb_hcd *hcd); #ifdef CONFIG_PM int xhci_bus_suspend(struct usb_hcd *hcd); diff --git a/drivers/video/fbdev/msm/mdss_dp_util.c b/drivers/video/fbdev/msm/mdss_dp_util.c index 037741df4382..5cb141b1d5e7 100644 --- a/drivers/video/fbdev/msm/mdss_dp_util.c +++ b/drivers/video/fbdev/msm/mdss_dp_util.c @@ -1233,6 +1233,7 @@ static void mdss_dp_audio_setup_audio_stream_sdp(struct dss_io_data *ctrl_io, /* Config header and parity byte 1 */ value = readl_relaxed(ctrl_io->base + MMSS_DP_AUDIO_STREAM_0); + value &= 0x0000ffff; new_value = 0x02; parity_byte = mdss_dp_calculate_parity_byte(new_value); value |= ((new_value << HEADER_BYTE_1_BIT) @@ -1243,7 +1244,8 @@ static void mdss_dp_audio_setup_audio_stream_sdp(struct dss_io_data *ctrl_io, /* Config header and parity byte 2 */ value = readl_relaxed(ctrl_io->base + MMSS_DP_AUDIO_STREAM_1); - new_value = value; + value &= 0xffff0000; + new_value = 0x00; parity_byte = mdss_dp_calculate_parity_byte(new_value); value |= ((new_value << HEADER_BYTE_2_BIT) | (parity_byte << PARITY_BYTE_2_BIT)); @@ -1253,6 +1255,7 @@ static void mdss_dp_audio_setup_audio_stream_sdp(struct dss_io_data *ctrl_io, /* Config header and parity byte 3 */ value = readl_relaxed(ctrl_io->base + MMSS_DP_AUDIO_STREAM_1); + value &= 0x0000ffff; new_value = num_of_channels - 1; parity_byte = mdss_dp_calculate_parity_byte(new_value); value |= ((new_value << HEADER_BYTE_3_BIT) @@ -1271,6 +1274,7 @@ static void mdss_dp_audio_setup_audio_timestamp_sdp(struct dss_io_data *ctrl_io) /* Config header and parity byte 1 */ value = readl_relaxed(ctrl_io->base + MMSS_DP_AUDIO_TIMESTAMP_0); + value &= 0x0000ffff; new_value = 0x1; parity_byte = mdss_dp_calculate_parity_byte(new_value); value |= ((new_value << HEADER_BYTE_1_BIT) @@ -1281,6 +1285,7 @@ static void mdss_dp_audio_setup_audio_timestamp_sdp(struct dss_io_data *ctrl_io) /* Config header and parity byte 2 */ value = readl_relaxed(ctrl_io->base + MMSS_DP_AUDIO_TIMESTAMP_1); + value &= 0xffff0000; new_value = 0x17; parity_byte = mdss_dp_calculate_parity_byte(new_value); value |= ((new_value << HEADER_BYTE_2_BIT) @@ -1291,6 +1296,7 @@ static void mdss_dp_audio_setup_audio_timestamp_sdp(struct dss_io_data *ctrl_io) /* Config header and parity byte 3 */ value = readl_relaxed(ctrl_io->base + MMSS_DP_AUDIO_TIMESTAMP_1); + value &= 0x0000ffff; new_value = (0x0 | (0x11 << 2)); parity_byte = mdss_dp_calculate_parity_byte(new_value); value |= ((new_value << HEADER_BYTE_3_BIT) @@ -1308,6 +1314,7 @@ static void mdss_dp_audio_setup_audio_infoframe_sdp(struct dss_io_data *ctrl_io) /* Config header and parity byte 1 */ value = readl_relaxed(ctrl_io->base + MMSS_DP_AUDIO_INFOFRAME_0); + value &= 0x0000ffff; new_value = 0x84; parity_byte = mdss_dp_calculate_parity_byte(new_value); value |= ((new_value << HEADER_BYTE_1_BIT) @@ -1318,6 +1325,7 @@ static void mdss_dp_audio_setup_audio_infoframe_sdp(struct dss_io_data *ctrl_io) /* Config header and parity byte 2 */ value = readl_relaxed(ctrl_io->base + MMSS_DP_AUDIO_INFOFRAME_1); + value &= 0xffff0000; new_value = 0x1b; parity_byte = mdss_dp_calculate_parity_byte(new_value); value |= ((new_value << HEADER_BYTE_2_BIT) @@ -1328,6 +1336,7 @@ static void mdss_dp_audio_setup_audio_infoframe_sdp(struct dss_io_data *ctrl_io) /* Config header and parity byte 3 */ value = readl_relaxed(ctrl_io->base + MMSS_DP_AUDIO_INFOFRAME_1); + value &= 0x0000ffff; new_value = (0x0 | (0x11 << 2)); parity_byte = mdss_dp_calculate_parity_byte(new_value); value |= ((new_value << HEADER_BYTE_3_BIT) @@ -1349,6 +1358,7 @@ static void mdss_dp_audio_setup_copy_management_sdp(struct dss_io_data *ctrl_io) /* Config header and parity byte 1 */ value = readl_relaxed(ctrl_io->base + MMSS_DP_AUDIO_COPYMANAGEMENT_0); + value &= 0x0000ffff; new_value = 0x05; parity_byte = mdss_dp_calculate_parity_byte(new_value); value |= ((new_value << HEADER_BYTE_1_BIT) @@ -1361,6 +1371,7 @@ static void mdss_dp_audio_setup_copy_management_sdp(struct dss_io_data *ctrl_io) /* Config header and parity byte 2 */ value = readl_relaxed(ctrl_io->base + MMSS_DP_AUDIO_COPYMANAGEMENT_1); + value &= 0xffff0000; new_value = 0x0F; parity_byte = mdss_dp_calculate_parity_byte(new_value); value |= ((new_value << HEADER_BYTE_2_BIT) @@ -1373,6 +1384,7 @@ static void mdss_dp_audio_setup_copy_management_sdp(struct dss_io_data *ctrl_io) /* Config header and parity byte 3 */ value = readl_relaxed(ctrl_io->base + MMSS_DP_AUDIO_COPYMANAGEMENT_1); + value &= 0x0000ffff; new_value = 0x0; parity_byte = mdss_dp_calculate_parity_byte(new_value); value |= ((new_value << HEADER_BYTE_3_BIT) @@ -1398,6 +1410,7 @@ static void mdss_dp_audio_setup_isrc_sdp(struct dss_io_data *ctrl_io) /* Config header and parity byte 1 */ value = readl_relaxed(ctrl_io->base + MMSS_DP_AUDIO_ISRC_0); + value &= 0x0000ffff; new_value = 0x06; parity_byte = mdss_dp_calculate_parity_byte(new_value); value |= ((new_value << HEADER_BYTE_1_BIT) @@ -1408,6 +1421,7 @@ static void mdss_dp_audio_setup_isrc_sdp(struct dss_io_data *ctrl_io) /* Config header and parity byte 2 */ value = readl_relaxed(ctrl_io->base + MMSS_DP_AUDIO_ISRC_1); + value &= 0xffff0000; new_value = 0x0F; parity_byte = mdss_dp_calculate_parity_byte(new_value); value |= ((new_value << HEADER_BYTE_2_BIT) diff --git a/drivers/video/fbdev/msm/mdss_hdmi_panel.c b/drivers/video/fbdev/msm/mdss_hdmi_panel.c index a8a56e3a8745..af72973a3988 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_panel.c +++ b/drivers/video/fbdev/msm/mdss_hdmi_panel.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2010-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -632,6 +632,19 @@ static int hdmi_panel_setup_dc(struct hdmi_panel *panel) vbi_pkt_reg = DSS_REG_R(panel->io, HDMI_VBI_PKT_CTRL); vbi_pkt_reg |= BIT(5) | BIT(4); DSS_REG_W(panel->io, HDMI_VBI_PKT_CTRL, vbi_pkt_reg); + } else { + hdmi_ctrl_reg = DSS_REG_R(panel->io, HDMI_CTRL); + + /* disable GC CD override */ + hdmi_ctrl_reg &= ~BIT(27); + /* disable deep color for RGB888/YUV444/YUV420 30 bits */ + hdmi_ctrl_reg &= ~BIT(24); + DSS_REG_W(panel->io, HDMI_CTRL, hdmi_ctrl_reg); + + /* disable the GC packet sending */ + vbi_pkt_reg = DSS_REG_R(panel->io, HDMI_VBI_PKT_CTRL); + vbi_pkt_reg &= ~(BIT(5) | BIT(4)); + DSS_REG_W(panel->io, HDMI_VBI_PKT_CTRL, vbi_pkt_reg); } return rc; diff --git a/drivers/video/fbdev/msm/mdss_hdmi_tx.c b/drivers/video/fbdev/msm/mdss_hdmi_tx.c index 5eb17ab27e4c..5cb436261115 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_tx.c +++ b/drivers/video/fbdev/msm/mdss_hdmi_tx.c @@ -2223,6 +2223,9 @@ static int hdmi_tx_read_sink_info(struct hdmi_tx_ctrl *hdmi_ctrl) DSS_REG_W_ND(io, HDMI_DDC_ARBITRATION, DSS_REG_R(io, HDMI_DDC_ARBITRATION) & ~(BIT(4))); + /* Set/Reset HDMI max TMDS clock supported by source */ + hdmi_edid_set_max_pclk_rate(data, hdmi_ctrl->max_pclk_khz); + if (!hdmi_ctrl->custom_edid && !hdmi_ctrl->sim_mode) { hdmi_ddc_config(&hdmi_ctrl->ddc_ctrl); diff --git a/drivers/video/fbdev/msm/mdss_mdp_util.c b/drivers/video/fbdev/msm/mdss_mdp_util.c index 1ae3d0ba4ec6..6015ed20fe56 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_util.c +++ b/drivers/video/fbdev/msm/mdss_mdp_util.c @@ -524,11 +524,12 @@ int mdss_mdp_get_plane_sizes(struct mdss_mdp_format_params *fmt, u32 w, u32 h, if (ps == NULL) return -EINVAL; + memset(ps, 0, sizeof(struct mdss_mdp_plane_sizes)); + if ((w > MAX_IMG_WIDTH) || (h > MAX_IMG_HEIGHT)) return -ERANGE; bpp = fmt->bpp; - memset(ps, 0, sizeof(struct mdss_mdp_plane_sizes)); if (mdss_mdp_is_ubwc_format(fmt)) { rc = mdss_mdp_get_ubwc_plane_size(fmt, w, h, ps); diff --git a/drivers/video/msm/ba/msm_ba.c b/drivers/video/msm/ba/msm_ba.c index 8d1459088b80..4200b8f20073 100644 --- a/drivers/video/msm/ba/msm_ba.c +++ b/drivers/video/msm/ba/msm_ba.c @@ -812,6 +812,11 @@ void *msm_ba_open(const struct msm_ba_ext_ops *ext_ops) dev_ctxt = get_ba_dev(); + if (!dev_ctxt) { + dprintk(BA_ERR, "Failed to get ba dev"); + return NULL; + } + inst = kzalloc(sizeof(*inst), GFP_KERNEL); if (!inst) { diff --git a/include/linux/memblock.h b/include/linux/memblock.h index 2d79ec1496e5..d3f41bfe05f1 100644 --- a/include/linux/memblock.h +++ b/include/linux/memblock.h @@ -84,6 +84,7 @@ int memblock_mark_hotplug(phys_addr_t base, phys_addr_t size); int memblock_clear_hotplug(phys_addr_t base, phys_addr_t size); int memblock_mark_mirror(phys_addr_t base, phys_addr_t size); int memblock_mark_nomap(phys_addr_t base, phys_addr_t size); +int memblock_clear_nomap(phys_addr_t base, phys_addr_t size); ulong choose_memblock_flags(void); unsigned long memblock_region_resize_late_begin(void); void memblock_region_resize_late_end(unsigned long); diff --git a/include/linux/memory_hotplug.h b/include/linux/memory_hotplug.h index 538488bd1d3d..ba23995e51b4 100644 --- a/include/linux/memory_hotplug.h +++ b/include/linux/memory_hotplug.h @@ -89,7 +89,7 @@ extern int test_pages_in_a_zone(unsigned long start_pfn, unsigned long end_pfn, unsigned long *valid_start, unsigned long *valid_end); extern void __offline_isolated_pages(unsigned long, unsigned long); -typedef void (*online_page_callback_t)(struct page *page); +typedef int (*online_page_callback_t)(struct page *page); extern int set_online_page_callback(online_page_callback_t callback); extern int restore_online_page_callback(online_page_callback_t callback); diff --git a/include/linux/spi/qcom-spi.h b/include/linux/spi/qcom-spi.h index 598481079383..67ef31c69641 100644 --- a/include/linux/spi/qcom-spi.h +++ b/include/linux/spi/qcom-spi.h @@ -48,9 +48,11 @@ struct msm_spi_platform_data { u32 infinite_mode; bool ver_reg_exists; bool use_bam; + bool slv_test; u32 bam_consumer_pipe_index; u32 bam_producer_pipe_index; bool rt_priority; bool use_pinctrl; bool is_shared; + bool is_slv_ctrl; }; diff --git a/include/linux/usb.h b/include/linux/usb.h index e8b2ed4ad851..f226476a2ea4 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -755,6 +755,7 @@ usb_get_sec_event_ring_dma_addr(struct usb_device *dev, extern dma_addr_t usb_get_dcba_dma_addr(struct usb_device *dev); extern dma_addr_t usb_get_xfer_ring_dma_addr(struct usb_device *dev, struct usb_host_endpoint *ep); +extern int usb_get_controller_id(struct usb_device *dev); /* Sets up a group of bulk endpoints to support multiple stream IDs. */ extern int usb_alloc_streams(struct usb_interface *interface, diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h index dff7adbc60bb..f603b46ff48a 100644 --- a/include/linux/usb/hcd.h +++ b/include/linux/usb/hcd.h @@ -405,6 +405,7 @@ struct hc_driver { struct usb_device *udev, struct usb_host_endpoint *ep); dma_addr_t (*get_dcba_dma_addr)(struct usb_hcd *hcd, struct usb_device *udev); + int (*get_core_id)(struct usb_hcd *hcd); }; static inline int hcd_giveback_urb_in_bh(struct usb_hcd *hcd) @@ -454,6 +455,7 @@ extern dma_addr_t usb_hcd_get_dcba_dma_addr(struct usb_device *udev); extern dma_addr_t usb_hcd_get_xfer_ring_dma_addr(struct usb_device *udev, struct usb_host_endpoint *ep); +extern int usb_hcd_get_controller_id(struct usb_device *udev); extern struct usb_hcd *usb_create_hcd(const struct hc_driver *driver, struct device *dev, const char *bus_name); diff --git a/include/soc/qcom/icnss.h b/include/soc/qcom/icnss.h index 78ca0f4bbd08..7915841b17ea 100644 --- a/include/soc/qcom/icnss.h +++ b/include/soc/qcom/icnss.h @@ -13,10 +13,15 @@ #define _ICNSS_WLAN_H_ #include <linux/interrupt.h> +#include <linux/device.h> #define ICNSS_MAX_IRQ_REGISTRATIONS 12 #define ICNSS_MAX_TIMESTAMP_LEN 32 +#ifndef ICNSS_API_WITH_DEV +#define ICNSS_API_WITH_DEV +#endif + enum icnss_uevent { ICNSS_UEVENT_FW_READY, ICNSS_UEVENT_FW_CRASHED, @@ -40,6 +45,8 @@ struct icnss_uevent_data { struct icnss_driver_ops { char *name; + unsigned long drv_state; + struct device_driver driver; int (*probe)(struct device *dev); void (*remove)(struct device *dev); void (*shutdown)(struct device *dev); @@ -105,28 +112,34 @@ struct icnss_soc_info { char fw_build_timestamp[ICNSS_MAX_TIMESTAMP_LEN + 1]; }; -extern int icnss_register_driver(struct icnss_driver_ops *driver); -extern int icnss_unregister_driver(struct icnss_driver_ops *driver); -extern int icnss_wlan_enable(struct icnss_wlan_enable_cfg *config, +#define icnss_register_driver(ops) \ + __icnss_register_driver(ops, THIS_MODULE, KBUILD_MODNAME) +extern int __icnss_register_driver(struct icnss_driver_ops *ops, + struct module *owner, const char *mod_name); + +extern int icnss_unregister_driver(struct icnss_driver_ops *ops); + +extern int icnss_wlan_enable(struct device *dev, + struct icnss_wlan_enable_cfg *config, enum icnss_driver_mode mode, const char *host_version); -extern int icnss_wlan_disable(enum icnss_driver_mode mode); -extern void icnss_enable_irq(unsigned int ce_id); -extern void icnss_disable_irq(unsigned int ce_id); -extern int icnss_get_soc_info(struct icnss_soc_info *info); -extern int icnss_ce_free_irq(unsigned int ce_id, void *ctx); -extern int icnss_ce_request_irq(unsigned int ce_id, +extern int icnss_wlan_disable(struct device *dev, enum icnss_driver_mode mode); +extern void icnss_enable_irq(struct device *dev, unsigned int ce_id); +extern void icnss_disable_irq(struct device *dev, unsigned int ce_id); +extern int icnss_get_soc_info(struct device *dev, struct icnss_soc_info *info); +extern int icnss_ce_free_irq(struct device *dev, unsigned int ce_id, void *ctx); +extern int icnss_ce_request_irq(struct device *dev, unsigned int ce_id, irqreturn_t (*handler)(int, void *), unsigned long flags, const char *name, void *ctx); -extern int icnss_get_ce_id(int irq); -extern int icnss_set_fw_log_mode(uint8_t fw_log_mode); +extern int icnss_get_ce_id(struct device *dev, int irq); +extern int icnss_set_fw_log_mode(struct device *dev, uint8_t fw_log_mode); extern int icnss_athdiag_read(struct device *dev, uint32_t offset, uint32_t mem_type, uint32_t data_len, uint8_t *output); extern int icnss_athdiag_write(struct device *dev, uint32_t offset, uint32_t mem_type, uint32_t data_len, uint8_t *input); -extern int icnss_get_irq(int ce_id); +extern int icnss_get_irq(struct device *dev, int ce_id); extern int icnss_power_on(struct device *dev); extern int icnss_power_off(struct device *dev); extern struct dma_iommu_mapping *icnss_smmu_get_mapping(struct device *dev); @@ -138,7 +151,7 @@ extern int icnss_get_wlan_unsafe_channel(u16 *unsafe_ch_list, u16 *ch_count, u16 buf_len); extern int icnss_wlan_set_dfs_nol(const void *info, u16 info_len); extern int icnss_wlan_get_dfs_nol(void *info, u16 info_len); -extern bool icnss_is_qmi_disable(void); +extern bool icnss_is_qmi_disable(struct device *dev); extern bool icnss_is_fw_ready(void); extern int icnss_set_wlan_mac_address(const u8 *in, const uint32_t len); extern u8 *icnss_get_wlan_mac_address(struct device *dev, uint32_t *num); diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 3dd0091f4af3..75050fac06fb 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -4904,12 +4904,17 @@ enum nl80211_smps_mode { * change to the channel status. * @NL80211_RADAR_NOP_FINISHED: The Non-Occupancy Period for this channel is * over, channel becomes usable. + * @NL80211_RADAR_PRE_CAC_EXPIRED: Channel Availability Check done on this + * non-operating channel is expired and no longer valid. New CAC must + * be done on this channel before starting the operation. This is not + * applicable for ETSI dfs domain where pre-CAC is valid for ever. */ enum nl80211_radar_event { NL80211_RADAR_DETECTED, NL80211_RADAR_CAC_FINISHED, NL80211_RADAR_CAC_ABORTED, NL80211_RADAR_NOP_FINISHED, + NL80211_RADAR_PRE_CAC_EXPIRED, }; /** diff --git a/include/uapi/media/ais/msm_ais_isp.h b/include/uapi/media/ais/msm_ais_isp.h index 7c9daafc404d..f323d3bf7baf 100644 --- a/include/uapi/media/ais/msm_ais_isp.h +++ b/include/uapi/media/ais/msm_ais_isp.h @@ -23,6 +23,8 @@ #define ISP_STATS_STREAM_BIT 0x80000000 +#define INTERLACE_SUPPORT_OLD_REMOVED + struct msm_vfe_cfg_cmd_list; enum ISP_START_PIXEL_PATTERN { @@ -733,6 +735,7 @@ struct msm_isp_buf_event { uint32_t handle; uint32_t output_format; int8_t buf_idx; + uint8_t field_type; }; struct msm_isp_fetch_eng_event { uint32_t session_id; diff --git a/mm/Kconfig b/mm/Kconfig index b880dce3fafd..7077376523ed 100644 --- a/mm/Kconfig +++ b/mm/Kconfig @@ -187,7 +187,7 @@ config MEMORY_HOTPLUG bool "Allow for memory hot-add" depends on SPARSEMEM || X86_64_ACPI_NUMA depends on ARCH_ENABLE_MEMORY_HOTPLUG - depends on (IA64 || X86 || PPC_BOOK3S_64 || SUPERH || S390) + depends on (IA64 || X86 || PPC_BOOK3S_64 || SUPERH || S390 || ARM64) config MEMORY_HOTPLUG_SPARSE def_bool y diff --git a/mm/memblock.c b/mm/memblock.c index 241225579f3a..fb63a9cc00fd 100644 --- a/mm/memblock.c +++ b/mm/memblock.c @@ -840,6 +840,16 @@ int __init_memblock memblock_mark_nomap(phys_addr_t base, phys_addr_t size) } /** + * memblock_clear_nomap - Clear a flag of MEMBLOCK_NOMAP memory region + * @base: the base phys addr of the region + * @size: the size of the region + */ +int __init_memblock memblock_clear_nomap(phys_addr_t base, phys_addr_t size) +{ + return memblock_setclr_flag(base, size, 0, MEMBLOCK_NOMAP); +} + +/** * __next_reserved_mem_region - next function for for_each_reserved_region() * @idx: pointer to u64 loop variable * @out_start: ptr to phys_addr_t for start address of the region, can be %NULL diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c index 2ad8a8888032..81957b076d66 100644 --- a/mm/memory_hotplug.c +++ b/mm/memory_hotplug.c @@ -45,7 +45,7 @@ * and restore_online_page_callback() for generic callback restore. */ -static void generic_online_page(struct page *page); +static int generic_online_page(struct page *page); static online_page_callback_t online_page_callback = generic_online_page; static DEFINE_MUTEX(online_page_callback_lock); @@ -857,11 +857,12 @@ void __online_page_free(struct page *page) } EXPORT_SYMBOL_GPL(__online_page_free); -static void generic_online_page(struct page *page) +static int generic_online_page(struct page *page) { __online_page_set_limits(page); __online_page_increment_counters(page); __online_page_free(page); + return 0; } static int online_pages_range(unsigned long start_pfn, unsigned long nr_pages, @@ -870,11 +871,13 @@ static int online_pages_range(unsigned long start_pfn, unsigned long nr_pages, unsigned long i; unsigned long onlined_pages = *(unsigned long *)arg; struct page *page; + int ret; if (PageReserved(pfn_to_page(start_pfn))) for (i = 0; i < nr_pages; i++) { page = pfn_to_page(start_pfn + i); - (*online_page_callback)(page); - onlined_pages++; + ret = (*online_page_callback)(page); + if (!ret) + onlined_pages++; } *(unsigned long *)arg = onlined_pages; return 0; diff --git a/net/wireless/ap.c b/net/wireless/ap.c index 91d02ac0f42f..547d38356583 100644 --- a/net/wireless/ap.c +++ b/net/wireless/ap.c @@ -32,6 +32,11 @@ int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev, rdev_set_qos_map(rdev, dev, NULL); if (notify) nl80211_send_ap_stopped(wdev); + + /* Should we apply the grace period during beaconing interface + * shutdown also? + */ + cfg80211_sched_dfs_chan_update(rdev); } return err; diff --git a/net/wireless/chan.c b/net/wireless/chan.c index d5ccaeaa76e0..6b5467ea99db 100644 --- a/net/wireless/chan.c +++ b/net/wireless/chan.c @@ -456,6 +456,105 @@ bool cfg80211_chandef_dfs_usable(struct wiphy *wiphy, return (r1 + r2 > 0); } +/* + * Checks if center frequency of chan falls with in the bandwidth + * range of chandef. + */ +bool cfg80211_is_sub_chan(struct cfg80211_chan_def *chandef, + struct ieee80211_channel *chan) +{ + int width; + u32 cf_offset, freq; + + if (chandef->chan->center_freq == chan->center_freq) + return true; + + width = cfg80211_chandef_get_width(chandef); + if (width <= 20) + return false; + + cf_offset = width / 2 - 10; + + for (freq = chandef->center_freq1 - width / 2 + 10; + freq <= chandef->center_freq1 + width / 2 - 10; freq += 20) { + if (chan->center_freq == freq) + return true; + } + + if (!chandef->center_freq2) + return false; + + for (freq = chandef->center_freq2 - width / 2 + 10; + freq <= chandef->center_freq2 + width / 2 - 10; freq += 20) { + if (chan->center_freq == freq) + return true; + } + + return false; +} + +bool cfg80211_beaconing_iface_active(struct wireless_dev *wdev) +{ + bool active = false; + + ASSERT_WDEV_LOCK(wdev); + + if (!wdev->chandef.chan) + return false; + + switch (wdev->iftype) { + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_P2P_GO: + active = wdev->beacon_interval != 0; + break; + case NL80211_IFTYPE_ADHOC: + active = wdev->ssid_len != 0; + break; + case NL80211_IFTYPE_MESH_POINT: + active = wdev->mesh_id_len != 0; + break; + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_OCB: + case NL80211_IFTYPE_P2P_CLIENT: + case NL80211_IFTYPE_MONITOR: + case NL80211_IFTYPE_AP_VLAN: + case NL80211_IFTYPE_WDS: + case NL80211_IFTYPE_P2P_DEVICE: + break; + case NL80211_IFTYPE_UNSPECIFIED: + case NUM_NL80211_IFTYPES: + WARN_ON(1); + } + + return active; +} + +bool cfg80211_any_wiphy_oper_chan(struct wiphy *wiphy, + struct ieee80211_channel *chan) +{ + struct wireless_dev *wdev; + + ASSERT_RTNL(); + + if (!(chan->flags & IEEE80211_CHAN_RADAR)) + return false; + + list_for_each_entry(wdev, &wiphy->wdev_list, list) { + wdev_lock(wdev); + if (!cfg80211_beaconing_iface_active(wdev)) { + wdev_unlock(wdev); + continue; + } + + if (cfg80211_is_sub_chan(&wdev->chandef, chan)) { + wdev_unlock(wdev); + return true; + } + wdev_unlock(wdev); + } + + return false; +} static bool cfg80211_get_chans_dfs_available(struct wiphy *wiphy, u32 center_freq, diff --git a/net/wireless/core.h b/net/wireless/core.h index be5ab8c13a39..55c64d08db31 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -438,6 +438,16 @@ unsigned int cfg80211_chandef_dfs_cac_time(struct wiphy *wiphy, const struct cfg80211_chan_def *chandef); +void cfg80211_sched_dfs_chan_update(struct cfg80211_registered_device *rdev); + +bool cfg80211_any_wiphy_oper_chan(struct wiphy *wiphy, + struct ieee80211_channel *chan); + +bool cfg80211_beaconing_iface_active(struct wireless_dev *wdev); + +bool cfg80211_is_sub_chan(struct cfg80211_chan_def *chandef, + struct ieee80211_channel *chan); + static inline unsigned int elapsed_jiffies_msecs(unsigned long start) { unsigned long end = jiffies; diff --git a/net/wireless/db.txt b/net/wireless/db.txt index 86005410a22f..499d98745d44 100644 --- a/net/wireless/db.txt +++ b/net/wireless/db.txt @@ -1478,9 +1478,9 @@ country VI: DFS-FCC country VN: DFS-FCC (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (24), AUTO-BW - (5250 - 5330 @ 80), (24), DFS, AUTO-BW - (5490 - 5730 @ 160), (24), DFS + (5170 - 5250 @ 80), (24) + (5250 - 5330 @ 80), (24), DFS + (5490 - 5730 @ 80), (24), DFS (5735 - 5835 @ 80), (30) # 60 gHz band channels 1-4 (57240 - 65880 @ 2160), (40) diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c index 4c55fab9b4e4..7da0cd9c5e73 100644 --- a/net/wireless/ibss.c +++ b/net/wireless/ibss.c @@ -186,6 +186,7 @@ static void __cfg80211_clear_ibss(struct net_device *dev, bool nowext) if (!nowext) wdev->wext.ibss.ssid_len = 0; #endif + cfg80211_sched_dfs_chan_update(rdev); } void cfg80211_clear_ibss(struct net_device *dev, bool nowext) diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c index 092300b30c37..dda90a39be40 100644 --- a/net/wireless/mesh.c +++ b/net/wireless/mesh.c @@ -260,6 +260,7 @@ int __cfg80211_leave_mesh(struct cfg80211_registered_device *rdev, wdev->mesh_id_len = 0; memset(&wdev->chandef, 0, sizeof(wdev->chandef)); rdev_set_qos_map(rdev, dev, NULL); + cfg80211_sched_dfs_chan_update(rdev); } return err; diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 2bc6eaa766c7..465e0d31229d 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -743,6 +743,12 @@ bool cfg80211_rx_mgmt(struct wireless_dev *wdev, int freq, int sig_mbm, } EXPORT_SYMBOL(cfg80211_rx_mgmt); +void cfg80211_sched_dfs_chan_update(struct cfg80211_registered_device *rdev) +{ + cancel_delayed_work(&rdev->dfs_update_channels_wk); + queue_delayed_work(cfg80211_wq, &rdev->dfs_update_channels_wk, 0); +} + void cfg80211_dfs_channels_update_work(struct work_struct *work) { struct delayed_work *delayed_work; @@ -753,6 +759,8 @@ void cfg80211_dfs_channels_update_work(struct work_struct *work) struct wiphy *wiphy; bool check_again = false; unsigned long timeout, next_time = 0; + unsigned long time_dfs_update; + enum nl80211_radar_event radar_event; int bandid, i; delayed_work = container_of(work, struct delayed_work, work); @@ -769,11 +777,27 @@ void cfg80211_dfs_channels_update_work(struct work_struct *work) for (i = 0; i < sband->n_channels; i++) { c = &sband->channels[i]; - if (c->dfs_state != NL80211_DFS_UNAVAILABLE) + if (!(c->flags & IEEE80211_CHAN_RADAR)) + continue; + + if (c->dfs_state != NL80211_DFS_UNAVAILABLE && + c->dfs_state != NL80211_DFS_AVAILABLE) continue; - timeout = c->dfs_state_entered + msecs_to_jiffies( - IEEE80211_DFS_MIN_NOP_TIME_MS); + if (c->dfs_state == NL80211_DFS_UNAVAILABLE) { + time_dfs_update = IEEE80211_DFS_MIN_NOP_TIME_MS; + radar_event = NL80211_RADAR_NOP_FINISHED; + } else { + if (regulatory_pre_cac_allowed(wiphy) || + cfg80211_any_wiphy_oper_chan(wiphy, c)) + continue; + + time_dfs_update = REG_PRE_CAC_EXPIRY_GRACE_MS; + radar_event = NL80211_RADAR_PRE_CAC_EXPIRED; + } + + timeout = c->dfs_state_entered + + msecs_to_jiffies(time_dfs_update); if (time_after_eq(jiffies, timeout)) { c->dfs_state = NL80211_DFS_USABLE; @@ -783,8 +807,8 @@ void cfg80211_dfs_channels_update_work(struct work_struct *work) NL80211_CHAN_NO_HT); nl80211_radar_notify(rdev, &chandef, - NL80211_RADAR_NOP_FINISHED, - NULL, GFP_ATOMIC); + radar_event, NULL, + GFP_ATOMIC); continue; } @@ -809,7 +833,6 @@ void cfg80211_radar_event(struct wiphy *wiphy, gfp_t gfp) { struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); - unsigned long timeout; trace_cfg80211_radar_event(wiphy, chandef); @@ -819,9 +842,7 @@ void cfg80211_radar_event(struct wiphy *wiphy, */ cfg80211_set_dfs_state(wiphy, chandef, NL80211_DFS_UNAVAILABLE); - timeout = msecs_to_jiffies(IEEE80211_DFS_MIN_NOP_TIME_MS); - queue_delayed_work(cfg80211_wq, &rdev->dfs_update_channels_wk, - timeout); + cfg80211_sched_dfs_chan_update(rdev); nl80211_radar_notify(rdev, chandef, NL80211_RADAR_DETECTED, NULL, gfp); } @@ -850,6 +871,7 @@ void cfg80211_cac_event(struct net_device *netdev, msecs_to_jiffies(wdev->cac_time_ms); WARN_ON(!time_after_eq(jiffies, timeout)); cfg80211_set_dfs_state(wiphy, chandef, NL80211_DFS_AVAILABLE); + cfg80211_sched_dfs_chan_update(rdev); break; case NL80211_RADAR_CAC_ABORTED: break; diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 050d7948dd68..26ac0a4808a0 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -3247,6 +3247,34 @@ bool regulatory_indoor_allowed(void) return reg_is_indoor; } +bool regulatory_pre_cac_allowed(struct wiphy *wiphy) +{ + const struct ieee80211_regdomain *regd = NULL; + const struct ieee80211_regdomain *wiphy_regd = NULL; + bool pre_cac_allowed = false; + + rcu_read_lock(); + + regd = rcu_dereference(cfg80211_regdomain); + wiphy_regd = rcu_dereference(wiphy->regd); + if (!wiphy_regd) { + if (regd->dfs_region == NL80211_DFS_ETSI) + pre_cac_allowed = true; + + rcu_read_unlock(); + + return pre_cac_allowed; + } + + if (regd->dfs_region == wiphy_regd->dfs_region && + wiphy_regd->dfs_region == NL80211_DFS_ETSI) + pre_cac_allowed = true; + + rcu_read_unlock(); + + return pre_cac_allowed; +} + int __init regulatory_init(void) { int err = 0; diff --git a/net/wireless/reg.h b/net/wireless/reg.h index 9f495d76eca0..7bbe2d138d2a 100644 --- a/net/wireless/reg.h +++ b/net/wireless/reg.h @@ -143,4 +143,18 @@ int cfg80211_get_unii(int freq); */ bool regulatory_indoor_allowed(void); +/* + * Grace period to timeout pre-CAC results on the dfs channels. This timeout + * value is used for Non-ETSI domain. + * TODO: May be make this timeout available through regdb? + */ +#define REG_PRE_CAC_EXPIRY_GRACE_MS 2000 + +/** + * regulatory_pre_cac_allowed - if pre-CAC allowed in the current dfs domain + * @wiphy: wiphy for which pre-CAC capability is checked. + + * Pre-CAC is allowed only in ETSI domain. + */ +bool regulatory_pre_cac_allowed(struct wiphy *wiphy); #endif /* __NET_WIRELESS_REG_H */ diff --git a/net/wireless/sysfs.c b/net/wireless/sysfs.c index 460c4b0e343c..e0eb2a4cfd8e 100644 --- a/net/wireless/sysfs.c +++ b/net/wireless/sysfs.c @@ -97,7 +97,7 @@ static int wiphy_suspend(struct device *dev) rtnl_lock(); if (rdev->wiphy.registered) if (rdev->ops->suspend) - ret = rdev_suspend(rdev, NULL); + ret = rdev_suspend(rdev, rdev->wiphy.wowlan_config); rtnl_unlock(); return ret; diff --git a/security/pfe/pfk_ice.c b/security/pfe/pfk_ice.c index facecedc3827..2bf18b74bfd5 100644 --- a/security/pfe/pfk_ice.c +++ b/security/pfe/pfk_ice.c @@ -68,25 +68,34 @@ int qti_pfk_ice_set_key(uint32_t index, uint8_t *key, uint8_t *salt, char *storage_type) { struct scm_desc desc = {0}; - int ret; + int ret, ret1; char *tzbuf_key = (char *)ice_key; char *tzbuf_salt = (char *)ice_salt; + char *s_type = storage_type; uint32_t smc_id = 0; u32 tzbuflen_key = sizeof(ice_key); u32 tzbuflen_salt = sizeof(ice_salt); - if (index < MIN_ICE_KEY_INDEX || index > MAX_ICE_KEY_INDEX) + if (index < MIN_ICE_KEY_INDEX || index > MAX_ICE_KEY_INDEX) { + pr_err("%s Invalid index %d\n", __func__, index); return -EINVAL; + } - if (!key || !salt) + if (!key || !salt) { + pr_err("%s Invalid key/salt\n", __func__); return -EINVAL; + } - if (!tzbuf_key || !tzbuf_salt) + if (!tzbuf_key || !tzbuf_salt) { + pr_err("%s No Memory\n", __func__); return -ENOMEM; + } - if (storage_type == NULL) + if (s_type == NULL) { + pr_err("%s Invalid storage\n", __func__); return -EINVAL; + } memset(tzbuf_key, 0, tzbuflen_key); memset(tzbuf_salt, 0, tzbuflen_salt); @@ -98,7 +107,6 @@ int qti_pfk_ice_set_key(uint32_t index, uint8_t *key, uint8_t *salt, dmac_flush_range(tzbuf_salt, tzbuf_salt + tzbuflen_salt); smc_id = TZ_ES_SET_ICE_KEY_ID; - pr_debug(" %s , smc_id = 0x%x\n", __func__, smc_id); desc.arginfo = TZ_ES_SET_ICE_KEY_PARAM_ID; desc.args[0] = index; @@ -107,27 +115,36 @@ int qti_pfk_ice_set_key(uint32_t index, uint8_t *key, uint8_t *salt, desc.args[3] = virt_to_phys(tzbuf_salt); desc.args[4] = tzbuflen_salt; - ret = qcom_ice_setup_ice_hw((const char *)storage_type, true); + ret = qcom_ice_setup_ice_hw((const char *)s_type, true); if (ret) { - pr_err("%s: could not enable clocks: 0x%x\n", __func__, ret); - return ret; + pr_err("%s: could not enable clocks: %d\n", __func__, ret); + goto out; } ret = scm_call2(smc_id, &desc); - ret = qcom_ice_setup_ice_hw((const char *)storage_type, false); - pr_debug(" %s , ret = %d\n", __func__, ret); - if (ret) { - pr_err("%s: Error: 0x%x\n", __func__, ret); + if (ret) { + pr_err("%s: Set key Error: %d\n", __func__, ret); + if (ret == -EBUSY) { + if (qcom_ice_setup_ice_hw((const char *)s_type, false)) + pr_err("%s: disable clock failed\n", __func__); + goto out; + } + /*Try to invalidate the key to keep ICE in proper state*/ smc_id = TZ_ES_INVALIDATE_ICE_KEY_ID; desc.arginfo = TZ_ES_INVALIDATE_ICE_KEY_PARAM_ID; desc.args[0] = index; - scm_call2(smc_id, &desc); + ret1 = scm_call2(smc_id, &desc); + if (ret1) + pr_err("%s:Invalidate key Error: %d\n", __func__, + ret1); } + ret = qcom_ice_setup_ice_hw((const char *)s_type, false); +out: return ret; } @@ -139,14 +156,17 @@ int qti_pfk_ice_invalidate_key(uint32_t index, char *storage_type) uint32_t smc_id = 0; - if (index < MIN_ICE_KEY_INDEX || index > MAX_ICE_KEY_INDEX) + if (index < MIN_ICE_KEY_INDEX || index > MAX_ICE_KEY_INDEX) { + pr_err("%s Invalid index %d\n", __func__, index); return -EINVAL; + } - if (storage_type == NULL) + if (storage_type == NULL) { + pr_err("%s Invalid storage\n", __func__); return -EINVAL; + } smc_id = TZ_ES_INVALIDATE_ICE_KEY_ID; - pr_debug(" %s , smc_id = 0x%x\n", __func__, smc_id); desc.arginfo = TZ_ES_INVALIDATE_ICE_KEY_PARAM_ID; desc.args[0] = index; @@ -160,12 +180,13 @@ int qti_pfk_ice_invalidate_key(uint32_t index, char *storage_type) ret = scm_call2(smc_id, &desc); - ret = qcom_ice_setup_ice_hw((const char *)storage_type, false); - - pr_debug(" %s , ret = %d\n", __func__, ret); - if (ret) + if (ret) { pr_err("%s: Error: 0x%x\n", __func__, ret); + if (qcom_ice_setup_ice_hw((const char *)storage_type, false)) + pr_err("%s: could not disable clocks\n", __func__); + } else { + ret = qcom_ice_setup_ice_hw((const char *)storage_type, false); + } return ret; - } diff --git a/sound/soc/codecs/wcd934x/wcd934x.c b/sound/soc/codecs/wcd934x/wcd934x.c index bfe471e73503..c8cc17d4dfd3 100644 --- a/sound/soc/codecs/wcd934x/wcd934x.c +++ b/sound/soc/codecs/wcd934x/wcd934x.c @@ -2996,7 +2996,7 @@ static int tavil_codec_enable_asrc(struct snd_soc_codec *codec, int asrc_in, int event) { struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec); - u16 cfg_reg, ctl_reg, clk_reg, asrc_ctl, mix_ctl_reg; + u16 cfg_reg, ctl_reg, clk_reg, asrc_ctl, mix_ctl_reg, paired_reg; int asrc, ret = 0; u8 main_sr, mix_sr, asrc_mode = 0; @@ -3005,6 +3005,7 @@ static int tavil_codec_enable_asrc(struct snd_soc_codec *codec, cfg_reg = WCD934X_CDC_RX1_RX_PATH_CFG0; ctl_reg = WCD934X_CDC_RX1_RX_PATH_CTL; clk_reg = WCD934X_MIXING_ASRC0_CLK_RST_CTL; + paired_reg = WCD934X_MIXING_ASRC1_CLK_RST_CTL; asrc_ctl = WCD934X_MIXING_ASRC0_CTL1; asrc = ASRC0; break; @@ -3012,6 +3013,7 @@ static int tavil_codec_enable_asrc(struct snd_soc_codec *codec, cfg_reg = WCD934X_CDC_RX3_RX_PATH_CFG0; ctl_reg = WCD934X_CDC_RX3_RX_PATH_CTL; clk_reg = WCD934X_MIXING_ASRC0_CLK_RST_CTL; + paired_reg = WCD934X_MIXING_ASRC1_CLK_RST_CTL; asrc_ctl = WCD934X_MIXING_ASRC0_CTL1; asrc = ASRC0; break; @@ -3019,6 +3021,7 @@ static int tavil_codec_enable_asrc(struct snd_soc_codec *codec, cfg_reg = WCD934X_CDC_RX2_RX_PATH_CFG0; ctl_reg = WCD934X_CDC_RX2_RX_PATH_CTL; clk_reg = WCD934X_MIXING_ASRC1_CLK_RST_CTL; + paired_reg = WCD934X_MIXING_ASRC0_CLK_RST_CTL; asrc_ctl = WCD934X_MIXING_ASRC1_CTL1; asrc = ASRC1; break; @@ -3026,6 +3029,7 @@ static int tavil_codec_enable_asrc(struct snd_soc_codec *codec, cfg_reg = WCD934X_CDC_RX4_RX_PATH_CFG0; ctl_reg = WCD934X_CDC_RX4_RX_PATH_CTL; clk_reg = WCD934X_MIXING_ASRC1_CLK_RST_CTL; + paired_reg = WCD934X_MIXING_ASRC0_CLK_RST_CTL; asrc_ctl = WCD934X_MIXING_ASRC1_CTL1; asrc = ASRC1; break; @@ -3033,6 +3037,7 @@ static int tavil_codec_enable_asrc(struct snd_soc_codec *codec, cfg_reg = WCD934X_CDC_RX7_RX_PATH_CFG0; ctl_reg = WCD934X_CDC_RX7_RX_PATH_CTL; clk_reg = WCD934X_MIXING_ASRC2_CLK_RST_CTL; + paired_reg = WCD934X_MIXING_ASRC3_CLK_RST_CTL; asrc_ctl = WCD934X_MIXING_ASRC2_CTL1; asrc = ASRC2; break; @@ -3040,6 +3045,7 @@ static int tavil_codec_enable_asrc(struct snd_soc_codec *codec, cfg_reg = WCD934X_CDC_RX8_RX_PATH_CFG0; ctl_reg = WCD934X_CDC_RX8_RX_PATH_CTL; clk_reg = WCD934X_MIXING_ASRC3_CLK_RST_CTL; + paired_reg = WCD934X_MIXING_ASRC2_CLK_RST_CTL; asrc_ctl = WCD934X_MIXING_ASRC3_CTL1; asrc = ASRC3; break; @@ -3053,6 +3059,13 @@ static int tavil_codec_enable_asrc(struct snd_soc_codec *codec, switch (event) { case SND_SOC_DAPM_PRE_PMU: if (tavil->asrc_users[asrc] == 0) { + if ((snd_soc_read(codec, clk_reg) & 0x02) || + (snd_soc_read(codec, paired_reg) & 0x02)) { + snd_soc_update_bits(codec, clk_reg, + 0x02, 0x00); + snd_soc_update_bits(codec, paired_reg, + 0x02, 0x00); + } snd_soc_update_bits(codec, cfg_reg, 0x80, 0x80); snd_soc_update_bits(codec, clk_reg, 0x01, 0x01); main_sr = snd_soc_read(codec, ctl_reg) & 0x0F; @@ -3072,7 +3085,7 @@ static int tavil_codec_enable_asrc(struct snd_soc_codec *codec, tavil->asrc_users[asrc] = 0; snd_soc_update_bits(codec, asrc_ctl, 0x07, 0x00); snd_soc_update_bits(codec, cfg_reg, 0x80, 0x00); - snd_soc_update_bits(codec, clk_reg, 0x01, 0x00); + snd_soc_update_bits(codec, clk_reg, 0x03, 0x02); } break; }; diff --git a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c index 471be3294881..7e22567ead96 100644 --- a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c @@ -2672,8 +2672,8 @@ static int msm_compr_pointer(struct snd_compr_stream *cstream, tstamp.copied_total = prtd->received_total; first_buffer = prtd->first_buffer; if (atomic_read(&prtd->error)) { - pr_err("%s Got RESET EVENTS notification, return error\n", - __func__); + pr_err_ratelimited("%s Got RESET EVENTS notification, return error\n", + __func__); if (cstream->direction == SND_COMPRESS_PLAYBACK) runtime->total_bytes_transferred = tstamp.copied_total; else diff --git a/sound/usb/usb_audio_qmi_svc.c b/sound/usb/usb_audio_qmi_svc.c index 28c5a3736a9c..3b41e552afb2 100644 --- a/sound/usb/usb_audio_qmi_svc.c +++ b/sound/usb/usb_audio_qmi_svc.c @@ -555,6 +555,13 @@ skip_sync_ep: resp->interrupter_num = uaudio_qdev->intr_num; resp->interrupter_num_valid = 1; + ret = usb_get_controller_id(subs->dev); + if (ret < 0) + goto err; + + resp->controller_num = ret; + resp->controller_num_valid = 1; + /* map xhci data structures PA memory to iova */ /* event ring */ diff --git a/sound/usb/usb_audio_qmi_v01.c b/sound/usb/usb_audio_qmi_v01.c index 6f6f194e89fb..a93665cb7b25 100644 --- a/sound/usb/usb_audio_qmi_v01.c +++ b/sound/usb/usb_audio_qmi_v01.c @@ -1,4 +1,4 @@ - /* Copyright (c) 2016, The Linux Foundation. All rights reserved. + /* 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 @@ -633,6 +633,46 @@ struct elem_info qmi_uaudio_stream_resp_msg_v01_ei[] = { interrupter_num), }, { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x1C, + .offset = offsetof( + struct qmi_uaudio_stream_resp_msg_v01, + speed_info_valid), + }, + { + .data_type = QMI_SIGNED_4_BYTE_ENUM, + .elem_len = 1, + .elem_size = sizeof(enum usb_audio_device_speed_enum_v01), + .is_array = NO_ARRAY, + .tlv_type = 0x1C, + .offset = offsetof( + struct qmi_uaudio_stream_resp_msg_v01, + speed_info), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x1D, + .offset = offsetof( + struct qmi_uaudio_stream_resp_msg_v01, + controller_num_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x1D, + .offset = offsetof( + struct qmi_uaudio_stream_resp_msg_v01, + controller_num), + }, + { .data_type = QMI_EOTI, .is_array = NO_ARRAY, .is_array = QMI_COMMON_TLV_TYPE, diff --git a/sound/usb/usb_audio_qmi_v01.h b/sound/usb/usb_audio_qmi_v01.h index aa1018a22105..9900764bf76f 100644 --- a/sound/usb/usb_audio_qmi_v01.h +++ b/sound/usb/usb_audio_qmi_v01.h @@ -1,4 +1,4 @@ - /* Copyright (c) 2016, The Linux Foundation. All rights reserved. + /* 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 @@ -77,6 +77,16 @@ enum usb_audio_device_indication_enum_v01 { USB_AUDIO_DEVICE_INDICATION_ENUM_MAX_VAL_V01 = INT_MAX, }; +enum usb_audio_device_speed_enum_v01 { + USB_AUDIO_DEVICE_SPEED_ENUM_MIN_VAL_V01 = INT_MIN, + USB_AUDIO_DEVICE_SPEED_INVALID_V01 = 0, + USB_AUDIO_DEVICE_SPEED_LOW_V01 = 1, + USB_AUDIO_DEVICE_SPEED_FULL_V01 = 2, + USB_AUDIO_DEVICE_SPEED_HIGH_V01 = 3, + USB_AUDIO_DEVICE_SPEED_SUPER_V01 = 4, + USB_AUDIO_DEVICE_SPEED_ENUM_MAX_VAL_V01 = INT_MAX, +}; + struct qmi_uaudio_stream_req_msg_v01 { uint8_t enable; uint32_t usb_token; @@ -118,8 +128,12 @@ struct qmi_uaudio_stream_resp_msg_v01 { struct apps_mem_info_v01 xhci_mem_info; uint8_t interrupter_num_valid; uint8_t interrupter_num; + uint8_t speed_info_valid; + enum usb_audio_device_speed_enum_v01 speed_info; + uint8_t controller_num_valid; + uint8_t controller_num; }; -#define QMI_UAUDIO_STREAM_RESP_MSG_V01_MAX_MSG_LEN 191 +#define QMI_UAUDIO_STREAM_RESP_MSG_V01_MAX_MSG_LEN 202 extern struct elem_info qmi_uaudio_stream_resp_msg_v01_ei[]; struct qmi_uaudio_stream_ind_msg_v01 { |
